diff options
author | Dexter Morgan <dmorgan@mageia.org> | 2011-06-02 20:51:35 +0000 |
---|---|---|
committer | Dexter Morgan <dmorgan@mageia.org> | 2011-06-02 20:51:35 +0000 |
commit | a9b2bdafaf625d10aef2f476aa4014fd36c846bc (patch) | |
tree | 2364afc0ee6739b59a25c44d68c9f003bcaf03d9 /mdk-stage1/newt | |
download | drakx-a9b2bdafaf625d10aef2f476aa4014fd36c846bc.tar drakx-a9b2bdafaf625d10aef2f476aa4014fd36c846bc.tar.gz drakx-a9b2bdafaf625d10aef2f476aa4014fd36c846bc.tar.bz2 drakx-a9b2bdafaf625d10aef2f476aa4014fd36c846bc.tar.xz drakx-a9b2bdafaf625d10aef2f476aa4014fd36c846bc.zip |
Branch for updates
Diffstat (limited to 'mdk-stage1/newt')
-rw-r--r-- | mdk-stage1/newt/Makefile | 42 | ||||
-rw-r--r-- | mdk-stage1/newt/button.c | 192 | ||||
-rw-r--r-- | mdk-stage1/newt/buttonbar.c | 46 | ||||
-rw-r--r-- | mdk-stage1/newt/checkbox.c | 292 | ||||
-rw-r--r-- | mdk-stage1/newt/checkboxtree.c | 714 | ||||
-rw-r--r-- | mdk-stage1/newt/entry.c | 378 | ||||
-rw-r--r-- | mdk-stage1/newt/form.c | 713 | ||||
-rw-r--r-- | mdk-stage1/newt/grid.c | 389 | ||||
-rw-r--r-- | mdk-stage1/newt/label.c | 81 | ||||
-rw-r--r-- | mdk-stage1/newt/listbox.c | 752 | ||||
-rw-r--r-- | mdk-stage1/newt/newt.c | 672 | ||||
-rw-r--r-- | mdk-stage1/newt/newt.h | 362 | ||||
-rw-r--r-- | mdk-stage1/newt/newt_pr.h | 82 | ||||
-rw-r--r-- | mdk-stage1/newt/scale.c | 72 | ||||
-rw-r--r-- | mdk-stage1/newt/scrollbar.c | 124 | ||||
-rw-r--r-- | mdk-stage1/newt/textbox.c | 409 | ||||
-rw-r--r-- | mdk-stage1/newt/windows.c | 275 |
17 files changed, 5595 insertions, 0 deletions
diff --git a/mdk-stage1/newt/Makefile b/mdk-stage1/newt/Makefile new file mode 100644 index 000000000..6750b70ec --- /dev/null +++ b/mdk-stage1/newt/Makefile @@ -0,0 +1,42 @@ + #****************************************************************************** + # + # Guillaume Cottenceau (gc@mandriva.com) + # + # Copyright 2000 Mandriva + # + # This software may be freely redistributed under the terms of the GNU + # public license. + # + # You should have received a copy of the GNU General Public License + # along with this program; if not, write to the Free Software + # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + # + #***************************************************************************** + +top_dir = .. + +include $(top_dir)/Makefile.common + + +LIBNAME = libnewt + +OBJS = newt.o button.o form.o checkbox.o entry.o label.o listbox.o scrollbar.o textbox.o scale.o grid.o windows.o buttonbar.o checkboxtree.o + +DEFS = -DVERSION=\"0.50.19\" + +INCS = -I../slang + + +TARGETS = $(LIBNAME).a + +all: $(TARGETS) + +clean: + rm -f *.o *.a + +$(LIBNAME).a: $(OBJS) + ar -cru $@ $^ + ranlib $@ + +$(OBJS): %.o: %.c + $(DIET) gcc $(CFLAGS) $(DEFS) $(INCS) $(INCLUDES) -c $< -o $@ diff --git a/mdk-stage1/newt/button.c b/mdk-stage1/newt/button.c new file mode 100644 index 000000000..d7da58175 --- /dev/null +++ b/mdk-stage1/newt/button.c @@ -0,0 +1,192 @@ +#include <slang.h> +#include <stdlib.h> +#include <string.h> + +#include "newt.h" +#include "newt_pr.h" + +struct button { + char * text; + int compact; +}; + +static void buttonDrawIt(newtComponent co, int active, int pushed); +static void buttonDrawText(newtComponent co, int active, int pushed); + +static void buttonDraw(newtComponent c); +static void buttonDestroy(newtComponent co); +static struct eventResult buttonEvent(newtComponent c, + struct event ev); +static void buttonPlace(newtComponent co, int newLeft, int newTop); + +static struct componentOps buttonOps = { + buttonDraw, + buttonEvent, + buttonDestroy, + buttonPlace, + newtDefaultMappedHandler, +} ; + +static newtComponent createButton(int left, int row, const char * text, int compact) { + newtComponent co; + struct button * bu; + + co = malloc(sizeof(*co)); + bu = malloc(sizeof(struct button)); + co->data = bu; + + bu->text = strdup(text); + bu->compact = compact; + co->ops = &buttonOps; + + if (bu->compact) { + co->height = 1; + co->width = strlen(text) + 3; + } else { + co->height = 4; + co->width = strlen(text) + 5; + } + + co->top = row; + co->left = left; + co->takesFocus = 1; + co->isMapped = 0; + + newtGotorc(co->top, co->left); + + return co; +} + +newtComponent newtCompactButton(int left, int row, const char * text) { + return createButton(left, row, text, 1); +} + +newtComponent newtButton(int left, int row, const char * text) { + return createButton(left, row, text, 0); +} + +static void buttonDestroy(newtComponent co) { + struct button * bu = co->data; + + free(bu->text); + free(bu); + free(co); +} + +static void buttonPlace(newtComponent co, int newLeft, int newTop) { + co->top = newTop; + co->left = newLeft; + + newtGotorc(co->top, co->left); +} + +static void buttonDraw(newtComponent co) { + buttonDrawIt(co, 0, 0); +} + +static void buttonDrawIt(newtComponent co, int active, int pushed) { + struct button * bu = co->data; + + if (!co->isMapped) return; + + SLsmg_set_color(NEWT_COLORSET_BUTTON); + + if (bu->compact) { + if (active) + SLsmg_set_color(NEWT_COLORSET_COMPACTBUTTON); + else + SLsmg_set_color(NEWT_COLORSET_BUTTON); + newtGotorc(co->top+ pushed, co->left + 1 + pushed); + SLsmg_write_char('<'); + SLsmg_write_string(bu->text); + SLsmg_write_char('>'); + } else { + if (pushed) { + SLsmg_set_color(NEWT_COLORSET_BUTTON); + newtDrawBox(co->left + 1, co->top + 1, co->width - 1, 3, 0); + + SLsmg_set_color(NEWT_COLORSET_WINDOW); + newtClearBox(co->left, co->top, co->width, 1); + newtClearBox(co->left, co->top, 1, co->height); + } else { + newtDrawBox(co->left, co->top, co->width - 1, 3, 1); + } + + buttonDrawText(co, active, pushed); + } +} + +static void buttonDrawText(newtComponent co, int active, int pushed) { + struct button * bu = co->data; + + if (pushed) pushed = 1; + + if (active) + SLsmg_set_color(NEWT_COLORSET_ACTBUTTON); + else + SLsmg_set_color(NEWT_COLORSET_BUTTON); + + newtGotorc(co->top + 1 + pushed, co->left + 1 + pushed); + SLsmg_write_char(' '); + SLsmg_write_string(bu->text); + SLsmg_write_char(' '); +} + +static struct eventResult buttonEvent(newtComponent co, + struct event ev) { + struct eventResult er; + struct button * bu = co->data; + er.result = ER_IGNORED; + er.u.focus = NULL; + + if (ev.when == EV_NORMAL) { + switch (ev.event) { + case EV_FOCUS: + buttonDrawIt(co, 1, 0); + er.result = ER_SWALLOWED; + break; + + case EV_UNFOCUS: + buttonDrawIt(co, 0, 0); + er.result = ER_SWALLOWED; + break; + + case EV_KEYPRESS: + if (ev.u.key == ' ' || ev.u.key == '\r') { + if (!bu->compact) { + /* look pushed */ + buttonDrawIt(co, 1, 1); + newtRefresh(); + newtDelay(150000); + buttonDrawIt(co, 1, 0); + newtRefresh(); + newtDelay(150000); + } + + er.result = ER_EXITFORM; + } else + er.result = ER_IGNORED; + break; + case EV_MOUSE: + if (ev.u.mouse.type == MOUSE_BUTTON_DOWN && + co->top <= ev.u.mouse.y && + co->top + co->height - !bu->compact > ev.u.mouse.y && + co->left <= ev.u.mouse.x && + co->left + co->width - !bu->compact > ev.u.mouse.x) { + if (!bu->compact) { + buttonDrawIt(co, 1, 1); + newtRefresh(); + newtDelay(150000); + buttonDrawIt(co, 1, 0); + newtRefresh(); + newtDelay(150000); + } + er.result = ER_EXITFORM; + } + break; + } + } else + er.result = ER_IGNORED; + + return er; +} diff --git a/mdk-stage1/newt/buttonbar.c b/mdk-stage1/newt/buttonbar.c new file mode 100644 index 000000000..45473c9d2 --- /dev/null +++ b/mdk-stage1/newt/buttonbar.c @@ -0,0 +1,46 @@ +#include <stdarg.h> + +#include "newt.h" + +/* if they try and pack more then 50 buttons, screw 'em */ +newtGrid newtButtonBarv(char * button1, newtComponent * b1comp, va_list args) { + newtGrid grid; + struct buttonInfo { + char * name; + newtComponent * compPtr; + } buttons[50]; + int num; + int i; + + buttons[0].name = button1, buttons[0].compPtr = b1comp, num = 1; + while (1) { + buttons[num].name = va_arg(args, char *); + if (!buttons[num].name) break; + buttons[num].compPtr = va_arg(args, newtComponent *); + num++; + } + + grid = newtCreateGrid(num, 1); + + for (i = 0; i < num; i++) { + *buttons[i].compPtr = newtButton(-1, -1, buttons[i].name); + newtGridSetField(grid, i, 0, NEWT_GRID_COMPONENT, + *buttons[i].compPtr, + num ? 1 : 0, 0, 0, 0, 0, 0); + } + + return grid; +} + +newtGrid newtButtonBar(char * button1, newtComponent * b1comp, ...) { + va_list args; + newtGrid grid; + + va_start(args, b1comp); + + grid = newtButtonBarv(button1, b1comp, args); + + va_end(args); + + return grid; +} diff --git a/mdk-stage1/newt/checkbox.c b/mdk-stage1/newt/checkbox.c new file mode 100644 index 000000000..643609d34 --- /dev/null +++ b/mdk-stage1/newt/checkbox.c @@ -0,0 +1,292 @@ +#include <slang.h> +#include <stdlib.h> +#include <string.h> + +#include "newt.h" +#include "newt_pr.h" + +enum type { CHECK, RADIO }; + +struct checkbox { + char * text; + char * seq; + char * result; + newtComponent prevButton, lastButton; + enum type type; + char value; + int active, inactive; + const void * data; + int flags; + int hasFocus; +}; + +static void makeActive(newtComponent co); + +static void cbDraw(newtComponent c); +static void cbDestroy(newtComponent co); +struct eventResult cbEvent(newtComponent co, struct event ev); + +static struct componentOps cbOps = { + cbDraw, + cbEvent, + cbDestroy, + newtDefaultPlaceHandler, + newtDefaultMappedHandler, +} ; + +newtComponent newtRadiobutton(int left, int top, const char * text, int isDefault, + newtComponent prevButton) { + newtComponent co; + newtComponent curr; + struct checkbox * rb; + char initialValue; + + if (isDefault) + initialValue = '*'; + else + initialValue = ' '; + + co = newtCheckbox(left, top, text, initialValue, " *", NULL); + rb = co->data; + rb->type = RADIO; + + rb->prevButton = prevButton; + + for (curr = co; curr; curr = rb->prevButton) { + rb = curr->data; + rb->lastButton = co; + } + + return co; +} + +newtComponent newtRadioGetCurrent(newtComponent setMember) { + struct checkbox * rb = setMember->data; + + setMember = rb->lastButton; + rb = setMember->data; + + while (rb && rb->value != '*') { + setMember = rb->prevButton; + if (!setMember) + return NULL; + rb = setMember->data; + } + + return setMember; +} + +char newtCheckboxGetValue(newtComponent co) { + struct checkbox * cb = co->data; + + return cb->value; +} + +void newtCheckboxSetValue(newtComponent co, char value) { + struct checkbox * cb = co->data; + + *cb->result = value; + cbDraw(co); +} + +newtComponent newtCheckbox(int left, int top, const char * text, char defValue, + const char * seq, char * result) { + newtComponent co; + struct checkbox * cb; + + if (!seq) seq = " *"; + + co = malloc(sizeof(*co)); + cb = malloc(sizeof(struct checkbox)); + co->data = cb; + cb->flags = 0; + if (result) + cb->result = result; + else + cb->result = &cb->value; + + cb->text = strdup(text); + cb->seq = strdup(seq); + cb->type = CHECK; + cb->hasFocus = 0; + cb->inactive = COLORSET_CHECKBOX; + cb->active = COLORSET_ACTCHECKBOX; + defValue ? (*cb->result = defValue) : (*cb->result = cb->seq[0]); + + co->ops = &cbOps; + + co->callback = NULL; + co->height = 1; + co->width = strlen(text) + 4; + co->top = top; + co->left = left; + co->takesFocus = 1; + + return co; +} + +void newtCheckboxSetFlags(newtComponent co, int flags, enum newtFlagsSense sense) { + struct checkbox * cb = co->data; + int row, col; + + cb->flags = newtSetFlags(cb->flags, flags, sense); + + if (!(cb->flags & NEWT_FLAG_DISABLED)) + co->takesFocus = 1; + else + co->takesFocus = 0; + + newtGetrc(&row, &col); + cbDraw(co); + newtGotorc(row, col); +} + +static void cbDraw(newtComponent c) { + struct checkbox * cb = c->data; + + if (c->top == -1 || !c->isMapped) return; + + if (cb->flags & NEWT_FLAG_DISABLED) { + cb->inactive = NEWT_COLORSET_DISENTRY; + cb->active = NEWT_COLORSET_DISENTRY; + } else { + cb->inactive = COLORSET_CHECKBOX; + cb->active = COLORSET_ACTCHECKBOX; + } + + SLsmg_set_color(cb->inactive); + + newtGotorc(c->top, c->left); + + switch (cb->type) { + case RADIO: + SLsmg_write_string("( ) "); + break; + + case CHECK: + SLsmg_write_string("[ ] "); + break; + + default: + break; + } + + SLsmg_write_string(cb->text); + + if (cb->hasFocus) + SLsmg_set_color(cb->active); + + newtGotorc(c->top, c->left + 1); + SLsmg_write_char(*cb->result); +} + +static void cbDestroy(newtComponent co) { + struct checkbox * cb = co->data; + + free(cb->text); + free(cb->seq); + free(cb); + free(co); +} + +struct eventResult cbEvent(newtComponent co, struct event ev) { + struct checkbox * cb = co->data; + struct eventResult er; + const char * cur; + er.result = ER_IGNORED; + er.u.focus = NULL; + + if (ev.when == EV_NORMAL) { + switch (ev.event) { + case EV_FOCUS: + cb->hasFocus = 1; + cbDraw(co); + er.result = ER_SWALLOWED; + break; + + case EV_UNFOCUS: + cb->hasFocus = 0; + cbDraw(co); + er.result = ER_SWALLOWED; + break; + + case EV_KEYPRESS: + if (ev.u.key == ' ') { + if (cb->type == RADIO) { + makeActive(co); + } else if (cb->type == CHECK) { + cur = strchr(cb->seq, *cb->result); + if (!cur) + *cb->result = *cb->seq; + else { + cur++; + if (! *cur) + *cb->result = *cb->seq; + else + *cb->result = *cur; + } + cbDraw(co); + er.result = ER_SWALLOWED; + + if (co->callback) + co->callback(co, co->callbackData); + } else { + er.result = ER_IGNORED; + } + } else if(ev.u.key == NEWT_KEY_ENTER) { + er.result = ER_IGNORED; + } else { + er.result = ER_IGNORED; + } + break; + case EV_MOUSE: + if (ev.u.mouse.type == MOUSE_BUTTON_DOWN) { + if (cb->type == RADIO) { + makeActive(co); + } else if (cb->type == CHECK) { + cur = strchr(cb->seq, *cb->result); + if (!cur) + *cb->result = *cb->seq; + else { + cur++; + if (! *cur) + *cb->result = *cb->seq; + else + *cb->result = *cur; + } + cbDraw(co); + er.result = ER_SWALLOWED; + + if (co->callback) + co->callback(co, co->callbackData); + } + } + } + } else + er.result = ER_IGNORED; + + return er; +} + +static void makeActive(newtComponent co) { + struct checkbox * cb = co->data; + struct checkbox * rb; + newtComponent curr; + + /* find the one that's turned off */ + curr = cb->lastButton; + rb = curr->data; + while (curr && rb->value == rb->seq[0]) { + curr = rb->prevButton; + if (curr) rb = curr->data; + } + if (curr) { + rb->value = rb->seq[0]; + cbDraw(curr); + } + cb->value = cb->seq[1]; + cbDraw(co); + + if (co->callback) + co->callback(co, co->callbackData); +} diff --git a/mdk-stage1/newt/checkboxtree.c b/mdk-stage1/newt/checkboxtree.c new file mode 100644 index 000000000..00113f23e --- /dev/null +++ b/mdk-stage1/newt/checkboxtree.c @@ -0,0 +1,714 @@ +#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; + 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 */ + struct items * itemlist; + struct items ** flatList, ** currItem, ** firstItem; + int flatCount; + 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 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=0, COUNT_SELECTED=1 }; +static int countItems(struct items * item, enum countWhat justExposed); + +static struct componentOps ctOps = { + ctDraw, + ctEvent, + ctDestroy, + ctPlace, + ctMapped, +} ; + +static int countItems(struct items * item, enum countWhat what) { + int count = 0; + + while (item) { + if ((!item->branch && item->selected == what) || (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; + + if (ct->flatList) free(ct->flatList); + ct->flatCount = countItems(ct->itemlist, COUNT_EXPOSED); + + ct->flatList = malloc(sizeof(*ct->flatList) * (ct->flatCount+1)); + ct->flatCount = 0; + doBuildFlatList(ct, ct->itemlist); + ct->flatList[ct->flatCount] = NULL; +} + +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 + 1)); + 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 = NULL; + 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; + item->next = NULL; + } 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; + + i = 4 + (3 * item->depth); + + if ((strlen(text) + i + ct->pad) > (size_t)co->width) { + co->width = strlen(text) + i + ct->pad; + } + + 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, const void ** list, int seqindex) { + while (items) { + if ((seqindex ? items->selected==seqindex : items->selected) && !items->branch) + list[(*num)++] = (void *) items->data; + if (items->branch) + listSelected(items->branch, num, list, seqindex); + items = items->next; + } +} + +const void ** newtCheckboxTreeGetSelection(newtComponent co, int *numitems) +{ + return newtCheckboxTreeGetMultiSelection(co, numitems, 0); +} + +const void ** newtCheckboxTreeGetMultiSelection(newtComponent co, int *numitems, char seqnum) +{ + struct CheckboxTree * ct; + const void **retval; + int seqindex=0; + + if(!co || !numitems) return NULL; + + ct = co->data; + + if (seqnum) { + while( ct->seq[seqindex] && ( ct->seq[seqindex] != seqnum )) seqindex++; + } else { + seqindex = 0; + } + + *numitems = countItems(ct->itemlist, (seqindex ? seqindex : COUNT_SELECTED)); + if (!*numitems) return NULL; + + retval = malloc(*numitems * sizeof(void *)); + *numitems = 0; + listSelected(ct->itemlist, numitems, retval, seqindex); + + return retval; +} + +newtComponent newtCheckboxTree(int left, int top, int height, int flags) { + return newtCheckboxTreeMulti(left, top, height, NULL, flags); +} + +newtComponent newtCheckboxTreeMulti(int left, int top, int height, char *seq, int flags) { + newtComponent co; + struct CheckboxTree * ct; + + co = malloc(sizeof(*co)); + ct = malloc(sizeof(struct CheckboxTree)); + co->callback = NULL; + co->data = ct; + co->ops = &ctOps; + co->takesFocus = 1; + co->height = height; + co->width = 0; + co->isMapped = 0; + ct->itemlist = NULL; + ct->firstItem = NULL; + ct->currItem = NULL; + ct->flatList = NULL; + if (seq) + ct->seq = strdup(seq); + else + ct->seq = strdup(" *"); + 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; + struct items * currItem; + struct items * firstItem; + + if (!item) + return 1; + + switch(sense) { + case NEWT_FLAGS_RESET: + item->selected = 0; + break; + case NEWT_FLAGS_SET: + item->selected = 1; + break; + case NEWT_FLAGS_TOGGLE: + if (item->branch) + item->selected = !item->selected; + else { + item->selected++; + if (item->selected==strlen(ct->seq)) + item->selected = 0; + } + break; + } + + if (item->branch) { + currItem = *ct->currItem; + firstItem = *ct->firstItem; + + buildFlatList(co); + + ct->currItem = ct->flatList; + while (*ct->currItem != currItem) ct->currItem++; + + ct->firstItem = ct->flatList; + if (ct->flatCount > co->height) { + struct items ** last = ct->flatList + ct->flatCount - co->height; + while (*ct->firstItem != firstItem && ct->firstItem != last) + ct->firstItem++; + } + } + + return 0; +} + +static void ctSetItems(struct items *item, int selected) +{ + for (; item; item = item->next) { + if (!item->branch) + item->selected = selected; + else + ctSetItems(item->branch, selected); + } +} + +static void ctDraw(newtComponent co) { + struct CheckboxTree * ct = co->data; + struct items ** item; + int i, j; + char * spaces = NULL; + int currRow = -1; + + 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) { + newtGotorc(co->top + i, co->left); + if (*item == *ct->currItem) { + SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX); + currRow = co->top + i; + } else + SLsmg_set_color(NEWT_COLORSET_LISTBOX); + + for (j = 0; j < (*item)->depth; j++) + SLsmg_write_string(" "); + + if ((*item)->branch) { + if ((*item)->selected) + SLsmg_write_string("<-> "); + else + SLsmg_write_string("<+> "); + } else { + char tmp[5]; + snprintf(tmp,5,"[%c] ",ct->seq[(*item)->selected]); + SLsmg_write_string(tmp); + } + + SLsmg_write_nstring((*item)->text, co->width - 4 - + (3 * (*item)->depth)); + item++; + i++; + } + + /* There could be empty lines left (i.e. if the user closes an expanded + list which is the last thing in the tree, and whose elements are + displayed at the bottom of the screen */ + if (i < co->height) { + spaces = alloca(co->width); + memset(spaces, ' ', co->width); + SLsmg_set_color(NEWT_COLORSET_LISTBOX); + } + while (i < co->height) { + newtGotorc(co->top + i, co->left); + SLsmg_write_nstring(spaces, co->width); + i++; + } + + if(ct->sb) { + newtScrollbarSet(ct->sb, ct->currItem - ct->flatList, + ct->flatCount - 1); + ct->sb->ops->draw(ct->sb); + } + + newtGotorc(currRow, 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->seq); + free(ct); + free(co); +} + +struct eventResult ctEvent(newtComponent co, struct event ev) { + struct CheckboxTree * ct = co->data; + struct eventResult er; + struct items ** listEnd, ** lastItem; + int key, selnum = 1; + + er.result = ER_IGNORED; + + if(ev.when == EV_EARLY || ev.when == EV_LATE) { + return er; + } + + switch(ev.event) { + case EV_KEYPRESS: + key = ev.u.key; + if (key == (char) key && key != ' ') { + for (selnum = 0; ct->seq[selnum]; selnum++) + if (key == ct->seq[selnum]) + break; + if (!ct->seq[selnum]) + switch (key) { + case '-': selnum = 0; break; + case '+': + case '*': selnum = 1; break; + } + if (ct->seq[selnum]) + key = '*'; + } + switch(key) { + case ' ': + case NEWT_KEY_ENTER: + ctSetItem(co, *ct->currItem, NEWT_FLAGS_TOGGLE); + er.result = ER_SWALLOWED; + if (!(*ct->currItem)->branch || (*ct->currItem)->selected) + key = NEWT_KEY_DOWN; + else + key = '*'; + break; + case '*': + if ((*ct->currItem)->branch) { + ctSetItems((*ct->currItem)->branch, selnum); + if (!(*ct->currItem)->selected) + key = NEWT_KEY_DOWN; + } else { + (*ct->currItem)->selected = selnum; + key = NEWT_KEY_DOWN; + } + er.result = ER_SWALLOWED; + break; + } + switch (key) { + case '*': + ctDraw(co); + if(co->callback) co->callback(co, co->callbackData); + return er; + case NEWT_KEY_HOME: + ct->currItem = ct->flatList; + ct->firstItem = ct->flatList; + ctDraw(co); + if(co->callback) co->callback(co, co->callbackData); + er.result = ER_SWALLOWED; + return er; + case NEWT_KEY_END: + ct->currItem = ct->flatList + ct->flatCount - 1; + if (ct->flatCount <= co->height) + ct->firstItem = ct->flatList; + else + ct->firstItem = ct->flatList + ct->flatCount - co->height; + ctDraw(co); + if(co->callback) co->callback(co, co->callbackData); + er.result = ER_SWALLOWED; + return er; + case NEWT_KEY_DOWN: + if (ev.u.key != NEWT_KEY_DOWN) { + if(co->callback) co->callback(co, co->callbackData); + if (strlen(ct->seq) != 2) { + ctDraw(co); + return er; + } + } + if ((ct->currItem - ct->flatList + 1) < ct->flatCount) { + ct->currItem++; + + if (ct->currItem - ct->firstItem >= co->height) + ct->firstItem++; + + ctDraw(co); + } else if (ev.u.key != NEWT_KEY_DOWN) + ctDraw(co); + if(co->callback) co->callback(co, co->callbackData); + er.result = ER_SWALLOWED; + return er; + case NEWT_KEY_UP: + if (ct->currItem != ct->flatList) { + ct->currItem--; + + if (ct->currItem < ct->firstItem) + ct->firstItem = ct->currItem; + + ctDraw(co); + } + er.result = ER_SWALLOWED; + if(co->callback) co->callback(co, co->callbackData); + return er; + case NEWT_KEY_PGUP: + if (ct->firstItem - co->height < ct->flatList) { + ct->firstItem = ct->currItem = ct->flatList; + } else { + ct->currItem -= co->height; + ct->firstItem -= co->height; + } + + ctDraw(co); + if(co->callback) co->callback(co, co->callbackData); + er.result = ER_SWALLOWED; + return er; + case NEWT_KEY_PGDN: + 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; + } + + ctDraw(co); + if(co->callback) co->callback(co, co->callbackData); + er.result = ER_SWALLOWED; + return er; + } + 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; +} + +const void * newtCheckboxTreeGetCurrent(newtComponent co) { + struct CheckboxTree * ct = co->data; + + if (!ct->currItem) return NULL; + return (*ct->currItem)->data; +} + +void newtCheckboxTreeSetEntry(newtComponent co, const void * data, const char * text) +{ + struct CheckboxTree * ct; + struct items * item; + int i; + + if (!co) return; + ct = co->data; + item = findItem(ct->itemlist, data); + if (!item) return; + + free(item->text); + item->text = strdup(text); + + i = 4 + (3 * item->depth); + + if ((strlen(text) + i + ct->pad) > (size_t)co->width) { + co->width = strlen(text) + i + ct->pad; + } + + ctDraw(co); +} + +char newtCheckboxTreeGetEntryValue(newtComponent co, const void * data) +{ + struct CheckboxTree * ct; + struct items * item; + + if (!co) return -1; + ct = co->data; + item = findItem(ct->itemlist, data); + if (!item) return -1; + if (item->branch) + return item->selected ? NEWT_CHECKBOXTREE_EXPANDED : NEWT_CHECKBOXTREE_COLLAPSED; + else + return ct->seq[item->selected]; +} + +void newtCheckboxTreeSetEntryValue(newtComponent co, const void * data, char value) +{ + struct CheckboxTree * ct; + struct items * item; + int i; + + if (!co) return; + ct = co->data; + item = findItem(ct->itemlist, data); + if (!item || item->branch) return; + + for(i = 0; ct->seq[i]; i++) + if (value == ct->seq[i]) + break; + + if (!ct->seq[i]) return; + item->selected = i; + + ctDraw(co); +} + diff --git a/mdk-stage1/newt/entry.c b/mdk-stage1/newt/entry.c new file mode 100644 index 000000000..0ee449cf9 --- /dev/null +++ b/mdk-stage1/newt/entry.c @@ -0,0 +1,378 @@ +#include <ctype.h> +#include <slang.h> +#include <stdlib.h> +#include <string.h> + +#include "newt.h" +#include "newt_pr.h" + +struct entry { + int flags; + char * buf; + char ** resultPtr; + int bufAlloced; + int bufUsed; /* amount of the buffer that's been used */ + int cursorPosition; /* cursor *in the string* on on screen */ + int firstChar; /* first character position being shown */ + newtEntryFilter filter; + void * filterData; +}; + +static void entryDraw(newtComponent co); +static void entryDestroy(newtComponent co); +static struct eventResult entryEvent(newtComponent co, + struct event ev); + +static struct eventResult entryHandleKey(newtComponent co, int key); + +static struct componentOps entryOps = { + entryDraw, + entryEvent, + entryDestroy, + newtDefaultPlaceHandler, + newtDefaultMappedHandler, +} ; + +void newtEntrySet(newtComponent co, const char * value, int cursorAtEnd) { + struct entry * en = co->data; + + if ((strlen(value) + 1) > (unsigned int)en->bufAlloced) { + free(en->buf); + en->bufAlloced = strlen(value) + 1; + en->buf = malloc(en->bufAlloced); + if (en->resultPtr) *en->resultPtr = en->buf; + } + memset(en->buf, 0, en->bufAlloced); /* clear the buffer */ + strcpy(en->buf, value); + en->bufUsed = strlen(value); + en->firstChar = 0; + if (cursorAtEnd) + en->cursorPosition = en->bufUsed; + else + en->cursorPosition = 0; + + entryDraw(co); +} ; + +newtComponent newtEntry(int left, int top, const char * initialValue, int width, + char ** resultPtr, int flags) { + newtComponent co; + struct entry * en; + + co = malloc(sizeof(*co)); + en = malloc(sizeof(struct entry)); + co->data = en; + + co->top = top; + co->left = left; + co->height = 1; + co->width = width; + co->isMapped = 0; + co->callback = NULL; + + co->ops = &entryOps; + + en->flags = flags; + en->cursorPosition = 0; + en->firstChar = 0; + en->bufUsed = 0; + en->bufAlloced = width + 1; + en->filter = NULL; + + if (!(en->flags & NEWT_FLAG_DISABLED)) + co->takesFocus = 1; + else + co->takesFocus = 0; + + if (initialValue && strlen(initialValue) > (unsigned int)width) { + en->bufAlloced = strlen(initialValue) + 1; + } + en->buf = malloc(en->bufAlloced); + en->resultPtr = resultPtr; + if (en->resultPtr) *en->resultPtr = en->buf; + + memset(en->buf, 0, en->bufAlloced); + if (initialValue) { + strcpy(en->buf, initialValue); + en->bufUsed = strlen(initialValue); + en->cursorPosition = en->bufUsed; + } else { + *en->buf = '\0'; + en->bufUsed = 0; + en->cursorPosition = 0; + } + + return co; +} + +static void entryDraw(newtComponent co) { + struct entry * en = co->data; + int i; + char * chptr; + int len; + + if (!co->isMapped) return; + + if (en->flags & NEWT_FLAG_DISABLED) + SLsmg_set_color(NEWT_COLORSET_DISENTRY); + else + SLsmg_set_color(NEWT_COLORSET_ENTRY); + + if (en->flags & NEWT_FLAG_HIDDEN) { + newtGotorc(co->top, co->left); + for (i = 0; i < co->width; i++) + SLsmg_write_char('_'); + newtGotorc(co->top, co->left); + + return; + } + + newtGotorc(co->top, co->left); + + if (en->cursorPosition < en->firstChar) { + /* scroll to the left */ + en->firstChar = en->cursorPosition; + } else if ((en->firstChar + co->width) <= en->cursorPosition) { + /* scroll to the right */ + en->firstChar = en->cursorPosition - co->width + 1; + } + + chptr = en->buf + en->firstChar; + + if (en->flags & NEWT_FLAG_PASSWORD) { + char *tmpptr, *p; + + tmpptr = alloca(strlen(chptr+2)); + strcpy(tmpptr, chptr); + for (p = tmpptr; *p; p++) + *p = '*'; + chptr = tmpptr; + } + + len = strlen(chptr); + + if (len <= co->width) { + i = len; + SLsmg_write_string(chptr); + while (i < co->width) { + SLsmg_write_char('_'); + i++; + } + } else { + SLsmg_write_nstring(chptr, co->width); + } + + if (en->flags & NEWT_FLAG_HIDDEN) + newtGotorc(co->top, co->left); + else + newtGotorc(co->top, co->left + (en->cursorPosition - en->firstChar)); +} + +void newtEntrySetFlags(newtComponent co, int flags, enum newtFlagsSense sense) { + struct entry * en = co->data; + int row, col; + + en->flags = newtSetFlags(en->flags, flags, sense); + + if (!(en->flags & NEWT_FLAG_DISABLED)) + co->takesFocus = 1; + else + co->takesFocus = 0; + + newtGetrc(&row, &col); + entryDraw(co); + newtGotorc(row, col); +} + +static void entryDestroy(newtComponent co) { + struct entry * en = co->data; + + free(en->buf); + free(en); + free(co); +} + +static struct eventResult entryEvent(newtComponent co, + struct event ev) { + struct entry * en = co->data; + struct eventResult er; + int ch; + er.result = ER_IGNORED; + er.u.focus = NULL; + + if (ev.when == EV_NORMAL) { + switch (ev.event) { + case EV_FOCUS: + newtCursorOn(); + if (en->flags & NEWT_FLAG_HIDDEN) + newtGotorc(co->top, co->left); + else + newtGotorc(co->top, co->left + + (en->cursorPosition - en->firstChar)); + er.result = ER_SWALLOWED; + break; + + case EV_UNFOCUS: + newtCursorOff(); + newtGotorc(0, 0); + er.result = ER_SWALLOWED; + if (co->callback) + co->callback(co, co->callbackData); + break; + + case EV_KEYPRESS: + ch = ev.u.key; + if (en->filter) + ch = en->filter(co, en->filterData, ch, en->cursorPosition); + if (ch) er = entryHandleKey(co, ch); + break; + + case EV_MOUSE: + if ((ev.u.mouse.type == MOUSE_BUTTON_DOWN) && + (en->flags ^ NEWT_FLAG_HIDDEN)) { + if (strlen(en->buf) >= (size_t) (ev.u.mouse.x - co->left)) { + en->cursorPosition = ev.u.mouse.x - co->left; + newtGotorc(co->top, + co->left +(en->cursorPosition - en->firstChar)); + } else { + en->cursorPosition = strlen(en->buf); + newtGotorc(co->top, + co->left +(en->cursorPosition - en->firstChar)); + } + } + break; + } + } else + er.result = ER_IGNORED; + + return er; +} + +static struct eventResult entryHandleKey(newtComponent co, int key) { + struct entry * en = co->data; + struct eventResult er; + char * chptr, * insPoint; + + er.result = ER_SWALLOWED; + switch (key) { + case '\r': /* Return */ + if (en->flags & NEWT_FLAG_RETURNEXIT) { + er.result = ER_EXITFORM; + } else { + er.result = ER_NEXTCOMP; + } + break; + + case '\001': /* ^A */ + case NEWT_KEY_HOME: + en->cursorPosition = 0; + break; + + case '\005': /* ^E */ + case NEWT_KEY_END: + en->cursorPosition = en->bufUsed; + break; + + case '\013': /* ^K */ + en->bufUsed = en->cursorPosition; + memset(en->buf + en->bufUsed, 0, en->bufAlloced - en->bufUsed); + break; + + case '\002': /* ^B */ + case NEWT_KEY_LEFT: + if (en->cursorPosition) + en->cursorPosition--; + break; + + case '\004': + case NEWT_KEY_DELETE: + chptr = en->buf + en->cursorPosition; + if (*chptr) { + chptr++; + while (*chptr) { + *(chptr - 1) = *chptr; + chptr++; + } + *(chptr - 1) = '\0'; + en->bufUsed--; + } + break; + + case NEWT_KEY_BKSPC: + if (en->cursorPosition) { + /* if this isn't true, there's nothing to erase */ + chptr = en->buf + en->cursorPosition; + en->bufUsed--; + en->cursorPosition--; + while (*chptr) { + *(chptr - 1) = *chptr; + chptr++; + } + *(chptr - 1) = '\0'; + } + break; + + case '\006': /* ^B */ + case NEWT_KEY_RIGHT: + if (en->cursorPosition < en->bufUsed) + en->cursorPosition++; + break; + + default: + if ((key >= 0x20 && key <= 0x7e) || (key >= 0xa0 && key <= 0xff)) { + if (!(en->flags & NEWT_FLAG_SCROLL) && en->bufUsed >= co->width) { + SLtt_beep(); + break; + } + + if ((en->bufUsed + 1) == en->bufAlloced) { + en->bufAlloced += 20; + en->buf = realloc(en->buf, en->bufAlloced); + if (en->resultPtr) *en->resultPtr = en->buf; + memset(en->buf + en->bufUsed + 1, 0, 20); + } + + if (en->cursorPosition == en->bufUsed) { + en->bufUsed++; + } else { + /* insert the new character */ + + /* chptr is the last character in the string */ + chptr = (en->buf + en->bufUsed) - 1; + if ((en->bufUsed + 1) == en->bufAlloced) { + /* this string fills the buffer, so clip it */ + chptr--; + } else + en->bufUsed++; + + insPoint = en->buf + en->cursorPosition; + + while (chptr >= insPoint) { + *(chptr + 1) = *chptr; + chptr--; + } + + } + + en->buf[en->cursorPosition++] = key; + } else { + er.result = ER_IGNORED; + } + } + + entryDraw(co); + + return er; +} + +char * newtEntryGetValue(newtComponent co) { + struct entry * en = co->data; + + return en->buf; +} + +void newtEntrySetFilter(newtComponent co, newtEntryFilter filter, void * data) { + struct entry * en = co->data; + en->filter = filter; + en->filterData = data; +} diff --git a/mdk-stage1/newt/form.c b/mdk-stage1/newt/form.c new file mode 100644 index 000000000..ad7520e95 --- /dev/null +++ b/mdk-stage1/newt/form.c @@ -0,0 +1,713 @@ +#include <unistd.h> +#include <slang.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <sys/types.h> + +#include "newt.h" +#include "newt_pr.h" + + +/**************************************************************************** + These forms handle vertical scrolling of components with a height of 1 + + Horizontal scrolling won't work, and scrolling large widgets will fail + miserably. It shouldn't be too hard to fix either of those if anyone + cares to. I only use scrolling for listboxes and text boxes though so + I didn't bother. +*****************************************************************************/ + +struct element { + int top, left; /* Actual, not virtual. These are translated */ + newtComponent co; /* into actual through vertOffset */ +}; + +struct fdInfo { + int fd; + int flags; +}; + +struct form { + int numCompsAlloced; + struct element * elements; + int numComps; + int currComp; + int fixedHeight; + int flags; + int vertOffset; + newtComponent vertBar, exitComp; + const char * help; + int numRows; + int * hotKeys; + int numHotKeys; + int background; + int beenSet; + int numFds; + struct fdInfo * fds; + int maxFd; + int timer; /* in milliseconds */ + struct timeval lastTimeout; + void * helpTag; + newtCallback helpCb; +}; + +static void gotoComponent(struct form * form, int newComp); +static struct eventResult formEvent(newtComponent co, struct event ev); +static struct eventResult sendEvent(newtComponent comp, struct event ev); +static void formPlace(newtComponent co, int left, int top); + +/* Global, ick */ +static newtCallback helpCallback; + +/* this isn't static as grid.c tests against it to find forms */ +struct componentOps formOps = { + newtDrawForm, + formEvent, + newtFormDestroy, + formPlace, + newtDefaultMappedHandler, +} ; + +static inline int componentFits(newtComponent co, int compNum) { + struct form * form = co->data; + struct element * el = form->elements + compNum; + + if ((co->top + form->vertOffset) > el->top) return 0; + if ((co->top + form->vertOffset + co->height) < + (el->top + el->co->height)) return 0; + + return 1; +} + +newtComponent newtForm(newtComponent vertBar, void * help, int flags) { + newtComponent co; + struct form * form; + + co = malloc(sizeof(*co)); + form = malloc(sizeof(*form)); + co->data = form; + co->width = 0; + co->height = 0; + co->top = -1; + co->left = -1; + co->isMapped = 0; + + co->takesFocus = 0; /* we may have 0 components */ + co->ops = &formOps; + + form->help = help; + form->flags = flags; + form->numCompsAlloced = 5; + form->numComps = 0; + form->currComp = -1; + form->vertOffset = 0; + form->fixedHeight = 0; + form->numRows = 0; + form->numFds = 0; + form->maxFd = 0; + form->fds = NULL; + form->beenSet = 0; + form->elements = malloc(sizeof(*(form->elements)) * form->numCompsAlloced); + + form->background = COLORSET_WINDOW; + form->hotKeys = malloc(sizeof(int)); + form->numHotKeys = 0; + form->timer = 0; + form->lastTimeout.tv_sec = form->lastTimeout.tv_usec = 0; + if (!(form->flags & NEWT_FLAG_NOF12)) { + newtFormAddHotKey(co, NEWT_KEY_F12); + } + + if (vertBar) + form->vertBar = vertBar; + else + form->vertBar = NULL; + + form->helpTag = help; + form->helpCb = helpCallback; + + return co; +} + +newtComponent newtFormGetCurrent(newtComponent co) { + struct form * form = co->data; + + return form->elements[form->currComp].co; +} + +void newtFormSetCurrent(newtComponent co, newtComponent subco) { + struct form * form = co->data; + int i, new; + + for (i = 0; i < form->numComps; i++) { + if (form->elements[i].co == subco) break; + } + + if (form->elements[i].co != subco) return; + new = i; + + if (co->isMapped && !componentFits(co, new)) { + gotoComponent(form, -1); + form->vertOffset = form->elements[new].top - co->top - 1; + if (form->vertOffset > (form->numRows - co->height)) + form->vertOffset = form->numRows - co->height; + } + + gotoComponent(form, new); +} + +void newtFormSetTimer(newtComponent co, int millisecs) { + struct form * form = co->data; + + form->timer = millisecs; + form->lastTimeout.tv_usec = 0; + form->lastTimeout.tv_sec = 0; +} + +void newtFormSetHeight(newtComponent co, int height) { + struct form * form = co->data; + + form->fixedHeight = 1; + co->height = height; +} + +void newtFormSetWidth(newtComponent co, int width) { + co->width = width; +} + +void newtFormAddComponent(newtComponent co, newtComponent newco) { + struct form * form = co->data; + + co->takesFocus = 1; + + if (form->numCompsAlloced == form->numComps) { + form->numCompsAlloced += 5; + form->elements = realloc(form->elements, + sizeof(*(form->elements)) * form->numCompsAlloced); + } + + /* we grab real values for these a bit later */ + form->elements[form->numComps].left = -2; + form->elements[form->numComps].top = -2; + form->elements[form->numComps].co = newco; + + if (newco->takesFocus && form->currComp == -1) + form->currComp = form->numComps; + + form->numComps++; +} + +void newtFormAddComponents(newtComponent co, ...) { + va_list ap; + newtComponent subco; + + va_start(ap, co); + + while ((subco = va_arg(ap, newtComponent))) + newtFormAddComponent(co, subco); + + va_end(ap); +} + +static void formPlace(newtComponent co, int left, int top) { + struct form * form = co->data; + int vertDelta, horizDelta; + struct element * el; + int i; + + newtFormSetSize(co); + + vertDelta = top - co->top; + horizDelta = left - co->left; + co->top = top; + co->left = left; + + for (i = 0, el = form->elements; i < form->numComps; i++, el++) { + el->co->top += vertDelta; + el->top += vertDelta; + el->co->left += horizDelta; + el->left += horizDelta; + } +} + +void newtDrawForm(newtComponent co) { + struct form * form = co->data; + struct element * el; + int i; + + newtFormSetSize(co); + + SLsmg_set_color(form->background); + newtClearBox(co->left, co->top, co->width, co->height); + for (i = 0, el = form->elements; i < form->numComps; i++, el++) { + /* the scrollbar *always* fits somewhere */ + if (el->co == form->vertBar) { + el->co->ops->mapped(el->co, 1); + el->co->ops->draw(el->co); + } else { + /* only draw it if it'll fit on the screen vertically */ + if (componentFits(co, i)) { + el->co->top = el->top - form->vertOffset; + el->co->ops->mapped(el->co, 1); + el->co->ops->draw(el->co); + } else { + el->co->ops->mapped(el->co, 0); + } + } + } + + if (form->vertBar) + newtScrollbarSet(form->vertBar, form->vertOffset, + form->numRows - co->height); +} + +static struct eventResult formEvent(newtComponent co, struct event ev) { + struct form * form = co->data; + newtComponent subco = form->elements[form->currComp].co; + int new, wrap = 0; + struct eventResult er; + int dir = 0, page = 0; + int i, num, found; + struct element * el; + + er.result = ER_IGNORED; + if (!form->numComps) return er; + + subco = form->elements[form->currComp].co; + + switch (ev.when) { + case EV_EARLY: + if (ev.event == EV_KEYPRESS) { + if (ev.u.key == NEWT_KEY_TAB) { + er.result = ER_SWALLOWED; + dir = 1; + wrap = 1; + } else if (ev.u.key == NEWT_KEY_UNTAB) { + er.result = ER_SWALLOWED; + dir = -1; + wrap = 1; + } + } + + if (form->numComps) { + i = form->currComp; + num = 0; + while (er.result == ER_IGNORED && num != form->numComps ) { + er = form->elements[i].co->ops->event(form->elements[i].co, ev); + + num++; + i++; + if (i == form->numComps) i = 0; + } + } + + break; + + case EV_NORMAL: + if (ev.event == EV_MOUSE) { + found = 0; + for (i = 0, el = form->elements; i < form->numComps; i++, el++) { + if ((el->co->top <= ev.u.mouse.y) && + (el->co->top + el->co->height > ev.u.mouse.y) && + (el->co->left <= ev.u.mouse.x) && + (el->co->left + el->co->width > ev.u.mouse.x)) { + found = 1; + if (el->co->takesFocus) { + gotoComponent(form, i); + subco = form->elements[form->currComp].co; + } + } + /* If we did not find a co to send this event to, we + should just swallow the event here. */ + } + if (!found) { + er.result = ER_SWALLOWED; + + return er; + } + } + er = subco->ops->event(subco, ev); + switch (er.result) { + case ER_NEXTCOMP: + er.result = ER_SWALLOWED; + dir = 1; + break; + + case ER_EXITFORM: + form->exitComp = subco; + break; + + default: + break; + } + break; + + case EV_LATE: + er = subco->ops->event(subco, ev); + + if (er.result == ER_IGNORED) { + switch (ev.u.key) { + case NEWT_KEY_UP: + case NEWT_KEY_LEFT: + case NEWT_KEY_BKSPC: + er.result = ER_SWALLOWED; + dir = -1; + break; + + case NEWT_KEY_DOWN: + case NEWT_KEY_RIGHT: + er.result = ER_SWALLOWED; + dir = 1; + break; + + case NEWT_KEY_PGUP: + er.result = ER_SWALLOWED; + dir = -1; + page = 1; + break; + + case NEWT_KEY_PGDN: + er.result = ER_SWALLOWED; + dir = 1; + page = 1; + break; + } + } + } + + if (dir) { + new = form->currComp; + + if (page) { + new += dir * co->height; + if (new < 0) + new = 0; + else if (new >= form->numComps) + new = (form->numComps - 1); + + while (!form->elements[new].co->takesFocus) + new = new - dir; + } else { + do { + new += dir; + + if (wrap) { + if (new < 0) + new = form->numComps - 1; + else if (new >= form->numComps) + new = 0; + } else if (new < 0 || new >= form->numComps) + return er; + } while (!form->elements[new].co->takesFocus); + } + + /* make sure this component is visible */ + if (!componentFits(co, new)) { + gotoComponent(form, -1); + + if (dir < 0) { + /* make the new component the first one */ + form->vertOffset = form->elements[new].top - co->top; + } else { + /* make the new component the last one */ + form->vertOffset = (form->elements[new].top + + form->elements[new].co->height) - + (co->top + co->height); + } + + if (form->vertOffset < 0) form->vertOffset = 0; + if (form->vertOffset > (form->numRows - co->height)) + form->vertOffset = form->numRows - co->height; + + newtDrawForm(co); + } + + gotoComponent(form, new); + er.result = ER_SWALLOWED; + } + + return er; +} + +/* this also destroys all of the components on the form */ +void newtFormDestroy(newtComponent co) { + newtComponent subco; + struct form * form = co->data; + int i; + + /* first, destroy all of the components */ + for (i = 0; i < form->numComps; i++) { + subco = form->elements[i].co; + if (subco->ops->destroy) { + subco->ops->destroy(subco); + } else { + if (subco->data) free(subco->data); + free(subco); + } + } + + if (form->hotKeys) free(form->hotKeys); + + free(form->elements); + free(form); + free(co); +} + +newtComponent newtRunForm(newtComponent co) { + struct newtExitStruct es; + + newtFormRun(co, &es); + if (es.reason == NEWT_EXIT_HOTKEY) { + if (es.u.key == NEWT_KEY_F12) { + es.reason = NEWT_EXIT_COMPONENT; + es.u.co = co; + } else { + return NULL; + } + } + + return es.u.co; +} + +void newtFormAddHotKey(newtComponent co, int key) { + struct form * form = co->data; + + form->numHotKeys++; + form->hotKeys = realloc(form->hotKeys, sizeof(int) * form->numHotKeys); + form->hotKeys[form->numHotKeys - 1] = key; +} + +void newtFormSetSize(newtComponent co) { + struct form * form = co->data; + int delta, i; + struct element * el; + + if (form->beenSet) return; + + form->beenSet = 1; + + if (!form->numComps) return; + + co->width = 0; + if (!form->fixedHeight) co->height = 0; + + co->top = form->elements[0].co->top; + co->left = form->elements[0].co->left; + for (i = 0, el = form->elements; i < form->numComps; i++, el++) { + if (el->co->ops == &formOps) + newtFormSetSize(el->co); + + el->left = el->co->left; + el->top = el->co->top; + + if (co->left > el->co->left) { + delta = co->left - el->co->left; + co->left -= delta; + co->width += delta; + } + + if (co->top > el->co->top) { + delta = co->top - el->co->top; + co->top -= delta; + if (!form->fixedHeight) + co->height += delta; + } + + if ((co->left + co->width) < (el->co->left + el->co->width)) + co->width = (el->co->left + el->co->width) - co->left; + + if (!form->fixedHeight) { + if ((co->top + co->height) < (el->co->top + el->co->height)) + co->height = (el->co->top + el->co->height) - co->top; + } + + if ((el->co->top + el->co->height - co->top) > form->numRows) { + form->numRows = el->co->top + el->co->height - co->top; + } + } +} + +void newtFormRun(newtComponent co, struct newtExitStruct * es) { + struct form * form = co->data; + struct event ev; + struct eventResult er; + int key, i, max; + int done = 0; + fd_set readSet, writeSet; + struct timeval nextTimeout, now, timeout; + + newtFormSetSize(co); + /* draw all of the components */ + newtDrawForm(co); + + if (form->currComp == -1) { + gotoComponent(form, 0); + } else + gotoComponent(form, form->currComp); + + while (!done) { + newtRefresh(); + + FD_ZERO(&readSet); + FD_ZERO(&writeSet); + FD_SET(0, &readSet); + max = form->maxFd; + + for (i = 0; i < form->numFds; i++) { + if (form->fds[i].flags & NEWT_FD_READ) + FD_SET(form->fds[i].fd, &readSet); + if (form->fds[i].flags & NEWT_FD_WRITE) + FD_SET(form->fds[i].fd, &writeSet); + } + + if (form->timer) { + /* Calculate when we next need to return with a timeout. Do + this inside the loop in case a callback resets the timer. */ + if (!form->lastTimeout.tv_sec && !form->lastTimeout.tv_usec) + gettimeofday(&form->lastTimeout, NULL); + + nextTimeout.tv_sec = form->lastTimeout.tv_sec + + (form->timer / 1000); + nextTimeout.tv_usec = form->lastTimeout.tv_usec + + (form->timer % 1000) * 1000; + + gettimeofday(&now, 0); + + if (now.tv_sec > nextTimeout.tv_sec) { + timeout.tv_sec = timeout.tv_usec = 0; + } else if (now.tv_sec == nextTimeout.tv_sec) { + timeout.tv_sec = 0; + if (now.tv_usec > nextTimeout.tv_usec) + timeout.tv_usec = 0; + else + timeout.tv_usec = nextTimeout.tv_usec - now.tv_usec; + } else if (now.tv_sec < nextTimeout.tv_sec) { + timeout.tv_sec = nextTimeout.tv_sec - now.tv_sec; + if (now.tv_usec > nextTimeout.tv_usec) + timeout.tv_sec--, + timeout.tv_usec = nextTimeout.tv_usec + 1000000 - + now.tv_usec; + else + timeout.tv_usec = nextTimeout.tv_usec - now.tv_usec; + } + } else { + timeout.tv_sec = timeout.tv_usec = 0; + } + + i = select(max + 1, &readSet, &writeSet, NULL, + form->timer ? &timeout : NULL); + if (i < 0) continue; /* ?? What should we do here? */ + + if (i == 0) { + done = 1; + es->reason = NEWT_EXIT_TIMER; + gettimeofday(&form->lastTimeout, NULL); + } else + { + if (FD_ISSET(0, &readSet)) { + + key = newtGetKey(); + + if (key == NEWT_KEY_RESIZE) { + /* newtResizeScreen(1); */ + continue; + } + + for (i = 0; i < form->numHotKeys; i++) { + if (form->hotKeys[i] == key) { + es->reason = NEWT_EXIT_HOTKEY; + es->u.key = key; + done = 1; + break; + } + } + + if (key == NEWT_KEY_F1 && form->helpTag && form->helpCb) + form->helpCb(co, form->helpTag); + + if (!done) { + ev.event = EV_KEYPRESS; + ev.u.key = key; + + er = sendEvent(co, ev); + + if (er.result == ER_EXITFORM) { + done = 1; + es->reason = NEWT_EXIT_COMPONENT; + es->u.co = form->exitComp; + } + } + } else { + es->reason = NEWT_EXIT_FDREADY; + done = 1; + } + } + } + newtRefresh(); +} + +static struct eventResult sendEvent(newtComponent co, struct event ev) { + struct eventResult er; + + ev.when = EV_EARLY; + er = co->ops->event(co, ev); + + if (er.result == ER_IGNORED) { + ev.when = EV_NORMAL; + er = co->ops->event(co, ev); + } + + if (er.result == ER_IGNORED) { + ev.when = EV_LATE; + er = co->ops->event(co, ev); + } + + return er; +} + +static void gotoComponent(struct form * form, int newComp) { + struct event ev; + + if (form->currComp != -1) { + ev.event = EV_UNFOCUS; + sendEvent(form->elements[form->currComp].co, ev); + } + + form->currComp = newComp; + + if (form->currComp != -1) { + ev.event = EV_FOCUS; + ev.when = EV_NORMAL; + sendEvent(form->elements[form->currComp].co, ev); + } +} + +void newtComponentAddCallback(newtComponent co, newtCallback f, void * data) { + co->callback = f; + co->callbackData = data; +} + +void newtComponentTakesFocus(newtComponent co, int val) { + co->takesFocus = val; +} + +void newtFormSetBackground(newtComponent co, int color) { + struct form * form = co->data; + + form->background = color; +} + +void newtFormWatchFd(newtComponent co, int fd, int fdFlags) { + struct form * form = co->data; + + form->fds = realloc(form->fds, (form->numFds + 1) * sizeof(*form->fds)); + form->fds[form->numFds].fd = fd; + form->fds[form->numFds++].flags = fdFlags; + if (form->maxFd < fd) form->maxFd = fd; +} + +void newtSetHelpCallback(newtCallback cb) { + helpCallback = cb; +} diff --git a/mdk-stage1/newt/grid.c b/mdk-stage1/newt/grid.c new file mode 100644 index 000000000..37d2b2e74 --- /dev/null +++ b/mdk-stage1/newt/grid.c @@ -0,0 +1,389 @@ +#include <alloca.h> +#include <stdlib.h> +#include <string.h> + +#include "newt.h" +#include "newt_pr.h" + +struct gridField { + enum newtGridElement type; + union { + newtGrid grid; + newtComponent co; + } u; + int padLeft, padTop, padRight, padBottom; + int anchor; + int flags; +}; + +struct grid_s { + int rows, cols; + int width, height; /* totals, -1 means unknown */ + struct gridField ** fields; +}; + +/* this is a bit of a hack */ +extern struct componentOps formOps[]; + +newtGrid newtCreateGrid(int cols, int rows) { + newtGrid grid; + + grid = malloc(sizeof(*grid)); + grid->rows = rows; + grid->cols = cols; + + grid->fields = malloc(sizeof(*grid->fields) * cols); + while (cols--) { + grid->fields[cols] = malloc(sizeof(**(grid->fields)) * rows); + memset(grid->fields[cols], 0, sizeof(**(grid->fields)) * rows); + } + + grid->width = grid->height = -1; + + return grid; +} + +void newtGridSetField(newtGrid grid, int col, int row, + enum newtGridElement type, void * val, int padLeft, + int padTop, int padRight, int padBottom, int anchor, + int flags) { + struct gridField * field = &grid->fields[col][row]; + + if (field->type == NEWT_GRID_SUBGRID) + newtGridFree(field->u.grid, 1); + + field->type = type; + field->u.co = (void *) val; + + field->padLeft = padLeft; + field->padRight = padRight; + field->padTop = padTop; + field->padBottom = padBottom; + field->anchor = anchor; + field->flags = flags; + + grid->width = grid->height = -1; +} + +static void distSpace(int extra, int items, int * list) { + int all, some, i; + + all = extra / items; + some = extra % items; + for (i = 0; i < items; i++) { + list[i] += all; + if (some) { + list[i]++; + some--; + } + } +} + +static void shuffleGrid(newtGrid grid, int left, int top, int set) { + struct gridField * field; + int row, col; + int i, j; + int minWidth, minHeight; + int * widths, * heights; + int thisLeft, thisTop; + int x, y, remx, remy; + + widths = alloca(sizeof(*widths) * grid->cols); + memset(widths, 0, sizeof(*widths) * grid->cols); + heights = alloca(sizeof(*heights) * grid->rows); + memset(heights, 0, sizeof(*heights) * grid->rows); + + minWidth = 0; + for (row = 0; row < grid->rows; row++) { + i = 0; + for (col = 0; col < grid->cols; col++) { + field = &grid->fields[col][row]; + if (field->type == NEWT_GRID_SUBGRID) { + /* we'll have to redo this later */ + if (field->u.grid->width == -1) + shuffleGrid(field->u.grid, left, top, 0); + j = field->u.grid->width; + } else if (field->type == NEWT_GRID_COMPONENT) { + if (field->u.co->ops == formOps) + newtFormSetSize(field->u.co); + j = field->u.co->width; + } else + j = 0; + + j += field->padLeft + field->padRight; + + if (j > widths[col]) widths[col] = j; + i += widths[col]; + } + + if (i > minWidth) minWidth = i; + } + + minHeight = 0; + for (col = 0; col < grid->cols; col++) { + i = 0; + for (row = 0; row < grid->rows; row++) { + field = &grid->fields[col][row]; + if (field->type == NEWT_GRID_SUBGRID) { + /* we'll have to redo this later */ + if (field->u.grid->height == -1) + shuffleGrid(field->u.grid, 0, 0, 0); + j = field->u.grid->height; + } else if (field->type == NEWT_GRID_COMPONENT){ + j = field->u.co->height; + } else + j = 0; + + j += field->padTop + field->padBottom; + + if (j > heights[row]) heights[row] = j; + i += heights[row]; + } + + if (i > minHeight) minHeight = i; + } + + /* this catches the -1 case */ + if (grid->width < minWidth) grid->width = minWidth; /* ack! */ + if (grid->height < minHeight) grid->height = minHeight; /* ditto! */ + + if (!set) return; + + distSpace(grid->width - minWidth, grid->cols, widths); + distSpace(grid->height - minHeight, grid->rows, heights); + + thisTop = top; + for (row = 0; row < grid->rows; row++) { + i = 0; + thisLeft = left; + for (col = 0; col < grid->cols; col++) { + field = &grid->fields[col][row]; + + if (field->type == NEWT_GRID_EMPTY) continue; + + x = thisLeft + field->padLeft; + remx = widths[col] - field->padLeft - field->padRight; + y = thisTop + field->padTop; + remy = heights[row] - field->padTop - field->padBottom; + + if (field->type == NEWT_GRID_SUBGRID) { + remx -= field->u.grid->width; + remy -= field->u.grid->height; + } else if (field->type == NEWT_GRID_COMPONENT) { + remx -= field->u.co->width; + remy -= field->u.co->height; + } + + if (!(field->flags & NEWT_GRID_FLAG_GROWX)) { + if (field->anchor & NEWT_ANCHOR_RIGHT) + x += remx; + else if (!(field->anchor & NEWT_ANCHOR_LEFT)) + x += (remx / 2); + } + + if (!(field->flags & NEWT_GRID_FLAG_GROWY)) { + if (field->anchor & NEWT_ANCHOR_BOTTOM) + y += remx; + else if (!(field->anchor & NEWT_ANCHOR_TOP)) + y += (remy / 2); + } + + if (field->type == NEWT_GRID_SUBGRID) { + if (field->flags & NEWT_GRID_FLAG_GROWX) + field->u.grid->width = widths[col] - field->padLeft + - field->padRight; + if (field->flags & NEWT_GRID_FLAG_GROWY) + field->u.grid->height = heights[col] - field->padTop + - field->padBottom; + + shuffleGrid(field->u.grid, x, y, 1); + } else if (field->type == NEWT_GRID_COMPONENT) { + field->u.co->ops->place(field->u.co, x, y); + } + + thisLeft += widths[col]; + } + + thisTop += heights[row]; + } +} + +void newtGridPlace(newtGrid grid, int left, int top) { + shuffleGrid(grid, left, top, 1); +} + +void newtGridFree(newtGrid grid, int recurse) { + int row, col; + + for (col = 0; col < grid->cols; col++) { + if (recurse) { + for (row = 0; row < grid->rows; row++) { + if (grid->fields[col][row].type == NEWT_GRID_SUBGRID) + newtGridFree(grid->fields[col][row].u.grid, 1); + } + } + + free(grid->fields[col]); + } + + free(grid->fields); + free(grid); +} + +void newtGridGetSize(newtGrid grid, int * width, int * height) { + if (grid->width == -1 || grid->height == -1) { + grid->width = grid->height = -1; + shuffleGrid(grid, 0, 0, 1); + } + + *width = grid->width; + *height = grid->height; +} + +void newtGridWrappedWindow(newtGrid grid, char * title) { + int width, height, offset = 0; + + newtGridGetSize(grid, &width, &height); + if ((size_t)width < strlen(title) + 2) { + offset = ((strlen(title) + 2) - width) / 2; + width = strlen(title) + 2; + } + newtCenteredWindow(width + 2, height + 2, title); + newtGridPlace(grid, 1 + offset, 1); +} + +void newtGridWrappedWindowAt(newtGrid grid, char * title, int left, int top) { + int width, height; + + newtGridGetSize(grid, &width, &height); + newtOpenWindow(left, top, width + 2, height + 2, title); + newtGridPlace(grid, 1, 1); +} + +void newtGridAddComponentsToForm(newtGrid grid, newtComponent form, + int recurse) { + int row, col; + + for (col = 0; col < grid->cols; col++) { + for (row = 0; row < grid->rows; row++) { + if (grid->fields[col][row].type == NEWT_GRID_SUBGRID && recurse) + newtGridAddComponentsToForm(grid->fields[col][row].u.grid, + form, 1); + else if (grid->fields[col][row].type == NEWT_GRID_COMPONENT) + newtFormAddComponent(form, grid->fields[col][row].u.co); + } + } +} + +/* this handles up to 50 items */ +static newtGrid stackem(int isVert, enum newtGridElement type1, void * what1, + va_list args, int close) { + struct item { + enum newtGridElement type; + void * what; + } items[50]; + int i, num; + newtGrid grid; + + items[0].type = type1, items[0].what = what1, num = 1; + while (1) { + items[num].type = va_arg(args, enum newtGridElement); + if (items[num].type == NEWT_GRID_EMPTY) break; + + items[num].what = va_arg(args, void *); + num++; + } + + grid = newtCreateGrid(isVert ? 1 : num, isVert ? num : 1); + + for (i = 0; i < num; i++) { + newtGridSetField(grid, isVert ? 0 : i, isVert ? i : 0, + items[i].type, items[i].what, + close ? 0 : (i ? (isVert ? 0 : 1) : 0), + close ? 0 : (i ? (isVert ? 1 : 0) : 0), 0, 0, 0, 0); + } + + return grid; +} + +newtGrid newtGridHCloseStacked(enum newtGridElement type1, void * what1, ...) { + va_list args; + newtGrid grid; + + va_start(args, what1); + + grid = stackem(0, type1, what1, args, 1); + + va_start(args, what1); + + return grid; +} + +newtGrid newtGridVCloseStacked(enum newtGridElement type1, void * what1, ...) { + va_list args; + newtGrid grid; + + va_start(args, what1); + + grid = stackem(1, type1, what1, args, 1); + + va_start(args, what1); + + return grid; +} + +newtGrid newtGridVStacked(enum newtGridElement type1, void * what1, ...) { + va_list args; + newtGrid grid; + + va_start(args, what1); + + grid = stackem(1, type1, what1, args, 0); + + va_start(args, what1); + + return grid; +} + +newtGrid newtGridHStacked(enum newtGridElement type1, void * what1, ...) { + va_list args; + newtGrid grid; + + va_start(args, what1); + + grid = stackem(0, type1, what1, args, 0); + + va_start(args, what1); + + return grid; +} + +newtGrid newtGridBasicWindow(newtComponent text, newtGrid middle, + newtGrid buttons) { + newtGrid grid; + + grid = newtCreateGrid(1, 3); + newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text, + 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); + newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, middle, + 0, 1, 0, 0, 0, 0); + newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons, + 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX); + + return grid; +} + +newtGrid newtGridSimpleWindow(newtComponent text, newtComponent middle, + newtGrid buttons) { + newtGrid grid; + + grid = newtCreateGrid(1, 3); + newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text, + 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); + newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, middle, + 0, 1, 0, 0, 0, 0); + newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons, + 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX); + + return grid; +} diff --git a/mdk-stage1/newt/label.c b/mdk-stage1/newt/label.c new file mode 100644 index 000000000..f1a9cebbf --- /dev/null +++ b/mdk-stage1/newt/label.c @@ -0,0 +1,81 @@ +#include <slang.h> +#include <stdlib.h> +#include <string.h> + +#include "newt.h" +#include "newt_pr.h" + +struct label { + char * text; + int length; +}; + +static void labelDraw(newtComponent co); +static void labelDestroy(newtComponent co); + +static struct componentOps labelOps = { + labelDraw, + newtDefaultEventHandler, + labelDestroy, + newtDefaultPlaceHandler, + newtDefaultMappedHandler, +} ; + +newtComponent newtLabel(int left, int top, const char * text) { + newtComponent co; + struct label * la; + + co = malloc(sizeof(*co)); + la = malloc(sizeof(struct label)); + co->data = la; + + co->ops = &labelOps; + + co->height = 1; + co->width = strlen(text); + co->top = top; + co->left = left; + co->takesFocus = 0; + + la->length = strlen(text); + la->text = strdup(text); + + return co; +} + +void newtLabelSetText(newtComponent co, const char * text) { + int newLength; + struct label * la = co->data; + + newLength = strlen(text); + if (newLength <= la->length) { + memset(la->text, ' ', la->length); + memcpy(la->text, text, newLength); + } else { + free(la->text); + la->text = strdup(text); + la->length = newLength; + co->width = newLength; + } + + labelDraw(co); +} + +static void labelDraw(newtComponent co) { + struct label * la = co->data; + + if (co->isMapped == -1) return; + + SLsmg_set_color(COLORSET_LABEL); + + newtGotorc(co->top, co->left); + SLsmg_write_string(la->text); +} + +static void labelDestroy(newtComponent co) { + struct label * la = co->data; + + free(la->text); + free(la); + free(co); +} diff --git a/mdk-stage1/newt/listbox.c b/mdk-stage1/newt/listbox.c new file mode 100644 index 000000000..0048c3782 --- /dev/null +++ b/mdk-stage1/newt/listbox.c @@ -0,0 +1,752 @@ +/* This goofed-up box whacked into shape by Elliot Lee <sopwith@cuc.edu> + (from the original listbox by Erik Troan <ewt@redhat.com>) + and contributed to newt for use under the LGPL license. + Copyright (C) 1996, 1997 Elliot Lee */ + +#include <slang.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "newt.h" +#include "newt_pr.h" + + +/* Linked list of items in the listbox */ +struct items { + char * text; + const void *data; + unsigned char isSelected; + struct items *next; +}; + +/* Holds all the relevant information for this listbox */ +struct listbox { + newtComponent sb; /* Scrollbar on right side of listbox */ + int curWidth; /* size of text w/o scrollbar or border*/ + int curHeight; /* size of text w/o border */ + int sbAdjust; + int bdxAdjust, bdyAdjust; + int numItems, numSelected; + int userHasSetWidth; + int currItem, startShowItem; /* startShowItem is the first item displayed + on the screen */ + int isActive; /* If we handle key events all the time, it seems + to do things even when they are supposed to be for + another button/whatever */ + struct items *boxItems; + int grow; + int flags; /* flags for this listbox, right now just + NEWT_FLAG_RETURNEXIT */ +}; + +static void listboxDraw(newtComponent co); +static void listboxDestroy(newtComponent co); +static struct eventResult listboxEvent(newtComponent co, struct event ev); +static void newtListboxRealSetCurrent(newtComponent co); +static void listboxPlace(newtComponent co, int newLeft, int newTop); +static inline void updateWidth(newtComponent co, struct listbox * li, + int maxField); +static void listboxMapped(newtComponent co, int isMapped); + +static struct componentOps listboxOps = { + listboxDraw, + listboxEvent, + listboxDestroy, + listboxPlace, + listboxMapped, +}; + +static void listboxMapped(newtComponent co, int isMapped) { + struct listbox * li = co->data; + + co->isMapped = isMapped; + if (li->sb) + li->sb->ops->mapped(li->sb, isMapped); +} + +static void listboxPlace(newtComponent co, int newLeft, int newTop) { + struct listbox * li = co->data; + + co->top = newTop; + co->left = newLeft; + + if (li->sb) + li->sb->ops->place(li->sb, co->left + co->width - li->bdxAdjust - 1, + co->top); +} + +newtComponent newtListbox(int left, int top, int height, int flags) { + newtComponent co, sb; + struct listbox * li; + + if (!(co = malloc(sizeof(*co)))) + return NULL; + + if (!(li = malloc(sizeof(struct listbox)))) { + free(co); + return NULL; + } + + li->boxItems = NULL; + li->numItems = 0; + li->currItem = 0; + li->numSelected = 0; + li->isActive = 0; + li->userHasSetWidth = 0; + li->startShowItem = 0; + li->sbAdjust = 0; + li->bdxAdjust = 0; + li->bdyAdjust = 0; + li->flags = flags & (NEWT_FLAG_RETURNEXIT | NEWT_FLAG_BORDER | + NEWT_FLAG_MULTIPLE); + + if (li->flags & NEWT_FLAG_BORDER) { + li->bdxAdjust = 2; + li->bdyAdjust = 1; + } + + co->height = height; + li->curHeight = co->height - (2 * li->bdyAdjust); + + if (height) { + li->grow = 0; + if (flags & NEWT_FLAG_SCROLL) { + sb = newtVerticalScrollbar(left, top + li->bdyAdjust, + li->curHeight, + COLORSET_LISTBOX, COLORSET_ACTLISTBOX); + li->sbAdjust = 3; + } else { + sb = NULL; + } + } else { + li->grow = 1; + sb = NULL; + } + + li->sb = sb; + co->data = li; + co->isMapped = 0; + co->left = left; + co->top = top; + co->ops = &listboxOps; + co->takesFocus = 1; + co->callback = NULL; + + updateWidth(co, li, 5); + + return co; +} + +static inline void updateWidth(newtComponent co, struct listbox * li, + int maxField) { + li->curWidth = maxField; + co->width = li->curWidth + li->sbAdjust + 2 * li->bdxAdjust; + + if (li->sb) + li->sb->left = co->left + co->width - li->bdxAdjust - 1; +} + +void newtListboxSetCurrentByKey(newtComponent co, void * key) { + struct listbox * li = co->data; + struct items * item; + int i; + + item = li->boxItems, i = 0; + while (item && item->data != key) + item = item->next, i++; + + if (item) + newtListboxSetCurrent(co, i); +} + +void newtListboxSetCurrent(newtComponent co, int num) +{ + struct listbox * li = co->data; + + if (num >= li->numItems) + li->currItem = li->numItems - 1; + else if (num < 0) + li->currItem = 0; + else + li->currItem = num; + + if (li->currItem < li->startShowItem) + li->startShowItem = li->currItem; + else if (li->currItem - li->startShowItem > li->curHeight - 1) + li->startShowItem = li->currItem - li->curHeight + 1; + if (li->startShowItem + li->curHeight > li->numItems) + li->startShowItem = li->numItems - li->curHeight; + if(li->startShowItem < 0) + li->startShowItem = 0; + + newtListboxRealSetCurrent(co); +} + +static void newtListboxRealSetCurrent(newtComponent co) +{ + struct listbox * li = co->data; + + if(li->sb) + newtScrollbarSet(li->sb, li->currItem + 1, li->numItems); + listboxDraw(co); + if(co->callback) co->callback(co, co->callbackData); +} + +void newtListboxSetWidth(newtComponent co, int width) { + struct listbox * li = co->data; + + co->width = width; + li->curWidth = co->width - li->sbAdjust - 2 * li->bdxAdjust; + li->userHasSetWidth = 1; + if (li->sb) li->sb->left = co->width + co->left - 1; + listboxDraw(co); +} + +void * newtListboxGetCurrent(newtComponent co) { + struct listbox * li = co->data; + int i; + struct items *item; + + for(i = 0, item = li->boxItems; item != NULL && i < li->currItem; + i++, item = item->next); + + if (item) + return (void *)item->data; + else + return NULL; +} + +void newtListboxSelectItem(newtComponent co, const void * key, + enum newtFlagsSense sense) +{ + struct listbox * li = co->data; + int i; + struct items * item; + + item = li->boxItems, i = 0; + while (item && item->data != key) + item = item->next, i++; + + if (!item) return; + + if (item->isSelected) + li->numSelected--; + + switch(sense) { + case NEWT_FLAGS_RESET: + item->isSelected = 0; break; + case NEWT_FLAGS_SET: + item->isSelected = 1; break; + case NEWT_FLAGS_TOGGLE: + item->isSelected = !item->isSelected; + } + + if (item->isSelected) + li->numSelected++; + + listboxDraw(co); +} + +void newtListboxClearSelection(newtComponent co) +{ + struct items *item; + struct listbox * li = co->data; + + for(item = li->boxItems; item != NULL; + item = item->next) + item->isSelected = 0; + li->numSelected = 0; + listboxDraw(co); +} + +/* Free the returned array after use, but NOT the values in the array */ +void ** newtListboxGetSelection(newtComponent co, int *numitems) +{ + struct listbox * li; + int i; + void **retval; + struct items *item; + + if(!co || !numitems) return NULL; + + li = co->data; + if(!li || !li->numSelected) return NULL; + + retval = malloc(li->numSelected * sizeof(void *)); + for(i = 0, item = li->boxItems; item != NULL; + item = item->next) + if(item->isSelected) + retval[i++] = (void *)item->data; + *numitems = li->numSelected; + return retval; +} + +void newtListboxSetEntry(newtComponent co, int num, const char * text) { + struct listbox * li = co->data; + int i; + struct items *item; + + for(i = 0, item = li->boxItems; item != NULL && i < num; + i++, item = item->next); + + if(!item) + return; + else { + free(item->text); + item->text = strdup(text); + } + if (li->userHasSetWidth == 0 && strlen(text) > (size_t)li->curWidth) { + updateWidth(co, li, strlen(text)); + } + + if (num >= li->startShowItem && num <= li->startShowItem + co->height) + listboxDraw(co); +} + +void newtListboxSetData(newtComponent co, int num, void * data) { + struct listbox * li = co->data; + int i; + struct items *item; + + for(i = 0, item = li->boxItems; item != NULL && i < num; + i++, item = item->next); + + item->data = data; +} + +int newtListboxAppendEntry(newtComponent co, const char * text, + const void * data) { + struct listbox * li = co->data; + struct items *item; + + if(li->boxItems) { + for (item = li->boxItems; item->next != NULL; item = item->next); + + item = item->next = malloc(sizeof(struct items)); + } else { + item = li->boxItems = malloc(sizeof(struct items)); + } + + if (!li->userHasSetWidth && text && (strlen(text) > (size_t)li->curWidth)) + updateWidth(co, li, strlen(text)); + + item->text = strdup(text); item->data = data; item->next = NULL; + item->isSelected = 0; + + if (li->grow) + co->height++, li->curHeight++; + li->numItems++; + + return 0; +} + +int newtListboxInsertEntry(newtComponent co, const char * text, + const void * data, void * key) { + struct listbox * li = co->data; + struct items *item, *t; + + if (li->boxItems) { + if (key) { + item = li->boxItems; + while (item && item->data != key) item = item->next; + + if (!item) return 1; + + t = item->next; + item = item->next = malloc(sizeof(struct items)); + item->next = t; + } else { + t = li->boxItems; + item = li->boxItems = malloc(sizeof(struct items)); + item->next = t; + } + } else if (key) { + return 1; + } else { + item = li->boxItems = malloc(sizeof(struct items)); + item->next = NULL; + } + + if (!li->userHasSetWidth && text && (strlen(text) > (size_t)li->curWidth)) + updateWidth(co, li, strlen(text)); + + item->text = strdup(text?text:"(null)"); item->data = data; + item->isSelected = 0; + + if (li->sb) + li->sb->left = co->left + co->width - li->bdxAdjust - 1; + li->numItems++; + + listboxDraw(co); + + return 0; +} + +int newtListboxDeleteEntry(newtComponent co, void * key) { + struct listbox * li = co->data; + int widest = 0, t; + struct items *item, *item2 = NULL; + int num; + + if (li->boxItems == NULL || li->numItems <= 0) + return 0; + + num = 0; + + item2 = NULL, item = li->boxItems; + while (item && item->data != key) { + item2 = item; + item = item->next; + num++; + } + + if (!item) + return -1; + + if (item2) + item2->next = item->next; + else + li->boxItems = item->next; + + free(item->text); + free(item); + li->numItems--; + + if (!li->userHasSetWidth) { + widest = 0; + for (item = li->boxItems; item != NULL; item = item->next) + if ((t = strlen(item->text)) > widest) widest = t; + } + + if (li->currItem >= num) + li->currItem--; + + if (!li->userHasSetWidth) { + updateWidth(co, li, widest); + } + + listboxDraw(co); + + return 0; +} + +void newtListboxClear(newtComponent co) +{ + struct listbox * li; + struct items *anitem, *nextitem; + if(co == NULL || (li = co->data) == NULL) + return; + for(anitem = li->boxItems; anitem != NULL; anitem = nextitem) { + nextitem = anitem->next; + free(anitem->text); + free(anitem); + } + li->numItems = li->numSelected = li->currItem = li->startShowItem = 0; + li->boxItems = NULL; + if (!li->userHasSetWidth) + updateWidth(co, li, 5); +} + +/* If you don't want to get back the text, pass in NULL for the ptr-ptr. Same + goes for the data. */ +void newtListboxGetEntry(newtComponent co, int num, char **text, void **data) { + struct listbox * li = co->data; + int i; + struct items *item; + + if (!li->boxItems || num >= li->numItems) { + if(text) + *text = NULL; + if(data) + *data = NULL; + return; + } + + i = 0; + item = li->boxItems; + while (item && i < num) { + i++, item = item->next; + } + + if (item) { + if (text) + *text = item->text; + if (data) + *data = (void *)item->data; + } +} + +static void listboxDraw(newtComponent co) +{ + struct listbox * li = co->data; + struct items *item; + int i, j; + + if (!co->isMapped) return ; + + if(li->flags & NEWT_FLAG_BORDER) { + if(li->isActive) + SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX); + else + SLsmg_set_color(NEWT_COLORSET_LISTBOX); + + newtDrawBox(co->left, co->top, co->width, co->height, 0); + } + + if(li->sb) + li->sb->ops->draw(li->sb); + + SLsmg_set_color(NEWT_COLORSET_LISTBOX); + + for(i = 0, item = li->boxItems; item != NULL && i < li->startShowItem; + i++, item = item->next); + + j = i; + + for (i = 0; item != NULL && i < li->curHeight; i++, item = item->next) { + if (!item->text) continue; + + newtGotorc(co->top + i + li->bdyAdjust, co->left + li->bdxAdjust); + if(j + i == li->currItem) { + if(item->isSelected) + SLsmg_set_color(NEWT_COLORSET_ACTSELLISTBOX); + else + SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX); + } else if(item->isSelected) + SLsmg_set_color(NEWT_COLORSET_SELLISTBOX); + else + SLsmg_set_color(NEWT_COLORSET_LISTBOX); + + SLsmg_write_nstring(item->text, li->curWidth); + + } + newtGotorc(co->top + (li->currItem - li->startShowItem), co->left); +} + +static struct eventResult listboxEvent(newtComponent co, struct event ev) { + struct eventResult er; + struct listbox * li = co->data; + 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: + if (!li->isActive) break; + + switch(ev.u.key) { + case ' ': + if(!(li->flags & NEWT_FLAG_MULTIPLE)) break; + newtListboxSelectItem(co, li->boxItems[li->currItem].data, + NEWT_FLAGS_TOGGLE); + er.result = ER_SWALLOWED; + /* We don't break here, because it is cool to be able to + hold space to select a bunch of items in a list at once */ + + case NEWT_KEY_DOWN: + if(li->numItems <= 0) break; + if(li->currItem < li->numItems - 1) { + li->currItem++; + if(li->currItem > (li->startShowItem + li->curHeight - 1)) { + li->startShowItem = li->currItem - li->curHeight + 1; + if(li->startShowItem + li->curHeight > li->numItems) + li->startShowItem = li->numItems - li->curHeight; + } + if(li->sb) + newtScrollbarSet(li->sb, li->currItem + 1, li->numItems); + listboxDraw(co); + } + if(co->callback) co->callback(co, co->callbackData); + er.result = ER_SWALLOWED; + break; + + case NEWT_KEY_ENTER: + if(li->numItems <= 0) break; + if(li->flags & NEWT_FLAG_RETURNEXIT) + er.result = ER_EXITFORM; + break; + + case NEWT_KEY_UP: + if(li->numItems <= 0) break; + if(li->currItem > 0) { + li->currItem--; + if(li->currItem < li->startShowItem) + li->startShowItem = li->currItem; + if(li->sb) + newtScrollbarSet(li->sb, li->currItem + 1, li->numItems); + listboxDraw(co); + } + if(co->callback) co->callback(co, co->callbackData); + er.result = ER_SWALLOWED; + break; + + case NEWT_KEY_PGUP: + if(li->numItems <= 0) break; + li->startShowItem -= li->curHeight - 1; + if(li->startShowItem < 0) + li->startShowItem = 0; + li->currItem -= li->curHeight - 1; + if(li->currItem < 0) + li->currItem = 0; + newtListboxRealSetCurrent(co); + er.result = ER_SWALLOWED; + break; + + case NEWT_KEY_PGDN: + if(li->numItems <= 0) break; + li->startShowItem += li->curHeight; + if(li->startShowItem > (li->numItems - li->curHeight)) { + li->startShowItem = li->numItems - li->curHeight; + } + li->currItem += li->curHeight; + if(li->currItem >= li->numItems) { + li->currItem = li->numItems - 1; + } + newtListboxRealSetCurrent(co); + er.result = ER_SWALLOWED; + break; + + case NEWT_KEY_HOME: + if(li->numItems <= 0) break; + newtListboxSetCurrent(co, 0); + er.result = ER_SWALLOWED; + break; + + case NEWT_KEY_END: + if(li->numItems <= 0) break; + li->startShowItem = li->numItems - li->curHeight; + if(li->startShowItem < 0) + li->startShowItem = 0; + li->currItem = li->numItems - 1; + newtListboxRealSetCurrent(co); + er.result = ER_SWALLOWED; + break; + default: + if (li->numItems <= 0) break; + if (ev.u.key < NEWT_KEY_EXTRA_BASE && isalpha(ev.u.key)) { + for(i = 0, item = li->boxItems; item != NULL && + i < li->currItem; i++, item = item->next); + + if (item && item->text && (toupper(*item->text) == toupper(ev.u.key))) { + item = item->next; + i++; + } else { + item = li->boxItems; + i = 0; + } + while (item && item->text && + toupper(*item->text) != toupper(ev.u.key)) { + item = item->next; + i++; + } + if (item) { + li->currItem = i; + if(li->currItem < li->startShowItem || + li->currItem > li->startShowItem) + li->startShowItem = + li->currItem > li->numItems - li->curHeight ? + li->numItems - li->curHeight : + li->currItem; + if(li->sb) + newtScrollbarSet(li->sb, li->currItem + 1, li->numItems); + newtListboxRealSetCurrent(co); + er.result = ER_SWALLOWED; + } + } + } + break; + + case EV_FOCUS: + li->isActive = 1; + listboxDraw(co); + er.result = ER_SWALLOWED; + break; + + case EV_UNFOCUS: + li->isActive = 0; + listboxDraw(co); + er.result = ER_SWALLOWED; + break; + + case EV_MOUSE: + /* if this mouse click was within the listbox, make the current + item the item clicked on. */ + /* Up scroll arrow */ + if (li->sb && + ev.u.mouse.x == co->left + co->width - li->bdxAdjust - 1 && + ev.u.mouse.y == co->top + li->bdyAdjust) { + if(li->numItems <= 0) break; + if(li->currItem > 0) { + li->currItem--; + if(li->currItem < li->startShowItem) + li->startShowItem = li->currItem; + if(li->sb) + newtScrollbarSet(li->sb, li->currItem + 1, li->numItems); + listboxDraw(co); + } + if(co->callback) co->callback(co, co->callbackData); + er.result = ER_SWALLOWED; + break; + } + /* Down scroll arrow */ + if (li->sb && + ev.u.mouse.x == co->left + co->width - li->bdxAdjust - 1 && + ev.u.mouse.y == co->top + co->height - li->bdyAdjust - 1) { + if(li->numItems <= 0) break; + if(li->currItem < li->numItems - 1) { + li->currItem++; + if(li->currItem > (li->startShowItem + li->curHeight - 1)) { + li->startShowItem = li->currItem - li->curHeight + 1; + if(li->startShowItem + li->curHeight > li->numItems) + li->startShowItem = li->numItems - li->curHeight; + } + if(li->sb) + newtScrollbarSet(li->sb, li->currItem + 1, li->numItems); + listboxDraw(co); + } + if(co->callback) co->callback(co, co->callbackData); + er.result = ER_SWALLOWED; + break; + } + if ((ev.u.mouse.y >= co->top + li->bdyAdjust) && + (ev.u.mouse.y <= co->top + co->height - (li->bdyAdjust * 2)) && + (ev.u.mouse.x >= co->left + li->bdxAdjust) && + (ev.u.mouse.x <= co->left + co->width + (li->bdxAdjust * 2))) { + li->currItem = li->startShowItem + + (ev.u.mouse.y - li->bdyAdjust - co->top); + newtListboxRealSetCurrent(co); + listboxDraw(co); + if(co->callback) co->callback(co, co->callbackData); + er.result = ER_SWALLOWED; + break; + } + } + + return er; +} + +static void listboxDestroy(newtComponent co) { + struct listbox * li = co->data; + struct items * item, * nextitem; + + nextitem = item = li->boxItems; + + while (item != NULL) { + nextitem = item->next; + free(item->text); + free(item); + item = nextitem; + } + + if (li->sb) li->sb->ops->destroy(li->sb); + + free(li); + free(co); +} diff --git a/mdk-stage1/newt/newt.c b/mdk-stage1/newt/newt.c new file mode 100644 index 000000000..8ff5e39a5 --- /dev/null +++ b/mdk-stage1/newt/newt.c @@ -0,0 +1,672 @@ +#include <slang.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/signal.h> +#include <sys/time.h> +#include <sys/types.h> +#include <termios.h> +#include <unistd.h> + +#include "newt.h" +#include "newt_pr.h" + +struct Window { + int height, width, top, left; + short * buffer; + char * title; +}; + +struct keymap { + char * str; + int code; + char * tc; +}; + +static struct Window windowStack[20]; +static struct Window * currentWindow = NULL; + +static char * helplineStack[20]; +static char ** currentHelpline = NULL; + +static int cursorRow, cursorCol; +static int needResize; +static int cursorOn = 1; + +static const char * defaultHelpLine = +" <Tab>/<Alt-Tab> between elements | <Space> selects | <F12> next screen" +; + +const struct newtColors newtDefaultColorPalette = { + "cyan", "black", /* root fg, bg */ + "black", "blue", /* border fg, bg */ + "white", "blue", /* window fg, bg */ + "white", "black", /* shadow fg, bg */ + "white", "blue", /* title fg, bg */ + "black", "cyan", /* button fg, bg */ + "yellow", "cyan", /* active button fg, bg */ + "yellow", "blue", /* checkbox fg, bg */ + "blue", "brown", /* active checkbox fg, bg */ + "yellow", "blue", /* entry box fg, bg */ + "white", "blue", /* label fg, bg */ + "black", "cyan", /* listbox fg, bg */ + "yellow", "cyan", /* active listbox fg, bg */ + "white", "blue", /* textbox fg, bg */ + "cyan", "black", /* active textbox fg, bg */ + "white", "blue", /* help line */ + "yellow", "blue", /* root text */ + "blue", /* scale full */ + "red", /* scale empty */ + "blue", "cyan", /* disabled entry fg, bg */ + "white", "blue", /* compact button fg, bg */ + "yellow", "red", /* active & sel listbox */ + "black", "brown" /* selected listbox */ +}; + +static const struct keymap keymap[] = { + { "\033OA", NEWT_KEY_UP, "kh" }, + { "\033[A", NEWT_KEY_UP, "ku" }, + { "\033OB", NEWT_KEY_DOWN, "kd" }, + { "\033[B", NEWT_KEY_DOWN, "kd" }, + { "\033[C", NEWT_KEY_RIGHT, "kr" }, + { "\033OC", NEWT_KEY_RIGHT, "kr" }, + { "\033[D", NEWT_KEY_LEFT, "kl" }, + { "\033OD", NEWT_KEY_LEFT, "kl" }, + { "\033[H", NEWT_KEY_HOME, "kh" }, + { "\033[1~", NEWT_KEY_HOME, "kh" }, + { "\033Ow", NEWT_KEY_END, "kH" }, + { "\033[4~", NEWT_KEY_END, "kH" }, + + { "\033[3~", NEWT_KEY_DELETE, "kl" }, + { "\033[2~", NEWT_KEY_INSERT, NULL }, + + { "\033\t", NEWT_KEY_UNTAB, NULL }, + + { "\033[5~", NEWT_KEY_PGUP, NULL }, + { "\033[6~", NEWT_KEY_PGDN, NULL }, + { "\033V", NEWT_KEY_PGUP, "kH" }, + { "\033v", NEWT_KEY_PGUP, "kH" }, + + { "\033[[A", NEWT_KEY_F1, NULL }, + { "\033[[B", NEWT_KEY_F2, NULL }, + { "\033[[C", NEWT_KEY_F3, NULL }, + { "\033[[D", NEWT_KEY_F4, NULL }, + { "\033[[E", NEWT_KEY_F5, NULL }, + + { "\033OP", NEWT_KEY_F1, NULL }, + { "\033OQ", NEWT_KEY_F2, NULL }, + { "\033OR", NEWT_KEY_F3, NULL }, + { "\033OS", NEWT_KEY_F4, NULL }, + + { "\033[11~", NEWT_KEY_F1, NULL }, + { "\033[12~", NEWT_KEY_F2, NULL }, + { "\033[13~", NEWT_KEY_F3, NULL }, + { "\033[14~", NEWT_KEY_F4, NULL }, + { "\033[15~", NEWT_KEY_F5, NULL }, + { "\033[17~", NEWT_KEY_F6, NULL }, + { "\033[18~", NEWT_KEY_F7, NULL }, + { "\033[19~", NEWT_KEY_F8, NULL }, + { "\033[20~", NEWT_KEY_F9, NULL }, + { "\033[21~", NEWT_KEY_F10, NULL }, + { "\033[23~", NEWT_KEY_F11, NULL }, + { "\033[24~", NEWT_KEY_F12, NULL }, + + { NULL, 0, NULL }, /* LEAVE this one */ +}; +static char keyPrefix = '\033'; + +static const char * version = "Newt windowing library version " VERSION + " - (C) 1996-2000 Red Hat Software. " + "Redistributable under the term of the Library " + "GNU Public License. " + "Written by Erik Troan\n"; + +static newtSuspendCallback suspendCallback = NULL; +static void * suspendCallbackData = NULL; + +void newtSetSuspendCallback(newtSuspendCallback cb, void * data) { + suspendCallback = cb; + suspendCallbackData = data; +} + +static void handleSigwinch(int signum __attribute__ ((unused))) { + needResize = 1; +} + +static int getkeyInterruptHook(void) { + return -1; +} + +void newtFlushInput(void) { + while (SLang_input_pending(0)) { + SLang_getkey(); + } +} + +void newtRefresh(void) { + SLsmg_refresh(); +} + +void newtSuspend(void) { + SLtt_set_cursor_visibility (1); + SLsmg_suspend_smg(); + SLang_reset_tty(); + SLtt_set_cursor_visibility (cursorOn); +} + +void newtResume(void) { + SLsmg_resume_smg (); + SLsmg_refresh(); + SLang_init_tty(0, 0, 0); +} + +void newtCls(void) { + SLsmg_set_color(NEWT_COLORSET_ROOT); + SLsmg_gotorc(0, 0); + SLsmg_erase_eos(); + + newtRefresh(); +} + +#if defined(THIS_DOESNT_WORK) +void newtResizeScreen(int redraw) { + newtPushHelpLine(""); + + SLtt_get_screen_size(); + SLang_init_tty(0, 0, 0); + + SLsmg_touch_lines (0, SLtt_Screen_Rows - 1); + + /* I don't know why I need this */ + SLsmg_refresh(); + + newtPopHelpLine(); + + if (redraw) + SLsmg_refresh(); +} +#endif + +int newtInit(void) { + char * MonoValue, * MonoEnv = "NEWT_MONO"; + + /* use the version variable just to be sure it gets included */ + (void) strlen(version); + + SLtt_get_terminfo(); + SLtt_get_screen_size(); + + MonoValue = getenv(MonoEnv); + if ( MonoValue == NULL ) { + SLtt_Use_Ansi_Colors = 1; + } else { + SLtt_Use_Ansi_Colors = 0; + } + + SLsmg_init_smg(); + SLang_init_tty(0, 0, 0); + + newtSetColors(newtDefaultColorPalette); + newtCursorOff(); + /*initKeymap();*/ + + /*memset(&sa, 0, sizeof(sa)); + sa.sa_handler = handleSigwinch; + sigaction(SIGWINCH, &sa, NULL);*/ + + SLsignal_intr(SIGWINCH, handleSigwinch); + SLang_getkey_intr_hook = getkeyInterruptHook; + + + + return 0; +} + +int newtFinished(void) { + SLsmg_gotorc(SLtt_Screen_Rows - 1, 0); + newtCursorOn(); + SLsmg_refresh(); + SLsmg_reset_smg(); + SLang_reset_tty(); + + return 0; +} + +void newtSetColors(struct newtColors colors) { + SLtt_set_color(NEWT_COLORSET_ROOT, "", colors.rootFg, colors.rootBg); + SLtt_set_color(NEWT_COLORSET_BORDER, "", colors.borderFg, colors.borderBg); + SLtt_set_color(NEWT_COLORSET_WINDOW, "", colors.windowFg, colors.windowBg); + SLtt_set_color(NEWT_COLORSET_SHADOW, "", colors.shadowFg, colors.shadowBg); + SLtt_set_color(NEWT_COLORSET_TITLE, "", colors.titleFg, colors.titleBg); + SLtt_set_color(NEWT_COLORSET_BUTTON, "", colors.buttonFg, colors.buttonBg); + SLtt_set_color(NEWT_COLORSET_ACTBUTTON, "", colors.actButtonFg, + colors.actButtonBg); + SLtt_set_color(NEWT_COLORSET_CHECKBOX, "", colors.checkboxFg, + colors.checkboxBg); + SLtt_set_color(NEWT_COLORSET_ACTCHECKBOX, "", colors.actCheckboxFg, + colors.actCheckboxBg); + SLtt_set_color(NEWT_COLORSET_ENTRY, "", colors.entryFg, colors.entryBg); + SLtt_set_color(NEWT_COLORSET_LABEL, "", colors.labelFg, colors.labelBg); + SLtt_set_color(NEWT_COLORSET_LISTBOX, "", colors.listboxFg, + colors.listboxBg); + SLtt_set_color(NEWT_COLORSET_ACTLISTBOX, "", colors.actListboxFg, + colors.actListboxBg); + SLtt_set_color(NEWT_COLORSET_TEXTBOX, "", colors.textboxFg, + colors.textboxBg); + SLtt_set_color(NEWT_COLORSET_ACTTEXTBOX, "", colors.actTextboxFg, + colors.actTextboxBg); + SLtt_set_color(NEWT_COLORSET_HELPLINE, "", colors.helpLineFg, + colors.helpLineBg); + SLtt_set_color(NEWT_COLORSET_ROOTTEXT, "", colors.rootTextFg, + colors.rootTextBg); + + SLtt_set_color(NEWT_COLORSET_EMPTYSCALE, "", "black", + colors.emptyScale); + SLtt_set_color(NEWT_COLORSET_FULLSCALE, "", "black", + colors.fullScale); + SLtt_set_color(NEWT_COLORSET_DISENTRY, "", colors.disabledEntryFg, + colors.disabledEntryBg); + + SLtt_set_color(NEWT_COLORSET_COMPACTBUTTON, "", colors.compactButtonFg, + colors.compactButtonBg); + + SLtt_set_color(NEWT_COLORSET_ACTSELLISTBOX, "", colors.actSelListboxFg, + colors.actSelListboxBg); + SLtt_set_color(NEWT_COLORSET_SELLISTBOX, "", colors.selListboxFg, + colors.selListboxBg); +} + +int newtGetKey(void) { + int key; + char buf[10], * chptr = buf; + const struct keymap * curr; + + do { + key = SLang_getkey(); + if (key == 0xFFFF) { + if (needResize) + return NEWT_KEY_RESIZE; + + /* ignore other signals */ + continue; + } + + if (key == NEWT_KEY_SUSPEND && suspendCallback) + suspendCallback(suspendCallbackData); + } while (key == NEWT_KEY_SUSPEND); + + switch (key) { + case 'v' | 0x80: + case 'V' | 0x80: + return NEWT_KEY_PGUP; + + case 22: + return NEWT_KEY_PGDN; + + return NEWT_KEY_BKSPC; + case 0x7f: + return NEWT_KEY_BKSPC; + + case 0x08: + return NEWT_KEY_BKSPC; + + default: + if (key != keyPrefix) return key; + } + + memset(buf, 0, sizeof(buf)); + + *chptr++ = key; + while (SLang_input_pending(5)) { + key = SLang_getkey(); + if (key == keyPrefix) { + /* he hit unknown keys too many times -- start over */ + memset(buf, 0, sizeof(buf)); + chptr = buf; + } + + *chptr++ = key; + + /* this search should use bsearch(), but when we only look through + a list of 20 (or so) keymappings, it's probably faster just to + do a inline linear search */ + + for (curr = keymap; curr->code; curr++) { + if (curr->str) { + if (!strcmp(curr->str, buf)) + return curr->code; + } + } + } + + for (curr = keymap; curr->code; curr++) { + if (curr->str) { + if (!strcmp(curr->str, buf)) + return curr->code; + } + } + + /* Looks like we were a bit overzealous in reading characters. Return + just the first character, and put everything else back in the buffer + for later */ + + chptr--; + while (chptr > buf) + SLang_ungetkey(*chptr--); + + return *chptr; +} + +void newtWaitForKey(void) { + newtRefresh(); + + SLang_getkey(); + newtClearKeyBuffer(); +} + +void newtClearKeyBuffer(void) { + while (SLang_input_pending(1)) { + SLang_getkey(); + } +} + +int newtOpenWindow(int left, int top, int width, int height, + const char * title) { + int j, row, col; + int n; + int i; + + newtFlushInput(); + + if (!currentWindow) { + currentWindow = windowStack; + } else { + currentWindow++; + } + + currentWindow->left = left; + currentWindow->top = top; + currentWindow->width = width; + currentWindow->height = height; + currentWindow->title = title ? strdup(title) : NULL; + + currentWindow->buffer = malloc(sizeof(short) * (width + 3) * (height + 3)); + + row = top - 1; + col = left - 1; + n = 0; + for (j = 0; j < height + 3; j++, row++) { + SLsmg_gotorc(row, col); + SLsmg_read_raw((SLsmg_Char_Type *)currentWindow->buffer + n, + currentWindow->width + 3); + n += currentWindow->width + 3; + } + + SLsmg_set_color(NEWT_COLORSET_BORDER); + SLsmg_draw_box(top - 1, left - 1, height + 2, width + 2); + + if (currentWindow->title) { + i = strlen(currentWindow->title) + 4; + i = ((width - i) / 2) + left; + SLsmg_gotorc(top - 1, i); + SLsmg_set_char_set(1); + SLsmg_write_char(SLSMG_RTEE_CHAR); + SLsmg_set_char_set(0); + SLsmg_write_char(' '); + SLsmg_set_color(NEWT_COLORSET_TITLE); + SLsmg_write_string((char *)currentWindow->title); + SLsmg_set_color(NEWT_COLORSET_BORDER); + SLsmg_write_char(' '); + SLsmg_set_char_set(1); + SLsmg_write_char(SLSMG_LTEE_CHAR); + SLsmg_set_char_set(0); + } + + SLsmg_set_color(NEWT_COLORSET_WINDOW); + SLsmg_fill_region(top, left, height, width, ' '); + + SLsmg_set_color(NEWT_COLORSET_SHADOW); + SLsmg_fill_region(top + height + 1, left, 1, width + 2, ' '); + SLsmg_fill_region(top, left + width + 1, height + 1, 1, ' '); + + for (i = top; i < (top + height + 1); i++) { + SLsmg_gotorc(i, left + width + 1); + SLsmg_write_string(" "); + } + + return 0; +} + +int newtCenteredWindow(int width, int height, const char * title) { + int top, left; + + top = (SLtt_Screen_Rows - height) / 2; + + /* I don't know why, but this seems to look better */ + if ((SLtt_Screen_Rows % 2) && (top % 2)) top--; + + left = (SLtt_Screen_Cols - width) / 2; + + newtOpenWindow(left, top, width, height, title); + + return 0; +} + +void newtPopWindow(void) { + int j, row, col; + int n = 0; + + row = col = 0; + + row = currentWindow->top - 1; + col = currentWindow->left - 1; + for (j = 0; j < currentWindow->height + 3; j++, row++) { + SLsmg_gotorc(row, col); + SLsmg_write_raw((SLsmg_Char_Type *)currentWindow->buffer + n, + currentWindow->width + 3); + n += currentWindow->width + 3; + } + + free(currentWindow->buffer); + free(currentWindow->title); + + if (currentWindow == windowStack) + currentWindow = NULL; + else + currentWindow--; + + SLsmg_set_char_set(0); + + newtRefresh(); +} + +void newtGetWindowPos(int * x, int * y) { + if (currentWindow) { + *x = currentWindow->left; + *y = currentWindow->top; + } else + *x = *y = 0; +} + +void newtGetrc(int * row, int * col) { + *row = cursorRow; + *col = cursorCol; +} + +void newtGotorc(int newRow, int newCol) { + if (currentWindow) { + newRow += currentWindow->top; + newCol += currentWindow->left; + } + + cursorRow = newRow; + cursorCol = newCol; + SLsmg_gotorc(cursorRow, cursorCol); +} + +void newtDrawBox(int left, int top, int width, int height, int shadow) { + if (currentWindow) { + top += currentWindow->top; + left += currentWindow->left; + } + + SLsmg_draw_box(top, left, height, width); + + if (shadow) { + SLsmg_set_color(NEWT_COLORSET_SHADOW); + SLsmg_fill_region(top + height, left + 1, 1, width - 1, ' '); + SLsmg_fill_region(top + 1, left + width, height, 1, ' '); + } +} + +void newtClearBox(int left, int top, int width, int height) { + if (currentWindow) { + top += currentWindow->top; + left += currentWindow->left; + } + + SLsmg_fill_region(top, left, height, width, ' '); +} + +#if 0 +/* This doesn't seem to work quite right. I don't know why not, but when + I rsh from an rxvt into a box and run this code, the machine returns + console key's (\033[B) rather then xterm ones (\033OB). */ +static void initKeymap(void) { + struct keymap * curr; + + for (curr = keymap; curr->code; curr++) { + if (!curr->str) + curr->str = SLtt_tgetstr(curr->tc); + } + + /* Newt's keymap handling is a bit broken. It assumes that any extended + keystrokes begin with ESC. If you're using a homebrek terminal you + will probably need to fix this, or just yell at me and I'll be so + ashamed of myself for doing it this way I'll fix it */ + + keyPrefix = 0x1b; /* ESC */ +} +#endif + +void newtDelay(int usecs) { + fd_set set; + struct timeval tv; + + FD_ZERO(&set); + + tv.tv_sec = usecs / 1000000; + tv.tv_usec = usecs % 1000000; + + select(0, &set, &set, &set, &tv); +} + +struct eventResult newtDefaultEventHandler(newtComponent c __attribute__ ((unused)), + struct event ev __attribute__ ((unused))) { + struct eventResult er; + + er.result = ER_IGNORED; + return er; +} + +void newtRedrawHelpLine(void) { + char * buf; + + SLsmg_set_color(NEWT_COLORSET_HELPLINE); + + buf = alloca(SLtt_Screen_Cols + 1); + memset(buf, ' ', SLtt_Screen_Cols); + buf[SLtt_Screen_Cols] = '\0'; + + if (currentHelpline) + memcpy(buf, *currentHelpline, strlen(*currentHelpline)); + + SLsmg_gotorc(SLtt_Screen_Rows - 1, 0); + SLsmg_write_string(buf); +} + +void newtPushHelpLine(const char * text) { + if (!text) + text = defaultHelpLine; + + if (currentHelpline) + (*(++currentHelpline)) = strdup(text); + else { + currentHelpline = helplineStack; + *currentHelpline = strdup(text); + } + + newtRedrawHelpLine(); +} + +void newtPopHelpLine(void) { + if (!currentHelpline) return; + + free(*currentHelpline); + if (currentHelpline == helplineStack) + currentHelpline = NULL; + else + currentHelpline--; + + newtRedrawHelpLine(); +} + +void newtDrawRootText(int col, int row, const char * text) { + SLsmg_set_color(NEWT_COLORSET_ROOTTEXT); + + if (col < 0) { + col = SLtt_Screen_Cols + col; + } + + if (row < 0) { + row = SLtt_Screen_Rows + row; + } + + SLsmg_gotorc(row, col); + SLsmg_write_string((char *)text); +} + +int newtSetFlags(int oldFlags, int newFlags, enum newtFlagsSense sense) { + switch (sense) { + case NEWT_FLAGS_SET: + return oldFlags | newFlags; + + case NEWT_FLAGS_RESET: + return oldFlags & (~newFlags); + + case NEWT_FLAGS_TOGGLE: + return oldFlags ^ newFlags; + + default: + return oldFlags; + } +} + +void newtBell(void) +{ + SLtt_beep(); +} + +void newtGetScreenSize(int * cols, int * rows) { + if (rows) *rows = SLtt_Screen_Rows; + if (cols) *cols = SLtt_Screen_Cols; +} + +void newtDefaultPlaceHandler(newtComponent c, int newLeft, int newTop) { + c->left = newLeft; + c->top = newTop; +} + +void newtDefaultMappedHandler(newtComponent c, int isMapped) { + c->isMapped = isMapped; +} + +void newtCursorOff(void) { + cursorOn = 0; + SLtt_set_cursor_visibility (cursorOn); +} + +void newtCursorOn(void) { + cursorOn = 1; + SLtt_set_cursor_visibility (cursorOn); +} diff --git a/mdk-stage1/newt/newt.h b/mdk-stage1/newt/newt.h new file mode 100644 index 000000000..d3fd8bedc --- /dev/null +++ b/mdk-stage1/newt/newt.h @@ -0,0 +1,362 @@ +#ifndef H_NEWT +#define H_NEWT + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdarg.h> + +#define NEWT_COLORSET_ROOT 2 +#define NEWT_COLORSET_BORDER 3 +#define NEWT_COLORSET_WINDOW 4 +#define NEWT_COLORSET_SHADOW 5 +#define NEWT_COLORSET_TITLE 6 +#define NEWT_COLORSET_BUTTON 7 +#define NEWT_COLORSET_ACTBUTTON 8 +#define NEWT_COLORSET_CHECKBOX 9 +#define NEWT_COLORSET_ACTCHECKBOX 10 +#define NEWT_COLORSET_ENTRY 11 +#define NEWT_COLORSET_LABEL 12 +#define NEWT_COLORSET_LISTBOX 13 +#define NEWT_COLORSET_ACTLISTBOX 14 +#define NEWT_COLORSET_TEXTBOX 15 +#define NEWT_COLORSET_ACTTEXTBOX 16 +#define NEWT_COLORSET_HELPLINE 17 +#define NEWT_COLORSET_ROOTTEXT 18 +#define NEWT_COLORSET_EMPTYSCALE 19 +#define NEWT_COLORSET_FULLSCALE 20 +#define NEWT_COLORSET_DISENTRY 21 +#define NEWT_COLORSET_COMPACTBUTTON 22 +#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; + char * windowFg, * windowBg; + char * shadowFg, * shadowBg; + char * titleFg, * titleBg; + char * buttonFg, * buttonBg; + char * actButtonFg, * actButtonBg; + char * checkboxFg, * checkboxBg; + char * actCheckboxFg, * actCheckboxBg; + char * entryFg, * entryBg; + char * labelFg, * labelBg; + char * listboxFg, * listboxBg; + char * actListboxFg, * actListboxBg; + char * textboxFg, * textboxBg; + char * actTextboxFg, * actTextboxBg; + char * helpLineFg, * helpLineBg; + char * rootTextFg, * rootTextBg; + char * emptyScale, * fullScale; + char * disabledEntryFg, * disabledEntryBg; + char * compactButtonFg, * compactButtonBg; + char * actSelListboxFg, * actSelListboxBg; + char * selListboxFg, * selListboxBg; +}; + +enum newtFlagsSense { NEWT_FLAGS_SET, NEWT_FLAGS_RESET, NEWT_FLAGS_TOGGLE }; + +#define NEWT_FLAG_RETURNEXIT (1 << 0) +#define NEWT_FLAG_HIDDEN (1 << 1) +#define NEWT_FLAG_SCROLL (1 << 2) +#define NEWT_FLAG_DISABLED (1 << 3) +/* OBSOLETE #define NEWT_FLAG_NOSCROLL (1 << 4) for listboxes */ +#define NEWT_FLAG_BORDER (1 << 5) +#define NEWT_FLAG_WRAP (1 << 6) +#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_FLAG_PASSWORD (1 << 11) /* draw '*' of chars in entrybox */ +#define NEWT_FD_READ (1 << 0) +#define NEWT_FD_WRITE (1 << 1) + +#define NEWT_CHECKBOXTREE_COLLAPSED '\0' +#define NEWT_CHECKBOXTREE_EXPANDED '\1' +#define NEWT_CHECKBOXTREE_UNSELECTED ' ' +#define NEWT_CHECKBOXTREE_SELECTED '*' + +/* Backwards compatibility */ +#define NEWT_LISTBOX_RETURNEXIT NEWT_FLAG_RETURNEXIT +#define NEWT_ENTRY_SCROLL NEWT_FLAG_SCROLL +#define NEWT_ENTRY_HIDDEN NEWT_FLAG_HIDDEN +#define NEWT_ENTRY_RETURNEXIT NEWT_FLAG_RETURNEXIT +#define NEWT_ENTRY_DISABLED NEWT_FLAG_DISABLED + +#define NEWT_TEXTBOX_WRAP NEWT_FLAG_WRAP +#define NEWT_TEXTBOX_SCROLL NEWT_FLAG_SCROLL +#define NEWT_FORM_NOF12 NEWT_FLAG_NOF12 + +#define newtListboxAddEntry newtListboxAppendEntry + + +typedef struct newtComponent_struct * newtComponent; + +extern const struct newtColors newtDefaultColorPalette; + +typedef void (*newtCallback)(newtComponent, void *); +typedef void (*newtSuspendCallback)(void * data); + +int newtInit(void); +int newtFinished(void); +void newtCls(void); +void newtResizeScreen(int redraw); +void newtWaitForKey(void); +void newtClearKeyBuffer(void); +void newtDelay(int usecs); +/* top, left are *not* counting the border */ +int newtOpenWindow(int left, int top, int width, int height, + const char * title); +int newtCenteredWindow(int width, int height, const char * title); +void newtPopWindow(void); +void newtSetColors(struct newtColors colors); +void newtRefresh(void); +void newtSuspend(void); +void newtSetSuspendCallback(newtSuspendCallback cb, void * data); +void newtSetHelpCallback(newtCallback cb); +void newtResume(void); +void newtPushHelpLine(const char * text); +void newtRedrawHelpLine(void); +void newtPopHelpLine(void); +void newtDrawRootText(int col, int row, const char * text); +void newtBell(void); +void newtCursorOff(void); +void newtCursorOn(void); + +/* Components */ + +newtComponent newtCompactButton(int left, int top, const char * text); +newtComponent newtButton(int left, int top, const char * text); +newtComponent newtCheckbox(int left, int top, const char * text, char defValue, + const char * seq, char * result); +char newtCheckboxGetValue(newtComponent co); +void newtCheckboxSetValue(newtComponent co, char value); +void newtCheckboxSetFlags(newtComponent co, int flags, enum newtFlagsSense sense); + + +newtComponent newtRadiobutton(int left, int top, const char * text, int isDefault, + newtComponent prevButton); +newtComponent newtRadioGetCurrent(newtComponent setMember); +newtComponent newtListitem(int left, int top, const char * text, int isDefault, + newtComponent prevItem, const void * data, int flags); +void newtListitemSet(newtComponent co, const char * text); +void * newtListitemGetData(newtComponent co); +void newtGetScreenSize(int * cols, int * rows); + +newtComponent newtLabel(int left, int top, const char * text); +void newtLabelSetText(newtComponent co, const char * text); +newtComponent newtVerticalScrollbar(int left, int top, int height, + int normalColorset, int thumbColorset); +void newtScrollbarSet(newtComponent co, int where, int total); + +newtComponent newtListbox(int left, int top, int height, int flags); +void * newtListboxGetCurrent(newtComponent co); +void newtListboxSetCurrent(newtComponent co, int num); +void newtListboxSetCurrentByKey(newtComponent co, void * key); +void newtListboxSetEntry(newtComponent co, int num, const char * text); +void newtListboxSetWidth(newtComponent co, int width); +void newtListboxSetData(newtComponent co, int num, void * data); +int newtListboxAppendEntry(newtComponent co, const char * text, + const void * data); +/* Send the key to insert after, or NULL to insert at the top */ +int newtListboxInsertEntry(newtComponent co, const char * text, const void * data, void * key); +int newtListboxDeleteEntry(newtComponent co, void * data); +void newtListboxClear(newtComponent co); /* removes all entries from listbox */ +void newtListboxGetEntry(newtComponent co, int num, char **text, void **data); +/* Returns an array of data pointers from items, last element is NULL */ +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); +newtComponent newtCheckboxTreeMulti(int left, int top, int height, char *seq, int flags); +const void ** newtCheckboxTreeGetSelection(newtComponent co, int *numitems); +const void * newtCheckboxTreeGetCurrent(newtComponent co); +const void ** newtCheckboxTreeGetMultiSelection(newtComponent co, int *numitems, char seqnum); +/* 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); +void newtCheckboxTreeSetEntry(newtComponent co, const void * data, + const char * text); +char newtCheckboxTreeGetEntryValue(newtComponent co, const void * data); +void newtCheckboxTreeSetEntryValue(newtComponent co, const void * data, + char value); + +newtComponent newtTextboxReflowed(int left, int top, char * text, int width, + int flexDown, int flexUp, int flags); +newtComponent newtTextbox(int left, int top, int width, int height, int flags); +void newtTextboxSetText(newtComponent co, const char * text); +void newtTextboxSetHeight(newtComponent co, int height); +int newtTextboxGetNumLines(newtComponent co); +char * newtReflowText(char * text, int width, int flexDown, int flexUp, + int * actualWidth, int * actualHeight); + +struct newtExitStruct { + enum { NEWT_EXIT_HOTKEY, NEWT_EXIT_COMPONENT, NEWT_EXIT_FDREADY, + NEWT_EXIT_TIMER } reason; + union { + int key; + newtComponent co; + } u; +} ; + +newtComponent newtForm(newtComponent vertBar, void * helpTag, int flags); +void newtFormSetTimer(newtComponent form, int millisecs); +void newtFormWatchFd(newtComponent form, int fd, int fdFlags); +void newtFormSetSize(newtComponent co); +newtComponent newtFormGetCurrent(newtComponent co); +void newtFormSetBackground(newtComponent co, int color); +void newtFormSetCurrent(newtComponent co, newtComponent subco); +void newtFormAddComponent(newtComponent form, newtComponent co); +void newtFormAddComponents(newtComponent form, ...); +void newtFormSetHeight(newtComponent co, int height); +void newtFormSetWidth(newtComponent co, int width); +newtComponent newtRunForm(newtComponent form); /* obsolete */ +void newtFormRun(newtComponent co, struct newtExitStruct * es); +void newtDrawForm(newtComponent form); +void newtFormAddHotKey(newtComponent co, int key); + +typedef int (*newtEntryFilter)(newtComponent entry, void * data, int ch, + int cursor); +newtComponent newtEntry(int left, int top, const char * initialValue, int width, + char ** resultPtr, int flags); +void newtEntrySet(newtComponent co, const char * value, int cursorAtEnd); +void newtEntrySetFilter(newtComponent co, newtEntryFilter filter, void * data); +char * newtEntryGetValue(newtComponent co); +void newtEntrySetFlags(newtComponent co, int flags, enum newtFlagsSense sense); + +newtComponent newtScale(int left, int top, int width, int fullValue); +void newtScaleSet(newtComponent co, unsigned int amount); + +void newtComponentAddCallback(newtComponent co, newtCallback f, void * data); +void newtComponentTakesFocus(newtComponent co, int val); + +/* this also destroys all of the components (including other forms) on the + form */ +void newtFormDestroy(newtComponent form); + +/* Key codes */ + +#define NEWT_KEY_TAB '\t' +#define NEWT_KEY_ENTER '\r' +#define NEWT_KEY_SUSPEND '\032' /* ctrl - z*/ +#define NEWT_KEY_RETURN NEWT_KEY_ENTER + +#define NEWT_KEY_EXTRA_BASE 0x8000 +#define NEWT_KEY_UP NEWT_KEY_EXTRA_BASE + 1 +#define NEWT_KEY_DOWN NEWT_KEY_EXTRA_BASE + 2 +#define NEWT_KEY_LEFT NEWT_KEY_EXTRA_BASE + 4 +#define NEWT_KEY_RIGHT NEWT_KEY_EXTRA_BASE + 5 +#define NEWT_KEY_BKSPC NEWT_KEY_EXTRA_BASE + 6 +#define NEWT_KEY_DELETE NEWT_KEY_EXTRA_BASE + 7 +#define NEWT_KEY_HOME NEWT_KEY_EXTRA_BASE + 8 +#define NEWT_KEY_END NEWT_KEY_EXTRA_BASE + 9 +#define NEWT_KEY_UNTAB NEWT_KEY_EXTRA_BASE + 10 +#define NEWT_KEY_PGUP NEWT_KEY_EXTRA_BASE + 11 +#define NEWT_KEY_PGDN NEWT_KEY_EXTRA_BASE + 12 +#define NEWT_KEY_INSERT NEWT_KEY_EXTRA_BASE + 13 + +#define NEWT_KEY_F1 NEWT_KEY_EXTRA_BASE + 101 +#define NEWT_KEY_F2 NEWT_KEY_EXTRA_BASE + 102 +#define NEWT_KEY_F3 NEWT_KEY_EXTRA_BASE + 103 +#define NEWT_KEY_F4 NEWT_KEY_EXTRA_BASE + 104 +#define NEWT_KEY_F5 NEWT_KEY_EXTRA_BASE + 105 +#define NEWT_KEY_F6 NEWT_KEY_EXTRA_BASE + 106 +#define NEWT_KEY_F7 NEWT_KEY_EXTRA_BASE + 107 +#define NEWT_KEY_F8 NEWT_KEY_EXTRA_BASE + 108 +#define NEWT_KEY_F9 NEWT_KEY_EXTRA_BASE + 109 +#define NEWT_KEY_F10 NEWT_KEY_EXTRA_BASE + 110 +#define NEWT_KEY_F11 NEWT_KEY_EXTRA_BASE + 111 +#define NEWT_KEY_F12 NEWT_KEY_EXTRA_BASE + 112 + +/* not really a key, but newtGetKey returns it */ +#define NEWT_KEY_RESIZE NEWT_KEY_EXTRA_BASE + 113 + +#define NEWT_ANCHOR_LEFT (1 << 0) +#define NEWT_ANCHOR_RIGHT (1 << 1) +#define NEWT_ANCHOR_TOP (1 << 2) +#define NEWT_ANCHOR_BOTTOM (1 << 3) + +#define NEWT_GRID_FLAG_GROWX (1 << 0) +#define NEWT_GRID_FLAG_GROWY (1 << 1) + +typedef struct grid_s * newtGrid; +enum newtGridElement { NEWT_GRID_EMPTY = 0, + NEWT_GRID_COMPONENT, NEWT_GRID_SUBGRID }; + +newtGrid newtCreateGrid(int cols, int rows); +/* TYPE, what, TYPE, what, ..., NULL */ +newtGrid newtGridVStacked(enum newtGridElement type, void * what, ...); +newtGrid newtGridVCloseStacked(enum newtGridElement type, void * what, ...); +newtGrid newtGridHStacked(enum newtGridElement type1, void * what1, ...); +newtGrid newtGridHCloseStacked(enum newtGridElement type1, void * what1, ...); +newtGrid newtGridBasicWindow(newtComponent text, newtGrid middle, + newtGrid buttons); +newtGrid newtGridSimpleWindow(newtComponent text, newtComponent middle, + newtGrid buttons); +void newtGridSetField(newtGrid grid, int col, int row, + enum newtGridElement type, void * val, int padLeft, + int padTop, int padRight, int padBottom, int anchor, + int flags); +void newtGridPlace(newtGrid grid, int left, int top); +#define newtGridDestroy newtGridFree +void newtGridFree(newtGrid grid, int recurse); +void newtGridGetSize(newtGrid grid, int * width, int * height); +void newtGridWrappedWindow(newtGrid grid, char * title); +void newtGridWrappedWindowAt(newtGrid grid, char * title, int left, int top); +void newtGridAddComponentsToForm(newtGrid grid, newtComponent form, + int recurse); + +/* convienve */ +newtGrid newtButtonBarv(char * button1, newtComponent * b1comp, va_list args); +newtGrid newtButtonBar(char * button1, newtComponent * b1comp, ...); + +/* automatically centered and shrink wrapped */ +void newtWinMessage(char * title, char * buttonText, char * text, ...); +void newtWinMessagev(char * title, char * buttonText, char * text, + va_list argv); + +/* having separate calls for these two seems silly, but having two separate + variable length-arg lists seems like a bad idea as well */ + +/* Returns 0 if F12 was pressed, 1 for button1, 2 for button2 */ +int newtWinChoice(char * title, char * button1, char * button2, + char * text, ...); +/* Returns 0 if F12 was pressed, 1 for button1, 2 for button2, + 3 for button3 */ +int newtWinTernary(char * title, char * button1, char * button2, + char * button3, char * message, ...); + +/* Returns the button number pressed, 0 on F12 */ +int newtWinMenu(char * title, char * text, int suggestedWidth, int flexDown, + int flexUp, int maxListHeight, char ** items, int * listItem, + char * button1, ...); + +struct newtWinEntry { + char * text; + char ** value; /* may be initialized to set default */ + int flags; +}; + +/* Returns the button number pressed, 0 on F12. The final values are + dynamically allocated, and need to be freed. */ +int newtWinEntries(char * title, char * text, int suggestedWidth, int flexDown, + int flexUp, int dataWidth, + struct newtWinEntry * items, char * button1, ...); + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif + +#endif /* H_NEWT */ diff --git a/mdk-stage1/newt/newt_pr.h b/mdk-stage1/newt/newt_pr.h new file mode 100644 index 000000000..76f5e2f6f --- /dev/null +++ b/mdk-stage1/newt/newt_pr.h @@ -0,0 +1,82 @@ +#ifndef H_NEWT_PR +#define H_NEWT_PR + +#define COLORSET_ROOT NEWT_COLORSET_ROOT +#define COLORSET_BORDER NEWT_COLORSET_BORDER +#define COLORSET_WINDOW NEWT_COLORSET_WINDOW +#define COLORSET_SHADOW NEWT_COLORSET_SHADOW +#define COLORSET_TITLE NEWT_COLORSET_TITLE +#define COLORSET_BUTTON NEWT_COLORSET_BUTTON +#define COLORSET_ACTBUTTON NEWT_COLORSET_ACTBUTTON +#define COLORSET_CHECKBOX NEWT_COLORSET_CHECKBOX +#define COLORSET_ACTCHECKBOX NEWT_COLORSET_ACTCHECKBOX +#define COLORSET_ENTRY NEWT_COLORSET_ENTRY +#define COLORSET_LABEL NEWT_COLORSET_LABEL +#define COLORSET_LISTBOX NEWT_COLORSET_LISTBOX +#define COLORSET_ACTLISTBOX NEWT_COLORSET_ACTLISTBOX +#define COLORSET_TEXTBOX NEWT_COLORSET_TEXTBOX +#define COLORSET_ACTTEXTBOX NEWT_COLORSET_ACTTEXTBOX + +int newtSetFlags(int oldFlags, int newFlags, enum newtFlagsSense sense); + +void newtGotorc(int row, int col); +void newtGetrc(int * row, int * col); +void newtGetWindowPos(int * x, int * y); +void newtDrawBox(int left, int top, int width, int height, int shadow); +void newtClearBox(int left, int top, int width, int height); + +int newtGetKey(void); + +struct newtComponent_struct { + /* common data */ + int height, width; + int top, left; + int takesFocus; + int isMapped; + + struct componentOps * ops; + + newtCallback callback; + void * callbackData; + + void * data; +} ; + +enum eventResultTypes { ER_IGNORED, ER_SWALLOWED, ER_EXITFORM, ER_SETFOCUS, + ER_NEXTCOMP }; +struct eventResult { + enum eventResultTypes result; + union { + newtComponent focus; + } u; +}; + +enum eventTypes { EV_FOCUS, EV_UNFOCUS, EV_KEYPRESS, EV_MOUSE }; +enum eventSequence { EV_EARLY, EV_NORMAL, EV_LATE }; + +struct event { + enum eventTypes event; + enum eventSequence when; + union { + int key; + struct { + enum { MOUSE_MOTION, MOUSE_BUTTON_DOWN, MOUSE_BUTTON_UP } type; + int x, y; + } mouse; + } u; +} ; + +struct componentOps { + void (* draw)(newtComponent c); + struct eventResult (* event)(newtComponent c, struct event ev); + void (* destroy)(newtComponent c); + void (* place)(newtComponent c, int newLeft, int newTop); + void (* mapped)(newtComponent c, int isMapped); +} ; + +void newtDefaultPlaceHandler(newtComponent c, int newLeft, int newTop); +void newtDefaultMappedHandler(newtComponent c, int isMapped); +struct eventResult newtDefaultEventHandler(newtComponent c, + struct event ev); + +#endif /* H_NEWT_PR */ diff --git a/mdk-stage1/newt/scale.c b/mdk-stage1/newt/scale.c new file mode 100644 index 000000000..800958580 --- /dev/null +++ b/mdk-stage1/newt/scale.c @@ -0,0 +1,72 @@ +#include <slang.h> +#include <stdlib.h> +#include <string.h> + +#include "newt.h" +#include "newt_pr.h" + +struct scale { + int fullValue; + int charsSet; +}; + +static void scaleDraw(newtComponent co); + +static struct componentOps scaleOps = { + scaleDraw, + newtDefaultEventHandler, + NULL, + newtDefaultPlaceHandler, + newtDefaultMappedHandler, +} ; + +newtComponent newtScale(int left, int top, int width, int fullValue) { + newtComponent co; + struct scale * sc; + + co = malloc(sizeof(*co)); + sc = malloc(sizeof(struct scale)); + co->data = sc; + + co->ops = &scaleOps; + + co->height = 1; + co->width = width; + co->top = top; + co->left = left; + co->takesFocus = 0; + + sc->fullValue = fullValue; + sc->charsSet = 0; + + return co; +} + +void newtScaleSet(newtComponent co, unsigned int amount) { + struct scale * sc = co->data; + int newCharsSet; + + newCharsSet = (amount * co->width) / sc->fullValue; + + if (newCharsSet != sc->charsSet) { + sc->charsSet = newCharsSet; + scaleDraw(co); + } +} + +static void scaleDraw(newtComponent co) { + struct scale * sc = co->data; + int i; + + if (co->top == -1) return; + + newtGotorc(co->top, co->left); + + SLsmg_set_color(NEWT_COLORSET_FULLSCALE); + for (i = 0; i < sc->charsSet; i++) + SLsmg_write_string(" "); + + SLsmg_set_color(NEWT_COLORSET_EMPTYSCALE); + for (i = 0; i < (co->width - sc->charsSet); i++) + SLsmg_write_string(" "); +} diff --git a/mdk-stage1/newt/scrollbar.c b/mdk-stage1/newt/scrollbar.c new file mode 100644 index 000000000..cb4bc2757 --- /dev/null +++ b/mdk-stage1/newt/scrollbar.c @@ -0,0 +1,124 @@ +#include <slang.h> +#include <stdlib.h> +#include <string.h> + +#include "newt.h" +#include "newt_pr.h" + +struct scrollbar { + int curr; + int cs, csThumb; + int arrows; +} ; + +static void sbDraw(newtComponent co); +static void sbDestroy(newtComponent co); +static void sbDrawThumb(newtComponent co, int isOn); + +static struct componentOps sbOps = { + sbDraw, + newtDefaultEventHandler, + sbDestroy, + newtDefaultPlaceHandler, + newtDefaultMappedHandler, +} ; + +void newtScrollbarSet(newtComponent co, int where, int total) { + struct scrollbar * sb = co->data; + int new; + + if (sb->arrows) + new = (where * (co->height - 3)) / (total ? total : 1) + 1; + else + new = (where * (co->height - 1)) / (total ? total : 1); + if (new != sb->curr) { + sbDrawThumb(co, 0); + sb->curr = new; + sbDrawThumb(co, 1); + } +} + +newtComponent newtVerticalScrollbar(int left, int top, int height, + int normalColorset, int thumbColorset) { + newtComponent co; + struct scrollbar * sb; + + co = malloc(sizeof(*co)); + sb = malloc(sizeof(*sb)); + co->data = sb; + + if (!strcmp(getenv("TERM"), "linux") && height >= 2) { + sb->arrows = 1; + sb->curr = 1; + } else { + sb->arrows = 0; + sb->curr = 0; + } + sb->cs = normalColorset; + sb->csThumb = thumbColorset; + + co->ops = &sbOps; + co->isMapped = 0; + co->left = left; + co->top = top; + co->height = height; + co->width = 1; + co->takesFocus = 0; + + return co; +} + +static void sbDraw(newtComponent co) { + struct scrollbar * sb = co->data; + int i; + + if (!co->isMapped) return; + + SLsmg_set_color(sb->cs); + + SLsmg_set_char_set(1); + if (sb->arrows) { + newtGotorc(co->top, co->left); + SLsmg_write_char('\x2d'); + for (i = 1; i < co->height - 1; i++) { + newtGotorc(i + co->top, co->left); + SLsmg_write_char('\x61'); + } + newtGotorc(co->top + co->height - 1, co->left); + SLsmg_write_char('\x2e'); + } else { + for (i = 0; i < co->height; i++) { + newtGotorc(i + co->top, co->left); + SLsmg_write_char('\x61'); + } + } + + SLsmg_set_char_set(0); + + sbDrawThumb(co, 1); +} + +static void sbDrawThumb(newtComponent co, int isOn) { + struct scrollbar * sb = co->data; + char ch = isOn ? '#' : '\x61'; + + if (!co->isMapped) return; + + newtGotorc(sb->curr + co->top, co->left); + SLsmg_set_char_set(1); + + /*if (isOn) + SLsmg_set_color(sb->csThumb); + else*/ + SLsmg_set_color(sb->cs); + + SLsmg_write_char(ch); + SLsmg_set_char_set(0); +} + +static void sbDestroy(newtComponent co) { + struct scrollbar * sb = co->data; + + free(sb); + free(co); +} diff --git a/mdk-stage1/newt/textbox.c b/mdk-stage1/newt/textbox.c new file mode 100644 index 000000000..8eb4ae4db --- /dev/null +++ b/mdk-stage1/newt/textbox.c @@ -0,0 +1,409 @@ +#include <ctype.h> +#include <slang.h> +#include <stdlib.h> +#include <string.h> + +#include "newt.h" +#include "newt_pr.h" + +struct textbox { + char ** lines; + int numLines; + int linesAlloced; + int doWrap; + newtComponent sb; + int topLine; + int textWidth; +}; + +static char * expandTabs(const char * text); +static void textboxDraw(newtComponent co); +static void addLine(newtComponent co, const char * s, int len); +static void doReflow(const char * text, char ** resultPtr, int width, + int * badness, int * heightPtr); +static struct eventResult textboxEvent(newtComponent c, + struct event ev); +static void textboxDestroy(newtComponent co); +static void textboxPlace(newtComponent co, int newLeft, int newTop); +static void textboxMapped(newtComponent co, int isMapped); + +static struct componentOps textboxOps = { + textboxDraw, + textboxEvent, + textboxDestroy, + textboxPlace, + textboxMapped, +} ; + +static void textboxMapped(newtComponent co, int isMapped) { + struct textbox * tb = co->data; + + co->isMapped = isMapped; + if (tb->sb) + tb->sb->ops->mapped(tb->sb, isMapped); +} + +static void textboxPlace(newtComponent co, int newLeft, int newTop) { + struct textbox * tb = co->data; + + co->top = newTop; + co->left = newLeft; + + if (tb->sb) + tb->sb->ops->place(tb->sb, co->left + co->width - 1, co->top); +} + +void newtTextboxSetHeight(newtComponent co, int height) { + co->height = height; +} + +int newtTextboxGetNumLines(newtComponent co) { + struct textbox * tb = co->data; + + return (tb->numLines); +} + +newtComponent newtTextboxReflowed(int left, int top, char * text, int width, + int flexDown, int flexUp, int flags __attribute__ ((unused))) { + newtComponent co; + char * reflowedText; + int actWidth, actHeight; + + reflowedText = newtReflowText(text, width, flexDown, flexUp, + &actWidth, &actHeight); + + co = newtTextbox(left, top, actWidth, actHeight, NEWT_FLAG_WRAP); + newtTextboxSetText(co, reflowedText); + free(reflowedText); + + return co; +} + +newtComponent newtTextbox(int left, int top, int width, int height, int flags) { + newtComponent co; + struct textbox * tb; + + co = malloc(sizeof(*co)); + tb = malloc(sizeof(*tb)); + co->data = tb; + + co->ops = &textboxOps; + + co->height = height; + co->top = top; + co->left = left; + co->takesFocus = 0; + co->width = width; + + tb->doWrap = flags & NEWT_FLAG_WRAP; + tb->numLines = 0; + tb->linesAlloced = 0; + tb->lines = NULL; + tb->topLine = 0; + tb->textWidth = width; + + if (flags & NEWT_FLAG_SCROLL) { + co->width += 2; + tb->sb = newtVerticalScrollbar(co->left + co->width - 1, co->top, + co->height, COLORSET_TEXTBOX, COLORSET_TEXTBOX); + } else { + tb->sb = NULL; + } + + return co; +} + +static char * expandTabs(const char * text) { + int bufAlloced = strlen(text) + 40; + char * buf, * dest; + const char * src; + int bufUsed = 0; + int linePos = 0; + int i; + + buf = malloc(bufAlloced + 1); + for (src = text, dest = buf; *src; src++) { + if ((bufUsed + 10) > bufAlloced) { + bufAlloced += strlen(text) / 2; + buf = realloc(buf, bufAlloced + 1); + dest = buf + bufUsed; + } + if (*src == '\t') { + i = 8 - (linePos & 8); + memset(dest, ' ', i); + dest += i, bufUsed += i, linePos += i; + } else { + if (*src == '\n') + linePos = 0; + else + linePos++; + + *dest++ = *src; + bufUsed++; + } + } + + *dest = '\0'; + return buf; +} + +#define iseuckanji(c) (0xa1 <= (unsigned char)(c&0xff) && (unsigned char)(c&0xff) <= 0xfe) + +static void doReflow(const char * text, char ** resultPtr, int width, + int * badness, int * heightPtr) { + char * result = NULL; + const char * chptr, * end; + int i; + int howbad = 0; + int height = 0; + int kanji = 0; + + if (resultPtr) { + /* XXX I think this will work */ + result = malloc(strlen(text) + (strlen(text) / width) + 50); + *result = '\0'; + } + + while (*text) { + kanji = 0; + end = strchr(text, '\n'); + if (!end) + end = text + strlen(text); + + while (*text && text < end) { + if (end - text < width) { + if (result) { + strncat(result, text, end - text); + strcat(result, "\n"); + height++; + } + + if (end - text < (width / 2)) + howbad += ((width / 2) - (end - text)) / 2; + text = end; + if (*text) text++; + } else { + chptr = text; + kanji = 0; + for ( i = 0; i < width - 1; i++ ) { + if ( !iseuckanji(*chptr)) { + kanji = 0; + } else if ( kanji == 1 ) { + kanji = 2; + } else { + kanji = 1; + } + chptr++; + } + if (kanji == 0) { + while (chptr > text && !isspace(*chptr)) chptr--; + while (chptr > text && isspace(*chptr)) chptr--; + chptr++; + } + + if (chptr-text == 1 && !isspace(*chptr)) + chptr = text + width - 1; + + if (chptr > text) + howbad += width - (chptr - text) + 1; + if (result) { + if (kanji == 1) { + strncat(result, text, chptr - text + 1); + chptr++; + kanji = 0; + } else { + strncat(result, text, chptr - text); + } + strcat(result, "\n"); + height++; + } + + if (isspace(*chptr)) + text = chptr + 1; + else + text = chptr; + while (isspace(*text)) text++; + } + } + } + +// if (result) printf("result: %s\n", result); + + if (badness) *badness = howbad; + if (resultPtr) *resultPtr = result; + if (heightPtr) *heightPtr = height; +} + +char * newtReflowText(char * text, int width, int flexDown, int flexUp, + int * actualWidth, int * actualHeight) { + int min, max; + int i; + char * result; + int minbad, minbadwidth, howbad; + char * expandedText; + + expandedText = expandTabs(text); + + if (flexDown || flexUp) { + min = width - flexDown; + max = width + flexUp; + + minbad = -1; + minbadwidth = width; + + for (i = min; i <= max; i++) { + doReflow(expandedText, NULL, i, &howbad, NULL); + + if (minbad == -1 || howbad < minbad) { + minbad = howbad; + minbadwidth = i; + } + } + + width = minbadwidth; + } + + doReflow(expandedText, &result, width, NULL, actualHeight); + free(expandedText); + if (actualWidth) *actualWidth = width; + return result; +} + +void newtTextboxSetText(newtComponent co, const char * text) { + const char * start, * end; + struct textbox * tb = co->data; + char * reflowed, * expanded; + int badness, height; + + if (tb->lines) { + free(tb->lines); + tb->linesAlloced = tb->numLines = 0; + } + + expanded = expandTabs(text); + + if (tb->doWrap) { + doReflow(expanded, &reflowed, tb->textWidth, &badness, &height); + free(expanded); + expanded = reflowed; + } + + for (start = expanded; *start; start++) + if (*start == '\n') tb->linesAlloced++; + + /* This ++ leaves room for an ending line w/o a \n */ + tb->linesAlloced++; + tb->lines = malloc(sizeof(char *) * tb->linesAlloced); + + start = expanded; + while ((end = strchr(start, '\n'))) { + addLine(co, start, end - start); + start = end + 1; + } + + if (*start) + addLine(co, start, strlen(start)); + + free(expanded); +} + +/* This assumes the buffer is allocated properly! */ +static void addLine(newtComponent co, const char * s, int len) { + struct textbox * tb = co->data; + + if (len > tb->textWidth) len = tb->textWidth; + + tb->lines[tb->numLines] = malloc(tb->textWidth + 1); + memset(tb->lines[tb->numLines], ' ', tb->textWidth); + memcpy(tb->lines[tb->numLines], s, len); + tb->lines[tb->numLines++][tb->textWidth] = '\0'; +} + +static void textboxDraw(newtComponent c) { + int i; + struct textbox * tb = c->data; + int size; + + if (tb->sb) { + size = tb->numLines - c->height; + newtScrollbarSet(tb->sb, tb->topLine, size ? size : 0); + tb->sb->ops->draw(tb->sb); + } + + SLsmg_set_color(NEWT_COLORSET_TEXTBOX); + + for (i = 0; (i + tb->topLine) < tb->numLines && i < c->height; i++) { + newtGotorc(c->top + i, c->left); + SLsmg_write_string(tb->lines[i + tb->topLine]); + } +} + +static struct eventResult textboxEvent(newtComponent co, + struct event ev) { + struct textbox * tb = co->data; + struct eventResult er; + + er.result = ER_IGNORED; + + if (ev.when == EV_EARLY && ev.event == EV_KEYPRESS && tb->sb) { + switch (ev.u.key) { + case NEWT_KEY_UP: + if (tb->topLine) tb->topLine--; + textboxDraw(co); + er.result = ER_SWALLOWED; + break; + + case NEWT_KEY_DOWN: + if (tb->topLine < (tb->numLines - co->height)) tb->topLine++; + textboxDraw(co); + er.result = ER_SWALLOWED; + break; + + case NEWT_KEY_PGDN: + tb->topLine += co->height; + if (tb->topLine > (tb->numLines - co->height)) { + tb->topLine = tb->numLines - co->height; + if (tb->topLine < 0) tb->topLine = 0; + } + textboxDraw(co); + er.result = ER_SWALLOWED; + break; + + case NEWT_KEY_PGUP: + tb->topLine -= co->height; + if (tb->topLine < 0) tb->topLine = 0; + textboxDraw(co); + er.result = ER_SWALLOWED; + break; + } + } + if (ev.when == EV_EARLY && ev.event == EV_MOUSE && tb->sb) { + /* Top scroll arrow */ + if (ev.u.mouse.x == co->width && ev.u.mouse.y == co->top) { + if (tb->topLine) tb->topLine--; + textboxDraw(co); + + er.result = ER_SWALLOWED; + } + /* Bottom scroll arrow */ + if (ev.u.mouse.x == co->width && + ev.u.mouse.y == co->top + co->height - 1) { + if (tb->topLine < (tb->numLines - co->height)) tb->topLine++; + textboxDraw(co); + + er.result = ER_SWALLOWED; + } + } + return er; +} + +static void textboxDestroy(newtComponent co) { + int i; + struct textbox * tb = co->data; + + for (i = 0; i < tb->numLines; i++) + free(tb->lines[i]); + free(tb->lines); + free(tb); + free(co); +} diff --git a/mdk-stage1/newt/windows.c b/mdk-stage1/newt/windows.c new file mode 100644 index 000000000..30a8d526c --- /dev/null +++ b/mdk-stage1/newt/windows.c @@ -0,0 +1,275 @@ +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "errno.h" +#include "newt.h" + +static void * newtvwindow(char * title, char * button1, char * button2, + char * button3, char * message, va_list args) { + newtComponent b1, b2 = NULL, b3 = NULL, t, f, answer; + char * buf = NULL; + int size = 0; + int i = 0; + int scroll = 0; + int width, height; + char * flowedText; + newtGrid grid, buttonGrid; + + do { + size += 1000; + if (buf) free(buf); + buf = malloc(size); + i = vsnprintf(buf, size, message, args); + } while (i >= size || i == -1); + + flowedText = newtReflowText(buf, 50, 5, 5, &width, &height); + if (height > 6) { + free(flowedText); + flowedText = newtReflowText(buf, 60, 5, 5, &width, &height); + } + free(buf); + + if (height > 12) { + height = 12; + scroll = NEWT_FLAG_SCROLL; + } + t = newtTextbox(-1, -1, width, height, NEWT_TEXTBOX_WRAP | scroll); + newtTextboxSetText(t, flowedText); + free(flowedText); + + if (button3) { + buttonGrid = newtButtonBar(button1, &b1, button2, &b2, + button3, &b3, NULL); + } else if (button2) { + buttonGrid = newtButtonBar(button1, &b1, button2, &b2, NULL); + } else { + buttonGrid = newtButtonBar(button1, &b1, NULL); + } + + newtGridSetField(buttonGrid, 0, 0, NEWT_GRID_COMPONENT, b1, + 0, 0, button2 ? 1 : 0, 0, 0, 0); + + grid = newtCreateGrid(1, 2); + newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, t, 0, 0, 0, 0, 0, 0); + newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, buttonGrid, + 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX); + newtGridWrappedWindow(grid, title); + + f = newtForm(NULL, NULL, 0); + newtFormAddComponents(f, t, b1, NULL); + + if (button2) + newtFormAddComponent(f, b2); + if (button3) + newtFormAddComponent(f, b3); + + answer = newtRunForm(f); + newtGridFree(grid, 1); + + newtFormDestroy(f); + newtPopWindow(); + + if (answer == f) + return NULL; + else if (answer == b1) + return button1; + else if (answer == b2) + return button2; + + return button3; +} + +int newtWinChoice(char * title, char * button1, char * button2, + char * message, ...) { + va_list args; + void * rc; + + va_start(args, message); + rc = newtvwindow(title, button1, button2, NULL, message, args); + va_end(args); + + if (rc == button1) + return 1; + else if (rc == button2) + return 2; + + return 0; +} + +void newtWinMessage(char * title, char * buttonText, char * text, ...) { + va_list args; + + va_start(args, text); + newtvwindow(title, buttonText, NULL, NULL, text, args); + va_end(args); +} + +void newtWinMessagev(char * title, char * buttonText, char * text, + va_list argv) { + newtvwindow(title, buttonText, NULL, NULL, text, argv); +} + +int newtWinTernary(char * title, char * button1, char * button2, + char * button3, char * message, ...) { + va_list args; + void * rc; + + va_start(args, message); + rc = newtvwindow(title, button1, button2, button3, message, args); + va_end(args); + + if (rc == button1) + return 1; + else if (rc == button2) + return 2; + else if (rc == button3) + return 3; + + return 0; +} + +/* only supports up to 50 buttons -- shucks! */ +int newtWinMenu(char * title, char * text, int suggestedWidth, int flexDown, + int flexUp, int maxListHeight, char ** items, int * listItem, + char * button1, ...) { + newtComponent textbox, listbox, result, form; + va_list args; + newtComponent buttons[50]; + newtGrid grid, buttonBar; + int numButtons; + int i, rc; + int needScroll; + char * buttonName; + + textbox = newtTextboxReflowed(-1, -1, text, suggestedWidth, flexDown, + flexUp, 0); + + for (i = 0; items[i]; i++) ; + if (i < maxListHeight) maxListHeight = i; + needScroll = i > maxListHeight; + + listbox = newtListbox(-1, -1, maxListHeight, + (needScroll ? NEWT_FLAG_SCROLL : 0) | NEWT_FLAG_RETURNEXIT); + for (i = 0; items[i]; i++) { + newtListboxAddEntry(listbox, items[i], (void *) (long)i); + } + + newtListboxSetCurrent(listbox, *listItem); + + buttonName = button1, numButtons = 0; + va_start(args, button1); + while (buttonName) { + buttons[numButtons] = newtButton(-1, -1, buttonName); + numButtons++; + buttonName = va_arg(args, char *); + } + + va_end(args); + + buttonBar = newtCreateGrid(numButtons, 1); + for (i = 0; i < numButtons; i++) { + newtGridSetField(buttonBar, i, 0, NEWT_GRID_COMPONENT, + buttons[i], + i ? 1 : 0, 0, 0, 0, 0, 0); + } + + grid = newtGridSimpleWindow(textbox, listbox, buttonBar); + newtGridWrappedWindow(grid, title); + + form = newtForm(NULL, 0, 0); + newtGridAddComponentsToForm(grid, form, 1); + newtGridFree(grid, 1); + + result = newtRunForm(form); + + *listItem = ((long) newtListboxGetCurrent(listbox)); + + for (rc = 0; result != buttons[rc] && rc < numButtons; rc++); + if (rc == numButtons) + rc = 0; /* F12 or return-on-exit (which are the same for us) */ + else + rc++; + + newtFormDestroy(form); + newtPopWindow(); + + return rc; +} + +/* only supports up to 50 buttons and entries -- shucks! */ +int newtWinEntries(char * title, char * text, int suggestedWidth, int flexDown, + int flexUp, int dataWidth, + struct newtWinEntry * items, char * button1, ...) { + newtComponent buttons[50], result, form, textw; + newtGrid grid, buttonBar, subgrid; + int numItems; + int rc, i; + int numButtons; + char * buttonName; + va_list args; + + textw = newtTextboxReflowed(-1, -1, text, suggestedWidth, flexDown, + flexUp, 0); + + for (numItems = 0; items[numItems].text; numItems++); + + buttonName = button1, numButtons = 0; + va_start(args, button1); + while (buttonName) { + buttons[numButtons] = newtButton(-1, -1, buttonName); + numButtons++; + buttonName = va_arg(args, char *); + } + + va_end(args); + + buttonBar = newtCreateGrid(numButtons, 1); + for (i = 0; i < numButtons; i++) { + newtGridSetField(buttonBar, i, 0, NEWT_GRID_COMPONENT, + buttons[i], + i ? 1 : 0, 0, 0, 0, 0, 0); + } + + subgrid = newtCreateGrid(2, numItems); + for (i = 0; i < numItems; i++) { + newtGridSetField(subgrid, 0, i, NEWT_GRID_COMPONENT, + newtLabel(-1, -1, items[i].text), + 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); + newtGridSetField(subgrid, 1, i, NEWT_GRID_COMPONENT, + newtEntry(-1, -1, items[i].value ? + *items[i].value : NULL, dataWidth, + items[i].value, items[i].flags), + 1, 0, 0, 0, 0, 0); + } + + grid = newtCreateGrid(1, 3); + form = newtForm(NULL, 0, 0); + newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, textw, + 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); + newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, subgrid, + 0, 1, 0, 0, 0, 0); + newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttonBar, + 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX); + newtGridAddComponentsToForm(grid, form, 1); + newtGridWrappedWindow(grid, title); + newtGridFree(grid, 1); + + result = newtRunForm(form); + + for (rc = 0; rc < numItems; rc++) + *items[rc].value = strdup(*items[rc].value); + + for (rc = 0; result != buttons[rc] && rc < numButtons; rc++); + if (rc == numButtons) + rc = 0; /* F12 */ + else + rc++; + + newtFormDestroy(form); + newtPopWindow(); + + return rc; +} |