ncreader: conform to the New Way #627

This commit is contained in:
nick black 2020-09-13 13:53:11 -04:00
parent 8f089bc017
commit c3e5e47a2a
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC
10 changed files with 67 additions and 124 deletions

View File

@ -10,10 +10,14 @@ rearrangements of Notcurses.
of the provided `ncplane`. On an error in these functions, the `ncplane` of the provided `ncplane`. On an error in these functions, the `ncplane`
will be destroyed. Otherwise, the `ncplane` is destroyed by will be destroyed. Otherwise, the `ncplane` is destroyed by
`ncselector_destroy()` or `ncmultiselector_destroy()`. `ncselector_destroy()` or `ncmultiselector_destroy()`.
* `ncselector_create()` and `ncmultiselector_create()` no longer accept * `ncselector_create()`, `ncmultiselector_create()`, and
`int y, int x` placement parameters. Just place the `ncplane`. `ncreader_create()` no longer accept `int y, int x` placement
parameters. Just place the `ncplane`.
* `ncselector_options` and `ncmultiselector_options` have lost their * `ncselector_options` and `ncmultiselector_options` have lost their
`bgchannels` members. Just set the base character for the `ncplane`. `bgchannels` members. Just set the base character for the `ncplane`.
* `ncreader_options` has lost its `echannels`, `eattrword`, `egc`,
`physrows`, and `physcols` fields. Just set the base character and size
for the `ncplane`.
* ... * ...
* 1.7.2 (2020-09-09) * 1.7.2 (2020-09-09)

View File

@ -2271,20 +2271,14 @@ xxxxxxxxxxxxxxxx╰─────────────╯xxxxxxxxxxxxxxxxxxx
```c ```c
typedef struct ncreader_options { typedef struct ncreader_options {
uint64_t tchannels; // channels used for input uint64_t tchannels; // channels used for input
uint64_t echannels; // channels used for empty space
uint32_t tattrword; // attributes used for input uint32_t tattrword; // attributes used for input
uint32_t eattrword; // attributes used for empty space
const char* egc; // egc used for empty space
int physrows;
int physcols;
bool scroll; // allow more than the physical area's worth of input bool scroll; // allow more than the physical area's worth of input
} ncreader_options; } ncreader_options;
// ncreaders provide freeform input in a (possibly multiline) region, // ncreaders provide freeform input in a (possibly multiline) region, supporting
// supporting readline keybindings. 'rows' and 'cols' both must be negative. // optional readline keybindings. takes ownership of 'n', destroying it on any
// there are no restrictions on 'y' or 'x'. creates its own plane. // error (ncreader_destroy() otherwise destroys the ncplane).
struct ncreader* ncreader_create(struct notcurses* nc, int y, int x, struct ncreader* ncreader_create(struct ncplane* n, const ncreader_options* opts);
const ncreader_options* opts);
// empty the ncreader of any user input, and home the cursor. // empty the ncreader of any user input, and home the cursor.
int ncreader_clear(struct ncreader* n); int ncreader_clear(struct ncreader* n);
@ -2299,7 +2293,7 @@ bool ncreader_offer_input(struct ncreader* n, const struct ncinput* ni);
// return a nul-terminated heap copy of the current (UTF-8) contents. // return a nul-terminated heap copy of the current (UTF-8) contents.
char* ncreader_contents(const struct ncreader* n); char* ncreader_contents(const struct ncreader* n);
// destroy the reader and its bound plane. if 'contents' is not NULL, the // destroy the reader and its bound plane(s). if 'contents' is not NULL, the
// UTF-8 input will be heap-duplicated and written to 'contents'. // UTF-8 input will be heap-duplicated and written to 'contents'.
void ncreader_destroy(struct ncreader* n, char** contents); void ncreader_destroy(struct ncreader* n, char** contents);
``` ```

View File

@ -23,17 +23,12 @@ struct notcurses;
typedef struct ncreader_options { typedef struct ncreader_options {
uint64_t tchannels; // channels used for input uint64_t tchannels; // channels used for input
uint64_t echannels; // channels used for empty space
uint32_t tattrword; // attributes used for input uint32_t tattrword; // attributes used for input
uint32_t eattrword; // attributes used for empty space
const char* egc; // egc used for empty space
int physrows;
int physcols;
unsigned flags; // bitfield over NCREADER_OPTION_* unsigned flags; // bitfield over NCREADER_OPTION_*
} ncreader_options; } ncreader_options;
``` ```
**struct ncreader* ncreader_create(struct notcurses* nc, int y, int x, const ncreader_options* opts);** **struct ncreader* ncreader_create(struct notcurses* nc, const ncreader_options* opts);**
**int ncreader_clear(struct ncreader* n);** **int ncreader_clear(struct ncreader* n);**
@ -59,8 +54,9 @@ typedef struct ncreader_options {
The **ncreader** widget supports free-form, multi-line input. It supports The **ncreader** widget supports free-form, multi-line input. It supports
navigation with the arrow keys and scrolling. While the visible portion of navigation with the arrow keys and scrolling. While the visible portion of
the **ncreader** is always the same size (**physrows** by **physcols**), the the **ncreader** is always the same size (defined by the provided **ncplane**),
actual text backing this visible region can grow arbitrarily large. the actual text backing this visible region can grow arbitrarily large if
scrolling is enabled.
The following option flags are supported: The following option flags are supported:

View File

@ -12,27 +12,27 @@ namespace ncpp
class NCPP_API_EXPORT Reader : public Root class NCPP_API_EXPORT Reader : public Root
{ {
public: public:
explicit Reader (Plane *p, int y, int x, const ncreader_options *opts) explicit Reader (Plane *p, const ncreader_options *opts)
: Reader (static_cast<const Plane*>(p), y, x, opts) : Reader (static_cast<const Plane*>(p), opts)
{} {}
explicit Reader (Plane const* p, int y, int x, const ncreader_options *opts) explicit Reader (Plane const* p, const ncreader_options *opts)
: Root (Utilities::get_notcurses_cpp (p)) : Root (Utilities::get_notcurses_cpp (p))
{ {
if (p == nullptr) if (p == nullptr)
throw invalid_argument ("'plane' must be a valid pointer"); throw invalid_argument ("'plane' must be a valid pointer");
common_init (Utilities::to_ncplane (p), y, x, opts); common_init (Utilities::to_ncplane (p), opts);
} }
explicit Reader (Plane &p, int y, int x, const ncreader_options *opts) explicit Reader (Plane &p, const ncreader_options *opts)
: Reader (static_cast<Plane const&>(p), y, x, opts) : Reader (static_cast<Plane const&>(p), opts)
{} {}
explicit Reader (Plane const& p, int y, int x, const ncreader_options *opts) explicit Reader (Plane const& p, const ncreader_options *opts)
: Root (Utilities::get_notcurses_cpp (p)) : Root (Utilities::get_notcurses_cpp (p))
{ {
common_init (Utilities::to_ncplane (p), y, x, opts); common_init (Utilities::to_ncplane (p), opts);
} }
~Reader () ~Reader ()
@ -58,9 +58,9 @@ namespace ncpp
} }
private: private:
void common_init (ncplane *n, int y, int x, const ncreader_options *opts) void common_init (ncplane *n, const ncreader_options *opts)
{ {
reader = ncreader_create (n, y, x, opts); reader = ncreader_create (n, opts);
if (reader == nullptr) if (reader == nullptr)
throw init_error ("Notcurses failed to create a new reader"); throw init_error ("Notcurses failed to create a new reader");
} }

View File

@ -3034,20 +3034,14 @@ API int ncplane_qrcode(struct ncplane* n, ncblitter_e blitter, int* ymax,
typedef struct ncreader_options { typedef struct ncreader_options {
uint64_t tchannels; // channels used for input uint64_t tchannels; // channels used for input
uint64_t echannels; // channels used for empty space
uint32_t tattrword; // attributes used for input uint32_t tattrword; // attributes used for input
uint32_t eattrword; // attributes used for empty space
const char* egc; // egc used for empty space
int physrows;
int physcols;
uint64_t flags; // bitfield of NCREADER_OPTION_* uint64_t flags; // bitfield of NCREADER_OPTION_*
} ncreader_options; } ncreader_options;
// ncreaders provide freeform input in a (possibly multiline) region, // ncreaders provide freeform input in a (possibly multiline) region, supporting
// supporting readline keybindings. 'rows' and 'cols' both must be negative. // optional readline keybindings. takes ownership of 'n', destroying it on any
// there are no restrictions on 'y' or 'x'. creates its own plane. // error (ncreader_destroy() otherwise destroys the ncplane).
API struct ncreader* ncreader_create(struct ncplane* n, int y, int x, API struct ncreader* ncreader_create(struct ncplane* n, const ncreader_options* opts)
const ncreader_options* opts)
__attribute__ ((nonnull (1))); __attribute__ ((nonnull (1)));
// empty the ncreader of any user input, and home the cursor. // empty the ncreader of any user input, and home the cursor.

View File

@ -389,15 +389,10 @@ struct ncplane* ncsubproc_plane(struct ncsubproc* n);
int ncsubproc_destroy(struct ncsubproc* n); int ncsubproc_destroy(struct ncsubproc* n);
typedef struct ncreader_options { typedef struct ncreader_options {
uint64_t tchannels; // channels used for input uint64_t tchannels; // channels used for input
uint64_t echannels; // channels used for empty space
uint32_t tattrword; // attributes used for input uint32_t tattrword; // attributes used for input
uint32_t eattrword; // attributes used for empty space
const char* egc; // egc used for empty space
int physrows;
int physcols;
unsigned flags; // bitfield over NCREADER_OPTION_* unsigned flags; // bitfield over NCREADER_OPTION_*
} ncreader_options; } ncreader_options;
struct ncreader* ncreader_create(struct ncplane* n, int y, int x, const ncreader_options* opts); struct ncreader* ncreader_create(struct ncplane* n, const ncreader_options* opts);
int ncreader_clear(struct ncreader* n); int ncreader_clear(struct ncreader* n);
struct ncplane* ncreader_plane(struct ncreader* n); struct ncplane* ncreader_plane(struct ncreader* n);
bool ncreader_offer_input(struct ncreader* n, const struct ncinput* ni); bool ncreader_offer_input(struct ncreader* n, const struct ncinput* ni);

View File

@ -372,16 +372,15 @@ reader_demo(struct notcurses* nc){
const int READER_ROWS = 8; const int READER_ROWS = 8;
ncreader_options nopts = { ncreader_options nopts = {
.tchannels = CHANNELS_RGB_INITIALIZER(0xa0, 0xe0, 0xe0, 0, 0, 0), .tchannels = CHANNELS_RGB_INITIALIZER(0xa0, 0xe0, 0xe0, 0, 0, 0),
.echannels = CHANNELS_RGB_INITIALIZER(0x20, 0xe0, 0xe0, 0, 0, 0),
.egc = " ",
.physcols = READER_COLS,
.physrows = READER_ROWS,
}; };
channels_set_bg_alpha(&nopts.echannels, CELL_ALPHA_BLEND); uint64_t echannels = CHANNELS_RGB_INITIALIZER(0x20, 0xe0, 0xe0, 0, 0, 0);
const int x = ncplane_align(std, NCALIGN_CENTER, nopts.physcols); channels_set_bg_alpha(&echannels, CELL_ALPHA_BLEND);
const int x = ncplane_align(std, NCALIGN_CENTER, READER_COLS);
struct ncselector* selector = NULL; struct ncselector* selector = NULL;
struct ncmultiselector* mselector = NULL; struct ncmultiselector* mselector = NULL;
struct ncreader* reader = ncreader_create(std, dimy, x, &nopts); struct ncplane* rp = ncplane_new(nc, READER_ROWS, READER_COLS, dimy, x, NULL);
ncplane_set_base(rp, " ", 0, echannels);
struct ncreader* reader = ncreader_create(rp, &nopts);
if(reader == NULL){ if(reader == NULL){
goto done; goto done;
} }

View File

@ -1,53 +1,35 @@
#include "internal.h" #include "internal.h"
ncreader* ncreader_create(ncplane* n, int y, int x, const ncreader_options* opts){ ncreader* ncreader_create(ncplane* n, const ncreader_options* opts){
ncreader_options zeroed = {}; ncreader_options zeroed = {};
if(!opts){ if(!opts){
opts = &zeroed; opts = &zeroed;
} }
if(opts->physrows <= 0 || opts->physcols <= 0){
logerror(n->nc, "Provided illegal geometry %dx%d\n", opts->physcols, opts->physrows);
return NULL;
}
if(opts->flags > NCREADER_OPTION_CURSOR){ if(opts->flags > NCREADER_OPTION_CURSOR){
logwarn(n->nc, "Provided unsupported flags %016lx\n", opts->flags); logwarn(n->nc, "Provided unsupported flags %016lx\n", opts->flags);
} }
ncreader* nr = malloc(sizeof(*nr)); ncreader* nr = malloc(sizeof(*nr));
if(nr){ if(nr == NULL){
nr->ncp = ncplane_new(n->nc, opts->physrows, opts->physcols, y, x, NULL); ncplane_destroy(n);
if(!nr->ncp){ return NULL;
free(nr);
return NULL;
}
// do *not* bind it to the visible plane; we always want it offscreen,
// to the upper left of the true origin
if((nr->textarea = ncplane_new(n->nc, opts->physrows, opts->physcols, -opts->physrows, -opts->physcols, NULL)) == NULL){
ncplane_destroy(nr->ncp);
free(nr);
return NULL;
}
const char* egc = opts->egc ? opts->egc : "_";
if(ncplane_set_base(nr->ncp, egc, opts->eattrword, opts->echannels) <= 0){
ncreader_destroy(nr, NULL);
return NULL;
}
nr->horscroll = opts->flags & NCREADER_OPTION_HORSCROLL;
nr->xproject = 0;
nr->tchannels = opts->tchannels;
nr->tattrs = opts->tattrword;
nr->no_cmd_keys = opts->flags & NCREADER_OPTION_NOCMDKEYS;
nr->manage_cursor = opts->flags & NCREADER_OPTION_CURSOR;
ncplane_set_channels(nr->ncp, opts->tchannels);
ncplane_set_attr(nr->ncp, opts->tattrword);
if(nr->manage_cursor){
if(notcurses_cursor_enable(n->nc, nr->ncp->absy, nr->ncp->absx)){
ncplane_destroy(nr->textarea);
ncplane_destroy(nr->ncp);
free(nr);
return NULL;
}
}
} }
nr->ncp = n;
// do *not* bind it to the visible plane; we always want it offscreen,
// to the upper left of the true origin
if((nr->textarea = ncplane_new(n->nc, ncplane_dim_y(n), ncplane_dim_x(n),
-ncplane_dim_y(n), -ncplane_dim_x(n), NULL)) == NULL){
ncplane_destroy(nr->ncp);
free(nr);
return NULL;
}
nr->horscroll = opts->flags & NCREADER_OPTION_HORSCROLL;
nr->xproject = 0;
nr->tchannels = opts->tchannels;
nr->tattrs = opts->tattrword;
nr->no_cmd_keys = opts->flags & NCREADER_OPTION_NOCMDKEYS;
nr->manage_cursor = opts->flags & NCREADER_OPTION_CURSOR;
ncplane_set_channels(nr->ncp, opts->tchannels);
ncplane_set_attr(nr->ncp, opts->tattrword);
return nr; return nr;
} }

View File

@ -31,16 +31,14 @@ auto main(int argc, const char** argv) -> int {
nopts.flags = NCOPTION_INHIBIT_SETLOCALE; nopts.flags = NCOPTION_INHIBIT_SETLOCALE;
NotCurses nc(nopts); NotCurses nc(nopts);
int dimy, dimx; int dimy, dimx;
std::unique_ptr<Plane *> n = std::make_unique<Plane *>(nc.get_stdplane(&dimy, &dimx)); auto n = std::make_unique<Plane *>(nc.get_stdplane(&dimy, &dimx));
nc.get_term_dim(&dimy, &dimx); nc.get_term_dim(&dimy, &dimx);
ncreader_options opts{}; ncreader_options opts{};
opts.physrows = dimy / 8;
opts.physcols = dimx / 2;
opts.egc = "";
opts.flags = NCREADER_OPTION_CURSOR | (horscroll ? NCREADER_OPTION_HORSCROLL : 0); opts.flags = NCREADER_OPTION_CURSOR | (horscroll ? NCREADER_OPTION_HORSCROLL : 0);
// FIXME c++ is crashing // can't use Plane until we have move constructor for Reader
//Reader nr(nc, 0, 0, &opts); struct ncplane* rp = ncplane_new(nc, dimy / 8, dimx / 2, 2, 2, nullptr);
auto nr = ncreader_create(**n, 2, 2, &opts); ncplane_set_base(rp, "", 0, 0);
auto nr = ncreader_create(rp, &opts);
if(nr == nullptr){ if(nr == nullptr){
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -67,7 +65,7 @@ auto main(int argc, const char** argv) -> int {
nc.render(); nc.render();
char* contents; char* contents;
ncreader_destroy(nr, &contents); ncreader_destroy(nr, &contents);
nc.stop(); //nc.stop();
if(contents){ if(contents){
printf("\n input: %s\n", contents); printf("\n input: %s\n", contents);
} }

View File

@ -12,32 +12,13 @@ TEST_CASE("Readers") {
REQUIRE(n_); REQUIRE(n_);
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0)); REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
SUBCASE("ReaderBadOptions") {
ncreader_options opts{};
auto nr = ncreader_create(n_, 0, 0, &opts);
CHECK(!nr);
opts.physrows = 1;
nr = ncreader_create(n_, 0, 0, &opts);
CHECK(!nr);
opts.physcols = 1;
opts.physrows = 0;
nr = ncreader_create(n_, 0, 0, &opts);
CHECK(!nr);
}
SUBCASE("ReaderRender") { SUBCASE("ReaderRender") {
ncreader_options opts{}; ncreader_options opts{};
opts.physrows = dimy / 2; auto ncp = ncplane_new(nc_, dimy / 2, dimx / 2, 0, 0, nullptr);
opts.physcols = dimx / 2; uint64_t echannels = CHANNELS_RGB_INITIALIZER(0xff, 0x44, 0xff, 0, 0, 0);
if(enforce_utf8()){ ncplane_set_base(ncp, enforce_utf8() ? strdup("") : strdup("x"), 0, echannels);
opts.egc = strdup(""); auto nr = ncreader_create(ncp, &opts);
}else{
opts.egc = strdup("x");
}
auto nr = ncreader_create(n_, 0, 0, &opts);
REQUIRE(nullptr != nr); REQUIRE(nullptr != nr);
channels_set_fg(&opts.echannels, 0xff44ff);
ncplane_set_base(n_, opts.egc, opts.eattrword, opts.echannels);
CHECK(0 == notcurses_render(nc_)); CHECK(0 == notcurses_render(nc_));
char* contents = nullptr; char* contents = nullptr;
ncreader_destroy(nr, &contents); ncreader_destroy(nr, &contents);