Blame checkboxtree.c

Packit 4d380f
#include <slang.h>
Packit 4d380f
#include <stdlib.h>
Packit 4d380f
#include <string.h>
Packit 4d380f
Packit 4d380f
#include "newt.h"
Packit 4d380f
#include "newt_pr.h"
Packit 4d380f
Packit 4d380f
struct items {
Packit 4d380f
    char * text;
Packit 4d380f
    const void *data;
Packit 4d380f
    unsigned char selected;
Packit 4d380f
    struct items *next;
Packit 4d380f
    struct items *prev;
Packit 4d380f
    struct items *branch;
Packit 4d380f
    int flags;
Packit 4d380f
    int depth;
Packit 4d380f
};
Packit 4d380f
Packit 4d380f
struct CheckboxTree {
Packit 4d380f
    newtComponent sb;
Packit 4d380f
    struct items * itemlist;
Packit 4d380f
    struct items ** flatList, ** currItem, ** firstItem;
Packit 4d380f
    int flatCount;
Packit 4d380f
    int flags;
Packit 4d380f
    int sbAdjust;
Packit 4d380f
    int curWidth;
Packit 4d380f
    int userHasSetWidth;
Packit 4d380f
    int isActive;
Packit 4d380f
    char * seq;
Packit 4d380f
    char * result;
Packit 4d380f
};
Packit 4d380f
Packit 4d380f
static void ctDraw(newtComponent c);
Packit 4d380f
static void ctDestroy(newtComponent co);
Packit 4d380f
static void ctPlace(newtComponent co, int newLeft, int newTop);
Packit 4d380f
struct eventResult ctEvent(newtComponent co, struct event ev);
Packit 4d380f
static void ctMapped(newtComponent co, int isMapped);
Packit 4d380f
static struct items * findItem(struct items * items, const void * data);
Packit 4d380f
static void buildFlatList(newtComponent co);
Packit 4d380f
static void doBuildFlatList(struct CheckboxTree * ct, struct items * item);
Packit 4d380f
static int countItems(struct items * item, int what);
Packit 4d380f
static inline void updateWidth(newtComponent co, struct CheckboxTree * ct,
Packit 4d380f
				int maxField);
Packit 4d380f
Packit 4d380f
static struct componentOps ctOps = {
Packit 4d380f
    ctDraw,
Packit 4d380f
    ctEvent,
Packit 4d380f
    ctDestroy,
Packit 4d380f
    ctPlace,
Packit 4d380f
    ctMapped,
Packit 4d380f
} ;
Packit 4d380f
Packit 4d380f
static inline void updateWidth(newtComponent co, struct CheckboxTree * ct,
Packit 4d380f
				int maxField) {
Packit 4d380f
    ct->curWidth = maxField;
Packit 4d380f
    co->width = ct->curWidth + ct->sbAdjust;
Packit 4d380f
Packit 4d380f
    if (ct->sb)
Packit 4d380f
	ct->sb->left = co->left + co->width - 1;
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
static int countItems(struct items * item, int what) {
Packit 4d380f
    int count = 0;
Packit 4d380f
Packit 4d380f
    while (item) {
Packit 4d380f
	if (what < 0 || (!item->branch && ((what > 0 && item->selected == what)
Packit 4d380f
		    || (what == 0 && item->selected))))
Packit 4d380f
	    count++;
Packit 4d380f
	if (item->branch && (what >= 0 || (what < 0 && item->selected)))
Packit 4d380f
	    count += countItems(item->branch, what);
Packit 4d380f
	item = item->next;
Packit 4d380f
    }
Packit 4d380f
Packit 4d380f
    return count;
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
static void doBuildFlatList(struct CheckboxTree * ct, struct items * item) {
Packit 4d380f
    while (item) {
Packit 4d380f
    	ct->flatList[ct->flatCount++] = item;
Packit 4d380f
	if (item->branch && item->selected) doBuildFlatList(ct, item->branch);
Packit 4d380f
	item = item->next;
Packit 4d380f
    }
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
/* FIXME: Check what happens on malloc failure.
Packit 4d380f
 */
Packit 4d380f
static void buildFlatList(newtComponent co) {
Packit 4d380f
    struct CheckboxTree * ct = co->data;
Packit 4d380f
Packit 4d380f
    if (ct->flatList) free(ct->flatList);
Packit 4d380f
    ct->flatCount = countItems(ct->itemlist, -1);
Packit 4d380f
Packit 4d380f
    ct->flatList = malloc(sizeof(*ct->flatList) * (ct->flatCount+1));
Packit 4d380f
    ct->flatCount = 0;
Packit 4d380f
    doBuildFlatList(ct, ct->itemlist);
Packit 4d380f
    ct->flatList[ct->flatCount] = NULL;
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
int newtCheckboxTreeAddItem(newtComponent co, 
Packit 4d380f
			    const char * text, const void * data,
Packit 4d380f
			    int flags, int index, ...) {
Packit 4d380f
    va_list argList;
Packit 4d380f
    int numIndexes;
Packit 4d380f
    int * indexes;
Packit 4d380f
    int i;
Packit 4d380f
Packit 4d380f
    va_start(argList, index);
Packit 4d380f
    numIndexes = 0;
Packit 4d380f
    i = index;
Packit 4d380f
    while (i != NEWT_ARG_LAST) {
Packit 4d380f
	numIndexes++;
Packit 4d380f
	i = va_arg(argList, int);
Packit 4d380f
    }
Packit 4d380f
Packit 4d380f
    va_end(argList);
Packit 4d380f
Packit 4d380f
    indexes = alloca(sizeof(*indexes) * (numIndexes + 1));
Packit 4d380f
    va_start(argList, index);
Packit 4d380f
    numIndexes = 0;
Packit 4d380f
    i = index;
Packit 4d380f
    while (i != NEWT_ARG_LAST) {
Packit 4d380f
	indexes[numIndexes++] = i;
Packit 4d380f
	i = va_arg(argList, int);
Packit 4d380f
    }
Packit 4d380f
    va_end(argList);
Packit 4d380f
Packit 4d380f
    indexes[numIndexes++] = NEWT_ARG_LAST;
Packit 4d380f
Packit 4d380f
    return newtCheckboxTreeAddArray(co, text, data, flags, indexes);
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
static int doFindItemPath(struct items * items, void * data, int * path, 
Packit 4d380f
			  int * len) {
Packit 4d380f
    int where = 0;
Packit 4d380f
Packit 4d380f
    while (items) {
Packit 4d380f
	if (items->data == data) {
Packit 4d380f
	    if (path) path[items->depth] = where;
Packit 4d380f
	    if (len) *len = items->depth + 1;
Packit 4d380f
	    return 1;
Packit 4d380f
	}
Packit 4d380f
Packit 4d380f
	if (items->branch && doFindItemPath(items->branch, data, path, len)) {
Packit 4d380f
	    if (path) path[items->depth] = where;
Packit 4d380f
	    return 1;
Packit 4d380f
	}
Packit 4d380f
Packit 4d380f
	items = items->next;
Packit 4d380f
	where++;
Packit 4d380f
    }
Packit 4d380f
Packit 4d380f
    return 0;
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
int * newtCheckboxTreeFindItem(newtComponent co, void * data) {
Packit 4d380f
    int len;
Packit 4d380f
    int * path;
Packit 4d380f
    struct CheckboxTree * ct = co->data;
Packit 4d380f
Packit 4d380f
    if (!doFindItemPath(ct->itemlist, data, NULL, &len)) return NULL;
Packit 4d380f
Packit 4d380f
    path = malloc(sizeof(*path) * (len + 1));
Packit 4d380f
    doFindItemPath(ct->itemlist, data, path, NULL);
Packit 4d380f
    path[len] = NEWT_ARG_LAST;
Packit 4d380f
Packit 4d380f
    return path;
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
int newtCheckboxTreeAddArray(newtComponent co, 
Packit 4d380f
			    const char * text, const void * data,
Packit 4d380f
			    int flags, int * indexes) {
Packit 4d380f
    struct items * curList, * newNode, * item = NULL;
Packit 4d380f
    struct items ** listPtr = NULL;
Packit 4d380f
    int i, index, numIndexes, width;
Packit 4d380f
    struct CheckboxTree * ct = co->data;
Packit 4d380f
Packit 4d380f
    numIndexes = 0;
Packit 4d380f
    while (indexes[numIndexes] != NEWT_ARG_LAST) numIndexes++;
Packit 4d380f
Packit 4d380f
    if (!ct->itemlist) {
Packit 4d380f
	if (numIndexes > 1) return -1;
Packit 4d380f
Packit 4d380f
    	ct->itemlist = malloc(sizeof(*ct->itemlist)); // FIXME: Error check?
Packit 4d380f
    	item = ct->itemlist;
Packit 4d380f
	item->prev = NULL;
Packit 4d380f
	item->next = NULL;
Packit 4d380f
    } else {
Packit 4d380f
	curList = ct->itemlist;
Packit 4d380f
	listPtr = &ct->itemlist;
Packit 4d380f
Packit 4d380f
	i = 0;
Packit 4d380f
	index = indexes[i];
Packit 4d380f
	while (i < numIndexes) {
Packit 4d380f
	    item = curList;
Packit 4d380f
Packit 4d380f
	    if (index == NEWT_ARG_APPEND) {
Packit 4d380f
	    	item = NULL;
Packit 4d380f
	    } else {
Packit 4d380f
		while (index && item) 
Packit 4d380f
		    item = item->next, index--;
Packit 4d380f
	    }
Packit 4d380f
Packit 4d380f
	    i++;
Packit 4d380f
	    if (i < numIndexes) {
Packit 4d380f
		if (item == NULL)
Packit 4d380f
			return -1;
Packit 4d380f
		curList = item->branch;
Packit 4d380f
		listPtr = &item->branch;
Packit 4d380f
		if (!curList && (i + 1 != numIndexes)) return -1;
Packit 4d380f
Packit 4d380f
		index = indexes[i];
Packit 4d380f
	    }
Packit 4d380f
	}
Packit 4d380f
Packit 4d380f
	if (!curList) { 			/* create a new branch */
Packit 4d380f
	    item = malloc(sizeof(*curList->prev));
Packit 4d380f
	    item->next = item->prev = NULL;
Packit 4d380f
	    *listPtr = item;
Packit 4d380f
	} else if (!item) {			/* append to end */
Packit 4d380f
	    item = curList;
Packit 4d380f
	    while (item->next) item = item->next;
Packit 4d380f
	    item->next = malloc(sizeof(*curList->prev)); // FIXME Error check
Packit 4d380f
	    item->next->prev = item;
Packit 4d380f
	    item = item->next;
Packit 4d380f
	    item->next = NULL;
Packit 4d380f
	} else { 
Packit 4d380f
	    newNode = malloc(sizeof(*newNode)); // FIXME Error check ? 
Packit 4d380f
	    newNode->prev = item->prev;
Packit 4d380f
	    newNode->next = item;
Packit 4d380f
Packit 4d380f
	    if (item->prev) item->prev->next = newNode;
Packit 4d380f
	    item->prev = newNode;
Packit 4d380f
	    item = newNode;
Packit 4d380f
	    if (!item->prev) *listPtr = item;
Packit 4d380f
	}
Packit 4d380f
    }
Packit 4d380f
    	
Packit 4d380f
    item->text = strdup(text);
Packit 4d380f
    item->data = data;
Packit 4d380f
    if (flags & NEWT_FLAG_SELECTED) {
Packit 4d380f
    	item->selected = 1;
Packit 4d380f
    } else {
Packit 4d380f
	item->selected = 0;
Packit 4d380f
    }
Packit 4d380f
    item->flags = flags;
Packit 4d380f
    item->branch = NULL;
Packit 4d380f
    item->depth = numIndexes - 1;
Packit 4d380f
Packit 4d380f
    i = 4 + (3 * item->depth);
Packit 4d380f
    width = wstrlen(text, -1);
Packit 4d380f
Packit 4d380f
    if ((ct->userHasSetWidth == 0) && ((width + i + ct->sbAdjust) > co->width)) {
Packit 4d380f
	updateWidth(co, ct, width + i);
Packit 4d380f
    }
Packit 4d380f
Packit 4d380f
    return 0;
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
static struct items * findItem(struct items * items, const void * data) {
Packit 4d380f
    struct items * i;
Packit 4d380f
Packit 4d380f
    while (items) {
Packit 4d380f
	if (items->data == data) return items;
Packit 4d380f
    	if (items->branch) {
Packit 4d380f
	    i = findItem(items->branch, data);
Packit 4d380f
	    if (i) return i;
Packit 4d380f
	}
Packit 4d380f
Packit 4d380f
	items = items->next;
Packit 4d380f
    }
Packit 4d380f
Packit 4d380f
    return NULL;
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
static void listSelected(struct items * items, int * num, const void ** list, int seqindex) {
Packit 4d380f
    while (items) {
Packit 4d380f
	if ((seqindex ? items->selected==seqindex : items->selected) && !items->branch)
Packit 4d380f
	    list[(*num)++] = (void *) items->data;
Packit 4d380f
	if (items->branch)
Packit 4d380f
	    listSelected(items->branch, num, list, seqindex);
Packit 4d380f
	items = items->next;
Packit 4d380f
    }
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
void newtCheckboxTreeSetWidth(newtComponent co, int width) {
Packit 4d380f
    struct CheckboxTree * ct = co->data;
Packit 4d380f
Packit 4d380f
    co->width = width;
Packit 4d380f
    ct->curWidth = co->width - ct->sbAdjust;
Packit 4d380f
    ct->userHasSetWidth = 1;
Packit 4d380f
    if (ct->sb) ct->sb->left = co->width + co->left - 1;
Packit 4d380f
    ctDraw(co);
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
const void ** newtCheckboxTreeGetSelection(newtComponent co, int *numitems)
Packit 4d380f
{
Packit 4d380f
    return newtCheckboxTreeGetMultiSelection(co, numitems, 0);
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
const void ** newtCheckboxTreeGetMultiSelection(newtComponent co, int *numitems, char seqnum)
Packit 4d380f
{
Packit 4d380f
    struct CheckboxTree * ct;
Packit 4d380f
    const void **retval;
Packit 4d380f
    int seqindex=0;
Packit 4d380f
Packit 4d380f
    if(!co || !numitems) return NULL;
Packit 4d380f
Packit 4d380f
    ct = co->data;
Packit 4d380f
	
Packit 4d380f
    if (seqnum) {
Packit 4d380f
	    while( ct->seq[seqindex] && ( ct->seq[seqindex] != seqnum )) seqindex++;
Packit 4d380f
    } else {
Packit 4d380f
	    seqindex = 0;
Packit 4d380f
    }
Packit 4d380f
Packit 4d380f
    *numitems = countItems(ct->itemlist, seqindex);
Packit 4d380f
    if (!*numitems) return NULL;
Packit 4d380f
    
Packit 4d380f
    retval = malloc(*numitems * sizeof(void *));
Packit 4d380f
    *numitems = 0;
Packit 4d380f
    listSelected(ct->itemlist, numitems, retval, seqindex);
Packit 4d380f
Packit 4d380f
    return retval;
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
newtComponent newtCheckboxTree(int left, int top, int height, int flags) {
Packit 4d380f
	return newtCheckboxTreeMulti(left, top, height, NULL, flags);
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
newtComponent newtCheckboxTreeMulti(int left, int top, int height, char *seq, int flags) {
Packit 4d380f
    newtComponent co;
Packit 4d380f
    struct CheckboxTree * ct;
Packit 4d380f
Packit 4d380f
    co = malloc(sizeof(*co));
Packit 4d380f
    ct = malloc(sizeof(struct CheckboxTree));
Packit 4d380f
    co->callback = NULL;
Packit 4d380f
    co->destroyCallback = NULL;
Packit 4d380f
    co->data = ct;
Packit 4d380f
    co->left = left;
Packit 4d380f
    co->top = top;
Packit 4d380f
    co->ops = &ctOps;
Packit 4d380f
    co->takesFocus = 1;
Packit 4d380f
    co->height = height;
Packit 4d380f
    co->width = 0;
Packit 4d380f
    co->isMapped = 0;
Packit 4d380f
    ct->curWidth = 0;
Packit 4d380f
    ct->isActive = 0;
Packit 4d380f
    ct->userHasSetWidth = 0;
Packit 4d380f
    ct->itemlist = NULL;
Packit 4d380f
    ct->firstItem = NULL;
Packit 4d380f
    ct->currItem = NULL;
Packit 4d380f
    ct->flatList = NULL;
Packit 4d380f
Packit 4d380f
    ct->flags = flags;
Packit 4d380f
Packit 4d380f
    if (seq)
Packit 4d380f
	ct->seq = strdup(seq);
Packit 4d380f
    else
Packit 4d380f
	ct->seq = strdup(" *");
Packit 4d380f
    if (flags & NEWT_FLAG_SCROLL) {
Packit 4d380f
	ct->sb = newtVerticalScrollbar(left, top, height,
Packit 4d380f
				       COLORSET_LISTBOX, COLORSET_ACTLISTBOX);
Packit 4d380f
	ct->sbAdjust = 2;
Packit 4d380f
    } else {
Packit 4d380f
	ct->sb = NULL;
Packit 4d380f
	ct->sbAdjust = 0;
Packit 4d380f
    }
Packit 4d380f
    
Packit 4d380f
    return co;
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
static void ctMapped(newtComponent co, int isMapped) {
Packit 4d380f
    struct CheckboxTree * ct = co->data;
Packit 4d380f
Packit 4d380f
    co->isMapped = isMapped;
Packit 4d380f
    if (ct->sb)
Packit 4d380f
	ct->sb->ops->mapped(ct->sb, isMapped);
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
static void ctPlace(newtComponent co, int newLeft, int newTop) {
Packit 4d380f
    struct CheckboxTree * ct = co->data;
Packit 4d380f
Packit 4d380f
    co->top = newTop;
Packit 4d380f
    co->left = newLeft;
Packit 4d380f
Packit 4d380f
    if (ct->sb)
Packit 4d380f
	ct->sb->ops->place(ct->sb, co->left + co->width - 1, co->top);
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
int ctSetItem(newtComponent co, struct items *item, enum newtFlagsSense sense)
Packit 4d380f
{
Packit 4d380f
    struct CheckboxTree * ct = co->data;
Packit 4d380f
    struct items * currItem;
Packit 4d380f
    struct items * firstItem;
Packit 4d380f
    
Packit 4d380f
    if (!item)
Packit 4d380f
	return 1;
Packit 4d380f
    
Packit 4d380f
    switch(sense) {
Packit 4d380f
	case NEWT_FLAGS_RESET:
Packit 4d380f
	    item->selected = 0;
Packit 4d380f
	    break;
Packit 4d380f
	case NEWT_FLAGS_SET:
Packit 4d380f
	    item->selected = 1;
Packit 4d380f
	    break;
Packit 4d380f
	case NEWT_FLAGS_TOGGLE:
Packit 4d380f
	    if (item->branch)
Packit 4d380f
	      item->selected = !item->selected;
Packit 4d380f
	    else if (!(ct->flags & NEWT_CHECKBOXTREE_UNSELECTABLE)) {
Packit 4d380f
		    item->selected++;
Packit 4d380f
		    if (item->selected==strlen(ct->seq))
Packit 4d380f
		      item->selected = 0;
Packit 4d380f
	    }
Packit 4d380f
	    break;
Packit 4d380f
    }
Packit 4d380f
Packit 4d380f
    if (item->branch) {
Packit 4d380f
    	currItem = *ct->currItem;
Packit 4d380f
	firstItem = *ct->firstItem;
Packit 4d380f
Packit 4d380f
    	buildFlatList(co);
Packit 4d380f
Packit 4d380f
    	ct->currItem = ct->flatList;
Packit 4d380f
	while (*ct->currItem != currItem) ct->currItem++;
Packit 4d380f
Packit 4d380f
    	ct->firstItem = ct->flatList;
Packit 4d380f
    	if (ct->flatCount > co->height) {
Packit 4d380f
		struct items ** last = ct->flatList + ct->flatCount - co->height;
Packit 4d380f
		while (*ct->firstItem != firstItem && ct->firstItem != last)
Packit 4d380f
		    ct->firstItem++;
Packit 4d380f
	}
Packit 4d380f
    }
Packit 4d380f
Packit 4d380f
    return 0;
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
static void ctSetItems(struct items *item, int selected)
Packit 4d380f
{
Packit 4d380f
    for (; item; item = item->next) {
Packit 4d380f
	if (!item->branch)
Packit 4d380f
	    item->selected = selected;
Packit 4d380f
	else
Packit 4d380f
	    ctSetItems(item->branch, selected);
Packit 4d380f
    }
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
static void ctDraw(newtComponent co) {
Packit 4d380f
    struct CheckboxTree * ct = co->data;
Packit 4d380f
    struct items ** item; 
Packit 4d380f
    int i, j;
Packit 4d380f
    char * spaces;
Packit 4d380f
    int currRow = co->top;
Packit 4d380f
Packit 4d380f
    if (!co->isMapped) return ;
Packit 4d380f
Packit 4d380f
    if (!ct->firstItem) {
Packit 4d380f
	buildFlatList(co);
Packit 4d380f
	ct->firstItem = ct->currItem = ct->flatList;
Packit 4d380f
    }
Packit 4d380f
Packit 4d380f
    item = ct->firstItem;
Packit 4d380f
    
Packit 4d380f
    i = 0;
Packit 4d380f
Packit 4d380f
    newtTrashScreen();
Packit 4d380f
    
Packit 4d380f
    while (*item && i < co->height) {
Packit 4d380f
	newtGotorc(co->top + i, co->left);
Packit 4d380f
	SLsmg_set_color(NEWT_COLORSET_LISTBOX);
Packit 4d380f
	for (j = 0; j < (*item)->depth; j++)
Packit 4d380f
	    SLsmg_write_string("   ");
Packit 4d380f
Packit 4d380f
	if ((*item)->branch) {
Packit 4d380f
	    if ((*item)->selected) 
Packit 4d380f
		SLsmg_write_string("<-> ");
Packit 4d380f
	    else
Packit 4d380f
		SLsmg_write_string("<+> ");
Packit 4d380f
	} else {
Packit 4d380f
	    if (ct->flags & NEWT_CHECKBOXTREE_HIDE_BOX) {
Packit 4d380f
		if ((*item)->selected)
Packit 4d380f
		    SLsmg_set_color(NEWT_COLORSET_SELLISTBOX);
Packit 4d380f
	        SLsmg_write_string("    ");
Packit 4d380f
	    } else {
Packit 4d380f
	        char tmp[5];
Packit 4d380f
	        snprintf(tmp,5,"[%c] ",ct->seq[(*item)->selected]);
Packit 4d380f
	        SLsmg_write_string(tmp);
Packit 4d380f
	    }
Packit 4d380f
	}
Packit 4d380f
	if (*item == *ct->currItem) {
Packit 4d380f
	    SLsmg_set_color(ct->isActive ?
Packit 4d380f
		    NEWT_COLORSET_ACTSELLISTBOX : NEWT_COLORSET_ACTLISTBOX);
Packit 4d380f
	    currRow = co->top + i;
Packit 4d380f
	}
Packit 4d380f
Packit 4d380f
	SLsmg_write_nstring((*item)->text, co->width - 4 - (3 * (*item)->depth));
Packit 4d380f
Packit 4d380f
	item++;
Packit 4d380f
	i++;
Packit 4d380f
    }
Packit 4d380f
Packit 4d380f
    /* There could be empty lines left (i.e. if the user closes an expanded
Packit 4d380f
       list which is the last thing in the tree, and whose elements are
Packit 4d380f
       displayed at the bottom of the screen */
Packit 4d380f
    if (i < co->height) {
Packit 4d380f
	spaces = alloca(co->width + 1);
Packit 4d380f
	memset(spaces, ' ', co->width);
Packit 4d380f
	spaces[co->width] = '\0';
Packit 4d380f
	SLsmg_set_color(NEWT_COLORSET_LISTBOX);
Packit 4d380f
Packit 4d380f
	while (i < co->height) {
Packit 4d380f
	    newtGotorc(co->top + i, co->left);
Packit 4d380f
	    SLsmg_write_nstring(spaces, co->width);
Packit 4d380f
	    i++;
Packit 4d380f
	}
Packit 4d380f
    }
Packit 4d380f
    
Packit 4d380f
    if(ct->sb) {
Packit 4d380f
	newtScrollbarSet(ct->sb, ct->currItem - ct->flatList, 
Packit 4d380f
			 ct->flatCount - 1);
Packit 4d380f
	ct->sb->ops->draw(ct->sb);
Packit 4d380f
    }
Packit 4d380f
Packit 4d380f
    newtGotorc(currRow, co->left + 
Packit 4d380f
		    (*ct->currItem ? (*ct->currItem)->depth : 0) * 3 + 4);
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
static void destroyItems(struct items * item) {
Packit 4d380f
    struct items * nextitem;
Packit 4d380f
Packit 4d380f
    while (item != NULL) {
Packit 4d380f
	nextitem = item->next;
Packit 4d380f
	free(item->text);
Packit 4d380f
	if (item->branch)
Packit 4d380f
	    destroyItems(item->branch);
Packit 4d380f
	free(item);
Packit 4d380f
	item = nextitem;
Packit 4d380f
    }
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
static void ctDestroy(newtComponent co) {
Packit 4d380f
    struct CheckboxTree * ct = co->data;
Packit 4d380f
Packit 4d380f
    destroyItems(ct->itemlist);
Packit 4d380f
    free(ct->flatList);
Packit 4d380f
    if (ct->sb)
Packit 4d380f
	ct->sb->ops->destroy(ct->sb);
Packit 4d380f
    free(ct->seq);
Packit 4d380f
    free(ct);
Packit 4d380f
    free(co);
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
static void ctEnsureLimits( struct CheckboxTree *ct ) {
Packit 4d380f
    struct items **listEnd = ct->flatList + ct->flatCount - 1;
Packit 4d380f
    if (ct->firstItem < ct->flatList)
Packit 4d380f
        ct->firstItem = ct->flatList;
Packit 4d380f
    if (ct->currItem < ct->flatList)
Packit 4d380f
        ct->currItem = ct->flatList;
Packit 4d380f
    if (ct->firstItem > listEnd) {
Packit 4d380f
        ct->firstItem = listEnd;
Packit 4d380f
        ct->currItem = listEnd;
Packit 4d380f
    }
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
struct eventResult ctEvent(newtComponent co, struct event ev) {
Packit 4d380f
    struct CheckboxTree * ct = co->data;
Packit 4d380f
    struct eventResult er;
Packit 4d380f
    struct items ** listEnd, ** lastItem;
Packit 4d380f
    int key, selnum = 1;
Packit 4d380f
Packit 4d380f
    er.result = ER_IGNORED;
Packit 4d380f
Packit 4d380f
    if(ev.when == EV_EARLY || ev.when == EV_LATE) {
Packit 4d380f
	return er;
Packit 4d380f
    }
Packit 4d380f
Packit 4d380f
    switch(ev.event) {
Packit 4d380f
    case EV_KEYPRESS:
Packit 4d380f
	key = ev.u.key;
Packit 4d380f
	if (key == (char) key && key != ' ') {
Packit 4d380f
	    for (selnum = 0; ct->seq[selnum]; selnum++)
Packit 4d380f
	    if (key == ct->seq[selnum])
Packit 4d380f
		break;
Packit 4d380f
	    if (!ct->seq[selnum])
Packit 4d380f
		switch (key) {
Packit 4d380f
		case '-': selnum = 0; break;
Packit 4d380f
		case '+':
Packit 4d380f
		case '*': selnum = 1; break;
Packit 4d380f
		}
Packit 4d380f
	    if (ct->seq[selnum])
Packit 4d380f
		key = '*';
Packit 4d380f
	}
Packit 4d380f
	switch(key) {
Packit 4d380f
	case ' ':
Packit 4d380f
	case NEWT_KEY_ENTER:
Packit 4d380f
	    ctSetItem(co, *ct->currItem, NEWT_FLAGS_TOGGLE);
Packit 4d380f
	    er.result = ER_SWALLOWED;
Packit 4d380f
	    if (!(*ct->currItem)->branch || (*ct->currItem)->selected)
Packit 4d380f
		key = NEWT_KEY_DOWN;
Packit 4d380f
	    else
Packit 4d380f
		key = '*';
Packit 4d380f
	    break;
Packit 4d380f
	case '*':
Packit 4d380f
	    if ((*ct->currItem)->branch) {
Packit 4d380f
		ctSetItems((*ct->currItem)->branch, selnum);
Packit 4d380f
		if (!(*ct->currItem)->selected)
Packit 4d380f
		    key = NEWT_KEY_DOWN;
Packit 4d380f
	    } else {
Packit 4d380f
		(*ct->currItem)->selected = selnum;
Packit 4d380f
		key = NEWT_KEY_DOWN;
Packit 4d380f
	    }
Packit 4d380f
	    er.result = ER_SWALLOWED;
Packit 4d380f
	    break;
Packit 4d380f
	}
Packit 4d380f
	switch (key) {
Packit 4d380f
	case '*':
Packit 4d380f
	    ctDraw(co);
Packit 4d380f
	    if(co->callback) co->callback(co, co->callbackData);
Packit 4d380f
	    return er;
Packit 4d380f
	case NEWT_KEY_HOME:
Packit 4d380f
	    ct->currItem = ct->flatList;
Packit 4d380f
	    ct->firstItem = ct->flatList;
Packit 4d380f
	    ctDraw(co);
Packit 4d380f
	    if(co->callback) co->callback(co, co->callbackData);
Packit 4d380f
	    er.result = ER_SWALLOWED;
Packit 4d380f
	    return er;
Packit 4d380f
	case NEWT_KEY_END:
Packit 4d380f
	    ct->currItem = ct->flatList + ct->flatCount - 1;
Packit 4d380f
	    if (ct->flatCount <= co->height)
Packit 4d380f
		ct->firstItem = ct->flatList;
Packit 4d380f
	    else
Packit 4d380f
		ct->firstItem = ct->flatList + ct->flatCount - co->height;
Packit 4d380f
	    ctDraw(co);
Packit 4d380f
	    if(co->callback) co->callback(co, co->callbackData);
Packit 4d380f
	    er.result = ER_SWALLOWED;
Packit 4d380f
	    return er;
Packit 4d380f
	case NEWT_KEY_DOWN:
Packit 4d380f
	    if (ev.u.key != NEWT_KEY_DOWN) {
Packit 4d380f
		if(co->callback) co->callback(co, co->callbackData);
Packit 4d380f
		if (strlen(ct->seq) != 2) {
Packit 4d380f
		    ctDraw(co);
Packit 4d380f
		    return er;
Packit 4d380f
		}
Packit 4d380f
	    }
Packit 4d380f
	    if ((ct->currItem - ct->flatList + 1) < ct->flatCount) {
Packit 4d380f
		ct->currItem++;
Packit 4d380f
Packit 4d380f
		if (ct->currItem - ct->firstItem >= co->height) 
Packit 4d380f
		    ct->firstItem++;
Packit 4d380f
Packit 4d380f
		ctDraw(co);
Packit 4d380f
	    } else if (ev.u.key != NEWT_KEY_DOWN)
Packit 4d380f
	        ctDraw(co);
Packit 4d380f
	    if(co->callback) co->callback(co, co->callbackData);
Packit 4d380f
	    er.result = ER_SWALLOWED;
Packit 4d380f
	    return er;
Packit 4d380f
	case NEWT_KEY_UP:
Packit 4d380f
	    if (ct->currItem != ct->flatList) {
Packit 4d380f
		ct->currItem--;
Packit 4d380f
Packit 4d380f
		if (ct->currItem < ct->firstItem)
Packit 4d380f
		    ct->firstItem = ct->currItem;
Packit 4d380f
		    
Packit 4d380f
		ctDraw(co);
Packit 4d380f
	    }
Packit 4d380f
	    er.result = ER_SWALLOWED;
Packit 4d380f
	    if(co->callback) co->callback(co, co->callbackData);
Packit 4d380f
	    return er;
Packit 4d380f
	case NEWT_KEY_PGUP:
Packit 4d380f
	    if (ct->firstItem - co->height < ct->flatList) {
Packit 4d380f
	    	ct->firstItem = ct->currItem = ct->flatList;
Packit 4d380f
	    } else {
Packit 4d380f
		ct->currItem -= co->height;
Packit 4d380f
		ct->firstItem -= co->height;
Packit 4d380f
	    }
Packit 4d380f
	    ctEnsureLimits( ct );
Packit 4d380f
Packit 4d380f
	    ctDraw(co);
Packit 4d380f
	    if(co->callback) co->callback(co, co->callbackData);
Packit 4d380f
	    er.result = ER_SWALLOWED;
Packit 4d380f
	    return er;
Packit 4d380f
	case NEWT_KEY_PGDN:
Packit 4d380f
	    listEnd = ct->flatList + ct->flatCount - 1;
Packit 4d380f
	    lastItem = ct->firstItem + co->height - 1;
Packit 4d380f
Packit 4d380f
	    if (lastItem + co->height > listEnd) {
Packit 4d380f
	    	ct->firstItem = listEnd - co->height + 1;
Packit 4d380f
		ct->currItem = listEnd;
Packit 4d380f
	    } else {
Packit 4d380f
	    	ct->currItem += co->height;
Packit 4d380f
		ct->firstItem += co->height;
Packit 4d380f
	    }
Packit 4d380f
	    ctEnsureLimits( ct );
Packit 4d380f
Packit 4d380f
	    ctDraw(co);
Packit 4d380f
	    if(co->callback) co->callback(co, co->callbackData);
Packit 4d380f
	    er.result = ER_SWALLOWED;
Packit 4d380f
	    return er;
Packit 4d380f
	}
Packit 4d380f
	break;
Packit 4d380f
Packit 4d380f
    case EV_FOCUS:
Packit 4d380f
	ct->isActive = 1;
Packit 4d380f
	ctDraw(co);
Packit 4d380f
	er.result = ER_SWALLOWED;
Packit 4d380f
	break;
Packit 4d380f
	
Packit 4d380f
    case EV_UNFOCUS:
Packit 4d380f
	ct->isActive = 0;
Packit 4d380f
	ctDraw(co);
Packit 4d380f
	er.result = ER_SWALLOWED;
Packit 4d380f
	break;
Packit 4d380f
    default:
Packit 4d380f
	break;
Packit 4d380f
    }
Packit 4d380f
Packit 4d380f
    return er;
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
const void * newtCheckboxTreeGetCurrent(newtComponent co) {
Packit 4d380f
    struct CheckboxTree * ct = co->data;
Packit 4d380f
Packit 4d380f
    if (!ct->currItem) {
Packit 4d380f
	if (ct->itemlist)
Packit 4d380f
	    return ct->itemlist->data;
Packit 4d380f
	else
Packit 4d380f
	    return NULL;
Packit 4d380f
    }
Packit 4d380f
Packit 4d380f
    return (*ct->currItem)->data;
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
void newtCheckboxTreeSetEntry(newtComponent co, const void * data, const char * text)
Packit 4d380f
{
Packit 4d380f
    struct CheckboxTree * ct;
Packit 4d380f
    struct items * item;
Packit 4d380f
    int i, width;
Packit 4d380f
Packit 4d380f
    if (!co) return;
Packit 4d380f
    ct = co->data;
Packit 4d380f
    item = findItem(ct->itemlist, data);
Packit 4d380f
    if (!item) return;
Packit 4d380f
Packit 4d380f
    free(item->text);
Packit 4d380f
    item->text = strdup(text);
Packit 4d380f
Packit 4d380f
    i = 4 + (3 * item->depth);
Packit 4d380f
Packit 4d380f
    width = wstrlen(text, -1);
Packit 4d380f
    if ((ct->userHasSetWidth == 0) && ((width + i + ct->sbAdjust) > co->width)) {
Packit 4d380f
	updateWidth(co, ct, width + i);
Packit 4d380f
    }
Packit 4d380f
Packit 4d380f
    ctDraw(co);
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
char newtCheckboxTreeGetEntryValue(newtComponent co, const void * data)
Packit 4d380f
{
Packit 4d380f
    struct CheckboxTree * ct;
Packit 4d380f
    struct items * item;
Packit 4d380f
Packit 4d380f
    if (!co) return -1;
Packit 4d380f
    ct = co->data;
Packit 4d380f
    item = findItem(ct->itemlist, data);
Packit 4d380f
    if (!item) return -1;
Packit 4d380f
    if (item->branch)
Packit 4d380f
	return item->selected ? NEWT_CHECKBOXTREE_EXPANDED : NEWT_CHECKBOXTREE_COLLAPSED;
Packit 4d380f
    else
Packit 4d380f
	return ct->seq[item->selected];
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
void newtCheckboxTreeSetEntryValue(newtComponent co, const void * data, char value)
Packit 4d380f
{
Packit 4d380f
    struct CheckboxTree * ct;
Packit 4d380f
    struct items * item;
Packit 4d380f
    int i;
Packit 4d380f
Packit 4d380f
    if (!co) return;
Packit 4d380f
    ct = co->data;
Packit 4d380f
    item = findItem(ct->itemlist, data);
Packit 4d380f
    if (!item || item->branch) return;
Packit 4d380f
Packit 4d380f
    for(i = 0; ct->seq[i]; i++)
Packit 4d380f
	if (value == ct->seq[i])
Packit 4d380f
	    break;
Packit 4d380f
Packit 4d380f
    if (!ct->seq[i]) return;
Packit 4d380f
    item->selected = i;
Packit 4d380f
Packit 4d380f
    ctDraw(co);
Packit 4d380f
}
Packit 4d380f
Packit 4d380f
Packit 4d380f
void newtCheckboxTreeSetCurrent(newtComponent co, void * data) {
Packit 4d380f
    struct CheckboxTree * ct = co->data;
Packit 4d380f
    int * path;
Packit 4d380f
    int i, j;
Packit 4d380f
    struct items * treeTop, * item;
Packit 4d380f
Packit 4d380f
    path = newtCheckboxTreeFindItem(co, data);
Packit 4d380f
    if (!path) return;
Packit 4d380f
Packit 4d380f
    /* traverse the path and turn on all of the branches to this point */
Packit 4d380f
    for (i = 0, treeTop = ct->itemlist; path[i + 1] != NEWT_ARG_LAST; i++) {
Packit 4d380f
	for (j = 0, item = treeTop; j < path[i]; j++)
Packit 4d380f
	    item = item->next;
Packit 4d380f
Packit 4d380f
	item->selected = 1;
Packit 4d380f
	treeTop = item->branch;
Packit 4d380f
    }
Packit 4d380f
Packit 4d380f
    free(path);
Packit 4d380f
    buildFlatList(co);
Packit 4d380f
	
Packit 4d380f
    item = findItem(ct->itemlist, data);
Packit 4d380f
Packit 4d380f
    i = 0;
Packit 4d380f
    while (ct->flatList[i] != item) i++;
Packit 4d380f
Packit 4d380f
    /* choose the top item */
Packit 4d380f
    j = i - (co->height / 2);
Packit 4d380f
Packit 4d380f
    if ((j + co->height) > ct->flatCount) 
Packit 4d380f
	j = ct->flatCount - co->height;
Packit 4d380f
    
Packit 4d380f
    if (j < 0)
Packit 4d380f
	j = 0;
Packit 4d380f
Packit 4d380f
    ct->firstItem = ct->flatList + j;
Packit 4d380f
    ct->currItem = ct->flatList + i;
Packit 4d380f
Packit 4d380f
    ctDraw(co);
Packit 4d380f
}