struct items *next;
struct items *prev;
struct items *branch;
+ int flags;
+ int depth;
};
struct CheckboxTree {
newtComponent sb;
int curWidth; /* size of text w/o scrollbar or border*/
int curHeight; /* size of text w/o border */
- int sbAdjust;
- int bdxAdjust, bdyAdjust;
- int numBoxes, numSelected;
- int userHasSetWidth;
- struct items * currItem, * firstItem, * itemlist;
- int currPos;
- int isActive;
- int grow;
+ struct items * itemlist;
+ struct items ** flatList, ** currItem, ** firstItem;
+ int flatCount;
int flags;
int pad;
char * seq;
static void ctPlace(newtComponent co, int newLeft, int newTop);
struct eventResult ctEvent(newtComponent co, struct event ev);
static void ctMapped(newtComponent co, int isMapped);
+static struct items * findItem(struct items * items, const void * data);
+static void buildFlatList(newtComponent co);
+static void doBuildFlatList(struct CheckboxTree * ct, struct items * item);
+enum countWhat { COUNT_EXPOSED, COUNT_SELECTED };
+static int countItems(struct items * item, enum countWhat justExposed);
static struct componentOps ctOps = {
ctDraw,
ctMapped,
} ;
-int newtCheckboxTreeAppend(newtComponent co, int selected,
- const char * text,
- const void * data) {
+static int countItems(struct items * item, enum countWhat what) {
+ int count = 0;
+
+ while (item) {
+ if ((!item->branch) || (what == COUNT_EXPOSED))
+ count++;
+ if (item->branch && (what == COUNT_EXPOSED && item->selected))
+ count += countItems(item->branch, what);
+ item = item->next;
+ }
+
+ return count;
+}
+
+static void doBuildFlatList(struct CheckboxTree * ct, struct items * item) {
+ while (item) {
+ ct->flatList[ct->flatCount++] = item;
+ if (item->branch && item->selected) doBuildFlatList(ct, item->branch);
+ item = item->next;
+ }
+}
+
+static void buildFlatList(newtComponent co) {
struct CheckboxTree * ct = co->data;
- struct items *item, *prev;
- if(ct->itemlist) {
- for (item = ct->itemlist; item->next != NULL; item = item->next);
- prev = item;
- item = item->next = malloc(sizeof(struct items));
- item->prev = prev;
- } else {
- item = ct->itemlist = ct->firstItem =
- ct->currItem = malloc(sizeof(struct items));
+ if (ct->flatList) free(ct->flatList);
+ ct->flatCount = countItems(ct->itemlist, COUNT_EXPOSED);
+
+ ct->flatList = malloc(sizeof(*ct->flatList) * ct->flatCount);
+ ct->flatCount = 0;
+ doBuildFlatList(ct, ct->itemlist);;
+}
+
+int newtCheckboxTreeAddItem(newtComponent co,
+ const char * text, const void * data,
+ int flags, int index, ...) {
+ va_list argList;
+ int numIndexes;
+ int * indexes;
+ int i;
+
+ va_start(argList, index);
+ numIndexes = 0;
+ i = index;
+ while (i != NEWT_ARG_LAST) {
+ numIndexes++;
+ i = va_arg(argList, int);
+ }
+
+ va_end(argList);
+
+ indexes = alloca(sizeof(*indexes) * numIndexes);
+ va_start(argList, index);
+ numIndexes = 0;
+ i = index;
+ va_start(argList, index);
+ while (i != NEWT_ARG_LAST) {
+ indexes[numIndexes++] = i;
+ i = va_arg(argList, int);
+ }
+ va_end(argList);
+
+ indexes[numIndexes++] = NEWT_ARG_LAST;
+
+ return newtCheckboxTreeAddArray(co, text, data, flags, indexes);
+}
+
+static int doFindItemPath(struct items * items, void * data, int * path,
+ int * len) {
+ int where = 0;
+
+ while (items) {
+ if (items->data == data) {
+ if (path) path[items->depth] = where;
+ if (len) *len = items->depth + 1;
+ return 1;
+ }
+
+ if (items->branch && doFindItemPath(items->branch, data, path, len)) {
+ if (path) path[items->depth] = where;
+ return 1;
+ }
+
+ items = items->next;
+ where++;
+ }
+
+ return 0;
+}
+
+int * newtCheckboxTreeFindItem(newtComponent co, void * data) {
+ int len;
+ int * path;
+ struct CheckboxTree * ct = co->data;
+
+ if (!doFindItemPath(ct->itemlist, data, NULL, &len)) return NULL;
+
+ path = malloc(sizeof(*path) * (len + 1));
+ doFindItemPath(ct->itemlist, data, path, NULL);
+ path[len] = NEWT_ARG_LAST;
+
+ return path;
+}
+
+int newtCheckboxTreeAddArray(newtComponent co,
+ const char * text, const void * data,
+ int flags, int * indexes) {
+ struct items * curList, * newNode, * item;
+ struct items ** listPtr = NULL;
+ int i, index, numIndexes;
+ struct CheckboxTree * ct = co->data;
+
+ numIndexes = 0;
+ while (indexes[numIndexes] != NEWT_ARG_LAST) numIndexes++;
+
+ if (!ct->itemlist) {
+ if (numIndexes > 1) return -1;
+
+ ct->itemlist = malloc(sizeof(*ct->itemlist));
+ item = ct->itemlist;
item->prev = NULL;
+ item->next = NULL;
+ } else {
+ curList = ct->itemlist;
+ listPtr = &ct->itemlist;
+
+ i = 0;
+ index = indexes[i];
+ while (i < numIndexes) {
+ item = curList;
+
+ if (index == NEWT_ARG_APPEND) {
+ item = NULL;
+ } else {
+ while (index && item)
+ item = item->next, index--;
+ }
+
+ i++;
+ if (i < numIndexes) {
+ curList = item->branch;
+ listPtr = &item->branch;
+ if (!curList && (i + 1 != numIndexes)) return -1;
+
+ index = indexes[i];
+ }
+ }
+
+ if (!curList) { /* create a new branch */
+ item = malloc(sizeof(*curList->prev));
+ item->next = item->prev = NULL;
+ *listPtr = item;
+ } else if (!item) { /* append to end */
+ item = curList;
+ while (item->next) item = item->next;
+ item->next = malloc(sizeof(*curList->prev));
+ item->next->prev = item;
+ item = item->next;
+ } else {
+ newNode = malloc(sizeof(*newNode));
+ newNode->prev = item->prev;
+ newNode->next = item;
+
+ if (item->prev) item->prev->next = newNode;
+ item->prev = newNode;
+ item = newNode;
+ if (!item->prev) *listPtr = item;
+ }
+ }
+
+ item->text = strdup(text);
+ item->data = data;
+ if (flags & NEWT_FLAG_SELECTED) {
+ item->selected = 1;
+ } else {
+ item->selected = 0;
}
+ item->flags = flags;
+ item->branch = NULL;
+ item->depth = numIndexes - 1;
- if ((strlen(text) + 4 + ct->pad) > co->width) {
- co->width = strlen(text) + 4 + ct->pad;
+ i = 4;
+
+ if ((strlen(text) + i + ct->pad) > co->width) {
+ co->width = strlen(text) + i + ct->pad;
}
-
- item->text = strdup(text); item->data = data; item->next = NULL;
- item->selected = selected;
- ct->numSelected += selected;
- ct->numBoxes++;
+
return 0;
}
+static struct items * findItem(struct items * items, const void * data) {
+ struct items * i;
+
+ while (items) {
+ if (items->data == data) return items;
+ if (items->branch) {
+ i = findItem(items->branch, data);
+ if (i) return i;
+ }
+
+ items = items->next;
+ }
+
+ return NULL;
+}
+
+static void listSelected(struct items * items, int * num, void ** list) {
+ while (items) {
+ if (items->selected && !items->branch)
+ list[(*num)++] = items->data;
+ if (items->branch)
+ listSelected(items->branch, num, list);
+ items = items->next;
+ }
+}
+
void ** newtCheckboxTreeGetSelection(newtComponent co, int *numitems)
{
struct CheckboxTree * ct;
- int i;
void **retval;
- struct items *item;
if(!co || !numitems) return NULL;
ct = co->data;
- if(!ct || !ct->numSelected) {
- *numitems = 0;
- return NULL;
- }
+
+ *numitems = countItems(ct->itemlist, COUNT_SELECTED);
+ if (!*numitems) return NULL;
- retval = malloc(ct->numSelected * sizeof(void *));
- for(i = 0, item = ct->itemlist; item != NULL;
- item = item->next)
- if(item->selected)
- retval[i++] = (void *)item->data;
- *numitems = ct->numSelected;
+ retval = malloc(*numitems * sizeof(void *));
+ *numitems = 0;
+ listSelected(ct->itemlist, numitems, retval);
+
return retval;
}
co->height = height;
co->width = 0;
co->isMapped = 0;
- ct->numSelected = 0;
- ct->currPos = 0;
ct->itemlist = NULL;
- ct->numBoxes = 0;
+ ct->firstItem = NULL;
+ ct->currItem = NULL;
+ ct->flatList = NULL;
if (flags & NEWT_FLAG_SCROLL) {
ct->sb = newtVerticalScrollbar(left, top, height,
COLORSET_LISTBOX, COLORSET_ACTLISTBOX);
int ctSetItem(newtComponent co, struct items *item, enum newtFlagsSense sense)
{
struct CheckboxTree * ct = co->data;
+ struct items ** currItem;
if (!item)
return 1;
- if (item->selected)
- ct->numSelected--;
-
switch(sense) {
case NEWT_FLAGS_RESET:
item->selected = 0;
break;
}
- if (item->selected)
- ct->numSelected++;
-
+ if (item->branch) {
+ currItem = ct->currItem;
+
+ buildFlatList(co);
+
+ ct->currItem = ct->flatList;
+ while (*ct->currItem != *currItem) ct->currItem++;
+ }
+
return 0;
}
static void ctDraw(newtComponent co) {
struct CheckboxTree * ct = co->data;
- struct items * item;
- int i, curr, pos = 0;
-
- item = ct->itemlist;
- while (item && item != ct->firstItem) {
- item = item->next;
- pos++;
+ struct items ** item;
+ int i, curr, j;
+
+ if (!co->isMapped) return ;
+
+ if (!ct->firstItem) {
+ buildFlatList(co);
+ ct->firstItem = ct->currItem = ct->flatList;
}
+
+ item = ct->firstItem;
i = 0;
- while (item && i < co->height) {
+ while (*item && i < co->height) {
newtGotorc(co->top + i, co->left);
- if (item == ct->currItem) {
+ if (*item == *ct->currItem) {
SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
- ct->currPos = curr = i;
} else
SLsmg_set_color(NEWT_COLORSET_LISTBOX);
- SLsmg_write_string("[");
- SLsmg_write_string(item->selected ? "*" : " ");
- SLsmg_write_string("] ");
- SLsmg_write_nstring(item->text, co->width - 4);
- item = item->next;
+
+ for (j = 0; j < (*item)->depth; j++)
+ SLsmg_write_string(" ");
+
+ if ((*item)->branch) {
+ if ((*item)->selected)
+ SLsmg_write_string("<-> ");
+ else
+ SLsmg_write_string("<+> ");
+ } else {
+ if ((*item)->selected)
+ SLsmg_write_string("[*] ");
+ else
+ SLsmg_write_string("[ ] ");
+ }
+
+ SLsmg_write_nstring((*item)->text, co->width - 4 -
+ (3 * (*item)->depth));
+ item++;
i++;
}
if(ct->sb) {
- newtScrollbarSet(ct->sb, pos + curr + 1, ct->numBoxes);
+ newtScrollbarSet(ct->sb, ct->currItem - ct->flatList,
+ ct->flatCount - 1);
ct->sb->ops->draw(ct->sb);
}
struct eventResult ctEvent(newtComponent co, struct event ev) {
struct CheckboxTree * ct = co->data;
struct eventResult er;
- struct items * item;
- int i;
+ struct items ** listEnd, ** lastItem;
er.result = ER_IGNORED;
switch(ev.u.key) {
case ' ':
case NEWT_KEY_ENTER:
- if (ct->currItem) {
- ctSetItem(co, ct->currItem, NEWT_FLAGS_TOGGLE);
+ if (*ct->currItem) {
+ ctSetItem(co, *ct->currItem, NEWT_FLAGS_TOGGLE);
ctDraw(co);
er.result = ER_SWALLOWED;
}
break;
case NEWT_KEY_DOWN:
- if (ct->currItem && ct->currItem->next) {
- ct->currItem = ct->currItem->next;
+ if ((ct->currItem - ct->flatList + 1) < ct->flatCount) {
+ ct->currItem++;
+
er.result = ER_SWALLOWED;
- /* Check to see if our new position (currPos + 1) is past
- the end of the list. If so, scroll up. */
- if (ct->currPos + 1 >= co->height) {
- if (ct->firstItem->next)
- ct->firstItem = ct->firstItem->next;
- ct->currPos = co->height;
- } else
- ct->currPos++;
+
+ if (ct->currItem - ct->firstItem >= co->height)
+ ct->firstItem++;
+
ctDraw(co);
}
break;
case NEWT_KEY_UP:
- if (ct->currItem->prev) {
- ct->currItem = ct->currItem->prev;
+ if (ct->currItem != ct->flatList) {
+ ct->currItem--;
er.result = ER_SWALLOWED;
- /* Check to see if our new position (currPos - 1) is past
- the beginning of the list. If so, scroll down. */
- if (ct->currPos <= 0) {
- if (ct->firstItem->prev)
- ct->firstItem = ct->firstItem->prev;
- ct->currPos = 0;
- } else
- ct->currPos--;
+
+ if (ct->currItem < ct->firstItem)
+ ct->firstItem = ct->currItem;
+
ctDraw(co);
}
break;
case NEWT_KEY_PGUP:
- item = ct->currItem;
-
- for (i = 0; i < co->height; i++) {
- if (item->prev)
- item = item->prev;
- else
- break;
+ if (ct->firstItem - co->height < ct->flatList) {
+ ct->firstItem = ct->currItem = ct->flatList;
+ } else {
+ ct->currItem -= co->height;
+ ct->firstItem -= co->height;
}
- ct->currItem = ct->firstItem = item;
- ct->currPos = 0;
+
ctDraw(co);
er.result = ER_SWALLOWED;
break;
case NEWT_KEY_PGDN:
- item = ct->currItem;
-
- for (i = 0; i < co->height; i++) {
- if (item->next)
- item = item->next;
- else
- break;
- }
- ct->currItem = item;
- ct->currPos = co->height;
-
- /* back up the starting item to the current position */
- for (i = 0; i < co->height - 1; i++) {
- if (item->prev)
- item = item->prev;
- else
- break;
+ listEnd = ct->flatList + ct->flatCount - 1;
+ lastItem = ct->firstItem + co->height - 1;
+
+ if (lastItem + co->height > listEnd) {
+ ct->firstItem = listEnd - co->height + 1;
+ ct->currItem = listEnd;
+ } else {
+ ct->currItem += co->height;
+ ct->firstItem += co->height;
}
- ct->firstItem = item;
+
ctDraw(co);
er.result = ER_SWALLOWED;
break;
newtComponent answer;
void ** result, **ptr;
int numselected, i, j;
+ int * list;
newtInit();
newtCls();
checktree = newtCheckboxTree(-1, -1, 10, NEWT_FLAG_SCROLL);
- newtCheckboxTreeAppend(checktree, 0, "Foobar!", (void *) 1);
- newtCheckboxTreeAppend(checktree, 1, "Baz!", (void *) 2);
- newtCheckboxTreeAppend(checktree, 0, "Really really long thing",
- (void *) 3);
- newtCheckboxTreeAppend(checktree, 0, "number 4", (void *) 4);
- newtCheckboxTreeAppend(checktree, 1, "number 5", (void *) 5);
- newtCheckboxTreeAppend(checktree, 0, "number 6", (void *) 6);
- newtCheckboxTreeAppend(checktree, 1, "number 7", (void *) 7);
- newtCheckboxTreeAppend(checktree, 0, "number 8", (void *) 8);
- newtCheckboxTreeAppend(checktree, 0, "number 9", (void *) 9);
- newtCheckboxTreeAppend(checktree, 1, "number 10", (void *) 10);
- newtCheckboxTreeAppend(checktree, 0, "number 11", (void *) 11);
- newtCheckboxTreeAppend(checktree, 1, "number 12", (void *) 12);
-
+ newtCheckboxTreeAddItem(checktree, "Numbers", (void *) 2, 0,
+ NEWT_ARG_APPEND, NEWT_ARG_LAST);
+ newtCheckboxTreeAddItem(checktree, "Really really long thing",
+ (void *) 3, 0, NEWT_ARG_APPEND, NEWT_ARG_LAST);
+ newtCheckboxTreeAddItem(checktree, "number 5", (void *) 5,
+ NEWT_FLAG_SELECTED,
+ NEWT_ARG_APPEND, NEWT_ARG_LAST);
+ newtCheckboxTreeAddItem(checktree, "number 6", (void *) 6, 0,
+ NEWT_ARG_APPEND, NEWT_ARG_LAST);
+ newtCheckboxTreeAddItem(checktree, "number 7", (void *) 7,
+ NEWT_FLAG_SELECTED,
+ NEWT_ARG_APPEND, NEWT_ARG_LAST);
+ newtCheckboxTreeAddItem(checktree, "number 8", (void *) 8, 0,
+ NEWT_ARG_APPEND, NEWT_ARG_LAST);
+ newtCheckboxTreeAddItem(checktree, "number 9", (void *) 9, 0,
+ NEWT_ARG_APPEND, NEWT_ARG_LAST);
+ newtCheckboxTreeAddItem(checktree, "number 10", (void *) 10,
+ NEWT_FLAG_SELECTED,
+ NEWT_ARG_APPEND, NEWT_ARG_LAST);
+ newtCheckboxTreeAddItem(checktree, "number 11", (void *) 11, 0,
+ NEWT_ARG_APPEND, NEWT_ARG_LAST);
+ newtCheckboxTreeAddItem(checktree, "number 12", (void *) 12,
+ NEWT_FLAG_SELECTED,
+ NEWT_ARG_APPEND, NEWT_ARG_LAST);
+
+ newtCheckboxTreeAddItem(checktree, "Colors", (void *) 1, 0,
+ 0, NEWT_ARG_LAST);
+ newtCheckboxTreeAddItem(checktree, "Red", (void *) 100, 0,
+ 0, NEWT_ARG_APPEND, NEWT_ARG_LAST);
+ newtCheckboxTreeAddItem(checktree, "White", (void *) 101, 0,
+ 0, NEWT_ARG_APPEND, NEWT_ARG_LAST);
+ newtCheckboxTreeAddItem(checktree, "Blue", (void *) 102, 0,
+ 0, NEWT_ARG_APPEND, NEWT_ARG_LAST);
+
+ newtCheckboxTreeAddItem(checktree, "number 4", (void *) 4, 0,
+ 3, NEWT_ARG_LAST);
+
+ newtCheckboxTreeAddItem(checktree, "Single digit", (void *) 200, 0,
+ 1, NEWT_ARG_APPEND, NEWT_ARG_LAST);
+ newtCheckboxTreeAddItem(checktree, "One", (void *) 201, 0,
+ 1, 0, NEWT_ARG_APPEND, NEWT_ARG_LAST);
+ newtCheckboxTreeAddItem(checktree, "Two", (void *) 202, 0,
+ 1, 0, NEWT_ARG_APPEND, NEWT_ARG_LAST);
+ newtCheckboxTreeAddItem(checktree, "Three", (void *) 203, 0,
+ 1, 0, NEWT_ARG_APPEND, NEWT_ARG_LAST);
+ newtCheckboxTreeAddItem(checktree, "Four", (void *) 204, 0,
+ 1, 0, NEWT_ARG_APPEND, NEWT_ARG_LAST);
+
+ newtCheckboxTreeAddItem(checktree, "Double digit", (void *) 300, 0,
+ 1, NEWT_ARG_APPEND, NEWT_ARG_LAST);
+ newtCheckboxTreeAddItem(checktree, "Ten", (void *) 210, 0,
+ 1, 1, NEWT_ARG_APPEND, NEWT_ARG_LAST);
+ newtCheckboxTreeAddItem(checktree, "Eleven", (void *) 211, 0,
+ 1, 1, NEWT_ARG_APPEND, NEWT_ARG_LAST);
+ newtCheckboxTreeAddItem(checktree, "Twelve", (void *) 212, 0,
+ 1, 1, NEWT_ARG_APPEND, NEWT_ARG_LAST);
+ newtCheckboxTreeAddItem(checktree, "Thirteen", (void *) 213, 0,
+ 1, 1, NEWT_ARG_APPEND, NEWT_ARG_LAST);
+
button = newtButton(-1, -1, "Exit");
grid = newtCreateGrid(1, 2);
- newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, checktree, 0, 0, 0, 0,
+ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, checktree, 0, 0, 0, 1,
NEWT_ANCHOR_RIGHT, 0);
- newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, checktree, 0, 0, 0, 0,
- 0, 0);
newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, button, 0, 0, 0, 0,
0, 0);
}
if (result)
free(result);
+
+ list = newtCheckboxTreeFindItem(checktree, (void *) 213);
+ printf("path:");
+ for (i = 0; list && list[i] != NEWT_ARG_LAST; i++)
+ printf(" %d", list[i]);
+ printf("\n");
newtFormDestroy(form);