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
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)
* Exported `ncvisual_default_blitter()`, so that the effective value of
`NCBLIT_DEFAULT` can be determined.

View File

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

View File

@ -42,7 +42,7 @@ typedef struct 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);**
@ -56,24 +56,34 @@ typedef struct ncmultiselector_options {
# NOTES
Currently, the **ncplane** **n** provided to **ncmultiselector_create**
must not be **NULL**, though the **ncmultiselector** will always get its
own plane, and this plane will not (currently) be bound to **n**.
**ncmultiselector_selected** returns a bitmap corresponding to the
currently-selected options.
The **ncplane** **n** provided to **ncmultiselector_create** must not be
**NULL**. It will be freely resized by the new **ncmultiselector**.
**ncmultiselector_selected** returns the index of the option currently
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
drawn.
While the **ncmultiselector** can be driven entirely by client code,
input can be run through **ncmultiselector_offer_input** to take
advantage of common controls. It will handle the up and down arrows,
along with PageUp and PageDown, and space to select/deselect options.
If the mouse is enabled, the mouse scrollwheel and mouse clicks on the scroll
arrows will be handled.
Input should be run through **ncmultiselector_offer_input** to take advantage
of common controls. It will handle the up and down arrows, along with PageUp
and PageDown. 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
**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
**notcurses(3)**,

View File

@ -15,24 +15,24 @@ namespace ncpp
static ncmultiselector_options default_options;
public:
explicit MultiSelector (Plane *plane, int y, int x, const ncmultiselector_options *opts = nullptr)
: MultiSelector (static_cast<const Plane*>(plane), y, x, opts)
explicit MultiSelector (Plane *plane, const ncmultiselector_options *opts = nullptr)
: 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))
{
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)
: MultiSelector (static_cast<Plane const&>(plane), y, x, opts)
explicit MultiSelector (Plane &plane, const ncmultiselector_options *opts = nullptr)
: 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))
{
common_init (Utilities::to_ncplane (plane), y, x, opts);
common_init (Utilities::to_ncplane (plane), opts);
}
~MultiSelector ()
@ -54,12 +54,12 @@ namespace ncpp
Plane* get_plane () const noexcept;
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)
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)
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 secondary header──────╮
// │
// │ option1 Long text #1 │
// │ option2 Long text #2 │
// │ option3 Long text #3 │
// │ option4 Long text #4 │
// │ option5 Long text #5 │
// │ option6 Long text #6 │
// │
// │
// │ option1 Long text #1
// │ option2 Long text #2
// │ option3 Long text #3
// │ option4 Long text #4
// │ option5 Long text #5
// │ option6 Long text #6
// │
// ╰────────────────────────────────────here's the footer───╯
//
// At all times, exactly one item is selected.
@ -2736,22 +2736,22 @@ struct ncmselector_item {
// multiselection widget -- a selector supporting multiple selections.
//
// ────────────────────────────────────────────────────────────────╮
// │ this is truly an awfully long example of a MULTISELECTOR title │
//╭─────┴─────────────────────────────pick one (you will die regardless)─
// ╭───────────────────╮
// │ short round title │
//╭now this secondary is also very, very, very outlandishly long, you see
//│ ↑ │
//│ ☐ 1 Across the Atlantic Ocean, there was a place called North America
//│ ☐ 2 Discovered by an Italian in the employ of the queen of Spain
//│ ☐ 3 Colonized extensively by the Spanish and the French
//│ ☐ 4 Developed into a rich nation by Dutch-supplied African slaves
//│ ☐ 5 And thus became the largest English-speaking nation on earth
//│ ☐ 6 Namely, the United States of America
//│ ☐ 7 The inhabitants of the United States called themselves Yankees
//│ ☐ 8 For some reason
//│ ☐ 9 And, eventually noticing the rest of the world was there,
//│ ☐ 10 Decided to rule it.
//│ ☐ Pa231 Protactinium-231 (162kg)
//│ ☐ U233 Uranium-233 (15kg)
//│ ☐ U235 Uranium-235 (50kg)
//│ ☐ Np236 Neptunium-236 (7kg)
//│ ☐ Np237 Neptunium-237 (60kg)
//│ ☐ Pu238 Plutonium-238 (10kg)
//│ ☐ Pu239 Plutonium-239 (10kg)
//│ ☐ Pu240 Plutonium-240 (40kg)
//│ ☐ Pu241 Plutonium-241 (13kg)
//│ ☐ 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
// 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_*
} ncmultiselector_options;
API struct ncmultiselector* ncmultiselector_create(struct ncplane* n, int y, int x,
const ncmultiselector_options* opts)
API struct ncmultiselector* ncmultiselector_create(struct ncplane* n, const ncmultiselector_options* opts)
__attribute__ ((nonnull (1)));
// 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 bgchannels; // background channels, used only in body
} 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);
struct ncplane* ncmultiselector_plane(struct ncmultiselector* n);
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_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){
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
// the containing screen FIXME should be based on containing ncplane
// the containing plane
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 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
rows += 2;
}
@ -805,8 +805,7 @@ ncmultiselector_dim_yx(notcurses* nc, const ncmultiselector* n, int* ncdimy, int
return 0;
}
ncmultiselector* ncmultiselector_create(ncplane* n, int y, int x,
const ncmultiselector_options* opts){
ncmultiselector* ncmultiselector_create(ncplane* n, const ncmultiselector_options* opts){
ncmultiselector_options zeroed = {};
if(!opts){
opts = &zeroed;
@ -840,9 +839,7 @@ ncmultiselector* ncmultiselector_create(ncplane* n, int y, int x,
ns->darrowy = ns->uarrowy = ns->arrowx = -1;
if(itemcount){
if(!(ns->items = malloc(sizeof(*ns->items) * itemcount))){
free(ns->title); free(ns->secondary); free(ns->footer);
free(ns);
return NULL;
goto freeitems;
}
}else{
ns->items = NULL;
@ -867,10 +864,11 @@ ncmultiselector* ncmultiselector_create(ncplane* n, int y, int x,
}
}
int dimy, dimx;
if(ncmultiselector_dim_yx(n->nc, ns, &dimy, &dimx)){
ns->ncp = n;
if(ncmultiselector_dim_yx(ns, &dimy, &dimx)){
goto freeitems;
}
if(!(ns->ncp = ncplane_bound(n, dimy, dimx, y, x, NULL))){
if(ncplane_resize_simple(ns->ncp, dimy, dimx)){
goto freeitems;
}
cell_init(&ns->background);
@ -893,6 +891,7 @@ freeitems:
free(ns->items);
free(ns->title); free(ns->secondary); free(ns->footer);
free(ns);
ncplane_destroy(n);
return NULL;
}

View File

@ -7,17 +7,27 @@
// http://theboomerbible.com/tbb112.html
static struct ncmselector_item items[] = {
{ "1", "Across the Atlantic Ocean, there was a place called North America", .selected = false, },
{ "2", "Discovered by an Italian in the employ of the queen of Spain", .selected = false, },
{ "3", "Colonized extensively by the Spanish and the French", .selected = false, },
{ "4", "Developed into a rich nation by Dutch-supplied African slaves", .selected = false, },
{ "5", "And thus became the largest English-speaking nation on earth", .selected = false, },
{ "6", "Namely, the United States of America", .selected = false, },
{ "7", "The inhabitants of the United States called themselves Yankees", .selected = false, },
{ "8", "For some reason", .selected = false, },
{ "9", "And, eventually noticing the rest of the world was there,", .selected = false, },
{ "10", "Decided to rule it.", .selected = false, },
{ "11", "This is their story.", .selected = false, },
{ "Pa231", "Protactinium-231 (162kg)", .selected = false, },
{ "U233", "Uranium-233 (15kg)", .selected = false, },
{ "U235", "Uranium-235 (50kg)", .selected = false, },
{ "Np236", "Neptunium-236 (7kg)", .selected = false, },
{ "Np237", "Neptunium-237 (60kg)", .selected = false, },
{ "Pu238", "Plutonium-238 (10kg)", .selected = false, },
{ "Pu239", "Plutonium-239 (10kg)", .selected = false, },
{ "Pu240", "Plutonium-240 (40kg)", .selected = false, },
{ "Pu241", "Plutonium-241 (13kg)", .selected = false, },
{ "Am241", "Americium-241 (100kg)", .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, },
};
@ -96,28 +106,36 @@ int main(void){
ncplane_set_fg(n, 0x40f040);
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);
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);
sopts.title = "short round title";
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);
sopts.title = "the whole world is watching";
sopts.secondary = NULL;
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);
sopts.title = "chomps";
sopts.secondary = 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);
if(notcurses_stop(nc)){