ncmultiselect: normalize per new widget API #627 #1006

This commit is contained in:
nick black 2020-09-13 07:51:49 -04:00 committed by Nick Black
parent 692e0ce87f
commit 306948507f
9 changed files with 139 additions and 96 deletions

13
NEWS.md
View File

@ -1,6 +1,19 @@
This document attempts to list user-visible changes and any major internal This document attempts to list user-visible changes and any major internal
rearrangements of Notcurses. rearrangements of Notcurses.
* 1.7.3 (not yet released)
* The long-promised/dreaded Great Widget Review, normalizing behavior across
all widgets, has been effected. Sorry, there was no getting around this
one. Pretty much all widgets have slightly changed, because pretty much all
widgets previously behaved slightly differently:
* `ncselector` no longer accepts `y, x` placement parameters.
* `ncselector` now takes ownership of the provided `ncplane`. It is
destroyed by `ncselector_destroy`/`ncselector_create`.
* `ncmultiselector` no longer accepts `y, x` placement parameters.
* `ncmultiselector` now takes ownership of the provided `ncplane`. It is
destroyed by `ncmultiselector_destroy`/`ncmultiselector_create`.
* ...
* 1.7.2 (2020-09-09) * 1.7.2 (2020-09-09)
* Exported `ncvisual_default_blitter()`, so that the effective value of * Exported `ncvisual_default_blitter()`, so that the effective value of
`NCBLIT_DEFAULT` can be determined. `NCBLIT_DEFAULT` can be determined.

View File

@ -2221,36 +2221,36 @@ Selectors:
╭──────────────────────────╮ ╭──────────────────────────╮
│This is the primary header│ │This is the primary header│
╭──────────────────────this is the secondary header──────╮ ╭──────────────────────this is the secondary header──────╮
↑ │ │ ↑
│ option1 Long text #1 │ option1 Long text #1
│ option2 Long text #2 │ option2 Long text #2
│ option3 Long text #3 │ option3 Long text #3
│ option4 Long text #4 │ option4 Long text #4
│ option5 Long text #5 │ option5 Long text #5
│ option6 Long text #6 │ option6 Long text #6
↓ │ │ ↓
╰────────────────────────────────────here's the footer───╯ ╰────────────────────────────────────here's the footer───╯
``` ```
Multiselectors: Multiselectors:
``` ```
────────────────────────────────────────────────────────────────╮ ╭───────────────────╮
│ this is truly an awfully long example of a MULTISELECTOR title │ │ short round title │
─────┴─────────────────────────────pick one or more options─────────── now this secondary is also very, very, very outlandishly long, you see
│ ↑ │ │ ↑ │
│ ☐ 1 Across the Atlantic Ocean, there was a place called North America │ ☐ Pa231 Protactinium-231 (162kg)
│ ☐ 2 Discovered by an Italian in the employ of the queen of Spain │ ☐ U233 Uranium-233 (15kg)
☒ 3 Colonized extensively by the Spanish and the French ☐ U235 Uranium-235 (50kg)
│ ☐ 4 Developed into a rich nation by Dutch-supplied African slaves │ ☐ Np236 Neptunium-236 (7kg)
│ ☐ 5 And thus became the largest English-speaking nation on earth │ ☐ Np237 Neptunium-237 (60kg)
│ ☐ 6 Namely, the United States of America │ ☐ Pu238 Plutonium-238 (10kg)
│ ☐ 7 The inhabitants of the United States called themselves Yankees │ ☐ Pu239 Plutonium-239 (10kg)
☒ 8 For some reason ☐ Pu240 Plutonium-240 (40kg)
│ ☐ 9 And, eventually noticing the rest of the world was there, │ ☐ Pu241 Plutonium-241 (13kg)
│ ☐ 10 Decided to rule it. │ ☐ Am241 Americium-241 (100kg)
│ ↓ │ │ ↓ │
╰────────────────────────press q to exit (there is sartrev("no exit")─╯ ╰────────────────────────press q to exit (there is sartrev("no exit"))─╯
``` ```
Menus: Menus:

View File

@ -42,7 +42,7 @@ typedef struct ncmultiselector_options {
} ncmultiselector_options; } ncmultiselector_options;
``` ```
**struct ncmultiselector* ncmultiselector_create(struct ncplane* n, int y, int x, const ncmultiselector_options* opts);** **struct ncmultiselector* ncmultiselector_create(struct ncplane* n, const ncmultiselector_options* opts);**
**int ncmultiselector_selected(bool* selected, unsigned n);** **int ncmultiselector_selected(bool* selected, unsigned n);**
@ -56,24 +56,34 @@ typedef struct ncmultiselector_options {
# NOTES # NOTES
Currently, the **ncplane** **n** provided to **ncmultiselector_create** The **ncplane** **n** provided to **ncmultiselector_create** must not be
must not be **NULL**, though the **ncmultiselector** will always get its **NULL**. It will be freely resized by the new **ncmultiselector**.
own plane, and this plane will not (currently) be bound to **n**.
**ncmultiselector_selected** returns a bitmap corresponding to the **ncmultiselector_selected** returns the index of the option currently
currently-selected options. highlighted. It stores to the **n**-ary bitmap pointed to by **selected**
based on the currently-selected options.
**ncmultiselector_plane** will return the **ncplane** on which the widget is **ncmultiselector_plane** will return the **ncplane** on which the widget is
drawn. drawn.
While the **ncmultiselector** can be driven entirely by client code, Input should be run through **ncmultiselector_offer_input** to take advantage
input can be run through **ncmultiselector_offer_input** to take of common controls. It will handle the up and down arrows, along with PageUp
advantage of common controls. It will handle the up and down arrows, and PageDown. If the mouse is enabled, the mouse scrollwheel and mouse clicks
along with PageUp and PageDown, and space to select/deselect options. on the scroll arrows will be handled.
If the mouse is enabled, the mouse scrollwheel and mouse clicks on the scroll
arrows will be handled. **ncmultiselector_destroy** destroys the backing **ncplane**, as does
**ncmultiselector_create** in the event of any error.
# RETURN VALUES # RETURN VALUES
**ncmultiselector_create** returns **NULL** on an error, in which case the
passed **ncplane** is destroyed.
**ncmultiselector_selected** returns -1 if there are no items, or if **n** is
not equal to the number of items. It otherwise returns the index of the
currently highlighted option, and writes a bitmap to **selected** based off
the selected items.
# SEE ALSO # SEE ALSO
**notcurses(3)**, **notcurses(3)**,

View File

@ -15,24 +15,24 @@ namespace ncpp
static ncmultiselector_options default_options; static ncmultiselector_options default_options;
public: public:
explicit MultiSelector (Plane *plane, int y, int x, const ncmultiselector_options *opts = nullptr) explicit MultiSelector (Plane *plane, const ncmultiselector_options *opts = nullptr)
: MultiSelector (static_cast<const Plane*>(plane), y, x, opts) : MultiSelector (static_cast<const Plane*>(plane), opts)
{} {}
explicit MultiSelector (Plane const* plane, int y, int x, const ncmultiselector_options *opts = nullptr) explicit MultiSelector (Plane const* plane, const ncmultiselector_options *opts = nullptr)
: Root (Utilities::get_notcurses_cpp (plane)) : Root (Utilities::get_notcurses_cpp (plane))
{ {
common_init (Utilities::to_ncplane (plane), y, x, opts); common_init (Utilities::to_ncplane (plane), opts);
} }
explicit MultiSelector (Plane &plane, int y, int x, const ncmultiselector_options *opts = nullptr) explicit MultiSelector (Plane &plane, const ncmultiselector_options *opts = nullptr)
: MultiSelector (static_cast<Plane const&>(plane), y, x, opts) : MultiSelector (static_cast<Plane const&>(plane), opts)
{} {}
explicit MultiSelector (Plane const& plane, int y, int x, const ncmultiselector_options *opts = nullptr) explicit MultiSelector (Plane const& plane, const ncmultiselector_options *opts = nullptr)
: Root (Utilities::get_notcurses_cpp (plane)) : Root (Utilities::get_notcurses_cpp (plane))
{ {
common_init (Utilities::to_ncplane (plane), y, x, opts); common_init (Utilities::to_ncplane (plane), opts);
} }
~MultiSelector () ~MultiSelector ()
@ -54,12 +54,12 @@ namespace ncpp
Plane* get_plane () const noexcept; Plane* get_plane () const noexcept;
private: private:
void common_init (ncplane *plane, int y, int x, const ncmultiselector_options *opts) void common_init (ncplane *plane, const ncmultiselector_options *opts)
{ {
if (plane == nullptr) if (plane == nullptr)
throw invalid_argument ("'plane' must be a valid pointer"); throw invalid_argument ("'plane' must be a valid pointer");
multiselector = ncmultiselector_create (plane, y, x, opts == nullptr ? &default_options : opts); multiselector = ncmultiselector_create (plane, opts == nullptr ? &default_options : opts);
if (multiselector == nullptr) if (multiselector == nullptr)
throw init_error ("Notcurses failed to create a new multiselector"); throw init_error ("Notcurses failed to create a new multiselector");
} }

View File

@ -2657,14 +2657,14 @@ API void ncplane_greyscale(struct ncplane* n);
// ╭──────────────────────────╮ // ╭──────────────────────────╮
// │This is the primary header│ // │This is the primary header│
// ╭──────────────────────this is the secondary header──────╮ // ╭──────────────────────this is the secondary header──────╮
// │ // │
// │ option1 Long text #1 │ // │ option1 Long text #1
// │ option2 Long text #2 │ // │ option2 Long text #2
// │ option3 Long text #3 │ // │ option3 Long text #3
// │ option4 Long text #4 │ // │ option4 Long text #4
// │ option5 Long text #5 │ // │ option5 Long text #5
// │ option6 Long text #6 │ // │ option6 Long text #6
// │ // │
// ╰────────────────────────────────────here's the footer───╯ // ╰────────────────────────────────────here's the footer───╯
// //
// At all times, exactly one item is selected. // At all times, exactly one item is selected.
@ -2736,22 +2736,22 @@ struct ncmselector_item {
// multiselection widget -- a selector supporting multiple selections. // multiselection widget -- a selector supporting multiple selections.
// //
// ────────────────────────────────────────────────────────────────╮ // ╭───────────────────╮
// │ this is truly an awfully long example of a MULTISELECTOR title │ // │ short round title │
//╭─────┴─────────────────────────────pick one (you will die regardless)─ //╭now this secondary is also very, very, very outlandishly long, you see
//│ ↑ │ //│ ↑ │
//│ ☐ 1 Across the Atlantic Ocean, there was a place called North America //│ ☐ Pa231 Protactinium-231 (162kg)
//│ ☐ 2 Discovered by an Italian in the employ of the queen of Spain //│ ☐ U233 Uranium-233 (15kg)
//│ ☐ 3 Colonized extensively by the Spanish and the French //│ ☐ U235 Uranium-235 (50kg)
//│ ☐ 4 Developed into a rich nation by Dutch-supplied African slaves //│ ☐ Np236 Neptunium-236 (7kg)
//│ ☐ 5 And thus became the largest English-speaking nation on earth //│ ☐ Np237 Neptunium-237 (60kg)
//│ ☐ 6 Namely, the United States of America //│ ☐ Pu238 Plutonium-238 (10kg)
//│ ☐ 7 The inhabitants of the United States called themselves Yankees //│ ☐ Pu239 Plutonium-239 (10kg)
//│ ☐ 8 For some reason //│ ☐ Pu240 Plutonium-240 (40kg)
//│ ☐ 9 And, eventually noticing the rest of the world was there, //│ ☐ Pu241 Plutonium-241 (13kg)
//│ ☐ 10 Decided to rule it. //│ ☐ Am241 Americium-241 (100kg)
//│ ↓ │ //│ ↓ │
//╰────────────────────────press q to exit (there is sartrev("no exit")─╯ //╰────────────────────────press q to exit (there is sartrev("no exit"))─╯
// //
// Unlike the selector widget, zero to all of the items can be selected, but // Unlike the selector widget, zero to all of the items can be selected, but
// also the widget does not support adding or removing items at runtime. // also the widget does not support adding or removing items at runtime.
@ -2772,8 +2772,7 @@ typedef struct ncmultiselector_options {
uint64_t flags; // bitfield of NCMULTISELECTOR_OPTION_* uint64_t flags; // bitfield of NCMULTISELECTOR_OPTION_*
} ncmultiselector_options; } ncmultiselector_options;
API struct ncmultiselector* ncmultiselector_create(struct ncplane* n, int y, int x, API struct ncmultiselector* ncmultiselector_create(struct ncplane* n, const ncmultiselector_options* opts)
const ncmultiselector_options* opts)
__attribute__ ((nonnull (1))); __attribute__ ((nonnull (1)));
// Return selected vector. An array of bools must be provided, along with its // Return selected vector. An array of bools must be provided, along with its

View File

@ -277,7 +277,7 @@ typedef struct ncmultiselector_options {
uint64_t boxchannels; // border channels uint64_t boxchannels; // border channels
uint64_t bgchannels; // background channels, used only in body uint64_t bgchannels; // background channels, used only in body
} ncmultiselector_options; } ncmultiselector_options;
struct ncmultiselector* ncmultiselector_create(struct ncplane* n, int y, int x, const ncmultiselector_options* opts); struct ncmultiselector* ncmultiselector_create(struct ncplane* n, const ncmultiselector_options* opts);
int ncmultiselector_selected(struct ncmultiselector* n, bool* selected, unsigned count); int ncmultiselector_selected(struct ncmultiselector* n, bool* selected, unsigned count);
struct ncplane* ncmultiselector_plane(struct ncmultiselector* n); struct ncplane* ncmultiselector_plane(struct ncmultiselector* n);
bool ncmultiselector_offer_input(struct ncmultiselector* n, const struct ncinput* nc); bool ncmultiselector_offer_input(struct ncmultiselector* n, const struct ncinput* nc);

View File

@ -77,7 +77,11 @@ multiselector_demo(struct ncplane* n, struct ncplane* under, int y){
}; };
channels_set_fg_alpha(&mopts.bgchannels, CELL_ALPHA_BLEND); channels_set_fg_alpha(&mopts.bgchannels, CELL_ALPHA_BLEND);
channels_set_bg_alpha(&mopts.bgchannels, CELL_ALPHA_BLEND); channels_set_bg_alpha(&mopts.bgchannels, CELL_ALPHA_BLEND);
struct ncmultiselector* mselect = ncmultiselector_create(n, y, 0, &mopts); struct ncplane* mseln = ncplane_new(ncplane_notcurses(n), 1, 1, y, 0, NULL);
if(mseln == NULL){
return NULL;
}
struct ncmultiselector* mselect = ncmultiselector_create(mseln, &mopts);
if(mselect == NULL){ if(mselect == NULL){
return NULL; return NULL;
} }

View File

@ -773,12 +773,12 @@ bool ncmultiselector_offer_input(ncmultiselector* n, const ncinput* nc){
} }
// calculate the necessary dimensions based off properties of the selector and // calculate the necessary dimensions based off properties of the selector and
// the containing screen FIXME should be based on containing ncplane // the containing plane
static int static int
ncmultiselector_dim_yx(notcurses* nc, const ncmultiselector* n, int* ncdimy, int* ncdimx){ ncmultiselector_dim_yx(const ncmultiselector* n, int* ncdimy, int* ncdimx){
int rows = 0, cols = 0; // desired dimensions int rows = 0, cols = 0; // desired dimensions
int dimy, dimx; // dimensions of containing screen int dimy, dimx; // dimensions of containing screen
notcurses_term_dim_yx(nc, &dimy, &dimx); ncplane_dim_yx(ncplane_parent(n->ncp), &dimy, &dimx);
if(n->title){ // header adds two rows for riser if(n->title){ // header adds two rows for riser
rows += 2; rows += 2;
} }
@ -805,8 +805,7 @@ ncmultiselector_dim_yx(notcurses* nc, const ncmultiselector* n, int* ncdimy, int
return 0; return 0;
} }
ncmultiselector* ncmultiselector_create(ncplane* n, int y, int x, ncmultiselector* ncmultiselector_create(ncplane* n, const ncmultiselector_options* opts){
const ncmultiselector_options* opts){
ncmultiselector_options zeroed = {}; ncmultiselector_options zeroed = {};
if(!opts){ if(!opts){
opts = &zeroed; opts = &zeroed;
@ -840,9 +839,7 @@ ncmultiselector* ncmultiselector_create(ncplane* n, int y, int x,
ns->darrowy = ns->uarrowy = ns->arrowx = -1; ns->darrowy = ns->uarrowy = ns->arrowx = -1;
if(itemcount){ if(itemcount){
if(!(ns->items = malloc(sizeof(*ns->items) * itemcount))){ if(!(ns->items = malloc(sizeof(*ns->items) * itemcount))){
free(ns->title); free(ns->secondary); free(ns->footer); goto freeitems;
free(ns);
return NULL;
} }
}else{ }else{
ns->items = NULL; ns->items = NULL;
@ -867,10 +864,11 @@ ncmultiselector* ncmultiselector_create(ncplane* n, int y, int x,
} }
} }
int dimy, dimx; int dimy, dimx;
if(ncmultiselector_dim_yx(n->nc, ns, &dimy, &dimx)){ ns->ncp = n;
if(ncmultiselector_dim_yx(ns, &dimy, &dimx)){
goto freeitems; goto freeitems;
} }
if(!(ns->ncp = ncplane_bound(n, dimy, dimx, y, x, NULL))){ if(ncplane_resize_simple(ns->ncp, dimy, dimx)){
goto freeitems; goto freeitems;
} }
cell_init(&ns->background); cell_init(&ns->background);
@ -893,6 +891,7 @@ freeitems:
free(ns->items); free(ns->items);
free(ns->title); free(ns->secondary); free(ns->footer); free(ns->title); free(ns->secondary); free(ns->footer);
free(ns); free(ns);
ncplane_destroy(n);
return NULL; return NULL;
} }

View File

@ -7,17 +7,27 @@
// http://theboomerbible.com/tbb112.html // http://theboomerbible.com/tbb112.html
static struct ncmselector_item items[] = { static struct ncmselector_item items[] = {
{ "1", "Across the Atlantic Ocean, there was a place called North America", .selected = false, }, { "Pa231", "Protactinium-231 (162kg)", .selected = false, },
{ "2", "Discovered by an Italian in the employ of the queen of Spain", .selected = false, }, { "U233", "Uranium-233 (15kg)", .selected = false, },
{ "3", "Colonized extensively by the Spanish and the French", .selected = false, }, { "U235", "Uranium-235 (50kg)", .selected = false, },
{ "4", "Developed into a rich nation by Dutch-supplied African slaves", .selected = false, }, { "Np236", "Neptunium-236 (7kg)", .selected = false, },
{ "5", "And thus became the largest English-speaking nation on earth", .selected = false, }, { "Np237", "Neptunium-237 (60kg)", .selected = false, },
{ "6", "Namely, the United States of America", .selected = false, }, { "Pu238", "Plutonium-238 (10kg)", .selected = false, },
{ "7", "The inhabitants of the United States called themselves Yankees", .selected = false, }, { "Pu239", "Plutonium-239 (10kg)", .selected = false, },
{ "8", "For some reason", .selected = false, }, { "Pu240", "Plutonium-240 (40kg)", .selected = false, },
{ "9", "And, eventually noticing the rest of the world was there,", .selected = false, }, { "Pu241", "Plutonium-241 (13kg)", .selected = false, },
{ "10", "Decided to rule it.", .selected = false, }, { "Am241", "Americium-241 (100kg)", .selected = false, },
{ "11", "This is their story.", .selected = false, }, { "Pu242", "Plutonium-242 (100kg)", .selected = false, },
{ "Am242", "Americium-242 (18kg)", .selected = false, },
{ "Am243", "Americium-243 (155kg)", .selected = false, },
{ "Cm243", "Curium-243 (10kg)", .selected = false, },
{ "Cm244", "Curium-244 (30kg)", .selected = false, },
{ "Cm245", "Curium-245 (13kg)", .selected = false, },
{ "Cm246", "Curium-246 (84kg)", .selected = false, },
{ "Cm247", "Curium-247 (7kg)", .selected = false, },
{ "Bk247", "Berkelium-247 (10kg)", .selected = false, },
{ "Cf249", "Californium-249 (6kg)", .selected = false, },
{ "Cf251", "Californium-251 (9kg)", .selected = false, },
{ NULL, NULL, .selected = false, }, { NULL, NULL, .selected = false, },
}; };
@ -96,28 +106,36 @@ int main(void){
ncplane_set_fg(n, 0x40f040); ncplane_set_fg(n, 0x40f040);
ncplane_putstr_aligned(n, 0, NCALIGN_RIGHT, "multiselect widget demo"); ncplane_putstr_aligned(n, 0, NCALIGN_RIGHT, "multiselect widget demo");
struct ncmultiselector* ns = ncmultiselector_create(n, 3, 0, &sopts); struct ncplane* mseln = ncplane_new(nc, 1, 1, 3, 0, NULL);
if(mseln == NULL){
goto err;
}
struct ncmultiselector* ns = ncmultiselector_create(mseln, &sopts);
run_mselect(nc, ns); run_mselect(nc, ns);
sopts.title = "short round title"; sopts.title = "short round title";
ns = ncmultiselector_create(n, 3, 0, &sopts); mseln = ncplane_new(nc, 1, 1, 3, 0, NULL);
ns = ncmultiselector_create(mseln, &sopts);
run_mselect(nc, ns); run_mselect(nc, ns);
sopts.title = "short round title"; sopts.title = "short round title";
sopts.secondary = "now this secondary is also very, very, very outlandishly long, you see"; sopts.secondary = "now this secondary is also very, very, very outlandishly long, you see";
ns = ncmultiselector_create(n, 3, 0, &sopts); mseln = ncplane_new(nc, 1, 1, 3, 0, NULL);
ns = ncmultiselector_create(mseln, &sopts);
run_mselect(nc, ns); run_mselect(nc, ns);
sopts.title = "the whole world is watching"; sopts.title = "the whole world is watching";
sopts.secondary = NULL; sopts.secondary = NULL;
sopts.footer = "now this FOOTERFOOTER is also very, very, very outlandishly long, you see"; sopts.footer = "now this FOOTERFOOTER is also very, very, very outlandishly long, you see";
ns = ncmultiselector_create(n, 3, 0, &sopts); mseln = ncplane_new(nc, 1, 1, 3, 0, NULL);
ns = ncmultiselector_create(mseln, &sopts);
run_mselect(nc, ns); run_mselect(nc, ns);
sopts.title = "chomps"; sopts.title = "chomps";
sopts.secondary = NULL; sopts.secondary = NULL;
sopts.footer = NULL; sopts.footer = NULL;
ns = ncmultiselector_create(n, 3, 0, &sopts); mseln = ncplane_new(nc, 1, 1, 3, 0, NULL);
ns = ncmultiselector_create(mseln, &sopts);
run_mselect(nc, ns); run_mselect(nc, ns);
if(notcurses_stop(nc)){ if(notcurses_stop(nc)){