11
unsigned char selected;
21
struct items * itemlist;
22
struct items ** flatList, ** currItem, ** firstItem;
33
static void ctDraw(newtComponent c);
34
static void ctDestroy(newtComponent co);
35
static void ctPlace(newtComponent co, int newLeft, int newTop);
36
struct eventResult ctEvent(newtComponent co, struct event ev);
37
static void ctMapped(newtComponent co, int isMapped);
38
static struct items * findItem(struct items * items, const void * data);
39
static void buildFlatList(newtComponent co);
40
static void doBuildFlatList(struct CheckboxTree * ct, struct items * item);
41
static int countItems(struct items * item, int what);
42
static inline void updateWidth(newtComponent co, struct CheckboxTree * ct,
45
static struct componentOps ctOps = {
53
static inline void updateWidth(newtComponent co, struct CheckboxTree * ct,
55
ct->curWidth = maxField;
56
co->width = ct->curWidth + ct->sbAdjust;
59
ct->sb->left = co->left + co->width - 1;
62
static int countItems(struct items * item, int what) {
66
if (what < 0 || (!item->branch && ((what > 0 && item->selected == what)
67
|| (what == 0 && item->selected))))
69
if (item->branch && (what >= 0 || (what < 0 && item->selected)))
70
count += countItems(item->branch, what);
77
static void doBuildFlatList(struct CheckboxTree * ct, struct items * item) {
79
ct->flatList[ct->flatCount++] = item;
80
if (item->branch && item->selected) doBuildFlatList(ct, item->branch);
85
/* FIXME: Check what happens on malloc failure.
87
static void buildFlatList(newtComponent co) {
88
struct CheckboxTree * ct = co->data;
90
if (ct->flatList) free(ct->flatList);
91
ct->flatCount = countItems(ct->itemlist, -1);
93
ct->flatList = malloc(sizeof(*ct->flatList) * (ct->flatCount+1));
95
doBuildFlatList(ct, ct->itemlist);
96
ct->flatList[ct->flatCount] = NULL;
99
int newtCheckboxTreeAddItem(newtComponent co,
100
const char * text, const void * data,
101
int flags, int index, ...) {
107
va_start(argList, index);
110
while (i != NEWT_ARG_LAST) {
112
i = va_arg(argList, int);
117
indexes = alloca(sizeof(*indexes) * (numIndexes + 1));
118
va_start(argList, index);
121
while (i != NEWT_ARG_LAST) {
122
indexes[numIndexes++] = i;
123
i = va_arg(argList, int);
127
indexes[numIndexes++] = NEWT_ARG_LAST;
129
return newtCheckboxTreeAddArray(co, text, data, flags, indexes);
132
static int doFindItemPath(struct items * items, void * data, int * path,
137
if (items->data == data) {
138
if (path) path[items->depth] = where;
139
if (len) *len = items->depth + 1;
143
if (items->branch && doFindItemPath(items->branch, data, path, len)) {
144
if (path) path[items->depth] = where;
155
int * newtCheckboxTreeFindItem(newtComponent co, void * data) {
158
struct CheckboxTree * ct = co->data;
160
if (!doFindItemPath(ct->itemlist, data, NULL, &len)) return NULL;
162
path = malloc(sizeof(*path) * (len + 1));
163
doFindItemPath(ct->itemlist, data, path, NULL);
164
path[len] = NEWT_ARG_LAST;
169
int newtCheckboxTreeAddArray(newtComponent co,
170
const char * text, const void * data,
171
int flags, int * indexes) {
172
struct items * curList, * newNode, * item = NULL;
173
struct items ** listPtr = NULL;
174
int i, index, numIndexes, width;
175
struct CheckboxTree * ct = co->data;
178
while (indexes[numIndexes] != NEWT_ARG_LAST) numIndexes++;
181
if (numIndexes > 1) return -1;
183
ct->itemlist = malloc(sizeof(*ct->itemlist)); // FIXME: Error check?
188
curList = ct->itemlist;
189
listPtr = &ct->itemlist;
193
while (i < numIndexes) {
196
if (index == NEWT_ARG_APPEND) {
199
while (index && item)
200
item = item->next, index--;
204
if (i < numIndexes) {
207
curList = item->branch;
208
listPtr = &item->branch;
209
if (!curList && (i + 1 != numIndexes)) return -1;
215
if (!curList) { /* create a new branch */
216
item = malloc(sizeof(*curList->prev));
217
item->next = item->prev = NULL;
219
} else if (!item) { /* append to end */
221
while (item->next) item = item->next;
222
item->next = malloc(sizeof(*curList->prev)); // FIXME Error check
223
item->next->prev = item;
227
newNode = malloc(sizeof(*newNode)); // FIXME Error check ?
228
newNode->prev = item->prev;
229
newNode->next = item;
231
if (item->prev) item->prev->next = newNode;
232
item->prev = newNode;
234
if (!item->prev) *listPtr = item;
238
item->text = strdup(text);
240
if (flags & NEWT_FLAG_SELECTED) {
247
item->depth = numIndexes - 1;
249
i = 4 + (3 * item->depth);
250
width = wstrlen(text, -1);
252
if ((ct->userHasSetWidth == 0) && ((width + i + ct->sbAdjust) > co->width)) {
253
updateWidth(co, ct, width + i);
259
static struct items * findItem(struct items * items, const void * data) {
263
if (items->data == data) return items;
265
i = findItem(items->branch, data);
275
static void listSelected(struct items * items, int * num, const void ** list, int seqindex) {
277
if ((seqindex ? items->selected==seqindex : items->selected) && !items->branch)
278
list[(*num)++] = (void *) items->data;
280
listSelected(items->branch, num, list, seqindex);
285
void newtCheckboxTreeSetWidth(newtComponent co, int width) {
286
struct CheckboxTree * ct = co->data;
289
ct->curWidth = co->width - ct->sbAdjust;
290
ct->userHasSetWidth = 1;
291
if (ct->sb) ct->sb->left = co->width + co->left - 1;
295
const void ** newtCheckboxTreeGetSelection(newtComponent co, int *numitems)
297
return newtCheckboxTreeGetMultiSelection(co, numitems, 0);
300
const void ** newtCheckboxTreeGetMultiSelection(newtComponent co, int *numitems, char seqnum)
302
struct CheckboxTree * ct;
306
if(!co || !numitems) return NULL;
311
while( ct->seq[seqindex] && ( ct->seq[seqindex] != seqnum )) seqindex++;
316
*numitems = countItems(ct->itemlist, seqindex);
317
if (!*numitems) return NULL;
319
retval = malloc(*numitems * sizeof(void *));
321
listSelected(ct->itemlist, numitems, retval, seqindex);
326
newtComponent newtCheckboxTree(int left, int top, int height, int flags) {
327
return newtCheckboxTreeMulti(left, top, height, NULL, flags);
330
newtComponent newtCheckboxTreeMulti(int left, int top, int height, char *seq, int flags) {
332
struct CheckboxTree * ct;
334
co = malloc(sizeof(*co));
335
ct = malloc(sizeof(struct CheckboxTree));
337
co->destroyCallback = NULL;
348
ct->userHasSetWidth = 0;
350
ct->firstItem = NULL;
357
ct->seq = strdup(seq);
359
ct->seq = strdup(" *");
360
if (flags & NEWT_FLAG_SCROLL) {
361
ct->sb = newtVerticalScrollbar(left, top, height,
362
COLORSET_LISTBOX, COLORSET_ACTLISTBOX);
372
static void ctMapped(newtComponent co, int isMapped) {
373
struct CheckboxTree * ct = co->data;
375
co->isMapped = isMapped;
377
ct->sb->ops->mapped(ct->sb, isMapped);
380
static void ctPlace(newtComponent co, int newLeft, int newTop) {
381
struct CheckboxTree * ct = co->data;
387
ct->sb->ops->place(ct->sb, co->left + co->width - 1, co->top);
390
int ctSetItem(newtComponent co, struct items *item, enum newtFlagsSense sense)
392
struct CheckboxTree * ct = co->data;
393
struct items * currItem;
394
struct items * firstItem;
400
case NEWT_FLAGS_RESET:
406
case NEWT_FLAGS_TOGGLE:
408
item->selected = !item->selected;
409
else if (!(ct->flags & NEWT_CHECKBOXTREE_UNSELECTABLE)) {
411
if (item->selected==strlen(ct->seq))
418
currItem = *ct->currItem;
419
firstItem = *ct->firstItem;
423
ct->currItem = ct->flatList;
424
while (*ct->currItem != currItem) ct->currItem++;
426
ct->firstItem = ct->flatList;
427
if (ct->flatCount > co->height) {
428
struct items ** last = ct->flatList + ct->flatCount - co->height;
429
while (*ct->firstItem != firstItem && ct->firstItem != last)
437
static void ctSetItems(struct items *item, int selected)
439
for (; item; item = item->next) {
441
item->selected = selected;
443
ctSetItems(item->branch, selected);
447
static void ctDraw(newtComponent co) {
448
struct CheckboxTree * ct = co->data;
449
struct items ** item;
452
int currRow = co->top;
454
if (!co->isMapped) return ;
456
if (!ct->firstItem) {
458
ct->firstItem = ct->currItem = ct->flatList;
461
item = ct->firstItem;
467
while (*item && i < co->height) {
468
newtGotorc(co->top + i, co->left);
469
SLsmg_set_color(NEWT_COLORSET_LISTBOX);
470
for (j = 0; j < (*item)->depth; j++)
471
SLsmg_write_string(" ");
473
if ((*item)->branch) {
474
if ((*item)->selected)
475
SLsmg_write_string("<-> ");
477
SLsmg_write_string("<+> ");
479
if (ct->flags & NEWT_CHECKBOXTREE_HIDE_BOX) {
480
if ((*item)->selected)
481
SLsmg_set_color(NEWT_COLORSET_SELLISTBOX);
482
SLsmg_write_string(" ");
485
snprintf(tmp,5,"[%c] ",ct->seq[(*item)->selected]);
486
SLsmg_write_string(tmp);
489
if (*item == *ct->currItem) {
490
SLsmg_set_color(ct->isActive ?
491
NEWT_COLORSET_ACTSELLISTBOX : NEWT_COLORSET_ACTLISTBOX);
492
currRow = co->top + i;
495
write_nstring_int((*item)->text, co->width - 4 - (3 * (*item)->depth), NULL);
501
/* There could be empty lines left (i.e. if the user closes an expanded
502
list which is the last thing in the tree, and whose elements are
503
displayed at the bottom of the screen */
504
if (i < co->height) {
505
spaces = alloca(co->width + 1);
506
memset(spaces, ' ', co->width);
507
spaces[co->width] = '\0';
508
SLsmg_set_color(NEWT_COLORSET_LISTBOX);
510
while (i < co->height) {
511
newtGotorc(co->top + i, co->left);
512
SLsmg_write_nstring(spaces, co->width);
518
newtScrollbarSet(ct->sb, ct->currItem - ct->flatList,
520
ct->sb->ops->draw(ct->sb);
523
newtGotorc(currRow, co->left +
524
(*ct->currItem ? (*ct->currItem)->depth : 0) * 3 + 4);
527
static void destroyItems(struct items * item) {
528
struct items * nextitem;
530
while (item != NULL) {
531
nextitem = item->next;
534
destroyItems(item->branch);
540
static void ctDestroy(newtComponent co) {
541
struct CheckboxTree * ct = co->data;
543
destroyItems(ct->itemlist);
546
ct->sb->ops->destroy(ct->sb);
552
static void ctEnsureLimits( struct CheckboxTree *ct ) {
553
struct items **listEnd = ct->flatList + ct->flatCount - 1;
554
if (ct->firstItem < ct->flatList)
555
ct->firstItem = ct->flatList;
556
if (ct->currItem < ct->flatList)
557
ct->currItem = ct->flatList;
558
if (ct->firstItem > listEnd) {
559
ct->firstItem = listEnd;
560
ct->currItem = listEnd;
564
struct eventResult ctEvent(newtComponent co, struct event ev) {
565
struct CheckboxTree * ct = co->data;
566
struct eventResult er;
567
struct items ** listEnd, ** lastItem;
570
er.result = ER_IGNORED;
572
if(ev.when == EV_EARLY || ev.when == EV_LATE) {
579
if (key == (char) key && key != ' ') {
580
for (selnum = 0; ct->seq[selnum]; selnum++)
581
if (key == ct->seq[selnum])
583
if (!ct->seq[selnum])
585
case '-': selnum = 0; break;
587
case '*': selnum = 1; break;
595
ctSetItem(co, *ct->currItem, NEWT_FLAGS_TOGGLE);
596
er.result = ER_SWALLOWED;
597
if (!(*ct->currItem)->branch || (*ct->currItem)->selected)
603
if ((*ct->currItem)->branch) {
604
ctSetItems((*ct->currItem)->branch, selnum);
605
if (!(*ct->currItem)->selected)
608
(*ct->currItem)->selected = selnum;
611
er.result = ER_SWALLOWED;
617
if(co->callback) co->callback(co, co->callbackData);
620
ct->currItem = ct->flatList;
621
ct->firstItem = ct->flatList;
623
if(co->callback) co->callback(co, co->callbackData);
624
er.result = ER_SWALLOWED;
627
ct->currItem = ct->flatList + ct->flatCount - 1;
628
if (ct->flatCount <= co->height)
629
ct->firstItem = ct->flatList;
631
ct->firstItem = ct->flatList + ct->flatCount - co->height;
633
if(co->callback) co->callback(co, co->callbackData);
634
er.result = ER_SWALLOWED;
637
if (ev.u.key != NEWT_KEY_DOWN) {
638
if(co->callback) co->callback(co, co->callbackData);
639
if (strlen(ct->seq) != 2) {
644
if ((ct->currItem - ct->flatList + 1) < ct->flatCount) {
647
if (ct->currItem - ct->firstItem >= co->height)
651
} else if (ev.u.key != NEWT_KEY_DOWN)
653
if(co->callback) co->callback(co, co->callbackData);
654
er.result = ER_SWALLOWED;
657
if (ct->currItem != ct->flatList) {
660
if (ct->currItem < ct->firstItem)
661
ct->firstItem = ct->currItem;
665
er.result = ER_SWALLOWED;
666
if(co->callback) co->callback(co, co->callbackData);
669
if (ct->firstItem - co->height < ct->flatList) {
670
ct->firstItem = ct->currItem = ct->flatList;
672
ct->currItem -= co->height;
673
ct->firstItem -= co->height;
675
ctEnsureLimits( ct );
678
if(co->callback) co->callback(co, co->callbackData);
679
er.result = ER_SWALLOWED;
682
listEnd = ct->flatList + ct->flatCount - 1;
683
lastItem = ct->firstItem + co->height - 1;
685
if (lastItem + co->height > listEnd) {
686
ct->firstItem = listEnd - co->height + 1;
687
ct->currItem = listEnd;
689
ct->currItem += co->height;
690
ct->firstItem += co->height;
692
ctEnsureLimits( ct );
695
if(co->callback) co->callback(co, co->callbackData);
696
er.result = ER_SWALLOWED;
704
er.result = ER_SWALLOWED;
710
er.result = ER_SWALLOWED;
719
const void * newtCheckboxTreeGetCurrent(newtComponent co) {
720
struct CheckboxTree * ct = co->data;
724
return ct->itemlist->data;
729
return (*ct->currItem)->data;
732
void newtCheckboxTreeSetEntry(newtComponent co, const void * data, const char * text)
734
struct CheckboxTree * ct;
740
item = findItem(ct->itemlist, data);
744
item->text = strdup(text);
746
i = 4 + (3 * item->depth);
748
width = wstrlen(text, -1);
749
if ((ct->userHasSetWidth == 0) && ((width + i + ct->sbAdjust) > co->width)) {
750
updateWidth(co, ct, width + i);
756
char newtCheckboxTreeGetEntryValue(newtComponent co, const void * data)
758
struct CheckboxTree * ct;
763
item = findItem(ct->itemlist, data);
764
if (!item) return -1;
766
return item->selected ? NEWT_CHECKBOXTREE_EXPANDED : NEWT_CHECKBOXTREE_COLLAPSED;
768
return ct->seq[item->selected];
771
void newtCheckboxTreeSetEntryValue(newtComponent co, const void * data, char value)
773
struct CheckboxTree * ct;
779
item = findItem(ct->itemlist, data);
780
if (!item || item->branch) return;
782
for(i = 0; ct->seq[i]; i++)
783
if (value == ct->seq[i])
786
if (!ct->seq[i]) return;
793
void newtCheckboxTreeSetCurrent(newtComponent co, void * data) {
794
struct CheckboxTree * ct = co->data;
797
struct items * treeTop, * item;
799
path = newtCheckboxTreeFindItem(co, data);
802
/* traverse the path and turn on all of the branches to this point */
803
for (i = 0, treeTop = ct->itemlist; path[i + 1] != NEWT_ARG_LAST; i++) {
804
for (j = 0, item = treeTop; j < path[i]; j++)
808
treeTop = item->branch;
814
item = findItem(ct->itemlist, data);
817
while (ct->flatList[i] != item) i++;
819
/* choose the top item */
820
j = i - (co->height / 2);
822
if ((j + co->height) > ct->flatCount)
823
j = ct->flatCount - co->height;
828
ct->firstItem = ct->flatList + j;
829
ct->currItem = ct->flatList + i;