--- /dev/null
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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;
+}
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);
("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()
print "listbox:", li.current()
print "rb:", rb.getSelection()
print "bb:", bb.buttonPressed(result)
+print "checkboxtree:", ct.getSelection()
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 },
{ "suspendcallback", setSuspendCallback, METH_VARARGS, NULL },
{ "ternary", ternaryWindow, METH_VARARGS, NULL },
{ "textbox", (PyCFunction) textWidget, METH_VARARGS, NULL },
+ { "checkboxtree", (PyCFunction) checkboxTreeWidget, METH_VARARGS, NULL },
{ NULL }
} ;
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);
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 },
{ "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 }
};
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;
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+#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;
+}