mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-09 17:19:03 -04:00
New reel layout algorithm based on trimming and sifting. Fixes the original issue of #818, though I'm not marking that bug fixed until I've resolved the little issues remaining with this one. Back off CMake version dependency, see if we can get by with 3.11.4 for EPEL8 #851 Simplify tablet drawing tremendously by separating tablet border and data planes. Callbacks no longer need worry about the borders; they can simply fill the plane they're handed. #833 Improve notcurses_debug() a bit Add ncplane_new_named() and friends to expose plane naming to the user. Add internal ncplane_genocide() to kill a plane and all its bound descendents New industrial-strength ncreel unit testing notcurses-ncreel now accepts -ln for log level n Add ncplane_parent() and ncplane_parent_const()
This commit is contained in:
parent
dbdbf32b5e
commit
11d6a4eb89
@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
cmake_minimum_required(VERSION 3.11.4)
|
||||
project(notcurses VERSION 1.6.11
|
||||
DESCRIPTION "UI for modern terminal emulators"
|
||||
HOMEPAGE_URL "https://nick-black.com/dankwiki/index.php/notcurses"
|
||||
|
12
NEWS.md
12
NEWS.md
@ -2,11 +2,23 @@ This document attempts to list user-visible changes and any major internal
|
||||
rearrangements of Notcurses.
|
||||
|
||||
* 1.6.12 (not yet released)
|
||||
* `ncreel`s `tabletcb` callback function semantics are radically simplified.
|
||||
No more worrying about borders that might or might not have been drawn;
|
||||
simply fill up the plane that you're handed. This eliminates four of the
|
||||
seven arguments to these callbacks. I hope the inconvenience of adapting
|
||||
them is worth the elimination of complexity therein; I obviously think
|
||||
it is =].
|
||||
* `ncselector_redraw()` and `ncmultiselector_redraw()` no longer call
|
||||
`notcurses_render()`. You will need to call `notcurses_render()` for the
|
||||
display to reflect any changes. `ncselector_create` now binds the plane
|
||||
it creates to the plane it was provided, and no longer checks to ensure
|
||||
the widget can be fit within the borders of this binding plane.
|
||||
* Added `ncplane_new_named()`, `ncplane_bound_named()`, and
|
||||
`ncplane_aligned_named()`. These would be the defaults, but I didn't want
|
||||
to break existing code. They might become the defaults by 2.0. Names are
|
||||
used only for debugging (`notcurses_debug()`) at this time.
|
||||
* Added `ncplane_parent()` and `ncplane_parent_const()` for accessing the
|
||||
plane to which a plane is bound.
|
||||
|
||||
* 1.6.11 (2020-08-03)
|
||||
* `cell_egc_idx()` is no longer exported; it was never intended to be.
|
||||
|
@ -112,7 +112,7 @@ that fine library.
|
||||
## Requirements
|
||||
|
||||
* (build) A C11 and a C++17 compiler
|
||||
* (build) CMake 3.14.0+
|
||||
* (build) CMake 3.11.4+
|
||||
* (build+runtime) From NCURSES: terminfo 6.1+
|
||||
* (build+runtime) GNU libunistring 0.9.10+
|
||||
* (OPTIONAL) (build+runtime) From QR-Code-generator: [libqrcodegen](https://github.com/nayuki/QR-Code-generator) 1.5.0+
|
||||
|
30
USAGE.md
30
USAGE.md
@ -617,9 +617,10 @@ quickly reset the `ncplane`, use `ncplane_erase()`.
|
||||
struct ncplane* ncplane_new(struct notcurses* nc, int rows, int cols,
|
||||
int yoff, int xoff, void* opaque);
|
||||
|
||||
// Create a new ncplane aligned relative to 'n'.
|
||||
struct ncplane* ncplane_aligned(struct ncplane* n, int rows, int cols,
|
||||
int yoff, ncalign_e align, void* opaque);
|
||||
// Create a named plane ala ncplane_new(). Names are only used for debugging.
|
||||
struct ncplane* ncplane_new_named(struct notcurses* nc, int rows, int cols,
|
||||
int yoff, int xoff, void* opaque,
|
||||
const char* name);
|
||||
|
||||
// Create a plane bound to plane 'n'. Being bound to 'n' means that 'yoff' and
|
||||
// 'xoff' are interpreted relative to that plane's origin, and that if that
|
||||
@ -627,10 +628,28 @@ struct ncplane* ncplane_aligned(struct ncplane* n, int rows, int cols,
|
||||
struct ncplane* ncplane_bound(struct ncplane* n, int rows, int cols,
|
||||
int yoff, int xoff, void* opaque);
|
||||
|
||||
// Create a named plane ala ncplane_bound(). Names are used only for debugging.
|
||||
struct ncplane* ncplane_bound_named(struct ncplane* n, int rows, int cols,
|
||||
int yoff, int xoff, void* opaque,
|
||||
const char* name);
|
||||
|
||||
// Create a plane bound to 'n', and aligned relative to it using 'align'.
|
||||
struct ncplane* ncplane_aligned(struct ncplane* n, int rows, int cols,
|
||||
int yoff, ncalign_e align, void* opaque);
|
||||
|
||||
// Create a named plane ala ncplane_aligned(). Names are used only for debugging.
|
||||
struct ncplane* ncplane_aligned_named(struct ncplane* n, int rows, int cols,
|
||||
int yoff, ncalign_e align,
|
||||
void* opaque, const char* name);
|
||||
|
||||
// Plane 'n' will be unbound from its parent plane, if it is currently bound,
|
||||
// and will be made a bound child of 'newparent', if 'newparent' is not NULL.
|
||||
struct ncplane* ncplane_reparent(struct ncplane* n, struct ncplane* newparent);
|
||||
|
||||
// Get the plane to which the plane 'n' is bound, if any.
|
||||
struct ncplane* ncplane_parent(struct ncplane* n);
|
||||
const struct ncplane* ncplane_parent_const(const struct ncplane* n);
|
||||
|
||||
// Duplicate an existing ncplane. The new plane will have the same geometry,
|
||||
// will duplicate all content, and will start with the same rendering state.
|
||||
struct ncplane* ncplane_dup(struct ncplane* n, void* opaque);
|
||||
@ -1166,8 +1185,7 @@ ncplane_vline(struct ncplane* n, const cell* c, int len){
|
||||
|
||||
int ncplane_box(struct ncplane* n, const cell* ul, const cell* ur,
|
||||
const cell* ll, const cell* lr, const cell* hline,
|
||||
const cell* vline, int ystop, int xstop,
|
||||
unsigned ctlword);
|
||||
const cell* vline, int ystop, int xstop, unsigned ctlword);
|
||||
|
||||
// Draw a box with its upper-left corner at the current cursor position, having
|
||||
// dimensions 'ylen'x'xlen'. See ncplane_box() for more information. The
|
||||
@ -1382,8 +1400,6 @@ int ncblit_bgrx(const void* data, int linesize,
|
||||
const struct ncvisual_options* vopts);
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Plane channels API
|
||||
|
||||
Helpers are provided to manipulate an `ncplane`'s `channels` member. They are
|
||||
|
@ -55,7 +55,7 @@ At any time, press 'q' to quit. The demo is best run in at least an 80x45 termin
|
||||
|
||||
**-d delaymult**: Apply a non-negative rational multiplier to the standard delay of 1s.
|
||||
|
||||
**-l loglevel**: Log everything (high log level) or nothing (log level 0) to stderr.
|
||||
**-l loglevel**: Log everything (log level 8) or nothing (log level 0) to stderr.
|
||||
|
||||
**-f renderfile**: Render each frame to **renderfile** in addition to the screen.
|
||||
|
||||
|
@ -8,7 +8,7 @@ notcurses-ncreel - Experiment with ncreels
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
**notcurses-ncreel** [**-t tabletbordermask**] [**-b bordermask**] [**-ob bottomoffset**] [**-ot topoffset**] [**-ol leftoffset**] [**-or rightoffset**]
|
||||
**notcurses-ncreel** [**-t tabletbordermask**] [**-b bordermask**] [**-ob bottomoffset**] [**-ot topoffset**] [**-ol leftoffset**] [**-or rightoffset**] [**-ln**]
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
@ -18,6 +18,8 @@ tablet (if one exists). 'q' quits at any time.
|
||||
|
||||
# OPTIONS
|
||||
|
||||
**-l loglevel**: Log everything (log level 8) or nothing (log level 0) to stderr.
|
||||
|
||||
# NOTES
|
||||
|
||||
Optimal display requires a terminal advertising the **rgb** terminfo(5)
|
||||
|
@ -12,12 +12,18 @@ notcurses_plane - operations on ncplanes
|
||||
|
||||
**struct ncplane* ncplane_new(struct notcurses* nc, int rows, int cols, int yoff, int xoff, void* opaque);**
|
||||
|
||||
**struct ncplane* ncplane_new_named(struct notcurses* nc, int rows, int cols, int yoff, int xoff, void* opaque, const char* name);**
|
||||
|
||||
**struct ncplane* ncplane_bound(struct ncplane* n, int rows, int cols, int yoff, int xoff, void* opaque);**
|
||||
|
||||
**struct ncplane* ncplane_reparent(struct ncplane* n, struct ncplane* newparent);**
|
||||
**struct ncplane* ncplane_bound_named(struct ncplane* n, int rows, int cols, int yoff, int xoff, void* opaque, const char* name);**
|
||||
|
||||
**struct ncplane* ncplane_aligned(struct ncplane* n, int rows, int cols, int yoff, ncalign_e align, void* opaque);**
|
||||
|
||||
**struct ncplane* ncplane_aligned_named(struct ncplane* n, int rows, int cols, int yoff, ncalign_e align, void* opaque, const char* name);**
|
||||
|
||||
**struct ncplane* ncplane_reparent(struct ncplane* n, struct ncplane* newparent);**
|
||||
|
||||
**struct ncplane* ncplane_dup(struct ncplane* n, void* opaque);**
|
||||
|
||||
**int ncplane_resize(struct ncplane* n, int keepy, int keepx, int keepleny, int keeplenx, int yoff, int xoff, int ylen, int xlen);**
|
||||
@ -26,6 +32,10 @@ notcurses_plane - operations on ncplanes
|
||||
|
||||
**void ncplane_yx(const struct ncplane* n, int* restrict y, int* restrict x);**
|
||||
|
||||
**struct ncplane* ncplane_parent(struct ncplane* n);**
|
||||
|
||||
**const struct ncplane* ncplane_parent_const(const struct ncplane* n);**
|
||||
|
||||
**int ncplane_set_base_cell(struct ncplane* ncp, const cell* c);**
|
||||
|
||||
**int ncplane_set_base(struct ncplane* ncp, const char* egc, uint32_t attrword, uint64_t channels);**
|
||||
|
@ -984,8 +984,10 @@ API char* notcurses_at_yx(struct notcurses* nc, int yoff, int xoff,
|
||||
API struct ncplane* ncplane_new(struct notcurses* nc, int rows, int cols,
|
||||
int yoff, int xoff, void* opaque);
|
||||
|
||||
API struct ncplane* ncplane_aligned(struct ncplane* n, int rows, int cols,
|
||||
int yoff, ncalign_e align, void* opaque);
|
||||
// Create a named plane ala ncplane_new(). Names are only used for debugging.
|
||||
API struct ncplane* ncplane_new_named(struct notcurses* nc, int rows, int cols,
|
||||
int yoff, int xoff, void* opaque,
|
||||
const char* name);
|
||||
|
||||
// Create a plane bound to plane 'n'. Being bound to 'n' means that 'yoff' and
|
||||
// 'xoff' are interpreted relative to that plane's origin, and that if that
|
||||
@ -993,6 +995,20 @@ API struct ncplane* ncplane_aligned(struct ncplane* n, int rows, int cols,
|
||||
API struct ncplane* ncplane_bound(struct ncplane* n, int rows, int cols,
|
||||
int yoff, int xoff, void* opaque);
|
||||
|
||||
// Create a named plane ala ncplane_bound(). Names are used only for debugging.
|
||||
API struct ncplane* ncplane_bound_named(struct ncplane* n, int rows, int cols,
|
||||
int yoff, int xoff, void* opaque,
|
||||
const char* name);
|
||||
|
||||
// Create a plane bound to 'n', and aligned relative to it using 'align'.
|
||||
API struct ncplane* ncplane_aligned(struct ncplane* n, int rows, int cols,
|
||||
int yoff, ncalign_e align, void* opaque);
|
||||
|
||||
// Create a named plane ala ncplane_aligned(). Names are used only for debugging.
|
||||
API struct ncplane* ncplane_aligned_named(struct ncplane* n, int rows, int cols,
|
||||
int yoff, ncalign_e align,
|
||||
void* opaque, const char* name);
|
||||
|
||||
// Plane 'n' will be unbound from its parent plane, if it is currently bound,
|
||||
// and will be made a bound child of 'newparent', if 'newparent' is not NULL.
|
||||
API struct ncplane* ncplane_reparent(struct ncplane* n, struct ncplane* newparent);
|
||||
@ -1141,6 +1157,10 @@ API int ncplane_move_yx(struct ncplane* n, int y, int x);
|
||||
// which it is bound (if it is bound to a plane).
|
||||
API void ncplane_yx(const struct ncplane* n, int* RESTRICT y, int* RESTRICT x);
|
||||
|
||||
// Get the plane to which the plane 'n' is bound, if any.
|
||||
API struct ncplane* ncplane_parent(struct ncplane* n);
|
||||
API const struct ncplane* ncplane_parent_const(const struct ncplane* n);
|
||||
|
||||
// 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);
|
||||
@ -2463,22 +2483,10 @@ API struct ncreel* ncreel_create(struct ncplane* nc, const ncreel_options* popts
|
||||
API struct ncplane* ncreel_plane(struct ncreel* pr);
|
||||
|
||||
// Tablet draw callback, provided a tablet (from which the ncplane and userptr
|
||||
// may be extracted), the first column that may be used, the first row that may
|
||||
// be used, the first column that may not be used, the first row that may not
|
||||
// be used, and a bool indicating whether output ought be clipped at the top
|
||||
// (true) or bottom (false). Rows and columns are zero-indexed, and both are
|
||||
// relative to the tablet's plane.
|
||||
//
|
||||
// Regarding clipping: it is possible that the tablet is only partially
|
||||
// displayed on the screen. If so, it is either partially present on the top of
|
||||
// the screen, or partially present at the bottom. In the former case, the top
|
||||
// is clipped (cliptop will be true), and output ought start from the end. In
|
||||
// the latter case, cliptop is false, and output ought start from the beginning.
|
||||
//
|
||||
// Returns the number of lines of output, which ought be less than or equal to
|
||||
// maxy - begy, and non-negative (negative values might be used in the future).
|
||||
typedef int (*tabletcb)(struct nctablet* t, int begx, int begy, int maxx,
|
||||
int maxy, bool cliptop);
|
||||
// may be extracted), and a bool indicating whether output ought be drawn from
|
||||
// the top (true) or bottom (false). Returns non-negative count of output lines,
|
||||
// which must be less than or equal to ncplane_dim_y(nctablet_plane(t)).
|
||||
typedef int (*tabletcb)(struct nctablet* t, bool drawfromtop);
|
||||
|
||||
// Add a new nctablet to the provided ncreel, having the callback object
|
||||
// opaque. Neither, either, or both of after and before may be specified. If
|
||||
|
@ -96,15 +96,18 @@ int ncplane_base(struct ncplane* ncp, cell* c);
|
||||
struct ncplane* notcurses_top(struct notcurses* n);
|
||||
void notcurses_drop_planes(struct notcurses* nc);
|
||||
int notcurses_refresh(struct notcurses* n, int* restrict y, int* restrict x);
|
||||
struct ncplane* ncplane_new(struct notcurses* nc, int rows, int cols, int yoff, int xoff, void* opaque);
|
||||
struct ncplane* ncplane_bound(struct ncplane* n, int rows, int cols, int yoff, int xoff, void* opaque);
|
||||
struct ncplane* ncplane_reparent(struct ncplane* n, struct ncplane* newparent);
|
||||
typedef enum {
|
||||
NCALIGN_LEFT,
|
||||
NCALIGN_CENTER,
|
||||
NCALIGN_RIGHT,
|
||||
} ncalign_e;
|
||||
struct ncplane* ncplane_new(struct notcurses* nc, int rows, int cols, int yoff, int xoff, void* opaque);
|
||||
struct ncplane* ncplane_new_named(struct notcurses* nc, int rows, int cols, int yoff, int xoff, void* opaque, const char* name);
|
||||
struct ncplane* ncplane_bound(struct ncplane* n, int rows, int cols, int yoff, int xoff, void* opaque);
|
||||
struct ncplane* ncplane_bound_named(struct ncplane* n, int rows, int cols, int yoff, int xoff, void* opaque, const char* name);
|
||||
struct ncplane* ncplane_aligned(struct ncplane* n, int rows, int cols, int yoff, ncalign_e align, void* opaque);
|
||||
struct ncplane* ncplane_aligned_named(struct ncplane* n, int rows, int cols, int yoff, ncalign_e align, void* opaque, const char* name);
|
||||
unsigned notcurses_supported_styles(const struct notcurses* nc);
|
||||
int notcurses_palette_size(const struct notcurses* nc);
|
||||
bool notcurses_cantruecolor(const struct notcurses* nc);
|
||||
@ -510,6 +513,8 @@ int ncdirect_double_box(struct ncdirect* n, uint64_t ul, uint64_t ur, uint64_t l
|
||||
bool ncdirect_canopen_images(const struct ncdirect* n);
|
||||
bool ncdirect_canutf8(const struct ncdirect* n);
|
||||
nc_err_e ncdirect_render_image(struct ncdirect* n, const char* filename, ncalign_e align, ncblitter_e blitter, ncscale_e scale);
|
||||
struct ncplane* ncplane_parent(struct ncplane* n);
|
||||
const struct ncplane* ncplane_parent_const(const struct ncplane* n);
|
||||
""")
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -64,25 +64,25 @@ kill_active_tablet(struct ncreel* pr, tabletctx** tctx){
|
||||
// partially off-screen), but also leave unused space at the end (since
|
||||
// wresize() only keeps the top and left on a shrink).
|
||||
static int
|
||||
tabletup(struct ncplane* w, int begx, int begy, int maxx, int maxy,
|
||||
tabletctx* tctx, int rgb){
|
||||
tabletup(struct ncplane* w, int maxy, tabletctx* tctx, int rgb){
|
||||
char cchbuf[2];
|
||||
cell c = CELL_TRIVIAL_INITIALIZER;
|
||||
int y, idx;
|
||||
idx = tctx->lines;
|
||||
if(maxy - begy > tctx->lines){
|
||||
maxy -= (maxy - begy - tctx->lines);
|
||||
int maxx = ncplane_dim_x(w) - 1;
|
||||
if(maxy > tctx->lines){
|
||||
maxy = tctx->lines;
|
||||
}
|
||||
/*fprintf(stderr, "-OFFSET BY %d (%d->%d)\n", maxy - begy - tctx->lines,
|
||||
maxy, maxy - (maxy - begy - tctx->lines));*/
|
||||
for(y = maxy ; y >= begy ; --y, rgb += 16){
|
||||
for(y = maxy ; y >= 0 ; --y, rgb += 16){
|
||||
snprintf(cchbuf, sizeof(cchbuf) / sizeof(*cchbuf), "%x", idx % 16);
|
||||
cell_load(w, &c, cchbuf);
|
||||
if(cell_set_fg_rgb(&c, (rgb >> 16u) % 0xffu, (rgb >> 8u) % 0xffu, rgb % 0xffu)){
|
||||
return -1;
|
||||
}
|
||||
int x;
|
||||
for(x = begx ; x <= maxx ; ++x){
|
||||
for(x = 0 ; x <= maxx ; ++x){
|
||||
if(ncplane_putc_yx(w, y, x, &c) <= 0){
|
||||
return -1;
|
||||
}
|
||||
@ -97,57 +97,58 @@ tabletup(struct ncplane* w, int begx, int begy, int maxx, int maxy,
|
||||
}
|
||||
|
||||
static int
|
||||
tabletdown(struct ncplane* w, int begx, int begy, int maxx, int maxy,
|
||||
tabletctx* tctx, unsigned rgb){
|
||||
tabletdown(struct ncplane* w, int maxy, tabletctx* tctx, unsigned rgb){
|
||||
char cchbuf[2];
|
||||
cell c = CELL_TRIVIAL_INITIALIZER;
|
||||
int y;
|
||||
for(y = begy ; y <= maxy ; ++y, rgb += 16){
|
||||
if(y - begy >= tctx->lines){
|
||||
break;
|
||||
int maxx = ncplane_dim_x(w) - 1;
|
||||
if(maxy > tctx->lines){
|
||||
maxy = tctx->lines;
|
||||
}
|
||||
for(y = 0 ; y <= maxy ; ++y, rgb += 16){
|
||||
snprintf(cchbuf, sizeof(cchbuf) / sizeof(*cchbuf), "%x", y % 16);
|
||||
cell_load(w, &c, cchbuf);
|
||||
if(cell_set_fg_rgb(&c, (rgb >> 16u) % 0xffu, (rgb >> 8u) % 0xffu, rgb % 0xffu)){
|
||||
return -1;
|
||||
}
|
||||
int x;
|
||||
for(x = begx ; x <= maxx ; ++x){
|
||||
for(x = 0 ; x <= maxx ; ++x){
|
||||
if(ncplane_putc_yx(w, y, x, &c) <= 0){
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
cell_release(w, &c);
|
||||
}
|
||||
return y - begy;
|
||||
return y;
|
||||
}
|
||||
|
||||
static int
|
||||
tabletdraw(struct nctablet* t, int begx, int begy, int maxx, int maxy, bool cliptop){
|
||||
tabletdraw(struct nctablet* t, bool cliptop){
|
||||
struct ncplane* p = nctablet_ncplane(t);
|
||||
tabletctx* tctx = nctablet_userptr(t);
|
||||
pthread_mutex_lock(&tctx->lock);
|
||||
unsigned rgb = tctx->rgb;
|
||||
int ll;
|
||||
int maxy = ncplane_dim_y(p);
|
||||
if(cliptop){
|
||||
ll = tabletup(p, begx, begy, maxx, maxy, tctx, rgb);
|
||||
ll = tabletup(p, maxy, tctx, rgb);
|
||||
}else{
|
||||
ll = tabletdown(p, begx, begy, maxx, maxy, tctx, rgb);
|
||||
ll = tabletdown(p, maxy, tctx, rgb);
|
||||
}
|
||||
ncplane_set_fg_rgb(p, 242, 242, 242);
|
||||
if(ll){
|
||||
int summaryy = begy;
|
||||
int summaryy = 0;
|
||||
if(cliptop){
|
||||
if(ll == maxy - begy + 1){
|
||||
if(ll == maxy + 1){
|
||||
summaryy = ll - 1;
|
||||
}else{
|
||||
summaryy = ll;
|
||||
}
|
||||
}
|
||||
ncplane_styles_on(p, NCSTYLE_BOLD);
|
||||
if(ncplane_printf_yx(p, summaryy, begx, "[#%u %d line%s %u/%u] ",
|
||||
if(ncplane_printf_yx(p, summaryy, 0, "[#%u %d line%s %u available] ",
|
||||
tctx->id, tctx->lines, tctx->lines == 1 ? "" : "s",
|
||||
begy, maxy) < 0){
|
||||
maxy) < 0){
|
||||
pthread_mutex_unlock(&tctx->lock);
|
||||
return -1;
|
||||
}
|
||||
@ -184,7 +185,10 @@ tablet_thread(void* vtabletctx){
|
||||
pthread_mutex_lock(&renderlock);
|
||||
if(nctablet_ncplane(tctx->t)){
|
||||
ncreel_redraw(tctx->pr);
|
||||
demo_render(ncplane_notcurses(nctablet_ncplane(tctx->t)));
|
||||
struct ncplane* tplane = nctablet_ncplane(tctx->t);
|
||||
if(tplane){
|
||||
demo_render(ncplane_notcurses(tplane));
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&renderlock);
|
||||
}
|
||||
|
@ -6,11 +6,11 @@ void notcurses_debug(notcurses* nc, FILE* debugfp){
|
||||
int planeidx = 0;
|
||||
fprintf(debugfp, "*************************** notcurses debug state *****************************\n");
|
||||
while(n){
|
||||
fprintf(debugfp, "%04d off y: %3d x: %3d geom y: %3d x: %3d curs y: %3d x: %3d %06llx %.8s\n",
|
||||
fprintf(debugfp, "%04d off y: %3d x: %3d geom y: %3d x: %3d curs y: %3d x: %3d %p %.8s\n",
|
||||
planeidx, n->absy, n->absx, n->leny, n->lenx, n->y, n->x,
|
||||
(uintptr_t)n % 0x100000000ull, n->name ? n->name : "");
|
||||
n, n->name ? n->name : "");
|
||||
if(n->boundto || n->bnext || n->bprev || n->blist){
|
||||
fprintf(debugfp, " bound %p -> %p <- %p binds %p\n",
|
||||
fprintf(debugfp, " bound %p → %p ← %p binds %p\n",
|
||||
n->boundto, n->bnext, n->bprev, n->blist);
|
||||
}
|
||||
if(n->bnext == n || n->boundto == n || n->blist == n){
|
||||
|
@ -117,6 +117,32 @@ typedef struct renderstate {
|
||||
bool defaultelidable;
|
||||
} renderstate;
|
||||
|
||||
// Tablets are the toplevel entitites within an ncreel. Each corresponds to
|
||||
// a single, distinct ncplane.
|
||||
typedef struct nctablet {
|
||||
ncplane* p; // border plane, NULL when offscreen
|
||||
ncplane* cbp; // data plane, NULL when offscreen
|
||||
struct nctablet* next;
|
||||
struct nctablet* prev;
|
||||
tabletcb cbfxn; // application callback to draw cbp
|
||||
void* curry; // application data provided to cbfxn
|
||||
} nctablet;
|
||||
|
||||
typedef struct ncreel {
|
||||
ncplane* p; // ncplane this ncreel occupies, under tablets
|
||||
// doubly-linked list, a circular one when infinity scrolling is in effect.
|
||||
// points at the focused tablet (when at least one tablet exists, one must be
|
||||
// focused). it will be visibly focused following the next redraw.
|
||||
nctablet* tablets;
|
||||
nctablet* vft; // the visibly-focused tablet
|
||||
enum {
|
||||
LASTDIRECTION_UP,
|
||||
LASTDIRECTION_DOWN,
|
||||
} direction; // last direction of travel
|
||||
int tabletcount; // could be derived, but we keep it o(1)
|
||||
ncreel_options ropts; // copied in ncreel_create()
|
||||
} ncreel;
|
||||
|
||||
// ncmenu_item and ncmenu_section have internal and (minimal) external forms
|
||||
typedef struct ncmenu_int_item {
|
||||
char* desc; // utf-8 menu item, NULL for horizontal separator
|
||||
@ -795,6 +821,9 @@ cell_nobackground_p(const cell* c){
|
||||
return c->channels & CELL_NOBACKGROUND_MASK;
|
||||
}
|
||||
|
||||
// Destroy a plane and all its bound descendants.
|
||||
int ncplane_genocide(ncplane *ncp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -297,11 +297,13 @@ void free_plane(ncplane* p){
|
||||
ncplane* ncplane_create(notcurses* nc, ncplane* n, int rows, int cols,
|
||||
int yoff, int xoff, void* opaque, const char* name){
|
||||
if(rows <= 0 || cols <= 0){
|
||||
logerror(nc, "Won't create denormalized plane (r=%d, c=%d)\n", rows, cols);
|
||||
return NULL;
|
||||
}
|
||||
ncplane* p = malloc(sizeof(*p));
|
||||
size_t fbsize = sizeof(*p->fb) * (rows * cols);
|
||||
if((p->fb = malloc(fbsize)) == NULL){
|
||||
logerror(nc, "Error allocating cellmatrix (r=%d, c=%d)\n", rows, cols);
|
||||
free(p);
|
||||
return NULL;
|
||||
}
|
||||
@ -346,6 +348,7 @@ ncplane* ncplane_create(notcurses* nc, ncplane* n, int rows, int cols,
|
||||
}else{
|
||||
p->below = NULL;
|
||||
}
|
||||
loginfo(nc, "Created new %dx%d plane @ %dx%d\n", rows, cols, yoff, xoff);
|
||||
return p;
|
||||
}
|
||||
|
||||
@ -371,16 +374,32 @@ ncplane* ncplane_new(notcurses* nc, int rows, int cols, int yoff, int xoff, void
|
||||
return ncplane_create(nc, NULL, rows, cols, yoff, xoff, opaque, NULL);
|
||||
}
|
||||
|
||||
ncplane* ncplane_new_named(notcurses* nc, int rows, int cols, int yoff,
|
||||
int xoff, void* opaque, const char* name){
|
||||
return ncplane_create(nc, NULL, rows, cols, yoff, xoff, opaque, name);
|
||||
}
|
||||
|
||||
ncplane* ncplane_bound(ncplane* n, int rows, int cols, int yoff, int xoff, void* opaque){
|
||||
return ncplane_create(n->nc, n, rows, cols, yoff, xoff, opaque, NULL);
|
||||
}
|
||||
|
||||
ncplane* ncplane_bound_named(ncplane* n, int rows, int cols, int yoff, int xoff,
|
||||
void* opaque, const char* name){
|
||||
return ncplane_create(n->nc, n, rows, cols, yoff, xoff, opaque, name);
|
||||
}
|
||||
|
||||
ncplane* ncplane_aligned(ncplane* n, int rows, int cols, int yoff,
|
||||
ncalign_e align, void* opaque){
|
||||
return ncplane_create(n->nc, n, rows, cols, yoff,
|
||||
ncplane_align(n, align, cols), opaque, NULL);
|
||||
}
|
||||
|
||||
ncplane* ncplane_aligned_named(ncplane* n, int rows, int cols, int yoff,
|
||||
ncalign_e align, void* opaque, const char* name){
|
||||
return ncplane_create(n->nc, n, rows, cols, yoff,
|
||||
ncplane_align(n, align, cols), opaque, name);
|
||||
}
|
||||
|
||||
void ncplane_home(ncplane* n){
|
||||
n->x = 0;
|
||||
n->y = 0;
|
||||
@ -583,14 +602,34 @@ int ncplane_destroy(ncplane* ncp){
|
||||
ncp->bnext->bprev = ncp->bprev;
|
||||
}
|
||||
}
|
||||
if(ncp->blist){
|
||||
// FIXME need unlink all on list
|
||||
ncp->blist->bprev = NULL;
|
||||
ncp->blist->bnext = NULL;
|
||||
int ret = 0;
|
||||
struct ncplane* bound = ncp->blist;
|
||||
while(bound){
|
||||
struct ncplane* tmp = bound->bnext;
|
||||
if(ncplane_reparent(bound, ncp->boundto) == NULL){
|
||||
ret = -1;
|
||||
}
|
||||
bound = tmp;
|
||||
}
|
||||
free_plane(ncp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ncplane_genocide(ncplane *ncp){
|
||||
if(ncp == NULL){
|
||||
return 0;
|
||||
}
|
||||
if(ncp->nc->stdplane == ncp){
|
||||
logerror(ncp->nc, "Won't destroy standard plane\n");
|
||||
return -1;
|
||||
}
|
||||
int ret = 0;
|
||||
while(ncp->blist){
|
||||
ret |= ncplane_genocide(ncp->blist);
|
||||
}
|
||||
ret |= ncplane_destroy(ncp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
make_nonblocking(FILE* fp){
|
||||
@ -2178,6 +2217,14 @@ const notcurses* ncplane_notcurses_const(const ncplane* n){
|
||||
return n->nc;
|
||||
}
|
||||
|
||||
ncplane* ncplane_parent(ncplane* n){
|
||||
return n->boundto;
|
||||
}
|
||||
|
||||
const ncplane* ncplane_parent_const(const ncplane* n){
|
||||
return n->boundto;
|
||||
}
|
||||
|
||||
ncplane* ncplane_reparent(ncplane* n, ncplane* newparent){
|
||||
if(n == n->nc->stdplane){
|
||||
return NULL; // can't reparent standard plane
|
||||
|
661
src/lib/reel.c
661
src/lib/reel.c
@ -5,20 +5,10 @@
|
||||
#include <string.h>
|
||||
#include "internal.h"
|
||||
|
||||
// Tablets are the toplevel entitites within an ncreel. Each corresponds to
|
||||
// a single, distinct ncplane.
|
||||
typedef struct nctablet {
|
||||
ncplane* p; // visible panel, NULL when offscreen
|
||||
struct nctablet* next;
|
||||
struct nctablet* prev;
|
||||
tabletcb cbfxn; // application callback to draw tablet
|
||||
void* curry; // application data provided to cbfxn
|
||||
} nctablet;
|
||||
|
||||
typedef enum {
|
||||
DIRECTION_UP,
|
||||
DIRECTION_DOWN,
|
||||
} direction_e;
|
||||
} direction_e; // current direction of travel
|
||||
|
||||
// A UNIFIED THEORY OF NCREELS
|
||||
// (which are more complex than they may seem)
|
||||
@ -44,7 +34,8 @@ typedef enum {
|
||||
// Second rule: if there must be 2+ consecutive lines of blank space, they must
|
||||
// all be at the bottom of the reel (connect and anchor the reel).
|
||||
// Third rule: the focused tablet gets all the space it can use.
|
||||
// Fourth rule: the focused tablet should remain where it is across redraws,
|
||||
// Fourth rule: thou shalt never wrap a tablet [across a border]
|
||||
// Fifth rule: the focused tablet should remain where it is across redraws,
|
||||
// except as necessary to accommodate the prior rules.
|
||||
//
|
||||
// At any ncreel_redraw(), you can make three types of moves:
|
||||
@ -77,7 +68,7 @@ typedef enum {
|
||||
//
|
||||
// We otherwise have case iii. The focused tablet must be on-screen (if it was
|
||||
// off-screen, we matched one of case i or case ii). We want to draw it as near
|
||||
// to its current position as possible, subject to the first three Rules.
|
||||
// to its current position as possible, subject to the first four Rules.
|
||||
//
|
||||
// ncreel_redraw() thus starts by determining the case. This must be done
|
||||
// before any changes are made to the arrangement. It then clears the reel.
|
||||
@ -121,17 +112,6 @@ typedef enum {
|
||||
// * walk the list in the direction against travel, foc->focw
|
||||
// * if focw == backstop, we're done
|
||||
// * draw through edge
|
||||
typedef struct ncreel {
|
||||
ncplane* p; // ncplane this ncreel occupies, under tablets
|
||||
// doubly-linked list, a circular one when infinity scrolling is in effect.
|
||||
// points at the focused tablet (when at least one tablet exists, one must be
|
||||
// focused). it will be visibly focused following the next redraw.
|
||||
nctablet* tablets;
|
||||
nctablet* vft; // the visibly-focused tablet
|
||||
direction_e direction;// last direction of travel
|
||||
int tabletcount; // could be derived, but we keep it o(1)
|
||||
ncreel_options ropts; // copied in ncreel_create()
|
||||
} ncreel;
|
||||
|
||||
// Returns the starting coordinates (relative to the screen) of the specified
|
||||
// tablet, and its length. End is (begx + lenx - 1, begy + leny - 1).
|
||||
@ -142,8 +122,7 @@ tablet_coordinates(ncplane* w, int* begy, int* begx, int* leny, int* lenx){
|
||||
}
|
||||
|
||||
static int
|
||||
draw_borders(ncplane* w, unsigned mask, uint64_t channel,
|
||||
bool cliphead, bool clipfoot){
|
||||
draw_borders(ncplane* w, unsigned mask, uint64_t channel){
|
||||
int lenx, leny;
|
||||
int ret = 0;
|
||||
ncplane_dim_yx(w, &leny, &lenx);
|
||||
@ -155,12 +134,9 @@ draw_borders(ncplane* w, unsigned mask, uint64_t channel,
|
||||
if(cells_rounded_box(w, 0, channel, &ul, &ur, &ll, &lr, &hl, &vl)){
|
||||
return -1;
|
||||
}
|
||||
/*fprintf(stderr, "drawing borders %p ->%d/%d, mask: %04x, clipping: %c%c\n",
|
||||
w, maxx, maxy, mask,
|
||||
cliphead ? 'T' : 't', clipfoot ? 'F' : 'f');*/
|
||||
if(!cliphead){
|
||||
// lenx is the number of columns we have, but drop 2 due to
|
||||
// corners. we thus want lenx horizontal lines.
|
||||
//fprintf(stderr, "drawing borders %p ->%d/%d, mask: %04x\n", w, maxx, maxy, mask);
|
||||
// lenx is the number of columns we have, but drop 2 due to corners. we thus
|
||||
// want lenx horizontal lines.
|
||||
if(!(mask & NCBOXMASK_TOP)){
|
||||
ncplane_home(w);
|
||||
ncplane_putc(w, &ul);
|
||||
@ -176,9 +152,8 @@ draw_borders(ncplane* w, unsigned mask, uint64_t channel,
|
||||
ncplane_putc(w, &ur);
|
||||
}
|
||||
}
|
||||
}
|
||||
int y;
|
||||
for(y = !cliphead ; y < maxy + !!clipfoot ; ++y){
|
||||
for(y = 1 ; y < maxy ; ++y){
|
||||
if(!(mask & NCBOXMASK_LEFT)){
|
||||
ret |= ncplane_cursor_move_yx(w, y, 0);
|
||||
ncplane_putc(w, &vl);
|
||||
@ -188,7 +163,6 @@ draw_borders(ncplane* w, unsigned mask, uint64_t channel,
|
||||
ncplane_putc(w, &vl);
|
||||
}
|
||||
}
|
||||
if(!clipfoot){
|
||||
if(!(mask & NCBOXMASK_BOTTOM)){
|
||||
ret |= ncplane_cursor_move_yx(w, maxy, 0);
|
||||
ncplane_putc(w, &ll);
|
||||
@ -209,11 +183,8 @@ draw_borders(ncplane* w, unsigned mask, uint64_t channel,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cell_release(w, &ul); cell_release(w, &ur); cell_release(w, &hl);
|
||||
cell_release(w, &ll); cell_release(w, &lr); cell_release(w, &vl);
|
||||
// fprintf(stderr, "||--borders %d %d clip: %c%c ret: %d\n",
|
||||
// maxx, maxy, cliphead ? 'y' : 'n', clipfoot ? 'y' : 'n', ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -226,7 +197,7 @@ draw_ncreel_borders(const ncreel* nr){
|
||||
assert(maxy >= 0 && maxx >= 0);
|
||||
--maxx; // last column we can safely write to
|
||||
--maxy; // last line we can safely write to
|
||||
return draw_borders(nr->p, nr->ropts.bordermask, nr->ropts.borderchan, false, false);
|
||||
return draw_borders(nr->p, nr->ropts.bordermask, nr->ropts.borderchan);
|
||||
}
|
||||
|
||||
// Calculate the starting and ending coordinates available for occupation by
|
||||
@ -235,32 +206,26 @@ draw_ncreel_borders(const ncreel* nr){
|
||||
// (nr->tablets == t), it can take the entire reel -- frontiery is only a
|
||||
// suggestion in this case -- so give it the full breadth.
|
||||
static int
|
||||
tablet_columns(const ncreel* nr, nctablet* t, int* begx, int* begy,
|
||||
int* lenx, int* leny, int frontiery, direction_e direction){
|
||||
tablet_geom(const ncreel* nr, nctablet* t, int* begx, int* begy,
|
||||
int* lenx, int* leny, int frontiertop, int frontierbottom,
|
||||
direction_e direction){
|
||||
//fprintf(stderr, "jigsawing %p with %d/%d dir %d\n", t, frontiertop, frontierbottom, direction);
|
||||
*begy = 0;
|
||||
*begx = 0;
|
||||
ncplane_dim_yx(nr->p, leny, lenx);
|
||||
int maxy = *leny + *begy - 1;
|
||||
int begindraw = *begy + !(nr->ropts.bordermask & NCBOXMASK_TOP);
|
||||
int enddraw = maxy - !(nr->ropts.bordermask & NCBOXMASK_TOP);
|
||||
if(direction == DIRECTION_UP || nr->tablets == t){
|
||||
if(frontiery < begindraw){
|
||||
if(frontiertop < 0){
|
||||
if(direction == DIRECTION_UP){
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
if(frontiery > enddraw){
|
||||
// fprintf(stderr, "FRONTIER: %d ENDDRAW: %d\n", frontiery, enddraw);
|
||||
frontiertop = 0;
|
||||
}
|
||||
if(frontierbottom >= *leny){
|
||||
if(direction == DIRECTION_DOWN){
|
||||
return -1;
|
||||
}
|
||||
frontierbottom = *leny - 1;
|
||||
}
|
||||
// account for the ncreel borders
|
||||
if((direction == DIRECTION_UP || nr->tablets == t) && !(nr->ropts.bordermask & NCBOXMASK_TOP)){
|
||||
++*begy;
|
||||
--*leny;
|
||||
}
|
||||
if((direction == DIRECTION_DOWN || nr->tablets == t) && !(nr->ropts.bordermask & NCBOXMASK_BOTTOM)){
|
||||
--*leny;
|
||||
}
|
||||
// account for the ncreel borders on the sides
|
||||
if(!(nr->ropts.bordermask & NCBOXMASK_LEFT)){
|
||||
++*begx;
|
||||
--*lenx;
|
||||
@ -271,236 +236,235 @@ tablet_columns(const ncreel* nr, nctablet* t, int* begx, int* begy,
|
||||
// at this point, our coordinates describe the largest possible tablet for
|
||||
// this ncreel. this is the correct solution for the focused tablet. other
|
||||
// tablets can only grow in one of two directions, so tighten them up.
|
||||
if(direction == DIRECTION_DOWN && nr->tablets != t){
|
||||
*leny -= (frontiery - *begy);
|
||||
*begy = frontiery;
|
||||
}else if(direction == DIRECTION_UP && nr->tablets != t){
|
||||
*leny = frontiery - *begy + 1;
|
||||
if(nr->tablets != t){
|
||||
*leny -= (frontierbottom - (frontiertop + 1));
|
||||
if(direction == DIRECTION_DOWN){
|
||||
*begy = frontierbottom;
|
||||
}else{
|
||||
*begy = frontiertop - *leny;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Draw the specified tablet, if possible. DIRECTION_UP means we're
|
||||
// laying out towards the top. DIRECTION_DOWN means towards the bottom. 0
|
||||
// means this is the focused tablet, always the first one to be drawn.
|
||||
// frontiery is the line on which we're placing the tablet (in the case of the
|
||||
// focused window, this is only an ideal, subject to change). For direction
|
||||
// greater than or equal to 0, it's the top line of the tablet. For direction
|
||||
// less than 0, it's the bottom line. Gives the tablet all possible space to
|
||||
// work with (i.e. up to the edge we're approaching, or the entire panel for
|
||||
// the focused tablet). If the callback uses less space, shrinks the panel back
|
||||
// down before displaying it. Destroys any panel if it ought be hidden.
|
||||
// Returns 0 if the tablet was able to be wholly rendered, non-zero otherwise.
|
||||
// Draw the specified tablet, if possible. DIRECTION_UP means we're laying out
|
||||
// bottom-to-top. DIRECTION_DOWN means top-to-bottom. 'frontier{top, bottom}'
|
||||
// are the lines to which we'll be fitting the tablet ('frontiertop' to our
|
||||
// last row for DIRECTION_UP, and 'frontierbottom' to our first row for
|
||||
// DIRECTION_DOWN). Gives the tablet all possible space to work with (i.e.
|
||||
// everything beyond the frontiers, or the entire reel for the focused tablet).
|
||||
// If the callback uses less space, shrinks the plane to that size.
|
||||
static int
|
||||
ncreel_draw_tablet(const ncreel* nr, nctablet* t, int frontiery, int direction){
|
||||
ncreel_draw_tablet(const ncreel* nr, nctablet* t, int frontiertop,
|
||||
int frontierbottom, direction_e direction){
|
||||
assert(!t->p);
|
||||
if(t->p || t->cbp){
|
||||
//fprintf(stderr, "already drew %p: %p %p\n", t, t->p, t->cbp);
|
||||
return -1;
|
||||
}
|
||||
int lenx, leny, begy, begx;
|
||||
ncplane* fp = t->p;
|
||||
if(tablet_columns(nr, t, &begx, &begy, &lenx, &leny, frontiery, direction)){
|
||||
//fprintf(stderr, "no room: %p:%p base %d/%d len %d/%d dir %d\n", t, fp, begy, begx, leny, lenx, direction);
|
||||
//fprintf(stderr, "FRONTIER DONE!!!!!!\n");
|
||||
if(fp){
|
||||
//fprintf(stderr, "HIDING %p at frontier %d (dir %d) with %d\n", t, frontiery, direction, leny);
|
||||
ncplane_destroy(fp);
|
||||
t->p = NULL;
|
||||
}
|
||||
if(tablet_geom(nr, t, &begx, &begy, &lenx, &leny, frontiertop, frontierbottom, direction)){
|
||||
//fprintf(stderr, "no room: %p base %d/%d len %d/%d dir %d\n", t, begy, begx, leny, lenx, direction);
|
||||
return -1;
|
||||
}
|
||||
//fprintf(stderr, "tplacement: %p:%p base %d/%d len %d/%d\n", t, fp, begx, begy, lenx, leny);
|
||||
//fprintf(stderr, "DRAWING %p at frontier %d (dir %d) with %d\n", t, frontiery, direction, leny);
|
||||
if(fp == NULL){ // create a panel for the tablet
|
||||
t->p = ncplane_bound(nr->p, leny + 1, lenx, begy, begx, NULL);
|
||||
if((fp = t->p) == NULL){
|
||||
//fprintf(stderr, "tplacement: %p base %d/%d len %d/%d frontiery %d %d dir %d\n", t, begy, begx, leny, lenx, frontiertop, frontierbottom, direction);
|
||||
ncplane* fp = ncplane_bound_named(nr->p, leny, lenx, begy, begx, NULL, "tab");
|
||||
if((t->p = fp) == NULL){
|
||||
//fprintf(stderr, "failure creating border plane %d %d %d %d\n", leny, lenx, begy, begx);
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
int trueby, truebx;
|
||||
ncplane_yx(fp, &trueby, &truebx);
|
||||
int truey, truex;
|
||||
ncplane_dim_yx(fp, &truey, &truex);
|
||||
if(truey != leny){
|
||||
//fprintf(stderr, "RESIZE TRUEY: %d BEGY: %d LENY: %d\n", truey, begy, leny);
|
||||
if(ncplane_resize_simple(fp, leny, truex)){
|
||||
return -1;
|
||||
// we allow the callback to use a bound plane that lives above our border
|
||||
// plane, thus preventing the callback from spilling over the tablet border.
|
||||
int cby = 0, cbx = 0, cbleny = leny, cblenx = lenx;
|
||||
if(!(nr->ropts.tabletmask & NCBOXMASK_BOTTOM)){
|
||||
--cbleny;
|
||||
}
|
||||
truey = leny;
|
||||
}
|
||||
//fprintf(stderr, "begy: %d trueby: %d\n", begy, trueby);
|
||||
if(begy != trueby){
|
||||
ncplane_move_yx(fp, begy, begx);
|
||||
}
|
||||
}
|
||||
if(ncplane_resize_simple(fp, leny, lenx)){
|
||||
return -1;
|
||||
}
|
||||
bool cliphead = false;
|
||||
bool clipfoot = false;
|
||||
// We pass the coordinates in which the callback may freely write. That's
|
||||
// the full width (minus tablet borders), and the full range of open space
|
||||
// in the direction we're moving. We're not passing *lenghts* to the callback,
|
||||
// but *coordinates* within the window--everywhere save tabletborders.
|
||||
int cby = 0, cbx = 0, cbmaxy = leny, cbmaxx = lenx;
|
||||
--cbmaxy;
|
||||
--cbmaxx;
|
||||
// If we're drawing up, we'll always have a bottom border unless it's masked
|
||||
if((nr->tablets != t && direction == DIRECTION_UP) && !(nr->ropts.tabletmask & NCBOXMASK_BOTTOM)){
|
||||
--cbmaxy;
|
||||
}
|
||||
// If we're drawing down, we'll always have a top border unless it's masked
|
||||
if(direction == DIRECTION_DOWN && !(nr->ropts.tabletmask & NCBOXMASK_TOP)){
|
||||
if(!(nr->ropts.tabletmask & NCBOXMASK_TOP)){
|
||||
--cbleny;
|
||||
++cby;
|
||||
}
|
||||
// Adjust the x-bounds for side borders, which we always have if unmasked
|
||||
cbmaxx -= !(nr->ropts.tabletmask & NCBOXMASK_RIGHT);
|
||||
cbx += !(nr->ropts.tabletmask & NCBOXMASK_LEFT);
|
||||
bool cbdir = (nr->tablets != t && direction == DIRECTION_UP) ? true : false;
|
||||
// fprintf(stderr, "calling! lenx/leny: %d/%d cbx/cby: %d/%d cbmaxx/cbmaxy: %d/%d dir: %d\n",
|
||||
// lenx, leny, cbx, cby, cbmaxx, cbmaxy, direction);
|
||||
int ll = t->cbfxn(t, cbx, cby, cbmaxx, cbmaxy, cbdir);
|
||||
//fprintf(stderr, "RETURNRETURNRETURN %p %d (%d, %d, %d) DIR %d\n", t, ll, cby, cbmaxy, leny, direction);
|
||||
if(ll != leny){
|
||||
if(ll == leny - 1){ // only has one border visible (partially off-screen)
|
||||
if(cbdir){
|
||||
ll += !(nr->ropts.tabletmask & NCBOXMASK_BOTTOM);
|
||||
}else{
|
||||
ll += !(nr->ropts.tabletmask & NCBOXMASK_TOP);
|
||||
cblenx -= !(nr->ropts.tabletmask & NCBOXMASK_RIGHT);
|
||||
if(!(nr->ropts.tabletmask & NCBOXMASK_LEFT)){
|
||||
--cblenx;
|
||||
++cbx;
|
||||
}
|
||||
ncplane_resize_simple(fp, ll, lenx);
|
||||
if(direction == DIRECTION_UP && nr->tablets != t){
|
||||
cliphead = true;
|
||||
ncplane_move_yx(fp, begy + leny - ll, begx);
|
||||
//fprintf(stderr, "MOVEDOWN CLIPPED RESIZED (-1) from %d to %d\n", leny, ll);
|
||||
}else{
|
||||
clipfoot = true;
|
||||
//fprintf(stderr, "RESIZED (-1) from %d to %d\n", leny, ll);
|
||||
}
|
||||
}else if(ll < leny - 1){ // both borders are visible
|
||||
ll += !(nr->ropts.tabletmask & NCBOXMASK_BOTTOM) +
|
||||
!(nr->ropts.tabletmask & NCBOXMASK_TOP);
|
||||
//fprintf(stderr, "RESIZING (-2) from %d to %d\n", leny, ll);
|
||||
ncplane_resize_simple(fp, ll, lenx);
|
||||
if(direction == DIRECTION_UP && nr->tablets != t){
|
||||
//fprintf(stderr, "MOVEDOWN UNCLIPPED (skip %d)\n", leny - ll);
|
||||
ncplane_move_yx(fp, begy + leny - ll, begx);
|
||||
}
|
||||
}else{
|
||||
assert(ll == leny); // you fucked up! FIXME
|
||||
if(cbleny - cby + 1 > 0){
|
||||
t->cbp = ncplane_bound_named(t->p, cbleny - cby + 1, cblenx - cbx + 1, cby, cbx, NULL, "tdat");
|
||||
if(t->cbp == NULL){
|
||||
//fprintf(stderr, "failure creating data plane %d %d %d %d\n", cbleny - cby + 1, cblenx - cbx + 1, cby, cbx);
|
||||
ncplane_destroy(t->p);
|
||||
t->p = NULL;
|
||||
return -1;
|
||||
}
|
||||
ncplane_move_above(t->cbp, t->p);
|
||||
// fprintf(stderr, "calling! lenx/leny: %d/%d cbx/cby: %d/%d cblenx/cbleny: %d/%d dir: %d\n", lenx, leny, cbx, cby, cblenx, cbleny, direction);
|
||||
int ll = t->cbfxn(t, direction == DIRECTION_DOWN);
|
||||
//fprintf(stderr, "RETURNRETURNRETURN %p %d (%d, %d, %d) DIR %d\n", t, ll, cby, cbleny, leny, direction);
|
||||
if(ll != cbleny - cby + 1){
|
||||
int diff = (cbleny - cby + 1) - ll;
|
||||
//fprintf(stderr, "resizing data plane %d->%d\n", cbleny - cby + 1, ll);
|
||||
ncplane_resize_simple(t->cbp, ll, cblenx - cbx + 1);
|
||||
ncplane_resize_simple(t->p, leny - diff, lenx);
|
||||
// We needn't move the resized plane if drawing down, or the focused plane.
|
||||
// The focused tablet will have been resized properly above, but it might
|
||||
// be out of position (the focused tablet ought move as little as possible).
|
||||
// Move it back to the frontier, or the nearest line above if it has grown.
|
||||
if(nr->tablets == t){
|
||||
if(leny - frontiery + 1 < ll){
|
||||
//fprintf(stderr, "frontieryIZING ADJ %d %d %d %d NEW %d\n", cbmaxy, leny, frontiery, ll, frontiery - ll + 1);
|
||||
ncplane_yx(fp, &frontiery, NULL);
|
||||
frontiery += (leny - ll);
|
||||
if(leny - frontiertop + 1 < ll){
|
||||
ncplane_yx(fp, &frontiertop, NULL);
|
||||
frontiertop += (leny - ll);
|
||||
}
|
||||
ncplane_move_yx(fp, frontiertop, begx);
|
||||
//fprintf(stderr, "moved to frontiertop %d\n", frontiertop);
|
||||
}else if(direction == DIRECTION_UP){
|
||||
ncplane_move_yx(fp, begy + diff, begx);
|
||||
//fprintf(stderr, "MOVEDOWN from %d to %d\n", begy, begy + diff);
|
||||
}
|
||||
//fprintf(stderr, "moving to frontiery %d\n", frontiery);
|
||||
ncplane_move_yx(fp, frontiery, begx);
|
||||
}
|
||||
}
|
||||
draw_borders(fp, nr->ropts.tabletmask,
|
||||
nr->tablets == t ? nr->ropts.focusedchan : nr->ropts.tabletchan,
|
||||
cliphead, clipfoot);
|
||||
return cliphead || clipfoot;
|
||||
}
|
||||
|
||||
// draw and size the focused tablet, which must exist (nr->tablets may not be
|
||||
// NULL). it can occupy the entire ncreel.
|
||||
static int
|
||||
draw_focused_tablet(const ncreel* nr){
|
||||
int plenx, pleny; // ncreel window coordinates
|
||||
ncplane_dim_yx(nr->p, &pleny, &plenx);
|
||||
int fulcrum;
|
||||
if(nr->tablets->p == NULL){
|
||||
if(nr->direction == DIRECTION_DOWN){
|
||||
fulcrum = pleny + !(nr->ropts.bordermask & NCBOXMASK_BOTTOM);
|
||||
}else{
|
||||
fulcrum = !(nr->ropts.bordermask & NCBOXMASK_TOP);
|
||||
}
|
||||
//fprintf(stderr, "LTD: %d placing new at %d\n", nr->direction, fulcrum);
|
||||
}else{ // focused was already present. want to stay where we are, if possible
|
||||
ncplane_yx(nr->tablets->p, &fulcrum, NULL);
|
||||
// FIXME ugh can't we just remember the previous fulcrum?
|
||||
if(nr->direction == DIRECTION_DOWN){
|
||||
if(nr->tablets->prev->p){
|
||||
int prevfulcrum;
|
||||
ncplane_yx(nr->tablets->prev->p, &prevfulcrum, NULL);
|
||||
if(fulcrum < prevfulcrum){
|
||||
fulcrum = pleny + !(nr->ropts.bordermask & NCBOXMASK_BOTTOM);
|
||||
}
|
||||
}
|
||||
}else if(nr->direction == DIRECTION_UP){
|
||||
if(nr->tablets->next->p){
|
||||
int nextfulcrum;
|
||||
ncplane_yx(nr->tablets->next->p, &nextfulcrum, NULL);
|
||||
if(fulcrum > nextfulcrum){
|
||||
fulcrum = !(nr->ropts.bordermask & NCBOXMASK_TOP);
|
||||
}
|
||||
}
|
||||
}
|
||||
//fprintf(stderr, "existing: %p %d placing at %d\n", nr->tablets, nr->direction, fulcrum);
|
||||
}
|
||||
//fprintf(stderr, "PR dims: %d/%d fulcrum: %d\n", pleny, plenx, fulcrum);
|
||||
return ncreel_draw_tablet(nr, nr->tablets, fulcrum, 0);
|
||||
nr->tablets == t ? nr->ropts.focusedchan : nr->ropts.tabletchan);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// move down below the focused tablet, filling up the reel to the bottom.
|
||||
// returns the last tablet drawn.
|
||||
static nctablet*
|
||||
draw_following_tablets(const ncreel* nr, const nctablet* otherend){
|
||||
int wmaxy, wbegy, wbegx, wlenx, wleny; // working tablet window coordinates
|
||||
nctablet* working = nr->tablets;
|
||||
int frontiery;
|
||||
draw_following_tablets(const ncreel* nr, nctablet* otherend,
|
||||
int frontiertop, int* frontierbottom){
|
||||
//fprintf(stderr, "following otherend: %p ->p: %p %d/%d\n", otherend, otherend->p, frontiertop, *frontierbottom);
|
||||
nctablet* working = nr->tablets->next;
|
||||
const int maxx = ncplane_dim_y(nr->p) - 1;
|
||||
// move down past the focused tablet, filling up the reel to the bottom
|
||||
do{
|
||||
//fprintf(stderr, "following otherend: %p ->p: %p\n", otherend, otherend->p);
|
||||
// modify frontier based off the one we're at
|
||||
tablet_coordinates(working->p, &wbegy, &wbegx, &wleny, &wlenx);
|
||||
wmaxy = wbegy + wleny - 1;
|
||||
frontiery = wmaxy + 2;
|
||||
//fprintf(stderr, "EASTBOUND AND DOWN: %p->%p %d %d\n", working, working->next, frontiery, wmaxy + 2);
|
||||
working = working->next;
|
||||
if(working == otherend && otherend->p){
|
||||
//fprintf(stderr, "BREAKOUT ON OTHEREND %p:%p\n", working, working->p);
|
||||
while(*frontierbottom <= maxx && (working != otherend || !otherend->p)){
|
||||
if(working->p){
|
||||
break;
|
||||
}
|
||||
ncreel_draw_tablet(nr, working, frontiery, DIRECTION_DOWN);
|
||||
//fprintf(stderr, "following otherend: %p ->p: %p\n", otherend, otherend->p);
|
||||
// modify frontier based off the one we're at
|
||||
//fprintf(stderr, "EASTBOUND AND DOWN: %p->%p %d %d\n", working, working->next, frontiertop, *frontierbottom);
|
||||
if(ncreel_draw_tablet(nr, working, frontiertop, *frontierbottom, DIRECTION_DOWN)){
|
||||
return NULL;
|
||||
}
|
||||
if(working == otherend){
|
||||
otherend = otherend->next;
|
||||
}
|
||||
}while(working->p);
|
||||
*frontierbottom += ncplane_dim_y(working->p) + 1;
|
||||
working = working->next;
|
||||
}
|
||||
//fprintf(stderr, "done with prevs: %p->%p %d %d\n", working, working->prev, frontiertop, *frontierbottom);
|
||||
return working;
|
||||
}
|
||||
|
||||
// move up above the focused tablet, filling up the reel to the top.
|
||||
// returns the last tablet drawn.
|
||||
static nctablet*
|
||||
draw_previous_tablets(const ncreel* nr, const nctablet* otherend){
|
||||
//fprintf(stderr, "preceding otherend: %p ->p: %p\n", otherend, otherend->p);
|
||||
int wbegy, wbegx, wlenx, wleny; // working tablet window coordinates
|
||||
nctablet* upworking = nr->tablets;
|
||||
int frontiery;
|
||||
draw_previous_tablets(const ncreel* nr, nctablet* otherend,
|
||||
int* frontiertop, int frontierbottom){
|
||||
nctablet* upworking = nr->tablets->prev;
|
||||
//fprintf(stderr, "preceding %p otherend: %p ->p: %p frontiers: %d %d\n", upworking, otherend, otherend->p, *frontiertop, frontierbottom);
|
||||
// modify frontier based off the one we're at
|
||||
tablet_coordinates(upworking->p, &wbegy, &wbegx, &wleny, &wlenx);
|
||||
frontiery = wbegy - 2;
|
||||
while(upworking->prev != otherend || otherend->p == NULL){
|
||||
//fprintf(stderr, "MOVIN' ON UP: %p->%p %d %d\n", upworking, upworking->prev, frontiery, wbegy - 2);
|
||||
upworking = upworking->prev;
|
||||
ncreel_draw_tablet(nr, upworking, frontiery, DIRECTION_UP);
|
||||
while(*frontiertop >= 0 && (upworking != otherend || !otherend->p)){
|
||||
if(upworking->p){
|
||||
tablet_coordinates(upworking->p, &wbegy, &wbegx, &wleny, &wlenx);
|
||||
//fprintf(stderr, "new up coords: %d/%d + %d/%d, %d\n", wbegy, wbegx, wleny, wlenx, frontiery);
|
||||
frontiery = wbegy - 2;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
//fprintf(stderr, "MOVIN' ON UP: %p->%p %d %d\n", upworking, upworking->prev, *frontiertop, frontierbottom);
|
||||
if(ncreel_draw_tablet(nr, upworking, *frontiertop, frontierbottom, DIRECTION_UP)){
|
||||
return NULL;
|
||||
}
|
||||
if(upworking == otherend){
|
||||
otherend = otherend->prev;
|
||||
}
|
||||
*frontiertop -= ncplane_dim_y(upworking->p) + 1;
|
||||
upworking = upworking->prev;
|
||||
}
|
||||
//fprintf(stderr, "done with prevs: %p->%p %d %d\n", upworking, upworking->prev, *frontiertop, frontierbottom);
|
||||
return upworking;
|
||||
}
|
||||
|
||||
// Tablets are initially drawn assuming more space to be available than may
|
||||
// actually exist. We do a pass at the end trimming any overhang.
|
||||
static int
|
||||
trim_reel_overhang(ncreel* r, nctablet* top, nctablet* bottom){
|
||||
assert(top);
|
||||
assert(top->p);
|
||||
assert(bottom);
|
||||
assert(bottom->p);
|
||||
int y;
|
||||
//fprintf(stderr, "trimming: top %p bottom %p\n", top->p, bottom->p);
|
||||
ncplane_yx(top->p, &y, NULL);
|
||||
int ylen, xlen;
|
||||
ncplane_dim_yx(top->p, &ylen, &xlen);
|
||||
const int miny = !(r->ropts.bordermask & NCBOXMASK_TOP);
|
||||
int boty = y + ylen - 1;
|
||||
//fprintf(stderr, "top: %dx%d @ %d, miny: %d\n", ylen, xlen, y, miny);
|
||||
if(boty < miny){
|
||||
//fprintf(stderr, "NUKING top!\n");
|
||||
ncplane_genocide(top->p);
|
||||
top->p = NULL;
|
||||
top->cbp = NULL;
|
||||
top = top->next;
|
||||
return trim_reel_overhang(r, top, bottom); // FIXME need this at bottom?
|
||||
}else if(y < miny){
|
||||
const int ynew = ylen - (miny - y);
|
||||
if(ynew <= 0){
|
||||
ncplane_genocide(top->p);
|
||||
top->p = NULL;
|
||||
top->cbp = NULL;
|
||||
}else{
|
||||
if(ncplane_resize(top->p, miny - y, 0, ynew, xlen, 0, 0, ynew, xlen)){
|
||||
return -1;
|
||||
}
|
||||
if(top->cbp){
|
||||
if(ynew == 1){
|
||||
ncplane_genocide(top->cbp);
|
||||
top->cbp = NULL;
|
||||
}else{
|
||||
ncplane_dim_yx(top->cbp, &ylen, &xlen);
|
||||
if(ncplane_resize(top->cbp, miny - y, 0, ynew - 1, xlen, 0, 0, ynew - 1, xlen)){
|
||||
return -1;
|
||||
}
|
||||
int x;
|
||||
ncplane_yx(top->cbp, &y, &x);
|
||||
ncplane_move_yx(top->cbp, y - 1, x);
|
||||
}
|
||||
}
|
||||
//fprintf(stderr, "TRIMMED top %p from %d to %d (%d)\n", top->p, ylen, ynew, y - miny);
|
||||
}
|
||||
}
|
||||
ncplane_dim_yx(bottom->p, &ylen, &xlen);
|
||||
ncplane_yx(bottom->p, &y, NULL);
|
||||
const int maxy = ncplane_dim_y(r->p) - (1 + !(r->ropts.bordermask & NCBOXMASK_BOTTOM));
|
||||
boty = y + ylen - 1;
|
||||
//fprintf(stderr, "bot: %dx%d @ %d, maxy: %d\n", ylen, xlen, y, maxy);
|
||||
if(maxy < boty){
|
||||
const int ynew = ylen - (boty - maxy);
|
||||
if(ynew <= 0){
|
||||
ncplane_genocide(bottom->p);
|
||||
bottom->p = NULL;
|
||||
bottom->cbp = NULL;
|
||||
}else{
|
||||
if(ncplane_resize(bottom->p, 0, 0, ynew, xlen, 0, 0, ynew, xlen)){
|
||||
return -1;
|
||||
}
|
||||
if(bottom->cbp){
|
||||
if(ynew == 1){
|
||||
ncplane_genocide(bottom->cbp);
|
||||
bottom->cbp = NULL;
|
||||
}else{
|
||||
ncplane_dim_yx(bottom->cbp, &ylen, &xlen);
|
||||
if(ncplane_resize(bottom->cbp, 0, 0, ynew - 1, xlen, 0, 0, ynew - 1, xlen)){
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
//fprintf(stderr, "TRIMMED bottom %p from %d to %d (%d)\n", bottom->p, ylen, ynew, maxy - boty);
|
||||
}
|
||||
}
|
||||
//fprintf(stderr, "finished trimming\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tighten_reel_down(ncreel* r, int ybot){
|
||||
nctablet* cur = r->tablets;
|
||||
@ -516,6 +480,7 @@ tighten_reel_down(ncreel* r, int ybot){
|
||||
}
|
||||
cury = ybot - ylen;
|
||||
ncplane_move_yx(cur->p, cury, curx);
|
||||
//fprintf(stderr, "tightened %p down to %d\n", cur, cury);
|
||||
ybot = cury - 1;
|
||||
if((cur = cur->prev) == r->tablets){
|
||||
break;
|
||||
@ -528,9 +493,11 @@ tighten_reel_down(ncreel* r, int ybot){
|
||||
// of the reel. we prefer empty space at the bottom (FIXME but not
|
||||
// really -- we ought prefer space away from the last direction of
|
||||
// movement. rather than this postprocessing, draw things to the
|
||||
// right places!).
|
||||
// right places!). we then trim any tablet overhang.
|
||||
// FIXME could pass top/bottom in directly, available as otherend
|
||||
static int
|
||||
tighten_reel(ncreel* r){
|
||||
//fprintf(stderr, "tightening it up\n");
|
||||
nctablet* top = r->tablets;
|
||||
nctablet* cur = top;
|
||||
int ytop = INT_MAX;
|
||||
@ -549,6 +516,7 @@ tighten_reel(ncreel* r){
|
||||
}
|
||||
int expected = !(r->ropts.bordermask & NCBOXMASK_TOP);
|
||||
cur = top;
|
||||
nctablet* bottom = r->tablets;
|
||||
while(cur){
|
||||
if(cur->p == NULL){
|
||||
break;
|
||||
@ -557,6 +525,7 @@ tighten_reel(ncreel* r){
|
||||
ncplane_yx(cur->p, &cury, &curx);
|
||||
if(cury != expected){
|
||||
if(ncplane_move_yx(cur->p, expected, curx)){
|
||||
//fprintf(stderr, "tightened %p up to %d\n", cur, expected);
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
@ -565,6 +534,7 @@ tighten_reel(ncreel* r){
|
||||
int ylen;
|
||||
ncplane_dim_yx(cur->p, &ylen, NULL);
|
||||
expected += ylen + 1;
|
||||
bottom = cur;
|
||||
cur = cur->next;
|
||||
if(cur == top){
|
||||
break;
|
||||
@ -581,84 +551,37 @@ tighten_reel(ncreel* r){
|
||||
// FIXME want to tighten down whenever we're at the bottom, and the reel
|
||||
// is full, not just in this case (this can leave a gap of more than 1 row)
|
||||
if(yoff + ylen + 1 >= ybot){
|
||||
return tighten_reel_down(r, ybot);
|
||||
if(tighten_reel_down(r, ybot)){
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// debugging
|
||||
bool ncreel_validate(const ncreel* n){
|
||||
if(n->tablets == NULL){
|
||||
return true;
|
||||
}
|
||||
const nctablet* t = n->tablets;
|
||||
int cury = -1;
|
||||
bool wentaround = false;
|
||||
do{
|
||||
const ncplane* np = t->p;
|
||||
if(np){
|
||||
int y, x;
|
||||
ncplane_yx(np, &y, &x);
|
||||
//fprintf(stderr, "forvart: %p (%p) @ %d\n", t, np, y);
|
||||
if(y < cury){
|
||||
if(wentaround){
|
||||
return false;
|
||||
}
|
||||
wentaround = true;
|
||||
}else if(y == cury){
|
||||
return false;
|
||||
}
|
||||
cury = y;
|
||||
}
|
||||
}while((t = t->next) != n->tablets);
|
||||
cury = INT_MAX;
|
||||
wentaround = false;
|
||||
do{
|
||||
const ncplane* np = t->p;
|
||||
if(np){
|
||||
int y, x;
|
||||
ncplane_yx(np, &y, &x);
|
||||
//fprintf(stderr, "backwards: %p (%p) @ %d\n", t, np, y);
|
||||
if(y > cury){
|
||||
if(wentaround){
|
||||
return false;
|
||||
}
|
||||
wentaround = true;
|
||||
}else if(y == cury){
|
||||
return false;
|
||||
}
|
||||
cury = y;
|
||||
}
|
||||
}while((t = t->prev) != n->tablets);
|
||||
return true;
|
||||
return trim_reel_overhang(r, top, bottom);
|
||||
}
|
||||
|
||||
// destroy all existing tablet planes pursuant to redraw
|
||||
static void
|
||||
clean_reel(ncreel* r){
|
||||
if(r->tablets){
|
||||
nctablet* cur = r->tablets->next;
|
||||
while(cur && cur != r->tablets){// && cur->p){
|
||||
//fprintf(stderr, "CLEANING: %p (%p)\n", cur, cur->p);
|
||||
if(cur->p){
|
||||
ncplane_destroy(cur->p);
|
||||
cur->p = NULL;
|
||||
nctablet* vft = r->vft;
|
||||
if(vft){
|
||||
for(nctablet* n = vft->next ; n->p && n != vft ; n = n->next){
|
||||
//fprintf(stderr, "CLEANING NEXT: %p (%p)\n", n, n->p);
|
||||
ncplane_genocide(n->p);
|
||||
n->p = NULL;
|
||||
n->cbp = NULL;
|
||||
}
|
||||
cur = cur->next;
|
||||
for(nctablet* n = vft->prev ; n->p && n != vft ; n = n->prev){
|
||||
//fprintf(stderr, "CLEANING PREV: %p (%p)\n", n, n->p);
|
||||
ncplane_genocide(n->p);
|
||||
n->p = NULL;
|
||||
n->cbp = NULL;
|
||||
}
|
||||
//fprintf(stderr, "done clean next, %p %p %p\n", cur, r->tablets, cur ? cur->p : NULL);
|
||||
cur = r->tablets->prev;
|
||||
while(cur && cur != r->tablets){// && cur->p){
|
||||
//fprintf(stderr, "CLEANING: %p (%p)\n", cur, cur->p);
|
||||
if(cur->p){
|
||||
ncplane_destroy(cur->p);
|
||||
cur->p = NULL;
|
||||
//fprintf(stderr, "CLEANING VFT: %p (%p)\n", vft, vft->p);
|
||||
ncplane_genocide(vft->p);
|
||||
vft->p = NULL;
|
||||
vft->cbp = NULL;
|
||||
r->vft = NULL;
|
||||
}
|
||||
cur = cur->prev;
|
||||
}
|
||||
}
|
||||
//fprintf(stderr, "done clean prev, %p %p %p\n", cur, r->tablets, cur ? cur->p : NULL);
|
||||
}
|
||||
|
||||
// Arrange the panels, starting with the focused window, wherever it may be.
|
||||
@ -668,37 +591,89 @@ clean_reel(ncreel* r){
|
||||
// first. If we moved up, do the tablets below. This ensures tablets stay in
|
||||
// place relative to the new focus; they could otherwise pivot around the new
|
||||
// focus, if we're not filling out the reel.
|
||||
//
|
||||
// This can still leave a gap plus a partially-onscreen tablet FIXME
|
||||
int ncreel_redraw(ncreel* nr){
|
||||
//fprintf(stderr, "--------> BEGIN REDRAW <--------\n");
|
||||
//fprintf(stderr, "\n--------> BEGIN REDRAW <--------\n");
|
||||
nctablet* focused = nr->tablets;
|
||||
int fulcrum; // target line
|
||||
if(nr->direction == LASTDIRECTION_UP){
|
||||
// case i iff the last direction was UP, and either the focused tablet is
|
||||
// not visible, or below the visibly-focused tablet, or there is no
|
||||
// visibly-focused tablet.
|
||||
if(!focused || !focused->p || !nr->vft){
|
||||
fulcrum = 0;
|
||||
//fprintf(stderr, "case i fulcrum %d\n", fulcrum);
|
||||
}else{
|
||||
int focy, vfty;
|
||||
ncplane_yx(focused->p, &focy, NULL);
|
||||
ncplane_yx(nr->vft->p, &vfty, NULL);
|
||||
if(focy > vfty){
|
||||
fulcrum = 0;
|
||||
//fprintf(stderr, "case i fulcrum %d (%d %d) %p %p\n", fulcrum, focy, vfty, focused, nr->vft);
|
||||
}else{
|
||||
ncplane_yx(focused->p, &fulcrum, NULL); // case iii
|
||||
//fprintf(stderr, "case iii fulcrum %d (%d %d) %p %p lastdir: %d\n", fulcrum, focy, vfty, focused, nr->vft, nr->direction);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
// case ii iff the last direction was DOWN, and either the focused tablet
|
||||
// is not visible, or above the visibly-focused tablet, or there is no
|
||||
// visibly-focused tablet.
|
||||
if(!focused || !focused->p || !nr->vft){
|
||||
fulcrum = ncplane_dim_y(nr->p) - 1;
|
||||
//fprintf(stderr, "case ii fulcrum %d\n", fulcrum);
|
||||
}else{
|
||||
int focy, vfty;
|
||||
//fprintf(stderr, "focused: %p\n", focused);
|
||||
ncplane_yx(focused->p, &focy, NULL);
|
||||
ncplane_yx(nr->vft->p, &vfty, NULL);
|
||||
if(focy < vfty){
|
||||
fulcrum = ncplane_dim_y(nr->p) - 1;
|
||||
//fprintf(stderr, "case ii fulcrum %d (%d %d) %p %p\n", fulcrum, focy, vfty, focused, nr->vft);
|
||||
}else{
|
||||
ncplane_yx(focused->p, &fulcrum, NULL); // case iii
|
||||
//fprintf(stderr, "case iii fulcrum %d (%d %d) %p %p lastdir: %d\n", fulcrum, focy, vfty, focused, nr->vft, nr->direction);
|
||||
}
|
||||
}
|
||||
}
|
||||
clean_reel(nr);
|
||||
if(focused){
|
||||
//fprintf(stderr, "drawing focused tablet %p dir: %d fulcrum: %d!\n", focused, nr->direction, fulcrum);
|
||||
if(ncreel_draw_tablet(nr, focused, fulcrum, fulcrum, DIRECTION_DOWN)){
|
||||
return -1;
|
||||
}
|
||||
//fprintf(stderr, "drew focused tablet %p -> %p lastdir: %d!\n", focused, focused->p, nr->direction);
|
||||
nctablet* otherend = focused;
|
||||
int frontiertop, frontierbottom;
|
||||
ncplane_yx(nr->tablets->p, &frontiertop, NULL);
|
||||
frontierbottom = frontiertop + ncplane_dim_y(nr->tablets->p) + 1;
|
||||
frontiertop -= 2;
|
||||
if(nr->direction == LASTDIRECTION_DOWN){
|
||||
otherend = draw_previous_tablets(nr, otherend, &frontiertop, frontierbottom);
|
||||
if(otherend == NULL){
|
||||
return -1;
|
||||
}
|
||||
otherend = draw_following_tablets(nr, otherend, frontiertop, &frontierbottom);
|
||||
}else{ // DIRECTION_UP
|
||||
otherend = draw_previous_tablets(nr, otherend, &frontiertop, frontierbottom);
|
||||
if(otherend == NULL){
|
||||
return -1;
|
||||
}
|
||||
otherend = draw_following_tablets(nr, otherend, frontiertop, &frontierbottom);
|
||||
}
|
||||
if(otherend == NULL){
|
||||
return -1;
|
||||
}
|
||||
//notcurses_debug(nr->p->nc, stderr);
|
||||
if(tighten_reel(nr)){
|
||||
return -1;
|
||||
}
|
||||
//notcurses_debug(nr->p->nc, stderr);
|
||||
}
|
||||
nr->vft = nr->tablets; // update the visually-focused tablet pointer
|
||||
//fprintf(stderr, "DONE ARRANGING\n");
|
||||
if(draw_ncreel_borders(nr)){
|
||||
return -1; // enforces specified dimensional minima
|
||||
}
|
||||
nctablet* focused = nr->tablets;
|
||||
if(focused == NULL){
|
||||
//fprintf(stderr, "no focus!\n");
|
||||
return 0; // if none are focused, none exist
|
||||
}
|
||||
//fprintf(stderr, "drawing focused tablet %p dir: %d!\n", focused, nr->direction);
|
||||
draw_focused_tablet(nr);
|
||||
//fprintf(stderr, "drew focused tablet %p dir: %d!\n", focused, nr->direction);
|
||||
clean_reel(nr);
|
||||
nctablet* otherend = focused;
|
||||
if(nr->direction >= DIRECTION_DOWN){
|
||||
otherend = draw_previous_tablets(nr, otherend);
|
||||
otherend = draw_following_tablets(nr, otherend);
|
||||
draw_previous_tablets(nr, otherend);
|
||||
}else{
|
||||
otherend = draw_following_tablets(nr, otherend);
|
||||
otherend = draw_previous_tablets(nr, otherend);
|
||||
draw_following_tablets(nr, otherend);
|
||||
}
|
||||
tighten_reel(nr);
|
||||
//fprintf(stderr, "DONE ARRANGING\n");
|
||||
if(!ncreel_validate(nr)){
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -727,7 +702,7 @@ validate_ncreel_opts(ncplane* w, const ncreel_options* ropts){
|
||||
}
|
||||
|
||||
ncplane* nctablet_ncplane(nctablet* t){
|
||||
return t->p;
|
||||
return t->cbp;
|
||||
}
|
||||
|
||||
ncplane* ncreel_plane(ncreel* nr){
|
||||
@ -745,9 +720,10 @@ ncreel* ncreel_create(ncplane* w, const ncreel_options* ropts){
|
||||
}
|
||||
nr->tablets = NULL;
|
||||
nr->tabletcount = 0;
|
||||
nr->direction = DIRECTION_DOWN; // draw down after the initial tablet
|
||||
nr->direction = LASTDIRECTION_DOWN; // draw down after the initial tablet
|
||||
memcpy(&nr->ropts, ropts, sizeof(*ropts));
|
||||
nr->p = w;
|
||||
nr->vft = NULL;
|
||||
ncplane_set_base(nr->p, "", 0, ropts->bgchannel);
|
||||
if(ncreel_redraw(nr)){
|
||||
ncplane_destroy(nr->p);
|
||||
@ -762,6 +738,7 @@ nctablet* ncreel_add(ncreel* nr, nctablet* after, nctablet *before,
|
||||
nctablet* t;
|
||||
if(after && before){
|
||||
if(after->prev != before || before->next != after){
|
||||
logerror(nr->p->nc, "bad before (%p) / after (%p) spec\n", before, after);
|
||||
return NULL;
|
||||
}
|
||||
}else if(!after && !before){
|
||||
@ -793,6 +770,7 @@ nctablet* ncreel_add(ncreel* nr, nctablet* after, nctablet *before,
|
||||
t->curry = opaque;
|
||||
++nr->tabletcount;
|
||||
t->p = NULL;
|
||||
t->cbp = NULL;
|
||||
return t;
|
||||
}
|
||||
|
||||
@ -805,10 +783,15 @@ int ncreel_del(ncreel* nr, struct nctablet* t){
|
||||
if((nr->tablets = t->next) == t){
|
||||
nr->tablets = NULL;
|
||||
}
|
||||
// FIXME ought set direction based on actual location of replacement t
|
||||
nr->direction = LASTDIRECTION_DOWN;
|
||||
}
|
||||
if(nr->vft == t){
|
||||
clean_reel(nr); // maybe just make nr->tablets the vft?
|
||||
}
|
||||
t->next->prev = t->prev;
|
||||
if(t->p){
|
||||
ncplane_destroy(t->p);
|
||||
ncplane_genocide(t->p);
|
||||
}
|
||||
free(t);
|
||||
--nr->tabletcount;
|
||||
@ -843,9 +826,8 @@ nctablet* ncreel_focused(ncreel* nr){
|
||||
nctablet* ncreel_next(ncreel* nr){
|
||||
if(nr->tablets){
|
||||
nr->tablets = nr->tablets->next;
|
||||
//fprintf(stderr, "---------------> moved to next, %p to %p <----------\n",
|
||||
// nr->tablets->prev, nr->tablets);
|
||||
nr->direction = DIRECTION_DOWN;
|
||||
//fprintf(stderr, "---------------> moved to next, %p to %p <----------\n", nr->tablets->prev, nr->tablets);
|
||||
nr->direction = LASTDIRECTION_DOWN;
|
||||
}
|
||||
return nr->tablets;
|
||||
}
|
||||
@ -853,9 +835,8 @@ nctablet* ncreel_next(ncreel* nr){
|
||||
nctablet* ncreel_prev(ncreel* nr){
|
||||
if(nr->tablets){
|
||||
nr->tablets = nr->tablets->prev;
|
||||
//fprintf(stderr, "----------------> moved to prev, %p to %p <----------\n",
|
||||
// nr->tablets->next, nr->tablets);
|
||||
nr->direction = DIRECTION_UP;
|
||||
//fprintf(stderr, "----------------> moved to prev, %p to %p <----------\n", nr->tablets->next, nr->tablets);
|
||||
nr->direction = LASTDIRECTION_UP;
|
||||
}
|
||||
return nr->tablets;
|
||||
}
|
||||
|
@ -40,12 +40,7 @@ class TabletCtx {
|
||||
inline static int class_idx = 0;
|
||||
};
|
||||
|
||||
int tabletfxn(struct nctablet* _t, int begx, int begy, int maxx, int maxy,
|
||||
bool cliptop){
|
||||
(void)begx;
|
||||
(void)begy;
|
||||
(void)maxx;
|
||||
(void)maxy;
|
||||
int tabletfxn(struct nctablet* _t, bool cliptop){
|
||||
(void)cliptop;
|
||||
NcTablet *t = NcTablet::map_tablet (_t);
|
||||
Plane* p = t->get_plane();
|
||||
@ -65,6 +60,7 @@ void usage(const char* argv0, std::ostream& c, int status){
|
||||
c << "usage: " << argv0 << " [ -h ] | options\n"
|
||||
<< " -b bordermask: hex ncreel border mask (0x0..0xf)\n"
|
||||
<< " -m margin(s): margin(s) around the reel\n"
|
||||
<< " -ln: logging level, higher n for more output (0 ≤ n ≤ 8)\n"
|
||||
<< " -t tabletmask: hex tablet border mask (0x0..0xf)" << std::endl;
|
||||
exit(status);
|
||||
}
|
||||
@ -75,9 +71,19 @@ void parse_args(int argc, char** argv, struct notcurses_options* opts,
|
||||
{ .name = nullptr, .has_arg = 0, .flag = nullptr, .val = 0, },
|
||||
};
|
||||
int c;
|
||||
while((c = getopt_long(argc, argv, "b:t:m:h", longopts, nullptr)) != -1){
|
||||
while((c = getopt_long(argc, argv, "l:b:t:m:h", longopts, nullptr)) != -1){
|
||||
switch(c){
|
||||
case 'b':{
|
||||
case 'l':{
|
||||
int loglevel;
|
||||
std::stringstream s(optarg);
|
||||
s >> loglevel;
|
||||
opts->loglevel = static_cast<ncloglevel_e>(loglevel);
|
||||
if(opts->loglevel < NCLOGLEVEL_SILENT || opts->loglevel > NCLOGLEVEL_TRACE){
|
||||
fprintf(stderr, "Invalid log level: %d\n", opts->loglevel);
|
||||
usage(argv[0], std::cerr, EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
}case 'b':{
|
||||
std::stringstream ss;
|
||||
ss << std::hex << optarg;
|
||||
ss >> ropts->bordermask;
|
||||
|
275
tests/reel.cpp
275
tests/reel.cpp
@ -1,16 +1,70 @@
|
||||
#include "main.h"
|
||||
#include <iostream>
|
||||
|
||||
auto panelcb(struct nctablet* t, int begx, int begy, int maxx, int maxy, bool cliptop) -> int {
|
||||
auto panelcb(struct nctablet* t, bool toptobottom) -> int {
|
||||
CHECK(nctablet_ncplane(t));
|
||||
CHECK(begx < maxx);
|
||||
CHECK(begy < maxy);
|
||||
CHECK(!nctablet_userptr(t));
|
||||
CHECK(!cliptop);
|
||||
CHECK(toptobottom);
|
||||
// FIXME verify geometry is as expected
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto cbfxn(struct nctablet* t, bool toptobottom) -> int {
|
||||
(void)toptobottom;
|
||||
int* userptr = static_cast<int*>(nctablet_userptr(t));
|
||||
int y;
|
||||
ncplane_yx(nctablet_ncplane(t), &y, NULL);
|
||||
*userptr += y;
|
||||
return 4;
|
||||
}
|
||||
|
||||
// debugging
|
||||
bool ncreel_validate(const ncreel* n){
|
||||
if(n->tablets == NULL){
|
||||
return true;
|
||||
}
|
||||
const nctablet* t = n->tablets;
|
||||
int cury = -1;
|
||||
bool wentaround = false;
|
||||
do{
|
||||
const ncplane* np = t->p;
|
||||
if(np){
|
||||
int y, x;
|
||||
ncplane_yx(np, &y, &x);
|
||||
//fprintf(stderr, "forvart: %p (%p) @ %d\n", t, np, y);
|
||||
if(y < cury){
|
||||
if(wentaround){
|
||||
return false;
|
||||
}
|
||||
wentaround = true;
|
||||
}else if(y == cury){
|
||||
return false;
|
||||
}
|
||||
cury = y;
|
||||
}
|
||||
}while((t = t->next) != n->tablets);
|
||||
cury = INT_MAX;
|
||||
wentaround = false;
|
||||
do{
|
||||
const ncplane* np = t->p;
|
||||
if(np){
|
||||
int y, x;
|
||||
ncplane_yx(np, &y, &x);
|
||||
//fprintf(stderr, "backwards: %p (%p) @ %d\n", t, np, y);
|
||||
if(y > cury){
|
||||
if(wentaround){
|
||||
return false;
|
||||
}
|
||||
wentaround = true;
|
||||
}else if(y == cury){
|
||||
return false;
|
||||
}
|
||||
cury = y;
|
||||
}
|
||||
}while((t = t->prev) != n->tablets);
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST_CASE("Reels") {
|
||||
auto nc_ = testing_notcurses();
|
||||
if(!nc_){
|
||||
@ -38,6 +92,7 @@ TEST_CASE("Reels") {
|
||||
r.flags = NCREEL_OPTION_INFINITESCROLL | NCREEL_OPTION_CIRCULAR;
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(nr);
|
||||
CHECK(ncreel_validate(nr));
|
||||
REQUIRE(0 == ncreel_destroy(nr));
|
||||
}
|
||||
|
||||
@ -56,9 +111,13 @@ TEST_CASE("Reels") {
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(nr);
|
||||
CHECK(!ncreel_next(nr));
|
||||
// CHECK_EQ(0, ncreel_validate(n_, pr));
|
||||
CHECK_EQ(0, ncreel_redraw(nr));
|
||||
CHECK_EQ(0, notcurses_render(nc_));
|
||||
CHECK(ncreel_validate(nr));
|
||||
CHECK(!ncreel_prev(nr));
|
||||
// CHECK_EQ(0, ncreel_validate(n_, pr));
|
||||
CHECK_EQ(0, ncreel_redraw(nr));
|
||||
CHECK_EQ(0, notcurses_render(nc_));
|
||||
CHECK(ncreel_validate(nr));
|
||||
}
|
||||
|
||||
SUBCASE("OneTablet") {
|
||||
@ -67,9 +126,13 @@ TEST_CASE("Reels") {
|
||||
REQUIRE(nr);
|
||||
struct nctablet* t = ncreel_add(nr, nullptr, nullptr, panelcb, nullptr);
|
||||
REQUIRE(t);
|
||||
// CHECK_EQ(0, ncreel_validate(n_, pr));
|
||||
CHECK_EQ(0, ncreel_redraw(nr));
|
||||
CHECK_EQ(0, notcurses_render(nc_));
|
||||
CHECK(ncreel_validate(nr));
|
||||
CHECK(0 == ncreel_del(nr, t));
|
||||
// CHECK_EQ(0, ncreel_validate(n_, pr));
|
||||
CHECK_EQ(0, ncreel_redraw(nr));
|
||||
CHECK_EQ(0, notcurses_render(nc_));
|
||||
CHECK(ncreel_validate(nr));
|
||||
}
|
||||
|
||||
SUBCASE("MovementWithOneTablet") {
|
||||
@ -78,13 +141,21 @@ TEST_CASE("Reels") {
|
||||
REQUIRE(nr);
|
||||
struct nctablet* t = ncreel_add(nr, nullptr, nullptr, panelcb, nullptr);
|
||||
REQUIRE(t);
|
||||
// CHECK_EQ(0, ncreel_validate(n_, pr));
|
||||
CHECK_EQ(0, ncreel_redraw(nr));
|
||||
CHECK_EQ(0, notcurses_render(nc_));
|
||||
CHECK(ncreel_validate(nr));
|
||||
CHECK(ncreel_next(nr));
|
||||
// CHECK_EQ(0, ncreel_validate(n_, pr));
|
||||
CHECK_EQ(0, ncreel_redraw(nr));
|
||||
CHECK_EQ(0, notcurses_render(nc_));
|
||||
CHECK(ncreel_validate(nr));
|
||||
CHECK(ncreel_prev(nr));
|
||||
// CHECK_EQ(0, ncreel_validate(n_, pr));
|
||||
CHECK_EQ(0, ncreel_redraw(nr));
|
||||
CHECK_EQ(0, notcurses_render(nc_));
|
||||
CHECK(ncreel_validate(nr));
|
||||
CHECK(0 == ncreel_del(nr, t));
|
||||
// CHECK_EQ(0, ncreel_validate(n_, pr));
|
||||
CHECK_EQ(0, ncreel_redraw(nr));
|
||||
CHECK_EQ(0, notcurses_render(nc_));
|
||||
CHECK(ncreel_validate(nr));
|
||||
}
|
||||
|
||||
SUBCASE("DeleteActiveTablet") {
|
||||
@ -94,6 +165,9 @@ TEST_CASE("Reels") {
|
||||
struct nctablet* t = ncreel_add(nr, nullptr, nullptr, panelcb, nullptr);
|
||||
REQUIRE(t);
|
||||
CHECK(0 == ncreel_del(nr, ncreel_focused(nr)));
|
||||
CHECK_EQ(0, ncreel_redraw(nr));
|
||||
CHECK_EQ(0, notcurses_render(nc_));
|
||||
CHECK(ncreel_validate(nr));
|
||||
}
|
||||
|
||||
SUBCASE("NoBorder") {
|
||||
@ -102,6 +176,9 @@ TEST_CASE("Reels") {
|
||||
NCBOXMASK_TOP | NCBOXMASK_BOTTOM;
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(nr);
|
||||
CHECK_EQ(0, ncreel_redraw(nr));
|
||||
CHECK_EQ(0, notcurses_render(nc_));
|
||||
CHECK(ncreel_validate(nr));
|
||||
}
|
||||
|
||||
SUBCASE("BadBorderBitsRejected") {
|
||||
@ -117,6 +194,9 @@ TEST_CASE("Reels") {
|
||||
NCBOXMASK_TOP | NCBOXMASK_BOTTOM;
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(nr);
|
||||
CHECK_EQ(0, ncreel_redraw(nr));
|
||||
CHECK_EQ(0, notcurses_render(nc_));
|
||||
CHECK(ncreel_validate(nr));
|
||||
}
|
||||
|
||||
SUBCASE("NoTopBottomBorder") {
|
||||
@ -124,6 +204,9 @@ TEST_CASE("Reels") {
|
||||
r.bordermask = NCBOXMASK_TOP | NCBOXMASK_BOTTOM;
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(nr);
|
||||
CHECK_EQ(0, ncreel_redraw(nr));
|
||||
CHECK_EQ(0, notcurses_render(nc_));
|
||||
CHECK(ncreel_validate(nr));
|
||||
}
|
||||
|
||||
SUBCASE("NoSideBorders") {
|
||||
@ -131,6 +214,9 @@ TEST_CASE("Reels") {
|
||||
r.bordermask = NCBOXMASK_LEFT | NCBOXMASK_RIGHT;
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(nr);
|
||||
CHECK_EQ(0, ncreel_redraw(nr));
|
||||
CHECK_EQ(0, notcurses_render(nc_));
|
||||
CHECK(ncreel_validate(nr));
|
||||
}
|
||||
|
||||
SUBCASE("BadTabletBorderBitsRejected") {
|
||||
@ -140,90 +226,97 @@ TEST_CASE("Reels") {
|
||||
REQUIRE(!nr);
|
||||
}
|
||||
|
||||
/*
|
||||
// Make a target window occupying all but a containing perimeter of the
|
||||
// specified WINDOW (which will usually be n_).
|
||||
struct ncpanel* make_targwin(struct ncpanel* w) {
|
||||
cchar_t cc;
|
||||
int cpair = COLOR_GREEN;
|
||||
CHECK_EQ(OK, setcchar(&cc, L"W", 0, 0, &cpair));
|
||||
int x, y, xx, yy;
|
||||
getbegyx(w, y, x);
|
||||
getmaxyx(w, yy, xx);
|
||||
yy -= 2;
|
||||
xx -= 2;
|
||||
++x;
|
||||
++y;
|
||||
WINDOW* ww = subwin(w, yy, xx, y, x);
|
||||
CHECK_NE(nullptr, ww);
|
||||
PANEL* p = new_panel(ww);
|
||||
CHECK_NE(nullptr, p);
|
||||
CHECK_EQ(OK, wbkgrnd(ww, &cc));
|
||||
return p;
|
||||
}
|
||||
|
||||
SUBCASE("InitWithinSubwin") {
|
||||
ncreel_options r{};
|
||||
r.loff = 1;
|
||||
r.roff = 1;
|
||||
r.toff = 1;
|
||||
r.boff = 1;
|
||||
CHECK_EQ(0, clear());
|
||||
PANEL* base = make_targwin(n_);
|
||||
REQUIRE_NE(nullptr, base);
|
||||
WINDOW* basew = panel_window(base);
|
||||
REQUIRE_NE(nullptr, basew);
|
||||
struct ncreel* nr = ncreel_create(basew, &r);
|
||||
REQUIRE_NE(nullptr, pr);
|
||||
CHECK_EQ(0, ncreel_validate(basew, pr));
|
||||
REQUIRE_EQ(0, ncreel_destroy(nr));
|
||||
CHECK_EQ(OK, del_panel(base));
|
||||
CHECK_EQ(OK, delwin(basew));
|
||||
}
|
||||
|
||||
SUBCASE("SubwinNoncreelBorders") {
|
||||
ncreel_options r{};
|
||||
r.loff = 1;
|
||||
r.roff = 1;
|
||||
r.toff = 1;
|
||||
r.boff = 1;
|
||||
r.bordermask = NCBOXMASK_LEFT | NCBOXMASK_RIGHT |
|
||||
NCBOXMASK_TOP | NCBOXMASK_BOTTOM;
|
||||
CHECK_EQ(0, clear());
|
||||
PANEL* base = make_targwin(n_);
|
||||
REQUIRE_NE(nullptr, base);
|
||||
WINDOW* basew = panel_window(base);
|
||||
REQUIRE_NE(nullptr, basew);
|
||||
struct ncreel* nr = ncreel_create(basew, &r);
|
||||
REQUIRE_NE(nullptr, pr);
|
||||
CHECK_EQ(0, ncreel_validate(basew, pr));
|
||||
REQUIRE_EQ(0, ncreel_destroy(nr));
|
||||
CHECK_EQ(OK, del_panel(base));
|
||||
CHECK_EQ(OK, delwin(basew));
|
||||
}
|
||||
|
||||
SUBCASE("SubwinNoOffsetGeom") {
|
||||
ncreel_options r{};
|
||||
CHECK_EQ(0, clear());
|
||||
PANEL* base = make_targwin(n_);
|
||||
REQUIRE_NE(nullptr, base);
|
||||
WINDOW* basew = panel_window(base);
|
||||
REQUIRE_NE(nullptr, basew);
|
||||
struct ncreel* nr = ncreel_create(basew, &r);
|
||||
REQUIRE_NE(nullptr, pr);
|
||||
CHECK_EQ(0, ncreel_validate(basew, pr));
|
||||
REQUIRE_EQ(0, ncreel_destroy(nr));
|
||||
CHECK_EQ(OK, del_panel(base));
|
||||
CHECK_EQ(OK, delwin(basew));
|
||||
}
|
||||
*/
|
||||
|
||||
SUBCASE("TransparentBackground") {
|
||||
ncreel_options r{};
|
||||
channels_set_bg_alpha(&r.bgchannel, 3);
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(nr);
|
||||
// FIXME
|
||||
CHECK_EQ(0, ncreel_redraw(nr));
|
||||
CHECK_EQ(0, notcurses_render(nc_));
|
||||
CHECK(ncreel_validate(nr));
|
||||
}
|
||||
|
||||
// Layout tests. Add some tablets, move around, and verify that they all
|
||||
// have the expected locations/contents/geometries.
|
||||
SUBCASE("ThreeCycleDown") {
|
||||
ncreel_options r{};
|
||||
channels_set_bg_alpha(&r.bgchannel, 3);
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(nr);
|
||||
CHECK_EQ(0, ncreel_redraw(nr));
|
||||
CHECK_EQ(0, notcurses_render(nc_));
|
||||
CHECK(ncreel_validate(nr));
|
||||
int order[3];
|
||||
nctablet* tabs[3];
|
||||
for(size_t n = 0 ; n < sizeof(order) / sizeof(*order) ; ++n){
|
||||
order[n] = -1;
|
||||
tabs[n] = ncreel_add(nr, nullptr, nullptr, cbfxn, &order[n]);
|
||||
REQUIRE(tabs[n]);
|
||||
CHECK(tabs[0] == nr->tablets);
|
||||
CHECK_EQ(0, ncreel_redraw(nr));
|
||||
CHECK_EQ(0, notcurses_render(nc_));
|
||||
CHECK(ncreel_validate(nr));
|
||||
}
|
||||
int expectedy = 1;
|
||||
for(size_t n = 0 ; n < sizeof(order) / sizeof(*order) ; ++n){
|
||||
CHECK_LE(0, order[n]);
|
||||
int y;
|
||||
ncplane_yx(ncplane_parent(nctablet_ncplane(tabs[n])), &y, nullptr);
|
||||
CHECK(y == expectedy);
|
||||
expectedy += 7;
|
||||
}
|
||||
ncreel_next(nr);
|
||||
CHECK(tabs[1] == nr->tablets);
|
||||
CHECK_EQ(0, ncreel_redraw(nr));
|
||||
CHECK_EQ(0, notcurses_render(nc_));
|
||||
CHECK(ncreel_validate(nr));
|
||||
expectedy = 1;
|
||||
for(size_t n = 0 ; n < sizeof(order) / sizeof(*order) ; ++n){
|
||||
CHECK_LE(1, order[n]);
|
||||
int y;
|
||||
ncplane_yx(ncplane_parent(nctablet_ncplane(tabs[n])), &y, nullptr);
|
||||
CHECK(y == expectedy);
|
||||
expectedy += 7;
|
||||
}
|
||||
ncreel_next(nr);
|
||||
CHECK(tabs[2] == nr->tablets);
|
||||
CHECK_EQ(0, ncreel_redraw(nr));
|
||||
CHECK_EQ(0, notcurses_render(nc_));
|
||||
CHECK(ncreel_validate(nr));
|
||||
expectedy = 1;
|
||||
for(size_t n = 0 ; n < sizeof(order) / sizeof(*order) ; ++n){
|
||||
//CHECK_EQ(2 - n + 2, order[n]);
|
||||
int y;
|
||||
ncplane_yx(ncplane_parent(nctablet_ncplane(tabs[n])), &y, nullptr);
|
||||
CHECK(y == expectedy);
|
||||
expectedy += 7;
|
||||
}
|
||||
ncreel_prev(nr);
|
||||
CHECK(tabs[1] == nr->tablets);
|
||||
CHECK_EQ(0, ncreel_redraw(nr));
|
||||
CHECK_EQ(0, notcurses_render(nc_));
|
||||
CHECK(ncreel_validate(nr));
|
||||
expectedy = 1;
|
||||
for(size_t n = 0 ; n < sizeof(order) / sizeof(*order) ; ++n){
|
||||
//CHECK_EQ(2 - n + 3, order[n]);
|
||||
int y;
|
||||
ncplane_yx(ncplane_parent(nctablet_ncplane(tabs[n])), &y, nullptr);
|
||||
CHECK(y == expectedy);
|
||||
expectedy += 7;
|
||||
}
|
||||
ncreel_prev(nr);
|
||||
CHECK(tabs[0] == nr->tablets);
|
||||
CHECK_EQ(0, ncreel_redraw(nr));
|
||||
CHECK_EQ(0, notcurses_render(nc_));
|
||||
CHECK(ncreel_validate(nr));
|
||||
expectedy = 1;
|
||||
for(size_t n = 0 ; n < sizeof(order) / sizeof(*order) ; ++n){
|
||||
//CHECK_EQ(2 - n + 4, order[n]);
|
||||
int y;
|
||||
ncplane_yx(ncplane_parent(nctablet_ncplane(tabs[n])), &y, nullptr);
|
||||
CHECK(y == expectedy);
|
||||
expectedy += 7;
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(0 == notcurses_stop(nc_));
|
||||
|
Loading…
x
Reference in New Issue
Block a user