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 */
5 
6 #include <slang.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11 
12 #include "newt.h"
13 #include "newt_pr.h"
14 
15 
16 /* Linked list of items in the listbox */
17 struct items {
18     char * text;
19     const void *data;
20     unsigned char isSelected;
21     struct items *next;
22 };
23 
24 /* Holds all the relevant information for this listbox */
25 struct listbox {
26     newtComponent sb;   /* Scrollbar on right side of listbox */
27     int curWidth;	/* size of text w/o scrollbar or border*/
28     int curHeight;	/* size of text w/o border */
29     int sbAdjust;
30     int bdxAdjust, bdyAdjust;
31     int numItems, numSelected;
32     int userHasSetWidth;
33     int currItem, startShowItem; /* startShowItem is the first item displayed
34 				   on the screen */
35     int isActive; /* If we handle key events all the time, it seems
36 		     to do things even when they are supposed to be for
37 		     another button/whatever */
38     struct items *boxItems;
39     int grow;
40     int flags; /* flags for this listbox, right now just
41 		  NEWT_FLAG_RETURNEXIT */
42 };
43 
44 static void listboxDraw(newtComponent co);
45 static void listboxDestroy(newtComponent co);
46 static struct eventResult listboxEvent(newtComponent co, struct event ev);
47 static void newtListboxRealSetCurrent(newtComponent co);
48 static void listboxPlace(newtComponent co, int newLeft, int newTop);
49 static inline void updateWidth(newtComponent co, struct listbox * li,
50 				int maxField);
51 static void listboxMapped(newtComponent co, int isMapped);
52 
53 static struct componentOps listboxOps = {
54     listboxDraw,
55     listboxEvent,
56     listboxDestroy,
57     listboxPlace,
58     listboxMapped,
59 };
60 
listboxMapped(newtComponent co,int isMapped)61 static void listboxMapped(newtComponent co, int isMapped) {
62     struct listbox * li = co->data;
63 
64     co->isMapped = isMapped;
65     if (li->sb)
66 	li->sb->ops->mapped(li->sb, isMapped);
67 }
68 
listboxPlace(newtComponent co,int newLeft,int newTop)69 static void listboxPlace(newtComponent co, int newLeft, int newTop) {
70     struct listbox * li = co->data;
71 
72     co->top = newTop;
73     co->left = newLeft;
74 
75     if (li->sb)
76 	li->sb->ops->place(li->sb, co->left + co->width - li->bdxAdjust - 1,
77 			   co->top + li->bdyAdjust);
78 }
79 
newtListbox(int left,int top,int height,int flags)80 newtComponent newtListbox(int left, int top, int height, int flags) {
81     newtComponent co, sb;
82     struct listbox * li;
83 
84     if (!(co = malloc(sizeof(*co))))
85 	return NULL;
86 
87     if (!(li = malloc(sizeof(struct listbox)))) {
88 	free(co);
89 	return NULL;
90     }
91 
92     li->boxItems = NULL;
93     li->numItems = 0;
94     li->currItem = 0;
95     li->numSelected = 0;
96     li->isActive = 0;
97     li->userHasSetWidth = 0;
98     li->startShowItem = 0;
99     li->sbAdjust = 0;
100     li->bdxAdjust = 0;
101     li->bdyAdjust = 0;
102     li->flags = flags & (NEWT_FLAG_RETURNEXIT | NEWT_FLAG_BORDER |
103 			 NEWT_FLAG_MULTIPLE | NEWT_FLAG_SHOWCURSOR);
104 
105     if (li->flags & NEWT_FLAG_BORDER) {
106 	li->bdxAdjust = 2;
107 	li->bdyAdjust = 1;
108     }
109 
110     co->height = height;
111     li->curHeight = co->height - (2 * li->bdyAdjust);
112 
113     if (height) {
114 	li->grow = 0;
115 	if (flags & NEWT_FLAG_SCROLL) {
116 	    sb = newtVerticalScrollbar(left, top + li->bdyAdjust,
117 					li->curHeight,
118 					COLORSET_LISTBOX, COLORSET_ACTLISTBOX);
119 	    li->sbAdjust = 3;
120 	} else {
121 	    sb = NULL;
122 	}
123     } else {
124 	li->grow = 1;
125 	sb = NULL;
126     }
127 
128     li->sb = sb;
129     co->data = li;
130     co->isMapped = 0;
131     co->left = left;
132     co->top = top;
133     co->ops = &listboxOps;
134     co->takesFocus = 1;
135     co->callback = NULL;
136     co->destroyCallback = NULL;
137 
138     updateWidth(co, li, 5);
139 
140     return co;
141 }
142 
updateWidth(newtComponent co,struct listbox * li,int maxField)143 static inline void updateWidth(newtComponent co, struct listbox * li,
144 				int maxField) {
145     li->curWidth = maxField;
146     co->width = li->curWidth + li->sbAdjust + 2 * li->bdxAdjust;
147 
148     if (li->sb)
149 	li->sb->left = co->left + co->width - li->bdxAdjust - 1;
150 }
151 
newtListboxSetCurrentByKey(newtComponent co,void * key)152 void newtListboxSetCurrentByKey(newtComponent co, void * key) {
153     struct listbox * li = co->data;
154     struct items * item;
155     int i;
156 
157     item = li->boxItems, i = 0;
158     while (item && item->data != key)
159 	item = item->next, i++;
160 
161     if (item)
162 	newtListboxSetCurrent(co, i);
163 }
164 
newtListboxSetCurrent(newtComponent co,int num)165 void newtListboxSetCurrent(newtComponent co, int num)
166 {
167     struct listbox * li = co->data;
168 
169     if (num >= li->numItems)
170 	li->currItem = li->numItems - 1;
171     else if (num < 0)
172 	li->currItem = 0;
173     else
174 	li->currItem = num;
175 
176     if (li->currItem < li->startShowItem)
177 	li->startShowItem = li->currItem;
178     else if (li->currItem - li->startShowItem > li->curHeight - 1)
179 	li->startShowItem = li->currItem - li->curHeight + 1;
180     if (li->startShowItem + li->curHeight > li->numItems)
181 	li->startShowItem = li->numItems - li->curHeight;
182     if(li->startShowItem < 0)
183 	li->startShowItem = 0;
184 
185     newtListboxRealSetCurrent(co);
186 }
187 
newtListboxRealSetCurrent(newtComponent co)188 static void newtListboxRealSetCurrent(newtComponent co)
189 {
190     struct listbox * li = co->data;
191 
192     if(li->sb)
193 	newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
194     listboxDraw(co);
195     if(co->callback) co->callback(co, co->callbackData);
196 }
197 
newtListboxSetWidth(newtComponent co,int width)198 void newtListboxSetWidth(newtComponent co, int width) {
199     struct listbox * li = co->data;
200 
201     co->width = width;
202     li->curWidth = co->width - li->sbAdjust - 2 * li->bdxAdjust;
203     li->userHasSetWidth = 1;
204     if (li->sb)
205 	li->sb->left = co->left + co->width - li->bdxAdjust - 1;
206     listboxDraw(co);
207 }
208 
newtListboxGetCurrent(newtComponent co)209 void * newtListboxGetCurrent(newtComponent co) {
210     struct listbox * li = co->data;
211     int i;
212     struct items *item;
213 
214     for(i = 0, item = li->boxItems; item != NULL && i < li->currItem;
215 	i++, item = item->next);
216 
217     if (item)
218 	return (void *)item->data;
219     else
220 	return NULL;
221 }
222 
newtListboxSelectItem(newtComponent co,const void * key,enum newtFlagsSense sense)223 void newtListboxSelectItem(newtComponent co, const void * key,
224 	enum newtFlagsSense sense)
225 {
226     struct listbox * li = co->data;
227     int i;
228     struct items * item;
229 
230     item = li->boxItems, i = 0;
231     while (item && item->data != key)
232 	item = item->next, i++;
233 
234     if (!item) return;
235 
236     if (item->isSelected)
237 	li->numSelected--;
238 
239     switch(sense) {
240 	case NEWT_FLAGS_RESET:
241 		item->isSelected = 0; break;
242 	case NEWT_FLAGS_SET:
243 		item->isSelected = 1; break;
244 	case NEWT_FLAGS_TOGGLE:
245 		item->isSelected = !item->isSelected;
246     }
247 
248     if (item->isSelected)
249 	li->numSelected++;
250 
251     listboxDraw(co);
252 }
253 
newtListboxClearSelection(newtComponent co)254 void newtListboxClearSelection(newtComponent co)
255 {
256     struct items *item;
257     struct listbox * li = co->data;
258 
259     for(item = li->boxItems; item != NULL;
260 	item = item->next)
261 	item->isSelected = 0;
262     li->numSelected = 0;
263     listboxDraw(co);
264 }
265 
266 /* Free the returned array after use, but NOT the values in the array */
newtListboxGetSelection(newtComponent co,int * numitems)267 void ** newtListboxGetSelection(newtComponent co, int *numitems)
268 {
269     struct listbox * li;
270     int i;
271     void **retval;
272     struct items *item;
273 
274     if(!co || !numitems) return NULL;
275 
276     li = co->data;
277     if(!li || !li->numSelected) return NULL;
278 
279     retval = malloc(li->numSelected * sizeof(void *));
280     for(i = 0, item = li->boxItems; item != NULL;
281 	item = item->next)
282 	if(item->isSelected)
283 	    retval[i++] = (void *)item->data;
284     *numitems = li->numSelected;
285     return retval;
286 }
287 
newtListboxSetEntry(newtComponent co,int num,const char * text)288 void newtListboxSetEntry(newtComponent co, int num, const char * text) {
289     struct listbox * li = co->data;
290     int i;
291     struct items *item;
292 
293     for(i = 0, item = li->boxItems; item != NULL && i < num;
294 	i++, item = item->next);
295 
296     if(!item)
297 	return;
298     else {
299 	free(item->text);
300 	item->text = strdup(text);
301     }
302     if (li->userHasSetWidth == 0 && wstrlen(text,-1) > li->curWidth) {
303 	updateWidth(co, li, wstrlen(text,-1));
304     }
305 
306     if (num >= li->startShowItem && num <= li->startShowItem + co->height)
307 	listboxDraw(co);
308 }
309 
newtListboxSetData(newtComponent co,int num,void * data)310 void newtListboxSetData(newtComponent co, int num, void * data) {
311     struct listbox * li = co->data;
312     int i;
313     struct items *item;
314 
315     for(i = 0, item = li->boxItems; item != NULL && i < num;
316 	i++, item = item->next);
317 
318     if (item)
319 	item->data = data;
320 }
321 
newtListboxAppendEntry(newtComponent co,const char * text,const void * data)322 int newtListboxAppendEntry(newtComponent co, const char * text,
323 	                const void * data) {
324     struct listbox * li = co->data;
325     struct items *item;
326 
327     if(li->boxItems) {
328 	for (item = li->boxItems; item->next != NULL; item = item->next);
329 
330 	item = item->next = malloc(sizeof(struct items));
331     } else {
332 	item = li->boxItems = malloc(sizeof(struct items));
333     }
334 
335     if (!li->userHasSetWidth && text && (wstrlen(text,-1) > li->curWidth))
336 	updateWidth(co, li, wstrlen(text,-1));
337 
338     item->text = strdup(text); item->data = data; item->next = NULL;
339     item->isSelected = 0;
340 
341     if (li->grow)
342 	co->height++, li->curHeight++;
343     li->numItems++;
344 
345     return 0;
346 }
347 
newtListboxInsertEntry(newtComponent co,const char * text,const void * data,void * key)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;
352 
353     if (li->boxItems) {
354 	if (key) {
355 	    item = li->boxItems;
356 	    while (item && item->data != key) item = item->next;
357 
358 	    if (!item) return 1;
359 
360 	    t = item->next;
361 	    item = item->next = malloc(sizeof(struct items));
362 	    item->next = t;
363 	} else {
364 	    t = li->boxItems;
365 	    item = li->boxItems = malloc(sizeof(struct items));
366 	    item->next = t;
367 	}
368     } else if (key) {
369 	return 1;
370     } else {
371 	item = li->boxItems = malloc(sizeof(struct items));
372 	item->next = NULL;
373     }
374 
375     if (!li->userHasSetWidth && text && (wstrlen(text,-1) > li->curWidth))
376 	updateWidth(co, li, wstrlen(text,-1));
377 
378     item->text = strdup(text?text:"(null)"); item->data = data;
379     item->isSelected = 0;
380 
381     if (li->sb)
382 	li->sb->left = co->left + co->width - li->bdxAdjust - 1;
383     li->numItems++;
384 
385     listboxDraw(co);
386 
387     return 0;
388 }
389 
newtListboxDeleteEntry(newtComponent co,void * key)390 int newtListboxDeleteEntry(newtComponent co, void * key) {
391     struct listbox * li = co->data;
392     int widest = 0, t;
393     struct items *item, *item2 = NULL;
394     int num;
395 
396     if (li->boxItems == NULL || li->numItems <= 0)
397 	return 0;
398 
399     num = 0;
400 
401     item2 = NULL, item = li->boxItems;
402     while (item && item->data != key) {
403 	item2 = item;
404 	item = item->next;
405 	num++;
406     }
407 
408     if (!item)
409 	return -1;
410 
411     if (item2)
412 	item2->next = item->next;
413     else
414 	li->boxItems = item->next;
415 
416     free(item->text);
417     free(item);
418     li->numItems--;
419 
420     if (!li->userHasSetWidth) {
421 	widest = 0;
422 	for (item = li->boxItems; item != NULL; item = item->next)
423 	    if ((t = wstrlen(item->text,-1)) > widest) widest = t;
424     }
425 
426     if (li->currItem >= num)
427 	li->currItem--;
428 
429     if (!li->userHasSetWidth) {
430 	updateWidth(co, li, widest);
431     }
432 
433     listboxDraw(co);
434 
435     return 0;
436 }
437 
newtListboxClear(newtComponent co)438 void newtListboxClear(newtComponent co)
439 {
440     struct listbox * li;
441     struct items *anitem, *nextitem;
442     if(co == NULL || (li = co->data) == NULL)
443 	return;
444     for(anitem = li->boxItems; anitem != NULL; anitem = nextitem) {
445 	nextitem = anitem->next;
446 	free(anitem->text);
447 	free(anitem);
448     }
449     li->numItems = li->numSelected = li->currItem = li->startShowItem = 0;
450     li->boxItems = NULL;
451     if (!li->userHasSetWidth)
452 	updateWidth(co, li, 5);
453 }
454 
newtListboxItemCount(newtComponent co)455 int newtListboxItemCount(newtComponent co)
456 {
457     struct listbox *li = co->data;
458     return li->numItems;
459 }
460 
461 /* If you don't want to get back the text, pass in NULL for the ptr-ptr. Same
462    goes for the data. */
newtListboxGetEntry(newtComponent co,int num,char ** text,void ** data)463 void newtListboxGetEntry(newtComponent co, int num, char **text, void **data) {
464     struct listbox * li = co->data;
465     int i;
466     struct items *item;
467 
468     if (!li->boxItems || num >= li->numItems) {
469 	if(text)
470 	    *text = NULL;
471 	if(data)
472 	    *data = NULL;
473 	return;
474     }
475 
476     i = 0;
477     item = li->boxItems;
478     while (item && i < num) {
479 	i++, item = item->next;
480     }
481 
482     if (item) {
483 	if (text)
484 	    *text = item->text;
485 	if (data)
486 	    *data = (void *)item->data;
487     }
488 }
489 
listboxDraw(newtComponent co)490 static void listboxDraw(newtComponent co)
491 {
492     struct listbox * li = co->data;
493     struct items *item;
494     int i, j;
495 
496     if (!co->isMapped) return ;
497 
498     newtTrashScreen();
499 
500     if(li->flags & NEWT_FLAG_BORDER) {
501       if(li->isActive)
502 	  SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
503       else
504           SLsmg_set_color(NEWT_COLORSET_LISTBOX);
505 
506       newtDrawBox(co->left, co->top, co->width, co->height, 0);
507     }
508 
509     if(li->sb)
510 	li->sb->ops->draw(li->sb);
511 
512     SLsmg_set_color(NEWT_COLORSET_LISTBOX);
513 
514     for(i = 0, item = li->boxItems; item != NULL && i < li->startShowItem;
515 	i++, item = item->next);
516 
517     j = i;
518 
519     for (i = 0; item != NULL && i < li->curHeight; i++, item = item->next) {
520 	if (!item->text) continue;
521 
522 	newtGotorc(co->top + i + li->bdyAdjust, co->left + li->bdxAdjust);
523 	if(j + i == li->currItem) {
524 	    if(li->isActive)
525 		SLsmg_set_color(NEWT_COLORSET_ACTSELLISTBOX);
526 	    else
527 		SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
528 	} else if(item->isSelected)
529 	    SLsmg_set_color(NEWT_COLORSET_SELLISTBOX);
530 	else
531 	    SLsmg_set_color(NEWT_COLORSET_LISTBOX);
532 
533 	SLsmg_write_nstring(item->text, li->curWidth);
534 
535 	if (li->flags & NEWT_FLAG_MULTIPLE) {
536 	    newtGotorc(co->top + i + li->bdyAdjust, co->left + li->bdxAdjust);
537 	    SLsmg_set_color(item->isSelected ?
538 		    NEWT_COLORSET_SELLISTBOX : NEWT_COLORSET_LISTBOX);
539 	    SLsmg_write_nstring(item->text, 1);
540 	}
541     }
542     newtGotorc(co->top + (li->currItem - li->startShowItem) + li->bdyAdjust,
543                co->left + li->bdxAdjust);
544 }
545 
listboxEvent(newtComponent co,struct event ev)546 static struct eventResult listboxEvent(newtComponent co, struct event ev) {
547     struct eventResult er;
548     struct listbox * li = co->data;
549     struct items *item;
550     int i;
551 
552     er.result = ER_IGNORED;
553 
554     if(ev.when == EV_EARLY || ev.when == EV_LATE) {
555 	return er;
556     }
557 
558     switch(ev.event) {
559       case EV_KEYPRESS:
560 	if (!li->isActive) break;
561 
562 	switch(ev.u.key) {
563 	  case ' ':
564 	    if(!(li->flags & NEWT_FLAG_MULTIPLE)) break;
565 	    newtListboxSelectItem(co, newtListboxGetCurrent(co),
566 				  NEWT_FLAGS_TOGGLE);
567 	    er.result = ER_SWALLOWED;
568 	    /* We don't break here, because it is cool to be able to
569 	       hold space to select a bunch of items in a list at once */
570 
571 	  case NEWT_KEY_DOWN:
572 	    if(li->numItems <= 0) break;
573 	    if(li->currItem < li->numItems - 1) {
574 		li->currItem++;
575 		if(li->currItem > (li->startShowItem + li->curHeight - 1)) {
576 		    li->startShowItem = li->currItem - li->curHeight + 1;
577 		    if(li->startShowItem + li->curHeight > li->numItems)
578 			li->startShowItem = li->numItems - li->curHeight;
579 		}
580 		if(li->sb)
581 		    newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
582 		listboxDraw(co);
583 	    }
584 	    if(co->callback) co->callback(co, co->callbackData);
585 	    er.result = ER_SWALLOWED;
586 	    break;
587 
588 	  case NEWT_KEY_ENTER:
589 	    if(li->numItems <= 0) break;
590 	    if(li->flags & NEWT_FLAG_RETURNEXIT)
591 		er.result = ER_EXITFORM;
592 	    break;
593 
594 	  case NEWT_KEY_UP:
595 	    if(li->numItems <= 0) break;
596 	    if(li->currItem > 0) {
597 		li->currItem--;
598 		if(li->currItem < li->startShowItem)
599 		    li->startShowItem = li->currItem;
600 		if(li->sb)
601 		    newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
602 		listboxDraw(co);
603 	    }
604 	    if(co->callback) co->callback(co, co->callbackData);
605 	    er.result = ER_SWALLOWED;
606 	    break;
607 
608 	  case NEWT_KEY_PGUP:
609 	    if(li->numItems <= 0) break;
610 	    li->startShowItem -= li->curHeight - 1;
611 	    if(li->startShowItem < 0)
612 		li->startShowItem = 0;
613 	    li->currItem -= li->curHeight - 1;
614 	    if(li->currItem < 0)
615 		li->currItem = 0;
616 	    newtListboxRealSetCurrent(co);
617 	    er.result = ER_SWALLOWED;
618 	    break;
619 
620 	  case NEWT_KEY_PGDN:
621 	    if(li->numItems <= 0) break;
622 	    li->startShowItem += li->curHeight;
623 	    if(li->startShowItem > (li->numItems - li->curHeight)) {
624 		li->startShowItem = li->numItems - li->curHeight;
625 	    }
626 	    li->currItem += li->curHeight;
627 	    if(li->currItem >= li->numItems) {
628 		li->currItem = li->numItems - 1;
629 	    }
630 	    newtListboxRealSetCurrent(co);
631 	    er.result = ER_SWALLOWED;
632 	    break;
633 
634 	  case NEWT_KEY_HOME:
635 	    if(li->numItems <= 0) break;
636 	    newtListboxSetCurrent(co, 0);
637 	    er.result = ER_SWALLOWED;
638 	    break;
639 
640 	  case NEWT_KEY_END:
641 	    if(li->numItems <= 0) break;
642 	    li->startShowItem = li->numItems - li->curHeight;
643 	    if(li->startShowItem < 0)
644 		li->startShowItem = 0;
645 	    li->currItem = li->numItems - 1;
646 	    newtListboxRealSetCurrent(co);
647 	    er.result = ER_SWALLOWED;
648 	    break;
649 	  default:
650 	      if (li->numItems <= 0) break;
651               if (ev.u.key < NEWT_KEY_EXTRA_BASE && isalpha(ev.u.key)) {
652 		  for(i = 0, item = li->boxItems; item != NULL &&
653 			  i < li->currItem; i++, item = item->next);
654 
655 		  if (item && item->text && (toupper(*item->text) == toupper(ev.u.key))) {
656 		      item = item->next;
657 		      i++;
658 		  } else {
659 		      item = li->boxItems;
660 		      i = 0;
661 		  }
662 		  while (item && item->text &&
663 			 toupper(*item->text) != toupper(ev.u.key)) {
664 		      item = item->next;
665 		      i++;
666 		  }
667 		  if (item) {
668 		      li->currItem = i;
669 		      if(li->currItem < li->startShowItem ||
670 			 li->currItem > li->startShowItem)
671 			  li->startShowItem =
672 			      li->currItem > li->numItems - li->curHeight ?
673 			      li->numItems - li->curHeight :
674 			      li->currItem;
675 		      if(li->sb)
676 			  newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
677 		      newtListboxRealSetCurrent(co);
678 		      er.result = ER_SWALLOWED;
679 		  }
680 	      }
681 	}
682 	break;
683 
684       case EV_FOCUS:
685 	li->isActive = 1;
686 	listboxDraw(co);
687 	if(li->flags & NEWT_FLAG_SHOWCURSOR)
688 	  newtCursorOn();
689 	er.result = ER_SWALLOWED;
690 	break;
691 
692       case EV_UNFOCUS:
693 	li->isActive = 0;
694 	listboxDraw(co);
695 	if(li->flags & NEWT_FLAG_SHOWCURSOR)
696 	  newtCursorOff();
697 	er.result = ER_SWALLOWED;
698 	break;
699 
700       case EV_MOUSE:
701 	  /* if this mouse click was within the listbox, make the current
702 	     item the item clicked on. */
703 	/* Up scroll arrow */
704 	if (li->sb &&
705 	    ev.u.mouse.x == co->left + co->width - li->bdxAdjust - 1 &&
706 	    ev.u.mouse.y == co->top + li->bdyAdjust) {
707 	    if(li->numItems <= 0) break;
708 	    if(li->currItem > 0) {
709 		li->currItem--;
710 		if(li->currItem < li->startShowItem)
711 		    li->startShowItem = li->currItem;
712 		if(li->sb)
713 		    newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
714 		listboxDraw(co);
715 	    }
716 	    if(co->callback) co->callback(co, co->callbackData);
717 	    er.result = ER_SWALLOWED;
718 	    break;
719 	}
720 	/* Down scroll arrow */
721 	if (li->sb &&
722 	    ev.u.mouse.x == co->left + co->width - li->bdxAdjust - 1 &&
723 	    ev.u.mouse.y == co->top + co->height - li->bdyAdjust - 1) {
724 	    if(li->numItems <= 0) break;
725 	    if(li->currItem < li->numItems - 1) {
726 		li->currItem++;
727 		if(li->currItem > (li->startShowItem + li->curHeight - 1)) {
728 		    li->startShowItem = li->currItem - li->curHeight + 1;
729 		    if(li->startShowItem + li->curHeight > li->numItems)
730 			li->startShowItem = li->numItems - li->curHeight;
731 		}
732 		if(li->sb)
733 		    newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
734 		listboxDraw(co);
735 	    }
736 	    if(co->callback) co->callback(co, co->callbackData);
737 	    er.result = ER_SWALLOWED;
738 	    break;
739 	}
740 	if ((ev.u.mouse.y >= co->top + li->bdyAdjust) &&
741 	    (ev.u.mouse.y <= co->top + co->height - (li->bdyAdjust * 2)) &&
742 	    (ev.u.mouse.x >= co->left + li->bdxAdjust) &&
743 	    (ev.u.mouse.x <= co->left + co->width + (li->bdxAdjust * 2))) {
744 	    li->currItem = li->startShowItem +
745 		(ev.u.mouse.y - li->bdyAdjust - co->top);
746 	    newtListboxRealSetCurrent(co);
747 	    listboxDraw(co);
748 	    if(co->callback) co->callback(co, co->callbackData);
749 	    er.result = ER_SWALLOWED;
750 	    break;
751 	}
752     }
753 
754     return er;
755 }
756 
listboxDestroy(newtComponent co)757 static void listboxDestroy(newtComponent co) {
758     struct listbox * li = co->data;
759     struct items * item, * nextitem;
760 
761     nextitem = item = li->boxItems;
762 
763     while (item != NULL) {
764 	nextitem = item->next;
765 	free(item->text);
766 	free(item);
767 	item = nextitem;
768     }
769 
770     if (li->sb) li->sb->ops->destroy(li->sb);
771 
772     free(li);
773     free(co);
774 }
775