mirror of
https://github.com/dankamongmen/notcurses.git
synced 2024-11-18 03:25:55 +00:00
Use column width in selector calculations #302
This commit is contained in:
parent
5982707f9e
commit
fad612bd2f
@ -2136,6 +2136,8 @@ API int ncdirect_stop(struct ncdirect* nc);
|
||||
struct selector_item {
|
||||
char* option;
|
||||
char* desc;
|
||||
size_t opcolumns; // filled in by library
|
||||
size_t desccolumns; // filled in by library
|
||||
};
|
||||
|
||||
typedef struct selector_options {
|
||||
|
@ -128,13 +128,16 @@ typedef struct ncselector {
|
||||
unsigned selected; // index of selection
|
||||
unsigned startdisp; // index of first option displayed
|
||||
unsigned maxdisplay; // max number of items to display, 0 -> no limit
|
||||
size_t longop; // length of longest option
|
||||
size_t longdesc; // length of longest description
|
||||
int longop; // columns occupied by longest option
|
||||
int longdesc; // columns occupied by longest description
|
||||
struct selector_item* items; // list of items and descriptions, heap-copied
|
||||
unsigned itemcount; // number of pairs in 'items'
|
||||
char* title; // can be NULL, in which case there's no riser
|
||||
int titlecols; // columns occupied by title
|
||||
char* secondary; // can be NULL
|
||||
int secondarycols; // columns occupied by secondary
|
||||
char* footer; // can be NULL
|
||||
int footercols; // columns occupied by footer
|
||||
uint64_t opchannels; // option channels
|
||||
uint64_t descchannels; // description channels
|
||||
uint64_t titlechannels; // title channels
|
||||
|
@ -4,16 +4,16 @@
|
||||
// ideal body width given the ncselector's items and secondary/footer
|
||||
static size_t
|
||||
ncselector_body_width(const ncselector* n){
|
||||
size_t cols = 0;
|
||||
int cols = 0;
|
||||
// the body is the maximum of
|
||||
// * longop + longdesc + 5
|
||||
// * secondary + 2
|
||||
// * footer + 2
|
||||
if(n->footer && strlen(n->footer) + 2 > cols){
|
||||
cols = strlen(n->footer) + 2;
|
||||
if(n->footercols + 2 > cols){
|
||||
cols = n->footercols + 2;
|
||||
}
|
||||
if(n->secondary && strlen(n->secondary) + 2 > cols){
|
||||
cols = strlen(n->secondary) + 2;
|
||||
if(n->secondarycols + 2 > cols){
|
||||
cols = n->secondarycols + 2;
|
||||
}
|
||||
if(n->longop + n->longdesc + 5 > cols){
|
||||
cols = n->longop + n->longdesc + 5;
|
||||
@ -32,7 +32,7 @@ ncselector_draw(ncselector* n){
|
||||
// draw a rounded box. the body will blow part or all of the bottom away.
|
||||
int yoff = 0;
|
||||
if(n->title){
|
||||
size_t riserwidth = strlen(n->title) + 4;
|
||||
size_t riserwidth = n->titlecols + 4;
|
||||
int offx = ncplane_align(n->ncp, NCALIGN_RIGHT, riserwidth);
|
||||
ncplane_cursor_move_yx(n->ncp, 0, offx);
|
||||
ncplane_rounded_box_sized(n->ncp, 0, n->boxchannels, 3, riserwidth, 0);
|
||||
@ -49,13 +49,13 @@ ncselector_draw(ncselector* n){
|
||||
ncplane_rounded_box_sized(n->ncp, 0, n->boxchannels, dimy - yoff, bodywidth, 0);
|
||||
if(n->secondary){
|
||||
// FIXME move it to the left a bit *iff* there's room to do so
|
||||
int xloc = ncplane_align(n->ncp, NCALIGN_RIGHT, strlen(n->secondary) + 1);
|
||||
int xloc = ncplane_align(n->ncp, NCALIGN_RIGHT, n->secondarycols + 1);
|
||||
n->ncp->channels = n->footchannels;
|
||||
ncplane_putstr_yx(n->ncp, yoff, xloc, n->secondary);
|
||||
}
|
||||
if(n->footer){
|
||||
// FIXME move it to the left a bit *iff* there's room to do so
|
||||
int xloc = ncplane_align(n->ncp, NCALIGN_RIGHT, strlen(n->footer) + 2);
|
||||
int xloc = ncplane_align(n->ncp, NCALIGN_RIGHT, n->footercols + 2);
|
||||
n->ncp->channels = n->footchannels;
|
||||
ncplane_putstr_yx(n->ncp, dimy - 1, xloc, n->footer);
|
||||
}
|
||||
@ -108,8 +108,8 @@ ncselector_dim_yx(notcurses* nc, const ncselector* n, int* ncdimy, int* ncdimx){
|
||||
*ncdimy = rows;
|
||||
cols = ncselector_body_width(n);
|
||||
// the riser, if it exists, is header + 4. the cols are the max of these two.
|
||||
if(n->title && strlen(n->title) + 4 > (size_t)cols){
|
||||
cols = strlen(n->title) + 4;
|
||||
if(n->titlecols + 4 > cols){
|
||||
cols = n->titlecols + 4;
|
||||
}
|
||||
if(cols > dimx){ // insufficient width to display selector
|
||||
return -1;
|
||||
@ -124,8 +124,11 @@ ncselector* ncselector_create(ncplane* n, int y, int x, const selector_options*
|
||||
}
|
||||
ncselector* ns = malloc(sizeof(*ns));
|
||||
ns->title = opts->title ? strdup(opts->title) : NULL;
|
||||
ns->titlecols = opts->title ? mbswidth(opts->title) : 0;
|
||||
ns->secondary = opts->secondary ? strdup(opts->secondary) : NULL;
|
||||
ns->secondarycols = opts->secondary ? mbswidth(opts->secondary) : 0;
|
||||
ns->footer = opts->footer ? strdup(opts->footer) : NULL;
|
||||
ns->footercols = opts->footer ? mbswidth(opts->footer) : 0;
|
||||
ns->selected = opts->defidx;
|
||||
ns->startdisp = opts->defidx >= opts->maxdisplay ? opts->defidx - opts->maxdisplay + 1 : 0;
|
||||
ns->longop = 0;
|
||||
@ -148,11 +151,11 @@ ncselector* ncselector_create(ncplane* n, int y, int x, const selector_options*
|
||||
}
|
||||
for(ns->itemcount = 0 ; ns->itemcount < opts->itemcount ; ++ns->itemcount){
|
||||
const struct selector_item* src = &opts->items[ns->itemcount];
|
||||
if(strlen(src->option) > ns->longop){
|
||||
ns->longop = strlen(src->option);
|
||||
if(mbswidth(src->option) > ns->longop){
|
||||
ns->longop = mbswidth(src->option);
|
||||
}
|
||||
if(strlen(src->desc) > ns->longdesc){
|
||||
ns->longdesc = strlen(src->desc);
|
||||
if(mbswidth(src->desc) > ns->longdesc){
|
||||
ns->longdesc = mbswidth(src->desc);
|
||||
}
|
||||
ns->items[ns->itemcount].option = strdup(src->option);
|
||||
ns->items[ns->itemcount].desc = strdup(src->desc);
|
||||
|
@ -12,7 +12,7 @@ static struct selector_item items[] = {
|
||||
{ "five", "golden rings", },
|
||||
{ "666", "now it is time for me to REIGN IN BLOOD", },
|
||||
{ "7seven7", "this monkey's gone to heaven", },
|
||||
{ "8 8 8", "the chinese love me, i'm told", },
|
||||
{ "8 8 8", "the chinese 平仮名平平仮名仮名love me, i'm told", },
|
||||
{ "nine", "nine, nine, nine 'cause you left me", },
|
||||
{ "ten", "stunning and brave", },
|
||||
};
|
||||
|
16
src/poc/wcwidth.c
Normal file
16
src/poc/wcwidth.c
Normal file
@ -0,0 +1,16 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <locale.h>
|
||||
#include <wchar.h>
|
||||
|
||||
int main(void){
|
||||
if(!setlocale(LC_ALL, "")){
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
for(int i = 0 ; i < 128 ; ++i){
|
||||
wchar_t w = i;
|
||||
printf("width('%02x'): %d\t", i, wcwidth(w));
|
||||
}
|
||||
printf("\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -79,9 +79,9 @@ TEST_CASE("SelectorTest") {
|
||||
|
||||
SUBCASE("PopulatedSelector") {
|
||||
selector_item items[] = {
|
||||
{ strdup("op1"), strdup("this is option 1"), },
|
||||
{ strdup("2ndop"), strdup("this is option #2"), },
|
||||
{ strdup("tres"), strdup("option the third"), },
|
||||
{ strdup("op1"), strdup("this is option 1"), 0, 0, },
|
||||
{ strdup("2ndop"), strdup("this is option #2"), 0, 0, },
|
||||
{ strdup("tres"), strdup("option the third"), 0, 0, },
|
||||
};
|
||||
struct selector_options opts{};
|
||||
opts.items = items;
|
||||
@ -116,9 +116,9 @@ TEST_CASE("SelectorTest") {
|
||||
|
||||
SUBCASE("SelectorMovement") {
|
||||
selector_item items[] = {
|
||||
{ strdup("op1"), strdup("this is option 1"), },
|
||||
{ strdup("2ndop"), strdup("this is option #2"), },
|
||||
{ strdup("tres"), strdup("option the third"), },
|
||||
{ strdup("op1"), strdup("this is option 1"), 0, 0, },
|
||||
{ strdup("2ndop"), strdup("this is option #2"), 0, 0, },
|
||||
{ strdup("tres"), strdup("option the third"), 0, 0, },
|
||||
};
|
||||
struct selector_options opts{};
|
||||
opts.items = items;
|
||||
@ -158,9 +158,9 @@ TEST_CASE("SelectorTest") {
|
||||
// Provide three items, limited to 1 shown at a time
|
||||
SUBCASE("ScrollingSelectorOne") {
|
||||
selector_item items[] = {
|
||||
{ strdup("op1"), strdup("this is option 1"), },
|
||||
{ strdup("2ndop"), strdup("this is option #2"), },
|
||||
{ strdup("tres"), strdup("option the third"), },
|
||||
{ strdup("op1"), strdup("this is option 1"), 0, 0, },
|
||||
{ strdup("2ndop"), strdup("this is option #2"), 0, 0, },
|
||||
{ strdup("tres"), strdup("option the third"), 0, 0, },
|
||||
};
|
||||
struct selector_options opts{};
|
||||
opts.maxdisplay = 1;
|
||||
@ -206,9 +206,9 @@ TEST_CASE("SelectorTest") {
|
||||
// Provide three items, limited to 2 shown at a time
|
||||
SUBCASE("ScrollingSelectorTwo") {
|
||||
selector_item items[] = {
|
||||
{ strdup("op1"), strdup("this is option 1"), },
|
||||
{ strdup("2ndop"), strdup("this is option #2"), },
|
||||
{ strdup("tres"), strdup("option the third"), },
|
||||
{ strdup("op1"), strdup("this is option 1"), 0, 0, },
|
||||
{ strdup("2ndop"), strdup("this is option #2"), 0, 0, },
|
||||
{ strdup("tres"), strdup("option the third"), 0, 0, },
|
||||
};
|
||||
struct selector_options opts{};
|
||||
opts.maxdisplay = 2;
|
||||
|
Loading…
Reference in New Issue
Block a user