From: ewt Date: Mon, 12 Jul 1999 14:38:37 +0000 (+0000) Subject: reworked checkboxtree implementation to function as a tree X-Git-Tag: r0-50~37 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1e0b187b9b044b07170d7cbd5dbabc90c412a1af;p=thirdparty%2Fnewt.git reworked checkboxtree implementation to function as a tree --- diff --git a/Makefile.in b/Makefile.in index 9c907df..058e7e6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -12,7 +12,7 @@ VERSION = @VERSION@ CVSTAG = r$(subst .,-,$(VERSION)) SONAME = @VERSION@ -PROGS = test whiptail whiptcl.so testgrid +PROGS = test whiptail whiptcl.so testgrid testtree TESTOBJS = test.o NDIALOGOBJS = whiptail.o dialogboxes.o WHIPTCLOBJS = whiptcl.o dialogboxes.o @@ -54,6 +54,9 @@ test: $(TESTOBJS) $(LIBNEWT) testgrid: testgrid.o $(LIBNEWT) gcc -g -o testgrid testgrid.o $(LIBNEWT) $(LIBS) +testtree: testtree.o $(LIBNEWT) + gcc -g -o testtree testtree.o $(LIBNEWT) $(LIBS) + _snackmodule.so: snackmodule.o $(LIBNEWTSH) gcc --shared -o _snackmodule.so snackmodule.o -L . $(LIBNEWTSH) diff --git a/checkboxtree.c b/checkboxtree.c index debb0bc..159ae5c 100644 --- a/checkboxtree.c +++ b/checkboxtree.c @@ -12,20 +12,17 @@ struct items { 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; @@ -37,6 +34,11 @@ static void ctDestroy(newtComponent co); 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, @@ -46,55 +48,238 @@ static struct componentOps ctOps = { 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; } @@ -110,10 +295,10 @@ newtComponent newtCheckboxTree(int left, int top, int height, int flags) { 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); @@ -147,13 +332,11 @@ static void ctPlace(newtComponent co, int newLeft, int newTop) { 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; @@ -166,42 +349,65 @@ int ctSetItem(newtComponent co, struct items *item, enum newtFlagsSense sense) 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); } @@ -228,8 +434,7 @@ static void ctDestroy(newtComponent co) { 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; @@ -242,76 +447,58 @@ struct eventResult ctEvent(newtComponent co, struct event ev) { 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; diff --git a/newt.h b/newt.h index 59b9e52..f1358ac 100644 --- a/newt.h +++ b/newt.h @@ -31,6 +31,9 @@ extern "C" { #define NEWT_COLORSET_ACTSELLISTBOX 23 #define NEWT_COLORSET_SELLISTBOX 24 +#define NEWT_ARG_LAST -100000 +#define NEWT_ARG_APPEND -1 + struct newtColors { char * rootFg, * rootBg; char * borderFg, * borderBg; @@ -68,6 +71,7 @@ enum newtFlagsSense { NEWT_FLAGS_SET, NEWT_FLAGS_RESET, NEWT_FLAGS_TOGGLE }; #define NEWT_FLAG_NOF12 (1 << 7) #define NEWT_FLAG_MULTIPLE (1 << 8) #define NEWT_FLAG_SELECTED (1 << 9) +#define NEWT_FLAG_CHECKBOX (1 << 10) #define NEWT_FD_READ (1 << 0) #define NEWT_FD_WRITE (1 << 1) @@ -161,11 +165,17 @@ void **newtListboxGetSelection(newtComponent co, int *numitems); void newtListboxClearSelection(newtComponent co); void newtListboxSelectItem(newtComponent co, const void * key, enum newtFlagsSense sense); + newtComponent newtCheckboxTree(int left, int top, int height, int flags); void ** newtCheckboxTreeGetSelection(newtComponent co, int *numitems); -int newtCheckboxTreeAppend(newtComponent co, int selected, - const char * text, - const void * data); +/* last item is NEWT_ARG_LAST for all of these */ +int newtCheckboxTreeAddItem(newtComponent co, + const char * text, const void * data, + int flags, int index, ...); +int newtCheckboxTreeAddArray(newtComponent co, + const char * text, const void * data, + int flags, int * indexes); +int * newtCheckboxTreeFindItem(newtComponent co, void * data); newtComponent newtTextboxReflowed(int left, int top, char * text, int width, int flexDown, int flexUp, int flags); diff --git a/testtree.c b/testtree.c index b8988e7..514f562 100644 --- a/testtree.c +++ b/testtree.c @@ -13,32 +13,76 @@ int main(void) { 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); @@ -64,6 +108,12 @@ int main(void) { } 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);