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