mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-03 15:38:22 +00:00
Add TUI paneling example
This commit is contained in:
parent
bf03b2e64c
commit
26ac6871da
3 changed files with 179 additions and 1 deletions
2
Makefile
2
Makefile
|
@ -137,7 +137,6 @@ include libc/testlib/testlib.mk
|
|||
include tool/viz/lib/vizlib.mk
|
||||
include third_party/lua/lua.mk
|
||||
include third_party/quickjs/quickjs.mk
|
||||
include examples/examples.mk
|
||||
include third_party/lz4cli/lz4cli.mk
|
||||
include tool/build/lib/buildlib.mk
|
||||
include third_party/chibicc/chibicc.mk
|
||||
|
@ -145,6 +144,7 @@ include third_party/chibicc/test/test.mk
|
|||
include tool/build/emucrt/emucrt.mk
|
||||
include tool/build/emubin/emubin.mk
|
||||
include tool/build/build.mk
|
||||
include examples/examples.mk
|
||||
include tool/decode/lib/decodelib.mk
|
||||
include tool/decode/decode.mk
|
||||
include tool/hash/hash.mk
|
||||
|
|
|
@ -74,6 +74,7 @@ EXAMPLES_DIRECTDEPS = \
|
|||
THIRD_PARTY_STB \
|
||||
THIRD_PARTY_XED \
|
||||
THIRD_PARTY_ZLIB \
|
||||
TOOL_BUILD_LIB \
|
||||
TOOL_VIZ_LIB
|
||||
|
||||
EXAMPLES_DEPS := \
|
||||
|
|
177
examples/panels.c
Normal file
177
examples/panels.c
Normal file
|
@ -0,0 +1,177 @@
|
|||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/ioctl.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/termios.h"
|
||||
#include "libc/calls/struct/winsize.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/gdb.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/panel.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Cosmopolitan Paneling Demo.
|
||||
*
|
||||
* This is useful for creating terminal user interfaces. We take the
|
||||
* simplest approach possible. The main thing we abstract is like,
|
||||
* truncating the lines that overflow within a panel. In order to do
|
||||
* that, we abstract the ANSI parsing and the implementation is able to
|
||||
* tell how many cells wide each UNICODE character is.
|
||||
*
|
||||
* There are smarter ways for Cosmopolitan to do this. For example, it'd
|
||||
* be great to have automatic flex boxes. It'd also be nice to be able
|
||||
* to use dynamic programming for low bandwidth display updates, like
|
||||
* Emacs does, but that's less of an issue these days and can actually
|
||||
* make things slower, since for heavy workloads like printing videos,
|
||||
* having ANSI codes bouncing around the display actually goes slower.
|
||||
*
|
||||
* Beyond basic paneling, a message box widget is also provided, which
|
||||
* makes it easier to do modal dialogs.
|
||||
*/
|
||||
|
||||
struct Panels {
|
||||
union {
|
||||
struct {
|
||||
struct Panel left;
|
||||
struct Panel right;
|
||||
};
|
||||
struct Panel p[2];
|
||||
};
|
||||
} pan;
|
||||
|
||||
long tyn;
|
||||
long txn;
|
||||
char key[8];
|
||||
bool shutdown;
|
||||
bool invalidated;
|
||||
struct termios oldterm;
|
||||
|
||||
void OnShutdown(int sig) {
|
||||
shutdown = true;
|
||||
}
|
||||
|
||||
void OnInvalidate(int sig) {
|
||||
invalidated = true;
|
||||
}
|
||||
|
||||
void GetTtySize(void) {
|
||||
struct winsize wsize;
|
||||
wsize.ws_row = tyn;
|
||||
wsize.ws_col = txn;
|
||||
getttysize(1, &wsize);
|
||||
tyn = wsize.ws_row;
|
||||
txn = wsize.ws_col;
|
||||
}
|
||||
|
||||
int Write(const char *s) {
|
||||
return write(1, s, strlen(s));
|
||||
}
|
||||
|
||||
void Setup(void) {
|
||||
CHECK_NE(-1, ioctl(1, TCGETS, &oldterm));
|
||||
}
|
||||
|
||||
void Enter(void) {
|
||||
struct termios term;
|
||||
memcpy(&term, &oldterm, sizeof(term));
|
||||
term.c_cc[VMIN] = 1;
|
||||
term.c_cc[VTIME] = 1;
|
||||
term.c_iflag &= ~(INPCK | ISTRIP | PARMRK | INLCR | IGNCR | ICRNL | IXON);
|
||||
term.c_lflag &= ~(IEXTEN | ICANON | ECHO | ECHONL);
|
||||
term.c_cflag &= ~(CSIZE | PARENB);
|
||||
term.c_cflag |= CS8;
|
||||
term.c_iflag |= IUTF8;
|
||||
CHECK_NE(-1, ioctl(1, TCSETS, &term));
|
||||
Write("\e[?25l");
|
||||
}
|
||||
|
||||
void Leave(void) {
|
||||
Write(gc(xasprintf("\e[?25h\e[%d;%dH\e[S\r\n", tyn, txn)));
|
||||
ioctl(1, TCSETS, &oldterm);
|
||||
}
|
||||
|
||||
void Clear(void) {
|
||||
long i, j;
|
||||
for (i = 0; i < ARRAYLEN(pan.p); ++i) {
|
||||
for (j = 0; j < pan.p[i].n; ++j) {
|
||||
free(pan.p[i].lines[j].p);
|
||||
}
|
||||
free(pan.p[i].lines);
|
||||
pan.p[i].lines = 0;
|
||||
pan.p[i].n = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Layout(void) {
|
||||
long i, j;
|
||||
i = txn >> 1;
|
||||
pan.left.top = 0;
|
||||
pan.left.left = 0;
|
||||
pan.left.bottom = tyn;
|
||||
pan.left.right = i;
|
||||
pan.right.top = 0;
|
||||
pan.right.left = i + 1;
|
||||
pan.right.bottom = tyn;
|
||||
pan.right.right = txn;
|
||||
pan.left.n = pan.left.bottom - pan.left.top;
|
||||
pan.left.lines = xcalloc(pan.left.n, sizeof(*pan.left.lines));
|
||||
pan.right.n = pan.right.bottom - pan.right.top;
|
||||
pan.right.lines = xcalloc(pan.right.n, sizeof(*pan.right.lines));
|
||||
}
|
||||
|
||||
void Append(struct Panel *p, int i, const char *s) {
|
||||
if (i >= p->n) return;
|
||||
AppendStr(p->lines + i, s);
|
||||
}
|
||||
|
||||
void Draw(void) {
|
||||
Append(&pan.left, 0, gc(xasprintf("you typed %`'s", key)));
|
||||
Append(&pan.left, ((tyn + 1) >> 1) + 0, "hello left 1 𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷");
|
||||
Append(&pan.left, ((tyn + 1) >> 1) + 1, "hello left 2 (╯°□°)╯");
|
||||
Append(&pan.right, ((tyn + 1) >> 1) + 0, "hello right 1");
|
||||
Append(&pan.right, ((tyn + 1) >> 1) + 1, "hello right 2");
|
||||
PrintPanels(1, ARRAYLEN(pan.p), pan.p, tyn, txn);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct sigaction sa[2] = {
|
||||
{.sa_handler = OnShutdown},
|
||||
{.sa_handler = OnInvalidate, .sa_flags = SA_RESTART},
|
||||
};
|
||||
showcrashreports();
|
||||
Setup();
|
||||
Enter();
|
||||
GetTtySize();
|
||||
sigaction(SIGINT, &sa[0], 0);
|
||||
sigaction(SIGCONT, &sa[1], 0);
|
||||
sigaction(SIGWINCH, &sa[1], 0);
|
||||
atexit(Leave);
|
||||
do {
|
||||
Clear();
|
||||
Layout();
|
||||
Draw();
|
||||
if (invalidated) {
|
||||
Enter();
|
||||
GetTtySize();
|
||||
invalidated = false;
|
||||
} else {
|
||||
readansi(0, key, sizeof(key));
|
||||
}
|
||||
} while (!shutdown);
|
||||
}
|
Loading…
Add table
Reference in a new issue