1
/* This goofed-up box whacked into shape by Elliot Lee <sopwith@cuc.edu>
2
(from the original listbox by Erik Troan <ewt@redhat.com>)
3
and contributed to newt for use under the LGPL license.
4
Copyright (C) 1996, 1997 Elliot Lee */
16
#define strwidth strlen
19
/* Linked list of items in the listbox */
23
unsigned char isSelected;
27
/* Holds all the relevant information for this listbox */
29
newtComponent sb; /* Scrollbar on right side of listbox */
30
int curWidth; /* size of text w/o scrollbar or border*/
31
int curHeight; /* size of text w/o border */
33
int bdxAdjust, bdyAdjust;
34
int numItems, numSelected;
36
int currItem, startShowItem; /* startShowItem is the first item displayed
38
int isActive; /* If we handle key events all the time, it seems
39
to do things even when they are supposed to be for
40
another button/whatever */
41
struct items *boxItems;
43
int flags; /* flags for this listbox, right now just
44
NEWT_FLAG_RETURNEXIT */
47
static void listboxDraw(newtComponent co);
48
static void listboxDestroy(newtComponent co);
49
static struct eventResult listboxEvent(newtComponent co, struct event ev);
50
static void newtListboxRealSetCurrent(newtComponent co);
51
static void listboxPlace(newtComponent co, int newLeft, int newTop);
52
static inline void updateWidth(newtComponent co, struct listbox * li,
54
static void listboxMapped(newtComponent co, int isMapped);
56
static struct componentOps listboxOps = {
64
static void listboxMapped(newtComponent co, int isMapped) {
65
struct listbox * li = co->data;
67
co->isMapped = isMapped;
69
li->sb->ops->mapped(li->sb, isMapped);
72
static void listboxPlace(newtComponent co, int newLeft, int newTop) {
73
struct listbox * li = co->data;
79
li->sb->ops->place(li->sb, co->left + co->width - li->bdxAdjust - 1,
83
newtComponent newtListbox(int left, int top, int height, int flags) {
87
if (!(co = malloc(sizeof(*co))))
90
if (!(li = malloc(sizeof(struct listbox)))) {
100
li->userHasSetWidth = 0;
101
li->startShowItem = 0;
105
li->flags = flags & (NEWT_FLAG_RETURNEXIT | NEWT_FLAG_BORDER |
108
if (li->flags & NEWT_FLAG_BORDER) {
114
li->curHeight = co->height - (2 * li->bdyAdjust);
118
if (flags & NEWT_FLAG_SCROLL) {
119
sb = newtVerticalScrollbar(left, top + li->bdyAdjust,
121
COLORSET_LISTBOX, COLORSET_ACTLISTBOX);
136
co->ops = &listboxOps;
140
updateWidth(co, li, 5);
145
static inline void updateWidth(newtComponent co, struct listbox * li,
147
li->curWidth = maxField;
148
co->width = li->curWidth + li->sbAdjust + 2 * li->bdxAdjust;
151
li->sb->left = co->left + co->width - li->bdxAdjust - 1;
154
void newtListboxSetCurrentByKey(newtComponent co, void * key) {
155
struct listbox * li = co->data;
159
item = li->boxItems, i = 0;
160
while (item && item->data != key)
161
item = item->next, i++;
164
newtListboxSetCurrent(co, i);
167
void newtListboxSetCurrent(newtComponent co, int num)
169
struct listbox * li = co->data;
171
if (num >= li->numItems)
172
li->currItem = li->numItems - 1;
178
if (li->currItem < li->startShowItem)
179
li->startShowItem = li->currItem;
180
else if (li->currItem - li->startShowItem > li->curHeight - 1)
181
li->startShowItem = li->currItem - li->curHeight + 1;
182
if (li->startShowItem + li->curHeight > li->numItems)
183
li->startShowItem = li->numItems - li->curHeight;
184
if(li->startShowItem < 0)
185
li->startShowItem = 0;
187
newtListboxRealSetCurrent(co);
190
static void newtListboxRealSetCurrent(newtComponent co)
192
struct listbox * li = co->data;
195
newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
197
if(co->callback) co->callback(co, co->callbackData);
200
void newtListboxSetWidth(newtComponent co, int width) {
201
struct listbox * li = co->data;
204
li->curWidth = co->width - li->sbAdjust - 2 * li->bdxAdjust;
205
li->userHasSetWidth = 1;
206
if (li->sb) li->sb->left = co->width + co->left - 1;
210
void * newtListboxGetCurrent(newtComponent co) {
211
struct listbox * li = co->data;
215
for(i = 0, item = li->boxItems; item != NULL && i < li->currItem;
216
i++, item = item->next);
219
return (void *)item->data;
224
void newtListboxSelectItem(newtComponent co, const void * key,
225
enum newtFlagsSense sense)
227
struct listbox * li = co->data;
231
item = li->boxItems, i = 0;
232
while (item && item->data != key)
233
item = item->next, i++;
237
if (item->isSelected)
241
case NEWT_FLAGS_RESET:
242
item->isSelected = 0; break;
244
item->isSelected = 1; break;
245
case NEWT_FLAGS_TOGGLE:
246
item->isSelected = !item->isSelected;
249
if (item->isSelected)
255
void newtListboxClearSelection(newtComponent co)
258
struct listbox * li = co->data;
260
for(item = li->boxItems; item != NULL;
262
item->isSelected = 0;
267
/* Free the returned array after use, but NOT the values in the array */
268
void ** newtListboxGetSelection(newtComponent co, int *numitems)
275
if(!co || !numitems) return NULL;
278
if(!li || !li->numSelected) return NULL;
280
retval = malloc(li->numSelected * sizeof(void *));
281
for(i = 0, item = li->boxItems; item != NULL;
284
retval[i++] = (void *)item->data;
285
*numitems = li->numSelected;
289
void newtListboxSetEntry(newtComponent co, int num, const char * text) {
290
struct listbox * li = co->data;
294
for(i = 0, item = li->boxItems; item != NULL && i < num;
295
i++, item = item->next);
301
item->text = strdup(text);
303
if (li->userHasSetWidth == 0 && strwidth(text) > li->curWidth) {
304
updateWidth(co, li, strwidth(text));
307
if (num >= li->startShowItem && num <= li->startShowItem + co->height)
311
void newtListboxSetData(newtComponent co, int num, void * data) {
312
struct listbox * li = co->data;
316
for(i = 0, item = li->boxItems; item != NULL && i < num;
317
i++, item = item->next);
322
int newtListboxAppendEntry(newtComponent co, const char * text,
324
struct listbox * li = co->data;
328
for (item = li->boxItems; item->next != NULL; item = item->next);
330
item = item->next = malloc(sizeof(struct items));
332
item = li->boxItems = malloc(sizeof(struct items));
335
if (!li->userHasSetWidth && text && (strwidth(text) > li->curWidth))
336
updateWidth(co, li, strwidth(text));
338
item->text = strdup(text); item->data = data; item->next = NULL;
339
item->isSelected = 0;
342
co->height++, li->curHeight++;
348
int newtListboxInsertEntry(newtComponent co, const char * text,
349
const void * data, void * key) {
350
struct listbox * li = co->data;
351
struct items *item, *t;
356
while (item && item->data != key) item = item->next;
361
item = item->next = malloc(sizeof(struct items));
365
item = li->boxItems = malloc(sizeof(struct items));
371
item = li->boxItems = malloc(sizeof(struct items));
375
if (!li->userHasSetWidth && text && (strwidth(text) > li->curWidth))
376
updateWidth(co, li, strwidth(text));
378
item->text = strdup(text?text:"(null)"); item->data = data;
379
item->isSelected = 0;
382
li->sb->left = co->left + co->width - li->bdxAdjust - 1;
390
int newtListboxDeleteEntry(newtComponent co, void * key) {
391
struct listbox * li = co->data;
393
struct items *item, *item2 = NULL;
396
if (li->boxItems == NULL || li->numItems <= 0)
401
item2 = NULL, item = li->boxItems;
402
while (item && item->data != key) {
412
item2->next = item->next;
414
li->boxItems = item->next;
420
if (!li->userHasSetWidth) {
422
for (item = li->boxItems; item != NULL; item = item->next)
423
if ((t = strwidth(item->text)) > widest) widest = t;
426
if (li->currItem >= num)
429
if (!li->userHasSetWidth) {
430
updateWidth(co, li, widest);
438
void newtListboxClear(newtComponent co)
441
struct items *anitem, *nextitem;
442
if(co == NULL || (li = co->data) == NULL)
444
for(anitem = li->boxItems; anitem != NULL; anitem = nextitem) {
445
nextitem = anitem->next;
449
li->numItems = li->numSelected = li->currItem = li->startShowItem = 0;
451
if (!li->userHasSetWidth)
452
updateWidth(co, li, 5);
455
/* If you don't want to get back the text, pass in NULL for the ptr-ptr. Same
456
goes for the data. */
457
void newtListboxGetEntry(newtComponent co, int num, char **text, void **data) {
458
struct listbox * li = co->data;
462
if (!li->boxItems || num >= li->numItems) {
472
while (item && i < num) {
473
i++, item = item->next;
480
*data = (void *)item->data;
484
static void listboxDraw(newtComponent co)
486
struct listbox * li = co->data;
491
if (!co->isMapped) return ;
493
if(li->flags & NEWT_FLAG_BORDER) {
495
newtColor(NEWT_COLORSET_ACTLISTBOX);
497
newtColor(NEWT_COLORSET_LISTBOX);
499
newtColor(NEWT_COLORSET_BORDER);
500
newtDrawBox(co->left, co->top, co->width, co->height, 0);
510
li->sb->ops->draw(li->sb);
512
newtColor(NEWT_COLORSET_LISTBOX);
514
for(i = 0, item = li->boxItems; item != NULL && i < li->startShowItem;
515
i++, item = item->next);
519
for (i = 0; item != NULL && i < li->curHeight; i++, item = item->next) {
520
if (!item->text) continue;
522
newtGotorc(co->top + i + li->bdyAdjust, co->left + li->bdxAdjust);
523
if(j + i == li->currItem) {
525
newtColor(NEWT_COLORSET_ACTSELLISTBOX);
527
newtColor(NEWT_COLORSET_SELLISTBOX);
528
} else if(li->isActive)
529
newtColor(NEWT_COLORSET_ACTLISTBOX);
531
newtColor(NEWT_COLORSET_LISTBOX);
533
SLsmg_write_nstring(item->text, li->curWidth);
536
newtGotorc(co->top + yadj + (li->currItem - li->startShowItem), co->left + xadj);
539
static struct eventResult listboxEvent(newtComponent co, struct event ev) {
540
struct eventResult er;
541
struct listbox * li = co->data;
545
er.result = ER_IGNORED;
547
if(ev.when == EV_EARLY || ev.when == EV_LATE) {
553
if (!li->isActive) break;
557
if(!(li->flags & NEWT_FLAG_MULTIPLE)) break;
558
newtListboxSelectItem(co, li->boxItems[li->currItem].data,
560
er.result = ER_SWALLOWED;
561
/* We don't break here, because it is cool to be able to
562
hold space to select a bunch of items in a list at once */
565
if(li->numItems <= 0) break;
566
if(li->currItem < li->numItems - 1) {
568
if(li->currItem > (li->startShowItem + li->curHeight - 1)) {
569
li->startShowItem = li->currItem - li->curHeight + 1;
570
if(li->startShowItem + li->curHeight > li->numItems)
571
li->startShowItem = li->numItems - li->curHeight;
574
newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
577
if(co->callback) co->callback(co, co->callbackData);
578
er.result = ER_SWALLOWED;
582
if(li->numItems <= 0) break;
583
if(li->flags & NEWT_FLAG_RETURNEXIT)
584
er.result = ER_EXITFORM;
588
if(li->numItems <= 0) break;
589
if(li->currItem > 0) {
591
if(li->currItem < li->startShowItem)
592
li->startShowItem = li->currItem;
594
newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
597
if(co->callback) co->callback(co, co->callbackData);
598
er.result = ER_SWALLOWED;
602
if(li->numItems <= 0) break;
603
li->startShowItem -= li->curHeight - 1;
604
if(li->startShowItem < 0)
605
li->startShowItem = 0;
606
li->currItem -= li->curHeight - 1;
609
newtListboxRealSetCurrent(co);
610
er.result = ER_SWALLOWED;
614
if(li->numItems <= 0) break;
615
li->startShowItem += li->curHeight;
616
if(li->startShowItem > (li->numItems - li->curHeight)) {
617
li->startShowItem = li->numItems - li->curHeight;
619
li->currItem += li->curHeight;
620
if(li->currItem >= li->numItems) {
621
li->currItem = li->numItems - 1;
623
newtListboxRealSetCurrent(co);
624
er.result = ER_SWALLOWED;
628
if(li->numItems <= 0) break;
629
newtListboxSetCurrent(co, 0);
630
er.result = ER_SWALLOWED;
634
if(li->numItems <= 0) break;
635
li->startShowItem = li->numItems - li->curHeight;
636
if(li->startShowItem < 0)
637
li->startShowItem = 0;
638
li->currItem = li->numItems - 1;
639
newtListboxRealSetCurrent(co);
640
er.result = ER_SWALLOWED;
643
if (li->numItems <= 0) break;
644
if (ev.u.key < NEWT_KEY_EXTRA_BASE && isalpha(ev.u.key)) {
645
for(i = 0, item = li->boxItems; item != NULL &&
646
i < li->currItem; i++, item = item->next);
648
if (item && item->text && (toupper(*item->text) == toupper(ev.u.key))) {
655
while (item && item->text &&
656
toupper(*item->text) != toupper(ev.u.key)) {
662
if(li->currItem < li->startShowItem ||
663
li->currItem > li->startShowItem)
665
li->currItem > li->numItems - li->curHeight ?
666
li->startShowItem = li->numItems - li->curHeight :
669
newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
670
newtListboxRealSetCurrent(co);
671
er.result = ER_SWALLOWED;
680
er.result = ER_SWALLOWED;
686
er.result = ER_SWALLOWED;
690
/* if this mouse click was within the listbox, make the current
691
item the item clicked on. */
692
/* Up scroll arrow */
694
ev.u.mouse.x == co->left + co->width - li->bdxAdjust - 1 &&
695
ev.u.mouse.y == co->top + li->bdyAdjust) {
696
if(li->numItems <= 0) break;
697
if(li->currItem > 0) {
699
if(li->currItem < li->startShowItem)
700
li->startShowItem = li->currItem;
702
newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
705
if(co->callback) co->callback(co, co->callbackData);
706
er.result = ER_SWALLOWED;
709
/* Down scroll arrow */
711
ev.u.mouse.x == co->left + co->width - li->bdxAdjust - 1 &&
712
ev.u.mouse.y == co->top + co->height - li->bdyAdjust - 1) {
713
if(li->numItems <= 0) break;
714
if(li->currItem < li->numItems - 1) {
716
if(li->currItem > (li->startShowItem + li->curHeight - 1)) {
717
li->startShowItem = li->currItem - li->curHeight + 1;
718
if(li->startShowItem + li->curHeight > li->numItems)
719
li->startShowItem = li->numItems - li->curHeight;
722
newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
725
if(co->callback) co->callback(co, co->callbackData);
726
er.result = ER_SWALLOWED;
729
if ((ev.u.mouse.y >= co->top + li->bdyAdjust) &&
730
(ev.u.mouse.y <= co->top + co->height - (li->bdyAdjust * 2)) &&
731
(ev.u.mouse.x >= co->left + li->bdxAdjust) &&
732
(ev.u.mouse.x <= co->left + co->width + (li->bdxAdjust * 2))) {
733
li->currItem = li->startShowItem +
734
(ev.u.mouse.y - li->bdyAdjust - co->top);
735
newtListboxRealSetCurrent(co);
737
if(co->callback) co->callback(co, co->callbackData);
738
er.result = ER_SWALLOWED;
746
static void listboxDestroy(newtComponent co) {
747
struct listbox * li = co->data;
748
struct items * item, * nextitem;
750
nextitem = item = li->boxItems;
752
while (item != NULL) {
753
nextitem = item->next;
759
if (li->sb) li->sb->ops->destroy(li->sb);