From: msw Date: Fri, 9 Jul 1999 00:42:51 +0000 (+0000) Subject: added the start of a checkbox tree widget X-Git-Tag: r0-50~41 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f06c5a99bf76e789fc2f23b22a18828eb4f900f6;p=thirdparty%2Fnewt.git added the start of a checkbox tree widget --- diff --git a/checkboxtree.c b/checkboxtree.c new file mode 100644 index 0000000..debb0bc --- /dev/null +++ b/checkboxtree.c @@ -0,0 +1,333 @@ +#include +#include +#include + +#include "newt.h" +#include "newt_pr.h" + +struct items { + char * text; + const void *data; + unsigned char selected; + struct items *next; + struct items *prev; + struct items *branch; +}; + +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; + int flags; + int pad; + char * seq; + char * result; +}; + +static void ctDraw(newtComponent c); +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 componentOps ctOps = { + ctDraw, + ctEvent, + ctDestroy, + ctPlace, + ctMapped, +} ; + +int newtCheckboxTreeAppend(newtComponent co, int selected, + const char * text, + const void * data) { + 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)); + item->prev = NULL; + } + + if ((strlen(text) + 4 + ct->pad) > co->width) { + co->width = strlen(text) + 4 + ct->pad; + } + + item->text = strdup(text); item->data = data; item->next = NULL; + item->selected = selected; + ct->numSelected += selected; + ct->numBoxes++; + return 0; +} + +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; + } + + 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; + return retval; +} + +newtComponent newtCheckboxTree(int left, int top, int height, int flags) { + newtComponent co; + struct CheckboxTree * ct; + + co = malloc(sizeof(*co)); + ct = malloc(sizeof(struct CheckboxTree)); + co->data = ct; + co->ops = &ctOps; + co->takesFocus = 1; + co->height = height; + co->width = 0; + co->isMapped = 0; + ct->numSelected = 0; + ct->currPos = 0; + ct->itemlist = NULL; + ct->numBoxes = 0; + if (flags & NEWT_FLAG_SCROLL) { + ct->sb = newtVerticalScrollbar(left, top, height, + COLORSET_LISTBOX, COLORSET_ACTLISTBOX); + ct->pad = 2; + } else { + ct->sb = NULL; + ct->pad = 0; + } + + return co; +} + +static void ctMapped(newtComponent co, int isMapped) { + struct CheckboxTree * ct = co->data; + + co->isMapped = isMapped; + if (ct->sb) + ct->sb->ops->mapped(ct->sb, isMapped); +} + +static void ctPlace(newtComponent co, int newLeft, int newTop) { + struct CheckboxTree * ct = co->data; + + co->top = newTop; + co->left = newLeft; + + if (ct->sb) + ct->sb->ops->place(ct->sb, co->left + co->width - 1, co->top); +} + +int ctSetItem(newtComponent co, struct items *item, enum newtFlagsSense sense) +{ + struct CheckboxTree * ct = co->data; + + if (!item) + return 1; + + if (item->selected) + ct->numSelected--; + + switch(sense) { + case NEWT_FLAGS_RESET: + item->selected = 0; + break; + case NEWT_FLAGS_SET: + item->selected = 1; + break; + case NEWT_FLAGS_TOGGLE: + item->selected = !item->selected; + break; + } + + if (item->selected) + ct->numSelected++; + + 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++; + } + + i = 0; + while (item && i < co->height) { + newtGotorc(co->top + i, co->left); + 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; + i++; + } + + if(ct->sb) { + newtScrollbarSet(ct->sb, pos + curr + 1, ct->numBoxes); + ct->sb->ops->draw(ct->sb); + } + + newtGotorc(co->top + curr, co->left + 1); +} + +static void ctDestroy(newtComponent co) { + struct CheckboxTree * ct = co->data; + struct items * item, * nextitem; + + nextitem = item = ct->itemlist; + + while (item != NULL) { + nextitem = item->next; + free(item->text); + free(item); + item = nextitem; + } + + free(ct); + free(co); +} + +struct eventResult ctEvent(newtComponent co, struct event ev) { + struct CheckboxTree * ct = co->data; + struct eventResult er; + struct items * item; + int i; + + er.result = ER_IGNORED; + + if(ev.when == EV_EARLY || ev.when == EV_LATE) { + return er; + } + + switch(ev.event) { + case EV_KEYPRESS: + switch(ev.u.key) { + case ' ': + case NEWT_KEY_ENTER: + 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; + 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++; + ctDraw(co); + } + break; + case NEWT_KEY_UP: + if (ct->currItem->prev) { + ct->currItem = ct->currItem->prev; + 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--; + 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; + } + 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; + } + ct->firstItem = item; + ctDraw(co); + er.result = ER_SWALLOWED; + break; + } + case EV_FOCUS: + ctDraw(co); + er.result = ER_SWALLOWED; + break; + + case EV_UNFOCUS: + ctDraw(co); + er.result = ER_SWALLOWED; + break; + default: + break; + } + + return er; +} diff --git a/newt.h b/newt.h index 1bf7203..59b9e52 100644 --- a/newt.h +++ b/newt.h @@ -161,7 +161,11 @@ 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); newtComponent newtTextboxReflowed(int left, int top, char * text, int width, int flexDown, int flexUp, int flags); diff --git a/peanuts.py b/peanuts.py index 49e56ba..c5ec8bf 100755 --- a/peanuts.py +++ b/peanuts.py @@ -13,12 +13,18 @@ rb = RadioBar(screen, (("This", "this", 0), ("That", "that", 0))) bb = ButtonBar(screen, (("Ok", "ok"), ("Cancel", "cancel"))) -g = GridForm(screen, "My Test", 1, 3) +ct = CheckboxTree(height = 5, scroll = 1) +ct.append("Foo", 1, 1) +ct.append("Bar", 2, 0) +ct.append("Bang", 3, 1) + +g = GridForm(screen, "My Test", 1, 4) g.add(li, 0, 0) g.add(rb, 0, 1, (0, 1, 0, 1)) -g.add(bb, 0, 2, growx = 1) +g.add(ct, 0, 2) +g.add(bb, 0, 3, growx = 1) -result = g.run_once() +result = g.runOnce() screen.finish() @@ -26,3 +32,4 @@ print result print "listbox:", li.current() print "rb:", rb.getSelection() print "bb:", bb.buttonPressed(result) +print "checkboxtree:", ct.getSelection() diff --git a/snackmodule.c b/snackmodule.c index 34f3d6c..a17ec5f 100644 --- a/snackmodule.c +++ b/snackmodule.c @@ -44,6 +44,7 @@ static PyObject * setSuspendCallback(PyObject * s, PyObject * args); static PyObject * reflowText(PyObject * s, PyObject * args); static snackWidget * textWidget(PyObject * s, PyObject * args); static PyObject * ternaryWindow(PyObject * s, PyObject * args); +static snackWidget * checkboxTreeWidget(PyObject * s, PyObject * args); static PyMethodDef snackModuleMethods[] = { { "button", (PyCFunction) buttonWidget, METH_VARARGS, NULL }, @@ -72,6 +73,7 @@ static PyMethodDef snackModuleMethods[] = { { "suspendcallback", setSuspendCallback, METH_VARARGS, NULL }, { "ternary", ternaryWindow, METH_VARARGS, NULL }, { "textbox", (PyCFunction) textWidget, METH_VARARGS, NULL }, + { "checkboxtree", (PyCFunction) checkboxTreeWidget, METH_VARARGS, NULL }, { NULL } } ; @@ -151,6 +153,44 @@ struct snackWidget_s { int anint; } ; +typedef struct cbSelection_t { + PyObject_HEAD; + void ** selection; + int numselected; +} cbSelection; + +static int selectionLength(PyObject * o); +PyObject * selectionItem(PyObject * o, int n); + +static PySequenceMethods selectionAsSeq = { + selectionLength, /* length */ + 0, /* concat */ + 0, /* repeat */ + selectionItem, /* item */ + 0, /* slice */ + 0, /* assign item */ + 0, /* assign slice */ +}; + +static void selectionDestructor(PyObject * s); + +static PyTypeObject cbTreeSelection = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "cbselection", /* tp_name */ + sizeof(cbSelection), /* tp_size */ + 0, /* tp_itemsize */ + selectionDestructor, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + &selectionAsSeq, /* tp_as_sequence */ + 0, /* tp_as_mapping */ +}; + static PyObject * widgetAddCallback(snackWidget * s, PyObject * args); static PyObject * widgetGetAttr(PyObject * s, char * name); static PyObject * widgetEntrySetValue(snackWidget * s, PyObject * args); @@ -161,6 +201,9 @@ static PyObject * widgetListboxIns(snackWidget * s, PyObject * args); static PyObject * widgetListboxDel(snackWidget * s, PyObject * args); static PyObject * widgetListboxGet(snackWidget * s, PyObject * args); static PyObject * widgetTextboxText(snackWidget * s, PyObject * args); +static PyObject * widgetCheckboxTreeAppend(snackWidget * s, PyObject * args); +static cbSelection * widgetCheckboxTreeGetSel(snackWidget * s, + PyObject * args); static PyMethodDef widgetMethods[] = { { "setCallback", (PyCFunction) widgetAddCallback, METH_VARARGS, NULL }, @@ -173,6 +216,10 @@ static PyMethodDef widgetMethods[] = { { "listboxSetWidth", (PyCFunction) widgetListboxSetW, METH_VARARGS, NULL }, { "listboxDeleteItem", (PyCFunction) widgetListboxDel, METH_VARARGS, NULL }, { "scaleSet", (PyCFunction) scaleSet, METH_VARARGS, NULL }, + { "checkboxtreeAppend", (PyCFunction) widgetCheckboxTreeAppend, + METH_VARARGS, NULL }, + { "checkboxtreeGetSelection", (PyCFunction) widgetCheckboxTreeGetSel, + METH_VARARGS, NULL }, { NULL } }; @@ -757,6 +804,78 @@ static PyObject * widgetListboxSetW(snackWidget * s, PyObject * args) { static void emptyDestructor(PyObject * s) { } +static snackWidget * checkboxTreeWidget(PyObject * s, PyObject * args) { + int height; + int scrollBar = 0; + snackWidget * widget; + + if (!PyArg_ParseTuple(args, "i|i", &height, &scrollBar)) + return NULL; + + widget = PyObject_NEW(snackWidget, &snackWidgetType); + widget->co = newtCheckboxTree(-1, -1, height, + scrollBar ? NEWT_FLAG_SCROLL : 0); + + widget->anint = 1; + + return widget; +} + +static PyObject * widgetCheckboxTreeAppend(snackWidget * s, PyObject * args) { + char * text; + void * key; + int selected = 0; + + if (!PyArg_ParseTuple(args, "s|i", &text, &selected)) + return NULL; + + newtCheckboxTreeAppend(s->co, selected, text, (void *) s->anint); + + return PyInt_FromLong(s->anint++); +} + +static cbSelection * widgetCheckboxTreeGetSel(snackWidget * s, + PyObject * args) { + void ** selection; + int numselected; + cbSelection * sel; + + selection = newtCheckboxTreeGetSelection(s->co, &numselected); + + sel = PyObject_NEW(cbSelection, &cbTreeSelection); + sel->selection = selection; + sel->numselected = numselected; + + return sel; +} + +static int selectionLength(PyObject * o) { + cbSelection * sel = (void *) o; + + return sel->numselected; +} + +PyObject * selectionItem(PyObject * o, int n) { + cbSelection * sel = (void *) o; + void **result; + + if (n > sel->numselected - 1 || sel->numselected == 0) { + PyErr_SetString(PyExc_IndexError, "index out of bounds"); + return NULL; + } + + result = sel->selection[n]; + + return Py_BuildValue("i", (int) result); +} + +static void selectionDestructor(PyObject * o) { + cbSelection * sel = (void *) o; + + if (sel->selection != NULL) + free(sel->selection); +} + void init_snack(void) { PyObject * d, * m; diff --git a/testtree.c b/testtree.c new file mode 100644 index 0000000..b8988e7 --- /dev/null +++ b/testtree.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include + +#include "newt.h" + +int main(void) { + newtGrid grid; + newtComponent checktree; + newtComponent button; + newtComponent form; + newtComponent answer; + void ** result, **ptr; + int numselected, i, j; + + 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); + + button = newtButton(-1, -1, "Exit"); + + grid = newtCreateGrid(1, 2); + newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, checktree, 0, 0, 0, 0, + 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); + + newtGridWrappedWindow(grid, "Checkbox Tree Test"); + newtGridFree(grid, 1); + + form = newtForm(NULL, NULL, 0); + newtFormAddComponents(form, checktree, button, NULL); + + answer = newtRunForm(form); + + newtFinished(); + + result = newtCheckboxTreeGetSelection(checktree, &numselected); + ptr = result; + if (!result || !numselected) + printf("none selected\n"); + else + printf("Current selection:\n"); + for (i = 0; i < numselected; i++) { + j = (int) *ptr++; + printf("%d\n", j); + } + if (result) + free(result); + + newtFormDestroy(form); + + return 0; +}