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 enum countWhat
{ COUNT_EXPOSED
=0, COUNT_SELECTED
=1 };
42 static int countItems(struct items
* item
, enum countWhat justExposed
);
43 static inline void updateWidth(newtComponent co
, struct CheckboxTree
* ct
,
46 static struct componentOps ctOps
= {
54 static inline void updateWidth(newtComponent co
, struct CheckboxTree
* ct
,
56 ct
->curWidth
= maxField
;
57 co
->width
= ct
->curWidth
+ ct
->sbAdjust
;
60 ct
->sb
->left
= co
->left
+ co
->width
- 1;
63 static int countItems(struct items
* item
, enum countWhat what
) {
67 if ((!item
->branch
&& item
->selected
== what
) || (what
== COUNT_EXPOSED
))
69 if (item
->branch
|| (what
== COUNT_EXPOSED
&& 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
, COUNT_EXPOSED
);
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 va_start(argList
, index
);
122 while (i
!= NEWT_ARG_LAST
) {
123 indexes
[numIndexes
++] = i
;
124 i
= va_arg(argList
, int);
128 indexes
[numIndexes
++] = NEWT_ARG_LAST
;
130 return newtCheckboxTreeAddArray(co
, text
, data
, flags
, indexes
);
133 static int doFindItemPath(struct items
* items
, void * data
, int * path
,
138 if (items
->data
== data
) {
139 if (path
) path
[items
->depth
] = where
;
140 if (len
) *len
= items
->depth
+ 1;
144 if (items
->branch
&& doFindItemPath(items
->branch
, data
, path
, len
)) {
145 if (path
) path
[items
->depth
] = where
;
156 int * newtCheckboxTreeFindItem(newtComponent co
, void * data
) {
159 struct CheckboxTree
* ct
= co
->data
;
161 if (!doFindItemPath(ct
->itemlist
, data
, NULL
, &len
)) return NULL
;
163 path
= malloc(sizeof(*path
) * (len
+ 1));
164 doFindItemPath(ct
->itemlist
, data
, path
, NULL
);
165 path
[len
] = NEWT_ARG_LAST
;
170 int newtCheckboxTreeAddArray(newtComponent co
,
171 const char * text
, const void * data
,
172 int flags
, int * indexes
) {
173 struct items
* curList
, * newNode
, * item
= NULL
;
174 struct items
** listPtr
= NULL
;
175 int i
, index
, numIndexes
, width
;
176 struct CheckboxTree
* ct
= co
->data
;
179 while (indexes
[numIndexes
] != NEWT_ARG_LAST
) numIndexes
++;
182 if (numIndexes
> 1) return -1;
184 ct
->itemlist
= malloc(sizeof(*ct
->itemlist
)); // FIXME: Error check?
189 curList
= ct
->itemlist
;
190 listPtr
= &ct
->itemlist
;
194 while (i
< numIndexes
) {
197 if (index
== NEWT_ARG_APPEND
) {
200 while (index
&& item
)
201 item
= item
->next
, index
--;
205 if (i
< numIndexes
) {
206 curList
= item
->branch
;
207 listPtr
= &item
->branch
;
208 if (!curList
&& (i
+ 1 != numIndexes
)) return -1;
214 if (!curList
) { /* create a new branch */
215 item
= malloc(sizeof(*curList
->prev
));
216 item
->next
= item
->prev
= NULL
;
218 } else if (!item
) { /* append to end */
220 while (item
->next
) item
= item
->next
;
221 item
->next
= malloc(sizeof(*curList
->prev
)); // FIXME Error check
222 item
->next
->prev
= item
;
226 newNode
= malloc(sizeof(*newNode
)); // FIXME Error check ?
227 newNode
->prev
= item
->prev
;
228 newNode
->next
= item
;
230 if (item
->prev
) item
->prev
->next
= newNode
;
231 item
->prev
= newNode
;
233 if (!item
->prev
) *listPtr
= item
;
237 item
->text
= strdup(text
);
239 if (flags
& NEWT_FLAG_SELECTED
) {
246 item
->depth
= numIndexes
- 1;
248 i
= 4 + (3 * item
->depth
);
249 width
= wstrlen(text
, -1);
251 if ((ct
->userHasSetWidth
== 0) && ((width
+ i
+ ct
->sbAdjust
) > co
->width
)) {
252 updateWidth(co
, ct
, width
+ i
);
258 static struct items
* findItem(struct items
* items
, const void * data
) {
262 if (items
->data
== data
) return items
;
264 i
= findItem(items
->branch
, data
);
274 static void listSelected(struct items
* items
, int * num
, const void ** list
, int seqindex
) {
276 if ((seqindex
? items
->selected
==seqindex
: items
->selected
) && !items
->branch
)
277 list
[(*num
)++] = (void *) items
->data
;
279 listSelected(items
->branch
, num
, list
, seqindex
);
284 void newtCheckboxTreeSetWidth(newtComponent co
, int width
) {
285 struct CheckboxTree
* ct
= co
->data
;
288 ct
->curWidth
= co
->width
- ct
->sbAdjust
;
289 ct
->userHasSetWidth
= 1;
290 if (ct
->sb
) ct
->sb
->left
= co
->width
+ co
->left
- 1;
294 const void ** newtCheckboxTreeGetSelection(newtComponent co
, int *numitems
)
296 return newtCheckboxTreeGetMultiSelection(co
, numitems
, 0);
299 const void ** newtCheckboxTreeGetMultiSelection(newtComponent co
, int *numitems
, char seqnum
)
301 struct CheckboxTree
* ct
;
305 if(!co
|| !numitems
) return NULL
;
310 while( ct
->seq
[seqindex
] && ( ct
->seq
[seqindex
] != seqnum
)) seqindex
++;
315 *numitems
= countItems(ct
->itemlist
, (seqindex
? seqindex
: COUNT_SELECTED
));
316 if (!*numitems
) return NULL
;
318 retval
= malloc(*numitems
* sizeof(void *));
320 listSelected(ct
->itemlist
, numitems
, retval
, seqindex
);
325 newtComponent
newtCheckboxTree(int left
, int top
, int height
, int flags
) {
326 return newtCheckboxTreeMulti(left
, top
, height
, NULL
, flags
);
329 newtComponent
newtCheckboxTreeMulti(int left
, int top
, int height
, char *seq
, int flags
) {
331 struct CheckboxTree
* ct
;
333 co
= malloc(sizeof(*co
));
334 ct
= malloc(sizeof(struct CheckboxTree
));
346 ct
->userHasSetWidth
= 0;
348 ct
->firstItem
= NULL
;
355 ct
->seq
= strdup(seq
);
357 ct
->seq
= strdup(" *");
358 if (flags
& NEWT_FLAG_SCROLL
) {
359 ct
->sb
= newtVerticalScrollbar(left
, top
, height
,
360 COLORSET_LISTBOX
, COLORSET_ACTLISTBOX
);
370 static void ctMapped(newtComponent co
, int isMapped
) {
371 struct CheckboxTree
* ct
= co
->data
;
373 co
->isMapped
= isMapped
;
375 ct
->sb
->ops
->mapped(ct
->sb
, isMapped
);
378 static void ctPlace(newtComponent co
, int newLeft
, int newTop
) {
379 struct CheckboxTree
* ct
= co
->data
;
385 ct
->sb
->ops
->place(ct
->sb
, co
->left
+ co
->width
- 1, co
->top
);
388 int ctSetItem(newtComponent co
, struct items
*item
, enum newtFlagsSense sense
)
390 struct CheckboxTree
* ct
= co
->data
;
391 struct items
* currItem
;
392 struct items
* firstItem
;
398 case NEWT_FLAGS_RESET
:
404 case NEWT_FLAGS_TOGGLE
:
406 item
->selected
= !item
->selected
;
407 else if (!(ct
->flags
& NEWT_CHECKBOXTREE_UNSELECTABLE
)) {
409 if (item
->selected
==strlen(ct
->seq
))
416 currItem
= *ct
->currItem
;
417 firstItem
= *ct
->firstItem
;
421 ct
->currItem
= ct
->flatList
;
422 while (*ct
->currItem
!= currItem
) ct
->currItem
++;
424 ct
->firstItem
= ct
->flatList
;
425 if (ct
->flatCount
> co
->height
) {
426 struct items
** last
= ct
->flatList
+ ct
->flatCount
- co
->height
;
427 while (*ct
->firstItem
!= firstItem
&& ct
->firstItem
!= last
)
435 static void ctSetItems(struct items
*item
, int selected
)
437 for (; item
; item
= item
->next
) {
439 item
->selected
= selected
;
441 ctSetItems(item
->branch
, selected
);
445 static void ctDraw(newtComponent co
) {
446 struct CheckboxTree
* ct
= co
->data
;
447 struct items
** item
;
452 if (!co
->isMapped
) return ;
454 if (!ct
->firstItem
) {
456 ct
->firstItem
= ct
->currItem
= ct
->flatList
;
459 item
= ct
->firstItem
;
465 while (*item
&& i
< co
->height
) {
466 newtGotorc(co
->top
+ i
, co
->left
);
467 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
468 for (j
= 0; j
< (*item
)->depth
; j
++)
469 SLsmg_write_string(" ");
471 if ((*item
)->branch
) {
472 if ((*item
)->selected
)
473 SLsmg_write_string("<-> ");
475 SLsmg_write_string("<+> ");
477 if (ct
->flags
& NEWT_CHECKBOXTREE_HIDE_BOX
) {
478 if ((*item
)->selected
)
479 SLsmg_set_color(NEWT_COLORSET_SELLISTBOX
);
480 SLsmg_write_string(" ");
483 snprintf(tmp
,5,"[%c] ",ct
->seq
[(*item
)->selected
]);
484 SLsmg_write_string(tmp
);
487 if (*item
== *ct
->currItem
) {
488 SLsmg_set_color(ct
->isActive
?
489 NEWT_COLORSET_ACTSELLISTBOX
: NEWT_COLORSET_ACTLISTBOX
);
490 currRow
= co
->top
+ i
;
493 SLsmg_write_nstring((*item
)->text
, co
->width
- 4 -
494 (3 * (*item
)->depth
));
500 /* There could be empty lines left (i.e. if the user closes an expanded
501 list which is the last thing in the tree, and whose elements are
502 displayed at the bottom of the screen */
503 if (i
< co
->height
) {
504 spaces
= alloca(co
->width
);
505 memset(spaces
, ' ', co
->width
);
506 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
508 while (i
< co
->height
) {
509 newtGotorc(co
->top
+ i
, co
->left
);
510 SLsmg_write_nstring(spaces
, co
->width
);
515 newtScrollbarSet(ct
->sb
, ct
->currItem
- ct
->flatList
,
517 ct
->sb
->ops
->draw(ct
->sb
);
520 newtGotorc(currRow
, co
->left
+ 1);
523 static void ctDestroy(newtComponent co
) {
524 struct CheckboxTree
* ct
= co
->data
;
525 struct items
* item
, * nextitem
;
527 nextitem
= item
= ct
->itemlist
;
529 while (item
!= NULL
) {
530 nextitem
= item
->next
;
541 static void ctEnsureLimits( struct CheckboxTree
*ct
) {
542 struct items
**listEnd
= ct
->flatList
+ ct
->flatCount
- 1;
543 if (ct
->firstItem
< ct
->flatList
)
544 ct
->firstItem
= ct
->flatList
;
545 if (ct
->currItem
< ct
->flatList
)
546 ct
->currItem
= ct
->flatList
;
547 if (ct
->firstItem
> listEnd
) {
548 ct
->firstItem
= listEnd
;
549 ct
->currItem
= listEnd
;
553 struct eventResult
ctEvent(newtComponent co
, struct event ev
) {
554 struct CheckboxTree
* ct
= co
->data
;
555 struct eventResult er
;
556 struct items
** listEnd
, ** lastItem
;
559 er
.result
= ER_IGNORED
;
561 if(ev
.when
== EV_EARLY
|| ev
.when
== EV_LATE
) {
568 if (key
== (char) key
&& key
!= ' ') {
569 for (selnum
= 0; ct
->seq
[selnum
]; selnum
++)
570 if (key
== ct
->seq
[selnum
])
572 if (!ct
->seq
[selnum
])
574 case '-': selnum
= 0; break;
576 case '*': selnum
= 1; break;
584 ctSetItem(co
, *ct
->currItem
, NEWT_FLAGS_TOGGLE
);
585 er
.result
= ER_SWALLOWED
;
586 if (!(*ct
->currItem
)->branch
|| (*ct
->currItem
)->selected
)
592 if ((*ct
->currItem
)->branch
) {
593 ctSetItems((*ct
->currItem
)->branch
, selnum
);
594 if (!(*ct
->currItem
)->selected
)
597 (*ct
->currItem
)->selected
= selnum
;
600 er
.result
= ER_SWALLOWED
;
606 if(co
->callback
) co
->callback(co
, co
->callbackData
);
609 ct
->currItem
= ct
->flatList
;
610 ct
->firstItem
= ct
->flatList
;
612 if(co
->callback
) co
->callback(co
, co
->callbackData
);
613 er
.result
= ER_SWALLOWED
;
616 ct
->currItem
= ct
->flatList
+ ct
->flatCount
- 1;
617 if (ct
->flatCount
<= co
->height
)
618 ct
->firstItem
= ct
->flatList
;
620 ct
->firstItem
= ct
->flatList
+ ct
->flatCount
- co
->height
;
622 if(co
->callback
) co
->callback(co
, co
->callbackData
);
623 er
.result
= ER_SWALLOWED
;
626 if (ev
.u
.key
!= NEWT_KEY_DOWN
) {
627 if(co
->callback
) co
->callback(co
, co
->callbackData
);
628 if (strlen(ct
->seq
) != 2) {
633 if ((ct
->currItem
- ct
->flatList
+ 1) < ct
->flatCount
) {
636 if (ct
->currItem
- ct
->firstItem
>= co
->height
)
640 } else if (ev
.u
.key
!= NEWT_KEY_DOWN
)
642 if(co
->callback
) co
->callback(co
, co
->callbackData
);
643 er
.result
= ER_SWALLOWED
;
646 if (ct
->currItem
!= ct
->flatList
) {
649 if (ct
->currItem
< ct
->firstItem
)
650 ct
->firstItem
= ct
->currItem
;
654 er
.result
= ER_SWALLOWED
;
655 if(co
->callback
) co
->callback(co
, co
->callbackData
);
658 if (ct
->firstItem
- co
->height
< ct
->flatList
) {
659 ct
->firstItem
= ct
->currItem
= ct
->flatList
;
661 ct
->currItem
-= co
->height
;
662 ct
->firstItem
-= co
->height
;
664 ctEnsureLimits( ct
);
667 if(co
->callback
) co
->callback(co
, co
->callbackData
);
668 er
.result
= ER_SWALLOWED
;
671 listEnd
= ct
->flatList
+ ct
->flatCount
- 1;
672 lastItem
= ct
->firstItem
+ co
->height
- 1;
674 if (lastItem
+ co
->height
> listEnd
) {
675 ct
->firstItem
= listEnd
- co
->height
+ 1;
676 ct
->currItem
= listEnd
;
678 ct
->currItem
+= co
->height
;
679 ct
->firstItem
+= co
->height
;
681 ctEnsureLimits( ct
);
684 if(co
->callback
) co
->callback(co
, co
->callbackData
);
685 er
.result
= ER_SWALLOWED
;
693 er
.result
= ER_SWALLOWED
;
699 er
.result
= ER_SWALLOWED
;
708 const void * newtCheckboxTreeGetCurrent(newtComponent co
) {
709 struct CheckboxTree
* ct
= co
->data
;
711 if (!ct
->currItem
) return NULL
;
712 return (*ct
->currItem
)->data
;
715 void newtCheckboxTreeSetEntry(newtComponent co
, const void * data
, const char * text
)
717 struct CheckboxTree
* ct
;
723 item
= findItem(ct
->itemlist
, data
);
727 item
->text
= strdup(text
);
729 i
= 4 + (3 * item
->depth
);
731 width
= wstrlen(text
, -1);
732 if ((ct
->userHasSetWidth
== 0) && ((width
+ i
+ ct
->sbAdjust
) > co
->width
)) {
733 updateWidth(co
, ct
, width
+ i
);
739 char newtCheckboxTreeGetEntryValue(newtComponent co
, const void * data
)
741 struct CheckboxTree
* ct
;
746 item
= findItem(ct
->itemlist
, data
);
747 if (!item
) return -1;
749 return item
->selected
? NEWT_CHECKBOXTREE_EXPANDED
: NEWT_CHECKBOXTREE_COLLAPSED
;
751 return ct
->seq
[item
->selected
];
754 void newtCheckboxTreeSetEntryValue(newtComponent co
, const void * data
, char value
)
756 struct CheckboxTree
* ct
;
762 item
= findItem(ct
->itemlist
, data
);
763 if (!item
|| item
->branch
) return;
765 for(i
= 0; ct
->seq
[i
]; i
++)
766 if (value
== ct
->seq
[i
])
769 if (!ct
->seq
[i
]) return;
776 void newtCheckboxTreeSetCurrent(newtComponent co
, void * data
) {
777 struct CheckboxTree
* ct
= co
->data
;
780 struct items
* treeTop
, * item
;
782 path
= newtCheckboxTreeFindItem(co
, data
);
785 /* traverse the path and turn on all of the branches to this point */
786 for (i
= 0, treeTop
= ct
->itemlist
; path
[i
+ 1] != NEWT_ARG_LAST
; i
++) {
787 for (j
= 0, item
= treeTop
; j
< path
[i
]; j
++)
791 treeTop
= item
->branch
;
796 item
= findItem(ct
->itemlist
, data
);
799 while (ct
->flatList
[i
] != item
) i
++;
801 /* choose the top item */
802 j
= i
- (co
->height
/ 2);
804 if ((j
+ co
->height
) > ct
->flatCount
)
805 j
= ct
->flatCount
- co
->height
;
810 ct
->firstItem
= ct
->flatList
+ j
;
811 ct
->currItem
= ct
->flatList
+ i
;