and contributed to newt for use under the LGPL license.
Copyright (C) 1996, 1997 Elliot Lee */
-#include <slang/slang.h>
+#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 {
- void *key;
+ char * text;
const void *data;
unsigned char isSelected;
struct items *next;
int curHeight; /* size of text w/o border */
int sbAdjust;
int bdxAdjust, bdyAdjust;
- int numItems, numSelected;
+ int numItems, numSelected;
int userHasSetWidth;
int currItem, startShowItem; /* startShowItem is the first item displayed
on the screen */
static void listboxDestroy(newtComponent co);
static struct eventResult listboxEvent(newtComponent co, struct event ev);
static void newtListboxRealSetCurrent(newtComponent co);
-static void listboxPlace(newtComponent co);
-static inline void updateWidth(newtComponent co, struct listbox * li,
+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 listboxPlace(newtComponent co) {
+static void listboxMapped(newtComponent co, int isMapped) {
struct listbox * li = co->data;
- if (li->sb) {
- li->sb->top = co->top;
- li->sb->left = co->left + co->width - 1;
- if (li->sb->ops->place) li->sb->ops->place(li->sb);
- }
+ 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 + li->bdyAdjust);
}
newtComponent newtListbox(int left, int top, int height, int flags) {
li->sbAdjust = 0;
li->bdxAdjust = 0;
li->bdyAdjust = 0;
- li->flags = flags & (NEWT_FLAG_RETURNEXIT | NEWT_FLAG_DOBORDER |
- NEWT_FLAG_MULTIPLE);
+ li->flags = flags & (NEWT_FLAG_RETURNEXIT | NEWT_FLAG_BORDER |
+ NEWT_FLAG_MULTIPLE | NEWT_FLAG_SHOWCURSOR);
- if (li->flags & NEWT_FLAG_DOBORDER) {
+ 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_NOSCROLL) {
- sb = NULL;
- } else {
- sb = newtVerticalScrollbar(left, top, height, COLORSET_LISTBOX,
- COLORSET_ACTLISTBOX);
+ if (flags & NEWT_FLAG_SCROLL) {
+ sb = newtVerticalScrollbar(left, top + li->bdyAdjust,
+ li->curHeight,
+ COLORSET_LISTBOX, COLORSET_ACTLISTBOX);
li->sbAdjust = 3;
+ } else {
+ sb = NULL;
}
- co->height = height;
} else {
li->grow = 1;
sb = NULL;
- co->height = 2 * li->bdyAdjust;
}
li->sb = sb;
co->ops = &listboxOps;
co->takesFocus = 1;
co->callback = NULL;
+ co->destroyCallback = NULL;
updateWidth(co, li, 5);
- li->curHeight = co->height - (2 * li->bdyAdjust);
return co;
}
-static inline void updateWidth(newtComponent co, struct listbox * li,
+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 - 1;
+ 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)
if (li->currItem < li->startShowItem)
li->startShowItem = li->currItem;
- else if (li->currItem - li->startShowItem > co->height - 1)
- li->startShowItem = li->currItem - co->height + 1;
- if (li->startShowItem + co->height > li->numItems)
- li->startShowItem = li->numItems - co->height;
+ 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)
+static void newtListboxRealSetCurrent(newtComponent co)
{
struct listbox * li = co->data;
+
if(li->sb)
newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
listboxDraw(co);
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;
+ if (li->sb)
+ li->sb->left = co->left + co->width - li->bdxAdjust - 1;
listboxDraw(co);
}
return NULL;
}
-void newtListboxSelectItem(newtComponent co, int item,
+void newtListboxSelectItem(newtComponent co, const void * key,
enum newtFlagsSense sense)
{
struct listbox * li = co->data;
int i;
- struct items *iitem;
-
- for(i = 0, iitem = li->boxItems; iitem != NULL && i < item;
- i++, iitem = iitem->next);
-
- if (iitem) {
- if(iitem->isSelected && sense != NEWT_FLAGS_SET)
- li->numSelected--;
- else if(!iitem->isSelected && sense != NEWT_FLAGS_RESET)
- li->numSelected++;
- switch(sense) {
- case NEWT_FLAGS_RESET:
- iitem->isSelected = 0; break;
- case NEWT_FLAGS_SET:
- iitem->isSelected = 1; break;
- case NEWT_FLAGS_TOGGLE:
- iitem->isSelected = !iitem->isSelected;
- }
+ 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);
}
return retval;
}
-void newtListboxSetText(newtComponent co, int num, const char * text) {
+void newtListboxSetEntry(newtComponent co, int num, const char * text) {
struct listbox * li = co->data;
int i;
struct items *item;
if(!item)
return;
else {
- free(item->key);
- item->key = strdup(text);
+ free(item->text);
+ item->text = strdup(text);
}
- if (li->userHasSetWidth == 0 && strlen(text) > li->curWidth) {
- updateWidth(co, li, strlen(text));
+ if (li->userHasSetWidth == 0 && wstrlen(text,-1) > li->curWidth) {
+ updateWidth(co, li, wstrlen(text,-1));
}
if (num >= li->startShowItem && num <= li->startShowItem + co->height)
listboxDraw(co);
}
-void newtListboxSetEntry(newtComponent co, int num, const char * text) {
- newtListboxSetText(co, num, text);
-}
-
void newtListboxSetData(newtComponent co, int num, void * data) {
struct listbox * li = co->data;
int i;
for(i = 0, item = li->boxItems; item != NULL && i < num;
i++, item = item->next);
- item->data = data;
+ if (item)
+ item->data = data;
}
-int newtListboxAddEntry(newtComponent co, const char * text,
- const void * data) {
+int newtListboxAppendEntry(newtComponent co, const char * text,
+ const void * data) {
struct listbox * li = co->data;
struct items *item;
item = li->boxItems = malloc(sizeof(struct items));
}
- if (!li->userHasSetWidth && text && (strlen(text) > li->curWidth))
- updateWidth(co, li, strlen(text));
+ if (!li->userHasSetWidth && text && (wstrlen(text,-1) > li->curWidth))
+ updateWidth(co, li, wstrlen(text,-1));
- item->key = strdup(text); item->data = data; item->next = NULL;
+ item->text = strdup(text); item->data = data; item->next = NULL;
item->isSelected = 0;
-
+
if (li->grow)
co->height++, li->curHeight++;
li->numItems++;
- return li->numItems;
+ return 0;
}
-
int newtListboxInsertEntry(newtComponent co, const char * text,
- const void * data, int num) {
+ const void * data, void * key) {
struct listbox * li = co->data;
struct items *item, *t;
- int i;
- if(num > li->numItems)
- num = li->numItems;
if (li->boxItems) {
- if(num > 0) {
- for(i = 0, item = li->boxItems; item->next != NULL && i < num - 1;
- item = item->next, i++);
+ 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;
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) > li->curWidth))
- updateWidth(co, li, strlen(text));
+ if (!li->userHasSetWidth && text && (wstrlen(text,-1) > li->curWidth))
+ updateWidth(co, li, wstrlen(text,-1));
- item->key = strdup(text?text:"(null)"); item->data = data;
+ item->text = strdup(text?text:"(null)"); item->data = data;
item->isSelected = 0;
-
+
if (li->sb)
- li->sb->left = co->left + co->width - 1;
+ li->sb->left = co->left + co->width - li->bdxAdjust - 1;
li->numItems++;
listboxDraw(co);
- return li->numItems;
+ return 0;
}
-int newtListboxDeleteEntry(newtComponent co, int num) {
+int newtListboxDeleteEntry(newtComponent co, void * key) {
struct listbox * li = co->data;
- int i, widest = 0, t;
+ int widest = 0, t;
struct items *item, *item2 = NULL;
-
- if(num > li->numItems)
- num = li->numItems;
+ int num;
if (li->boxItems == NULL || li->numItems <= 0)
return 0;
- if (num <= 1) {
- item = li->boxItems;
- li->boxItems = item->next;
+ num = 0;
- /* Fix things up for the width-finding loop near the bottom */
- item2 = li->boxItems;
- widest = strlen(item2?item2->key:"");
- } else {
- for(i = 0, item = li->boxItems; item != NULL && i < num - 1;
- i++, item = item->next) {
- if((t = strlen(item->key)) > widest) widest = t;
- item2 = item;
- }
+ item2 = NULL, item = li->boxItems;
+ while (item && item->data != key) {
+ item2 = item;
+ item = item->next;
+ num++;
+ }
- if (!item)
- return -1;
+ if (!item)
+ return -1;
+ if (item2)
item2->next = item->next;
- }
- free(item->key);
+ else
+ li->boxItems = item->next;
+
+ free(item->text);
free(item);
li->numItems--;
- if(li->currItem >= num)
+
+ if (!li->userHasSetWidth) {
+ widest = 0;
+ for (item = li->boxItems; item != NULL; item = item->next)
+ if ((t = wstrlen(item->text,-1)) > widest) widest = t;
+ }
+
+ if (li->currItem >= num)
li->currItem--;
- for (item = item2?item2->next:item2; item != NULL; item = item->next)
- if((t = strlen(item->key)) > widest) widest = t;
- /* Adjust the listbox width */
if (!li->userHasSetWidth) {
updateWidth(co, li, widest);
}
listboxDraw(co);
- return li->numItems;
+ return 0;
}
void newtListboxClear(newtComponent co)
return;
for(anitem = li->boxItems; anitem != NULL; anitem = nextitem) {
nextitem = anitem->next;
- free(anitem->key);
+ free(anitem->text);
free(anitem);
}
li->numItems = li->numSelected = li->currItem = li->startShowItem = 0;
li->boxItems = NULL;
- if (!li->userHasSetWidth)
+ if (!li->userHasSetWidth)
updateWidth(co, li, 5);
}
+int newtListboxItemCount(newtComponent co)
+{
+ struct listbox *li = co->data;
+ return li->numItems;
+}
+
/* 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) {
}
i = 0;
- item = li->boxItems;
+ item = li->boxItems;
while (item && i < num) {
i++, item = item->next;
}
if (item) {
if (text)
- *text = item->key;
+ *text = item->text;
if (data)
- *data = (void *)item->data;
+ *data = (void *)item->data;
}
}
if (!co->isMapped) return ;
- if(li->sb)
- li->sb->ops->draw(li->sb);
-
- if(li->flags & NEWT_FLAG_DOBORDER) {
+ newtTrashScreen();
+
+ if(li->flags & NEWT_FLAG_BORDER) {
if(li->isActive)
SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
else
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->key) continue;
+ if (!item->text) continue;
newtGotorc(co->top + i + li->bdyAdjust, co->left + li->bdxAdjust);
if(j + i == li->currItem) {
- if(item->isSelected)
+ if(li->isActive)
SLsmg_set_color(NEWT_COLORSET_ACTSELLISTBOX);
else
SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
SLsmg_set_color(NEWT_COLORSET_SELLISTBOX);
else
SLsmg_set_color(NEWT_COLORSET_LISTBOX);
-
- SLsmg_write_nstring(item->key, li->curWidth);
+ SLsmg_write_nstring(item->text, li->curWidth);
+
+ if (li->flags & NEWT_FLAG_MULTIPLE) {
+ newtGotorc(co->top + i + li->bdyAdjust, co->left + li->bdxAdjust);
+ SLsmg_set_color(item->isSelected ?
+ NEWT_COLORSET_SELLISTBOX : NEWT_COLORSET_LISTBOX);
+ SLsmg_write_nstring(item->text, 1);
+ }
}
- newtGotorc(co->top + (li->currItem - li->startShowItem), co->left);
+ newtGotorc(co->top + (li->currItem - li->startShowItem) + li->bdyAdjust,
+ co->left + li->bdxAdjust);
}
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->currItem, NEWT_FLAGS_TOGGLE);
+ newtListboxSelectItem(co, newtListboxGetCurrent(co),
+ 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 */
li->startShowItem = li->numItems - li->curHeight;
}
li->currItem += li->curHeight;
- if(li->currItem > li->numItems) {
+ if(li->currItem >= li->numItems) {
li->currItem = li->numItems - 1;
}
newtListboxRealSetCurrent(co);
case NEWT_KEY_END:
if(li->numItems <= 0) break;
- li->startShowItem = li->numItems - li->curHeight - 1;
+ li->startShowItem = li->numItems - li->curHeight;
if(li->startShowItem < 0)
li->startShowItem = 0;
- newtListboxRealSetCurrent(co, li->numItems - 1);
+ li->currItem = li->numItems - 1;
+ newtListboxRealSetCurrent(co);
er.result = ER_SWALLOWED;
break;
default:
- /* keeps gcc quiet */
+ 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);
+ if(li->flags & NEWT_FLAG_SHOWCURSOR)
+ newtCursorOn();
er.result = ER_SWALLOWED;
break;
case EV_UNFOCUS:
li->isActive = 0;
listboxDraw(co);
+ if(li->flags & NEWT_FLAG_SHOWCURSOR)
+ newtCursorOff();
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;
struct listbox * li = co->data;
struct items * item, * nextitem;
- nextitem = item = li->boxItems;
+ item = li->boxItems;
while (item != NULL) {
nextitem = item->next;
- free(item->key);
+ free(item->text);
free(item);
item = nextitem;
}
+ if (li->sb) li->sb->ops->destroy(li->sb);
+
free(li);
free(co);
}
-