11 unsigned char selected
;
21 struct items
* itemlist
;
22 struct items
** flatList
, ** currItem
, ** firstItem
;
32 static void ctDraw(newtComponent c
);
33 static void ctDestroy(newtComponent co
);
34 static void ctPlace(newtComponent co
, int newLeft
, int newTop
);
35 struct eventResult
ctEvent(newtComponent co
, struct event ev
);
36 static void ctMapped(newtComponent co
, int isMapped
);
37 static struct items
* findItem(struct items
* items
, const void * data
);
38 static void buildFlatList(newtComponent co
);
39 static void doBuildFlatList(struct CheckboxTree
* ct
, struct items
* item
);
40 enum countWhat
{ COUNT_EXPOSED
=0, COUNT_SELECTED
=1 };
41 static int countItems(struct items
* item
, enum countWhat justExposed
);
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
, enum countWhat what
) {
66 if ((!item
->branch
&& item
->selected
== what
) || (what
== COUNT_EXPOSED
))
68 if (item
->branch
|| (what
== COUNT_EXPOSED
&& item
->selected
))
69 count
+= countItems(item
->branch
, what
);
76 static void doBuildFlatList(struct CheckboxTree
* ct
, struct items
* item
) {
78 ct
->flatList
[ct
->flatCount
++] = item
;
79 if (item
->branch
&& item
->selected
) doBuildFlatList(ct
, item
->branch
);
84 static void buildFlatList(newtComponent co
) {
85 struct CheckboxTree
* ct
= co
->data
;
87 if (ct
->flatList
) free(ct
->flatList
);
88 ct
->flatCount
= countItems(ct
->itemlist
, COUNT_EXPOSED
);
90 ct
->flatList
= malloc(sizeof(*ct
->flatList
) * (ct
->flatCount
+1));
92 doBuildFlatList(ct
, ct
->itemlist
);
93 ct
->flatList
[ct
->flatCount
] = NULL
;
96 int newtCheckboxTreeAddItem(newtComponent co
,
97 const char * text
, const void * data
,
98 int flags
, int index
, ...) {
104 va_start(argList
, index
);
107 while (i
!= NEWT_ARG_LAST
) {
109 i
= va_arg(argList
, int);
114 indexes
= alloca(sizeof(*indexes
) * (numIndexes
+ 1));
115 va_start(argList
, index
);
118 va_start(argList
, index
);
119 while (i
!= NEWT_ARG_LAST
) {
120 indexes
[numIndexes
++] = i
;
121 i
= va_arg(argList
, int);
125 indexes
[numIndexes
++] = NEWT_ARG_LAST
;
127 return newtCheckboxTreeAddArray(co
, text
, data
, flags
, indexes
);
130 static int doFindItemPath(struct items
* items
, void * data
, int * path
,
135 if (items
->data
== data
) {
136 if (path
) path
[items
->depth
] = where
;
137 if (len
) *len
= items
->depth
+ 1;
141 if (items
->branch
&& doFindItemPath(items
->branch
, data
, path
, len
)) {
142 if (path
) path
[items
->depth
] = where
;
153 int * newtCheckboxTreeFindItem(newtComponent co
, void * data
) {
156 struct CheckboxTree
* ct
= co
->data
;
158 if (!doFindItemPath(ct
->itemlist
, data
, NULL
, &len
)) return NULL
;
160 path
= malloc(sizeof(*path
) * (len
+ 1));
161 doFindItemPath(ct
->itemlist
, data
, path
, NULL
);
162 path
[len
] = NEWT_ARG_LAST
;
167 int newtCheckboxTreeAddArray(newtComponent co
,
168 const char * text
, const void * data
,
169 int flags
, int * indexes
) {
170 struct items
* curList
, * newNode
, * item
;
171 struct items
** listPtr
= NULL
;
172 int i
, index
, numIndexes
;
173 struct CheckboxTree
* ct
= co
->data
;
176 while (indexes
[numIndexes
] != NEWT_ARG_LAST
) numIndexes
++;
179 if (numIndexes
> 1) return -1;
181 ct
->itemlist
= malloc(sizeof(*ct
->itemlist
));
186 curList
= ct
->itemlist
;
187 listPtr
= &ct
->itemlist
;
191 while (i
< numIndexes
) {
194 if (index
== NEWT_ARG_APPEND
) {
197 while (index
&& item
)
198 item
= item
->next
, index
--;
202 if (i
< numIndexes
) {
203 curList
= item
->branch
;
204 listPtr
= &item
->branch
;
205 if (!curList
&& (i
+ 1 != numIndexes
)) return -1;
211 if (!curList
) { /* create a new branch */
212 item
= malloc(sizeof(*curList
->prev
));
213 item
->next
= item
->prev
= NULL
;
215 } else if (!item
) { /* append to end */
217 while (item
->next
) item
= item
->next
;
218 item
->next
= malloc(sizeof(*curList
->prev
));
219 item
->next
->prev
= item
;
223 newNode
= malloc(sizeof(*newNode
));
224 newNode
->prev
= item
->prev
;
225 newNode
->next
= item
;
227 if (item
->prev
) item
->prev
->next
= newNode
;
228 item
->prev
= newNode
;
230 if (!item
->prev
) *listPtr
= item
;
234 item
->text
= strdup(text
);
236 if (flags
& NEWT_FLAG_SELECTED
) {
243 item
->depth
= numIndexes
- 1;
245 i
= 4 + (3 * item
->depth
);
247 if ((ct
->userHasSetWidth
== 0) && ((strlen(text
) + i
+ ct
->sbAdjust
) > co
->width
)) {
248 updateWidth(co
, ct
, strlen(text
) + i
);
254 static struct items
* findItem(struct items
* items
, const void * data
) {
258 if (items
->data
== data
) return items
;
260 i
= findItem(items
->branch
, data
);
270 static void listSelected(struct items
* items
, int * num
, const void ** list
, int seqindex
) {
272 if ((seqindex
? items
->selected
==seqindex
: items
->selected
) && !items
->branch
)
273 list
[(*num
)++] = (void *) items
->data
;
275 listSelected(items
->branch
, num
, list
, seqindex
);
280 void newtCheckboxTreeSetWidth(newtComponent co
, int width
) {
281 struct CheckboxTree
* ct
= co
->data
;
284 ct
->curWidth
= co
->width
- ct
->sbAdjust
;
285 ct
->userHasSetWidth
= 1;
286 if (ct
->sb
) ct
->sb
->left
= co
->width
+ co
->left
- 1;
290 const void ** newtCheckboxTreeGetSelection(newtComponent co
, int *numitems
)
292 return newtCheckboxTreeGetMultiSelection(co
, numitems
, 0);
295 const void ** newtCheckboxTreeGetMultiSelection(newtComponent co
, int *numitems
, char seqnum
)
297 struct CheckboxTree
* ct
;
301 if(!co
|| !numitems
) return NULL
;
306 while( ct
->seq
[seqindex
] && ( ct
->seq
[seqindex
] != seqnum
)) seqindex
++;
311 *numitems
= countItems(ct
->itemlist
, (seqindex
? seqindex
: COUNT_SELECTED
));
312 if (!*numitems
) return NULL
;
314 retval
= malloc(*numitems
* sizeof(void *));
316 listSelected(ct
->itemlist
, numitems
, retval
, seqindex
);
321 newtComponent
newtCheckboxTree(int left
, int top
, int height
, int flags
) {
322 return newtCheckboxTreeMulti(left
, top
, height
, NULL
, flags
);
325 newtComponent
newtCheckboxTreeMulti(int left
, int top
, int height
, char *seq
, int flags
) {
327 struct CheckboxTree
* ct
;
329 co
= malloc(sizeof(*co
));
330 ct
= malloc(sizeof(struct CheckboxTree
));
339 ct
->userHasSetWidth
= 0;
341 ct
->firstItem
= NULL
;
348 ct
->seq
= strdup(seq
);
350 ct
->seq
= strdup(" *");
351 if (flags
& NEWT_FLAG_SCROLL
) {
352 ct
->sb
= newtVerticalScrollbar(left
, top
, height
,
353 COLORSET_LISTBOX
, COLORSET_ACTLISTBOX
);
363 static void ctMapped(newtComponent co
, int isMapped
) {
364 struct CheckboxTree
* ct
= co
->data
;
366 co
->isMapped
= isMapped
;
368 ct
->sb
->ops
->mapped(ct
->sb
, isMapped
);
371 static void ctPlace(newtComponent co
, int newLeft
, int newTop
) {
372 struct CheckboxTree
* ct
= co
->data
;
378 ct
->sb
->ops
->place(ct
->sb
, co
->left
+ co
->width
- 1, co
->top
);
381 int ctSetItem(newtComponent co
, struct items
*item
, enum newtFlagsSense sense
)
383 struct CheckboxTree
* ct
= co
->data
;
384 struct items
* currItem
;
385 struct items
* firstItem
;
391 case NEWT_FLAGS_RESET
:
397 case NEWT_FLAGS_TOGGLE
:
399 item
->selected
= !item
->selected
;
400 else if (!(ct
->flags
& NEWT_CHECKBOXTREE_UNSELECTABLE
)) {
402 if (item
->selected
==strlen(ct
->seq
))
409 currItem
= *ct
->currItem
;
410 firstItem
= *ct
->firstItem
;
414 ct
->currItem
= ct
->flatList
;
415 while (*ct
->currItem
!= currItem
) ct
->currItem
++;
417 ct
->firstItem
= ct
->flatList
;
418 if (ct
->flatCount
> co
->height
) {
419 struct items
** last
= ct
->flatList
+ ct
->flatCount
- co
->height
;
420 while (*ct
->firstItem
!= firstItem
&& ct
->firstItem
!= last
)
428 static void ctSetItems(struct items
*item
, int selected
)
430 for (; item
; item
= item
->next
) {
432 item
->selected
= selected
;
434 ctSetItems(item
->branch
, selected
);
438 static void ctDraw(newtComponent co
) {
439 struct CheckboxTree
* ct
= co
->data
;
440 struct items
** item
;
445 if (!co
->isMapped
) return ;
447 if (!ct
->firstItem
) {
449 ct
->firstItem
= ct
->currItem
= ct
->flatList
;
452 item
= ct
->firstItem
;
458 while (*item
&& i
< co
->height
) {
459 newtGotorc(co
->top
+ i
, co
->left
);
460 if (*item
== *ct
->currItem
) {
461 SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX
);
462 currRow
= co
->top
+ i
;
464 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
466 for (j
= 0; j
< (*item
)->depth
; j
++)
467 SLsmg_write_string(" ");
469 if ((*item
)->branch
) {
470 if ((*item
)->selected
)
471 SLsmg_write_string("<-> ");
473 SLsmg_write_string("<+> ");
475 if (ct
->flags
& NEWT_CHECKBOXTREE_HIDE_BOX
) {
476 if ((*item
)->selected
)
477 SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX
);
480 snprintf(tmp
,5,"[%c] ",ct
->seq
[(*item
)->selected
]);
481 SLsmg_write_string(tmp
);
485 SLsmg_write_nstring((*item
)->text
, co
->width
- 4 -
486 (3 * (*item
)->depth
));
488 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
494 /* There could be empty lines left (i.e. if the user closes an expanded
495 list which is the last thing in the tree, and whose elements are
496 displayed at the bottom of the screen */
497 if (i
< co
->height
) {
498 spaces
= alloca(co
->width
);
499 memset(spaces
, ' ', co
->width
);
500 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
502 while (i
< co
->height
) {
503 newtGotorc(co
->top
+ i
, co
->left
);
504 SLsmg_write_nstring(spaces
, co
->width
);
509 newtScrollbarSet(ct
->sb
, ct
->currItem
- ct
->flatList
,
511 ct
->sb
->ops
->draw(ct
->sb
);
514 newtGotorc(currRow
, co
->left
+ 1);
517 static void ctDestroy(newtComponent co
) {
518 struct CheckboxTree
* ct
= co
->data
;
519 struct items
* item
, * nextitem
;
521 nextitem
= item
= ct
->itemlist
;
523 while (item
!= NULL
) {
524 nextitem
= item
->next
;
535 struct eventResult
ctEvent(newtComponent co
, struct event ev
) {
536 struct CheckboxTree
* ct
= co
->data
;
537 struct eventResult er
;
538 struct items
** listEnd
, ** lastItem
;
541 er
.result
= ER_IGNORED
;
543 if(ev
.when
== EV_EARLY
|| ev
.when
== EV_LATE
) {
550 if (key
== (char) key
&& key
!= ' ') {
551 for (selnum
= 0; ct
->seq
[selnum
]; selnum
++)
552 if (key
== ct
->seq
[selnum
])
554 if (!ct
->seq
[selnum
])
556 case '-': selnum
= 0; break;
558 case '*': selnum
= 1; break;
566 ctSetItem(co
, *ct
->currItem
, NEWT_FLAGS_TOGGLE
);
567 er
.result
= ER_SWALLOWED
;
568 if (!(*ct
->currItem
)->branch
|| (*ct
->currItem
)->selected
)
574 if ((*ct
->currItem
)->branch
) {
575 ctSetItems((*ct
->currItem
)->branch
, selnum
);
576 if (!(*ct
->currItem
)->selected
)
579 (*ct
->currItem
)->selected
= selnum
;
582 er
.result
= ER_SWALLOWED
;
588 if(co
->callback
) co
->callback(co
, co
->callbackData
);
591 ct
->currItem
= ct
->flatList
;
592 ct
->firstItem
= ct
->flatList
;
594 if(co
->callback
) co
->callback(co
, co
->callbackData
);
595 er
.result
= ER_SWALLOWED
;
598 ct
->currItem
= ct
->flatList
+ ct
->flatCount
- 1;
599 if (ct
->flatCount
<= co
->height
)
600 ct
->firstItem
= ct
->flatList
;
602 ct
->firstItem
= ct
->flatList
+ ct
->flatCount
- co
->height
;
604 if(co
->callback
) co
->callback(co
, co
->callbackData
);
605 er
.result
= ER_SWALLOWED
;
608 if (ev
.u
.key
!= NEWT_KEY_DOWN
) {
609 if(co
->callback
) co
->callback(co
, co
->callbackData
);
610 if (strlen(ct
->seq
) != 2) {
615 if ((ct
->currItem
- ct
->flatList
+ 1) < ct
->flatCount
) {
618 if (ct
->currItem
- ct
->firstItem
>= co
->height
)
622 } else if (ev
.u
.key
!= NEWT_KEY_DOWN
)
624 if(co
->callback
) co
->callback(co
, co
->callbackData
);
625 er
.result
= ER_SWALLOWED
;
628 if (ct
->currItem
!= ct
->flatList
) {
631 if (ct
->currItem
< ct
->firstItem
)
632 ct
->firstItem
= ct
->currItem
;
636 er
.result
= ER_SWALLOWED
;
637 if(co
->callback
) co
->callback(co
, co
->callbackData
);
640 if (ct
->firstItem
- co
->height
< ct
->flatList
) {
641 ct
->firstItem
= ct
->currItem
= ct
->flatList
;
643 ct
->currItem
-= co
->height
;
644 ct
->firstItem
-= co
->height
;
648 if(co
->callback
) co
->callback(co
, co
->callbackData
);
649 er
.result
= ER_SWALLOWED
;
652 listEnd
= ct
->flatList
+ ct
->flatCount
- 1;
653 lastItem
= ct
->firstItem
+ co
->height
- 1;
655 if (lastItem
+ co
->height
> listEnd
) {
656 ct
->firstItem
= listEnd
- co
->height
+ 1;
657 ct
->currItem
= listEnd
;
659 ct
->currItem
+= co
->height
;
660 ct
->firstItem
+= co
->height
;
664 if(co
->callback
) co
->callback(co
, co
->callbackData
);
665 er
.result
= ER_SWALLOWED
;
672 er
.result
= ER_SWALLOWED
;
677 er
.result
= ER_SWALLOWED
;
686 const void * newtCheckboxTreeGetCurrent(newtComponent co
) {
687 struct CheckboxTree
* ct
= co
->data
;
689 if (!ct
->currItem
) return NULL
;
690 return (*ct
->currItem
)->data
;
693 void newtCheckboxTreeSetEntry(newtComponent co
, const void * data
, const char * text
)
695 struct CheckboxTree
* ct
;
701 item
= findItem(ct
->itemlist
, data
);
705 item
->text
= strdup(text
);
707 i
= 4 + (3 * item
->depth
);
709 if ((ct
->userHasSetWidth
== 0) && ((strlen(text
) + i
+ ct
->sbAdjust
) > co
->width
)) {
710 updateWidth(co
, ct
, strlen(text
) + i
);
716 char newtCheckboxTreeGetEntryValue(newtComponent co
, const void * data
)
718 struct CheckboxTree
* ct
;
723 item
= findItem(ct
->itemlist
, data
);
724 if (!item
) return -1;
726 return item
->selected
? NEWT_CHECKBOXTREE_EXPANDED
: NEWT_CHECKBOXTREE_COLLAPSED
;
728 return ct
->seq
[item
->selected
];
731 void newtCheckboxTreeSetEntryValue(newtComponent co
, const void * data
, char value
)
733 struct CheckboxTree
* ct
;
739 item
= findItem(ct
->itemlist
, data
);
740 if (!item
|| item
->branch
) return;
742 for(i
= 0; ct
->seq
[i
]; i
++)
743 if (value
== ct
->seq
[i
])
746 if (!ct
->seq
[i
]) return;
753 void newtCheckboxTreeSetCurrent(newtComponent co
, void * data
) {
754 struct CheckboxTree
* ct
= co
->data
;
756 int i
, j
, itemsAfter
;
757 struct items
* treeTop
, * item
;
759 path
= newtCheckboxTreeFindItem(co
, data
);
762 /* traverse the path and turn on all of the branches to this point */
763 for (i
= 0, treeTop
= ct
->itemlist
; path
[i
+ 1] != NEWT_ARG_LAST
; i
++) {
764 for (j
= 0, item
= treeTop
; j
< path
[i
]; j
++)
768 treeTop
= item
->branch
;
773 item
= findItem(ct
->itemlist
, data
);
776 while (ct
->flatList
[i
] != item
) i
++;
778 /* choose the top item */
779 j
= i
- (co
->height
/ 2);
781 if ((j
+ co
->height
) > ct
->flatCount
)
782 j
= ct
->flatCount
- co
->height
;
787 ct
->firstItem
= ct
->flatList
+ j
;
788 ct
->currItem
= ct
->flatList
+ i
;