Cursor work (placement, drop RETAIN_CURSOR) #953

notcurses_enable_cursor() now accepts placement arguments.
both it and notcurses_disable_cursor() now return int rather
than void. add notcurses_cursor_move_yx().
This commit is contained in:
nick black 2020-08-25 02:54:46 -04:00 committed by Nick Black
parent df33f381e5
commit cab19cf790
11 changed files with 112 additions and 46 deletions

View File

@ -6,6 +6,13 @@ rearrangements of Notcurses.
functions which once returned `nc_err_e` now return a bimodal `int`. Those functions which once returned `nc_err_e` now return a bimodal `int`. Those
functions which accepted a value-result `nc_err_e*` no longer take this functions which accepted a value-result `nc_err_e*` no longer take this
argument. argument.
* `notcurses_cursor_move_yx()` has been added for placement of the terminal
cursor. Remember, you must call `notcurses_cursor_enable()` before it will
be made visible.
* `notcurses_cursor_enable()` now takes two `int` parameters specifying the
desired location of the cursor. Both `notcurses_cursor_enable()` and
`notcurses_cursor_disable()` now return `int` rather than `void`.
* `NCOPTION_RETAIN_CURSOR` has been removed.
* 1.6.17 (2020-08-22) * 1.6.17 (2020-08-22)
* `ncdirect_flush()` now takes a `const struct ncdirect*`. * `ncdirect_flush()` now takes a `const struct ncdirect*`.

View File

@ -99,10 +99,6 @@ typedef enum {
// registration of these signal handlers. // registration of these signal handlers.
#define NCOPTION_NO_QUIT_SIGHANDLERS 0x0008 #define NCOPTION_NO_QUIT_SIGHANDLERS 0x0008
// By default, we hide the cursor if possible. This flag inhibits use of
// the civis capability, retaining the cursor.
#define NCOPTION_RETAIN_CURSOR 0x0010
// Notcurses typically prints version info in notcurses_init() and performance // Notcurses typically prints version info in notcurses_init() and performance
// info in notcurses_stop(). This inhibits that output. // info in notcurses_stop(). This inhibits that output.
#define NCOPTION_SUPPRESS_BANNERS 0x0020 #define NCOPTION_SUPPRESS_BANNERS 0x0020
@ -231,6 +227,16 @@ notcurses_term_dim_yx(const struct notcurses* n, int* restrict rows,
// NCKEY_RESIZE event has been read and you're not ready to render. // NCKEY_RESIZE event has been read and you're not ready to render.
int notcurses_refresh(struct notcurses* n, int* restrict y, int* restrict x); int notcurses_refresh(struct notcurses* n, int* restrict y, int* restrict x);
// Enable or disable the terminal's cursor, if supported. Immediate effect.
void notcurses_cursor_enable(struct notcurses* nc);
void notcurses_cursor_disable(struct notcurses* nc);
// Move the terminal cursor to the specified location. If 'y' or 'x' is
// negative, there is no movement along that axis. Returns error if the
// coordinates are outside the viewing area. The cursor must be explicitly
// enabled with notcurses_cursor_enable() to be seen.
int notcurses_cursor_move_yx(struct notcurses* nc, int y, int x);
// Returns a 16-bit bitmask in the LSBs of supported curses-style attributes // Returns a 16-bit bitmask in the LSBs of supported curses-style attributes
// (NCSTYLE_UNDERLINE, NCSTYLE_BOLD, etc.) The attribute is only // (NCSTYLE_UNDERLINE, NCSTYLE_BOLD, etc.) The attribute is only
// indicated as supported if the terminal can support it together with color. // indicated as supported if the terminal can support it together with color.

View File

@ -15,7 +15,6 @@ notcurses_init - initialize a notcurses instance
#define NCOPTION_VERIFY_SIXEL 0x0002ull #define NCOPTION_VERIFY_SIXEL 0x0002ull
#define NCOPTION_NO_WINCH_SIGHANDLER 0x0004ull #define NCOPTION_NO_WINCH_SIGHANDLER 0x0004ull
#define NCOPTION_NO_QUIT_SIGHANDLERS 0x0008ull #define NCOPTION_NO_QUIT_SIGHANDLERS 0x0008ull
#define NCOPTION_RETAIN_CURSOR 0x0010ull
#define NCOPTION_SUPPRESS_BANNERS 0x0020ull #define NCOPTION_SUPPRESS_BANNERS 0x0020ull
#define NCOPTION_NO_ALTERNATE_SCREEN 0x0040ull #define NCOPTION_NO_ALTERNATE_SCREEN 0x0040ull
#define NCOPTION_NO_FONT_CHANGES 0x0080ull #define NCOPTION_NO_FONT_CHANGES 0x0080ull
@ -47,6 +46,12 @@ typedef struct notcurses_options {
**struct notcurses* notcurses_init(const notcurses_options* opts, FILE* fp);** **struct notcurses* notcurses_init(const notcurses_options* opts, FILE* fp);**
**int notcurses_cursor_enable(struct notcurses* nc, int y, int x);**
**int notcurses_cursor_move_yx(struct notcurses* nc, int y, int x);**
**int notcurses_cursor_disable(struct notcurses* nc);**
# DESCRIPTION # DESCRIPTION
**notcurses_init** prepares the terminal for cursor-addressable (multiline) **notcurses_init** prepares the terminal for cursor-addressable (multiline)
@ -74,9 +79,9 @@ by setting **NCOPTION_NO_ALTERNATE_SCREEN** in **flags**. Users tend to have
strong opinions regarding the alternate screen, so it's often useful to expose strong opinions regarding the alternate screen, so it's often useful to expose
this via a command-line option. this via a command-line option.
notcurses furthermore hides the cursor by default, but **NCOPTION_RETAIN_CURSOR** notcurses hides the cursor by default. It can be dynamically enabled or
can prevent this (the cursor can be dynamically enabled or disabled during disabled during execution via **notcurses_cursor_enable(3)** and
execution via **notcurses_cursor_enable(3)** and **notcurses_cursor_disable(3)**). **notcurses_cursor_disable(3)**, and moved with **notcurses_cursor_move_yx()**.
**notcurses_init** typically emits some diagnostics at startup, including version **notcurses_init** typically emits some diagnostics at startup, including version
information and some details of the configured terminal. This can be inhibited information and some details of the configured terminal. This can be inhibited
@ -123,9 +128,6 @@ zero. The following flags are defined:
cleaning up the terminal on such exceptions. With this flag, the handler cleaning up the terminal on such exceptions. With this flag, the handler
will not be installed. will not be installed.
* **NCOPTION_RETAIN_CURSOR**: Notcurses typically disables the cursor on
startup. With this flag, the cursor will be left enabled.
* **NCOPTION_SUPPRESS_BANNERS**: Disables the diagnostics and version * **NCOPTION_SUPPRESS_BANNERS**: Disables the diagnostics and version
information printed on startup, and the performance summary on exit. information printed on startup, and the performance summary on exit.

View File

@ -151,14 +151,19 @@ namespace ncpp
return notcurses_cantruecolor (nc); return notcurses_cantruecolor (nc);
} }
void cursor_enable () const noexcept int cursor_enable (int y, int x) const noexcept
{ {
notcurses_cursor_enable (nc); return error_guard (notcurses_cursor_enable (nc, y, x), -1);
} }
void cursor_disable () const noexcept int cursor_disable () const noexcept
{ {
notcurses_cursor_disable (nc); return error_guard (notcurses_cursor_disable (nc), -1);
}
int cursor_move_yx (int y, int x) const noexcept
{
return error_guard (notcurses_cursor_move_yx (nc, y, x), -1);
} }
void get_stats (ncstats *stats) const noexcept void get_stats (ncstats *stats) const noexcept

View File

@ -781,9 +781,7 @@ typedef enum {
// registration of these signal handlers. // registration of these signal handlers.
#define NCOPTION_NO_QUIT_SIGHANDLERS 0x0008ull #define NCOPTION_NO_QUIT_SIGHANDLERS 0x0008ull
// By default, we hide the cursor if possible. This flag inhibits use of // NCOPTION_RETAIN_CURSOR was removed in 1.6.18. It ought be repurposed. FIXME.
// the civis capability, retaining the cursor.
#define NCOPTION_RETAIN_CURSOR 0x0010ull
// Notcurses typically prints version info in notcurses_init() and performance // Notcurses typically prints version info in notcurses_init() and performance
// info in notcurses_stop(). This inhibits that output. // info in notcurses_stop(). This inhibits that output.
@ -2570,9 +2568,17 @@ bprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
return ncmetric(val, decimal, buf, omitdec, 1024, 'i'); return ncmetric(val, decimal, buf, omitdec, 1024, 'i');
} }
// Enable or disable the terminal's cursor, if supported. Immediate effect. // Enable or disable the terminal's cursor, if supported, placing it at
API void notcurses_cursor_enable(struct notcurses* nc); // 'y', 'x'. Immediate effect (no need for a call to notcurses_render()).
API void notcurses_cursor_disable(struct notcurses* nc); // It is an error if 'y', 'x' lies outside the standard plane.
API int notcurses_cursor_enable(struct notcurses* nc, int y, int x);
API int notcurses_cursor_disable(struct notcurses* nc);
// Move the terminal cursor to the specified location. If 'y' or 'x' is
// negative, there is no movement along that axis. Returns error if the
// coordinates are outside the viewing area. The cursor must be explicitly
// enabled with notcurses_cursor_enable() to be seen.
API int notcurses_cursor_move_yx(struct notcurses* nc, int y, int x);
// Palette API. Some terminals only support 256 colors, but allow the full // Palette API. Some terminals only support 256 colors, but allow the full
// palette to be specified with arbitrary RGB colors. In all cases, it's more // palette to be specified with arbitrary RGB colors. In all cases, it's more

View File

@ -431,6 +431,9 @@ bool ncdirect_canutf8(const struct ncdirect* n);
int ncdirect_render_image(struct ncdirect* n, const char* filename, ncalign_e align, ncblitter_e blitter, ncscale_e scale); int 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); struct ncplane* ncplane_parent(struct ncplane* n);
const struct ncplane* ncplane_parent_const(const struct ncplane* n); const struct ncplane* ncplane_parent_const(const struct ncplane* n);
int notcurses_cursor_enable(struct notcurses* nc, int y, int x);
int notcurses_cursor_move_yx(struct notcurses* nc, int y, int x);
int notcurses_cursor_disable(struct notcurses* nc);
""") """)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -14,7 +14,6 @@ NCOPTION_INHIBIT_SETLOCALE = 0x0001
NCOPTION_VERIFY_SIXEL = 0x0002 NCOPTION_VERIFY_SIXEL = 0x0002
NCOPTION_NO_WINCH_SIGHANDLER = 0x0004 NCOPTION_NO_WINCH_SIGHANDLER = 0x0004
NCOPTION_NO_QUIT_SIGHANDLERS = 0x0008 NCOPTION_NO_QUIT_SIGHANDLERS = 0x0008
NCOPTION_RETAIN_CURSOR = 0x0010
NCOPTION_SUPPRESS_BANNERS = 0x0020 NCOPTION_SUPPRESS_BANNERS = 0x0020
NCOPTION_NO_ALTERNATE_SCREEN = 0x0040 NCOPTION_NO_ALTERNATE_SCREEN = 0x0040
NCOPTION_NO_FONT_CHANGES = 0x0080 NCOPTION_NO_FONT_CHANGES = 0x0080

View File

@ -101,7 +101,7 @@ typedef struct renderstate {
// the current cursor position. this is independent of whether the cursor is // the current cursor position. this is independent of whether the cursor is
// visible. it is the cell at which the next write will take place. this is // visible. it is the cell at which the next write will take place. this is
// modified by: output, cursor moves, clearing the screen (during refresh) // modified by: output, cursor moves, clearing the screen (during refresh).
int y, x; int y, x;
uint32_t curattr;// current attributes set (does not include colors) uint32_t curattr;// current attributes set (does not include colors)
@ -275,6 +275,9 @@ typedef struct notcurses {
int lfdimy; // lfdimx/lfdimy are 0 until first render int lfdimy; // lfdimx/lfdimy are 0 until first render
egcpool pool; // duplicate EGCs into this pool egcpool pool; // duplicate EGCs into this pool
int cursory; // desired cursor placement according to user. -1 is a don't-
int cursorx; // care, otherwise moved here after each render.
ncstats stats; // some statistics across the lifetime of the notcurses ctx ncstats stats; // some statistics across the lifetime of the notcurses ctx
ncstats stashstats; // cumulative stats, unaffected by notcurses_reset_stats() ncstats stashstats; // cumulative stats, unaffected by notcurses_reset_stats()

View File

@ -859,6 +859,7 @@ notcurses* notcurses_init(const notcurses_options* opts, FILE* outfp){
ret->margin_b = opts->margin_b; ret->margin_b = opts->margin_b;
ret->margin_l = opts->margin_l; ret->margin_l = opts->margin_l;
ret->margin_r = opts->margin_r; ret->margin_r = opts->margin_r;
ret->cursory = ret->cursorx = -1;
ret->stats.fbbytes = 0; ret->stats.fbbytes = 0;
ret->stashstats.fbbytes = 0; ret->stashstats.fbbytes = 0;
reset_stats(&ret->stats); reset_stats(&ret->stats);
@ -966,11 +967,9 @@ notcurses* notcurses_init(const notcurses_options* opts, FILE* outfp){
free_plane(ret->top); free_plane(ret->top);
goto err; goto err;
} }
if(!(opts->flags & NCOPTION_RETAIN_CURSOR)){ if(ret->tcache.civis && tty_emit("civis", ret->tcache.civis, ret->ttyfd)){
if(ret->tcache.civis && tty_emit("civis", ret->tcache.civis, ret->ttyfd)){ free_plane(ret->top);
free_plane(ret->top); goto err;
goto err;
}
} }
} }
if((ret->rstate.mstreamfp = open_memstream(&ret->rstate.mstream, &ret->rstate.mstrsize)) == NULL){ if((ret->rstate.mstreamfp = open_memstream(&ret->rstate.mstream, &ret->rstate.mstrsize)) == NULL){
@ -1885,22 +1884,6 @@ void ncplane_erase(ncplane* n){
n->y = n->x = 0; n->y = n->x = 0;
} }
void notcurses_cursor_enable(notcurses* nc){
if(nc->ttyfd >= 0){
if(nc->tcache.cnorm){
tty_emit("cnorm", nc->tcache.cnorm, nc->ttyfd);
}
}
}
void notcurses_cursor_disable(notcurses* nc){
if(nc->ttyfd >= 0){
if(nc->tcache.civis){
tty_emit("civis", nc->tcache.civis, nc->ttyfd);
}
}
}
ncplane* notcurses_top(notcurses* n){ ncplane* notcurses_top(notcurses* n){
return n->top; return n->top;
} }

View File

@ -968,7 +968,7 @@ int notcurses_refresh(notcurses* nc, int* restrict dimy, int* restrict dimx){
return 0; return 0;
} }
int notcurses_render_to_file(struct notcurses* nc, FILE* fp){ int notcurses_render_to_file(notcurses* nc, FILE* fp){
if(nc->lfdimx == 0 || nc->lfdimy == 0){ if(nc->lfdimx == 0 || nc->lfdimy == 0){
return 0; return 0;
} }
@ -1101,3 +1101,52 @@ int ncdirect_fg(ncdirect* nc, unsigned rgb){
nc->fgrgb = rgb; nc->fgrgb = rgb;
return 0; return 0;
} }
int notcurses_cursor_enable(notcurses* nc, int y, int x){
if(y < 0 || x < 0){
logerror(nc, "Illegal cursor placement: %d, %d\n", y, x);
return -1;
}
if(y >= nc->stdplane->leny || x >= nc->stdplane->lenx){
logerror(nc, "Illegal cursor placement: %d, %d\n", y, x);
return -1;
}
if(nc->ttyfd >= 0){
if(nc->tcache.cnorm){
if(stage_cursor(nc, nc->ttyfp, y, x) || fflush(nc->ttyfp)){
return -1;
}
nc->cursory = y;
nc->cursorx = x;
if(tty_emit("cnorm", nc->tcache.cnorm, nc->ttyfd) == 0){
return 0;
}
}
}
return -1;
}
int notcurses_cursor_disable(notcurses* nc){
nc->cursory = -1;
nc->cursorx = -1;
if(nc->ttyfd >= 0){
if(nc->tcache.civis){
if(tty_emit("civis", nc->tcache.civis, nc->ttyfd) == 0){
return 0;
}
}
}
return -1;
}
int notcurses_cursor_move_yx(notcurses* nc, int y, int x){
if(nc->cursory >= 0 && nc->cursorx >= 0){
return -1;
}
if(stage_cursor(nc, nc->ttyfp, y, x) || fflush(nc->ttyfp)){
return -1;
}
nc->cursory = y;
nc->cursorx = x;
return 0;
}

View File

@ -28,6 +28,9 @@ auto main() -> int {
if(nr == nullptr){ if(nr == nullptr){
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if(!nc.cursor_enable(2 + opts.physrows, 2 + opts.physcols)){
return EXIT_FAILURE;
}
ncinput ni; ncinput ni;
nc.render(); nc.render();
while(nc.getc(true, &ni) != (char32_t)-1){ while(nc.getc(true, &ni) != (char32_t)-1){
@ -41,7 +44,7 @@ auto main() -> int {
ncreader_destroy(nr, &contents); ncreader_destroy(nr, &contents);
nc.stop(); nc.stop();
if(contents){ if(contents){
printf("%s\n", contents); printf("input: %s\n", contents);
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }