1 #include <slang.h>
2 #include <stdlib.h>
3 #include <string.h>
4 
5 #include "newt.h"
6 #include "newt_pr.h"
7 
8 struct items {
9     char * text;
10     const void *data;
11     unsigned char selected;
12     struct items *next;
13     struct items *prev;
14     struct items *branch;
15     int flags;
16     int depth;
17 };
18 
19 struct CheckboxTree {
20     newtComponent sb;
21     struct items * itemlist;
22     struct items ** flatList, ** currItem, ** firstItem;
23     int flatCount;
24     int flags;
25     int sbAdjust;
26     int curWidth;
27     int userHasSetWidth;
28     int isActive;
29     char * seq;
30     char * result;
31 };
32 
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,
43 				int maxField);
44 
45 static struct componentOps ctOps = {
46     ctDraw,
47     ctEvent,
48     ctDestroy,
49     ctPlace,
50     ctMapped,
51 } ;
52 
updateWidth(newtComponent co,struct CheckboxTree * ct,int maxField)53 static inline void updateWidth(newtComponent co, struct CheckboxTree * ct,
54 				int maxField) {
55     ct->curWidth = maxField;
56     co->width = ct->curWidth + ct->sbAdjust;
57 
58     if (ct->sb)
59 	ct->sb->left = co->left + co->width - 1;
60 }
61 
countItems(struct items * item,int what)62 static int countItems(struct items * item, int what) {
63     int count = 0;
64 
65     while (item) {
66 	if (what < 0 || (!item->branch && ((what > 0 && item->selected == what)
67 		    || (what == 0 && item->selected))))
68 	    count++;
69 	if (item->branch && (what >= 0 || (what < 0 && item->selected)))
70 	    count += countItems(item->branch, what);
71 	item = item->next;
72     }
73 
74     return count;
75 }
76 
doBuildFlatList(struct CheckboxTree * ct,struct items * item)77 static void doBuildFlatList(struct CheckboxTree * ct, struct items * item) {
78     while (item) {
79     	ct->flatList[ct->flatCount++] = item;
80 	if (item->branch && item->selected) doBuildFlatList(ct, item->branch);
81 	item = item->next;
82     }
83 }
84 
85 /* FIXME: Check what happens on malloc failure.
86  */
buildFlatList(newtComponent co)87 static void buildFlatList(newtComponent co) {
88     struct CheckboxTree * ct = co->data;
89 
90     if (ct->flatList) free(ct->flatList);
91     ct->flatCount = countItems(ct->itemlist, -1);
92 
93     ct->flatList = malloc(sizeof(*ct->flatList) * (ct->flatCount+1));
94     ct->flatCount = 0;
95     doBuildFlatList(ct, ct->itemlist);
96     ct->flatList[ct->flatCount] = NULL;
97 }
98 
newtCheckboxTreeAddItem(newtComponent co,const char * text,const void * data,int flags,int index,...)99 int newtCheckboxTreeAddItem(newtComponent co,
100 			    const char * text, const void * data,
101 			    int flags, int index, ...) {
102     va_list argList;
103     int numIndexes;
104     int * indexes;
105     int i;
106 
107     va_start(argList, index);
108     numIndexes = 0;
109     i = index;
110     while (i != NEWT_ARG_LAST) {
111 	numIndexes++;
112 	i = va_arg(argList, int);
113     }
114 
115     va_end(argList);
116 
117     indexes = alloca(sizeof(*indexes) * (numIndexes + 1));
118     va_start(argList, index);
119     numIndexes = 0;
120     i = index;
121     while (i != NEWT_ARG_LAST) {
122 	indexes[numIndexes++] = i;
123 	i = va_arg(argList, int);
124     }
125     va_end(argList);
126 
127     indexes[numIndexes++] = NEWT_ARG_LAST;
128 
129     return newtCheckboxTreeAddArray(co, text, data, flags, indexes);
130 }
131 
doFindItemPath(struct items * items,void * data,int * path,int * len)132 static int doFindItemPath(struct items * items, void * data, int * path,
133 			  int * len) {
134     int where = 0;
135 
136     while (items) {
137 	if (items->data == data) {
138 	    if (path) path[items->depth] = where;
139 	    if (len) *len = items->depth + 1;
140 	    return 1;
141 	}
142 
143 	if (items->branch && doFindItemPath(items->branch, data, path, len)) {
144 	    if (path) path[items->depth] = where;
145 	    return 1;
146 	}
147 
148 	items = items->next;
149 	where++;
150     }
151 
152     return 0;
153 }
154 
newtCheckboxTreeFindItem(newtComponent co,void * data)155 int * newtCheckboxTreeFindItem(newtComponent co, void * data) {
156     int len;
157     int * path;
158     struct CheckboxTree * ct = co->data;
159 
160     if (!doFindItemPath(ct->itemlist, data, NULL, &len)) return NULL;
161 
162     path = malloc(sizeof(*path) * (len + 1));
163     doFindItemPath(ct->itemlist, data, path, NULL);
164     path[len] = NEWT_ARG_LAST;
165 
166     return path;
167 }
168 
newtCheckboxTreeAddArray(newtComponent co,const char * text,const void * data,int flags,int * indexes)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;
176 
177     numIndexes = 0;
178     while (indexes[numIndexes] != NEWT_ARG_LAST) numIndexes++;
179 
180     if (!ct->itemlist) {
181 	if (numIndexes > 1) return -1;
182 
183     	ct->itemlist = malloc(sizeof(*ct->itemlist)); // FIXME: Error check?
184     	item = ct->itemlist;
185 	item->prev = NULL;
186 	item->next = NULL;
187     } else {
188 	curList = ct->itemlist;
189 	listPtr = &ct->itemlist;
190 
191 	i = 0;
192 	index = indexes[i];
193 	while (i < numIndexes) {
194 	    item = curList;
195 
196 	    if (index == NEWT_ARG_APPEND) {
197 	    	item = NULL;
198 	    } else {
199 		while (index && item)
200 		    item = item->next, index--;
201 	    }
202 
203 	    i++;
204 	    if (i < numIndexes) {
205 		if (item == NULL)
206 			return -1;
207 		curList = item->branch;
208 		listPtr = &item->branch;
209 		if (!curList && (i + 1 != numIndexes)) return -1;
210 
211 		index = indexes[i];
212 	    }
213 	}
214 
215 	if (!curList) { 			/* create a new branch */
216 	    item = malloc(sizeof(*curList->prev));
217 	    item->next = item->prev = NULL;
218 	    *listPtr = item;
219 	} else if (!item) {			/* append to end */
220 	    item = curList;
221 	    while (item->next) item = item->next;
222 	    item->next = malloc(sizeof(*curList->prev)); // FIXME Error check
223 	    item->next->prev = item;
224 	    item = item->next;
225 	    item->next = NULL;
226 	} else {
227 	    newNode = malloc(sizeof(*newNode)); // FIXME Error check ?
228 	    newNode->prev = item->prev;
229 	    newNode->next = item;
230 
231 	    if (item->prev) item->prev->next = newNode;
232 	    item->prev = newNode;
233 	    item = newNode;
234 	    if (!item->prev) *listPtr = item;
235 	}
236     }
237 
238     item->text = strdup(text);
239     item->data = data;
240     if (flags & NEWT_FLAG_SELECTED) {
241     	item->selected = 1;
242     } else {
243 	item->selected = 0;
244     }
245     item->flags = flags;
246     item->branch = NULL;
247     item->depth = numIndexes - 1;
248 
249     i = 4 + (3 * item->depth);
250     width = wstrlen(text, -1);
251 
252     if ((ct->userHasSetWidth == 0) && ((width + i + ct->sbAdjust) > co->width)) {
253 	updateWidth(co, ct, width + i);
254     }
255 
256     return 0;
257 }
258 
findItem(struct items * items,const void * data)259 static struct items * findItem(struct items * items, const void * data) {
260     struct items * i;
261 
262     while (items) {
263 	if (items->data == data) return items;
264     	if (items->branch) {
265 	    i = findItem(items->branch, data);
266 	    if (i) return i;
267 	}
268 
269 	items = items->next;
270     }
271 
272     return NULL;
273 }
274 
listSelected(struct items * items,int * num,const void ** list,int seqindex)275 static void listSelected(struct items * items, int * num, const void ** list, int seqindex) {
276     while (items) {
277 	if ((seqindex ? items->selected==seqindex : items->selected) && !items->branch)
278 	    list[(*num)++] = (void *) items->data;
279 	if (items->branch)
280 	    listSelected(items->branch, num, list, seqindex);
281 	items = items->next;
282     }
283 }
284 
newtCheckboxTreeSetWidth(newtComponent co,int width)285 void newtCheckboxTreeSetWidth(newtComponent co, int width) {
286     struct CheckboxTree * ct = co->data;
287 
288     co->width = width;
289     ct->curWidth = co->width - ct->sbAdjust;
290     ct->userHasSetWidth = 1;
291     if (ct->sb) ct->sb->left = co->width + co->left - 1;
292     ctDraw(co);
293 }
294 
newtCheckboxTreeGetSelection(newtComponent co,int * numitems)295 const void ** newtCheckboxTreeGetSelection(newtComponent co, int *numitems)
296 {
297     return newtCheckboxTreeGetMultiSelection(co, numitems, 0);
298 }
299 
newtCheckboxTreeGetMultiSelection(newtComponent co,int * numitems,char seqnum)300 const void ** newtCheckboxTreeGetMultiSelection(newtComponent co, int *numitems, char seqnum)
301 {
302     struct CheckboxTree * ct;
303     const void **retval;
304     int seqindex=0;
305 
306     if(!co || !numitems) return NULL;
307 
308     ct = co->data;
309 
310     if (seqnum) {
311 	    while( ct->seq[seqindex] && ( ct->seq[seqindex] != seqnum )) seqindex++;
312     } else {
313 	    seqindex = 0;
314     }
315 
316     *numitems = countItems(ct->itemlist, seqindex);
317     if (!*numitems) return NULL;
318 
319     retval = malloc(*numitems * sizeof(void *));
320     *numitems = 0;
321     listSelected(ct->itemlist, numitems, retval, seqindex);
322 
323     return retval;
324 }
325 
newtCheckboxTree(int left,int top,int height,int flags)326 newtComponent newtCheckboxTree(int left, int top, int height, int flags) {
327 	return newtCheckboxTreeMulti(left, top, height, NULL, flags);
328 }
329 
newtCheckboxTreeMulti(int left,int top,int height,char * seq,int flags)330 newtComponent newtCheckboxTreeMulti(int left, int top, int height, char *seq, int flags) {
331     newtComponent co;
332     struct CheckboxTree * ct;
333 
334     co = malloc(sizeof(*co));
335     ct = malloc(sizeof(struct CheckboxTree));
336     co->callback = NULL;
337     co->destroyCallback = NULL;
338     co->data = ct;
339     co->left = left;
340     co->top = top;
341     co->ops = &ctOps;
342     co->takesFocus = 1;
343     co->height = height;
344     co->width = 0;
345     co->isMapped = 0;
346     ct->curWidth = 0;
347     ct->isActive = 0;
348     ct->userHasSetWidth = 0;
349     ct->itemlist = NULL;
350     ct->firstItem = NULL;
351     ct->currItem = NULL;
352     ct->flatList = NULL;
353 
354     ct->flags = flags;
355 
356     if (seq)
357 	ct->seq = strdup(seq);
358     else
359 	ct->seq = strdup(" *");
360     if (flags & NEWT_FLAG_SCROLL) {
361 	ct->sb = newtVerticalScrollbar(left, top, height,
362 				       COLORSET_LISTBOX, COLORSET_ACTLISTBOX);
363 	ct->sbAdjust = 2;
364     } else {
365 	ct->sb = NULL;
366 	ct->sbAdjust = 0;
367     }
368 
369     return co;
370 }
371 
ctMapped(newtComponent co,int isMapped)372 static void ctMapped(newtComponent co, int isMapped) {
373     struct CheckboxTree * ct = co->data;
374 
375     co->isMapped = isMapped;
376     if (ct->sb)
377 	ct->sb->ops->mapped(ct->sb, isMapped);
378 }
379 
ctPlace(newtComponent co,int newLeft,int newTop)380 static void ctPlace(newtComponent co, int newLeft, int newTop) {
381     struct CheckboxTree * ct = co->data;
382 
383     co->top = newTop;
384     co->left = newLeft;
385 
386     if (ct->sb)
387 	ct->sb->ops->place(ct->sb, co->left + co->width - 1, co->top);
388 }
389 
ctSetItem(newtComponent co,struct items * item,enum newtFlagsSense sense)390 int ctSetItem(newtComponent co, struct items *item, enum newtFlagsSense sense)
391 {
392     struct CheckboxTree * ct = co->data;
393     struct items * currItem;
394     struct items * firstItem;
395 
396     if (!item)
397 	return 1;
398 
399     switch(sense) {
400 	case NEWT_FLAGS_RESET:
401 	    item->selected = 0;
402 	    break;
403 	case NEWT_FLAGS_SET:
404 	    item->selected = 1;
405 	    break;
406 	case NEWT_FLAGS_TOGGLE:
407 	    if (item->branch)
408 	      item->selected = !item->selected;
409 	    else if (!(ct->flags & NEWT_CHECKBOXTREE_UNSELECTABLE)) {
410 		    item->selected++;
411 		    if (item->selected==strlen(ct->seq))
412 		      item->selected = 0;
413 	    }
414 	    break;
415     }
416 
417     if (item->branch) {
418     	currItem = *ct->currItem;
419 	firstItem = *ct->firstItem;
420 
421     	buildFlatList(co);
422 
423     	ct->currItem = ct->flatList;
424 	while (*ct->currItem != currItem) ct->currItem++;
425 
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)
430 		    ct->firstItem++;
431 	}
432     }
433 
434     return 0;
435 }
436 
ctSetItems(struct items * item,int selected)437 static void ctSetItems(struct items *item, int selected)
438 {
439     for (; item; item = item->next) {
440 	if (!item->branch)
441 	    item->selected = selected;
442 	else
443 	    ctSetItems(item->branch, selected);
444     }
445 }
446 
ctDraw(newtComponent co)447 static void ctDraw(newtComponent co) {
448     struct CheckboxTree * ct = co->data;
449     struct items ** item;
450     int i, j;
451     char * spaces;
452     int currRow = co->top;
453 
454     if (!co->isMapped) return ;
455 
456     if (!ct->firstItem) {
457 	buildFlatList(co);
458 	ct->firstItem = ct->currItem = ct->flatList;
459     }
460 
461     item = ct->firstItem;
462 
463     i = 0;
464 
465     newtTrashScreen();
466 
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("   ");
472 
473 	if ((*item)->branch) {
474 	    if ((*item)->selected)
475 		SLsmg_write_string("<-> ");
476 	    else
477 		SLsmg_write_string("<+> ");
478 	} else {
479 	    if (ct->flags & NEWT_CHECKBOXTREE_HIDE_BOX) {
480 		if ((*item)->selected)
481 		    SLsmg_set_color(NEWT_COLORSET_SELLISTBOX);
482 	        SLsmg_write_string("    ");
483 	    } else {
484 	        char tmp[5];
485 	        snprintf(tmp,5,"[%c] ",ct->seq[(*item)->selected]);
486 	        SLsmg_write_string(tmp);
487 	    }
488 	}
489 	if (*item == *ct->currItem) {
490 	    SLsmg_set_color(ct->isActive ?
491 		    NEWT_COLORSET_ACTSELLISTBOX : NEWT_COLORSET_ACTLISTBOX);
492 	    currRow = co->top + i;
493 	}
494 
495 	SLsmg_write_nstring((*item)->text, co->width - 4 - (3 * (*item)->depth));
496 
497 	item++;
498 	i++;
499     }
500 
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);
509 
510 	while (i < co->height) {
511 	    newtGotorc(co->top + i, co->left);
512 	    SLsmg_write_nstring(spaces, co->width);
513 	    i++;
514 	}
515     }
516 
517     if(ct->sb) {
518 	newtScrollbarSet(ct->sb, ct->currItem - ct->flatList,
519 			 ct->flatCount - 1);
520 	ct->sb->ops->draw(ct->sb);
521     }
522 
523     newtGotorc(currRow, co->left +
524 		    (*ct->currItem ? (*ct->currItem)->depth : 0) * 3 + 4);
525 }
526 
destroyItems(struct items * item)527 static void destroyItems(struct items * item) {
528     struct items * nextitem;
529 
530     while (item != NULL) {
531 	nextitem = item->next;
532 	free(item->text);
533 	if (item->branch)
534 	    destroyItems(item->branch);
535 	free(item);
536 	item = nextitem;
537     }
538 }
539 
ctDestroy(newtComponent co)540 static void ctDestroy(newtComponent co) {
541     struct CheckboxTree * ct = co->data;
542 
543     destroyItems(ct->itemlist);
544     free(ct->flatList);
545     if (ct->sb)
546 	ct->sb->ops->destroy(ct->sb);
547     free(ct->seq);
548     free(ct);
549     free(co);
550 }
551 
ctEnsureLimits(struct CheckboxTree * ct)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;
561     }
562 }
563 
ctEvent(newtComponent co,struct event ev)564 struct eventResult ctEvent(newtComponent co, struct event ev) {
565     struct CheckboxTree * ct = co->data;
566     struct eventResult er;
567     struct items ** listEnd, ** lastItem;
568     int key, selnum = 1;
569 
570     er.result = ER_IGNORED;
571 
572     if(ev.when == EV_EARLY || ev.when == EV_LATE) {
573 	return er;
574     }
575 
576     switch(ev.event) {
577     case EV_KEYPRESS:
578 	key = ev.u.key;
579 	if (key == (char) key && key != ' ') {
580 	    for (selnum = 0; ct->seq[selnum]; selnum++)
581 	    if (key == ct->seq[selnum])
582 		break;
583 	    if (!ct->seq[selnum])
584 		switch (key) {
585 		case '-': selnum = 0; break;
586 		case '+':
587 		case '*': selnum = 1; break;
588 		}
589 	    if (ct->seq[selnum])
590 		key = '*';
591 	}
592 	switch(key) {
593 	case ' ':
594 	case NEWT_KEY_ENTER:
595 	    ctSetItem(co, *ct->currItem, NEWT_FLAGS_TOGGLE);
596 	    er.result = ER_SWALLOWED;
597 	    if (!(*ct->currItem)->branch || (*ct->currItem)->selected)
598 		key = NEWT_KEY_DOWN;
599 	    else
600 		key = '*';
601 	    break;
602 	case '*':
603 	    if ((*ct->currItem)->branch) {
604 		ctSetItems((*ct->currItem)->branch, selnum);
605 		if (!(*ct->currItem)->selected)
606 		    key = NEWT_KEY_DOWN;
607 	    } else {
608 		(*ct->currItem)->selected = selnum;
609 		key = NEWT_KEY_DOWN;
610 	    }
611 	    er.result = ER_SWALLOWED;
612 	    break;
613 	}
614 	switch (key) {
615 	case '*':
616 	    ctDraw(co);
617 	    if(co->callback) co->callback(co, co->callbackData);
618 	    return er;
619 	case NEWT_KEY_HOME:
620 	    ct->currItem = ct->flatList;
621 	    ct->firstItem = ct->flatList;
622 	    ctDraw(co);
623 	    if(co->callback) co->callback(co, co->callbackData);
624 	    er.result = ER_SWALLOWED;
625 	    return er;
626 	case NEWT_KEY_END:
627 	    ct->currItem = ct->flatList + ct->flatCount - 1;
628 	    if (ct->flatCount <= co->height)
629 		ct->firstItem = ct->flatList;
630 	    else
631 		ct->firstItem = ct->flatList + ct->flatCount - co->height;
632 	    ctDraw(co);
633 	    if(co->callback) co->callback(co, co->callbackData);
634 	    er.result = ER_SWALLOWED;
635 	    return er;
636 	case NEWT_KEY_DOWN:
637 	    if (ev.u.key != NEWT_KEY_DOWN) {
638 		if(co->callback) co->callback(co, co->callbackData);
639 		if (strlen(ct->seq) != 2) {
640 		    ctDraw(co);
641 		    return er;
642 		}
643 	    }
644 	    if ((ct->currItem - ct->flatList + 1) < ct->flatCount) {
645 		ct->currItem++;
646 
647 		if (ct->currItem - ct->firstItem >= co->height)
648 		    ct->firstItem++;
649 
650 		ctDraw(co);
651 	    } else if (ev.u.key != NEWT_KEY_DOWN)
652 	        ctDraw(co);
653 	    if(co->callback) co->callback(co, co->callbackData);
654 	    er.result = ER_SWALLOWED;
655 	    return er;
656 	case NEWT_KEY_UP:
657 	    if (ct->currItem != ct->flatList) {
658 		ct->currItem--;
659 
660 		if (ct->currItem < ct->firstItem)
661 		    ct->firstItem = ct->currItem;
662 
663 		ctDraw(co);
664 	    }
665 	    er.result = ER_SWALLOWED;
666 	    if(co->callback) co->callback(co, co->callbackData);
667 	    return er;
668 	case NEWT_KEY_PGUP:
669 	    if (ct->firstItem - co->height < ct->flatList) {
670 	    	ct->firstItem = ct->currItem = ct->flatList;
671 	    } else {
672 		ct->currItem -= co->height;
673 		ct->firstItem -= co->height;
674 	    }
675 	    ctEnsureLimits( ct );
676 
677 	    ctDraw(co);
678 	    if(co->callback) co->callback(co, co->callbackData);
679 	    er.result = ER_SWALLOWED;
680 	    return er;
681 	case NEWT_KEY_PGDN:
682 	    listEnd = ct->flatList + ct->flatCount - 1;
683 	    lastItem = ct->firstItem + co->height - 1;
684 
685 	    if (lastItem + co->height > listEnd) {
686 	    	ct->firstItem = listEnd - co->height + 1;
687 		ct->currItem = listEnd;
688 	    } else {
689 	    	ct->currItem += co->height;
690 		ct->firstItem += co->height;
691 	    }
692 	    ctEnsureLimits( ct );
693 
694 	    ctDraw(co);
695 	    if(co->callback) co->callback(co, co->callbackData);
696 	    er.result = ER_SWALLOWED;
697 	    return er;
698 	}
699 	break;
700 
701     case EV_FOCUS:
702 	ct->isActive = 1;
703 	ctDraw(co);
704 	er.result = ER_SWALLOWED;
705 	break;
706 
707     case EV_UNFOCUS:
708 	ct->isActive = 0;
709 	ctDraw(co);
710 	er.result = ER_SWALLOWED;
711 	break;
712     default:
713 	break;
714     }
715 
716     return er;
717 }
718 
newtCheckboxTreeGetCurrent(newtComponent co)719 const void * newtCheckboxTreeGetCurrent(newtComponent co) {
720     struct CheckboxTree * ct = co->data;
721 
722     if (!ct->currItem) {
723 	if (ct->itemlist)
724 	    return ct->itemlist->data;
725 	else
726 	    return NULL;
727     }
728 
729     return (*ct->currItem)->data;
730 }
731 
newtCheckboxTreeSetEntry(newtComponent co,const void * data,const char * text)732 void newtCheckboxTreeSetEntry(newtComponent co, const void * data, const char * text)
733 {
734     struct CheckboxTree * ct;
735     struct items * item;
736     int i, width;
737 
738     if (!co) return;
739     ct = co->data;
740     item = findItem(ct->itemlist, data);
741     if (!item) return;
742 
743     free(item->text);
744     item->text = strdup(text);
745 
746     i = 4 + (3 * item->depth);
747 
748     width = wstrlen(text, -1);
749     if ((ct->userHasSetWidth == 0) && ((width + i + ct->sbAdjust) > co->width)) {
750 	updateWidth(co, ct, width + i);
751     }
752 
753     ctDraw(co);
754 }
755 
newtCheckboxTreeGetEntryValue(newtComponent co,const void * data)756 char newtCheckboxTreeGetEntryValue(newtComponent co, const void * data)
757 {
758     struct CheckboxTree * ct;
759     struct items * item;
760 
761     if (!co) return -1;
762     ct = co->data;
763     item = findItem(ct->itemlist, data);
764     if (!item) return -1;
765     if (item->branch)
766 	return item->selected ? NEWT_CHECKBOXTREE_EXPANDED : NEWT_CHECKBOXTREE_COLLAPSED;
767     else
768 	return ct->seq[item->selected];
769 }
770 
newtCheckboxTreeSetEntryValue(newtComponent co,const void * data,char value)771 void newtCheckboxTreeSetEntryValue(newtComponent co, const void * data, char value)
772 {
773     struct CheckboxTree * ct;
774     struct items * item;
775     int i;
776 
777     if (!co) return;
778     ct = co->data;
779     item = findItem(ct->itemlist, data);
780     if (!item || item->branch) return;
781 
782     for(i = 0; ct->seq[i]; i++)
783 	if (value == ct->seq[i])
784 	    break;
785 
786     if (!ct->seq[i]) return;
787     item->selected = i;
788 
789     ctDraw(co);
790 }
791 
792 
newtCheckboxTreeSetCurrent(newtComponent co,void * data)793 void newtCheckboxTreeSetCurrent(newtComponent co, void * data) {
794     struct CheckboxTree * ct = co->data;
795     int * path;
796     int i, j;
797     struct items * treeTop, * item;
798 
799     path = newtCheckboxTreeFindItem(co, data);
800     if (!path) return;
801 
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++)
805 	    item = item->next;
806 
807 	item->selected = 1;
808 	treeTop = item->branch;
809     }
810 
811     free(path);
812     buildFlatList(co);
813 
814     item = findItem(ct->itemlist, data);
815 
816     i = 0;
817     while (ct->flatList[i] != item) i++;
818 
819     /* choose the top item */
820     j = i - (co->height / 2);
821 
822     if ((j + co->height) > ct->flatCount)
823 	j = ct->flatCount - co->height;
824 
825     if (j < 0)
826 	j = 0;
827 
828     ct->firstItem = ct->flatList + j;
829     ct->currItem = ct->flatList + i;
830 
831     ctDraw(co);
832 }
833