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 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
);
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
));
336 co
->destroyCallback
= NULL
;
347 ct
->userHasSetWidth
= 0;
349 ct
->firstItem
= NULL
;
356 ct
->seq
= strdup(seq
);
358 ct
->seq
= strdup(" *");
359 if (flags
& NEWT_FLAG_SCROLL
) {
360 ct
->sb
= newtVerticalScrollbar(left
, top
, height
,
361 COLORSET_LISTBOX
, COLORSET_ACTLISTBOX
);
371 static void ctMapped(newtComponent co
, int isMapped
) {
372 struct CheckboxTree
* ct
= co
->data
;
374 co
->isMapped
= isMapped
;
376 ct
->sb
->ops
->mapped(ct
->sb
, isMapped
);
379 static void ctPlace(newtComponent co
, int newLeft
, int newTop
) {
380 struct CheckboxTree
* ct
= co
->data
;
386 ct
->sb
->ops
->place(ct
->sb
, co
->left
+ co
->width
- 1, co
->top
);
389 int ctSetItem(newtComponent co
, struct items
*item
, enum newtFlagsSense sense
)
391 struct CheckboxTree
* ct
= co
->data
;
392 struct items
* currItem
;
393 struct items
* firstItem
;
399 case NEWT_FLAGS_RESET
:
405 case NEWT_FLAGS_TOGGLE
:
407 item
->selected
= !item
->selected
;
408 else if (!(ct
->flags
& NEWT_CHECKBOXTREE_UNSELECTABLE
)) {
410 if (item
->selected
==strlen(ct
->seq
))
417 currItem
= *ct
->currItem
;
418 firstItem
= *ct
->firstItem
;
422 ct
->currItem
= ct
->flatList
;
423 while (*ct
->currItem
!= currItem
) ct
->currItem
++;
425 ct
->firstItem
= ct
->flatList
;
426 if (ct
->flatCount
> co
->height
) {
427 struct items
** last
= ct
->flatList
+ ct
->flatCount
- co
->height
;
428 while (*ct
->firstItem
!= firstItem
&& ct
->firstItem
!= last
)
436 static void ctSetItems(struct items
*item
, int selected
)
438 for (; item
; item
= item
->next
) {
440 item
->selected
= selected
;
442 ctSetItems(item
->branch
, selected
);
446 static void ctDraw(newtComponent co
) {
447 struct CheckboxTree
* ct
= co
->data
;
448 struct items
** item
;
451 int currRow
= co
->top
;
453 if (!co
->isMapped
) return ;
455 if (!ct
->firstItem
) {
457 ct
->firstItem
= ct
->currItem
= ct
->flatList
;
460 item
= ct
->firstItem
;
466 while (*item
&& i
< co
->height
) {
467 newtGotorc(co
->top
+ i
, co
->left
);
468 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
469 for (j
= 0; j
< (*item
)->depth
; j
++)
470 SLsmg_write_string(" ");
472 if ((*item
)->branch
) {
473 if ((*item
)->selected
)
474 SLsmg_write_string("<-> ");
476 SLsmg_write_string("<+> ");
478 if (ct
->flags
& NEWT_CHECKBOXTREE_HIDE_BOX
) {
479 if ((*item
)->selected
)
480 SLsmg_set_color(NEWT_COLORSET_SELLISTBOX
);
481 SLsmg_write_string(" ");
484 snprintf(tmp
,5,"[%c] ",ct
->seq
[(*item
)->selected
]);
485 SLsmg_write_string(tmp
);
488 if (*item
== *ct
->currItem
) {
489 SLsmg_set_color(ct
->isActive
?
490 NEWT_COLORSET_ACTSELLISTBOX
: NEWT_COLORSET_ACTLISTBOX
);
491 currRow
= co
->top
+ i
;
494 j
= 4 + (3 * (*item
)->depth
);
495 SLsmg_write_nstring(NULL
, co
->width
- j
);
496 newtGotorc(co
->top
+ i
, co
->left
+ j
);
497 if (wstrlen((*item
)->text
, -1) > co
->width
- j
) {
499 tmp
= strdup((*item
)->text
);
500 trim_string(tmp
, co
->width
- j
);
501 SLsmg_write_string(tmp
);
504 SLsmg_write_string((*item
)->text
);
510 /* There could be empty lines left (i.e. if the user closes an expanded
511 list which is the last thing in the tree, and whose elements are
512 displayed at the bottom of the screen */
513 if (i
< co
->height
) {
514 spaces
= alloca(co
->width
);
515 memset(spaces
, ' ', co
->width
);
516 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
518 while (i
< co
->height
) {
519 newtGotorc(co
->top
+ i
, co
->left
);
520 SLsmg_write_nstring(spaces
, co
->width
);
526 newtScrollbarSet(ct
->sb
, ct
->currItem
- ct
->flatList
,
528 ct
->sb
->ops
->draw(ct
->sb
);
531 newtGotorc(currRow
, co
->left
+
532 (*ct
->currItem
? (*ct
->currItem
)->depth
: 0) * 3 + 4);
535 static void destroyItems(struct items
* item
) {
536 struct items
* nextitem
;
538 while (item
!= NULL
) {
539 nextitem
= item
->next
;
542 destroyItems(item
->branch
);
548 static void ctDestroy(newtComponent co
) {
549 struct CheckboxTree
* ct
= co
->data
;
551 destroyItems(ct
->itemlist
);
554 ct
->sb
->ops
->destroy(ct
->sb
);
560 static void ctEnsureLimits( struct CheckboxTree
*ct
) {
561 struct items
**listEnd
= ct
->flatList
+ ct
->flatCount
- 1;
562 if (ct
->firstItem
< ct
->flatList
)
563 ct
->firstItem
= ct
->flatList
;
564 if (ct
->currItem
< ct
->flatList
)
565 ct
->currItem
= ct
->flatList
;
566 if (ct
->firstItem
> listEnd
) {
567 ct
->firstItem
= listEnd
;
568 ct
->currItem
= listEnd
;
572 struct eventResult
ctEvent(newtComponent co
, struct event ev
) {
573 struct CheckboxTree
* ct
= co
->data
;
574 struct eventResult er
;
575 struct items
** listEnd
, ** lastItem
;
578 er
.result
= ER_IGNORED
;
580 if(ev
.when
== EV_EARLY
|| ev
.when
== EV_LATE
) {
587 if (key
== (char) key
&& key
!= ' ') {
588 for (selnum
= 0; ct
->seq
[selnum
]; selnum
++)
589 if (key
== ct
->seq
[selnum
])
591 if (!ct
->seq
[selnum
])
593 case '-': selnum
= 0; break;
595 case '*': selnum
= 1; break;
603 ctSetItem(co
, *ct
->currItem
, NEWT_FLAGS_TOGGLE
);
604 er
.result
= ER_SWALLOWED
;
605 if (!(*ct
->currItem
)->branch
|| (*ct
->currItem
)->selected
)
611 if ((*ct
->currItem
)->branch
) {
612 ctSetItems((*ct
->currItem
)->branch
, selnum
);
613 if (!(*ct
->currItem
)->selected
)
616 (*ct
->currItem
)->selected
= selnum
;
619 er
.result
= ER_SWALLOWED
;
625 if(co
->callback
) co
->callback(co
, co
->callbackData
);
628 ct
->currItem
= ct
->flatList
;
629 ct
->firstItem
= ct
->flatList
;
631 if(co
->callback
) co
->callback(co
, co
->callbackData
);
632 er
.result
= ER_SWALLOWED
;
635 ct
->currItem
= ct
->flatList
+ ct
->flatCount
- 1;
636 if (ct
->flatCount
<= co
->height
)
637 ct
->firstItem
= ct
->flatList
;
639 ct
->firstItem
= ct
->flatList
+ ct
->flatCount
- co
->height
;
641 if(co
->callback
) co
->callback(co
, co
->callbackData
);
642 er
.result
= ER_SWALLOWED
;
645 if (ev
.u
.key
!= NEWT_KEY_DOWN
) {
646 if(co
->callback
) co
->callback(co
, co
->callbackData
);
647 if (strlen(ct
->seq
) != 2) {
652 if ((ct
->currItem
- ct
->flatList
+ 1) < ct
->flatCount
) {
655 if (ct
->currItem
- ct
->firstItem
>= co
->height
)
659 } else if (ev
.u
.key
!= NEWT_KEY_DOWN
)
661 if(co
->callback
) co
->callback(co
, co
->callbackData
);
662 er
.result
= ER_SWALLOWED
;
665 if (ct
->currItem
!= ct
->flatList
) {
668 if (ct
->currItem
< ct
->firstItem
)
669 ct
->firstItem
= ct
->currItem
;
673 er
.result
= ER_SWALLOWED
;
674 if(co
->callback
) co
->callback(co
, co
->callbackData
);
677 if (ct
->firstItem
- co
->height
< ct
->flatList
) {
678 ct
->firstItem
= ct
->currItem
= ct
->flatList
;
680 ct
->currItem
-= co
->height
;
681 ct
->firstItem
-= co
->height
;
683 ctEnsureLimits( ct
);
686 if(co
->callback
) co
->callback(co
, co
->callbackData
);
687 er
.result
= ER_SWALLOWED
;
690 listEnd
= ct
->flatList
+ ct
->flatCount
- 1;
691 lastItem
= ct
->firstItem
+ co
->height
- 1;
693 if (lastItem
+ co
->height
> listEnd
) {
694 ct
->firstItem
= listEnd
- co
->height
+ 1;
695 ct
->currItem
= listEnd
;
697 ct
->currItem
+= co
->height
;
698 ct
->firstItem
+= co
->height
;
700 ctEnsureLimits( ct
);
703 if(co
->callback
) co
->callback(co
, co
->callbackData
);
704 er
.result
= ER_SWALLOWED
;
712 er
.result
= ER_SWALLOWED
;
718 er
.result
= ER_SWALLOWED
;
727 const void * newtCheckboxTreeGetCurrent(newtComponent co
) {
728 struct CheckboxTree
* ct
= co
->data
;
730 if (!ct
->currItem
) return NULL
;
731 return (*ct
->currItem
)->data
;
734 void newtCheckboxTreeSetEntry(newtComponent co
, const void * data
, const char * text
)
736 struct CheckboxTree
* ct
;
742 item
= findItem(ct
->itemlist
, data
);
746 item
->text
= strdup(text
);
748 i
= 4 + (3 * item
->depth
);
750 width
= wstrlen(text
, -1);
751 if ((ct
->userHasSetWidth
== 0) && ((width
+ i
+ ct
->sbAdjust
) > co
->width
)) {
752 updateWidth(co
, ct
, width
+ i
);
758 char newtCheckboxTreeGetEntryValue(newtComponent co
, const void * data
)
760 struct CheckboxTree
* ct
;
765 item
= findItem(ct
->itemlist
, data
);
766 if (!item
) return -1;
768 return item
->selected
? NEWT_CHECKBOXTREE_EXPANDED
: NEWT_CHECKBOXTREE_COLLAPSED
;
770 return ct
->seq
[item
->selected
];
773 void newtCheckboxTreeSetEntryValue(newtComponent co
, const void * data
, char value
)
775 struct CheckboxTree
* ct
;
781 item
= findItem(ct
->itemlist
, data
);
782 if (!item
|| item
->branch
) return;
784 for(i
= 0; ct
->seq
[i
]; i
++)
785 if (value
== ct
->seq
[i
])
788 if (!ct
->seq
[i
]) return;
795 void newtCheckboxTreeSetCurrent(newtComponent co
, void * data
) {
796 struct CheckboxTree
* ct
= co
->data
;
799 struct items
* treeTop
, * item
;
801 path
= newtCheckboxTreeFindItem(co
, data
);
804 /* traverse the path and turn on all of the branches to this point */
805 for (i
= 0, treeTop
= ct
->itemlist
; path
[i
+ 1] != NEWT_ARG_LAST
; i
++) {
806 for (j
= 0, item
= treeTop
; j
< path
[i
]; j
++)
810 treeTop
= item
->branch
;
816 item
= findItem(ct
->itemlist
, data
);
819 while (ct
->flatList
[i
] != item
) i
++;
821 /* choose the top item */
822 j
= i
- (co
->height
/ 2);
824 if ((j
+ co
->height
) > ct
->flatCount
)
825 j
= ct
->flatCount
- co
->height
;
830 ct
->firstItem
= ct
->flatList
+ j
;
831 ct
->currItem
= ct
->flatList
+ i
;