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
|
project(notcurses VERSION 1.6.11
|
||||||
DESCRIPTION "UI for modern terminal emulators"
|
DESCRIPTION "UI for modern terminal emulators"
|
||||||
HOMEPAGE_URL "https://nick-black.com/dankwiki/index.php/notcurses"
|
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.
|
rearrangements of Notcurses.
|
||||||
|
|
||||||
* 1.6.12 (not yet released)
|
* 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
|
* `ncselector_redraw()` and `ncmultiselector_redraw()` no longer call
|
||||||
`notcurses_render()`. You will need to call `notcurses_render()` for the
|
`notcurses_render()`. You will need to call `notcurses_render()` for the
|
||||||
display to reflect any changes. `ncselector_create` now binds the plane
|
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
|
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.
|
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)
|
* 1.6.11 (2020-08-03)
|
||||||
* `cell_egc_idx()` is no longer exported; it was never intended to be.
|
* `cell_egc_idx()` is no longer exported; it was never intended to be.
|
||||||
|
@ -112,7 +112,7 @@ that fine library.
|
|||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
* (build) A C11 and a C++17 compiler
|
* (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) From NCURSES: terminfo 6.1+
|
||||||
* (build+runtime) GNU libunistring 0.9.10+
|
* (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+
|
* (OPTIONAL) (build+runtime) From QR-Code-generator: [libqrcodegen](https://github.com/nayuki/QR-Code-generator) 1.5.0+
|
||||||
|
48
USAGE.md
48
USAGE.md
@ -536,7 +536,7 @@ typedef struct ncinput {
|
|||||||
// be NULL. Returns 0 on a timeout. If an event is processed, the return value
|
// be NULL. Returns 0 on a timeout. If an event is processed, the return value
|
||||||
// is the 'id' field from that event. 'ni' may be NULL.
|
// is the 'id' field from that event. 'ni' may be NULL.
|
||||||
char32_t notcurses_getc(struct notcurses* n, const struct timespec* ts,
|
char32_t notcurses_getc(struct notcurses* n, const struct timespec* ts,
|
||||||
sigset_t* sigmask, ncinput* ni);
|
sigset_t* sigmask, ncinput* ni);
|
||||||
|
|
||||||
// 'ni' may be NULL if the caller is uninterested in event details. If no event
|
// 'ni' may be NULL if the caller is uninterested in event details. If no event
|
||||||
// is ready, returns 0.
|
// is ready, returns 0.
|
||||||
@ -617,9 +617,10 @@ quickly reset the `ncplane`, use `ncplane_erase()`.
|
|||||||
struct ncplane* ncplane_new(struct notcurses* nc, int rows, int cols,
|
struct ncplane* ncplane_new(struct notcurses* nc, int rows, int cols,
|
||||||
int yoff, int xoff, void* opaque);
|
int yoff, int xoff, void* opaque);
|
||||||
|
|
||||||
// Create a new ncplane aligned relative to 'n'.
|
// Create a named plane ala ncplane_new(). Names are only used for debugging.
|
||||||
struct ncplane* ncplane_aligned(struct ncplane* n, int rows, int cols,
|
struct ncplane* ncplane_new_named(struct notcurses* nc, int rows, int cols,
|
||||||
int yoff, ncalign_e align, void* opaque);
|
int yoff, int xoff, void* opaque,
|
||||||
|
const char* name);
|
||||||
|
|
||||||
// Create a plane bound to plane 'n'. Being bound to 'n' means that 'yoff' and
|
// 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
|
// '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,
|
struct ncplane* ncplane_bound(struct ncplane* n, int rows, int cols,
|
||||||
int yoff, int xoff, void* opaque);
|
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,
|
// 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.
|
// and will be made a bound child of 'newparent', if 'newparent' is not NULL.
|
||||||
struct ncplane* ncplane_reparent(struct ncplane* n, struct ncplane* newparent);
|
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,
|
// Duplicate an existing ncplane. The new plane will have the same geometry,
|
||||||
// will duplicate all content, and will start with the same rendering state.
|
// will duplicate all content, and will start with the same rendering state.
|
||||||
struct ncplane* ncplane_dup(struct ncplane* n, void* opaque);
|
struct ncplane* ncplane_dup(struct ncplane* n, void* opaque);
|
||||||
@ -699,7 +718,7 @@ It is an error to invoke these functions on the standard plane.
|
|||||||
// Essentially, the kept material does not move. It serves to anchor the
|
// 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.
|
// resized plane. If there is no kept material, the plane can move freely.
|
||||||
int ncplane_resize(struct ncplane* n, int keepy, int keepx, int keepleny,
|
int ncplane_resize(struct ncplane* n, int keepy, int keepx, int keepleny,
|
||||||
int keeplenx, int yoff, int xoff, int ylen, int xlen);
|
int keeplenx, int yoff, int xoff, int ylen, int xlen);
|
||||||
|
|
||||||
// Resize the plane, retaining what data we can (everything, unless we're
|
// Resize the plane, retaining what data we can (everything, unless we're
|
||||||
// shrinking in some dimension). Keep the origin where it is.
|
// shrinking in some dimension). Keep the origin where it is.
|
||||||
@ -1038,10 +1057,10 @@ ncplane_putwstr(struct ncplane* n, const wchar_t* gclustarr){
|
|||||||
|
|
||||||
// The ncplane equivalents of printf(3) and vprintf(3).
|
// The ncplane equivalents of printf(3) and vprintf(3).
|
||||||
int ncplane_vprintf_aligned(struct ncplane* n, int y, ncalign_e align,
|
int ncplane_vprintf_aligned(struct ncplane* n, int y, ncalign_e align,
|
||||||
const char* format, va_list ap);
|
const char* format, va_list ap);
|
||||||
|
|
||||||
int ncplane_vprintf_yx(struct ncplane* n, int y, int x,
|
int ncplane_vprintf_yx(struct ncplane* n, int y, int x,
|
||||||
const char* format, va_list ap);
|
const char* format, va_list ap);
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
ncplane_vprintf(struct ncplane* n, const char* format, va_list ap){
|
ncplane_vprintf(struct ncplane* n, const char* format, va_list ap){
|
||||||
@ -1119,7 +1138,7 @@ on both sides. Boxes allow fairly detailed specification of how they're drawn.
|
|||||||
// number of cells drawn on success. On error, return the negative number of
|
// number of cells drawn on success. On error, return the negative number of
|
||||||
// cells drawn.
|
// cells drawn.
|
||||||
int ncplane_hline_interp(struct ncplane* n, const cell* c, int len,
|
int ncplane_hline_interp(struct ncplane* n, const cell* c, int len,
|
||||||
uint64_t c1, uint64_t c2);
|
uint64_t c1, uint64_t c2);
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
ncplane_hline(struct ncplane* n, const cell* c, int len){
|
ncplane_hline(struct ncplane* n, const cell* c, int len){
|
||||||
@ -1127,7 +1146,7 @@ ncplane_hline(struct ncplane* n, const cell* c, int len){
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ncplane_vline_interp(struct ncplane* n, const cell* c, int len,
|
int ncplane_vline_interp(struct ncplane* n, const cell* c, int len,
|
||||||
uint64_t c1, uint64_t c2);
|
uint64_t c1, uint64_t c2);
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
ncplane_vline(struct ncplane* n, const cell* c, int len){
|
ncplane_vline(struct ncplane* n, const cell* c, int len){
|
||||||
@ -1165,9 +1184,8 @@ ncplane_vline(struct ncplane* n, const cell* c, int len){
|
|||||||
#define NCBOXCORNER_SHIFT 8u
|
#define NCBOXCORNER_SHIFT 8u
|
||||||
|
|
||||||
int ncplane_box(struct ncplane* n, const cell* ul, const cell* ur,
|
int ncplane_box(struct ncplane* n, const cell* ul, const cell* ur,
|
||||||
const cell* ll, const cell* lr, const cell* hline,
|
const cell* ll, const cell* lr, const cell* hline,
|
||||||
const cell* vline, int ystop, int xstop,
|
const cell* vline, int ystop, int xstop, unsigned ctlword);
|
||||||
unsigned ctlword);
|
|
||||||
|
|
||||||
// Draw a box with its upper-left corner at the current cursor position, having
|
// 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
|
// dimensions 'ylen'x'xlen'. See ncplane_box() for more information. The
|
||||||
@ -1323,13 +1341,13 @@ typedef int (*fadecb)(struct notcurses* nc, struct ncplane* ncp,
|
|||||||
// modification (if the terminal uses a palette, our ability to fade planes is
|
// modification (if the terminal uses a palette, our ability to fade planes is
|
||||||
// limited, and affected by the complexity of the rest of the screen).
|
// limited, and affected by the complexity of the rest of the screen).
|
||||||
int ncplane_fadeout(struct ncplane* n, const struct timespec* ts,
|
int ncplane_fadeout(struct ncplane* n, const struct timespec* ts,
|
||||||
fadecb fader, void* curry);
|
fadecb fader, void* curry);
|
||||||
|
|
||||||
// Fade the ncplane in over the specified time. Load the ncplane with the
|
// Fade the ncplane in over the specified time. Load the ncplane with the
|
||||||
// target cells without rendering, then call this function. When it's done, the
|
// target cells without rendering, then call this function. When it's done, the
|
||||||
// ncplane will have reached the target levels, starting from zeroes.
|
// ncplane will have reached the target levels, starting from zeroes.
|
||||||
int ncplane_fadein(struct ncplane* n, const struct timespec* ts,
|
int ncplane_fadein(struct ncplane* n, const struct timespec* ts,
|
||||||
fadecb fader, void* curry);
|
fadecb fader, void* curry);
|
||||||
|
|
||||||
// Rather than the simple ncplane_fade{in/out}(), ncfadectx_setup() can be
|
// Rather than the simple ncplane_fade{in/out}(), ncfadectx_setup() can be
|
||||||
// Pulse the plane in and out until the callback returns non-zero, relying on
|
// Pulse the plane in and out until the callback returns non-zero, relying on
|
||||||
@ -1382,8 +1400,6 @@ int ncblit_bgrx(const void* data, int linesize,
|
|||||||
const struct ncvisual_options* vopts);
|
const struct ncvisual_options* vopts);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Plane channels API
|
### Plane channels API
|
||||||
|
|
||||||
Helpers are provided to manipulate an `ncplane`'s `channels` member. They are
|
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.
|
**-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.
|
**-f renderfile**: Render each frame to **renderfile** in addition to the screen.
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ notcurses-ncreel - Experiment with ncreels
|
|||||||
|
|
||||||
# SYNOPSIS
|
# 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
|
# DESCRIPTION
|
||||||
|
|
||||||
@ -18,6 +18,8 @@ tablet (if one exists). 'q' quits at any time.
|
|||||||
|
|
||||||
# OPTIONS
|
# OPTIONS
|
||||||
|
|
||||||
|
**-l loglevel**: Log everything (log level 8) or nothing (log level 0) to stderr.
|
||||||
|
|
||||||
# NOTES
|
# NOTES
|
||||||
|
|
||||||
Optimal display requires a terminal advertising the **rgb** terminfo(5)
|
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(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(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(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);**
|
**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);**
|
**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);**
|
**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_cell(struct ncplane* ncp, const cell* c);**
|
||||||
|
|
||||||
**int ncplane_set_base(struct ncplane* ncp, const char* egc, uint32_t attrword, uint64_t channels);**
|
**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,
|
API struct ncplane* ncplane_new(struct notcurses* nc, int rows, int cols,
|
||||||
int yoff, int xoff, void* opaque);
|
int yoff, int xoff, void* opaque);
|
||||||
|
|
||||||
API struct ncplane* ncplane_aligned(struct ncplane* n, int rows, int cols,
|
// Create a named plane ala ncplane_new(). Names are only used for debugging.
|
||||||
int yoff, ncalign_e align, void* opaque);
|
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
|
// 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
|
// '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,
|
API struct ncplane* ncplane_bound(struct ncplane* n, int rows, int cols,
|
||||||
int yoff, int xoff, void* opaque);
|
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,
|
// 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.
|
// 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);
|
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).
|
// 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);
|
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.
|
// 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_top(struct ncplane* n);
|
||||||
API void ncplane_move_bottom(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);
|
API struct ncplane* ncreel_plane(struct ncreel* pr);
|
||||||
|
|
||||||
// Tablet draw callback, provided a tablet (from which the ncplane and userptr
|
// 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
|
// may be extracted), and a bool indicating whether output ought be drawn from
|
||||||
// be used, the first column that may not be used, the first row that may not
|
// the top (true) or bottom (false). Returns non-negative count of output lines,
|
||||||
// be used, and a bool indicating whether output ought be clipped at the top
|
// which must be less than or equal to ncplane_dim_y(nctablet_plane(t)).
|
||||||
// (true) or bottom (false). Rows and columns are zero-indexed, and both are
|
typedef int (*tabletcb)(struct nctablet* t, bool drawfromtop);
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Add a new nctablet to the provided ncreel, having the callback object
|
// 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
|
// 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);
|
struct ncplane* notcurses_top(struct notcurses* n);
|
||||||
void notcurses_drop_planes(struct notcurses* nc);
|
void notcurses_drop_planes(struct notcurses* nc);
|
||||||
int notcurses_refresh(struct notcurses* n, int* restrict y, int* restrict x);
|
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);
|
struct ncplane* ncplane_reparent(struct ncplane* n, struct ncplane* newparent);
|
||||||
typedef enum {
|
typedef enum {
|
||||||
NCALIGN_LEFT,
|
NCALIGN_LEFT,
|
||||||
NCALIGN_CENTER,
|
NCALIGN_CENTER,
|
||||||
NCALIGN_RIGHT,
|
NCALIGN_RIGHT,
|
||||||
} ncalign_e;
|
} 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(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);
|
unsigned notcurses_supported_styles(const struct notcurses* nc);
|
||||||
int notcurses_palette_size(const struct notcurses* nc);
|
int notcurses_palette_size(const struct notcurses* nc);
|
||||||
bool notcurses_cantruecolor(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_canopen_images(const struct ncdirect* n);
|
||||||
bool ncdirect_canutf8(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);
|
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__":
|
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
|
// partially off-screen), but also leave unused space at the end (since
|
||||||
// wresize() only keeps the top and left on a shrink).
|
// wresize() only keeps the top and left on a shrink).
|
||||||
static int
|
static int
|
||||||
tabletup(struct ncplane* w, int begx, int begy, int maxx, int maxy,
|
tabletup(struct ncplane* w, int maxy, tabletctx* tctx, int rgb){
|
||||||
tabletctx* tctx, int rgb){
|
|
||||||
char cchbuf[2];
|
char cchbuf[2];
|
||||||
cell c = CELL_TRIVIAL_INITIALIZER;
|
cell c = CELL_TRIVIAL_INITIALIZER;
|
||||||
int y, idx;
|
int y, idx;
|
||||||
idx = tctx->lines;
|
idx = tctx->lines;
|
||||||
if(maxy - begy > tctx->lines){
|
int maxx = ncplane_dim_x(w) - 1;
|
||||||
maxy -= (maxy - begy - tctx->lines);
|
if(maxy > tctx->lines){
|
||||||
|
maxy = tctx->lines;
|
||||||
}
|
}
|
||||||
/*fprintf(stderr, "-OFFSET BY %d (%d->%d)\n", maxy - begy - tctx->lines,
|
/*fprintf(stderr, "-OFFSET BY %d (%d->%d)\n", maxy - begy - tctx->lines,
|
||||||
maxy, maxy - (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);
|
snprintf(cchbuf, sizeof(cchbuf) / sizeof(*cchbuf), "%x", idx % 16);
|
||||||
cell_load(w, &c, cchbuf);
|
cell_load(w, &c, cchbuf);
|
||||||
if(cell_set_fg_rgb(&c, (rgb >> 16u) % 0xffu, (rgb >> 8u) % 0xffu, rgb % 0xffu)){
|
if(cell_set_fg_rgb(&c, (rgb >> 16u) % 0xffu, (rgb >> 8u) % 0xffu, rgb % 0xffu)){
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int x;
|
int x;
|
||||||
for(x = begx ; x <= maxx ; ++x){
|
for(x = 0 ; x <= maxx ; ++x){
|
||||||
if(ncplane_putc_yx(w, y, x, &c) <= 0){
|
if(ncplane_putc_yx(w, y, x, &c) <= 0){
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -97,57 +97,58 @@ tabletup(struct ncplane* w, int begx, int begy, int maxx, int maxy,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
tabletdown(struct ncplane* w, int begx, int begy, int maxx, int maxy,
|
tabletdown(struct ncplane* w, int maxy, tabletctx* tctx, unsigned rgb){
|
||||||
tabletctx* tctx, unsigned rgb){
|
|
||||||
char cchbuf[2];
|
char cchbuf[2];
|
||||||
cell c = CELL_TRIVIAL_INITIALIZER;
|
cell c = CELL_TRIVIAL_INITIALIZER;
|
||||||
int y;
|
int y;
|
||||||
for(y = begy ; y <= maxy ; ++y, rgb += 16){
|
int maxx = ncplane_dim_x(w) - 1;
|
||||||
if(y - begy >= tctx->lines){
|
if(maxy > tctx->lines){
|
||||||
break;
|
maxy = tctx->lines;
|
||||||
}
|
}
|
||||||
|
for(y = 0 ; y <= maxy ; ++y, rgb += 16){
|
||||||
snprintf(cchbuf, sizeof(cchbuf) / sizeof(*cchbuf), "%x", y % 16);
|
snprintf(cchbuf, sizeof(cchbuf) / sizeof(*cchbuf), "%x", y % 16);
|
||||||
cell_load(w, &c, cchbuf);
|
cell_load(w, &c, cchbuf);
|
||||||
if(cell_set_fg_rgb(&c, (rgb >> 16u) % 0xffu, (rgb >> 8u) % 0xffu, rgb % 0xffu)){
|
if(cell_set_fg_rgb(&c, (rgb >> 16u) % 0xffu, (rgb >> 8u) % 0xffu, rgb % 0xffu)){
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int x;
|
int x;
|
||||||
for(x = begx ; x <= maxx ; ++x){
|
for(x = 0 ; x <= maxx ; ++x){
|
||||||
if(ncplane_putc_yx(w, y, x, &c) <= 0){
|
if(ncplane_putc_yx(w, y, x, &c) <= 0){
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cell_release(w, &c);
|
cell_release(w, &c);
|
||||||
}
|
}
|
||||||
return y - begy;
|
return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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);
|
struct ncplane* p = nctablet_ncplane(t);
|
||||||
tabletctx* tctx = nctablet_userptr(t);
|
tabletctx* tctx = nctablet_userptr(t);
|
||||||
pthread_mutex_lock(&tctx->lock);
|
pthread_mutex_lock(&tctx->lock);
|
||||||
unsigned rgb = tctx->rgb;
|
unsigned rgb = tctx->rgb;
|
||||||
int ll;
|
int ll;
|
||||||
|
int maxy = ncplane_dim_y(p);
|
||||||
if(cliptop){
|
if(cliptop){
|
||||||
ll = tabletup(p, begx, begy, maxx, maxy, tctx, rgb);
|
ll = tabletup(p, maxy, tctx, rgb);
|
||||||
}else{
|
}else{
|
||||||
ll = tabletdown(p, begx, begy, maxx, maxy, tctx, rgb);
|
ll = tabletdown(p, maxy, tctx, rgb);
|
||||||
}
|
}
|
||||||
ncplane_set_fg_rgb(p, 242, 242, 242);
|
ncplane_set_fg_rgb(p, 242, 242, 242);
|
||||||
if(ll){
|
if(ll){
|
||||||
int summaryy = begy;
|
int summaryy = 0;
|
||||||
if(cliptop){
|
if(cliptop){
|
||||||
if(ll == maxy - begy + 1){
|
if(ll == maxy + 1){
|
||||||
summaryy = ll - 1;
|
summaryy = ll - 1;
|
||||||
}else{
|
}else{
|
||||||
summaryy = ll;
|
summaryy = ll;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ncplane_styles_on(p, NCSTYLE_BOLD);
|
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",
|
tctx->id, tctx->lines, tctx->lines == 1 ? "" : "s",
|
||||||
begy, maxy) < 0){
|
maxy) < 0){
|
||||||
pthread_mutex_unlock(&tctx->lock);
|
pthread_mutex_unlock(&tctx->lock);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -184,7 +185,10 @@ tablet_thread(void* vtabletctx){
|
|||||||
pthread_mutex_lock(&renderlock);
|
pthread_mutex_lock(&renderlock);
|
||||||
if(nctablet_ncplane(tctx->t)){
|
if(nctablet_ncplane(tctx->t)){
|
||||||
ncreel_redraw(tctx->pr);
|
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);
|
pthread_mutex_unlock(&renderlock);
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,11 @@ void notcurses_debug(notcurses* nc, FILE* debugfp){
|
|||||||
int planeidx = 0;
|
int planeidx = 0;
|
||||||
fprintf(debugfp, "*************************** notcurses debug state *****************************\n");
|
fprintf(debugfp, "*************************** notcurses debug state *****************************\n");
|
||||||
while(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,
|
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){
|
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);
|
n->boundto, n->bnext, n->bprev, n->blist);
|
||||||
}
|
}
|
||||||
if(n->bnext == n || n->boundto == n || n->blist == n){
|
if(n->bnext == n || n->boundto == n || n->blist == n){
|
||||||
|
@ -117,6 +117,32 @@ typedef struct renderstate {
|
|||||||
bool defaultelidable;
|
bool defaultelidable;
|
||||||
} renderstate;
|
} 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
|
// ncmenu_item and ncmenu_section have internal and (minimal) external forms
|
||||||
typedef struct ncmenu_int_item {
|
typedef struct ncmenu_int_item {
|
||||||
char* desc; // utf-8 menu item, NULL for horizontal separator
|
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;
|
return c->channels & CELL_NOBACKGROUND_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Destroy a plane and all its bound descendants.
|
||||||
|
int ncplane_genocide(ncplane *ncp);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -297,11 +297,13 @@ void free_plane(ncplane* p){
|
|||||||
ncplane* ncplane_create(notcurses* nc, ncplane* n, int rows, int cols,
|
ncplane* ncplane_create(notcurses* nc, ncplane* n, int rows, int cols,
|
||||||
int yoff, int xoff, void* opaque, const char* name){
|
int yoff, int xoff, void* opaque, const char* name){
|
||||||
if(rows <= 0 || cols <= 0){
|
if(rows <= 0 || cols <= 0){
|
||||||
|
logerror(nc, "Won't create denormalized plane (r=%d, c=%d)\n", rows, cols);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ncplane* p = malloc(sizeof(*p));
|
ncplane* p = malloc(sizeof(*p));
|
||||||
size_t fbsize = sizeof(*p->fb) * (rows * cols);
|
size_t fbsize = sizeof(*p->fb) * (rows * cols);
|
||||||
if((p->fb = malloc(fbsize)) == NULL){
|
if((p->fb = malloc(fbsize)) == NULL){
|
||||||
|
logerror(nc, "Error allocating cellmatrix (r=%d, c=%d)\n", rows, cols);
|
||||||
free(p);
|
free(p);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -346,6 +348,7 @@ ncplane* ncplane_create(notcurses* nc, ncplane* n, int rows, int cols,
|
|||||||
}else{
|
}else{
|
||||||
p->below = NULL;
|
p->below = NULL;
|
||||||
}
|
}
|
||||||
|
loginfo(nc, "Created new %dx%d plane @ %dx%d\n", rows, cols, yoff, xoff);
|
||||||
return p;
|
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);
|
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){
|
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);
|
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,
|
ncplane* ncplane_aligned(ncplane* n, int rows, int cols, int yoff,
|
||||||
ncalign_e align, void* opaque){
|
ncalign_e align, void* opaque){
|
||||||
return ncplane_create(n->nc, n, rows, cols, yoff,
|
return ncplane_create(n->nc, n, rows, cols, yoff,
|
||||||
ncplane_align(n, align, cols), opaque, NULL);
|
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){
|
void ncplane_home(ncplane* n){
|
||||||
n->x = 0;
|
n->x = 0;
|
||||||
n->y = 0;
|
n->y = 0;
|
||||||
@ -583,13 +602,33 @@ int ncplane_destroy(ncplane* ncp){
|
|||||||
ncp->bnext->bprev = ncp->bprev;
|
ncp->bnext->bprev = ncp->bprev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(ncp->blist){
|
int ret = 0;
|
||||||
// FIXME need unlink all on list
|
struct ncplane* bound = ncp->blist;
|
||||||
ncp->blist->bprev = NULL;
|
while(bound){
|
||||||
ncp->blist->bnext = NULL;
|
struct ncplane* tmp = bound->bnext;
|
||||||
|
if(ncplane_reparent(bound, ncp->boundto) == NULL){
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
bound = tmp;
|
||||||
}
|
}
|
||||||
free_plane(ncp);
|
free_plane(ncp);
|
||||||
return 0;
|
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
|
static int
|
||||||
@ -2178,6 +2217,14 @@ const notcurses* ncplane_notcurses_const(const ncplane* n){
|
|||||||
return n->nc;
|
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){
|
ncplane* ncplane_reparent(ncplane* n, ncplane* newparent){
|
||||||
if(n == n->nc->stdplane){
|
if(n == n->nc->stdplane){
|
||||||
return NULL; // can't reparent standard plane
|
return NULL; // can't reparent standard plane
|
||||||
|
727
src/lib/reel.c
727
src/lib/reel.c
@ -5,20 +5,10 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "internal.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 {
|
typedef enum {
|
||||||
DIRECTION_UP,
|
DIRECTION_UP,
|
||||||
DIRECTION_DOWN,
|
DIRECTION_DOWN,
|
||||||
} direction_e;
|
} direction_e; // current direction of travel
|
||||||
|
|
||||||
// A UNIFIED THEORY OF NCREELS
|
// A UNIFIED THEORY OF NCREELS
|
||||||
// (which are more complex than they may seem)
|
// (which are more complex than they may seem)
|
||||||
@ -44,8 +34,9 @@ typedef enum {
|
|||||||
// Second rule: if there must be 2+ consecutive lines of blank space, they must
|
// 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).
|
// 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.
|
// 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]
|
||||||
// except as necessary to accommodate the prior rules.
|
// 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:
|
// 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
|
// 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
|
// 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
|
// 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.
|
// 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
|
// * walk the list in the direction against travel, foc->focw
|
||||||
// * if focw == backstop, we're done
|
// * if focw == backstop, we're done
|
||||||
// * draw through edge
|
// * 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
|
// Returns the starting coordinates (relative to the screen) of the specified
|
||||||
// tablet, and its length. End is (begx + lenx - 1, begy + leny - 1).
|
// 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
|
static int
|
||||||
draw_borders(ncplane* w, unsigned mask, uint64_t channel,
|
draw_borders(ncplane* w, unsigned mask, uint64_t channel){
|
||||||
bool cliphead, bool clipfoot){
|
|
||||||
int lenx, leny;
|
int lenx, leny;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
ncplane_dim_yx(w, &leny, &lenx);
|
ncplane_dim_yx(w, &leny, &lenx);
|
||||||
@ -155,30 +134,26 @@ draw_borders(ncplane* w, unsigned mask, uint64_t channel,
|
|||||||
if(cells_rounded_box(w, 0, channel, &ul, &ur, &ll, &lr, &hl, &vl)){
|
if(cells_rounded_box(w, 0, channel, &ul, &ur, &ll, &lr, &hl, &vl)){
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/*fprintf(stderr, "drawing borders %p ->%d/%d, mask: %04x, clipping: %c%c\n",
|
//fprintf(stderr, "drawing borders %p ->%d/%d, mask: %04x\n", w, maxx, maxy, mask);
|
||||||
w, maxx, maxy, mask,
|
// lenx is the number of columns we have, but drop 2 due to corners. we thus
|
||||||
cliphead ? 'T' : 't', clipfoot ? 'F' : 'f');*/
|
// want lenx horizontal lines.
|
||||||
if(!cliphead){
|
if(!(mask & NCBOXMASK_TOP)){
|
||||||
// lenx is the number of columns we have, but drop 2 due to
|
ncplane_home(w);
|
||||||
// corners. we thus want lenx horizontal lines.
|
ncplane_putc(w, &ul);
|
||||||
if(!(mask & NCBOXMASK_TOP)){
|
ncplane_hline(w, &hl, lenx - 2);
|
||||||
|
ncplane_putc(w, &ur);
|
||||||
|
}else{
|
||||||
|
if(!(mask & NCBOXMASK_LEFT)){
|
||||||
ncplane_home(w);
|
ncplane_home(w);
|
||||||
ncplane_putc(w, &ul);
|
ncplane_putc(w, &ul);
|
||||||
ncplane_hline(w, &hl, lenx - 2);
|
}
|
||||||
|
if(!(mask & NCBOXMASK_RIGHT)){
|
||||||
|
ncplane_cursor_move_yx(w, 0, lenx - 1);
|
||||||
ncplane_putc(w, &ur);
|
ncplane_putc(w, &ur);
|
||||||
}else{
|
|
||||||
if(!(mask & NCBOXMASK_LEFT)){
|
|
||||||
ncplane_home(w);
|
|
||||||
ncplane_putc(w, &ul);
|
|
||||||
}
|
|
||||||
if(!(mask & NCBOXMASK_RIGHT)){
|
|
||||||
ncplane_cursor_move_yx(w, 0, lenx - 1);
|
|
||||||
ncplane_putc(w, &ur);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int y;
|
int y;
|
||||||
for(y = !cliphead ; y < maxy + !!clipfoot ; ++y){
|
for(y = 1 ; y < maxy ; ++y){
|
||||||
if(!(mask & NCBOXMASK_LEFT)){
|
if(!(mask & NCBOXMASK_LEFT)){
|
||||||
ret |= ncplane_cursor_move_yx(w, y, 0);
|
ret |= ncplane_cursor_move_yx(w, y, 0);
|
||||||
ncplane_putc(w, &vl);
|
ncplane_putc(w, &vl);
|
||||||
@ -188,32 +163,28 @@ draw_borders(ncplane* w, unsigned mask, uint64_t channel,
|
|||||||
ncplane_putc(w, &vl);
|
ncplane_putc(w, &vl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!clipfoot){
|
if(!(mask & NCBOXMASK_BOTTOM)){
|
||||||
if(!(mask & NCBOXMASK_BOTTOM)){
|
ret |= ncplane_cursor_move_yx(w, maxy, 0);
|
||||||
ret |= ncplane_cursor_move_yx(w, maxy, 0);
|
ncplane_putc(w, &ll);
|
||||||
ncplane_putc(w, &ll);
|
ncplane_hline(w, &hl, lenx - 2);
|
||||||
ncplane_hline(w, &hl, lenx - 2);
|
ncplane_putc(w, &lr);
|
||||||
ncplane_putc(w, &lr);
|
}else{
|
||||||
}else{
|
if(!(mask & NCBOXMASK_LEFT)){
|
||||||
if(!(mask & NCBOXMASK_LEFT)){
|
if(ncplane_cursor_move_yx(w, maxy, 0) || ncplane_putc(w, &ll) < 0){
|
||||||
if(ncplane_cursor_move_yx(w, maxy, 0) || ncplane_putc(w, &ll) < 0){
|
ret = -1;
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(!(mask & NCBOXMASK_RIGHT)){
|
}
|
||||||
// mvwadd_wch returns error if we print to the lowermost+rightmost
|
if(!(mask & NCBOXMASK_RIGHT)){
|
||||||
// character cell. maybe we can make this go away with scrolling controls
|
// mvwadd_wch returns error if we print to the lowermost+rightmost
|
||||||
// at setup? until then, don't check for error here FIXME.
|
// character cell. maybe we can make this go away with scrolling controls
|
||||||
if(ncplane_cursor_move_yx(w, maxy, maxx) || ncplane_putc(w, &lr) < 0){
|
// at setup? until then, don't check for error here FIXME.
|
||||||
ret = -1;
|
if(ncplane_cursor_move_yx(w, maxy, maxx) || ncplane_putc(w, &lr) < 0){
|
||||||
}
|
ret = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cell_release(w, &ul); cell_release(w, &ur); cell_release(w, &hl);
|
cell_release(w, &ul); cell_release(w, &ur); cell_release(w, &hl);
|
||||||
cell_release(w, &ll); cell_release(w, &lr); cell_release(w, &vl);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,7 +197,7 @@ draw_ncreel_borders(const ncreel* nr){
|
|||||||
assert(maxy >= 0 && maxx >= 0);
|
assert(maxy >= 0 && maxx >= 0);
|
||||||
--maxx; // last column we can safely write to
|
--maxx; // last column we can safely write to
|
||||||
--maxy; // last line 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
|
// 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
|
// (nr->tablets == t), it can take the entire reel -- frontiery is only a
|
||||||
// suggestion in this case -- so give it the full breadth.
|
// suggestion in this case -- so give it the full breadth.
|
||||||
static int
|
static int
|
||||||
tablet_columns(const ncreel* nr, nctablet* t, int* begx, int* begy,
|
tablet_geom(const ncreel* nr, nctablet* t, int* begx, int* begy,
|
||||||
int* lenx, int* leny, int frontiery, direction_e direction){
|
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;
|
*begy = 0;
|
||||||
*begx = 0;
|
*begx = 0;
|
||||||
ncplane_dim_yx(nr->p, leny, lenx);
|
ncplane_dim_yx(nr->p, leny, lenx);
|
||||||
int maxy = *leny + *begy - 1;
|
if(frontiertop < 0){
|
||||||
int begindraw = *begy + !(nr->ropts.bordermask & NCBOXMASK_TOP);
|
if(direction == DIRECTION_UP){
|
||||||
int enddraw = maxy - !(nr->ropts.bordermask & NCBOXMASK_TOP);
|
|
||||||
if(direction == DIRECTION_UP || nr->tablets == t){
|
|
||||||
if(frontiery < begindraw){
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}else{
|
frontiertop = 0;
|
||||||
if(frontiery > enddraw){
|
}
|
||||||
// fprintf(stderr, "FRONTIER: %d ENDDRAW: %d\n", frontiery, enddraw);
|
if(frontierbottom >= *leny){
|
||||||
|
if(direction == DIRECTION_DOWN){
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
frontierbottom = *leny - 1;
|
||||||
}
|
}
|
||||||
// account for the ncreel borders
|
// account for the ncreel borders on the sides
|
||||||
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;
|
|
||||||
}
|
|
||||||
if(!(nr->ropts.bordermask & NCBOXMASK_LEFT)){
|
if(!(nr->ropts.bordermask & NCBOXMASK_LEFT)){
|
||||||
++*begx;
|
++*begx;
|
||||||
--*lenx;
|
--*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
|
// at this point, our coordinates describe the largest possible tablet for
|
||||||
// this ncreel. this is the correct solution for the focused tablet. other
|
// 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.
|
// tablets can only grow in one of two directions, so tighten them up.
|
||||||
if(direction == DIRECTION_DOWN && nr->tablets != t){
|
if(nr->tablets != t){
|
||||||
*leny -= (frontiery - *begy);
|
*leny -= (frontierbottom - (frontiertop + 1));
|
||||||
*begy = frontiery;
|
if(direction == DIRECTION_DOWN){
|
||||||
}else if(direction == DIRECTION_UP && nr->tablets != t){
|
*begy = frontierbottom;
|
||||||
*leny = frontiery - *begy + 1;
|
}else{
|
||||||
|
*begy = frontiertop - *leny;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the specified tablet, if possible. DIRECTION_UP means we're
|
// Draw the specified tablet, if possible. DIRECTION_UP means we're laying out
|
||||||
// laying out towards the top. DIRECTION_DOWN means towards the bottom. 0
|
// bottom-to-top. DIRECTION_DOWN means top-to-bottom. 'frontier{top, bottom}'
|
||||||
// means this is the focused tablet, always the first one to be drawn.
|
// are the lines to which we'll be fitting the tablet ('frontiertop' to our
|
||||||
// frontiery is the line on which we're placing the tablet (in the case of the
|
// last row for DIRECTION_UP, and 'frontierbottom' to our first row for
|
||||||
// focused window, this is only an ideal, subject to change). For direction
|
// DIRECTION_DOWN). Gives the tablet all possible space to work with (i.e.
|
||||||
// greater than or equal to 0, it's the top line of the tablet. For direction
|
// everything beyond the frontiers, or the entire reel for the focused tablet).
|
||||||
// less than 0, it's the bottom line. Gives the tablet all possible space to
|
// If the callback uses less space, shrinks the plane to that size.
|
||||||
// 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.
|
|
||||||
static int
|
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;
|
int lenx, leny, begy, begx;
|
||||||
ncplane* fp = t->p;
|
if(tablet_geom(nr, t, &begx, &begy, &lenx, &leny, frontiertop, frontierbottom, direction)){
|
||||||
if(tablet_columns(nr, t, &begx, &begy, &lenx, &leny, frontiery, direction)){
|
//fprintf(stderr, "no room: %p base %d/%d len %d/%d dir %d\n", t, begy, begx, leny, lenx, 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;
|
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
//fprintf(stderr, "tplacement: %p:%p base %d/%d len %d/%d\n", t, fp, begx, begy, lenx, leny);
|
//fprintf(stderr, "tplacement: %p base %d/%d len %d/%d frontiery %d %d dir %d\n", t, begy, begx, leny, lenx, frontiertop, frontierbottom, direction);
|
||||||
//fprintf(stderr, "DRAWING %p at frontier %d (dir %d) with %d\n", t, frontiery, direction, leny);
|
ncplane* fp = ncplane_bound_named(nr->p, leny, lenx, begy, begx, NULL, "tab");
|
||||||
if(fp == NULL){ // create a panel for the tablet
|
if((t->p = fp) == NULL){
|
||||||
t->p = ncplane_bound(nr->p, leny + 1, lenx, begy, begx, NULL);
|
//fprintf(stderr, "failure creating border plane %d %d %d %d\n", leny, lenx, begy, begx);
|
||||||
if((fp = t->p) == NULL){
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
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;
|
return -1;
|
||||||
}
|
}
|
||||||
bool cliphead = false;
|
// we allow the callback to use a bound plane that lives above our border
|
||||||
bool clipfoot = false;
|
// plane, thus preventing the callback from spilling over the tablet border.
|
||||||
// We pass the coordinates in which the callback may freely write. That's
|
int cby = 0, cbx = 0, cbleny = leny, cblenx = lenx;
|
||||||
// the full width (minus tablet borders), and the full range of open space
|
if(!(nr->ropts.tabletmask & NCBOXMASK_BOTTOM)){
|
||||||
// in the direction we're moving. We're not passing *lenghts* to the callback,
|
--cbleny;
|
||||||
// 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(!(nr->ropts.tabletmask & NCBOXMASK_TOP)){
|
||||||
if(direction == DIRECTION_DOWN && !(nr->ropts.tabletmask & NCBOXMASK_TOP)){
|
--cbleny;
|
||||||
++cby;
|
++cby;
|
||||||
}
|
}
|
||||||
// Adjust the x-bounds for side borders, which we always have if unmasked
|
cblenx -= !(nr->ropts.tabletmask & NCBOXMASK_RIGHT);
|
||||||
cbmaxx -= !(nr->ropts.tabletmask & NCBOXMASK_RIGHT);
|
if(!(nr->ropts.tabletmask & NCBOXMASK_LEFT)){
|
||||||
cbx += !(nr->ropts.tabletmask & NCBOXMASK_LEFT);
|
--cblenx;
|
||||||
bool cbdir = (nr->tablets != t && direction == DIRECTION_UP) ? true : false;
|
++cbx;
|
||||||
// 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);
|
if(cbleny - cby + 1 > 0){
|
||||||
int ll = t->cbfxn(t, cbx, cby, cbmaxx, cbmaxy, cbdir);
|
t->cbp = ncplane_bound_named(t->p, cbleny - cby + 1, cblenx - cbx + 1, cby, cbx, NULL, "tdat");
|
||||||
//fprintf(stderr, "RETURNRETURNRETURN %p %d (%d, %d, %d) DIR %d\n", t, ll, cby, cbmaxy, leny, direction);
|
if(t->cbp == NULL){
|
||||||
if(ll != leny){
|
//fprintf(stderr, "failure creating data plane %d %d %d %d\n", cbleny - cby + 1, cblenx - cbx + 1, cby, cbx);
|
||||||
if(ll == leny - 1){ // only has one border visible (partially off-screen)
|
ncplane_destroy(t->p);
|
||||||
if(cbdir){
|
t->p = NULL;
|
||||||
ll += !(nr->ropts.tabletmask & NCBOXMASK_BOTTOM);
|
return -1;
|
||||||
}else{
|
|
||||||
ll += !(nr->ropts.tabletmask & NCBOXMASK_TOP);
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
// The focused tablet will have been resized properly above, but it might
|
ncplane_move_above(t->cbp, t->p);
|
||||||
// be out of position (the focused tablet ought move as little as possible).
|
// 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);
|
||||||
// Move it back to the frontier, or the nearest line above if it has grown.
|
int ll = t->cbfxn(t, direction == DIRECTION_DOWN);
|
||||||
if(nr->tablets == t){
|
//fprintf(stderr, "RETURNRETURNRETURN %p %d (%d, %d, %d) DIR %d\n", t, ll, cby, cbleny, leny, direction);
|
||||||
if(leny - frontiery + 1 < ll){
|
if(ll != cbleny - cby + 1){
|
||||||
//fprintf(stderr, "frontieryIZING ADJ %d %d %d %d NEW %d\n", cbmaxy, leny, frontiery, ll, frontiery - ll + 1);
|
int diff = (cbleny - cby + 1) - ll;
|
||||||
ncplane_yx(fp, &frontiery, NULL);
|
//fprintf(stderr, "resizing data plane %d->%d\n", cbleny - cby + 1, ll);
|
||||||
frontiery += (leny - 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 - 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,
|
draw_borders(fp, nr->ropts.tabletmask,
|
||||||
nr->tablets == t ? nr->ropts.focusedchan : nr->ropts.tabletchan,
|
nr->tablets == t ? nr->ropts.focusedchan : nr->ropts.tabletchan);
|
||||||
cliphead, clipfoot);
|
return 0;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// move down below the focused tablet, filling up the reel to the bottom.
|
// move down below the focused tablet, filling up the reel to the bottom.
|
||||||
// returns the last tablet drawn.
|
// returns the last tablet drawn.
|
||||||
static nctablet*
|
static nctablet*
|
||||||
draw_following_tablets(const ncreel* nr, const nctablet* otherend){
|
draw_following_tablets(const ncreel* nr, nctablet* otherend,
|
||||||
int wmaxy, wbegy, wbegx, wlenx, wleny; // working tablet window coordinates
|
int frontiertop, int* frontierbottom){
|
||||||
nctablet* working = nr->tablets;
|
//fprintf(stderr, "following otherend: %p ->p: %p %d/%d\n", otherend, otherend->p, frontiertop, *frontierbottom);
|
||||||
int frontiery;
|
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
|
// move down past the focused tablet, filling up the reel to the bottom
|
||||||
do{
|
while(*frontierbottom <= maxx && (working != otherend || !otherend->p)){
|
||||||
//fprintf(stderr, "following otherend: %p ->p: %p\n", otherend, otherend->p);
|
if(working->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);
|
|
||||||
break;
|
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){
|
if(working == otherend){
|
||||||
otherend = otherend->next;
|
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;
|
return working;
|
||||||
}
|
}
|
||||||
|
|
||||||
// move up above the focused tablet, filling up the reel to the top.
|
// move up above the focused tablet, filling up the reel to the top.
|
||||||
// returns the last tablet drawn.
|
// returns the last tablet drawn.
|
||||||
static nctablet*
|
static nctablet*
|
||||||
draw_previous_tablets(const ncreel* nr, const nctablet* otherend){
|
draw_previous_tablets(const ncreel* nr, nctablet* otherend,
|
||||||
//fprintf(stderr, "preceding otherend: %p ->p: %p\n", otherend, otherend->p);
|
int* frontiertop, int frontierbottom){
|
||||||
int wbegy, wbegx, wlenx, wleny; // working tablet window coordinates
|
nctablet* upworking = nr->tablets->prev;
|
||||||
nctablet* upworking = nr->tablets;
|
//fprintf(stderr, "preceding %p otherend: %p ->p: %p frontiers: %d %d\n", upworking, otherend, otherend->p, *frontiertop, frontierbottom);
|
||||||
int frontiery;
|
|
||||||
// modify frontier based off the one we're at
|
// modify frontier based off the one we're at
|
||||||
tablet_coordinates(upworking->p, &wbegy, &wbegx, &wleny, &wlenx);
|
while(*frontiertop >= 0 && (upworking != otherend || !otherend->p)){
|
||||||
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);
|
|
||||||
if(upworking->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;
|
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){
|
if(upworking == otherend){
|
||||||
otherend = otherend->prev;
|
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;
|
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
|
static int
|
||||||
tighten_reel_down(ncreel* r, int ybot){
|
tighten_reel_down(ncreel* r, int ybot){
|
||||||
nctablet* cur = r->tablets;
|
nctablet* cur = r->tablets;
|
||||||
@ -516,6 +480,7 @@ tighten_reel_down(ncreel* r, int ybot){
|
|||||||
}
|
}
|
||||||
cury = ybot - ylen;
|
cury = ybot - ylen;
|
||||||
ncplane_move_yx(cur->p, cury, curx);
|
ncplane_move_yx(cur->p, cury, curx);
|
||||||
|
//fprintf(stderr, "tightened %p down to %d\n", cur, cury);
|
||||||
ybot = cury - 1;
|
ybot = cury - 1;
|
||||||
if((cur = cur->prev) == r->tablets){
|
if((cur = cur->prev) == r->tablets){
|
||||||
break;
|
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
|
// of the reel. we prefer empty space at the bottom (FIXME but not
|
||||||
// really -- we ought prefer space away from the last direction of
|
// really -- we ought prefer space away from the last direction of
|
||||||
// movement. rather than this postprocessing, draw things to the
|
// 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
|
static int
|
||||||
tighten_reel(ncreel* r){
|
tighten_reel(ncreel* r){
|
||||||
|
//fprintf(stderr, "tightening it up\n");
|
||||||
nctablet* top = r->tablets;
|
nctablet* top = r->tablets;
|
||||||
nctablet* cur = top;
|
nctablet* cur = top;
|
||||||
int ytop = INT_MAX;
|
int ytop = INT_MAX;
|
||||||
@ -549,6 +516,7 @@ tighten_reel(ncreel* r){
|
|||||||
}
|
}
|
||||||
int expected = !(r->ropts.bordermask & NCBOXMASK_TOP);
|
int expected = !(r->ropts.bordermask & NCBOXMASK_TOP);
|
||||||
cur = top;
|
cur = top;
|
||||||
|
nctablet* bottom = r->tablets;
|
||||||
while(cur){
|
while(cur){
|
||||||
if(cur->p == NULL){
|
if(cur->p == NULL){
|
||||||
break;
|
break;
|
||||||
@ -557,6 +525,7 @@ tighten_reel(ncreel* r){
|
|||||||
ncplane_yx(cur->p, &cury, &curx);
|
ncplane_yx(cur->p, &cury, &curx);
|
||||||
if(cury != expected){
|
if(cury != expected){
|
||||||
if(ncplane_move_yx(cur->p, expected, curx)){
|
if(ncplane_move_yx(cur->p, expected, curx)){
|
||||||
|
//fprintf(stderr, "tightened %p up to %d\n", cur, expected);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
@ -565,6 +534,7 @@ tighten_reel(ncreel* r){
|
|||||||
int ylen;
|
int ylen;
|
||||||
ncplane_dim_yx(cur->p, &ylen, NULL);
|
ncplane_dim_yx(cur->p, &ylen, NULL);
|
||||||
expected += ylen + 1;
|
expected += ylen + 1;
|
||||||
|
bottom = cur;
|
||||||
cur = cur->next;
|
cur = cur->next;
|
||||||
if(cur == top){
|
if(cur == top){
|
||||||
break;
|
break;
|
||||||
@ -581,84 +551,37 @@ tighten_reel(ncreel* r){
|
|||||||
// FIXME want to tighten down whenever we're at the bottom, and the reel
|
// 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)
|
// is full, not just in this case (this can leave a gap of more than 1 row)
|
||||||
if(yoff + ylen + 1 >= ybot){
|
if(yoff + ylen + 1 >= ybot){
|
||||||
return tighten_reel_down(r, ybot);
|
if(tighten_reel_down(r, ybot)){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return trim_reel_overhang(r, top, bottom);
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// destroy all existing tablet planes pursuant to redraw
|
// destroy all existing tablet planes pursuant to redraw
|
||||||
static void
|
static void
|
||||||
clean_reel(ncreel* r){
|
clean_reel(ncreel* r){
|
||||||
if(r->tablets){
|
nctablet* vft = r->vft;
|
||||||
nctablet* cur = r->tablets->next;
|
if(vft){
|
||||||
while(cur && cur != r->tablets){// && cur->p){
|
for(nctablet* n = vft->next ; n->p && n != vft ; n = n->next){
|
||||||
//fprintf(stderr, "CLEANING: %p (%p)\n", cur, cur->p);
|
//fprintf(stderr, "CLEANING NEXT: %p (%p)\n", n, n->p);
|
||||||
if(cur->p){
|
ncplane_genocide(n->p);
|
||||||
ncplane_destroy(cur->p);
|
n->p = NULL;
|
||||||
cur->p = NULL;
|
n->cbp = NULL;
|
||||||
}
|
|
||||||
cur = cur->next;
|
|
||||||
}
|
}
|
||||||
//fprintf(stderr, "done clean next, %p %p %p\n", cur, r->tablets, cur ? cur->p : NULL);
|
for(nctablet* n = vft->prev ; n->p && n != vft ; n = n->prev){
|
||||||
cur = r->tablets->prev;
|
//fprintf(stderr, "CLEANING PREV: %p (%p)\n", n, n->p);
|
||||||
while(cur && cur != r->tablets){// && cur->p){
|
ncplane_genocide(n->p);
|
||||||
//fprintf(stderr, "CLEANING: %p (%p)\n", cur, cur->p);
|
n->p = NULL;
|
||||||
if(cur->p){
|
n->cbp = NULL;
|
||||||
ncplane_destroy(cur->p);
|
|
||||||
cur->p = NULL;
|
|
||||||
}
|
|
||||||
cur = cur->prev;
|
|
||||||
}
|
}
|
||||||
|
//fprintf(stderr, "CLEANING VFT: %p (%p)\n", vft, vft->p);
|
||||||
|
ncplane_genocide(vft->p);
|
||||||
|
vft->p = NULL;
|
||||||
|
vft->cbp = NULL;
|
||||||
|
r->vft = NULL;
|
||||||
}
|
}
|
||||||
//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.
|
// 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
|
// 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
|
// place relative to the new focus; they could otherwise pivot around the new
|
||||||
// focus, if we're not filling out the reel.
|
// 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){
|
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)){
|
if(draw_ncreel_borders(nr)){
|
||||||
return -1; // enforces specified dimensional minima
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -727,7 +702,7 @@ validate_ncreel_opts(ncplane* w, const ncreel_options* ropts){
|
|||||||
}
|
}
|
||||||
|
|
||||||
ncplane* nctablet_ncplane(nctablet* t){
|
ncplane* nctablet_ncplane(nctablet* t){
|
||||||
return t->p;
|
return t->cbp;
|
||||||
}
|
}
|
||||||
|
|
||||||
ncplane* ncreel_plane(ncreel* nr){
|
ncplane* ncreel_plane(ncreel* nr){
|
||||||
@ -745,9 +720,10 @@ ncreel* ncreel_create(ncplane* w, const ncreel_options* ropts){
|
|||||||
}
|
}
|
||||||
nr->tablets = NULL;
|
nr->tablets = NULL;
|
||||||
nr->tabletcount = 0;
|
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));
|
memcpy(&nr->ropts, ropts, sizeof(*ropts));
|
||||||
nr->p = w;
|
nr->p = w;
|
||||||
|
nr->vft = NULL;
|
||||||
ncplane_set_base(nr->p, "", 0, ropts->bgchannel);
|
ncplane_set_base(nr->p, "", 0, ropts->bgchannel);
|
||||||
if(ncreel_redraw(nr)){
|
if(ncreel_redraw(nr)){
|
||||||
ncplane_destroy(nr->p);
|
ncplane_destroy(nr->p);
|
||||||
@ -762,6 +738,7 @@ nctablet* ncreel_add(ncreel* nr, nctablet* after, nctablet *before,
|
|||||||
nctablet* t;
|
nctablet* t;
|
||||||
if(after && before){
|
if(after && before){
|
||||||
if(after->prev != before || before->next != after){
|
if(after->prev != before || before->next != after){
|
||||||
|
logerror(nr->p->nc, "bad before (%p) / after (%p) spec\n", before, after);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}else if(!after && !before){
|
}else if(!after && !before){
|
||||||
@ -793,6 +770,7 @@ nctablet* ncreel_add(ncreel* nr, nctablet* after, nctablet *before,
|
|||||||
t->curry = opaque;
|
t->curry = opaque;
|
||||||
++nr->tabletcount;
|
++nr->tabletcount;
|
||||||
t->p = NULL;
|
t->p = NULL;
|
||||||
|
t->cbp = NULL;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -805,10 +783,15 @@ int ncreel_del(ncreel* nr, struct nctablet* t){
|
|||||||
if((nr->tablets = t->next) == t){
|
if((nr->tablets = t->next) == t){
|
||||||
nr->tablets = NULL;
|
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;
|
t->next->prev = t->prev;
|
||||||
if(t->p){
|
if(t->p){
|
||||||
ncplane_destroy(t->p);
|
ncplane_genocide(t->p);
|
||||||
}
|
}
|
||||||
free(t);
|
free(t);
|
||||||
--nr->tabletcount;
|
--nr->tabletcount;
|
||||||
@ -843,9 +826,8 @@ nctablet* ncreel_focused(ncreel* nr){
|
|||||||
nctablet* ncreel_next(ncreel* nr){
|
nctablet* ncreel_next(ncreel* nr){
|
||||||
if(nr->tablets){
|
if(nr->tablets){
|
||||||
nr->tablets = nr->tablets->next;
|
nr->tablets = nr->tablets->next;
|
||||||
//fprintf(stderr, "---------------> moved to next, %p to %p <----------\n",
|
//fprintf(stderr, "---------------> moved to next, %p to %p <----------\n", nr->tablets->prev, nr->tablets);
|
||||||
// nr->tablets->prev, nr->tablets);
|
nr->direction = LASTDIRECTION_DOWN;
|
||||||
nr->direction = DIRECTION_DOWN;
|
|
||||||
}
|
}
|
||||||
return nr->tablets;
|
return nr->tablets;
|
||||||
}
|
}
|
||||||
@ -853,9 +835,8 @@ nctablet* ncreel_next(ncreel* nr){
|
|||||||
nctablet* ncreel_prev(ncreel* nr){
|
nctablet* ncreel_prev(ncreel* nr){
|
||||||
if(nr->tablets){
|
if(nr->tablets){
|
||||||
nr->tablets = nr->tablets->prev;
|
nr->tablets = nr->tablets->prev;
|
||||||
//fprintf(stderr, "----------------> moved to prev, %p to %p <----------\n",
|
//fprintf(stderr, "----------------> moved to prev, %p to %p <----------\n", nr->tablets->next, nr->tablets);
|
||||||
// nr->tablets->next, nr->tablets);
|
nr->direction = LASTDIRECTION_UP;
|
||||||
nr->direction = DIRECTION_UP;
|
|
||||||
}
|
}
|
||||||
return nr->tablets;
|
return nr->tablets;
|
||||||
}
|
}
|
||||||
|
@ -40,12 +40,7 @@ class TabletCtx {
|
|||||||
inline static int class_idx = 0;
|
inline static int class_idx = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
int tabletfxn(struct nctablet* _t, int begx, int begy, int maxx, int maxy,
|
int tabletfxn(struct nctablet* _t, bool cliptop){
|
||||||
bool cliptop){
|
|
||||||
(void)begx;
|
|
||||||
(void)begy;
|
|
||||||
(void)maxx;
|
|
||||||
(void)maxy;
|
|
||||||
(void)cliptop;
|
(void)cliptop;
|
||||||
NcTablet *t = NcTablet::map_tablet (_t);
|
NcTablet *t = NcTablet::map_tablet (_t);
|
||||||
Plane* p = t->get_plane();
|
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"
|
c << "usage: " << argv0 << " [ -h ] | options\n"
|
||||||
<< " -b bordermask: hex ncreel border mask (0x0..0xf)\n"
|
<< " -b bordermask: hex ncreel border mask (0x0..0xf)\n"
|
||||||
<< " -m margin(s): margin(s) around the reel\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;
|
<< " -t tabletmask: hex tablet border mask (0x0..0xf)" << std::endl;
|
||||||
exit(status);
|
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, },
|
{ .name = nullptr, .has_arg = 0, .flag = nullptr, .val = 0, },
|
||||||
};
|
};
|
||||||
int c;
|
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){
|
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;
|
std::stringstream ss;
|
||||||
ss << std::hex << optarg;
|
ss << std::hex << optarg;
|
||||||
ss >> ropts->bordermask;
|
ss >> ropts->bordermask;
|
||||||
|
275
tests/reel.cpp
275
tests/reel.cpp
@ -1,16 +1,70 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include <iostream>
|
#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(nctablet_ncplane(t));
|
||||||
CHECK(begx < maxx);
|
|
||||||
CHECK(begy < maxy);
|
|
||||||
CHECK(!nctablet_userptr(t));
|
CHECK(!nctablet_userptr(t));
|
||||||
CHECK(!cliptop);
|
CHECK(toptobottom);
|
||||||
// FIXME verify geometry is as expected
|
// FIXME verify geometry is as expected
|
||||||
return 0;
|
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") {
|
TEST_CASE("Reels") {
|
||||||
auto nc_ = testing_notcurses();
|
auto nc_ = testing_notcurses();
|
||||||
if(!nc_){
|
if(!nc_){
|
||||||
@ -38,6 +92,7 @@ TEST_CASE("Reels") {
|
|||||||
r.flags = NCREEL_OPTION_INFINITESCROLL | NCREEL_OPTION_CIRCULAR;
|
r.flags = NCREEL_OPTION_INFINITESCROLL | NCREEL_OPTION_CIRCULAR;
|
||||||
struct ncreel* nr = ncreel_create(n_, &r);
|
struct ncreel* nr = ncreel_create(n_, &r);
|
||||||
REQUIRE(nr);
|
REQUIRE(nr);
|
||||||
|
CHECK(ncreel_validate(nr));
|
||||||
REQUIRE(0 == ncreel_destroy(nr));
|
REQUIRE(0 == ncreel_destroy(nr));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,9 +111,13 @@ TEST_CASE("Reels") {
|
|||||||
struct ncreel* nr = ncreel_create(n_, &r);
|
struct ncreel* nr = ncreel_create(n_, &r);
|
||||||
REQUIRE(nr);
|
REQUIRE(nr);
|
||||||
CHECK(!ncreel_next(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(!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") {
|
SUBCASE("OneTablet") {
|
||||||
@ -67,9 +126,13 @@ TEST_CASE("Reels") {
|
|||||||
REQUIRE(nr);
|
REQUIRE(nr);
|
||||||
struct nctablet* t = ncreel_add(nr, nullptr, nullptr, panelcb, nullptr);
|
struct nctablet* t = ncreel_add(nr, nullptr, nullptr, panelcb, nullptr);
|
||||||
REQUIRE(t);
|
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(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") {
|
SUBCASE("MovementWithOneTablet") {
|
||||||
@ -78,13 +141,21 @@ TEST_CASE("Reels") {
|
|||||||
REQUIRE(nr);
|
REQUIRE(nr);
|
||||||
struct nctablet* t = ncreel_add(nr, nullptr, nullptr, panelcb, nullptr);
|
struct nctablet* t = ncreel_add(nr, nullptr, nullptr, panelcb, nullptr);
|
||||||
REQUIRE(t);
|
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(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(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(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") {
|
SUBCASE("DeleteActiveTablet") {
|
||||||
@ -94,6 +165,9 @@ TEST_CASE("Reels") {
|
|||||||
struct nctablet* t = ncreel_add(nr, nullptr, nullptr, panelcb, nullptr);
|
struct nctablet* t = ncreel_add(nr, nullptr, nullptr, panelcb, nullptr);
|
||||||
REQUIRE(t);
|
REQUIRE(t);
|
||||||
CHECK(0 == ncreel_del(nr, ncreel_focused(nr)));
|
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") {
|
SUBCASE("NoBorder") {
|
||||||
@ -102,6 +176,9 @@ TEST_CASE("Reels") {
|
|||||||
NCBOXMASK_TOP | NCBOXMASK_BOTTOM;
|
NCBOXMASK_TOP | NCBOXMASK_BOTTOM;
|
||||||
struct ncreel* nr = ncreel_create(n_, &r);
|
struct ncreel* nr = ncreel_create(n_, &r);
|
||||||
REQUIRE(nr);
|
REQUIRE(nr);
|
||||||
|
CHECK_EQ(0, ncreel_redraw(nr));
|
||||||
|
CHECK_EQ(0, notcurses_render(nc_));
|
||||||
|
CHECK(ncreel_validate(nr));
|
||||||
}
|
}
|
||||||
|
|
||||||
SUBCASE("BadBorderBitsRejected") {
|
SUBCASE("BadBorderBitsRejected") {
|
||||||
@ -117,6 +194,9 @@ TEST_CASE("Reels") {
|
|||||||
NCBOXMASK_TOP | NCBOXMASK_BOTTOM;
|
NCBOXMASK_TOP | NCBOXMASK_BOTTOM;
|
||||||
struct ncreel* nr = ncreel_create(n_, &r);
|
struct ncreel* nr = ncreel_create(n_, &r);
|
||||||
REQUIRE(nr);
|
REQUIRE(nr);
|
||||||
|
CHECK_EQ(0, ncreel_redraw(nr));
|
||||||
|
CHECK_EQ(0, notcurses_render(nc_));
|
||||||
|
CHECK(ncreel_validate(nr));
|
||||||
}
|
}
|
||||||
|
|
||||||
SUBCASE("NoTopBottomBorder") {
|
SUBCASE("NoTopBottomBorder") {
|
||||||
@ -124,6 +204,9 @@ TEST_CASE("Reels") {
|
|||||||
r.bordermask = NCBOXMASK_TOP | NCBOXMASK_BOTTOM;
|
r.bordermask = NCBOXMASK_TOP | NCBOXMASK_BOTTOM;
|
||||||
struct ncreel* nr = ncreel_create(n_, &r);
|
struct ncreel* nr = ncreel_create(n_, &r);
|
||||||
REQUIRE(nr);
|
REQUIRE(nr);
|
||||||
|
CHECK_EQ(0, ncreel_redraw(nr));
|
||||||
|
CHECK_EQ(0, notcurses_render(nc_));
|
||||||
|
CHECK(ncreel_validate(nr));
|
||||||
}
|
}
|
||||||
|
|
||||||
SUBCASE("NoSideBorders") {
|
SUBCASE("NoSideBorders") {
|
||||||
@ -131,6 +214,9 @@ TEST_CASE("Reels") {
|
|||||||
r.bordermask = NCBOXMASK_LEFT | NCBOXMASK_RIGHT;
|
r.bordermask = NCBOXMASK_LEFT | NCBOXMASK_RIGHT;
|
||||||
struct ncreel* nr = ncreel_create(n_, &r);
|
struct ncreel* nr = ncreel_create(n_, &r);
|
||||||
REQUIRE(nr);
|
REQUIRE(nr);
|
||||||
|
CHECK_EQ(0, ncreel_redraw(nr));
|
||||||
|
CHECK_EQ(0, notcurses_render(nc_));
|
||||||
|
CHECK(ncreel_validate(nr));
|
||||||
}
|
}
|
||||||
|
|
||||||
SUBCASE("BadTabletBorderBitsRejected") {
|
SUBCASE("BadTabletBorderBitsRejected") {
|
||||||
@ -140,90 +226,97 @@ TEST_CASE("Reels") {
|
|||||||
REQUIRE(!nr);
|
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") {
|
SUBCASE("TransparentBackground") {
|
||||||
ncreel_options r{};
|
ncreel_options r{};
|
||||||
channels_set_bg_alpha(&r.bgchannel, 3);
|
channels_set_bg_alpha(&r.bgchannel, 3);
|
||||||
struct ncreel* nr = ncreel_create(n_, &r);
|
struct ncreel* nr = ncreel_create(n_, &r);
|
||||||
REQUIRE(nr);
|
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_));
|
CHECK(0 == notcurses_stop(nc_));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user