]> git.ipfire.org Git - thirdparty/newt.git/blobdiff - listbox.c
install python modules to purelib and platlib
[thirdparty/newt.git] / listbox.c
index fb3a860bb71f983ff10d61e17c8b5972dc05beca..aae4f836f7c108b02ca93de826fe3a1800637c85 100644 (file)
--- a/listbox.c
+++ b/listbox.c
-#include <slang/slang.h>
+/* 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 * items, form;
-    int numItems;
-    int allocedItems;
-    int flags;
-    newtComponent sb;
+    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 + li->bdyAdjust);
+}
 
 newtComponent newtListbox(int left, int top, int height, int flags) {
     newtComponent co, sb;
     struct listbox * li;
 
-    co = malloc(sizeof(*co));
-    li = malloc(sizeof(struct listbox));
+    if (!(co = malloc(sizeof(*co))))
+       return NULL;
 
-    li->allocedItems = 5;
-    li->numItems = 0; 
-    li->flags = flags;
-    li->items = malloc(li->allocedItems * sizeof(*li->items));
+    if (!(li = malloc(sizeof(struct listbox)))) {
+       free(co);
+       return NULL;
+    }
 
-    if (height) 
-       sb = newtVerticalScrollbar(left, top, height, COLORSET_LISTBOX,
-                                  COLORSET_ACTLISTBOX);
-    else
-       sb = NULL;
-    li->form = newtForm(sb);
-    li->sb = sb;
+    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 | NEWT_FLAG_SHOWCURSOR);
+
+    if (li->flags & NEWT_FLAG_BORDER) {
+       li->bdxAdjust = 2;
+       li->bdyAdjust = 1;
+    }
+
+    co->height = height;
+    li->curHeight = co->height - (2 * li->bdyAdjust);
 
     if (height) {
-       newtFormSetHeight(li->form, height);
-       newtFormAddComponent(li->form, sb);
+       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->height = li->form->height;
-    co->width = li->form->width;
     co->ops = &listboxOps;
     co->takesFocus = 1;
+    co->callback = NULL;
+    co->destroyCallback = NULL;
+
+    updateWidth(co, li, 5);
 
     return co;
 }
 
-void newtListboxSetCurrent(newtComponent co, int num) {
+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++;
 
-    newtFormSetCurrent(li->form, li->items[num]);
+    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->left + co->width - li->bdxAdjust - 1;
+    listboxDraw(co);
 }
 
 void * newtListboxGetCurrent(newtComponent co) {
     struct listbox * li = co->data;
-    newtComponent curr;
     int i;
+    struct items *item;
 
-    /* Having to do this linearly is really, really dumb */
+    for(i = 0, item = li->boxItems; item != NULL && i < li->currItem;
+       i++, item = item->next);
 
-    curr = newtFormGetCurrent(li->form);
-    for (i = 0; i < li->numItems; i++) {
-       if (li->items[i] == curr) break;
-    }
-    if (li->items[i] == curr) 
-        return newtListitemGetData(li->items[i]);
+    if (item)
+       return (void *)item->data;
     else
        return NULL;
 }
 
-void newtListboxSetEntry(newtComponent co, int num, char * text) {
+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;
 
-    /* this won't increase the size of the listbox! */
+    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;
 
-    newtListitemSet(li->items[num], text);
-    co->ops->draw(co);
+    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 newtListboxAddEntry(newtComponent co, char * text, void * data) {
+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 (li->numItems == li->allocedItems) {
-       li->allocedItems += 5;
-       li->items = realloc(li->items, li->allocedItems * sizeof(*li->items));
+    if(!item)
+       return;
+    else {
+       free(item->text);
+       item->text = strdup(text);
+    }
+    if (li->userHasSetWidth == 0 && wstrlen(text,-1) > li->curWidth) {
+       updateWidth(co, li, wstrlen(text,-1));
     }
 
-    if (li->numItems)
-       li->items[li->numItems] = newtListitem(co->left, 
-                                              li->numItems + co->top, 
-                                              text, 0,
-                                              li->items[li->numItems - 1],
-                                              data);
-    else
-       li->items[li->numItems] = newtListitem(co->left, 
-                                              li->numItems + co->top, 
-                                              text, 0, NULL, data);
+    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;
 
-    newtFormAddComponent(li->form, li->items[li->numItems]);
+    for(i = 0, item = li->boxItems; item != NULL && i < num;
+       i++, item = item->next);
+
+    if (item)
+       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 && (wstrlen(text,-1) > li->curWidth))
+       updateWidth(co, li, wstrlen(text,-1));
+
+    item->text = strdup(text); item->data = data; item->next = NULL;
+    item->isSelected = 0;
+
+    if (li->grow)
+       co->height++, li->curHeight++;
     li->numItems++;
 
-    co->height = li->form->height;
-    co->width = li->form->width;
+    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 && (wstrlen(text,-1) > li->curWidth))
+       updateWidth(co, li, wstrlen(text,-1));
+
+    item->text = strdup(text?text:"(null)"); item->data = data;
+    item->isSelected = 0;
 
     if (li->sb)
-       li->sb->left = co->left + co->width;
+       li->sb->left = co->left + co->width - li->bdxAdjust - 1;
+    li->numItems++;
+
+    listboxDraw(co);
+
+    return 0;
 }
 
-static void listboxDraw(newtComponent co) {
+int newtListboxDeleteEntry(newtComponent co, void * key) {
     struct listbox * li = co->data;
+    int widest = 0, t;
+    struct items *item, *item2 = NULL;
+    int num;
 
-    li->form->ops->draw(li->form);
+    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 = wstrlen(item->text,-1)) > widest) widest = t;
+    }
+
+    if (li->currItem >= num)
+       li->currItem--;
+
+    if (!li->userHasSetWidth) {
+       updateWidth(co, li, widest);
+    }
+
+    listboxDraw(co);
+
+    return 0;
 }
 
-static struct eventResult listboxEvent(newtComponent co, struct event ev) {
+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);
+}
+
+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) {
+    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 ;
+
+    newtTrashScreen();
+    
+    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(li->isActive)
+               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);
+
+       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) + 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 ((li->flags & NEWT_LISTBOX_RETURNEXIT) && ev.when == EV_NORMAL && 
-       ev.event == EV_KEYPRESS && ev.u.key == '\r') {
-       er.result = ER_EXITFORM;
+    if(ev.when == EV_EARLY || ev.when == EV_LATE) {
        return er;
     }
 
-    return li->form->ops->event(li->form, ev);
+    switch(ev.event) {
+      case EV_KEYPRESS:
+       if (!li->isActive) break;
+
+       switch(ev.u.key) {
+         case ' ':
+           if(!(li->flags & NEWT_FLAG_MULTIPLE)) break;
+           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 */
+
+         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);
+       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;
 }
 
 static void listboxDestroy(newtComponent co) {
     struct listbox * li = co->data;
+    struct items * item, * 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);
 
-    li->form->ops->destroy(li->form);
-    free(li->items);
     free(li);
     free(co);
 }