mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-09 09:09:03 -04:00
* sliding: bounding box around puzzle * slider: make moves, deleting planes #61 * implement z-index move functions * demo: allow demos to be chosen via command-line option * allow default bg/fg to be explicitly chosen * ncplane_resize() unit test #64 * useful links * slider: use random colors * use find_above() in ncplace_destroy() * ncplane_resize() work #64
This commit is contained in:
parent
374403fdeb
commit
7f9ac490b0
12
README.md
12
README.md
@ -398,3 +398,15 @@ to implement".
|
||||
tracing solutions exist, such as `bpftrace`.
|
||||
* There is no timeout functionality for input (`timeout()`, `halfdelay()`, etc.).
|
||||
Roll your own with any of the four thousand ways to do it.
|
||||
|
||||
## Useful links
|
||||
|
||||
* [BiDi in Terminal Emulators](https://terminal-wg.pages.freedesktop.org/bidi/)
|
||||
* [The Xterm FAQ](https://invisible-island.net/xterm/xterm.faq.html)
|
||||
* [The NCURSES FAQ](https://invisible-island.net/ncurses/ncurses.faq.html)
|
||||
* [ECMA-35 Character Code Structure and Extension Techniques](https://www.ecma-international.org/publications/standards/Ecma-035.htm) (ISO/IEC 2022)
|
||||
* [ECMA-43 8-bit Coded Character Set Structure and Rules](https://www.ecma-international.org/publications/standards/Ecma-043.htm)
|
||||
* [ECMA-48 Control Functions for Coded Character Sets](https://www.ecma-international.org/publications/standards/Ecma-048.htm) (ISO/IEC 6429)
|
||||
* [Unicode 12.1 Full Emoji List](https://unicode.org/emoji/charts/full-emoji-list.html)
|
||||
* [Unicode Standard Annex #29 Text Segmenation](http://www.unicode.org/reports/tr29)
|
||||
* [Unicode Standard Annex #15 Normalization Forms](https://unicode.org/reports/tr15/)
|
||||
|
@ -9,6 +9,9 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#define RESTRICT
|
||||
#else
|
||||
#define RESTRICT restrict
|
||||
#endif
|
||||
|
||||
#define API __attribute__((visibility("default")))
|
||||
@ -124,31 +127,52 @@ API int notcurses_resize(struct notcurses* n);
|
||||
API struct ncplane* notcurses_stdplane(struct notcurses* nc);
|
||||
API const struct ncplane* notcurses_stdplane_const(const struct notcurses* nc);
|
||||
|
||||
// Create a new plane at the specified offset (relative to the standard plane)
|
||||
// Create a new ncplane at the specified offset (relative to the standard plane)
|
||||
// and the specified size. The number of rows and columns must both be positive.
|
||||
// This plane is initially at the top of the z-buffer, as if ncplane_move_top()
|
||||
// had been called on it. The void* 'opaque' can be retrieved (and reset) later.
|
||||
API struct ncplane* notcurses_newplane(struct notcurses* nc, int rows, int cols,
|
||||
int yoff, int xoff, void* opaque);
|
||||
|
||||
// Resize the specified ncplane. The four parameters 'keepy', 'keepx',
|
||||
// 'keepleny', and 'keeplenx' define a subset of the ncplane to keep,
|
||||
// unchanged. This may be a section of size 0, though none of these four
|
||||
// parameters may be negative. 'keepx' and 'keepy' are relative to the ncplane.
|
||||
// They must specify a coordinate within the ncplane's totality. 'yoff' and
|
||||
// 'xoff' are relative to 'keepy' and 'keepx', and place the upper-left corner
|
||||
// of the resized ncplane. Finally, 'ylen' and 'xlen' are the dimensions of the
|
||||
// ncplane after resizing. 'ylen' must be greater than or equal to 'keepleny',
|
||||
// and 'xlen' must be greater than or equal to 'keeplenx'. It is an error to
|
||||
// attempt to resize the standard plane. If either of 'keepy' or 'keepx' is
|
||||
// non-zero, both must be non-zero.
|
||||
//
|
||||
// Essentially, the kept material does not move. It serves to anchor the
|
||||
// resized plane. If there is no kept material, the plane can move freely:
|
||||
// it is possible to implement ncplane_move() in terms of ncplane_resize().
|
||||
API int ncplane_resize(struct ncplane* n, int keepy, int keepx, int keepleny,
|
||||
int keeplenx, int yoff, int xoff, int ylen, int xlen);
|
||||
|
||||
// Destroy the specified ncplane. None of its contents will be visible after
|
||||
// the next call to notcurses_render(). It is an error to attempt to destroy
|
||||
// the standard plane.
|
||||
API int ncplane_destroy(struct notcurses* nc, struct ncplane* ncp);
|
||||
API int ncplane_destroy(struct ncplane* ncp);
|
||||
|
||||
// Move this plane relative to the standard plane.
|
||||
API int ncplane_move_yx(struct ncplane* n, int y, int x);
|
||||
// Move this plane relative to the standard plane. It is an error to attempt to
|
||||
// move the standard plane.
|
||||
API void ncplane_move_yx(struct ncplane* n, int y, int x);
|
||||
|
||||
// Get the origin of this plane relative to the standard plane.
|
||||
API void ncplane_yx(const struct ncplane* n, int* y, int* x);
|
||||
API void ncplane_yx(const struct ncplane* n, int* RESTRICT y, int* RESTRICT x);
|
||||
|
||||
// Splice ncplane 'n' out of the z-buffer, and reinsert it at the top or bottom.
|
||||
API int ncplane_move_top(struct ncplane* n);
|
||||
API int ncplane_move_bottom(struct ncplane* n);
|
||||
|
||||
// Splice ncplane 'n' out of the z-buffer, and reinsert it below 'below'.
|
||||
API int ncplane_move_below(struct ncplane* RESTRICT n, struct ncplane* RESTRICT below);
|
||||
|
||||
// Splice ncplane 'n' out of the z-buffer, and reinsert it above 'above'.
|
||||
API void ncplane_move_above(struct ncplane* n, struct ncplane* above);
|
||||
// Splice ncplane 'n' out of the z-buffer, and reinsert it below 'below'.
|
||||
API void ncplane_move_below(struct ncplane* n, struct ncplane* below);
|
||||
// Splice ncplane 'n' out of the z-buffer, and reinsert it at the top or bottom.
|
||||
API void ncplane_move_top(struct ncplane* n);
|
||||
API void ncplane_move_bottom(struct ncplane* n);
|
||||
API int ncplane_move_above(struct ncplane* RESTRICT n, struct ncplane* RESTRICT above);
|
||||
|
||||
// Retrieve the topmost cell at this location on the screen, returning it in
|
||||
// 'c'. If there is more than a byte of gcluster, it will be returned as a heap
|
||||
@ -163,12 +187,14 @@ API void* ncplane_userptr(struct ncplane* n);
|
||||
API const void* ncplane_userptr_const(const struct ncplane* n);
|
||||
|
||||
// Returns the dimensions of this ncplane.
|
||||
API void ncplane_dimyx(const struct ncplane* n, int* rows, int* cols);
|
||||
API void ncplane_dim_yx(const struct ncplane* n, int* RESTRICT rows,
|
||||
int* RESTRICT cols);
|
||||
|
||||
// Return our current idea of the terminal dimensions in rows and cols.
|
||||
static inline void
|
||||
notcurses_term_dimyx(const struct notcurses* n, int* rows, int* cols){
|
||||
ncplane_dimyx(notcurses_stdplane_const(n), rows, cols);
|
||||
notcurses_term_dim_yx(const struct notcurses* n, int* RESTRICT rows,
|
||||
int* RESTRICT cols){
|
||||
ncplane_dim_yx(notcurses_stdplane_const(n), rows, cols);
|
||||
}
|
||||
|
||||
// Move the cursor to the specified position (the cursor needn't be visible).
|
||||
@ -177,7 +203,8 @@ notcurses_term_dimyx(const struct notcurses* n, int* rows, int* cols){
|
||||
API int ncplane_cursor_move_yx(struct ncplane* n, int y, int x);
|
||||
|
||||
// Get the current position of the cursor within n. y and/or x may be NULL.
|
||||
API void ncplane_cursor_yx(const struct ncplane* n, int* y, int* x);
|
||||
API void ncplane_cursor_yx(const struct ncplane* n, int* RESTRICT y,
|
||||
int* RESTRICT x);
|
||||
|
||||
// Replace the cell underneath the cursor with the provided cell 'c', and
|
||||
// advance the cursor by the width of the cell (but not past the end of the
|
||||
@ -244,6 +271,10 @@ API void ncplane_erase(struct ncplane* n);
|
||||
API int ncplane_fg_rgb8(struct ncplane* n, int r, int g, int b);
|
||||
API int ncplane_bg_rgb8(struct ncplane* n, int r, int g, int b);
|
||||
|
||||
// use the default color for the foreground/background
|
||||
API void ncplane_fg_default(struct ncplane* n);
|
||||
API void ncplane_bg_default(struct ncplane* n);
|
||||
|
||||
// Set the specified style bits for the ncplane 'n', whether they're actively
|
||||
// supported or not.
|
||||
API void ncplane_styles_set(struct ncplane* n, unsigned stylebits);
|
||||
@ -359,22 +390,36 @@ cell_rgb_blue(uint32_t rgb){
|
||||
#define CELL_BGDEFAULT_MASK 0x0000000040000000ull
|
||||
#define CELL_BG_MASK 0x0000000000ffffffull
|
||||
|
||||
static inline void
|
||||
cell_rgb_set_fg(uint64_t* channels, unsigned r, unsigned g, unsigned b){
|
||||
static inline int
|
||||
cell_rgb_set_fg(uint64_t* channels, int r, int g, int b){
|
||||
if(r >= 256 || g >= 256 || b >= 256){
|
||||
return -1;
|
||||
}
|
||||
if(r < 0 || g < 0 || b < 0){
|
||||
return -1;
|
||||
}
|
||||
uint64_t rgb = (r & 0xffull) << 48u;
|
||||
rgb |= (g & 0xffull) << 40u;
|
||||
rgb |= (b & 0xffull) << 32u;
|
||||
rgb |= CELL_FGDEFAULT_MASK;
|
||||
*channels = (*channels & ~(CELL_FGDEFAULT_MASK | CELL_FG_MASK)) | rgb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
cell_rgb_set_bg(uint64_t* channels, unsigned r, unsigned g, unsigned b){
|
||||
static inline int
|
||||
cell_rgb_set_bg(uint64_t* channels, int r, int g, int b){
|
||||
if(r >= 256 || g >= 256 || b >= 256){
|
||||
return -1;
|
||||
}
|
||||
if(r < 0 || g < 0 || b < 0){
|
||||
return -1;
|
||||
}
|
||||
uint64_t rgb = (r & 0xffull) << 16u;
|
||||
rgb |= (g & 0xffull) << 8u;
|
||||
rgb |= (b & 0xffull);
|
||||
rgb |= CELL_BGDEFAULT_MASK;
|
||||
*channels = (*channels & ~(CELL_BGDEFAULT_MASK | CELL_BG_MASK)) | rgb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -407,12 +452,24 @@ cell_inherits_style(const cell* c){
|
||||
return (c->channels & CELL_INHERITSTYLE_MASK);
|
||||
}
|
||||
|
||||
// use the default color for the foreground
|
||||
static inline void
|
||||
cell_fg_default(cell* c){
|
||||
c->channels |= CELL_FGDEFAULT_MASK;
|
||||
}
|
||||
|
||||
// is the cell using the terminal's default foreground color for its foreground?
|
||||
static inline bool
|
||||
cell_fg_default_p(const cell* c){
|
||||
return !(c->channels & CELL_FGDEFAULT_MASK);
|
||||
}
|
||||
|
||||
// use the default color for the background
|
||||
static inline void
|
||||
cell_bg_default(cell* c){
|
||||
c->channels |= CELL_BGDEFAULT_MASK;
|
||||
}
|
||||
|
||||
// is the cell using the terminal's default background color for its background?
|
||||
static inline bool
|
||||
cell_bg_default_p(const cell* c){
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
int box_demo(struct notcurses* nc){
|
||||
int ylen, xlen;
|
||||
notcurses_term_dimyx(nc, &ylen, &xlen);
|
||||
notcurses_term_dim_yx(nc, &ylen, &xlen);
|
||||
struct ncplane* n = notcurses_stdplane(nc);
|
||||
ncplane_erase(n);
|
||||
cell ul, ll, lr, ur, hl, vl;
|
||||
|
225
src/demo/demo.c
225
src/demo/demo.c
@ -16,37 +16,140 @@ struct timespec demodelay = {
|
||||
static void
|
||||
usage(const char* exe, int status){
|
||||
FILE* out = status == EXIT_SUCCESS ? stdout : stderr;
|
||||
fprintf(out, "usage: %s [ -h ] [ -k ] [ -d ns ]\n", exe);
|
||||
fprintf(out, " h: this message\n");
|
||||
fprintf(out, " k: keep screen; do not switch to alternate\n");
|
||||
fprintf(out, " d: delay in nanoseconds between demos\n");
|
||||
fprintf(out, "usage: %s [ -h ] [ -k ] [ -d ns ] [ demos ]\n", exe);
|
||||
fprintf(out, " -h: this message\n");
|
||||
fprintf(out, " -k: keep screen; do not switch to alternate\n");
|
||||
fprintf(out, " -d: delay in nanoseconds between demos\n");
|
||||
fprintf(out, "all demos are run if no specification is provided\n");
|
||||
fprintf(out, " i: run intro\n");
|
||||
fprintf(out, " s: run shuffle\n");
|
||||
fprintf(out, " u: run uniblock\n");
|
||||
fprintf(out, " m: run maxcolor\n");
|
||||
fprintf(out, " b: run box\n");
|
||||
fprintf(out, " g: run grid\n");
|
||||
fprintf(out, " w: run widecolors\n");
|
||||
exit(status);
|
||||
}
|
||||
|
||||
static int
|
||||
ext_demos(struct notcurses* nc){
|
||||
if(sliding_puzzle_demo(nc)){
|
||||
intro(struct notcurses* nc){
|
||||
struct ncplane* ncp;
|
||||
if((ncp = notcurses_stdplane(nc)) == NULL){
|
||||
return -1;
|
||||
}
|
||||
if(unicodeblocks_demo(nc)){
|
||||
ncplane_erase(ncp);
|
||||
int x, y, rows, cols;
|
||||
ncplane_dim_yx(ncp, &rows, &cols);
|
||||
cell c;
|
||||
cell_init(&c);
|
||||
const char* cstr = "Δ";
|
||||
cell_load(ncp, &c, cstr);
|
||||
cell_set_fg(&c, 200, 0, 200);
|
||||
int ys = 200 / (rows - 2);
|
||||
for(y = 5 ; y < rows - 6 ; ++y){
|
||||
cell_set_bg(&c, 0, y * ys , 0);
|
||||
for(x = 5 ; x < cols - 6 ; ++x){
|
||||
if(ncplane_cursor_move_yx(ncp, y, x)){
|
||||
return -1;
|
||||
}
|
||||
if(ncplane_putc(ncp, &c) != (int)strlen(cstr)){
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
cell_release(ncp, &c);
|
||||
cell ul = CELL_TRIVIAL_INITIALIZER;
|
||||
cell ur = CELL_TRIVIAL_INITIALIZER;
|
||||
cell ll = CELL_TRIVIAL_INITIALIZER;
|
||||
cell lr = CELL_TRIVIAL_INITIALIZER;
|
||||
cell vl = CELL_TRIVIAL_INITIALIZER;
|
||||
cell hl = CELL_TRIVIAL_INITIALIZER;
|
||||
if(ncplane_rounded_box_cells(ncp, &ul, &ur, &ll, &lr, &hl, &vl)){
|
||||
return -1;
|
||||
}
|
||||
if(maxcolor_demo(nc)){
|
||||
cell_set_fg(&ul, 90, 0, 90);
|
||||
cell_set_fg(&ur, 90, 0, 90);
|
||||
cell_set_fg(&ll, 90, 0, 90);
|
||||
cell_set_fg(&lr, 90, 0, 90);
|
||||
cell_set_fg(&vl, 90, 0, 90);
|
||||
cell_set_fg(&hl, 90, 0, 90);
|
||||
cell_set_bg(&ul, 0, 0, 180);
|
||||
cell_set_bg(&ur, 0, 0, 180);
|
||||
cell_set_bg(&ll, 0, 0, 180);
|
||||
cell_set_bg(&lr, 0, 0, 180);
|
||||
cell_set_bg(&vl, 0, 0, 180);
|
||||
cell_set_bg(&hl, 0, 0, 180);
|
||||
if(ncplane_cursor_move_yx(ncp, 4, 4)){
|
||||
return -1;
|
||||
}
|
||||
if(box_demo(nc)){
|
||||
if(ncplane_box(ncp, &ul, &ur, &ll, &lr, &hl, &vl, rows - 6, cols - 6)){
|
||||
return -1;
|
||||
}
|
||||
if(grid_demo(nc)){
|
||||
const char s1[] = " Die Welt ist alles, was der Fall ist. ";
|
||||
const char str[] = " Wovon man nicht sprechen kann, darüber muss man schweigen. ";
|
||||
if(ncplane_fg_rgb8(ncp, 192, 192, 192)){
|
||||
return -1;
|
||||
}
|
||||
if(widecolor_demo(nc)){
|
||||
if(ncplane_bg_rgb8(ncp, 0, 40, 0)){
|
||||
return -1;
|
||||
}
|
||||
if(ncplane_cursor_move_yx(ncp, rows / 2 - 2, (cols - strlen(s1) + 4) / 2)){
|
||||
return -1;
|
||||
}
|
||||
if(ncplane_putstr(ncp, s1) != (int)strlen(s1)){
|
||||
return -1;
|
||||
}
|
||||
if(ncplane_cursor_move_yx(ncp, rows / 2, (cols - strlen(str) + 4) / 2)){
|
||||
return -1;
|
||||
}
|
||||
ncplane_styles_on(ncp, CELL_STYLE_ITALIC);
|
||||
if(ncplane_putstr(ncp, str) != (int)strlen(str)){
|
||||
return -1;
|
||||
}
|
||||
ncplane_styles_off(ncp, CELL_STYLE_ITALIC);
|
||||
const wchar_t wstr[] = L"▏▁ ▂ ▃ ▄ ▅ ▆ ▇ █ █ ▇ ▆ ▅ ▄ ▃ ▂ ▁▕";
|
||||
char mbstr[128];
|
||||
if(wcstombs(mbstr, wstr, sizeof(mbstr)) <= 0){
|
||||
return -1;
|
||||
}
|
||||
if(ncplane_cursor_move_yx(ncp, rows / 2 - 5, (cols - wcslen(wstr) + 4) / 2)){
|
||||
return -1;
|
||||
}
|
||||
if(ncplane_putstr(ncp, mbstr) != (int)strlen(mbstr)){
|
||||
return -1;
|
||||
}
|
||||
if(notcurses_render(nc)){
|
||||
return -1;
|
||||
}
|
||||
nanosleep(&demodelay, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ext_demos(struct notcurses* nc, const char* demos){
|
||||
while(*demos){
|
||||
int ret = 0;
|
||||
switch(*demos){
|
||||
case 'i': ret = intro(nc); break;
|
||||
case 's': ret = sliding_puzzle_demo(nc); break;
|
||||
case 'u': ret = unicodeblocks_demo(nc); break;
|
||||
case 'm': ret = maxcolor_demo(nc); break;
|
||||
case 'b': ret = box_demo(nc); break;
|
||||
case 'g': ret = grid_demo(nc); break;
|
||||
case 'w': ret = widecolor_demo(nc); break;
|
||||
}
|
||||
if(ret){
|
||||
return ret;
|
||||
}
|
||||
++demos;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// returns the demos to be run as a string. on error, returns NULL. on no
|
||||
// specification, also returns NULL, heh. determine this by argv[optind];
|
||||
// if it's NULL, there were valid options, but no spec.
|
||||
static const char*
|
||||
handle_opts(int argc, char** argv, notcurses_options* opts){
|
||||
int c;
|
||||
memset(opts, 0, sizeof(*opts));
|
||||
@ -67,16 +170,18 @@ handle_opts(int argc, char** argv, notcurses_options* opts){
|
||||
}
|
||||
demodelay.tv_sec = ns / 1000000000;
|
||||
demodelay.tv_nsec = ns % 1000000000;
|
||||
break;
|
||||
break;
|
||||
}default:
|
||||
usage(*argv, EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
const char* demos = argv[optind];
|
||||
return demos;
|
||||
}
|
||||
|
||||
// just fucking around...for now
|
||||
int main(int argc, char** argv){
|
||||
srandom(time(NULL)); // a classic blunder
|
||||
struct notcurses* nc;
|
||||
notcurses_options nopts;
|
||||
struct ncplane* ncp;
|
||||
@ -84,8 +189,12 @@ int main(int argc, char** argv){
|
||||
fprintf(stderr, "Couldn't set locale based on user preferences\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if(handle_opts(argc, argv, &nopts)){
|
||||
return EXIT_FAILURE;
|
||||
const char* demos;
|
||||
if((demos = handle_opts(argc, argv, &nopts)) == NULL){
|
||||
if(argv[optind] != NULL){
|
||||
usage(*argv, EXIT_FAILURE);
|
||||
}
|
||||
demos = "isumbgw";
|
||||
}
|
||||
if((nc = notcurses_init(&nopts)) == NULL){
|
||||
return EXIT_FAILURE;
|
||||
@ -95,91 +204,7 @@ int main(int argc, char** argv){
|
||||
goto err;
|
||||
}
|
||||
nanosleep(&demodelay, NULL);
|
||||
int x, y, rows, cols;
|
||||
ncplane_dimyx(ncp, &rows, &cols);
|
||||
cell c;
|
||||
cell_init(&c);
|
||||
const char* cstr = "Δ";
|
||||
cell_load(ncp, &c, cstr);
|
||||
cell_set_fg(&c, 200, 0, 200);
|
||||
int ys = 200 / (rows - 2);
|
||||
for(y = 5 ; y < rows - 6 ; ++y){
|
||||
cell_set_bg(&c, 0, y * ys , 0);
|
||||
for(x = 5 ; x < cols - 6 ; ++x){
|
||||
if(ncplane_cursor_move_yx(ncp, y, x)){
|
||||
goto err;
|
||||
}
|
||||
if(ncplane_putc(ncp, &c) != (int)strlen(cstr)){
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
cell_release(ncp, &c);
|
||||
cell ul = CELL_TRIVIAL_INITIALIZER;
|
||||
cell ur = CELL_TRIVIAL_INITIALIZER;
|
||||
cell ll = CELL_TRIVIAL_INITIALIZER;
|
||||
cell lr = CELL_TRIVIAL_INITIALIZER;
|
||||
cell vl = CELL_TRIVIAL_INITIALIZER;
|
||||
cell hl = CELL_TRIVIAL_INITIALIZER;
|
||||
if(ncplane_rounded_box_cells(ncp, &ul, &ur, &ll, &lr, &hl, &vl)){
|
||||
goto err;
|
||||
}
|
||||
cell_set_fg(&ul, 90, 0, 90);
|
||||
cell_set_fg(&ur, 90, 0, 90);
|
||||
cell_set_fg(&ll, 90, 0, 90);
|
||||
cell_set_fg(&lr, 90, 0, 90);
|
||||
cell_set_fg(&vl, 90, 0, 90);
|
||||
cell_set_fg(&hl, 90, 0, 90);
|
||||
cell_set_bg(&ul, 0, 0, 180);
|
||||
cell_set_bg(&ur, 0, 0, 180);
|
||||
cell_set_bg(&ll, 0, 0, 180);
|
||||
cell_set_bg(&lr, 0, 0, 180);
|
||||
cell_set_bg(&vl, 0, 0, 180);
|
||||
cell_set_bg(&hl, 0, 0, 180);
|
||||
if(ncplane_cursor_move_yx(ncp, 4, 4)){
|
||||
goto err;
|
||||
}
|
||||
if(ncplane_box(ncp, &ul, &ur, &ll, &lr, &hl, &vl, rows - 6, cols - 6)){
|
||||
goto err;
|
||||
}
|
||||
const char s1[] = " Die Welt ist alles, was der Fall ist. ";
|
||||
const char str[] = " Wovon man nicht sprechen kann, darüber muss man schweigen. ";
|
||||
if(ncplane_fg_rgb8(ncp, 192, 192, 192)){
|
||||
goto err;
|
||||
}
|
||||
if(ncplane_bg_rgb8(ncp, 0, 40, 0)){
|
||||
goto err;
|
||||
}
|
||||
if(ncplane_cursor_move_yx(ncp, rows / 2 - 2, (cols - strlen(s1) + 4) / 2)){
|
||||
goto err;
|
||||
}
|
||||
if(ncplane_putstr(ncp, s1) != (int)strlen(s1)){
|
||||
goto err;
|
||||
}
|
||||
if(ncplane_cursor_move_yx(ncp, rows / 2, (cols - strlen(str) + 4) / 2)){
|
||||
goto err;
|
||||
}
|
||||
ncplane_styles_on(ncp, CELL_STYLE_ITALIC);
|
||||
if(ncplane_putstr(ncp, str) != (int)strlen(str)){
|
||||
goto err;
|
||||
}
|
||||
ncplane_styles_off(ncp, CELL_STYLE_ITALIC);
|
||||
const wchar_t wstr[] = L"▏▁ ▂ ▃ ▄ ▅ ▆ ▇ █ █ ▇ ▆ ▅ ▄ ▃ ▂ ▁▕";
|
||||
char mbstr[128];
|
||||
if(wcstombs(mbstr, wstr, sizeof(mbstr)) <= 0){
|
||||
goto err;
|
||||
}
|
||||
if(ncplane_cursor_move_yx(ncp, rows / 2 - 5, (cols - wcslen(wstr) + 4) / 2)){
|
||||
goto err;
|
||||
}
|
||||
if(ncplane_putstr(ncp, mbstr) != (int)strlen(mbstr)){
|
||||
goto err;
|
||||
}
|
||||
if(notcurses_render(nc)){
|
||||
goto err;
|
||||
}
|
||||
nanosleep(&demodelay, NULL);
|
||||
if(ext_demos(nc)){
|
||||
if(ext_demos(nc, demos)){
|
||||
goto err;
|
||||
}
|
||||
if(notcurses_stop(nc)){
|
||||
|
@ -75,7 +75,7 @@ static int
|
||||
gridswitch_demo(struct notcurses* nc, struct ncplane *n){
|
||||
ncplane_erase(n);
|
||||
int maxx, maxy;
|
||||
notcurses_term_dimyx(nc, &maxy, &maxx);
|
||||
notcurses_term_dim_yx(nc, &maxy, &maxx);
|
||||
int rs = 256 / maxx;
|
||||
int gs = 256 / (maxx + maxy);
|
||||
int bs = 256 / maxy;
|
||||
@ -140,7 +140,7 @@ static int
|
||||
gridinv_demo(struct notcurses* nc, struct ncplane *n){
|
||||
ncplane_erase(n);
|
||||
int maxx, maxy;
|
||||
notcurses_term_dimyx(nc, &maxy, &maxx);
|
||||
notcurses_term_dim_yx(nc, &maxy, &maxx);
|
||||
int rs = 256 / maxx;
|
||||
int gs = 256 / (maxx + maxy);
|
||||
int bs = 256 / maxy;
|
||||
@ -204,7 +204,7 @@ gridinv_demo(struct notcurses* nc, struct ncplane *n){
|
||||
// red across, blue down, green from UL to LR
|
||||
int grid_demo(struct notcurses* nc){
|
||||
int maxx, maxy;
|
||||
notcurses_term_dimyx(nc, &maxy, &maxx);
|
||||
notcurses_term_dim_yx(nc, &maxy, &maxx);
|
||||
int rs = 256 / maxx;
|
||||
int gs = 256 / (maxx + maxy);
|
||||
int bs = 256 / maxy;
|
||||
|
@ -30,7 +30,7 @@ grow_rgb(uint32_t* rgb){
|
||||
// and that we can write to every coordinate.
|
||||
int maxcolor_demo(struct notcurses* nc){
|
||||
int maxx, maxy;
|
||||
notcurses_term_dimyx(nc, &maxy, &maxx);
|
||||
notcurses_term_dim_yx(nc, &maxy, &maxx);
|
||||
struct ncplane* n = notcurses_stdplane(nc);
|
||||
ncplane_fg_rgb8(n, 255, 255, 255);
|
||||
cell ul = CELL_TRIVIAL_INITIALIZER;
|
||||
|
@ -4,14 +4,66 @@
|
||||
#include "demo.h"
|
||||
|
||||
// FIXME do the bigger dimension on the screen's bigger dimension
|
||||
#define CHUNKS_VERT 8
|
||||
#define CHUNKS_HORZ 16
|
||||
#define CHUNKS_VERT 6
|
||||
#define CHUNKS_HORZ 12
|
||||
#define MOVES 45
|
||||
#define GIG 1000000000
|
||||
|
||||
// we take (MOVES / 5) * demodelay to play MOVES moves
|
||||
static int
|
||||
play(struct notcurses* nc, struct ncplane** chunks){
|
||||
const int chunkcount = CHUNKS_VERT * CHUNKS_HORZ;
|
||||
uint64_t movens = (MOVES / 5) * (demodelay.tv_sec * GIG + demodelay.tv_nsec);
|
||||
struct timespec movetime = {
|
||||
.tv_sec = movens / MOVES / GIG,
|
||||
.tv_nsec = movens / MOVES % GIG,
|
||||
};
|
||||
// struct ncplane* n = notcurses_stdplane(nc);
|
||||
int hole = random() % chunkcount;
|
||||
int holex, holey;
|
||||
ncplane_yx(chunks[hole], &holey, &holex);
|
||||
ncplane_destroy(chunks[hole]);
|
||||
chunks[hole] = NULL;
|
||||
int m;
|
||||
int lastdir = -1;
|
||||
for(m = 0 ; m < MOVES ; ++m){
|
||||
int mover = chunkcount;
|
||||
int direction;
|
||||
do{
|
||||
direction = random() % 4;
|
||||
switch(direction){
|
||||
case 3: // up
|
||||
if(lastdir != 1 && hole >= CHUNKS_HORZ){ mover = hole - CHUNKS_HORZ; } break;
|
||||
case 2: // right
|
||||
if(lastdir != 0 && hole % CHUNKS_HORZ < CHUNKS_HORZ - 1){ mover = hole + 1; } break;
|
||||
case 1: // down
|
||||
if(lastdir != 3 && hole < chunkcount - CHUNKS_HORZ){ mover = hole + CHUNKS_HORZ; } break;
|
||||
case 0: // left
|
||||
if(lastdir != 2 && hole % CHUNKS_HORZ){ mover = hole - 1; } break;
|
||||
}
|
||||
}while(mover == chunkcount);
|
||||
lastdir = direction;
|
||||
int newholex, newholey;
|
||||
ncplane_yx(chunks[mover], &newholey, &newholex);
|
||||
ncplane_move_yx(chunks[mover], holey, holex);
|
||||
holey = newholey;
|
||||
holex = newholex;
|
||||
chunks[hole] = chunks[mover];
|
||||
chunks[mover] = NULL;
|
||||
hole = mover;
|
||||
if(notcurses_render(nc)){
|
||||
return -1;
|
||||
}
|
||||
nanosleep(&movetime, NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fill_chunk(struct ncplane* n, int idx){
|
||||
char buf[4];
|
||||
int maxy, maxx;
|
||||
ncplane_dimyx(n, &maxy, &maxx);
|
||||
ncplane_dim_yx(n, &maxy, &maxx);
|
||||
snprintf(buf, sizeof(buf), "%03d", idx);
|
||||
cell ul = CELL_TRIVIAL_INITIALIZER, ur = CELL_TRIVIAL_INITIALIZER;
|
||||
cell ll = CELL_TRIVIAL_INITIALIZER, lr = CELL_TRIVIAL_INITIALIZER;
|
||||
@ -19,15 +71,7 @@ fill_chunk(struct ncplane* n, int idx){
|
||||
if(ncplane_double_box_cells(n, &ul, &ur, &ll, &lr, &hl, &vl)){
|
||||
return -1;
|
||||
}
|
||||
int r = 255, g = 255, b = 255;
|
||||
switch(idx % 6){
|
||||
case 5: r -= (idx % 64) * 4; break;
|
||||
case 4: g -= (idx % 64) * 4; break;
|
||||
case 3: b -= (idx % 64) * 4; break;
|
||||
case 2: r -= (idx % 64) * 4; b -= (idx % 64) * 4; break;
|
||||
case 1: r -= (idx % 64) * 4; g -= (idx % 64) * 4; break;
|
||||
case 0: b -= (idx % 64) * 4; g -= (idx % 64) * 4; break;
|
||||
}
|
||||
int r = random() % 256, g = random() % 256, b = random() % 256;
|
||||
cell_set_fg(&ul, r, g, b);
|
||||
cell_set_fg(&ur, r, g, b);
|
||||
cell_set_fg(&ll, r, g, b);
|
||||
@ -55,6 +99,36 @@ fill_chunk(struct ncplane* n, int idx){
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
draw_bounding_box(struct ncplane* n, int yoff, int xoff, int chunky, int chunkx){
|
||||
int ret = -1;
|
||||
cell ul = CELL_TRIVIAL_INITIALIZER, ur = CELL_TRIVIAL_INITIALIZER;
|
||||
cell ll = CELL_TRIVIAL_INITIALIZER, lr = CELL_TRIVIAL_INITIALIZER;
|
||||
cell hl = CELL_TRIVIAL_INITIALIZER, vl = CELL_TRIVIAL_INITIALIZER;
|
||||
if(ncplane_rounded_box_cells(n, &ul, &ur, &ll, &lr, &hl, &vl)){
|
||||
return -1;
|
||||
}
|
||||
cell_set_fg(&ul, 180, 80, 180);
|
||||
cell_set_fg(&ur, 180, 80, 180);
|
||||
cell_set_fg(&ll, 180, 80, 180);
|
||||
cell_set_fg(&lr, 180, 80, 180);
|
||||
cell_set_fg(&hl, 180, 80, 180);
|
||||
cell_set_fg(&vl, 180, 80, 180);
|
||||
ncplane_cursor_move_yx(n, yoff, xoff);
|
||||
if(!ncplane_box(n, &ul, &ur, &ll, &lr, &hl, &vl,
|
||||
CHUNKS_VERT * chunky + yoff + 1,
|
||||
CHUNKS_HORZ * chunkx + xoff + 1)){
|
||||
ret = 0;
|
||||
}
|
||||
cell_release(n, &ul);
|
||||
cell_release(n, &ur);
|
||||
cell_release(n, &ll);
|
||||
cell_release(n, &lr);
|
||||
cell_release(n, &hl);
|
||||
cell_release(n, &vl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// break whatever's on the screen into panels and shift them around like a
|
||||
// sliding puzzle. FIXME once we have copying, anyway. until then, just use
|
||||
// background colors.
|
||||
@ -62,17 +136,21 @@ int sliding_puzzle_demo(struct notcurses* nc){
|
||||
int ret = -1, z;
|
||||
int maxx, maxy;
|
||||
int chunky, chunkx;
|
||||
notcurses_term_dimyx(nc, &maxy, &maxx);
|
||||
notcurses_term_dim_yx(nc, &maxy, &maxx);
|
||||
// want at least 2x2 for each sliding chunk
|
||||
if(maxy < CHUNKS_VERT * 2 || maxx < CHUNKS_HORZ * 2){
|
||||
fprintf(stderr, "Terminal too small, need at least %dx%d\n",
|
||||
CHUNKS_HORZ, CHUNKS_VERT);
|
||||
return -1;
|
||||
}
|
||||
// we want an 8x8 grid of chunks. the leftover space will be unused
|
||||
chunky = maxy / CHUNKS_VERT;
|
||||
chunkx = maxx / CHUNKS_HORZ;
|
||||
int chunkcount = CHUNKS_VERT * CHUNKS_HORZ;
|
||||
// we want an 8x8 grid of chunks with a border. the leftover space will be unused
|
||||
chunky = (maxy - 2) / CHUNKS_VERT;
|
||||
chunkx = (maxx - 2) / CHUNKS_HORZ;
|
||||
int wastey = ((maxy - 2) % CHUNKS_VERT) / 2;
|
||||
int wastex = ((maxx - 2) % CHUNKS_HORZ) / 2;
|
||||
struct ncplane* n = notcurses_stdplane(nc);
|
||||
ncplane_erase(n);
|
||||
const int chunkcount = CHUNKS_VERT * CHUNKS_HORZ;
|
||||
struct ncplane** chunks = malloc(sizeof(*chunks) * chunkcount);
|
||||
if(chunks == NULL){
|
||||
return -1;
|
||||
@ -83,22 +161,28 @@ int sliding_puzzle_demo(struct notcurses* nc){
|
||||
for(cx = 0 ; cx < CHUNKS_HORZ ; ++cx){
|
||||
const int idx = cy * CHUNKS_HORZ + cx;
|
||||
chunks[idx] =
|
||||
notcurses_newplane(nc, chunky, chunkx, cy * chunky, cx * chunkx, NULL);
|
||||
notcurses_newplane(nc, chunky, chunkx, cy * chunky + wastey + 1,
|
||||
cx * chunkx + wastex + 1, NULL);
|
||||
if(chunks[idx] == NULL){
|
||||
goto done;
|
||||
}
|
||||
fill_chunk(chunks[idx], idx);
|
||||
}
|
||||
}
|
||||
if(draw_bounding_box(n, wastey, wastex, chunky, chunkx)){
|
||||
return -1;
|
||||
}
|
||||
if(notcurses_render(nc)){
|
||||
goto done;
|
||||
}
|
||||
nanosleep(&demodelay, NULL);
|
||||
if(play(nc, chunks)){
|
||||
goto done;
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
for(z = 0 ; z < chunkcount ; ++z){
|
||||
ncplane_destroy(nc, chunks[z]);
|
||||
ncplane_destroy(chunks[z]);
|
||||
}
|
||||
free(chunks);
|
||||
return ret;
|
||||
|
@ -13,7 +13,7 @@
|
||||
int unicodeblocks_demo(struct notcurses* nc){
|
||||
struct ncplane* n = notcurses_stdplane(nc);
|
||||
int maxx, maxy;
|
||||
notcurses_term_dimyx(nc, &maxy, &maxx);
|
||||
notcurses_term_dim_yx(nc, &maxy, &maxx);
|
||||
// some blocks are good for the printing, some less so. some are only
|
||||
// marginally covered by mainstream fonts, some not at all. we explicitly
|
||||
// list the ones we want.
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
static int
|
||||
message(struct ncplane* n, int maxy, int maxx, int num, int total){
|
||||
ncplane_bg_default(n);
|
||||
cell ul, ur, ll, lr, vl, hl;
|
||||
cell_init(&ul);
|
||||
cell_init(&ur);
|
||||
@ -19,9 +20,8 @@ message(struct ncplane* n, int maxy, int maxx, int num, int total){
|
||||
}
|
||||
ncplane_cursor_move_yx(n, 3, 1);
|
||||
ncplane_fg_rgb8(n, 255, 255, 255);
|
||||
ncplane_bg_rgb8(n, 0, 20, 0);
|
||||
ncplane_styles_on(n, CELL_STYLE_BOLD);
|
||||
if(ncplane_box(n, &ul, &ur, &ll, &lr, &hl, &vl, 5, 54)){
|
||||
if(ncplane_box(n, &ul, &ur, &ll, &lr, &hl, &vl, 5, 56)){
|
||||
return -1;
|
||||
}
|
||||
cell_load(n, &ll, "╨");
|
||||
@ -41,13 +41,12 @@ message(struct ncplane* n, int maxy, int maxx, int num, int total){
|
||||
ncplane_hline(n, &hl, 13);
|
||||
cell_load(n, &ur, "╗");
|
||||
ncplane_putc(n, &ur);
|
||||
ncplane_bg_rgb8(n, 0, 0, 0);
|
||||
ncplane_cursor_move_yx(n, 2, 5);
|
||||
ncplane_printf(n, " %dx%d (%d/%d) ", maxx, maxy, num, total);
|
||||
ncplane_cursor_move_yx(n, 4, 2);
|
||||
ncplane_styles_off(n, CELL_STYLE_BOLD);
|
||||
ncplane_fg_rgb8(n, 200, 20, 200);
|
||||
ncplane_putstr(n, " 🔥wide chars, multiple colors, resize awareness…🔥 ");
|
||||
ncplane_putstr(n, " 🔥wide chars, multiple colors, resize awareness…🔥 ");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -261,7 +260,7 @@ int widecolor_demo(struct notcurses* nc){
|
||||
const int step = steps[i];
|
||||
//do{
|
||||
int y, x, maxy, maxx;
|
||||
ncplane_dimyx(n, &maxy, &maxx);
|
||||
ncplane_dim_yx(n, &maxy, &maxx);
|
||||
int rgb = start;
|
||||
if(ncplane_cursor_move_yx(n, 0, 0)){
|
||||
return -1;
|
||||
|
@ -106,7 +106,7 @@ ncvisual* ncplane_visual_open(struct ncplane* nc, const char* filename){
|
||||
fprintf(stderr, "Couldn't create %s (%s)\n", filename, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
ncplane_dimyx(nc, &ncv->dstheight, &ncv->dstwidth);
|
||||
ncplane_dim_yx(nc, &ncv->dstheight, &ncv->dstwidth);
|
||||
int ret = avformat_open_input(&ncv->fmtctx, filename, NULL, NULL);
|
||||
if(ret < 0){
|
||||
fprintf(stderr, "Couldn't open %s (%s)\n", filename, av_err2str(ret));
|
||||
|
@ -43,6 +43,7 @@ typedef struct ncplane {
|
||||
uint64_t channels; // works the same way as cells
|
||||
uint32_t attrword; // same deal as in a cell
|
||||
void* userptr; // slot for the user to stick some opaque pointer
|
||||
struct notcurses* nc; // notcurses object of which we are a part
|
||||
} ncplane;
|
||||
|
||||
typedef struct ncstats {
|
||||
@ -200,7 +201,7 @@ const void* ncplane_userptr_const(const ncplane* n){
|
||||
return n->userptr;
|
||||
}
|
||||
|
||||
void ncplane_dimyx(const ncplane* n, int* rows, int* cols){
|
||||
void ncplane_dim_yx(const ncplane* n, int* rows, int* cols){
|
||||
if(rows){
|
||||
*rows = n->leny;
|
||||
}
|
||||
@ -296,6 +297,7 @@ ncplane_create(notcurses* nc, int rows, int cols, int yoff, int xoff){
|
||||
egcpool_init(&p->pool);
|
||||
p->z = nc->top;
|
||||
nc->top = p;
|
||||
p->nc = nc;
|
||||
return p;
|
||||
}
|
||||
|
||||
@ -315,6 +317,7 @@ create_initial_ncplane(notcurses* nc){
|
||||
// array of *rows * *cols cells (may be NULL if *rows == *cols == 0). Gets the
|
||||
// new size, and copies what can be copied from the old stdscr. Assumes that
|
||||
// the screen is always anchored in the same place.
|
||||
// FIXME rewrite this in terms of ncpanel_resize(n->stdscr)
|
||||
int notcurses_resize(notcurses* n){
|
||||
int oldrows = n->stdscr->leny;
|
||||
int oldcols = n->stdscr->lenx;
|
||||
@ -372,21 +375,113 @@ ncplane* notcurses_newplane(notcurses* nc, int rows, int cols,
|
||||
return n;
|
||||
}
|
||||
|
||||
int ncplane_destroy(notcurses* nc, ncplane* ncp){
|
||||
int ncplane_resize(ncplane* n, int keepy, int keepx, int keepleny,
|
||||
int keeplenx, int yoff, int xoff, int ylen, int xlen){
|
||||
if(n == n->nc->stdscr){
|
||||
return -1;
|
||||
}
|
||||
if(keepy < 0 || keepx < 0){ // can't retain negative size
|
||||
return -1;
|
||||
}
|
||||
if(ylen <= 0 || xlen <= 0){ // can't resize to trivial or negative size
|
||||
return -1;
|
||||
}
|
||||
if((!keepy && keepx) || (keepy && !keepx)){ // both must be 0
|
||||
return -1;
|
||||
}
|
||||
if(ylen < keepleny || xlen < keeplenx){ // can't be smaller than our keep
|
||||
return -1;
|
||||
}
|
||||
// we're good to resize. we'll need alloc up a new framebuffer, and copy in
|
||||
// those elements we're retaining, zeroing out the rest. alternatively, if
|
||||
// we've shrunk, we will be filling the new structure.
|
||||
int keptarea = keepy * keepx;
|
||||
int newarea = ylen * xlen;
|
||||
cell* fb = malloc(sizeof(*fb) * newarea);
|
||||
if(fb == NULL){
|
||||
return -1;
|
||||
}
|
||||
// update the cursor, if it would otherwise be off-plane
|
||||
if(n->y >= ylen){
|
||||
n->y = ylen - 1;
|
||||
}
|
||||
if(n->x >= xlen){
|
||||
n->x = xlen - 1;
|
||||
}
|
||||
cell* preserved = n->fb;
|
||||
n->fb = fb;
|
||||
n->absy = n->absy + keepy - yoff;
|
||||
n->absx = n->absx + keepx - xoff;
|
||||
// if we're keeping nothing, dump the old egcspool. otherwise, we go ahead
|
||||
// and keep it. perhaps we ought compact it?
|
||||
if(keptarea == 0){ // keep nothing, resize/move only
|
||||
memset(fb, 0, sizeof(*fb) * newarea);
|
||||
egcpool_dump(&n->pool);
|
||||
n->lenx = xlen;
|
||||
n->leny = ylen;
|
||||
free(preserved);
|
||||
return 0;
|
||||
}
|
||||
// we currently have maxy rows of maxx cells each. we will be keeping rows
|
||||
// keepy..keepy + keepleny - 1 and columns keepx..keepx + keeplenx - 1. they
|
||||
// will end up at keepy + yoff..keepy + keepleny - 1 + yoff and
|
||||
// keepx + xoff..keepx + keeplenx - 1 + xoff. everything else is zerod out.
|
||||
int itery;
|
||||
// we'll prepare each cell in our new framebuffer with either zeroes or a copy
|
||||
// from the old one.
|
||||
int sourceline = keepy;
|
||||
for(itery = 0 ; itery < ylen ; ++itery){
|
||||
int copyoff = itery * xlen; // our target at any given time
|
||||
// if we have nothing copied to this line, zero it out in one go
|
||||
if(itery < keepy + yoff || itery > keepy + keepleny - 1 + yoff){
|
||||
memset(fb + copyoff, 0, sizeof(*fb) * xlen);
|
||||
continue;
|
||||
}
|
||||
// we do have something to copy, and zero, one, or two regions to zero out
|
||||
int copied = 0;
|
||||
if(xoff < 0){
|
||||
memset(fb + copyoff, 0, sizeof(*fb) * -xoff);
|
||||
copyoff += -xoff;
|
||||
copied += -xoff;
|
||||
}
|
||||
const int sourceidx = fbcellidx(n, sourceline, keepx);
|
||||
memcpy(fb + copyoff, preserved + sourceidx, sizeof(*fb) * keepx);
|
||||
copyoff += keepx;
|
||||
copied += keepx;
|
||||
if(xlen > copied){
|
||||
memset(fb + copyoff, 0, sizeof(*fb) * (xlen - copied));
|
||||
}
|
||||
++sourceline;
|
||||
}
|
||||
free(preserved);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ncplane**
|
||||
find_above_ncplane(ncplane* n){
|
||||
notcurses* nc = n->nc;
|
||||
ncplane** above = &nc->top;
|
||||
while(*above){
|
||||
if(*above == n){
|
||||
return above;
|
||||
}
|
||||
above = &(*above)->z;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ncplane_destroy(ncplane* ncp){
|
||||
if(ncp == NULL){
|
||||
return 0;
|
||||
}
|
||||
if(nc->stdscr == ncp){
|
||||
if(ncp->nc->stdscr == ncp){
|
||||
return -1;
|
||||
}
|
||||
ncplane** above;
|
||||
// pull it out of the list
|
||||
for(above = &nc->top ; *above ; above = &(*above)->z){
|
||||
if(*above == ncp){
|
||||
*above = ncp->z;
|
||||
free_plane(ncp);
|
||||
return 0;
|
||||
}
|
||||
ncplane** above = find_above_ncplane(ncp);
|
||||
if(*above){
|
||||
*above = ncp->z; // splice it out of the list
|
||||
free_plane(ncp);
|
||||
return 0;
|
||||
}
|
||||
// couldn't find it in our stack. don't try to free this interloper.
|
||||
return -1;
|
||||
@ -570,26 +665,20 @@ int notcurses_stop(notcurses* nc){
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ncplane_fg_default(struct ncplane* n){
|
||||
n->channels |= CELL_FGDEFAULT_MASK;
|
||||
}
|
||||
|
||||
void ncplane_bg_default(struct ncplane* n){
|
||||
n->channels |= CELL_BGDEFAULT_MASK;
|
||||
}
|
||||
|
||||
int ncplane_bg_rgb8(ncplane* n, int r, int g, int b){
|
||||
if(r >= 256 || g >= 256 || b >= 256){
|
||||
return -1;
|
||||
}
|
||||
if(r < 0 || g < 0 || b < 0){
|
||||
return -1;
|
||||
}
|
||||
cell_rgb_set_bg(&n->channels, r, g, b);
|
||||
return 0;
|
||||
return cell_rgb_set_bg(&n->channels, r, g, b);
|
||||
}
|
||||
|
||||
int ncplane_fg_rgb8(ncplane* n, int r, int g, int b){
|
||||
if(r >= 256 || g >= 256 || b >= 256){
|
||||
return -1;
|
||||
}
|
||||
if(r < 0 || g < 0 || b < 0){
|
||||
return -1;
|
||||
}
|
||||
cell_rgb_set_fg(&n->channels, r, g, b);
|
||||
return 0;
|
||||
return cell_rgb_set_fg(&n->channels, r, g, b);
|
||||
}
|
||||
|
||||
// 3 for foreground, 4 for background, ugh FIXME
|
||||
@ -804,6 +893,60 @@ visible_cell(const notcurses* nc, int y, int x, const ncplane** retp){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 'n' ends up above 'above'
|
||||
int ncplane_move_above(ncplane* restrict n, ncplane* restrict above){
|
||||
ncplane** an = find_above_ncplane(n);
|
||||
if(an == NULL){
|
||||
return -1;
|
||||
}
|
||||
ncplane** aa = find_above_ncplane(above);
|
||||
if(aa == NULL){
|
||||
return -1;
|
||||
}
|
||||
*an = n->z; // splice n out
|
||||
n->z = above; // attach above below n
|
||||
*aa = n; // spline n in above
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 'n' ends up below 'below'
|
||||
int ncplane_move_below(ncplane* restrict n, ncplane* restrict below){
|
||||
ncplane** an = find_above_ncplane(n);
|
||||
if(an == NULL){
|
||||
return -1;
|
||||
}
|
||||
*an = n->z; // splice n out
|
||||
n->z = below->z; // reattach subbelow list to n
|
||||
below->z = n; // splice n in below
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ncplane_move_top(ncplane* n){
|
||||
ncplane** an = find_above_ncplane(n);
|
||||
if(an == NULL){
|
||||
return -1;
|
||||
}
|
||||
*an = n->z; // splice n out
|
||||
n->z = n->nc->top;
|
||||
n->nc->top = n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ncplane_move_bottom(ncplane* n){
|
||||
ncplane** an = find_above_ncplane(n);
|
||||
if(an == NULL){
|
||||
return -1;
|
||||
}
|
||||
*an = n->z; // splice n out
|
||||
an = &n->nc->top;
|
||||
while(*an){
|
||||
an = &(*an)->z;
|
||||
}
|
||||
*an = n;
|
||||
n->z = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// FIXME this needs to keep an invalidation bitmap, rather than blitting the
|
||||
// world every time
|
||||
int notcurses_render(notcurses* nc){
|
||||
@ -821,6 +964,8 @@ int notcurses_render(notcurses* nc){
|
||||
term_emit(nc->clear, out, false);
|
||||
for(y = 0 ; y < nc->stdscr->leny ; ++y){
|
||||
// FIXME previous line could have ended halfway through multicol. what happens?
|
||||
// FIXME also must explicitly move to next line if we're to deal with
|
||||
// surprise enlargenings, otherwise we just print forward
|
||||
for(x = 0 ; x < nc->stdscr->lenx ; ++x){
|
||||
unsigned r, g, b, br, bg, bb;
|
||||
const ncplane* p;
|
||||
@ -1078,7 +1223,7 @@ int ncplane_box(ncplane* n, const cell* ul, const cell* ur,
|
||||
if(xstop < xoff + 1){
|
||||
return -1;
|
||||
}
|
||||
ncplane_dimyx(n, &ymax, &xmax);
|
||||
ncplane_dim_yx(n, &ymax, &xmax);
|
||||
if(xstop >= xmax || ystop >= ymax){
|
||||
return -1;
|
||||
}
|
||||
@ -1126,6 +1271,16 @@ int ncplane_box(ncplane* n, const cell* ul, const cell* ur,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ncplane_move_yx(ncplane* n, int y, int x){
|
||||
n->absy = y;
|
||||
n->absx = x;
|
||||
}
|
||||
|
||||
void ncplane_yx(const ncplane* n, int* y, int* x){
|
||||
*y = n->absy;
|
||||
*x = n->absx;
|
||||
}
|
||||
|
||||
void ncplane_erase(ncplane* n){
|
||||
memset(n->fb, 0, sizeof(*n->fb) * n->lenx * n->leny);
|
||||
egcpool_dump(&n->pool);
|
||||
|
@ -38,9 +38,9 @@ TEST_F(NcplaneTest, StdPlanePosition) {
|
||||
// Dimensions of the standard plane ought be the same as those of the context
|
||||
TEST_F(NcplaneTest, StdPlaneDimensions) {
|
||||
int cols, rows;
|
||||
notcurses_term_dimyx(nc_, &rows, &cols);
|
||||
notcurses_term_dim_yx(nc_, &rows, &cols);
|
||||
int ncols, nrows;
|
||||
ncplane_dimyx(n_, &nrows, &ncols);
|
||||
ncplane_dim_yx(n_, &nrows, &ncols);
|
||||
EXPECT_EQ(rows, nrows);
|
||||
EXPECT_EQ(cols, ncols);
|
||||
}
|
||||
@ -48,7 +48,7 @@ TEST_F(NcplaneTest, StdPlaneDimensions) {
|
||||
// Verify that we can move to all four coordinates of the standard plane
|
||||
TEST_F(NcplaneTest, MoveStdPlaneDimensions) {
|
||||
int cols, rows;
|
||||
notcurses_term_dimyx(nc_, &rows, &cols);
|
||||
notcurses_term_dim_yx(nc_, &rows, &cols);
|
||||
EXPECT_EQ(0, ncplane_cursor_move_yx(n_, 0, 0));
|
||||
int x, y;
|
||||
ncplane_cursor_yx(n_, &y, &x);
|
||||
@ -71,7 +71,7 @@ TEST_F(NcplaneTest, MoveStdPlaneDimensions) {
|
||||
// Verify that we can move to all four coordinates of the standard plane
|
||||
TEST_F(NcplaneTest, MoveBeyondPlaneFails) {
|
||||
int cols, rows;
|
||||
notcurses_term_dimyx(nc_, &rows, &cols);
|
||||
notcurses_term_dim_yx(nc_, &rows, &cols);
|
||||
EXPECT_NE(0, ncplane_cursor_move_yx(n_, -1, 0));
|
||||
EXPECT_NE(0, ncplane_cursor_move_yx(n_, -1, -1));
|
||||
EXPECT_NE(0, ncplane_cursor_move_yx(n_, 0, -1));
|
||||
@ -128,7 +128,7 @@ TEST_F(NcplaneTest, EmitStr) {
|
||||
|
||||
TEST_F(NcplaneTest, HorizontalLines) {
|
||||
int x, y;
|
||||
ncplane_dimyx(n_, &y, &x);
|
||||
ncplane_dim_yx(n_, &y, &x);
|
||||
ASSERT_LT(0, y);
|
||||
ASSERT_LT(0, x);
|
||||
cell c{};
|
||||
@ -147,7 +147,7 @@ TEST_F(NcplaneTest, HorizontalLines) {
|
||||
|
||||
TEST_F(NcplaneTest, VerticalLines) {
|
||||
int x, y;
|
||||
ncplane_dimyx(n_, &y, &x);
|
||||
ncplane_dim_yx(n_, &y, &x);
|
||||
ASSERT_LT(0, y);
|
||||
ASSERT_LT(0, x);
|
||||
cell c{};
|
||||
@ -167,7 +167,7 @@ TEST_F(NcplaneTest, VerticalLines) {
|
||||
// reject attempts to draw boxes beyond the boundaries of the ncplane
|
||||
TEST_F(NcplaneTest, BadlyPlacedBoxen) {
|
||||
int x, y;
|
||||
ncplane_dimyx(n_, &y, &x);
|
||||
ncplane_dim_yx(n_, &y, &x);
|
||||
ASSERT_LT(2, y);
|
||||
ASSERT_LT(2, x);
|
||||
cell ul{}, ll{}, lr{}, ur{}, hl{}, vl{};
|
||||
@ -188,7 +188,7 @@ TEST_F(NcplaneTest, BadlyPlacedBoxen) {
|
||||
|
||||
TEST_F(NcplaneTest, PerimeterBox) {
|
||||
int x, y;
|
||||
ncplane_dimyx(n_, &y, &x);
|
||||
ncplane_dim_yx(n_, &y, &x);
|
||||
ASSERT_LT(2, y);
|
||||
ASSERT_LT(2, x);
|
||||
cell ul{}, ll{}, lr{}, ur{}, hl{}, vl{};
|
||||
@ -205,7 +205,7 @@ TEST_F(NcplaneTest, PerimeterBox) {
|
||||
|
||||
TEST_F(NcplaneTest, PerimeterBoxSized) {
|
||||
int x, y;
|
||||
ncplane_dimyx(n_, &y, &x);
|
||||
ncplane_dim_yx(n_, &y, &x);
|
||||
ASSERT_LT(2, y);
|
||||
ASSERT_LT(2, x);
|
||||
cell ul{}, ll{}, lr{}, ur{}, hl{}, vl{};
|
||||
@ -293,7 +293,7 @@ TEST_F(NcplaneTest, UserPtr) {
|
||||
EXPECT_EQ(nullptr, ncplane_userptr(n_));
|
||||
int x, y;
|
||||
void* sentinel = &x;
|
||||
notcurses_term_dimyx(nc_, &y, &x);
|
||||
notcurses_term_dim_yx(nc_, &y, &x);
|
||||
struct ncplane* ncp = notcurses_newplane(nc_, y, x, 0, 0, sentinel);
|
||||
ASSERT_NE(ncp, nullptr);
|
||||
EXPECT_EQ(&x, ncplane_userptr(ncp));
|
||||
@ -302,23 +302,92 @@ TEST_F(NcplaneTest, UserPtr) {
|
||||
sentinel = &y;
|
||||
EXPECT_EQ(nullptr, ncplane_set_userptr(ncp, sentinel));
|
||||
EXPECT_EQ(&y, ncplane_userptr(ncp));
|
||||
EXPECT_EQ(0, ncplane_destroy(nc_, ncp));
|
||||
EXPECT_EQ(0, ncplane_destroy(ncp));
|
||||
}
|
||||
|
||||
// create a new plane, the same size as the terminal, and verify that it
|
||||
// occupies the same dimensions as the standard plane.
|
||||
TEST_F(NcplaneTest, NewPlaneSameSize) {
|
||||
int x, y;
|
||||
notcurses_term_dimyx(nc_, &y, &x);
|
||||
notcurses_term_dim_yx(nc_, &y, &x);
|
||||
struct ncplane* ncp = notcurses_newplane(nc_, y, x, 0, 0, nullptr);
|
||||
ASSERT_NE(nullptr, ncp);
|
||||
int px, py;
|
||||
ncplane_dimyx(ncp, &py, &px);
|
||||
ncplane_dim_yx(ncp, &py, &px);
|
||||
EXPECT_EQ(y, py);
|
||||
EXPECT_EQ(x, px);
|
||||
int sx, sy;
|
||||
ncplane_dimyx(n_, &sy, &sx);
|
||||
ncplane_dim_yx(n_, &sy, &sx);
|
||||
EXPECT_EQ(sy, py);
|
||||
EXPECT_EQ(sx, px);
|
||||
EXPECT_EQ(0, ncplane_destroy(nc_, ncp));
|
||||
EXPECT_EQ(0, ncplane_destroy(ncp));
|
||||
}
|
||||
|
||||
TEST_F(NcplaneTest, ShrinkPlane) {
|
||||
int maxx, maxy;
|
||||
int x = 0, y = 0;
|
||||
notcurses_term_dim_yx(nc_, &maxy, &maxx);
|
||||
struct ncplane* newp = notcurses_newplane(nc_, maxy, maxx, y, x, nullptr);
|
||||
ASSERT_NE(nullptr, newp);
|
||||
while(y > 4 && x > 4){
|
||||
maxx -= 2;
|
||||
maxy -= 2;
|
||||
++x;
|
||||
++y;
|
||||
ASSERT_EQ(0, ncplane_resize(newp, 1, 1, maxy, maxx, 1, 1, maxy, maxx));
|
||||
// FIXME check dims, pos
|
||||
}
|
||||
while(y > 4){
|
||||
maxy -= 2;
|
||||
++y;
|
||||
ASSERT_EQ(0, ncplane_resize(newp, 1, 0, maxy, maxx, 1, 0, maxy, maxx));
|
||||
// FIXME check dims, pos
|
||||
}
|
||||
while(x > 4){
|
||||
maxx -= 2;
|
||||
++x;
|
||||
ASSERT_EQ(0, ncplane_resize(newp, 0, 1, maxy, maxx, 0, 1, maxy, maxx));
|
||||
// FIXME check dims, pos
|
||||
}
|
||||
ASSERT_EQ(0, ncplane_resize(newp, 0, 0, 0, 0, 0, 0, 2, 2));
|
||||
// FIXME check dims, pos
|
||||
ASSERT_EQ(0, ncplane_destroy(newp));
|
||||
}
|
||||
|
||||
TEST_F(NcplaneTest, GrowPlane) {
|
||||
int maxx = 2, maxy = 2;
|
||||
int x = 0, y = 0;
|
||||
int dimy, dimx;
|
||||
notcurses_term_dim_yx(nc_, &dimy, &dimx);
|
||||
x = dimx / 2 - 1;
|
||||
y = dimy / 2 - 1;
|
||||
struct ncplane* newp = notcurses_newplane(nc_, maxy, maxx, y, x, nullptr);
|
||||
ASSERT_NE(nullptr, newp);
|
||||
while(dimx - maxx > 4 && dimy - maxy > 4){
|
||||
maxx += 2;
|
||||
maxy += 2;
|
||||
--x;
|
||||
--y;
|
||||
// ASSERT_EQ(0, ncplane_resize(newp, 1, 1, maxy, maxx, 1, 1, maxy, maxx));
|
||||
// FIXME check dims, pos
|
||||
}
|
||||
while(y < dimy){
|
||||
++maxy;
|
||||
if(y){
|
||||
++y;
|
||||
}
|
||||
// ASSERT_EQ(0, ncplane_resize(newp, 1, 0, maxy, maxx, 1, 0, maxy, maxx));
|
||||
// FIXME check dims, pos
|
||||
}
|
||||
while(x < dimx){
|
||||
++maxx;
|
||||
if(x){
|
||||
++x;
|
||||
}
|
||||
// ASSERT_EQ(0, ncplane_resize(newp, 0, 1, maxy, maxx, 0, 1, maxy, maxx));
|
||||
// FIXME check dims, pos
|
||||
}
|
||||
ASSERT_EQ(0, ncplane_resize(newp, 0, 0, 0, 0, 0, 0, dimy, dimx));
|
||||
// FIXME check dims, pos
|
||||
ASSERT_EQ(0, ncplane_destroy(newp));
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ TEST_F(NotcursesTest, BasicLifetime) {
|
||||
|
||||
TEST_F(NotcursesTest, TermDimensions) {
|
||||
int x, y;
|
||||
notcurses_term_dimyx(nc_, &y, &x);
|
||||
notcurses_term_dim_yx(nc_, &y, &x);
|
||||
auto stry = getenv("LINES");
|
||||
if(stry){
|
||||
auto envy = std::stoi(stry, nullptr);
|
||||
@ -52,10 +52,10 @@ TEST_F(NotcursesTest, TermDimensions) {
|
||||
|
||||
TEST_F(NotcursesTest, ResizeSameSize) {
|
||||
int x, y;
|
||||
notcurses_term_dimyx(nc_, &y, &x);
|
||||
notcurses_term_dim_yx(nc_, &y, &x);
|
||||
EXPECT_EQ(0, notcurses_resize(nc_));
|
||||
int newx, newy;
|
||||
notcurses_term_dimyx(nc_, &newy, &newx);
|
||||
notcurses_term_dim_yx(nc_, &newy, &newx);
|
||||
EXPECT_EQ(newx, x);
|
||||
EXPECT_EQ(newy, y);
|
||||
}
|
||||
@ -70,13 +70,13 @@ TEST_F(NotcursesTest, CursesStyles) {
|
||||
TEST_F(NotcursesTest, RejectDestroyStdPlane) {
|
||||
ncplane* ncp = notcurses_stdplane(nc_);
|
||||
ASSERT_NE(nullptr, ncp);
|
||||
ASSERT_NE(0, ncplane_destroy(nc_, ncp));
|
||||
ASSERT_NE(0, ncplane_destroy(ncp));
|
||||
}
|
||||
|
||||
// create planes partitioning the entirety of the screen, one at each coordinate
|
||||
TEST_F(NotcursesTest, TileScreenWithPlanes) {
|
||||
int maxx, maxy;
|
||||
notcurses_term_dimyx(nc_, &maxy, &maxx);
|
||||
notcurses_term_dim_yx(nc_, &maxy, &maxx);
|
||||
auto total = maxx * maxy;
|
||||
struct ncplane** planes = new struct ncplane*[total];
|
||||
int* planesecrets = new int[total];
|
||||
@ -94,7 +94,7 @@ TEST_F(NotcursesTest, TileScreenWithPlanes) {
|
||||
auto userptr = ncplane_userptr(planes[idx]);
|
||||
ASSERT_NE(nullptr, userptr);
|
||||
EXPECT_EQ(userptr, &planesecrets[idx]);
|
||||
ASSERT_EQ(0, ncplane_destroy(nc_, planes[idx]));
|
||||
ASSERT_EQ(0, ncplane_destroy(planes[idx]));
|
||||
}
|
||||
}
|
||||
delete[] planesecrets;
|
||||
|
Loading…
x
Reference in New Issue
Block a user