selector: transfer ownership of ncplane #1006 #627

This commit is contained in:
nick black 2020-09-13 06:39:17 -04:00 committed by Nick Black
parent 8bf71f4bce
commit 8839d44454
6 changed files with 75 additions and 55 deletions

View File

@ -15,26 +15,26 @@ namespace ncpp
static ncselector_options default_options;
public:
explicit Selector (Plane *plane, int y, int x, const ncselector_options *opts = nullptr)
: Selector (static_cast<const Plane*>(plane), y, x, opts)
explicit Selector (Plane *plane, const ncselector_options *opts = nullptr)
: Selector (static_cast<const Plane*>(plane), opts)
{}
explicit Selector (Plane const* plane, int y, int x, const ncselector_options *opts = nullptr)
explicit Selector (Plane const* plane, const ncselector_options *opts = 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), y, x, opts);
common_init (Utilities::to_ncplane (plane), opts);
}
explicit Selector (Plane &plane, int y, int x, const ncselector_options *opts = nullptr)
: Selector (static_cast<Plane const&>(plane), y, x, opts)
explicit Selector (Plane &plane, const ncselector_options *opts = nullptr)
: Selector (static_cast<Plane const&>(plane), opts)
{}
explicit Selector (Plane const& plane, int y, int x, const ncselector_options *opts = nullptr)
explicit Selector (Plane const& plane, const ncselector_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);
}
~Selector ()
@ -76,12 +76,12 @@ namespace ncpp
Plane* get_plane () const noexcept;
private:
void common_init (ncplane *plane, int y, int x, const ncselector_options *opts = nullptr)
void common_init (ncplane *plane, const ncselector_options *opts = nullptr)
{
if (plane == nullptr)
throw invalid_argument ("'plane' must be a valid pointer");
selector = ncselector_create (plane, y, x, opts == nullptr ? &default_options : opts);
selector = ncselector_create (plane, opts == nullptr ? &default_options : opts);
if (selector == nullptr)
throw init_error ("Notcurses failed to create a new selector");
}

View File

@ -2696,8 +2696,7 @@ typedef struct ncselector_options {
uint64_t flags; // bitfield of NCSELECTOR_OPTION_*
} ncselector_options;
API struct ncselector* ncselector_create(struct ncplane* n, int y, int x,
const ncselector_options* opts)
API struct ncselector* ncselector_create(struct ncplane* n, const ncselector_options* opts)
__attribute__ ((nonnull (1)));
// Dynamically add or delete items. It is usually sufficient to supply a static

View File

@ -102,11 +102,14 @@ selector_demo(struct ncplane* n, struct ncplane* under, int dimx, int y){
};
channels_set_fg_alpha(&sopts.bgchannels, CELL_ALPHA_BLEND);
channels_set_bg_alpha(&sopts.bgchannels, CELL_ALPHA_BLEND);
struct ncselector* selector = ncselector_create(n, y, dimx, &sopts);
struct ncplane* mplane = ncplane_new(ncplane_notcurses(n), 1, 1, y, dimx, NULL);
if(mplane == NULL){
return NULL;
}
struct ncselector* selector = ncselector_create(mplane, &sopts);
if(selector == NULL){
return NULL;
}
struct ncplane* mplane = ncselector_plane(selector);
ncplane_move_below(mplane, under);
return selector;
}

View File

@ -193,10 +193,11 @@ ncselector_draw(ncselector* n){
// calculate the necessary dimensions based off properties of the selector
static void
ncselector_dim_yx(notcurses* nc, const ncselector* n, int* ncdimy, int* ncdimx){
ncselector_dim_yx(const ncselector* 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);
const ncplane* parent = ncplane_parent(n->ncp);
ncplane_dim_yx(parent, &dimy, &dimx);
if(n->title){ // header adds two rows for riser
rows += 2;
}
@ -216,7 +217,7 @@ ncselector_dim_yx(notcurses* nc, const ncselector* n, int* ncdimy, int* ncdimx){
*ncdimx = cols;
}
ncselector* ncselector_create(ncplane* n, int y, int x, const ncselector_options* opts){
ncselector* ncselector_create(ncplane* n, const ncselector_options* opts){
ncselector_options zeroed = {};
if(!opts){
opts = &zeroed;
@ -230,10 +231,13 @@ ncselector* ncselector_create(ncplane* n, int y, int x, const ncselector_options
++itemcount;
}
}
if(opts->defidx && opts->defidx >= itemcount){
return NULL;
}
ncselector* ns = malloc(sizeof(*ns));
if(ns == NULL){
goto freeitems;
}
if(opts->defidx && opts->defidx >= itemcount){
goto freeitems;
}
ns->title = opts->title ? strdup(opts->title) : NULL;
ns->titlecols = opts->title ? mbswidth(opts->title) : 0;
ns->secondary = opts->secondary ? strdup(opts->secondary) : NULL;
@ -261,9 +265,7 @@ ncselector* ncselector_create(ncplane* n, int y, int x, const ncselector_options
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;
@ -276,8 +278,7 @@ ncselector* ncselector_create(ncplane* n, int y, int x, const ncselector_options
ns->longop = cols;
}
cols = mbswidth(src->desc);
ns->items[ns->itemcount].desccolumns = cols;
if(cols > ns->longdesc){
ns->items[ns->itemcount].desccolumns = cols; if(cols > ns->longdesc){
ns->longdesc = cols;
}
ns->items[ns->itemcount].option = strdup(src->option);
@ -289,8 +290,10 @@ ncselector* ncselector_create(ncplane* n, int y, int x, const ncselector_options
}
}
int dimy, dimx;
ncselector_dim_yx(n->nc, ns, &dimy, &dimx);
if(!(ns->ncp = ncplane_bound(n, dimy, dimx, y, x, NULL))){
ns->ncp = n;
ncselector_dim_yx(ns, &dimy, &dimx);
if(ncplane_resize_simple(n, dimy, dimx)){
ncplane_destroy(ns->ncp);
goto freeitems;
}
cell_init(&ns->background);
@ -313,12 +316,13 @@ freeitems:
free(ns->items);
free(ns->title); free(ns->secondary); free(ns->footer);
free(ns);
ncplane_destroy(n);
return NULL;
}
int ncselector_additem(ncselector* n, const struct ncselector_item* item){
int origdimy, origdimx;
ncselector_dim_yx(n->ncp->nc, n, &origdimy, &origdimx);
ncselector_dim_yx(n, &origdimy, &origdimx);
size_t newsize = sizeof(*n->items) * (n->itemcount + 1);
struct ncselector_item* items = realloc(n->items, newsize);
if(!items){
@ -339,7 +343,7 @@ int ncselector_additem(ncselector* n, const struct ncselector_item* item){
}
++n->itemcount;
int dimy, dimx;
ncselector_dim_yx(n->ncp->nc, n, &dimy, &dimx);
ncselector_dim_yx(n, &dimy, &dimx);
if(origdimx < dimx || origdimy < dimy){ // resize if too small
ncplane_resize_simple(n->ncp, dimy, dimx);
}
@ -348,7 +352,7 @@ int ncselector_additem(ncselector* n, const struct ncselector_item* item){
int ncselector_delitem(ncselector* n, const char* item){
int origdimy, origdimx;
ncselector_dim_yx(n->ncp->nc, n, &origdimy, &origdimx);
ncselector_dim_yx(n, &origdimy, &origdimx);
bool found = false;
int maxop = 0, maxdesc = 0;
for(unsigned idx = 0 ; idx < n->itemcount ; ++idx){
@ -380,7 +384,7 @@ int ncselector_delitem(ncselector* n, const char* item){
n->longop = maxop;
n->longdesc = maxdesc;
int dimy, dimx;
ncselector_dim_yx(n->ncp->nc, n, &dimy, &dimx);
ncselector_dim_yx(n, &dimy, &dimx);
if(origdimx > dimx || origdimy > dimy){ // resize if too big
ncplane_resize_simple(n->ncp, dimy, dimx);
}

View File

@ -7,16 +7,16 @@
static struct ncselector_item items[] = {
#define SITEM(short, long) { short, long, 0, 0, }
SITEM("first", "this is the first option"),
SITEM("2nd", "this is the second option"),
SITEM("3", "third, third, third option am i"),
SITEM("fourth", "i have another option here"),
SITEM("five", "golden rings"),
SITEM("666", "now it is time for me to REIGN IN BLOOD"),
SITEM("7seven7", "this monkey's gone to heaven"),
SITEM("8 8 8", "the chinese 平仮名平平仮名仮名love me, i'm told"),
SITEM("nine", "nine, nine, nine 'cause you left me"),
SITEM("ten", "stunning and brave"),
SITEM("Afrikaans", "Ek kan glas eet, dit maak my nie seer nie."),
SITEM("Kabuverdianu", "Mtá podê kumê vidru, ká stá máguame."),
SITEM("Lao", "ຂອ້ຍກິນແກ້ວໄດ້ໂດຍທີ່ມັນບໍ່ໄດ້ເຮັດໃຫ້ຂອ້ຍເຈັບ."),
SITEM("Japanese", "私はガラスを食べられます。それは私を傷つけません。"),
SITEM("Khmer", "ខ្ញុំអាចញុំកញ្ចក់បាន ដោយគ្មានបញ្ហារ"),
SITEM("Hindi", "मैं काँच खा सकता हूँ और मुझे उससे कोई चोट नहीं पहुंचती. "),
SITEM("Tamil", "நான் கண்ணாடி சாப்பிடுவேன், அதனால் எனக்கு ஒரு கேடும் வராது. "),
SITEM("Telugu", "నేను గాజు తినగలను మరియు అలా చేసినా నాకు ఏమి ఇబ్బంది లేదు "),
SITEM("Tibetan", "ཤེལ་སྒོ་ཟ་ནས་ང་ན་གི་མ་རེད།"),
SITEM("Russian", "Я могу есть стекло, оно мне не вредит."),
SITEM(NULL, NULL),
#undef SITEM
};
@ -98,28 +98,33 @@ int main(void){
ncplane_set_fg(n, 0x40f040);
ncplane_putstr_aligned(n, 0, NCALIGN_RIGHT, "selector widget demo");
struct ncselector* ns = ncselector_create(n, 3, 0, &sopts);
struct ncplane* seln = ncplane_new(nc, 1, 1, 3, 0, NULL);
struct ncselector* ns = ncselector_create(seln, &sopts);
run_selector(nc, ns);
sopts.title = "short round title";
ns = ncselector_create(n, 3, 0, &sopts);
seln = ncplane_new(nc, 1, 1, 3, 0, NULL);
ns = ncselector_create(seln, &sopts);
run_selector(nc, ns);
sopts.title = "short round title";
sopts.secondary = "now this secondary is also very, very, very outlandishly long, you see";
ns = ncselector_create(n, 3, 0, &sopts);
seln = ncplane_new(nc, 1, 1, 3, 0, NULL);
ns = ncselector_create(seln, &sopts);
run_selector(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 = ncselector_create(n, 3, 0, &sopts);
seln = ncplane_new(nc, 1, 1, 3, 0, NULL);
ns = ncselector_create(seln, &sopts);
run_selector(nc, ns);
sopts.title = "chomps";
sopts.secondary = NULL;
sopts.footer = NULL;
ns = ncselector_create(n, 3, 0, &sopts);
seln = ncplane_new(nc, 1, 1, 3, 0, NULL);
ns = ncselector_create(seln, &sopts);
run_selector(nc, ns);
if(notcurses_stop(nc)){

View File

@ -13,7 +13,8 @@ TEST_CASE("Selectors") {
SUBCASE("EmptySelector") {
struct ncselector_options opts{};
struct ncselector* ncs = ncselector_create(n_, 0, 0, &opts);
struct ncplane* n = ncplane_new(nc_, 1, 1, 0, 0, nullptr);
struct ncselector* ncs = ncselector_create(n, &opts);
REQUIRE(nullptr != ncs);
CHECK(0 == notcurses_render(nc_));
CHECK(nullptr == ncselector_selected(ncs));
@ -29,7 +30,8 @@ TEST_CASE("Selectors") {
SUBCASE("TitledSelector") {
struct ncselector_options opts{};
opts.title = strdup("hey hey whaddya say");
struct ncselector* ncs = ncselector_create(n_, 0, 0, &opts);
struct ncplane* n = ncplane_new(nc_, 1, 1, 0, 0, nullptr);
struct ncselector* ncs = ncselector_create(n, &opts);
REQUIRE(nullptr != ncs);
CHECK(0 == notcurses_render(nc_));
struct ncplane* ncsp = ncselector_plane(ncs);
@ -44,7 +46,8 @@ TEST_CASE("Selectors") {
SUBCASE("SecondarySelector") {
struct ncselector_options opts{};
opts.secondary = strdup("this is not a title, but it's not *not* a title");
struct ncselector* ncs = ncselector_create(n_, 0, 0, &opts);
struct ncplane* n = ncplane_new(nc_, 1, 1, 0, 0, nullptr);
struct ncselector* ncs = ncselector_create(n, &opts);
REQUIRE(nullptr != ncs);
CHECK(0 == notcurses_render(nc_));
struct ncplane* ncsp = ncselector_plane(ncs);
@ -59,7 +62,8 @@ TEST_CASE("Selectors") {
SUBCASE("FooterSelector") {
struct ncselector_options opts{};
opts.footer = strdup("i am a lone footer, little old footer");
struct ncselector* ncs = ncselector_create(n_, 0, 0, &opts);
struct ncplane* n = ncplane_new(nc_, 1, 1, 0, 0, nullptr);
struct ncselector* ncs = ncselector_create(n, &opts);
REQUIRE(nullptr != ncs);
CHECK(0 == notcurses_render(nc_));
struct ncplane* ncsp = ncselector_plane(ncs);
@ -80,7 +84,8 @@ TEST_CASE("Selectors") {
};
struct ncselector_options opts{};
opts.items = items;
struct ncselector* ncs = ncselector_create(n_, 0, 0, &opts);
struct ncplane* n = ncplane_new(nc_, 1, 1, 0, 0, nullptr);
struct ncselector* ncs = ncselector_create(n, &opts);
REQUIRE(nullptr != ncs);
CHECK(0 == notcurses_render(nc_));
struct ncplane* ncsp = ncselector_plane(ncs);
@ -94,7 +99,8 @@ TEST_CASE("Selectors") {
SUBCASE("EmptySelectorMovement") {
struct ncselector_options opts{};
struct ncselector* ncs = ncselector_create(n_, 0, 0, &opts);
struct ncplane* n = ncplane_new(nc_, 1, 1, 0, 0, nullptr);
struct ncselector* ncs = ncselector_create(n, &opts);
REQUIRE(nullptr != ncs);
CHECK(0 == notcurses_render(nc_));
auto sel = ncselector_selected(ncs);
@ -117,7 +123,8 @@ TEST_CASE("Selectors") {
};
struct ncselector_options opts{};
opts.items = items;
struct ncselector* ncs = ncselector_create(n_, 0, 0, &opts);
struct ncplane* n = ncplane_new(nc_, 1, 1, 0, 0, nullptr);
struct ncselector* ncs = ncselector_create(n, &opts);
REQUIRE(nullptr != ncs);
auto sel = ncselector_selected(ncs);
REQUIRE(nullptr != sel);
@ -155,7 +162,8 @@ TEST_CASE("Selectors") {
struct ncselector_options opts{};
opts.maxdisplay = 1;
opts.items = items;
struct ncselector* ncs = ncselector_create(n_, 0, 0, &opts);
struct ncplane* n = ncplane_new(nc_, 1, 1, 0, 0, nullptr);
struct ncselector* ncs = ncselector_create(n, &opts);
REQUIRE(nullptr != ncs);
CHECK(0 == notcurses_render(nc_));
auto sel = ncselector_selected(ncs);
@ -198,7 +206,8 @@ TEST_CASE("Selectors") {
struct ncselector_options opts{};
opts.maxdisplay = 2;
opts.items = items;
struct ncselector* ncs = ncselector_create(n_, 0, 0, &opts);
struct ncplane* n = ncplane_new(nc_, 1, 1, 0, 0, nullptr);
struct ncselector* ncs = ncselector_create(n, &opts);
REQUIRE(nullptr != ncs);
CHECK(0 == notcurses_render(nc_));
const char* sel = ncselector_selected(ncs);