mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-09 09:09:03 -04:00
Tons of work on ncreel (#776)
Tons of work on ncreel (#627, #749, #694) Improve reel demo: get input wired up once more, avoid the FPS demo at bottom, print pointer and line count in each tablet, use new ncreel API. Improve notcurses-ncreel explorer: kill memory leaks (#694), draw tablets better, use new ncreel API. Fix bug in ncreel core where cruft could be left on the screen, via a very gross brute force algorithm. I'll likely come back and make this a bit less ghastly in the future #749. Remove weird one-off input system from ncreel, residue from outcurses. Make some of the normalizing changes speced out in #627 * ncreel: give each tablet an index, and print it #749 * reel: eliminate FIXME + param to insert_tabler() #749 * ncreel: label tablets with their adress to correlate against debugging logs #749 * more terminal environment variable notes * TERMS.md: add Sakura, st * ncreel: move legend out of reel proper * ncreel_options: dump min/max_supported_rows/cols #627 * ncreel: remove weird one-off input layer #627 * ncreel: add ncreel_offer_input() * reel demo: call demo_getc() * reel demo: rig up input to demo main * ncreel: drop ncreel_del_focused(), properly bind tablets * reel demo: don't free up necessary plane * ncreel: don't pull absolute locations of tablets * ncreel: place tablets correctly in boundrel * reel demo: add back support for left/right * reel demo: restore thread movement * ncreel: remove a great deal of complexity * reel demo: stay out of FPS graph's way * ncreel: give each tablet an index, and print it #749 * reel: eliminate FIXME + param to insert_tabler() #749 * ncreel: label tablets with their adress to correlate against debugging logs #749 * ncreel: move legend out of reel proper * ncreel_options: dump min/max_supported_rows/cols #627 * ncreel: remove weird one-off input layer #627 * ncreel: add ncreel_offer_input() * reel demo: call demo_getc() * reel demo: rig up input to demo main * ncreel: drop ncreel_del_focused(), properly bind tablets * reel demo: don't free up necessary plane * ncreel: don't pull absolute locations of tablets * ncreel: place tablets correctly in boundrel * reel demo: add back support for left/right * reel demo: restore thread movement * ncreel: remove a great deal of complexity * reel demo: stay out of FPS graph's way * reel: tighten up reel following redraw * reel: fix upper-left corner of topless perimeter * ncreel: print linecount, return clipped value * reel: draw focused tablet relative to reel * reel: brute force decruftification, how embarrassing #749
This commit is contained in:
parent
3918ab6999
commit
162f9910c2
4
NEWS.md
4
NEWS.md
@ -6,7 +6,9 @@ rearrangements of Notcurses.
|
||||
* The `ncreel` widget has been overhauled to bring it in line with the
|
||||
others (`ncreel` began life in another project, predating Notcurses).
|
||||
The `toff`, `boff`, `roff`, and `loff` fields of `ncreel_options` have
|
||||
been purged.
|
||||
been purged, as have `min_` and `max_supported_rows` and `_cols`. There
|
||||
is no longer any need to provide a pipe/eventfd. `ncreel_touch()`,
|
||||
`ncreel_del_focused()`, and `ncreel_move()` have been removed.
|
||||
|
||||
* 1.6.0 (2020-07-04)
|
||||
* Behavior has changed regarding use of the provided `FILE*` (which, when
|
||||
|
34
USAGE.md
34
USAGE.md
@ -1886,20 +1886,6 @@ configured instead.
|
||||
// scrolling gestures, trackballs, scrollwheels, touchpads, and verbal commands.
|
||||
|
||||
typedef struct ncreel_options {
|
||||
// require this many rows and columns (including borders). otherwise, a
|
||||
// message will be displayed stating that a larger terminal is necessary, and
|
||||
// input will be queued. if 0, no minimum will be enforced. may not be
|
||||
// negative. note that ncreel_create() does not return error if given a
|
||||
// plane smaller than these minima; it instead patiently waits for the
|
||||
// screen to get bigger.
|
||||
int min_supported_cols;
|
||||
int min_supported_rows;
|
||||
|
||||
// use no more than this many rows and columns (including borders). may not be
|
||||
// less than the corresponding minimum. 0 means no maximum.
|
||||
int max_supported_cols;
|
||||
int max_supported_rows;
|
||||
|
||||
// is scrolling infinite (can one move down or up forever, or is an end
|
||||
// reached?). if true, 'circular' specifies how to handle the special case of
|
||||
// an incompletely-filled reel.
|
||||
@ -1927,13 +1913,8 @@ struct nctablet;
|
||||
struct ncreel;
|
||||
|
||||
// Create an ncreel according to the provided specifications. Returns NULL on
|
||||
// failure. 'nc' must be a valid plane, to which offsets are relative. Note that
|
||||
// there might not be enough room for the specified offsets, in which case the
|
||||
// ncreel will be clipped on the bottom and right. A minimum number of rows
|
||||
// and columns can be enforced via popts. efd, if non-negative, is an eventfd
|
||||
// that ought be written to whenever ncreel_touch() updates a tablet (this
|
||||
// is useful in the case of nonblocking input).
|
||||
struct ncreel* ncreel_create(struct ncplane* nc, const ncreel_options* popts, int efd);
|
||||
// failure. 'nc' must be a valid plane.
|
||||
struct ncreel* ncreel_create(struct ncplane* nc, const ncreel_options* popts);
|
||||
|
||||
// Returns the ncplane on which this ncreel lives.
|
||||
struct ncplane* ncreel_plane(struct ncreel* pr);
|
||||
@ -1969,21 +1950,10 @@ struct nctablet* ncreel_add(struct ncreel* pr, struct nctablet* after,
|
||||
// Return the number of tablets.
|
||||
int ncreel_tabletcount(const struct ncreel* pr);
|
||||
|
||||
// Indicate that the specified tablet has been updated in a way that would
|
||||
// change its display. This will trigger some non-negative number of callbacks
|
||||
// (though not in the caller's context).
|
||||
int ncreel_touch(struct ncreel* pr, struct nctablet* t);
|
||||
|
||||
// Delete the tablet specified by t from the ncreel specified by pr. Returns
|
||||
// -1 if the tablet cannot be found.
|
||||
int ncreel_del(struct ncreel* pr, struct nctablet* t);
|
||||
|
||||
// Delete the active tablet. Returns -1 if there are no tablets.
|
||||
int ncreel_del_focused(struct ncreel* pr);
|
||||
|
||||
// Move to the specified location.
|
||||
int ncreel_move(struct ncreel* pr, int y, int x);
|
||||
|
||||
// Redraw the ncreel in its entirety.
|
||||
int ncreel_redraw(struct ncreel* pr);
|
||||
|
||||
|
@ -15,22 +15,6 @@ notcurses_reel - high-level widget for hierarchical data
|
||||
#define NCREEL_OPTION_CIRCULAR 0x0002
|
||||
|
||||
typedef struct ncreel_options {
|
||||
// require this many rows and columns (including borders).
|
||||
// otherwise, a message will be displayed stating that a
|
||||
// larger terminal is necessary, and input will be queued.
|
||||
// if 0, no minimum will be enforced. may not be negative.
|
||||
// note that ncreel_create() does not return error if
|
||||
// given a WINDOW smaller than these minima; it instead
|
||||
// patiently waits for the screen to get bigger.
|
||||
int min_supported_cols;
|
||||
int min_supported_rows;
|
||||
|
||||
// use no more than this many rows and columns (including
|
||||
// borders). may not be less than the corresponding minimum.
|
||||
// 0 means no maximum.
|
||||
int max_supported_cols;
|
||||
int max_supported_rows;
|
||||
|
||||
// notcurses can draw a border around the ncreel, and also
|
||||
// around the component tablets. inhibit borders by setting all
|
||||
// valid bits in the masks. partially inhibit borders by setting
|
||||
@ -48,7 +32,7 @@ typedef struct ncreel_options {
|
||||
} ncreel_options;
|
||||
```
|
||||
|
||||
**struct ncreel* ncreel_create(struct ncplane* nc, const ncreel_options* popts, int efd);**
|
||||
**struct ncreel* ncreel_create(struct ncplane* nc, const ncreel_options* popts);**
|
||||
|
||||
**struct ncplane* ncreel_plane(struct ncreel* nr);**
|
||||
|
||||
@ -58,14 +42,8 @@ typedef struct ncreel_options {
|
||||
|
||||
**int ncreel_tabletcount(const struct ncreel* nr);**
|
||||
|
||||
**int ncreel_touch(struct ncreel* nr, struct nctablet* t);**
|
||||
|
||||
**int ncreel_del(struct ncreel* nr, struct nctablet* t);**
|
||||
|
||||
**int ncreel_del_focused(struct ncreel* nr);**
|
||||
|
||||
**int ncreel_move(struct ncreel* nr, int y, int x);**
|
||||
|
||||
**int ncreel_redraw(struct ncreel* nr);**
|
||||
|
||||
**struct nctablet* ncreel_focused(struct ncreel* nr);**
|
||||
|
@ -884,9 +884,9 @@ namespace ncpp
|
||||
return static_cast<T*>(get_userptr ());
|
||||
}
|
||||
|
||||
NcReel* ncreel_create (const ncreel_options *popts = nullptr, int efd = -1) const
|
||||
NcReel* ncreel_create (const ncreel_options *popts = nullptr) const
|
||||
{
|
||||
return new NcReel (this, popts, efd);
|
||||
return new NcReel (this, popts);
|
||||
}
|
||||
|
||||
// Some Cell APIs go here since they act on individual panels even though it may seem weird at points (e.g.
|
||||
|
@ -15,27 +15,27 @@ namespace ncpp
|
||||
public:
|
||||
static ncreel_options default_options;
|
||||
|
||||
explicit NcReel (Plane &plane, const ncreel_options *popts = nullptr, int efd = -1)
|
||||
: NcReel (static_cast<Plane const&>(plane), popts, efd)
|
||||
explicit NcReel (Plane &plane, const ncreel_options *popts = nullptr)
|
||||
: NcReel (static_cast<Plane const&>(plane), popts)
|
||||
{}
|
||||
|
||||
explicit NcReel (Plane const&plane, const ncreel_options *popts = nullptr, int efd = -1)
|
||||
explicit NcReel (Plane const&plane, const ncreel_options *popts = nullptr)
|
||||
: Root (Utilities::get_notcurses_cpp (plane))
|
||||
{
|
||||
common_init (Utilities::to_ncplane (plane), popts, efd);
|
||||
common_init (Utilities::to_ncplane (plane), popts);
|
||||
}
|
||||
|
||||
explicit NcReel (Plane *plane, const ncreel_options *popts = nullptr, int efd = -1)
|
||||
: NcReel (static_cast<const Plane*>(plane), popts, efd)
|
||||
explicit NcReel (Plane *plane, const ncreel_options *popts = nullptr)
|
||||
: NcReel (static_cast<const Plane*>(plane), popts)
|
||||
{}
|
||||
|
||||
explicit NcReel (const Plane *plane, const ncreel_options *popts = nullptr, int efd = -1)
|
||||
explicit NcReel (const Plane *plane, const ncreel_options *popts = nullptr)
|
||||
: Root (Utilities::get_notcurses_cpp (plane))
|
||||
{
|
||||
if (plane == nullptr)
|
||||
throw invalid_argument ("'plane' must be a valid pointer");
|
||||
|
||||
common_init (Utilities::to_ncplane (plane), popts, efd);
|
||||
common_init (Utilities::to_ncplane (plane), popts);
|
||||
}
|
||||
|
||||
~NcReel ()
|
||||
@ -74,16 +74,6 @@ namespace ncpp
|
||||
return ncreel_tabletcount (reel);
|
||||
}
|
||||
|
||||
bool touch (NcTablet *t) const NOEXCEPT_MAYBE
|
||||
{
|
||||
return error_guard (ncreel_touch (reel, get_tablet (t)), -1);
|
||||
}
|
||||
|
||||
bool touch (NcTablet &t) const NOEXCEPT_MAYBE
|
||||
{
|
||||
return touch (&t);
|
||||
}
|
||||
|
||||
bool del (NcTablet *t) const NOEXCEPT_MAYBE
|
||||
{
|
||||
return error_guard (ncreel_del (reel, get_tablet (t)), -1);
|
||||
@ -94,16 +84,6 @@ namespace ncpp
|
||||
return del (&t);
|
||||
}
|
||||
|
||||
bool del_focused () const NOEXCEPT_MAYBE
|
||||
{
|
||||
return error_guard (ncreel_del_focused (reel), -1);
|
||||
}
|
||||
|
||||
bool move (int x, int y) const NOEXCEPT_MAYBE
|
||||
{
|
||||
return error_guard (ncreel_move (reel, x, y), -1);
|
||||
}
|
||||
|
||||
bool redraw () const NOEXCEPT_MAYBE
|
||||
{
|
||||
return error_guard (ncreel_redraw (reel), -1);
|
||||
@ -147,9 +127,9 @@ namespace ncpp
|
||||
return t->get_tablet ();
|
||||
}
|
||||
|
||||
void common_init (ncplane *plane, const ncreel_options *popts = nullptr, int efd = -1)
|
||||
void common_init (ncplane *plane, const ncreel_options *popts = nullptr)
|
||||
{
|
||||
reel = ncreel_create (plane, popts == nullptr ? &default_options : popts, efd);
|
||||
reel = ncreel_create (plane, popts == nullptr ? &default_options : popts);
|
||||
if (reel == nullptr)
|
||||
throw init_error ("Notcurses failed to create a new ncreel");
|
||||
}
|
||||
|
@ -2496,20 +2496,6 @@ API int ncblit_bgrx(const void* data, int linesize,
|
||||
#define NCREEL_OPTION_CIRCULAR 0x0002ull
|
||||
|
||||
typedef struct ncreel_options {
|
||||
// require this many rows and columns (including borders). otherwise, a
|
||||
// message will be displayed stating that a larger terminal is necessary, and
|
||||
// input will be queued. if 0, no minimum will be enforced. may not be
|
||||
// negative. note that ncreel_create() does not return error if given an
|
||||
// ncplane smaller than these minima; it instead patiently waits for the
|
||||
// screen to get bigger.
|
||||
int min_supported_cols;
|
||||
int min_supported_rows;
|
||||
|
||||
// use no more than this many rows and columns (including borders). may not be
|
||||
// less than the corresponding minimum. 0 means no maximum.
|
||||
int max_supported_cols;
|
||||
int max_supported_rows;
|
||||
|
||||
// notcurses can draw a border around the ncreel, and also around the
|
||||
// component tablets. inhibit borders by setting all valid bits in the masks.
|
||||
// partially inhibit borders by setting individual bits in the masks. the
|
||||
@ -2528,14 +2514,9 @@ typedef struct ncreel_options {
|
||||
struct nctablet;
|
||||
struct ncreel;
|
||||
|
||||
// Create an ncreel according to the provided specifications. Returns NULL on
|
||||
// failure. nc must be a valid ncplane*, to which offsets are relative. Note that
|
||||
// there might not be enough room for the specified offsets, in which case the
|
||||
// ncreel will be clipped on the bottom and right. A minimum number of rows
|
||||
// and columns can be enforced via popts. efd, if non-negative, is an eventfd
|
||||
// that ought be written to whenever ncreel_touch() updates a tablet (this
|
||||
// is useful in the case of nonblocking input).
|
||||
API struct ncreel* ncreel_create(struct ncplane* nc, const ncreel_options* popts, int efd);
|
||||
// Take over the ncplane 'nc' and use it to draw a reel according to 'popts'.
|
||||
// The plane will be destroyed by ncreel_destroy(); this transfers ownership.
|
||||
API struct ncreel* ncreel_create(struct ncplane* nc, const ncreel_options* popts);
|
||||
|
||||
// Returns the ncplane on which this ncreel lives.
|
||||
API struct ncplane* ncreel_plane(struct ncreel* pr);
|
||||
@ -2572,24 +2553,21 @@ API struct nctablet* ncreel_add(struct ncreel* pr, struct nctablet* after,
|
||||
// Return the number of nctablets in the ncreel.
|
||||
API int ncreel_tabletcount(const struct ncreel* pr);
|
||||
|
||||
// Indicate that the specified nctablet has been updated in a way that would
|
||||
// change its display. This will trigger some non-negative number of callbacks
|
||||
// (though not in the caller's context).
|
||||
API int ncreel_touch(struct ncreel* pr, struct nctablet* t);
|
||||
|
||||
// Delete the tablet specified by t from the ncreel specified by pr. Returns
|
||||
// -1 if the tablet cannot be found.
|
||||
API int ncreel_del(struct ncreel* pr, struct nctablet* t);
|
||||
|
||||
// Delete the active tablet. Returns -1 if there are no tablets.
|
||||
API int ncreel_del_focused(struct ncreel* pr);
|
||||
|
||||
// Move to the specified location.
|
||||
API int ncreel_move(struct ncreel* pr, int y, int x);
|
||||
|
||||
// Redraw the ncreel in its entirety.
|
||||
API int ncreel_redraw(struct ncreel* pr);
|
||||
|
||||
// Offer the input to the ncreel. If it's relevant, this function returns
|
||||
// true, and the input ought not be processed further. If it's irrelevant to
|
||||
// the reel, false is returned. Relevant inputs include:
|
||||
// * a mouse click on a tablet (focuses tablet)
|
||||
// * a mouse scrollwheel event (rolls reel)
|
||||
// * up, down, pgup, or pgdown (navigates among items)
|
||||
API bool ncreel_offer_input(struct ncreel* n, const struct ncinput* nc);
|
||||
|
||||
// Return the focused tablet, if any tablets are present. This is not a copy;
|
||||
// be careful to use it only for the duration of a critical section.
|
||||
API struct nctablet* ncreel_focused(struct ncreel* pr);
|
||||
|
@ -385,10 +385,6 @@ bool ncmenu_offer_input(struct ncmenu* n, const struct ncinput* nc);
|
||||
int ncmenu_destroy(struct ncmenu* n);
|
||||
const char* ncmetric(uintmax_t val, unsigned decimal, char* buf, int omitdec, unsigned mult, int uprefix);
|
||||
typedef struct ncreel_options {
|
||||
int min_supported_cols;
|
||||
int min_supported_rows;
|
||||
int max_supported_cols;
|
||||
int max_supported_rows;
|
||||
unsigned bordermask;
|
||||
uint64_t borderchan;
|
||||
unsigned tabletmask;
|
||||
@ -397,15 +393,12 @@ typedef struct ncreel_options {
|
||||
uint64_t bgchannel;
|
||||
unsigned flags; // bitfield over NCREEL_OPTION_*
|
||||
} ncreel_options;
|
||||
struct ncreel* ncreel_create(struct ncplane* nc, const ncreel_options* popts, int efd);
|
||||
struct ncreel* ncreel_create(struct ncplane* nc, const ncreel_options* popts);
|
||||
struct ncplane* ncreel_plane(struct ncreel* pr);
|
||||
typedef int (*tabletcb)(struct nctablet* t, int begx, int begy, int maxx, int maxy, bool cliptop);
|
||||
struct nctablet* ncreel_add(struct ncreel* pr, struct nctablet* after, struct nctablet* before, tabletcb cb, void* opaque);
|
||||
int ncreel_tabletcount(const struct ncreel* pr);
|
||||
int ncreel_touch(struct ncreel* pr, struct nctablet* t);
|
||||
int ncreel_del(struct ncreel* pr, struct nctablet* t);
|
||||
int ncreel_del_focused(struct ncreel* pr);
|
||||
int ncreel_move(struct ncreel* pr, int x, int y);
|
||||
int ncreel_redraw(struct ncreel* pr);
|
||||
struct nctablet* ncreel_focused(struct ncreel* pr);
|
||||
struct nctablet* ncreel_next(struct ncreel* pr);
|
||||
|
@ -84,13 +84,15 @@ char32_t demo_getc(struct notcurses* nc, const struct timespec* ts, ncinput* ni)
|
||||
if(id == 'L' && q->ni.ctrl){
|
||||
notcurses_refresh(nc, NULL, NULL);
|
||||
}else{
|
||||
handoff = false;
|
||||
handoff = true;
|
||||
}
|
||||
}
|
||||
}else if(id == 'L' && q->ni.ctrl){
|
||||
notcurses_refresh(nc, NULL, NULL);
|
||||
}else{
|
||||
handoff = false;
|
||||
if(id == 'L' && q->ni.ctrl){
|
||||
notcurses_refresh(nc, NULL, NULL);
|
||||
}else{
|
||||
handoff = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(handoff && ni){
|
||||
|
@ -3547,7 +3547,7 @@ makegroup(struct ncplane* title, int y, const char* emoji, const char* name){
|
||||
|
||||
struct ncplane*
|
||||
maketitle(struct ncplane* std){
|
||||
struct ncplane* title = ncplane_aligned(std, 3, 74, 1, NCALIGN_CENTER, NULL);
|
||||
struct ncplane* title = ncplane_aligned(std, 3, 74, 2, NCALIGN_CENTER, NULL);
|
||||
if(title == NULL){
|
||||
return NULL;
|
||||
}
|
||||
|
124
src/demo/reel.c
124
src/demo/reel.c
@ -10,6 +10,8 @@
|
||||
|
||||
#define INITIAL_TABLET_COUNT 4
|
||||
|
||||
static pthread_mutex_t renderlock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
// FIXME ought just be an unordered_map
|
||||
typedef struct tabletctx {
|
||||
pthread_t tid;
|
||||
@ -151,9 +153,7 @@ tabletdraw(struct nctablet* t, int begx, int begy, int maxx, int maxy, bool clip
|
||||
}
|
||||
ncplane_styles_off(p, NCSTYLE_BOLD);
|
||||
}
|
||||
/*fprintf(stderr, " \\--> callback for %d, %d lines (%d/%d -> %d/%d) dir: %s wrote: %d ret: %d\n", tctx->id,
|
||||
tctx->lines, begy, begx, maxy, maxx,
|
||||
cliptop ? "up" : "down", ll, err);*/
|
||||
//fprintf(stderr, " \\--> callback for %d, %d lines (%d/%d -> %d/%d) dir: %s wrote: %d\n", tctx->id, tctx->lines, begy, begx, maxy, maxx, cliptop ? "up" : "down", ll);
|
||||
pthread_mutex_unlock(&tctx->lock);
|
||||
return ll;
|
||||
}
|
||||
@ -175,14 +175,18 @@ tablet_thread(void* vtabletctx){
|
||||
if((tctx->lines -= (action + 1)) < 1){
|
||||
tctx->lines = 1;
|
||||
}
|
||||
ncreel_touch(tctx->pr, tctx->t);
|
||||
}else if(action > 2){
|
||||
if((tctx->lines += (action - 2)) < 1){
|
||||
tctx->lines = 1;
|
||||
}
|
||||
ncreel_touch(tctx->pr, tctx->t);
|
||||
}
|
||||
pthread_mutex_unlock(&tctx->lock);
|
||||
pthread_mutex_lock(&renderlock);
|
||||
if(nctablet_ncplane(tctx->t)){
|
||||
ncreel_redraw(tctx->pr);
|
||||
demo_render(ncplane_notcurses(nctablet_ncplane(tctx->t)));
|
||||
}
|
||||
pthread_mutex_unlock(&renderlock);
|
||||
}
|
||||
return tctx;
|
||||
}
|
||||
@ -212,80 +216,32 @@ new_tabletctx(struct ncreel* pr, unsigned *id){
|
||||
}
|
||||
|
||||
static wchar_t
|
||||
handle_input(struct notcurses* nc, struct ncreel* pr, int efd,
|
||||
const struct timespec* deadline){
|
||||
struct pollfd fds[2] = {
|
||||
{ .fd = demo_input_fd(), .events = POLLIN, .revents = 0, },
|
||||
{ .fd = efd, .events = POLLIN, .revents = 0, },
|
||||
};
|
||||
sigset_t sset;
|
||||
sigemptyset(&sset);
|
||||
wchar_t key = -1;
|
||||
int pret;
|
||||
DEMO_RENDER(nc);
|
||||
handle_input(struct notcurses* nc, const struct timespec* deadline,
|
||||
ncinput* ni){
|
||||
int64_t deadlinens = timespec_to_ns(deadline);
|
||||
do{
|
||||
struct timespec pollspec, cur;
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur);
|
||||
int64_t curns = timespec_to_ns(&cur);
|
||||
if(curns > deadlinens){
|
||||
return 0;
|
||||
}
|
||||
ns_to_timespec(curns - deadlinens, &pollspec);
|
||||
pret = ppoll(fds, sizeof(fds) / sizeof(*fds), &pollspec, &sset);
|
||||
if(pret == 0){
|
||||
return 0;
|
||||
}else if(pret < 0){
|
||||
if(errno != EINTR){
|
||||
fprintf(stderr, "Error polling on stdin/eventfd (%s)\n", strerror(errno));
|
||||
return (wchar_t)-1;
|
||||
}
|
||||
}else{
|
||||
if(fds[0].revents & POLLIN){
|
||||
uint64_t eventcount;
|
||||
if(read(fds[0].fd, &eventcount, sizeof(eventcount)) > 0){
|
||||
key = demo_getc_nblock(nc, NULL);
|
||||
if(key == (wchar_t)-1){
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(fds[1].revents & POLLIN){
|
||||
uint64_t val;
|
||||
if(read(efd, &val, sizeof(val)) != sizeof(val)){
|
||||
fprintf(stderr, "Error reading from eventfd %d (%s)\n", efd, strerror(errno));
|
||||
}else if(key == (wchar_t)-1){
|
||||
ncreel_redraw(pr);
|
||||
DEMO_RENDER(nc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}while(key == (wchar_t)-1);
|
||||
return key;
|
||||
}
|
||||
|
||||
static int
|
||||
close_pipes(int* pipes){
|
||||
if(close(pipes[0]) | close(pipes[1])){ // intentional, avoid short-circuiting
|
||||
return -1;
|
||||
struct timespec pollspec, cur;
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur);
|
||||
int64_t curns = timespec_to_ns(&cur);
|
||||
if(curns > deadlinens){
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
ns_to_timespec(deadlinens - curns, &pollspec);
|
||||
wchar_t r = demo_getc(nc, &pollspec, ni);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
ncreel_demo_core(struct notcurses* nc, int efdr, int efdw){
|
||||
ncreel_demo_core(struct notcurses* nc){
|
||||
tabletctx* tctxs = NULL;
|
||||
bool aborted = false;
|
||||
int x = 8, y = 4;
|
||||
int dimy, dimx;
|
||||
struct ncplane* std = notcurses_stddim_yx(nc, &dimy, &dimx);
|
||||
struct ncplane* w = ncplane_new(nc, dimy - 8, dimx - 16, y, x, NULL);
|
||||
struct ncplane* w = ncplane_new(nc, dimy - 12, dimx - 16, y, x, NULL);
|
||||
if(w == NULL){
|
||||
return -1;
|
||||
}
|
||||
ncreel_options popts = {
|
||||
.min_supported_cols = 8,
|
||||
.min_supported_rows = 5,
|
||||
.bordermask = 0,
|
||||
.borderchan = 0,
|
||||
.tabletchan = 0,
|
||||
@ -307,7 +263,7 @@ ncreel_demo_core(struct notcurses* nc, int efdr, int efdw){
|
||||
ncplane_destroy(w);
|
||||
return -1;
|
||||
}
|
||||
struct ncreel* pr = ncreel_create(w, &popts, efdw);
|
||||
struct ncreel* pr = ncreel_create(w, &popts);
|
||||
if(pr == NULL){
|
||||
ncplane_destroy(w);
|
||||
return -1;
|
||||
@ -317,7 +273,7 @@ ncreel_demo_core(struct notcurses* nc, int efdr, int efdw){
|
||||
ncplane_styles_on(std, NCSTYLE_BOLD | NCSTYLE_ITALIC);
|
||||
ncplane_set_fg_rgb(std, 58, 150, 221);
|
||||
ncplane_set_bg_default(std);
|
||||
ncplane_printf_yx(std, 1, 1, "a, b, c create tablets, DEL deletes.");
|
||||
ncplane_printf_yx(std, 1, 2, "a, b, c create tablets, DEL deletes.");
|
||||
ncplane_styles_off(std, NCSTYLE_BOLD | NCSTYLE_ITALIC);
|
||||
// FIXME clrtoeol();
|
||||
struct timespec deadline;
|
||||
@ -346,7 +302,17 @@ ncreel_demo_core(struct notcurses* nc, int efdr, int efdw){
|
||||
// FIXME wclrtoeol(w);
|
||||
ncplane_set_fg_rgb(std, 0, 55, 218);
|
||||
wchar_t rw;
|
||||
if((rw = handle_input(nc, pr, efdr, &deadline)) == (wchar_t)-1){
|
||||
ncinput ni;
|
||||
pthread_mutex_lock(&renderlock);
|
||||
ncreel_redraw(pr);
|
||||
int renderret;
|
||||
renderret = demo_render(nc);
|
||||
pthread_mutex_unlock(&renderlock);
|
||||
if(renderret){
|
||||
ncreel_destroy(pr);
|
||||
return renderret;
|
||||
}
|
||||
if((rw = handle_input(nc, &deadline, &ni)) == (wchar_t)-1){
|
||||
break;
|
||||
}
|
||||
// FIXME clrtoeol();
|
||||
@ -355,15 +321,19 @@ ncreel_demo_core(struct notcurses* nc, int efdr, int efdw){
|
||||
case 'a': newtablet = new_tabletctx(pr, &id); break;
|
||||
case 'b': newtablet = new_tabletctx(pr, &id); break;
|
||||
case 'c': newtablet = new_tabletctx(pr, &id); break;
|
||||
case 'h': --x; if(ncreel_move(pr, x, y)){ ++x; } break;
|
||||
case 'l': ++x; if(ncreel_move(pr, x, y)){ --x; } break;
|
||||
case 'k': ncreel_prev(pr); break;
|
||||
case 'j': ncreel_next(pr); break;
|
||||
case 'q': aborted = true; break;
|
||||
case NCKEY_LEFT: --x; if(ncreel_move(pr, x, y)){ ++x; } break;
|
||||
case NCKEY_RIGHT: ++x; if(ncreel_move(pr, x, y)){ --x; } break;
|
||||
case NCKEY_UP: ncreel_prev(pr); break;
|
||||
case NCKEY_DOWN: ncreel_next(pr); break;
|
||||
case NCKEY_LEFT:
|
||||
ncplane_yx(ncreel_plane(pr), &y, &x);
|
||||
ncplane_move_yx(ncreel_plane(pr), y, x - 1);
|
||||
break;
|
||||
case NCKEY_RIGHT:
|
||||
ncplane_yx(ncreel_plane(pr), &y, &x);
|
||||
ncplane_move_yx(ncreel_plane(pr), y, x + 1);
|
||||
break;
|
||||
case NCKEY_DEL: kill_active_tablet(pr, &tctxs); break;
|
||||
case NCKEY_RESIZE: notcurses_render(nc); break;
|
||||
default: ncplane_printf_yx(std, 3, 2, "Unknown keycode (0x%x)\n", rw); break;
|
||||
@ -390,15 +360,7 @@ ncreel_demo_core(struct notcurses* nc, int efdr, int efdw){
|
||||
}
|
||||
|
||||
int reel_demo(struct notcurses* nc){
|
||||
int pipes[2];
|
||||
ncplane_greyscale(notcurses_stdplane(nc));
|
||||
// freebsd doesn't have eventfd :/
|
||||
if(pipe2(pipes, O_CLOEXEC | O_NONBLOCK)){
|
||||
fprintf(stderr, "Error creating pipe (%s)\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
int ret = ncreel_demo_core(nc, pipes[0], pipes[1]);
|
||||
close_pipes(pipes);
|
||||
DEMO_RENDER(nc);
|
||||
int ret = ncreel_demo_core(nc);
|
||||
return ret;
|
||||
}
|
||||
|
473
src/lib/reel.c
473
src/lib/reel.c
@ -16,14 +16,52 @@ typedef struct nctablet {
|
||||
void* curry; // application data provided to cbfxn
|
||||
} nctablet;
|
||||
|
||||
// The visible screen can be reconstructed from three things:
|
||||
// The visible screen can be reconstructed from four things:
|
||||
// * which tablet is focused (pointed at by tablets)
|
||||
// * which row the focused tablet starts at (derived from focused window)
|
||||
// * the list of tablets (available from the focused tablet)
|
||||
// * from which direction we arrived at the focused window
|
||||
// Things which can happen between ncreel_redraw() calls:
|
||||
// * new focused tablet added (only when no tablets exist)
|
||||
// * new unfocused tablet added
|
||||
// * tablet removed (may be focused)
|
||||
// * tablets may grow or shrink
|
||||
// * focus can change
|
||||
// On tablet remove:
|
||||
// * destroy plane, remove from list
|
||||
// * if tablet was focused, change focus
|
||||
// On tablet add:
|
||||
// * add to list (do not create plane)
|
||||
// * if no tablet existed, change focus to new tablet
|
||||
// On focus change:
|
||||
// * change focus, update travel direction
|
||||
// On redraw:
|
||||
// * if no tablets, we're done (deleted planes are already gone)
|
||||
// * resize focused tablet to maximum
|
||||
// * call back for focused tablet redraw
|
||||
// * shrink focused tablet if applicable
|
||||
// * place focused tablet according to:
|
||||
// * the focused tablet should be wholly visible, or if not, use all space
|
||||
// * the focused tablet should be as close to its old position as possible.
|
||||
// * if focused tablet was not wholly on screen, it goes to the side
|
||||
// corresponding to the direction of movement.
|
||||
// * if out of space or tablets, we're done
|
||||
// FIXME *maybe* just draw up followed by down, rather than direction of travel?
|
||||
// * walk the list in the direction of travel, foc->focw
|
||||
// * designate tablet against the walk as 'focagainst', might be NULL
|
||||
// * if focagainst || focagainst, focw only through edge, otherwise
|
||||
// * focw can be as large as all remaining space
|
||||
// * if there is space, draw what we can of next tablet
|
||||
// * move the focused tablet againt the direction of travel if necessary
|
||||
// * prefer the space in the direction of walking
|
||||
// * last tablet drawn is 'backstop'
|
||||
// * if out of space or tablets, we're done
|
||||
// * walk the list in the direction against travel, foc->focw
|
||||
// * if focw == backstop, we're done
|
||||
// * draw through edge
|
||||
typedef struct ncreel {
|
||||
ncplane* p; // ncplane this ncreel occupies, under tablets
|
||||
ncplane* p; // ncplane this ncreel occupies, under tablets
|
||||
ncreel_options ropts; // copied in ncreel_create()
|
||||
int efd; // eventfd/pipe, signaled in ncreel_touch()
|
||||
// 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), which might be anywhere on the screen (but is always visible).
|
||||
@ -36,16 +74,12 @@ typedef struct ncreel {
|
||||
// drawing unfocused tablets opposite the direction of our last movement, so
|
||||
// that movement in an unfilled reel doesn't reorient our tablets.
|
||||
int last_traveled_direction;
|
||||
// are all of our tablets currently visible? our arrangement algorithm works
|
||||
// differently when the reel is not completely filled. ideally we'd unite the
|
||||
// two modes, but for now, check this bool and take one of two paths.
|
||||
bool all_visible;
|
||||
} ncreel;
|
||||
|
||||
// Returns the starting coordinates (relative to the screen) of the specified
|
||||
// window, and its length. End is (begx + lenx - 1, begy + leny - 1).
|
||||
// tablet, and its length. End is (begx + lenx - 1, begy + leny - 1).
|
||||
static inline void
|
||||
window_coordinates(ncplane* w, int* begy, int* begx, int* leny, int* lenx){
|
||||
tablet_coordinates(ncplane* w, int* begy, int* begx, int* leny, int* lenx){
|
||||
ncplane_yx(w, begy, begx);
|
||||
ncplane_dim_yx(w, leny, lenx);
|
||||
}
|
||||
@ -64,45 +98,43 @@ assert(lenx > 0);
|
||||
static int
|
||||
draw_borders(ncplane* w, unsigned mask, uint64_t channel,
|
||||
bool cliphead, bool clipfoot){
|
||||
int begx, begy, lenx, leny;
|
||||
int lenx, leny;
|
||||
int ret = 0;
|
||||
window_coordinates(w, &begy, &begx, &leny, &lenx);
|
||||
begx = 0;
|
||||
begy = 0;
|
||||
int maxx = begx + lenx - 1;
|
||||
int maxy = begy + leny - 1;
|
||||
ncplane_dim_yx(w, &leny, &lenx);
|
||||
int maxx = lenx - 1;
|
||||
int maxy = leny - 1;
|
||||
cell ul, ur, ll, lr, hl, vl;
|
||||
cell_init(&ul); cell_init(&ur); cell_init(&hl);
|
||||
cell_init(&ll); cell_init(&lr); cell_init(&vl);
|
||||
if(cells_rounded_box(w, 0, channel, &ul, &ur, &ll, &lr, &hl, &vl)){
|
||||
return -1;
|
||||
}
|
||||
/*fprintf(stderr, "drawing borders %p %d/%d->%d/%d, mask: %04x, clipping: %c%c\n",
|
||||
w, begx, begy, maxx, maxy, mask,
|
||||
/*fprintf(stderr, "drawing borders %p ->%d/%d, mask: %04x, clipping: %c%c\n",
|
||||
w, maxx, maxy, mask,
|
||||
cliphead ? 'T' : 't', clipfoot ? 'F' : 'f');*/
|
||||
if(!cliphead){
|
||||
// lenx - begx + 1 is the number of columns we have, but drop 2 due to
|
||||
// corners. we thus want lenx - begx - 1 horizontal lines.
|
||||
// lenx is the number of columns we have, but drop 2 due to
|
||||
// corners. we thus want lenx horizontal lines.
|
||||
if(!(mask & NCBOXMASK_TOP)){
|
||||
ret |= ncplane_cursor_move_yx(w, begy, begx);
|
||||
ncplane_home(w);
|
||||
ncplane_putc(w, &ul);
|
||||
ncplane_hline(w, &hl, lenx - 2);
|
||||
ncplane_putc(w, &ur);
|
||||
}else{
|
||||
if(!(mask & NCBOXMASK_LEFT)){
|
||||
ret |= ncplane_cursor_move_yx(w, begy, begx);
|
||||
ncplane_home(w);
|
||||
ncplane_putc(w, &ul);
|
||||
}
|
||||
if(!(mask & NCBOXMASK_RIGHT)){
|
||||
ret |= ncplane_cursor_move_yx(w, begy, maxx);
|
||||
ncplane_cursor_move_yx(w, 0, lenx - 1);
|
||||
ncplane_putc(w, &ur);
|
||||
}
|
||||
}
|
||||
}
|
||||
int y;
|
||||
for(y = begy + !cliphead ; y < maxy + !!clipfoot ; ++y){
|
||||
for(y = !cliphead ; y < maxy + !!clipfoot ; ++y){
|
||||
if(!(mask & NCBOXMASK_LEFT)){
|
||||
ret |= ncplane_cursor_move_yx(w, y, begx);
|
||||
ret |= ncplane_cursor_move_yx(w, y, 0);
|
||||
ncplane_putc(w, &vl);
|
||||
}
|
||||
if(!(mask & NCBOXMASK_RIGHT)){
|
||||
@ -112,13 +144,13 @@ draw_borders(ncplane* w, unsigned mask, uint64_t channel,
|
||||
}
|
||||
if(!clipfoot){
|
||||
if(!(mask & NCBOXMASK_BOTTOM)){
|
||||
ret |= ncplane_cursor_move_yx(w, maxy, begx);
|
||||
ret |= ncplane_cursor_move_yx(w, maxy, 0);
|
||||
ncplane_putc(w, &ll);
|
||||
ncplane_hline(w, &hl, lenx - 2);
|
||||
ncplane_putc(w, &lr);
|
||||
}else{
|
||||
if(!(mask & NCBOXMASK_LEFT)){
|
||||
if(ncplane_cursor_move_yx(w, maxy, begx) || ncplane_putc(w, &ll) < 0){
|
||||
if(ncplane_cursor_move_yx(w, maxy, 0) || ncplane_putc(w, &ll) < 0){
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
@ -134,8 +166,8 @@ draw_borders(ncplane* w, unsigned mask, uint64_t channel,
|
||||
}
|
||||
cell_release(w, &ul); cell_release(w, &ur); cell_release(w, &hl);
|
||||
cell_release(w, &ll); cell_release(w, &lr); cell_release(w, &vl);
|
||||
// fprintf(stderr, "||--borders %d %d %d %d clip: %c%c ret: %d\n",
|
||||
// begx, begy, maxx, maxy, cliphead ? 'y' : 'n', clipfoot ? 'y' : 'n', ret);
|
||||
// fprintf(stderr, "||--borders %d %d clip: %c%c ret: %d\n",
|
||||
// maxx, maxy, cliphead ? 'y' : 'n', clipfoot ? 'y' : 'n', ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -143,18 +175,11 @@ draw_borders(ncplane* w, unsigned mask, uint64_t channel,
|
||||
// any provided restrictions on visible window size.
|
||||
static int
|
||||
draw_ncreel_borders(const ncreel* nr){
|
||||
int begx, begy;
|
||||
int maxx, maxy;
|
||||
window_coordinates(nr->p, &begy, &begx, &maxy, &maxx);
|
||||
ncplane_dim_yx(nr->p, &maxy, &maxx);
|
||||
assert(maxy >= 0 && maxx >= 0);
|
||||
--maxx; // last column we can safely write to
|
||||
--maxy; // last line we can safely write to
|
||||
if(begx >= maxx || maxx - begx + 1 < nr->ropts.min_supported_rows){
|
||||
return 0; // no room
|
||||
}
|
||||
if(begy >= maxy || maxy - begy + 1 < nr->ropts.min_supported_cols){
|
||||
return 0; // no room
|
||||
}
|
||||
return draw_borders(nr->p, nr->ropts.bordermask, nr->ropts.borderchan, false, false);
|
||||
}
|
||||
|
||||
@ -166,7 +191,9 @@ draw_ncreel_borders(const ncreel* nr){
|
||||
static int
|
||||
tablet_columns(const ncreel* nr, int* begx, int* begy, int* lenx, int* leny,
|
||||
int frontiery, int direction){
|
||||
window_coordinates(nr->p, begy, begx, leny, lenx);
|
||||
*begy = 0;
|
||||
*begx = 0;
|
||||
ncplane_dim_yx(nr->p, leny, lenx);
|
||||
int maxy = *leny + *begy - 1;
|
||||
int begindraw = *begy + !(nr->ropts.bordermask & NCBOXMASK_TOP);
|
||||
int enddraw = maxy - !(nr->ropts.bordermask & NCBOXMASK_TOP);
|
||||
@ -236,7 +263,7 @@ ncreel_draw_tablet(const ncreel* nr, nctablet* t, int frontiery,
|
||||
//fprintf(stderr, "tplacement: %p:%p base %d/%d len %d/%d\n", t, fp, begx, begy, lenx, leny);
|
||||
//fprintf(stderr, "DRAWING %p at frontier %d (dir %d) with %d\n", t, frontiery, direction, leny);
|
||||
if(fp == NULL){ // create a panel for the tablet
|
||||
t->p = ncplane_new(nr->p->nc, leny + 1, lenx, begy, begx, NULL);
|
||||
t->p = ncplane_bound(nr->p, leny + 1, lenx, begy, begx, NULL);
|
||||
if((fp = t->p) == NULL){
|
||||
return -1;
|
||||
}
|
||||
@ -336,8 +363,9 @@ ncreel_draw_tablet(const ncreel* nr, nctablet* t, int frontiery,
|
||||
// NULL). it can occupy the entire ncreel.
|
||||
static int
|
||||
draw_focused_tablet(const ncreel* nr){
|
||||
int pbegy, pbegx, plenx, pleny; // ncreel window coordinates
|
||||
window_coordinates(nr->p, &pbegy, &pbegx, &pleny, &plenx);
|
||||
int pbegy, plenx, pleny; // ncreel window coordinates
|
||||
ncplane_dim_yx(nr->p, &pleny, &plenx);
|
||||
pbegy = 0;
|
||||
int fulcrum;
|
||||
if(nr->tablets->p == NULL){
|
||||
if(nr->last_traveled_direction >= 0){
|
||||
@ -345,6 +373,7 @@ draw_focused_tablet(const ncreel* nr){
|
||||
}else{
|
||||
fulcrum = pbegy + !(nr->ropts.bordermask & NCBOXMASK_TOP);
|
||||
}
|
||||
//fprintf(stderr, "LTD: %d placing new at %d\n", nr->last_traveled_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?
|
||||
@ -365,6 +394,7 @@ draw_focused_tablet(const ncreel* nr){
|
||||
}
|
||||
}
|
||||
}
|
||||
//fprintf(stderr, "existing: %p %d placing at %d\n", nr->tablets, nr->last_traveled_direction, fulcrum);
|
||||
}
|
||||
//fprintf(stderr, "PR dims: %d/%d + %d/%d fulcrum: %d\n", pbegy, pbegx, pleny, plenx, fulcrum);
|
||||
ncreel_draw_tablet(nr, nr->tablets, fulcrum, 0 /* nr->last_traveled_direction*/);
|
||||
@ -382,7 +412,7 @@ draw_following_tablets(const ncreel* nr, const nctablet* otherend){
|
||||
do{
|
||||
//fprintf(stderr, "following otherend: %p ->p: %p\n", otherend, otherend->p);
|
||||
// modify frontier based off the one we're at
|
||||
window_coordinates(working->p, &wbegy, &wbegx, &wleny, &wlenx);
|
||||
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);
|
||||
@ -409,14 +439,14 @@ draw_previous_tablets(const ncreel* nr, const nctablet* otherend){
|
||||
nctablet* upworking = nr->tablets;
|
||||
int frontiery;
|
||||
// modify frontier based off the one we're at
|
||||
window_coordinates(upworking->p, &wbegy, &wbegx, &wleny, &wlenx);
|
||||
tablet_coordinates(upworking->p, &wbegy, &wbegx, &wleny, &wlenx);
|
||||
frontiery = wbegy - 2;
|
||||
while(upworking->prev != otherend || otherend->p == NULL){
|
||||
//fprintf(stderr, "MOVIN' ON UP: %p->%p %d %d\n", upworking, upworking->prev, frontiery, wbegy - 2);
|
||||
upworking = upworking->prev;
|
||||
ncreel_draw_tablet(nr, upworking, frontiery, -1);
|
||||
if(upworking->p){
|
||||
window_coordinates(upworking->p, &wbegy, &wbegx, &wleny, &wlenx);
|
||||
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{
|
||||
@ -430,78 +460,131 @@ draw_previous_tablets(const ncreel* nr, const nctablet* otherend){
|
||||
return upworking;
|
||||
}
|
||||
|
||||
// all tablets must be visible (valid ->p), and at least one tablet must exist
|
||||
static nctablet*
|
||||
find_topmost(ncreel* nr){
|
||||
nctablet* t = nr->tablets;
|
||||
int curline;
|
||||
ncplane_yx(t->p, &curline, NULL);
|
||||
int trialline;
|
||||
ncplane_yx(t->prev->p, &trialline, NULL);
|
||||
while(trialline < curline){
|
||||
t = t->prev;
|
||||
curline = trialline;
|
||||
ncplane_yx(t->prev->p, &trialline, NULL);
|
||||
}
|
||||
// fprintf(stderr, "topmost: %p @ %d\n", t, curline);
|
||||
return t;
|
||||
}
|
||||
|
||||
// all the tablets are believed to be wholly visible. in this case, we only want
|
||||
// to fill up the necessary top rows, even if it means moving everything up at
|
||||
// the end. large gaps should always be at the bottom to avoid ui discontinuity.
|
||||
// this must only be called if we actually have at least one tablet. note that
|
||||
// as a result of this function, we might not longer all be wholly visible.
|
||||
// good god almighty, this is some fucking garbage.
|
||||
// run at the end of redraw, this aligns the top tablet with the top
|
||||
// of the reel. we prefer empty space at the bottom (FIXME but not
|
||||
// really -- we ought prefer space away from the last direction of
|
||||
// movement. rather than this postprocessing, draw things to the
|
||||
// right places!).
|
||||
static int
|
||||
ncreel_arrange_denormalized(ncreel* nr){
|
||||
//fprintf(stderr, "denormalized devolution (are we men?)\n");
|
||||
// we'll need the starting line of the tablet which just lost focus, and the
|
||||
// starting line of the tablet which just gained focus.
|
||||
int fromline, nowline;
|
||||
ncplane_yx(nr->tablets->p, &nowline, NULL);
|
||||
// we've moved to the next or previous tablet. either we were not at the end,
|
||||
// in which case we can just move the focus, or we were at the end, in which
|
||||
// case we need bring the target tablet to our end, and draw in the direction
|
||||
// opposite travel (a single tablet is a trivial case of the latter case).
|
||||
// how do we know whether we were at the end? if the new line is not in the
|
||||
// direction of movement relative to the old one, of course!
|
||||
nctablet* topmost = find_topmost(nr);
|
||||
int wbegy, wbegx, wleny, wlenx;
|
||||
window_coordinates(nr->p, &wbegy, &wbegx, &wleny, &wlenx);
|
||||
int frontiery = wbegy + !(nr->ropts.bordermask & NCBOXMASK_TOP);
|
||||
if(nr->last_traveled_direction >= 0){
|
||||
ncplane_yx(nr->tablets->prev->p, &fromline, NULL);
|
||||
if(fromline > nowline){ // keep the order we had
|
||||
topmost = topmost->next;
|
||||
}
|
||||
}else{
|
||||
ncplane_yx(nr->tablets->next->p, &fromline, NULL);
|
||||
if(fromline < nowline){ // keep the order we had
|
||||
topmost = topmost->prev;
|
||||
}
|
||||
}
|
||||
//fprintf(stderr, "gotta draw 'em all FROM: %d NOW: %d!\n", fromline, nowline);
|
||||
nctablet* t = topmost;
|
||||
do{
|
||||
int broken;
|
||||
if(t == nr->tablets){
|
||||
broken = ncreel_draw_tablet(nr, t, frontiery, 0);
|
||||
}else{
|
||||
broken = ncreel_draw_tablet(nr, t, frontiery, 1);
|
||||
}
|
||||
if(t->p == NULL || broken){
|
||||
nr->all_visible = false;
|
||||
tighten_reel(ncreel* r){
|
||||
nctablet* top = r->tablets;
|
||||
nctablet* cur = top;
|
||||
int ytop = INT_MAX;
|
||||
while(cur){
|
||||
if(cur->p == NULL){
|
||||
break;
|
||||
}
|
||||
int basey;
|
||||
ncplane_dim_yx(t->p, &frontiery, NULL);
|
||||
ncplane_yx(t->p, &basey, NULL);
|
||||
frontiery += basey + 1;
|
||||
}while((t = t->next) != topmost);
|
||||
int cury;
|
||||
ncplane_yx(cur->p, &cury, NULL);
|
||||
if(cury >= ytop){
|
||||
break;
|
||||
}
|
||||
ytop = cury;
|
||||
top = cur;
|
||||
cur = cur->prev;
|
||||
}
|
||||
int expected = !(r->ropts.bordermask & NCBOXMASK_TOP);
|
||||
cur = top;
|
||||
while(cur){
|
||||
if(cur->p == NULL){
|
||||
break;
|
||||
}
|
||||
int cury, curx;
|
||||
ncplane_yx(cur->p, &cury, &curx);
|
||||
if(cury != expected){
|
||||
if(ncplane_move_yx(cur->p, expected, curx)){
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
int ylen;
|
||||
ncplane_dim_yx(cur->p, &ylen, NULL);
|
||||
expected += ylen + 1;
|
||||
cur = cur->next;
|
||||
if(cur == top){
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// debugging
|
||||
bool ncreel_validate(const ncreel* n){
|
||||
if(n->tablets == NULL){
|
||||
return true;
|
||||
}
|
||||
const nctablet* t = n->tablets;
|
||||
int cury = -1;
|
||||
bool wentaround = false;
|
||||
do{
|
||||
const ncplane* np = t->p;
|
||||
if(np){
|
||||
int y, x;
|
||||
ncplane_yx(np, &y, &x);
|
||||
//fprintf(stderr, "forvart: %p (%p) @ %d\n", t, np, y);
|
||||
if(y < cury){
|
||||
if(wentaround){
|
||||
return false;
|
||||
}
|
||||
wentaround = true;
|
||||
}else if(y == cury){
|
||||
return false;
|
||||
}
|
||||
cury = y;
|
||||
}
|
||||
}while((t = t->next) != n->tablets);
|
||||
cury = INT_MAX;
|
||||
wentaround = false;
|
||||
do{
|
||||
const ncplane* np = t->p;
|
||||
if(np){
|
||||
int y, x;
|
||||
ncplane_yx(np, &y, &x);
|
||||
//fprintf(stderr, "backwards: %p (%p) @ %d\n", t, np, y);
|
||||
if(y > cury){
|
||||
if(wentaround){
|
||||
return false;
|
||||
}
|
||||
wentaround = true;
|
||||
}else if(y == cury){
|
||||
return false;
|
||||
}
|
||||
cury = y;
|
||||
}
|
||||
}while((t = t->prev) != n->tablets);
|
||||
return true;
|
||||
}
|
||||
|
||||
// destroy all existing tablet planes pursuant to redraw
|
||||
static void
|
||||
clean_reel(ncreel* r){
|
||||
nctablet* focused = r->tablets;
|
||||
nctablet* cur = focused;
|
||||
if(r->tablets){
|
||||
cur = r->tablets->next;
|
||||
while(cur && cur != r->tablets){// && cur->p){
|
||||
//fprintf(stderr, "CLEANING: %p (%p)\n", cur, cur->p);
|
||||
if(cur->p){
|
||||
ncplane_destroy(cur->p);
|
||||
cur->p = NULL;
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
//fprintf(stderr, "done clean next, %p %p %p\n", cur, r->tablets, cur ? cur->p : NULL);
|
||||
cur = r->tablets->prev;
|
||||
while(cur && cur != r->tablets){// && cur->p){
|
||||
//fprintf(stderr, "CLEANING: %p (%p)\n", cur, cur->p);
|
||||
if(cur->p){
|
||||
ncplane_destroy(cur->p);
|
||||
cur->p = NULL;
|
||||
}
|
||||
cur = cur->prev;
|
||||
}
|
||||
}
|
||||
//fprintf(stderr, "done clean prev, %p %p %p\n", cur, r->tablets, cur ? cur->p : NULL);
|
||||
}
|
||||
|
||||
// Arrange the panels, starting with the focused window, wherever it may be.
|
||||
// If necessary, resize it to the full size of the reel--focus has its
|
||||
// privileges. We then work in the opposite direction of travel, filling out
|
||||
@ -522,17 +605,10 @@ int ncreel_redraw(ncreel* nr){
|
||||
return 0; // if none are focused, none exist
|
||||
}
|
||||
//fprintf(stderr, "focused %p!\n", focused);
|
||||
// FIXME we special-cased this because i'm dumb and couldn't think of a more
|
||||
// elegant way to do this. we keep 'all_visible' as boolean state to avoid
|
||||
// having to do an o(n) iteration each round, but this is still grotesque, and
|
||||
// feels fragile...
|
||||
if(nr->all_visible){
|
||||
//fprintf(stderr, "all are visible!\n");
|
||||
return ncreel_arrange_denormalized(nr);
|
||||
}
|
||||
//fprintf(stderr, "drawing focused tablet %p dir: %d!\n", focused, nr->last_traveled_direction);
|
||||
draw_focused_tablet(nr);
|
||||
//fprintf(stderr, "drew focused tablet %p dir: %d!\n", focused, nr->last_traveled_direction);
|
||||
clean_reel(nr);
|
||||
nctablet* otherend = focused;
|
||||
if(nr->last_traveled_direction >= 0){
|
||||
otherend = draw_previous_tablets(nr, otherend);
|
||||
@ -543,7 +619,11 @@ int ncreel_redraw(ncreel* nr){
|
||||
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;
|
||||
}
|
||||
|
||||
@ -579,7 +659,7 @@ ncplane* ncreel_plane(ncreel* nr){
|
||||
return nr->p;
|
||||
}
|
||||
|
||||
ncreel* ncreel_create(ncplane* w, const ncreel_options* ropts, int efd){
|
||||
ncreel* ncreel_create(ncplane* w, const ncreel_options* ropts){
|
||||
ncreel* nr;
|
||||
|
||||
if(!validate_ncreel_opts(w, ropts)){
|
||||
@ -588,35 +668,11 @@ ncreel* ncreel_create(ncplane* w, const ncreel_options* ropts, int efd){
|
||||
if((nr = malloc(sizeof(*nr))) == NULL){
|
||||
return NULL;
|
||||
}
|
||||
nr->efd = efd;
|
||||
nr->tablets = NULL;
|
||||
nr->tabletcount = 0;
|
||||
nr->all_visible = true;
|
||||
nr->last_traveled_direction = -1; // draw down after the initial tablet
|
||||
memcpy(&nr->ropts, ropts, sizeof(*ropts));
|
||||
int maxx, maxy, wx, wy;
|
||||
window_coordinates(w, &wy, &wx, &maxy, &maxx);
|
||||
--maxy;
|
||||
--maxx;
|
||||
int ylen, xlen;
|
||||
ylen = maxy + 1;
|
||||
if(ylen < 0){
|
||||
ylen = maxy;
|
||||
if(ylen < 0){
|
||||
ylen = 0; // but this translates to a full-screen window...FIXME
|
||||
}
|
||||
}
|
||||
xlen = maxx + 1;
|
||||
if(xlen < 0){
|
||||
xlen = maxx;
|
||||
if(xlen < 0){
|
||||
xlen = 0; // FIXME see above...
|
||||
}
|
||||
}
|
||||
if((nr->p = ncplane_new(w->nc, ylen, xlen, wy, wx, NULL)) == NULL){
|
||||
free(nr);
|
||||
return NULL;
|
||||
}
|
||||
nr->p = w;
|
||||
ncplane_set_base(nr->p, "", 0, ropts->bgchannel);
|
||||
if(ncreel_redraw(nr)){
|
||||
ncplane_destroy(nr->p);
|
||||
@ -626,54 +682,6 @@ ncreel* ncreel_create(ncplane* w, const ncreel_options* ropts, int efd){
|
||||
return nr;
|
||||
}
|
||||
|
||||
// we've just added a new tablet. it needs be inserted at the correct place in
|
||||
// the reel. this will naturally fall out of things if the ncreel is full; we
|
||||
// can just call ncreel_redraw(). otherwise, we need make ourselves at least
|
||||
// minimally visible, to satisfy the preconditions of
|
||||
// ncreel_arrange_denormalized(). this function, and approach, is shit.
|
||||
// FIXME get rid of nc param here
|
||||
static nctablet*
|
||||
insert_new_panel(struct notcurses* nc, ncreel* nr, nctablet* t){
|
||||
if(!nr->all_visible){
|
||||
return t;
|
||||
}
|
||||
int wbegy, wbegx, wleny, wlenx; // params of PR
|
||||
window_coordinates(nr->p, &wbegy, &wbegx, &wleny, &wlenx);
|
||||
// are we the only tablet?
|
||||
int begx, begy, lenx, leny, frontiery;
|
||||
if(t->prev == t){
|
||||
frontiery = wbegy + !(nr->ropts.bordermask & NCBOXMASK_TOP);
|
||||
if(tablet_columns(nr, &begx, &begy, &lenx, &leny, frontiery, 1)){
|
||||
nr->all_visible = false;
|
||||
return t;
|
||||
}
|
||||
// fprintf(stderr, "newwin: %d/%d + %d/%d\n", begy, begx, leny, lenx);
|
||||
if((t->p = ncplane_new(nc, leny, lenx, begy, begx, NULL)) == NULL){
|
||||
nr->all_visible = false;
|
||||
return t;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
// we're not the only tablet, alas.
|
||||
// our new window needs to be after our prev
|
||||
ncplane_yx(t->prev->p, &frontiery, NULL);
|
||||
int dimprevy, dimprevx;
|
||||
ncplane_dim_yx(t->prev->p, &dimprevy, &dimprevx);
|
||||
frontiery += dimprevy + 2;
|
||||
frontiery += 2;
|
||||
if(tablet_columns(nr, &begx, &begy, &lenx, &leny, frontiery, 1)){
|
||||
nr->all_visible = false;
|
||||
return t;
|
||||
}
|
||||
// fprintf(stderr, "newwin: %d/%d + %d/%d\n", begy, begx, 2, lenx);
|
||||
if((t->p = ncplane_new(nc, 2, lenx, begy, begx, NULL)) == NULL){
|
||||
nr->all_visible = false;
|
||||
return t;
|
||||
}
|
||||
// FIXME push the other ones down by 4
|
||||
return t;
|
||||
}
|
||||
|
||||
nctablet* ncreel_add(ncreel* nr, nctablet* after, nctablet *before,
|
||||
tabletcb cbfxn, void* opaque){
|
||||
nctablet* t;
|
||||
@ -710,17 +718,9 @@ nctablet* ncreel_add(ncreel* nr, nctablet* after, nctablet *before,
|
||||
t->curry = opaque;
|
||||
++nr->tabletcount;
|
||||
t->p = NULL;
|
||||
// if we have room, it needs become visible immediately, in the proper place,
|
||||
// lest we invalidate the preconditions of ncreel_arrange_denormalized().
|
||||
insert_new_panel(nr->p->nc, nr, t);
|
||||
ncreel_redraw(nr); // don't return failure; tablet was still created...
|
||||
return t;
|
||||
}
|
||||
|
||||
int ncreel_del_focused(ncreel* nr){
|
||||
return ncreel_del(nr, nr->tablets);
|
||||
}
|
||||
|
||||
int ncreel_del(ncreel* nr, struct nctablet* t){
|
||||
if(nr == NULL || t == NULL){
|
||||
return -1;
|
||||
@ -737,7 +737,6 @@ int ncreel_del(ncreel* nr, struct nctablet* t){
|
||||
}
|
||||
free(t);
|
||||
--nr->tabletcount;
|
||||
ncreel_redraw(nr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -762,64 +761,10 @@ int ncreel_tabletcount(const ncreel* nreel){
|
||||
return nreel->tabletcount;
|
||||
}
|
||||
|
||||
int ncreel_touch(ncreel* nr, nctablet* t){
|
||||
(void)t; // FIXME make these more granular eventually
|
||||
int ret = 0;
|
||||
if(nr->efd >= 0){
|
||||
uint64_t val = 1;
|
||||
if(write(nr->efd, &val, sizeof(val)) != sizeof(val)){
|
||||
// fprintf(stderr, "Error writing to eventfd %d (%s)\n", nr->efd, strerror(errno));
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Move to some position relative to the current position
|
||||
static int
|
||||
move_tablet(ncplane* p, int deltay, int deltax){
|
||||
int oldx, oldy;
|
||||
ncplane_yx(p, &oldy, &oldx);
|
||||
int x = oldx + deltax;
|
||||
int y = oldy + deltay;
|
||||
ncplane_move_yx(p, y, x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nctablet* ncreel_focused(ncreel* nr){
|
||||
return nr->tablets;
|
||||
}
|
||||
|
||||
int ncreel_move(ncreel* nreel, int y, int x){
|
||||
ncplane* w = nreel->p;
|
||||
int oldx, oldy;
|
||||
ncplane_yx(w, &oldy, &oldx);
|
||||
const int deltax = x - oldx;
|
||||
const int deltay = y - oldy;
|
||||
if(ncplane_move_yx(nreel->p, y, x)){
|
||||
return -1;
|
||||
}
|
||||
if(nreel->tablets){
|
||||
nctablet* t = nreel->tablets;
|
||||
do{
|
||||
if(t->p == NULL){
|
||||
break;
|
||||
}
|
||||
move_tablet(t->p, deltay, deltax);
|
||||
}while((t = t->prev) != nreel->tablets);
|
||||
if(t != nreel->tablets){ // don't repeat if we covered all tablets
|
||||
for(t = nreel->tablets->next ; t != nreel->tablets ; t = t->next){
|
||||
if(t->p == NULL){
|
||||
break;
|
||||
}
|
||||
move_tablet(t->p, deltay, deltax);
|
||||
}
|
||||
}
|
||||
}
|
||||
ncreel_redraw(nreel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nctablet* ncreel_next(ncreel* nr){
|
||||
if(nr->tablets){
|
||||
nr->tablets = nr->tablets->next;
|
||||
@ -827,7 +772,6 @@ nctablet* ncreel_next(ncreel* nr){
|
||||
// nr->tablets->prev, nr->tablets);
|
||||
nr->last_traveled_direction = 1;
|
||||
}
|
||||
ncreel_redraw(nr);
|
||||
return nr->tablets;
|
||||
}
|
||||
|
||||
@ -838,6 +782,23 @@ nctablet* ncreel_prev(ncreel* nr){
|
||||
// nr->tablets->next, nr->tablets);
|
||||
nr->last_traveled_direction = -1;
|
||||
}
|
||||
ncreel_redraw(nr);
|
||||
return nr->tablets;
|
||||
}
|
||||
|
||||
bool ncreel_offer_input(ncreel* n, const ncinput* nc){
|
||||
if(nc->id == NCKEY_UP){
|
||||
ncreel_prev(n);
|
||||
return true;
|
||||
}else if(nc->id == NCKEY_DOWN){
|
||||
ncreel_next(n);
|
||||
return true;
|
||||
}else if(nc->id == NCKEY_SCROLL_UP){
|
||||
ncreel_prev(n);
|
||||
return true;
|
||||
}else if(nc->id == NCKEY_SCROLL_DOWN){
|
||||
ncreel_next(n);
|
||||
return true;
|
||||
}
|
||||
// FIXME there are a few more
|
||||
return false;
|
||||
}
|
||||
|
@ -5,10 +5,6 @@
|
||||
using namespace ncpp;
|
||||
|
||||
ncreel_options NcReel::default_options = {
|
||||
/* min_supported_cols */ 0,
|
||||
/* min_supported_rows */ 0,
|
||||
/* max_supported_cols */ 0,
|
||||
/* max_supported_rows */ 0,
|
||||
/* bordermask */ NCBox::MaskBottom | NCBox::MaskTop | NCBox::MaskRight | NCBox::MaskLeft,
|
||||
/* borderchan */ 0,
|
||||
/* tabletmask */ 0,
|
||||
|
@ -14,16 +14,22 @@ class TabletCtx {
|
||||
public:
|
||||
TabletCtx() :
|
||||
lines(rand() % 5 + 3),
|
||||
rgb(rand() % 0x1000000) {}
|
||||
rgb(rand() % 0x1000000),
|
||||
idx(++class_idx) {}
|
||||
int getLines() const {
|
||||
return lines;
|
||||
}
|
||||
int getIdx() const {
|
||||
return idx;
|
||||
}
|
||||
unsigned getRGB() const {
|
||||
return rgb;
|
||||
}
|
||||
private:
|
||||
int lines;
|
||||
unsigned rgb;
|
||||
int idx;
|
||||
inline static int class_idx = 0;
|
||||
};
|
||||
|
||||
int tabletfxn(struct nctablet* _t, int begx, int begy, int maxx, int maxy,
|
||||
@ -31,6 +37,7 @@ int tabletfxn(struct nctablet* _t, int begx, int begy, int maxx, int maxy,
|
||||
(void)begx;
|
||||
(void)begy;
|
||||
(void)maxx;
|
||||
(void)maxy;
|
||||
(void)cliptop;
|
||||
NcTablet *t = NcTablet::map_tablet (_t);
|
||||
Plane* p = t->get_plane();
|
||||
@ -40,7 +47,10 @@ int tabletfxn(struct nctablet* _t, int begx, int begy, int maxx, int maxy,
|
||||
c.set_bg(tctx->getRGB());
|
||||
p->set_base_cell(c);
|
||||
p->release(c);
|
||||
return tctx->getLines() > maxy - begy ? maxy - begy : tctx->getLines();
|
||||
p->set_bg(0xffffff);
|
||||
p->set_fg(0x000000);
|
||||
p->printf(1, 1, "%d %p lines: %d", tctx->getIdx(), _t, tctx->getLines());
|
||||
return tctx->getLines();
|
||||
}
|
||||
|
||||
void usage(const char* argv0, std::ostream& c, int status){
|
||||
@ -80,62 +90,65 @@ void parse_args(int argc, char** argv, struct notcurses_options* opts,
|
||||
opts->flags |= NCOPTION_SUPPRESS_BANNERS;
|
||||
}
|
||||
|
||||
int runreels(NotCurses& nc, ncreel_options& nopts){
|
||||
std::unique_ptr<Plane> nstd(nc.get_stdplane());
|
||||
int runreels(struct notcurses* nc, ncreel_options* nopts){
|
||||
int dimy, dimx;
|
||||
nstd->get_dim(&dimy, &dimx);
|
||||
auto n = std::make_shared<Plane>(dimy - 1, dimx, 1, 0);
|
||||
auto nstd = notcurses_stddim_yx(nc, &dimy, &dimx);
|
||||
if(ncplane_putstr_aligned(nstd, 0, NCALIGN_CENTER, "(a)dd (d)el (q)uit") <= 0){
|
||||
return -1;
|
||||
}
|
||||
auto n = ncplane_new(nc, dimy - 1, dimx, 1, 0, nullptr);
|
||||
if(!n){
|
||||
return -1;
|
||||
}
|
||||
if(!n->set_fg_rgb(0xb1, 0x1b, 0xb1)){
|
||||
if(ncplane_set_fg_rgb(n, 0xb1, 0x1b, 0xb1)){
|
||||
return -1;
|
||||
}
|
||||
if(n->putstr(0, NCAlign::Center, "(a)dd (d)el (q)uit") <= 0){
|
||||
return -1;
|
||||
}
|
||||
channels_set_fg(&nopts.focusedchan, 0xffffff);
|
||||
channels_set_bg(&nopts.focusedchan, 0x00c080);
|
||||
channels_set_fg(&nopts.borderchan, 0x00c080);
|
||||
std::shared_ptr<NcReel> nr(n->ncreel_create(&nopts));
|
||||
if(!nr || !nc.render()){
|
||||
channels_set_fg(&nopts->focusedchan, 0xffffff);
|
||||
channels_set_bg(&nopts->focusedchan, 0x00c080);
|
||||
channels_set_fg(&nopts->borderchan, 0x00c080);
|
||||
auto nr = ncreel_create(n, nopts);
|
||||
if(!nr || notcurses_render(nc)){
|
||||
return -1;
|
||||
}
|
||||
int y, x;
|
||||
char32_t key;
|
||||
while((key = nc.getc(true)) != (char32_t)-1){
|
||||
ncinput ni;
|
||||
while((key = notcurses_getc_blocking(nc, &ni)) != (char32_t)-1){
|
||||
switch(key){
|
||||
case 'q':
|
||||
return 0;
|
||||
case 'a':{
|
||||
auto tctx = new TabletCtx();
|
||||
nr->add(nullptr, nullptr, tabletfxn, tctx);
|
||||
ncreel_add(nr, nullptr, nullptr, tabletfxn, tctx);
|
||||
break;
|
||||
}
|
||||
case 'd':
|
||||
nr->del_focused();
|
||||
ncreel_del(nr, ncreel_focused(nr));
|
||||
break;
|
||||
case '*':
|
||||
notcurses_debug(nc, stderr);
|
||||
break;
|
||||
case NCKEY_LEFT:
|
||||
nr->get_plane()->get_yx(&y, &x);
|
||||
nr->move(y, x - 1);
|
||||
ncplane_yx(ncreel_plane(nr), &y, &x);
|
||||
ncplane_move_yx(ncreel_plane(nr), y, x - 1);
|
||||
break;
|
||||
case NCKEY_RIGHT:
|
||||
nr->get_plane()->get_yx(&y, &x);
|
||||
nr->move(y, x + 1);
|
||||
ncplane_yx(ncreel_plane(nr), &y, &x);
|
||||
ncplane_move_yx(ncreel_plane(nr), y, x + 1);
|
||||
break;
|
||||
case NCKEY_UP:
|
||||
nr->prev();
|
||||
ncreel_prev(nr);
|
||||
break;
|
||||
case NCKEY_DOWN:
|
||||
nr->next();
|
||||
ncreel_next(nr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(!nc.render()){
|
||||
if(ncreel_redraw(nr)){
|
||||
break;
|
||||
}
|
||||
if(notcurses_render(nc)){
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -149,8 +162,13 @@ int main(int argc, char** argv){
|
||||
notcurses_options ncopts{};
|
||||
ncreel_options nopts{};
|
||||
parse_args(argc, argv, &ncopts, &nopts);
|
||||
NotCurses nc(ncopts);
|
||||
int r = runreels(nc, nopts);
|
||||
nc.stop();
|
||||
auto nc = notcurses_init(&ncopts, NULL);
|
||||
if(nc == nullptr){
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
int r = runreels(nc, &nopts);
|
||||
if(notcurses_stop(nc)){
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return r ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -22,21 +22,21 @@ TEST_CASE("Reels") {
|
||||
|
||||
SUBCASE("InitLinear") {
|
||||
ncreel_options r = { };
|
||||
struct ncreel* nr = ncreel_create(n_, &r, -1);
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(nr);
|
||||
}
|
||||
|
||||
SUBCASE("InitLinearInfinite") {
|
||||
ncreel_options r{};
|
||||
r.flags = NCREEL_OPTION_INFINITESCROLL;
|
||||
struct ncreel* nr = ncreel_create(n_, &r, -1);
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(nr);
|
||||
}
|
||||
|
||||
SUBCASE("InitCircular") {
|
||||
ncreel_options r{};
|
||||
r.flags = NCREEL_OPTION_INFINITESCROLL | NCREEL_OPTION_CIRCULAR;
|
||||
struct ncreel* nr = ncreel_create(n_, &r, -1);
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(nr);
|
||||
REQUIRE(0 == ncreel_destroy(nr));
|
||||
}
|
||||
@ -45,7 +45,7 @@ TEST_CASE("Reels") {
|
||||
SUBCASE("FiniteCircleRejected") {
|
||||
ncreel_options r{};
|
||||
r.flags = NCREEL_OPTION_CIRCULAR;
|
||||
struct ncreel* nr = ncreel_create(n_, &r, -1);
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(!nr);
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ TEST_CASE("Reels") {
|
||||
// even if there are no tablets. They both ought return nullptr.
|
||||
SUBCASE("MovementWithoutTablets") {
|
||||
ncreel_options r{};
|
||||
struct ncreel* nr = ncreel_create(n_, &r, -1);
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(nr);
|
||||
CHECK(!ncreel_next(nr));
|
||||
// CHECK_EQ(0, ncreel_validate(n_, pr));
|
||||
@ -63,7 +63,7 @@ TEST_CASE("Reels") {
|
||||
|
||||
SUBCASE("OneTablet") {
|
||||
ncreel_options r{};
|
||||
struct ncreel* nr = ncreel_create(n_, &r, -1);
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(nr);
|
||||
struct nctablet* t = ncreel_add(nr, nullptr, nullptr, panelcb, nullptr);
|
||||
REQUIRE(t);
|
||||
@ -74,7 +74,7 @@ TEST_CASE("Reels") {
|
||||
|
||||
SUBCASE("MovementWithOneTablet") {
|
||||
ncreel_options r{};
|
||||
struct ncreel* nr = ncreel_create(n_, &r, -1);
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(nr);
|
||||
struct nctablet* t = ncreel_add(nr, nullptr, nullptr, panelcb, nullptr);
|
||||
REQUIRE(t);
|
||||
@ -89,25 +89,25 @@ TEST_CASE("Reels") {
|
||||
|
||||
SUBCASE("DeleteActiveTablet") {
|
||||
ncreel_options r{};
|
||||
struct ncreel* nr = ncreel_create(n_, &r, -1);
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(nr);
|
||||
struct nctablet* t = ncreel_add(nr, nullptr, nullptr, panelcb, nullptr);
|
||||
REQUIRE(t);
|
||||
CHECK(0 == ncreel_del_focused(nr));
|
||||
CHECK(0 == ncreel_del(nr, ncreel_focused(nr)));
|
||||
}
|
||||
|
||||
SUBCASE("NoBorder") {
|
||||
ncreel_options r{};
|
||||
r.bordermask = NCBOXMASK_LEFT | NCBOXMASK_RIGHT |
|
||||
NCBOXMASK_TOP | NCBOXMASK_BOTTOM;
|
||||
struct ncreel* nr = ncreel_create(n_, &r, -1);
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(nr);
|
||||
}
|
||||
|
||||
SUBCASE("BadBorderBitsRejected") {
|
||||
ncreel_options r{};
|
||||
r.bordermask = NCBOXMASK_LEFT * 2;
|
||||
struct ncreel* nr = ncreel_create(n_, &r, -1);
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(!nr);
|
||||
}
|
||||
|
||||
@ -115,28 +115,28 @@ TEST_CASE("Reels") {
|
||||
ncreel_options r{};
|
||||
r.tabletmask = NCBOXMASK_LEFT | NCBOXMASK_RIGHT |
|
||||
NCBOXMASK_TOP | NCBOXMASK_BOTTOM;
|
||||
struct ncreel* nr = ncreel_create(n_, &r, -1);
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(nr);
|
||||
}
|
||||
|
||||
SUBCASE("NoTopBottomBorder") {
|
||||
ncreel_options r{};
|
||||
r.bordermask = NCBOXMASK_TOP | NCBOXMASK_BOTTOM;
|
||||
struct ncreel* nr = ncreel_create(n_, &r, -1);
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(nr);
|
||||
}
|
||||
|
||||
SUBCASE("NoSideBorders") {
|
||||
ncreel_options r{};
|
||||
r.bordermask = NCBOXMASK_LEFT | NCBOXMASK_RIGHT;
|
||||
struct ncreel* nr = ncreel_create(n_, &r, -1);
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(nr);
|
||||
}
|
||||
|
||||
SUBCASE("BadTabletBorderBitsRejected") {
|
||||
ncreel_options r{};
|
||||
r.tabletmask = NCBOXMASK_LEFT * 2;
|
||||
struct ncreel* nr = ncreel_create(n_, &r, -1);
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(!nr);
|
||||
}
|
||||
|
||||
@ -173,7 +173,7 @@ TEST_CASE("Reels") {
|
||||
REQUIRE_NE(nullptr, base);
|
||||
WINDOW* basew = panel_window(base);
|
||||
REQUIRE_NE(nullptr, basew);
|
||||
struct ncreel* nr = ncreel_create(basew, &r, -1);
|
||||
struct ncreel* nr = ncreel_create(basew, &r);
|
||||
REQUIRE_NE(nullptr, pr);
|
||||
CHECK_EQ(0, ncreel_validate(basew, pr));
|
||||
REQUIRE_EQ(0, ncreel_destroy(nr));
|
||||
@ -194,7 +194,7 @@ TEST_CASE("Reels") {
|
||||
REQUIRE_NE(nullptr, base);
|
||||
WINDOW* basew = panel_window(base);
|
||||
REQUIRE_NE(nullptr, basew);
|
||||
struct ncreel* nr = ncreel_create(basew, &r, -1);
|
||||
struct ncreel* nr = ncreel_create(basew, &r);
|
||||
REQUIRE_NE(nullptr, pr);
|
||||
CHECK_EQ(0, ncreel_validate(basew, pr));
|
||||
REQUIRE_EQ(0, ncreel_destroy(nr));
|
||||
@ -209,7 +209,7 @@ TEST_CASE("Reels") {
|
||||
REQUIRE_NE(nullptr, base);
|
||||
WINDOW* basew = panel_window(base);
|
||||
REQUIRE_NE(nullptr, basew);
|
||||
struct ncreel* nr = ncreel_create(basew, &r, -1);
|
||||
struct ncreel* nr = ncreel_create(basew, &r);
|
||||
REQUIRE_NE(nullptr, pr);
|
||||
CHECK_EQ(0, ncreel_validate(basew, pr));
|
||||
REQUIRE_EQ(0, ncreel_destroy(nr));
|
||||
@ -221,7 +221,7 @@ TEST_CASE("Reels") {
|
||||
SUBCASE("TransparentBackground") {
|
||||
ncreel_options r{};
|
||||
channels_set_bg_alpha(&r.bgchannel, 3);
|
||||
struct ncreel* nr = ncreel_create(n_, &r, -1);
|
||||
struct ncreel* nr = ncreel_create(n_, &r);
|
||||
REQUIRE(nr);
|
||||
// FIXME
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user