]> git.ipfire.org Git - thirdparty/newt.git/blobdiff - listbox.c
install python modules to purelib and platlib
[thirdparty/newt.git] / listbox.c
index 46f59db7495e7b3cb0f561050192a4b6783a5c77..aae4f836f7c108b02ca93de826fe3a1800637c85 100644 (file)
--- a/listbox.c
+++ b/listbox.c
@@ -1,12 +1,13 @@
 /* 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 Elliot Lee 1996 */
+   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, *data;
+    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 numItems, curWidth, numSelected;
+    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 */
@@ -39,13 +45,38 @@ 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;
@@ -65,15 +96,30 @@ newtComponent newtListbox(int left, int top, int height, int flags) {
     li->isActive = 0;
     li->userHasSetWidth = 0;
     li->startShowItem = 0;
-    li->flags = flags & (NEWT_FLAG_RETURNEXIT|NEWT_FLAG_DOBORDER|NEWT_FLAG_MULTIPLE);
+    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) {
        li->grow = 0;
-       if (flags & NEWT_FLAG_NOSCROLL)
+       if (flags & NEWT_FLAG_SCROLL) {
+           sb = newtVerticalScrollbar(left, top + li->bdyAdjust,
+                                       li->curHeight,
+                                       COLORSET_LISTBOX, COLORSET_ACTLISTBOX);
+           li->sbAdjust = 3;
+       } else {
            sb = NULL;
-       else
-           sb = newtVerticalScrollbar(left, top, height, COLORSET_LISTBOX,
-                                      COLORSET_ACTLISTBOX);
+       }
     } else {
        li->grow = 1;
        sb = NULL;
@@ -81,20 +127,45 @@ newtComponent newtListbox(int left, int top, int height, int flags) {
 
     li->sb = sb;
     co->data = li;
+    co->isMapped = 0;
     co->left = left;
     co->top = top;
-    co->height = height;
-    li->curWidth = 5;
     co->ops = &listboxOps;
     co->takesFocus = 1;
     co->callback = NULL;
+    co->destroyCallback = 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)
@@ -104,31 +175,34 @@ void newtListboxSetCurrent(newtComponent co, int num)
 
     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);
     if(co->callback) co->callback(co, co->callbackData);
 }
 
-void newtListboxSetWidth(newtComponent co , int width) {
+void newtListboxSetWidth(newtComponent co, int width) {
     struct listbox * li = co->data;
-    
-    li->curWidth = co->width = width;
+
+    co->width = width;
+    li->curWidth = co->width - li->sbAdjust - 2 * li->bdxAdjust;
     li->userHasSetWidth = 1;
-    li->sb->left = width + co->left + 2;
+    if (li->sb)
+       li->sb->left = co->left + co->width - li->bdxAdjust - 1;
     listboxDraw(co);
 }
 
@@ -141,27 +215,39 @@ void * newtListboxGetCurrent(newtComponent co) {
        i++, item = item->next);
 
     if (item)
-       return item->data;
+       return (void *)item->data;
     else
        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);
+    struct items * item;
 
-    if (iitem) {
-       if(iitem->isSelected)
-           li->numSelected--;
-       else
-           li->numSelected++;
-       iitem->isSelected = !iitem->isSelected;
+    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);
 }
 
@@ -173,33 +259,33 @@ void newtListboxClearSelection(newtComponent co)
     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)
+void ** newtListboxGetSelection(newtComponent co, int *numitems)
 {
     struct listbox * li;
     int i;
     void **retval;
     struct items *item;
 
-    if(!co) return NULL;
+    if(!co || !numitems) return NULL;
 
     li = co->data;
     if(!li || !li->numSelected) return NULL;
 
-    retval = malloc((li->numSelected + 1) * sizeof(void *));
+    retval = malloc(li->numSelected * sizeof(void *));
     for(i = 0, item = li->boxItems; item != NULL;
        item = item->next)
        if(item->isSelected)
-           retval[i++] = item->data;
-    retval[i] = NULL;
+           retval[i++] = (void *)item->data;
+    *numitems = li->numSelected;
     return retval;
 }
 
-void newtListboxSetText(newtComponent co, int num, char * text) {
+void newtListboxSetEntry(newtComponent co, int num, const char * text) {
     struct listbox * li = co->data;
     int i;
     struct items *item;
@@ -210,24 +296,17 @@ void newtListboxSetText(newtComponent co, int num, char * text) {
     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) {
-       co->width = li->curWidth = strlen(text);
-       if (li->sb)
-           li->sb->left = co->left + co->width + 2;
+    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, char * text) {
-    newtListboxSetText(co, num, text);
-}
-
 void newtListboxSetData(newtComponent co, int num, void * data) {
     struct listbox * li = co->data;
     int i;
@@ -236,10 +315,12 @@ void newtListboxSetData(newtComponent co, int num, void * data) {
     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, char * text, void * data) {
+int newtListboxAppendEntry(newtComponent co, const char * text,
+                       const void * data) {
     struct listbox * li = co->data;
     struct items *item;
 
@@ -251,40 +332,31 @@ int newtListboxAddEntry(newtComponent co, char * text, void * data) {
        item = li->boxItems = malloc(sizeof(struct items));
     }
 
-    if (li->userHasSetWidth == 0
-       && text && (strlen(text) > li->curWidth))
-       li->curWidth = 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->sb)
-       li->sb->left = co->left + li->curWidth + 2;
 
     if (li->grow)
-       co->height++;
-    if(li->userHasSetWidth == 0)
-       co->width = li->curWidth;
+       co->height++, li->curHeight++;
     li->numItems++;
 
-    listboxDraw(co);
-    
-    return li->numItems;
+    return 0;
 }
 
-
-int newtListboxInsertEntry(newtComponent co, char * text, void * data, 
-                          int num) {
+int newtListboxInsertEntry(newtComponent co, const char * text,
+                          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 > 1) {
-           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;
@@ -293,76 +365,96 @@ int newtListboxInsertEntry(newtComponent co, char * text, void * data,
            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 == 0
-       && text && (strlen(text) > li->curWidth))
-       li->curWidth = 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 + li->curWidth + 2;
-    if (li->userHasSetWidth == 0)
-       co->width = li->curWidth;
+       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;
-    struct items *item, *item2;
-
-    if(num > li->numItems)
-       num = li->numItems;
+    int widest = 0, t;
+    struct items *item, *item2 = NULL;
+    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 == 0) {
-       co->width = li->curWidth = widest;
-       if (li->sb)
-               li->sb->left = co->left + widest + 2;
+
+    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);
+}
+
+int newtListboxItemCount(newtComponent co)
+{
+    struct listbox *li = co->data;
     return li->numItems;
 }
 
@@ -382,16 +474,16 @@ 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 = item->data; 
+           *data = (void *)item->data;
     }
 }
 
@@ -401,31 +493,35 @@ static void listboxDraw(newtComponent co)
     struct items *item;
     int i, j;
 
-    if(li->sb)
-       li->sb->ops->draw(li->sb);
+    if (!co->isMapped) return ;
 
-    if(li->flags & NEWT_FLAG_DOBORDER) {
+    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-1, co->top-1, co->width+5, co->height+2, 0);
+      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 < co->height; i++, item = item->next) {
-       if (!item->key) continue;
+    for (i = 0; item != NULL && i < li->curHeight; i++, item = item->next) {
+       if (!item->text) continue;
 
-       newtGotorc(co->top + i, co->left + 1);
+       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);
@@ -433,23 +529,32 @@ static void listboxDraw(newtComponent co)
            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;
@@ -457,7 +562,26 @@ static struct eventResult listboxEvent(newtComponent co, struct event ev) {
        switch(ev.u.key) {
          case ' ':
            if(!(li->flags & NEWT_FLAG_MULTIPLE)) break;
-           newtListboxSelectItem(co, li->currItem);
+           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;
 
@@ -481,29 +605,12 @@ static struct eventResult listboxEvent(newtComponent co, struct event ev) {
            er.result = ER_SWALLOWED;
            break;
 
-         case NEWT_KEY_DOWN:
-           if(li->numItems <= 0) break;
-           if(li->currItem < li->numItems - 1) {
-               li->currItem++;
-               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;
-               }
-               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 -= co->height - 1;
+           li->startShowItem -= li->curHeight - 1;
            if(li->startShowItem < 0)
                li->startShowItem = 0;
-           li->currItem -= co->height - 1;
+           li->currItem -= li->curHeight - 1;
            if(li->currItem < 0)
                li->currItem = 0;
            newtListboxRealSetCurrent(co);
@@ -512,12 +619,12 @@ static struct eventResult listboxEvent(newtComponent co, struct event ev) {
 
          case NEWT_KEY_PGDN:
            if(li->numItems <= 0) break;
-           li->startShowItem += co->height;
-           if(li->startShowItem > (li->numItems - co->height)) {
-               li->startShowItem = li->numItems - co->height;
+           li->startShowItem += li->curHeight;
+           if(li->startShowItem > (li->numItems - li->curHeight)) {
+               li->startShowItem = li->numItems - li->curHeight;
            }
-           li->currItem += co->height;
-           if(li->currItem > li->numItems) {
+           li->currItem += li->curHeight;
+           if(li->currItem >= li->numItems) {
                li->currItem = li->numItems - 1;
            }
            newtListboxRealSetCurrent(co);
@@ -532,25 +639,116 @@ static struct eventResult listboxEvent(newtComponent co, struct event ev) {
 
          case NEWT_KEY_END:
            if(li->numItems <= 0) break;
-           newtListboxSetCurrent(co, li->numItems - 1);
+           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:
-           /* 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;
@@ -560,16 +758,17 @@ static void listboxDestroy(newtComponent co) {
     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);
 }
-