From 57eeb16aba2613c1329eafbf7d7453cd67f2cc69 Mon Sep 17 00:00:00 2001
From: Joel Bodenmann <joel@unormal.org>
Date: Thu, 25 Jul 2013 19:15:51 +0200
Subject: list widget - work in progress

---
 include/gos/linux.h |   1 +
 include/gwin/list.h |   9 +++-
 src/gwin/list.c     | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 149 insertions(+), 4 deletions(-)

diff --git a/include/gos/linux.h b/include/gos/linux.h
index 7529a962..508b2b68 100644
--- a/include/gos/linux.h
+++ b/include/gos/linux.h
@@ -16,6 +16,7 @@
 #if GFX_USE_OS_LINUX
 
 #include <sys/types.h>
+#include <stdlib.h>
 #include <stdint.h>
 #include <pthread.h>
 
diff --git a/include/gwin/list.h b/include/gwin/list.h
index 0b525b03..46e32d5c 100644
--- a/include/gwin/list.h
+++ b/include/gwin/list.h
@@ -37,13 +37,16 @@
  * @brief	A list event
  */
 typedef struct GEventGWinList {
-	GEventType		type;			// The type of this event (GEVENT_GWIN_LIST)
-	GHandle			list;			// THe list that has generated the event
+	GEventType		type;		// The type of this event (GEVENT_GWIN_LIST)
+	GHandle			list;		// The list
+	int				item;		// The item that has been selected (or unselected in a multi-select listbox)
 } GEventGWinList;
 
 // A list window
 typedef struct GListObject {
 	GWidgetObject	w;
+	int				cnt;		// Number of items currently in the list (quicker than counting each time)
+	gfxQueueASync	list_head;	// The list of items
 } GListObject;
 
 #ifdef __cplusplus
@@ -52,6 +55,8 @@ extern "C" {
 
 GHandle gwinListCreate(GListObject *widget, GWidgetInit *pInit);
 
+int gwinListAddItem(GHandle gh, const char* item, bool_t useAlloc);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/gwin/list.c b/src/gwin/list.c
index eae9bb46..bfb341af 100644
--- a/src/gwin/list.c
+++ b/src/gwin/list.c
@@ -20,11 +20,106 @@
 #if GFX_USE_GWIN && GWIN_NEED_LIST
 
 #include "gwin/class_gwin.h"
+#include <string.h>
+
+#define widget(gh)	((GListObject *)gh)
+
+#define GLIST_FLG_MULTISELECT		(GWIN_FIRST_CONTROL_FLAG << 0)
+#define GLIST_FLG_HASIMAGES			(GWIN_FIRST_CONTROL_FLAG << 1)
+#define GLIST_FLG_SELECTED			(GWIN_FIRST_CONTROL_FLAG << 2)
+
+/*
+Use gw->pstyle->background for the unselected fill.
+Use gw->pstyle->enabled/disabled->text for unselected text color
+Use gw->pstyle->enabled/disabled->edge for the surounding box
+Use gw->pstyle->enabled/disabled->fill for the selected text fill
+or gw->pstyle->pressed->fill for the selected text fill (which ever looks best)
+and use gw->pstyle->pressed->text for the selected text color
+*/
+
+typedef struct ListItem {
+	gfxQueueASyncItem	q_item;		// This must be the first member in the struct
+
+	uint16_t 			id;
+	uint16_t			flags;
+	    #define LISTITEM_ALLOCEDTEXT      0x0001
+	    #define LISTITEM_SELECTED         0x0002
+	uint16_t			uparam;
+	const char*			text;
+	#if GWIN_LIST_IMAGES
+	gdispImage*			pimg;
+	#endif
+} ListItem;
+
+static void sendListEvent(GWidgetObject *gw) {
+	GSourceListener*	psl;
+	GEvent*				pe;
+	#define pse			((GEventGWinList *)pe)
+
+	// Trigger a GWIN list event
+	psl = 0;
+	while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) {
+		if (!(pe = geventGetEventBuffer(psl)))
+			continue
+
+		pse->type = GEVENT_GWIN_SLIDER;
+		pse->list = (GHandle)gw;
+		pse->item = 42;
+
+		geventSendEvent(psl);
+	}
+
+	#undef pse	
+}
 
 static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
+	#define gcw			((GListObject *)gw)
+	(void)param;
+
+	uint16_t i, fheight;
+	gfxQueueASyncItem* qi;
+
+	fheight = gdispGetFontMetric(gwinGetDefaultFont(), fontHeight);	
 
+	gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, Black);
+	
+	for (qi = gfxQueueASyncPeek(&gcw->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i += fheight + 4) {
+		if (((ListItem*)qi)->flags & GLIST_FLG_SELECTED) 
+			gdispFillStringBox(gw->g.x + 3, gw->g.y + 3 + i, gw->g.width - 6, fheight, ((ListItem*)qi)->text, gwinGetDefaultFont(), White, Black, justifyLeft);
+		else
+			gdispFillStringBox(gw->g.x + 3, gw->g.y + 3 + i, gw->g.width - 6, fheight, ((ListItem*)qi)->text, gwinGetDefaultFont(), Black, White, justifyLeft);
+	}
+
+	#undef gcw
 }
 
+#if GINPUT_NEED_MOUSE
+	// A mouse down has occured over the list area
+	static void MouseDown(GWidgetObject* gw, coord_t x, coord_t y) {
+		#define gcw			((GListObject *)gw)
+
+		uint16_t i, item_id, item_height;
+		gfxQueueASyncItem* qi;
+
+		item_height = gdispGetFontMetric(gwinGetDefaultFont(), fontHeight) + 2;
+
+		item_id = (y - gw->g.y) / item_height;
+		printf("item_id = %d\r\n", item_id);
+
+		for(qi = gfxQueueASyncPeek(&gcw->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
+			if (item_id == i)
+				((ListItem*)qi)->flags |= GLIST_FLG_SELECTED;
+			else
+				((ListItem*)qi)->flags &=~ GLIST_FLG_SELECTED;
+		}
+
+		_gwidgetRedraw((GHandle)gw);
+		sendListEvent(gw);
+
+		#undef gcw
+	}
+#endif
+
 static const gwidgetVMT listVMT = {
 	{
 		"List",					// The class name
@@ -34,9 +129,9 @@ static const gwidgetVMT listVMT = {
 		0,						// The after-clear routine
 	},
 	gwinListDefaultDraw,		// default drawing routine
-	#if GWINPUT_NEED_MOUSE
+	#if GINPUT_NEED_MOUSE
 		{
-			0,
+			MouseDown,
 			0,
 			0,
 		},
@@ -64,11 +159,55 @@ GHandle gwinListCreate(GListObject* widget, GWidgetInit* pInit) {
 	if (!(widget = (GListObject *)_gwidgetCreate(&widget->w, pInit, &listVMT)))
 		return 0;
 
+	// initialize the item queue
+	gfxQueueASyncInit(&(widget->list_head));
+	widget->cnt = 0;
+
 	gwinSetVisible(&widget->w.g, pInit->g.show);
 
 	return (GHandle)widget;
 }
 
+int gwinListAddItem(GHandle gh, const char* item_name, bool_t useAlloc) {
+	ListItem* newItem;
+
+	if (useAlloc) {
+		newItem = gfxAlloc(sizeof(newItem) + strlen(item_name) + 1);
+
+		// allocate string
+		newItem->text = gfxAlloc(strlen(item_name) + 1);
+		if (newItem->text == NULL)
+			return -1;
+
+		// assign text
+		newItem->text = item_name;		
+
+	} else {
+		newItem = gfxAlloc(sizeof(newItem));
+
+		if (newItem == NULL)
+			return -1;
+	}
+
+	// the item is not selected when added
+	newItem->flags &=~ GLIST_FLG_SELECTED;
+
+	// add the new item to the list
+	gfxQueueASyncPut(&(widget(gh)->list_head), &newItem->q_item);
+
+	// increment the total amount of entries in the list widget
+	widget(gh)->cnt++;
+}
+
+int gwinListGetSelected(GHandle gh) {
+	gfxQueueASyncItem* qi;
+	uint16_t i;
+
+	//for(qi = gfxQueueASyncPeek(&gcw->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
+
+	
+}
+
 #endif // GFX_USE_GWIN && GWIN_NEED_LIST
 /** @} */
 
-- 
cgit v1.2.3


From 9dfcbef84884f67bb487dc02c642a03ca5d19e32 Mon Sep 17 00:00:00 2001
From: Joel Bodenmann <joel@unormal.org>
Date: Sat, 27 Jul 2013 15:23:52 +0200
Subject: list work in progress

---
 src/gwin/list.c | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/src/gwin/list.c b/src/gwin/list.c
index bfb341af..cc7c40f4 100644
--- a/src/gwin/list.c
+++ b/src/gwin/list.c
@@ -40,17 +40,28 @@ and use gw->pstyle->pressed->text for the selected text color
 typedef struct ListItem {
 	gfxQueueASyncItem	q_item;		// This must be the first member in the struct
 
-	uint16_t 			id;
 	uint16_t			flags;
 	    #define LISTITEM_ALLOCEDTEXT      0x0001
 	    #define LISTITEM_SELECTED         0x0002
-	uint16_t			uparam;
+	uint16_t			param;		// A parameter the user can specify himself
 	const char*			text;
 	#if GWIN_LIST_IMAGES
 	gdispImage*			pimg;
 	#endif
 } ListItem;
 
+static int _getSelected(GWidgetObject *gw) {
+	gfxQueueASyncItem*	qi;
+	uint16_t i;
+
+	for(qi = gfxQueueASyncPeek(&((GListObject*)gw)->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
+		if (((ListItem*)qi)->flags & GLIST_FLG_SELECTED)
+			return i;
+	}
+
+	return -1;
+}
+
 static void sendListEvent(GWidgetObject *gw) {
 	GSourceListener*	psl;
 	GEvent*				pe;
@@ -58,17 +69,18 @@ static void sendListEvent(GWidgetObject *gw) {
 
 	// Trigger a GWIN list event
 	psl = 0;
+
 	while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) {
 		if (!(pe = geventGetEventBuffer(psl)))
 			continue
 
 		pse->type = GEVENT_GWIN_SLIDER;
 		pse->list = (GHandle)gw;
-		pse->item = 42;
+		pse->item = _getSelected(gw);
 
 		geventSendEvent(psl);
 	}
-
+	
 	#undef pse	
 }
 
@@ -104,7 +116,6 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
 		item_height = gdispGetFontMetric(gwinGetDefaultFont(), fontHeight) + 2;
 
 		item_id = (y - gw->g.y) / item_height;
-		printf("item_id = %d\r\n", item_id);
 
 		for(qi = gfxQueueASyncPeek(&gcw->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
 			if (item_id == i)
-- 
cgit v1.2.3


From 1fbbc4d52bed0b8e4f3289bc008b3f0928a6b24f Mon Sep 17 00:00:00 2001
From: inmarket <andrewh@inmarket.com.au>
Date: Sat, 27 Jul 2013 22:25:20 +1000
Subject: Integrate changes from master branch

---
 demos/modules/gwin/widgets/gfxconf.h | 2 +-
 include/gos/osx.h                    | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/demos/modules/gwin/widgets/gfxconf.h b/demos/modules/gwin/widgets/gfxconf.h
index fffe685d..f8d8fe5f 100644
--- a/demos/modules/gwin/widgets/gfxconf.h
+++ b/demos/modules/gwin/widgets/gfxconf.h
@@ -29,7 +29,7 @@
 #ifndef _GFXCONF_H
 #define _GFXCONF_H
 
-#define GFX_USE_OS_CHIBIOS		TRUE
+//#define GFX_USE_OS_CHIBIOS		TRUE
 //#define GFX_USE_OS_WIN32		TRUE
 //#define GFX_USE_OS_POSIX		TRUE
 
diff --git a/include/gos/osx.h b/include/gos/osx.h
index 2ba1c45d..3f36aaff 100644
--- a/include/gos/osx.h
+++ b/include/gos/osx.h
@@ -48,7 +48,6 @@ typedef pthread_mutex_t		gfxMutex;
 #define gfxSemSignalI(psem)				gfxSemSignal(psem)
 #define gfxSemCounterI(pSem)			((pSem)->cnt)
 
-#define TRUE						1
 #define TIME_IMMEDIATE				0
 #define TIME_INFINITE				((delaytime_t)-1)
 #define MAX_SEMAPHORE_COUNT			((semcount_t)-1)
-- 
cgit v1.2.3


From 984e14efb7ad257577db85fcdbed6c60618c1175 Mon Sep 17 00:00:00 2001
From: inmarket <andrewh@inmarket.com.au>
Date: Sat, 27 Jul 2013 22:26:16 +1000
Subject: List updates and add list demo - still work in progress

---
 demos/modules/gwin/list/gfxconf.h | 150 ++++++++++++++++++++++++++++++++++++++
 demos/modules/gwin/list/main.c    |  63 ++++++++++++++++
 src/gwin/list.c                   |  88 +++++++++++-----------
 3 files changed, 258 insertions(+), 43 deletions(-)
 create mode 100644 demos/modules/gwin/list/gfxconf.h
 create mode 100644 demos/modules/gwin/list/main.c

diff --git a/demos/modules/gwin/list/gfxconf.h b/demos/modules/gwin/list/gfxconf.h
new file mode 100644
index 00000000..895d7c49
--- /dev/null
+++ b/demos/modules/gwin/list/gfxconf.h
@@ -0,0 +1,150 @@
+/**
+ * This file has a different license to the rest of the GFX system.
+ * You can copy, modify and distribute this file as you see fit.
+ * You do not need to publish your source modifications to this file.
+ * The only thing you are not permitted to do is to relicense it
+ * under a different license.
+ */
+
+/**
+ * Copy this file into your project directory and rename it as gfxconf.h
+ * Edit your copy to turn on the GFX features you want to use.
+ */
+
+#ifndef _GFXCONF_H
+#define _GFXCONF_H
+
+/* The operating system to use - one of these must be defined */
+//#define GFX_USE_OS_CHIBIOS		FALSE
+//#define GFX_USE_OS_WIN32		FALSE
+//#define GFX_USE_OS_LINUX		TRUE
+//#define GFX_USE_OS_OSX			FALSE
+
+/* GFX subsystems to turn on */
+#define GFX_USE_GDISP			TRUE
+#define GFX_USE_TDISP			FALSE
+#define GFX_USE_GWIN			TRUE
+#define GFX_USE_GEVENT			TRUE
+#define GFX_USE_GTIMER			TRUE
+#define GFX_USE_GQUEUE			TRUE
+#define GFX_USE_GINPUT			TRUE
+#define GFX_USE_GADC			FALSE
+#define GFX_USE_GAUDIN			FALSE
+#define GFX_USE_GAUDOUT			FALSE
+#define GFX_USE_GMISC			FALSE
+
+/* Features for the GDISP subsystem */
+#define GDISP_NEED_VALIDATION		TRUE
+#define GDISP_NEED_CLIP				TRUE
+#define GDISP_NEED_TEXT				TRUE
+#define GDISP_NEED_CIRCLE			TRUE
+#define GDISP_NEED_ELLIPSE			TRUE
+#define GDISP_NEED_ARC				FALSE
+#define GDISP_NEED_CONVEX_POLYGON	FALSE
+#define GDISP_NEED_SCROLL			FALSE
+#define GDISP_NEED_PIXELREAD		FALSE
+#define GDISP_NEED_CONTROL			FALSE
+#define GDISP_NEED_QUERY			FALSE
+#define GDISP_NEED_IMAGE			FALSE
+#define GDISP_NEED_MULTITHREAD		FALSE
+#define GDISP_NEED_ASYNC			FALSE
+#define GDISP_NEED_MSGAPI			FALSE
+
+/* GDISP - builtin fonts */
+#define GDISP_INCLUDE_FONT_SMALL		FALSE
+#define GDISP_INCLUDE_FONT_LARGER		FALSE
+#define GDISP_INCLUDE_FONT_UI1			FALSE
+#define GDISP_INCLUDE_FONT_UI2			TRUE
+#define GDISP_INCLUDE_FONT_LARGENUMBERS	FALSE
+
+/* GDISP image decoders */
+#define GDISP_NEED_IMAGE_NATIVE		FALSE
+#define GDISP_NEED_IMAGE_GIF		FALSE
+#define GDISP_NEED_IMAGE_BMP		FALSE
+#define GDISP_NEED_IMAGE_JPG		FALSE
+#define GDISP_NEED_IMAGE_PNG		FALSE
+#define GDISP_NEED_IMAGE_ACCOUNTING	FALSE
+
+/* Optional image support that can be turned off */
+/*
+	#define GDISP_NEED_IMAGE_BMP_1		TRUE
+	#define GDISP_NEED_IMAGE_BMP_4		TRUE
+	#define GDISP_NEED_IMAGE_BMP_4_RLE	TRUE
+	#define GDISP_NEED_IMAGE_BMP_8		TRUE
+	#define GDISP_NEED_IMAGE_BMP_8_RLE	TRUE
+	#define GDISP_NEED_IMAGE_BMP_16		TRUE
+	#define GDISP_NEED_IMAGE_BMP_24		TRUE
+	#define GDISP_NEED_IMAGE_BMP_32		TRUE
+*/
+
+/* Features for the TDISP subsystem. */
+#define TDISP_NEED_MULTITHREAD	FALSE
+
+/* Features for the GWIN subsystem. */
+#define GWIN_NEED_WINDOWMANAGER	TRUE
+#define GWIN_NEED_CONSOLE		FALSE
+#define GWIN_NEED_GRAPH			FALSE
+#define GWIN_NEED_WIDGET		TRUE
+#define GWIN_NEED_BUTTON		FALSE
+#define GWIN_NEED_SLIDER		FALSE
+#define GWIN_NEED_CHECKBOX		FALSE
+#define GWIN_NEED_IMAGE			FALSE
+#define GWIN_NEED_RADIO			FALSE
+#define GWIN_NEED_LIST			TRUE
+
+/* Features for the GEVENT subsystem. */
+#define GEVENT_ASSERT_NO_RESOURCE	FALSE
+
+/* Features for the GTIMER subsystem. */
+/* NONE */
+
+/* Features for the GQUEUE subsystem. */
+#define GQUEUE_NEED_ASYNC		TRUE
+#define GQUEUE_NEED_GSYNC		FALSE
+#define GQUEUE_NEED_FSYNC		FALSE
+
+/* Features for the GINPUT subsystem. */
+#define GINPUT_NEED_MOUSE		TRUE
+#define GINPUT_NEED_KEYBOARD	FALSE
+#define GINPUT_NEED_TOGGLE		FALSE
+#define GINPUT_NEED_DIAL		FALSE
+
+/* Features for the GADC subsystem. */
+/* NONE */
+
+/* Features for the GAUDIN subsystem. */
+/* NONE */
+
+/* Features for the GAUDOUT subsystem. */
+/* NONE */
+
+/* Features for the GMISC subsystem. */
+#define GMISC_NEED_ARRAYOPS		FALSE
+#define GMISC_NEED_FASTTRIG		FALSE
+#define GMISC_NEED_FIXEDTRIG	FALSE
+
+/* Optional Parameters for various subsystems */
+/*
+	#define GDISP_MAX_FONT_HEIGHT			16
+	#define GEVENT_MAXIMUM_SIZE				32
+	#define GEVENT_MAX_SOURCE_LISTENERS		32
+	#define GTIMER_THREAD_WORKAREA_SIZE		512
+	#define GADC_MAX_LOWSPEED_DEVICES		4
+	#define GWIN_BUTTON_LAZY_RELEASE		FALSE
+	#define GWIN_CONSOLE_USE_BASESTREAM		FALSE
+	#define GWIN_CONSOLE_USE_FLOAT			FALSE
+	#define GWIN_NEED_IMAGE_ANIMATION		FALSE
+*/
+
+/* Optional Low Level Driver Definitions */
+/*
+	#define GDISP_USE_CUSTOM_BOARD		FALSE
+	#define GDISP_SCREEN_WIDTH			320
+	#define GDISP_SCREEN_HEIGHT			240
+	#define GDISP_USE_FSMC
+	#define GDISP_USE_GPIO
+	#define TDISP_COLUMNS				16
+	#define TDISP_ROWS					2
+*/
+
+#endif /* _GFXCONF_H */
diff --git a/demos/modules/gwin/list/main.c b/demos/modules/gwin/list/main.c
new file mode 100644
index 00000000..35847be0
--- /dev/null
+++ b/demos/modules/gwin/list/main.c
@@ -0,0 +1,63 @@
+#include "gfx.h"
+
+static GListener gl;
+static GHandle   ghList1;
+
+static void createWidgets(void) {
+	GWidgetInit	wi;
+
+	// Apply some default values for GWIN
+	wi.customDraw = 0;
+	wi.customParam = 0;
+	wi.customStyle = 0;
+	wi.g.show = TRUE;
+
+	// Apply the list parameters
+	wi.g.width = 300;
+	wi.g.height = 200;
+	wi.g.y = 10;
+	wi.g.x = 10;
+	wi.text = "List Name";
+
+	// Create the actual list
+	ghList1 = gwinListCreate(NULL, &wi);
+}
+
+int main(void) {
+	GEvent* pe;
+
+	// Initialize the display
+	gfxInit();
+
+	// Set the widget defaults
+	gwinSetDefaultFont(gdispOpenFont("UI2"));
+	gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE);
+	gdispClear(White);
+
+	// Attach the mouse input
+	gwinAttachMouse(0);
+
+	// create the widget
+	createWidgets();
+
+	// We want to listen for widget events
+	geventListenerInit(&gl);
+	gwinAttachListener(&gl);
+
+	// Add some items to the list widget
+	gwinListAddItem(ghList1, "Item 0", TRUE);
+	gwinListAddItem(ghList1, "Item 1", TRUE);
+	gwinListAddItem(ghList1, "Item 2", TRUE);
+	gwinListAddItem(ghList1, "Item 3", TRUE);
+	gwinListAddItem(ghList1, "Item 4", TRUE);
+
+	gwinRedraw(ghList1);
+
+	while(1) {
+		// Get an Event
+		pe = geventEventWait(&gl, TIME_INFINITE);
+
+	}
+
+	return 0;
+}
diff --git a/src/gwin/list.c b/src/gwin/list.c
index cc7c40f4..11fd01cb 100644
--- a/src/gwin/list.c
+++ b/src/gwin/list.c
@@ -50,19 +50,7 @@ typedef struct ListItem {
 	#endif
 } ListItem;
 
-static int _getSelected(GWidgetObject *gw) {
-	gfxQueueASyncItem*	qi;
-	uint16_t i;
-
-	for(qi = gfxQueueASyncPeek(&((GListObject*)gw)->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
-		if (((ListItem*)qi)->flags & GLIST_FLG_SELECTED)
-			return i;
-	}
-
-	return -1;
-}
-
-static void sendListEvent(GWidgetObject *gw) {
+static void sendListEvent(GWidgetObject *gw, int item) {
 	GSourceListener*	psl;
 	GEvent*				pe;
 	#define pse			((GEventGWinList *)pe)
@@ -72,11 +60,11 @@ static void sendListEvent(GWidgetObject *gw) {
 
 	while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) {
 		if (!(pe = geventGetEventBuffer(psl)))
-			continue
+			continue;
 
-		pse->type = GEVENT_GWIN_SLIDER;
+		pse->type = GEVENT_GWIN_LIST;
 		pse->list = (GHandle)gw;
-		pse->item = _getSelected(gw);
+		pse->item = item;
 
 		geventSendEvent(psl);
 	}
@@ -89,7 +77,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
 	(void)param;
 
 	uint16_t i, fheight;
-	gfxQueueASyncItem* qi;
+	const gfxQueueASyncItem* qi;
 
 	fheight = gdispGetFontMetric(gwinGetDefaultFont(), fontHeight);	
 
@@ -109,9 +97,11 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
 	// A mouse down has occured over the list area
 	static void MouseDown(GWidgetObject* gw, coord_t x, coord_t y) {
 		#define gcw			((GListObject *)gw)
+		#define li			((ListItem *)qi)
+		(void)				x;
 
 		uint16_t i, item_id, item_height;
-		gfxQueueASyncItem* qi;
+		const gfxQueueASyncItem* qi;
 
 		item_height = gdispGetFontMetric(gwinGetDefaultFont(), fontHeight) + 2;
 
@@ -119,23 +109,32 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
 
 		for(qi = gfxQueueASyncPeek(&gcw->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
 			if (item_id == i)
-				((ListItem*)qi)->flags |= GLIST_FLG_SELECTED;
+				li->flags |= GLIST_FLG_SELECTED;
 			else
-				((ListItem*)qi)->flags &=~ GLIST_FLG_SELECTED;
+				li->flags &=~ GLIST_FLG_SELECTED;
 		}
 
 		_gwidgetRedraw((GHandle)gw);
-		sendListEvent(gw);
+		sendListEvent(gw, item_id);
 
 		#undef gcw
+		#undef li
 	}
 #endif
 
+static void _destroy(GHandle gh) {
+	const gfxQueueASyncItem* qi;
+
+	while((qi = gfxQueueASyncGet(&((GListObject *)gh)->list_head)))
+		gfxFree((void *)qi);
+	_gwidgetDestroy(gh);
+}
+
 static const gwidgetVMT listVMT = {
 	{
 		"List",					// The class name
 		sizeof(GListObject),	// The object size
-		_gwidgetDestroy,		// The destroy routine
+		_destroy,		// The destroy routine
 		_gwidgetRedraw,			// The redraw routine
 		0,						// The after-clear routine
 	},
@@ -180,43 +179,46 @@ GHandle gwinListCreate(GListObject* widget, GWidgetInit* pInit) {
 }
 
 int gwinListAddItem(GHandle gh, const char* item_name, bool_t useAlloc) {
-	ListItem* newItem;
+	size_t		sz;
+	ListItem	*newItem;
 
-	if (useAlloc) {
-		newItem = gfxAlloc(sizeof(newItem) + strlen(item_name) + 1);
-
-		// allocate string
-		newItem->text = gfxAlloc(strlen(item_name) + 1);
-		if (newItem->text == NULL)
-			return -1;
-
-		// assign text
-		newItem->text = item_name;		
+	sz = useAlloc ? sizeof(ListItem)+strlen(item_name)+1 : sizeof(ListItem);
 
-	} else {
-		newItem = gfxAlloc(sizeof(newItem));
+	if (!(newItem = (ListItem *)gfxAlloc(sz)))
+		return -1;
 
-		if (newItem == NULL)
-			return -1;
+	if (useAlloc) {
+		strcpy((char *)(newItem+1), item_name);
+		item_name = (const char *)(newItem+1);
 	}
 
 	// the item is not selected when added
-	newItem->flags &=~ GLIST_FLG_SELECTED;
+	newItem->flags = 0;
+	newItem->param = 0;
+	newItem->text = item_name;
 
 	// add the new item to the list
-	gfxQueueASyncPut(&(widget(gh)->list_head), &newItem->q_item);
+	gfxQueueASyncPut(&widget(gh)->list_head, &newItem->q_item);
 
 	// increment the total amount of entries in the list widget
 	widget(gh)->cnt++;
+
+	return widget(gh)->cnt-1;
 }
 
 int gwinListGetSelected(GHandle gh) {
-	gfxQueueASyncItem* qi;
-	uint16_t i;
+	const gfxQueueASyncItem	*qi;
+	int i;
 
-	//for(qi = gfxQueueASyncPeek(&gcw->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
+	if (gh->vmt != (gwinVMT *)&listVMT)
+		return -1;
 
-	
+	for(qi = gfxQueueASyncPeek(&widget(gh)->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
+		if (((ListItem*)qi)->flags & GLIST_FLG_SELECTED)
+			return i;
+	}
+
+	return -1;
 }
 
 #endif // GFX_USE_GWIN && GWIN_NEED_LIST
-- 
cgit v1.2.3


From 40611e264d9fc8b05db05ec4dc410e919af7f98d Mon Sep 17 00:00:00 2001
From: Joel Bodenmann <joel@unormal.org>
Date: Sat, 27 Jul 2013 22:55:32 +0200
Subject: some more list work

---
 include/gwin/list.h |  18 ++++++
 src/gwin/list.c     | 177 +++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 185 insertions(+), 10 deletions(-)

diff --git a/include/gwin/list.h b/include/gwin/list.h
index 46e32d5c..307226c9 100644
--- a/include/gwin/list.h
+++ b/include/gwin/list.h
@@ -57,6 +57,24 @@ GHandle gwinListCreate(GListObject *widget, GWidgetInit *pInit);
 
 int gwinListAddItem(GHandle gh, const char* item, bool_t useAlloc);
 
+char* gwinListItemGetText(GHandle gh, int item);
+
+int gwinListFindText(GHandle gh, const char* text);
+
+void gwinListItemSetParam(GHandle gh, int item, uint16_t param);
+
+uint16_t gwinListItemGetParam(GHandle gh, int item);
+
+void nListDeleteAll(GHandle gh);
+
+void gwinListItemDelete(GHandle gh, int item);
+
+int gwinListItemCount(GHandle gh);
+
+bool_t gwinListItemIsSelected(GHandle gh, int item);
+
+int gwinListGetSelected(GHandle gh);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/gwin/list.c b/src/gwin/list.c
index 11fd01cb..9b9ab7c6 100644
--- a/src/gwin/list.c
+++ b/src/gwin/list.c
@@ -22,6 +22,8 @@
 #include "gwin/class_gwin.h"
 #include <string.h>
 
+#define BORDER		3
+
 #define widget(gh)	((GListObject *)gh)
 
 #define GLIST_FLG_MULTISELECT		(GWIN_FIRST_CONTROL_FLAG << 0)
@@ -42,7 +44,6 @@ typedef struct ListItem {
 
 	uint16_t			flags;
 	    #define LISTITEM_ALLOCEDTEXT      0x0001
-	    #define LISTITEM_SELECTED         0x0002
 	uint16_t			param;		// A parameter the user can specify himself
 	const char*			text;
 	#if GWIN_LIST_IMAGES
@@ -77,17 +78,18 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
 	(void)param;
 
 	uint16_t i, fheight;
-	const gfxQueueASyncItem* qi;
+	gfxQueueASyncItem* qi;
+	const GColorSet*	pcol;
 
 	fheight = gdispGetFontMetric(gwinGetDefaultFont(), fontHeight);	
 
 	gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, Black);
 	
-	for (qi = gfxQueueASyncPeek(&gcw->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i += fheight + 4) {
+	for (qi = gfxQueueASyncPeek(&gcw->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i += fheight + 2*BORDER) {
 		if (((ListItem*)qi)->flags & GLIST_FLG_SELECTED) 
-			gdispFillStringBox(gw->g.x + 3, gw->g.y + 3 + i, gw->g.width - 6, fheight, ((ListItem*)qi)->text, gwinGetDefaultFont(), White, Black, justifyLeft);
+			gdispFillStringBox(gw->g.x + BORDER, gw->g.y + BORDER + i, gw->g.width - 2*BORDER, fheight, ((ListItem*)qi)->text, gwinGetDefaultFont(), White, Black, justifyLeft);
 		else
-			gdispFillStringBox(gw->g.x + 3, gw->g.y + 3 + i, gw->g.width - 6, fheight, ((ListItem*)qi)->text, gwinGetDefaultFont(), Black, White, justifyLeft);
+			gdispFillStringBox(gw->g.x + BORDER, gw->g.y + BORDER + i, gw->g.width - 2*BORDER, fheight, ((ListItem*)qi)->text, gwinGetDefaultFont(), Black, White, justifyLeft);
 	}
 
 	#undef gcw
@@ -101,9 +103,9 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
 		(void)				x;
 
 		uint16_t i, item_id, item_height;
-		const gfxQueueASyncItem* qi;
+		gfxQueueASyncItem* qi;
 
-		item_height = gdispGetFontMetric(gwinGetDefaultFont(), fontHeight) + 2;
+		item_height = gdispGetFontMetric(gwinGetDefaultFont(), fontHeight) + 2*BORDER;
 
 		item_id = (y - gw->g.y) / item_height;
 
@@ -115,6 +117,11 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
 		}
 
 		_gwidgetRedraw((GHandle)gw);
+
+		// Do not generate an event if an empty section of the list has has been selected
+		if (item_id < 0 || item_id > gcw->cnt - 1)
+			return;
+
 		sendListEvent(gw, item_id);
 
 		#undef gcw
@@ -123,10 +130,11 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
 #endif
 
 static void _destroy(GHandle gh) {
-	const gfxQueueASyncItem* qi;
+	gfxQueueASyncItem* qi;
 
 	while((qi = gfxQueueASyncGet(&((GListObject *)gh)->list_head)))
 		gfxFree((void *)qi);
+
 	_gwidgetDestroy(gh);
 }
 
@@ -134,7 +142,7 @@ static const gwidgetVMT listVMT = {
 	{
 		"List",					// The class name
 		sizeof(GListObject),	// The object size
-		_destroy,		// The destroy routine
+		_destroy,				// The destroy routine
 		_gwidgetRedraw,			// The redraw routine
 		0,						// The after-clear routine
 	},
@@ -203,13 +211,58 @@ int gwinListAddItem(GHandle gh, const char* item_name, bool_t useAlloc) {
 	// increment the total amount of entries in the list widget
 	widget(gh)->cnt++;
 
+	// return the position in the list (-1 because we start with index 0)
 	return widget(gh)->cnt-1;
 }
 
+char* gwinListItemGetText(GHandle gh, int item) {
+	gfxQueueASyncItem* qi;
+	uint16_t i;
+
+	// is it a valid handle?
+	if (gh->vmt != (gwinVMT *)&listVMT)
+		return 0;
+
+	// watch out for an invalid item
+	if (item < 0 || item > (widget(gh)->cnt) - 1)
+		return 0;
+
+	qi = gfxQueueASyncPeek(&widget(gh)->list_head);
+	
+	for (i = 0; i < item; i++) {
+		qi = gfxQueueASyncNext(qi);
+	}
+
+	return ((ListItem*)qi)->text;
+}
+
+int gwinListFindText(GHandle gh, const char* text) {
+	gfxQueueASyncItem* qi;
+	uint16_t i;
+
+	// is it a valid handle?
+	if (gh->vmt != (gwinVMT *)&listVMT)
+		return -1;
+
+	// watch out for NULL pointers
+	if (!text)
+		return -1;
+
+	qi = gfxQueueASyncPeek(&widget(gh)->list_head);
+	
+	for(qi = gfxQueueASyncPeek(&widget(gh)->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
+		if (strcmp(((ListItem *)qi)->text, text) == 0)
+			return i;	
+	}
+
+	return -1;
+}
+
 int gwinListGetSelected(GHandle gh) {
-	const gfxQueueASyncItem	*qi;
+	gfxQueueASyncItem	*qi;
 	int i;
 
+	// is it a valid handle?
 	if (gh->vmt != (gwinVMT *)&listVMT)
 		return -1;
 
@@ -221,6 +274,110 @@ int gwinListGetSelected(GHandle gh) {
 	return -1;
 }
 
+void gwinListItemSetParam(GHandle gh, int item, uint16_t param) {
+	gfxQueueASyncItem* qi;
+	uint16_t i;
+
+	// is it a valid handle?
+	if (gh->vmt != (gwinVMT *)&listVMT)
+		return;
+
+	// watch out for an invalid item
+	if (item < 0 || item > (widget(gh)->cnt) - 1)
+		return;
+
+	qi = gfxQueueASyncPeek(&widget(gh)->list_head);
+	
+	for (i = 0; i < item; i++) {
+		((ListItem*)qi)->param = param;
+	}
+
+	return;	
+}
+
+void gwinListDeleteAll(GHandle gh) {
+	gfxQueueASyncItem* qi;
+
+	while((qi = gfxQueueASyncGet(&((GListObject *)gh)->list_head)))
+		gfxFree((void *)qi);
+}
+
+void gwinListItemDelete(GHandle gh, int item) {
+	gfxQueueASyncItem* qi;
+	uint16_t i;
+
+	// is it a valid handle?
+	if (gh->vmt != (gwinVMT *)&listVMT)
+		return;
+
+	// watch out for an invalid item
+	if (item < 0 || item > (widget(gh)->cnt) - 1)
+		return;
+
+	qi = gfxQueueASyncPeek(&widget(gh)->list_head);
+
+	// get our item pointer	
+	for (i = 0; i < item; i++) {
+		qi = gfxQueueASyncNext(qi);
+	}
+
+	gfxQueueASyncRemove(&widget(gh)->list_head, qi);
+	gfxFree((void*)qi);
+}
+
+uint16_t gwinListItemGetParam(GHandle gh, int item) {
+	gfxQueueASyncItem* qi;
+	uint16_t i;
+
+	// is it a valid handle?
+	if (gh->vmt != (gwinVMT *)&listVMT)
+		return 0;
+
+	// watch out for an invalid item
+	if (item < 0 || item > (widget(gh)->cnt) - 1)
+		return 0;
+
+	qi = gfxQueueASyncPeek(&widget(gh)->list_head);
+	
+	for (i = 0; i < item; i++) {
+		qi = gfxQueueASyncNext(qi);
+	}
+
+	return ((ListItem*)qi)->param;
+}
+
+bool_t gwinListItemIsSelected(GHandle gh, int item) {
+	gfxQueueASyncItem* qi;
+	uint16_t i;
+
+	// is it a valid handle?
+	if (gh->vmt != (gwinVMT *)&listVMT)
+		return FALSE;
+
+	// watch out for an invalid item
+	if (item < 0 || item > (widget(gh)->cnt) - 1)
+		return FALSE;
+
+	qi = gfxQueueASyncPeek(&widget(gh)->list_head);
+	
+	for (i = 0; i < item; i++) {
+		qi = gfxQueueASyncNext(qi);
+	}
+
+	if (((ListItem*)qi)->flags &  GLIST_FLG_SELECTED)
+		return TRUE;
+	else
+		return FALSE;
+}
+
+int gwinListItemCount(GHandle gh) {
+	// is it a valid handle?
+	if (gh->vmt != (gwinVMT *)&listVMT)
+		return 0;
+
+	return widget(gh)->cnt;
+}
+
 #endif // GFX_USE_GWIN && GWIN_NEED_LIST
 /** @} */
 
-- 
cgit v1.2.3


From 9edb1dab8b176a1f7e229709dcd5e7bca75a0890 Mon Sep 17 00:00:00 2001
From: Joel Bodenmann <joel@unormal.org>
Date: Sun, 28 Jul 2013 01:15:36 +0200
Subject: compiler warnings

---
 src/gwin/list.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/src/gwin/list.c b/src/gwin/list.c
index 9b9ab7c6..8e1f2ef4 100644
--- a/src/gwin/list.c
+++ b/src/gwin/list.c
@@ -78,7 +78,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
 	(void)param;
 
 	uint16_t i, fheight;
-	gfxQueueASyncItem* qi;
+	const gfxQueueASyncItem* qi;
 	const GColorSet*	pcol;
 
 	fheight = gdispGetFontMetric(gwinGetDefaultFont(), fontHeight);	
@@ -103,7 +103,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
 		(void)				x;
 
 		uint16_t i, item_id, item_height;
-		gfxQueueASyncItem* qi;
+		const gfxQueueASyncItem* qi;
 
 		item_height = gdispGetFontMetric(gwinGetDefaultFont(), fontHeight) + 2*BORDER;
 
@@ -130,7 +130,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
 #endif
 
 static void _destroy(GHandle gh) {
-	gfxQueueASyncItem* qi;
+	const gfxQueueASyncItem* qi;
 
 	while((qi = gfxQueueASyncGet(&((GListObject *)gh)->list_head)))
 		gfxFree((void *)qi);
@@ -216,7 +216,7 @@ int gwinListAddItem(GHandle gh, const char* item_name, bool_t useAlloc) {
 }
 
 char* gwinListItemGetText(GHandle gh, int item) {
-	gfxQueueASyncItem* qi;
+	const gfxQueueASyncItem* qi;
 	uint16_t i;
 
 	// is it a valid handle?
@@ -237,7 +237,7 @@ char* gwinListItemGetText(GHandle gh, int item) {
 }
 
 int gwinListFindText(GHandle gh, const char* text) {
-	gfxQueueASyncItem* qi;
+	const gfxQueueASyncItem* qi;
 	uint16_t i;
 
 	// is it a valid handle?
@@ -259,7 +259,7 @@ int gwinListFindText(GHandle gh, const char* text) {
 }
 
 int gwinListGetSelected(GHandle gh) {
-	gfxQueueASyncItem	*qi;
+	const gfxQueueASyncItem	*qi;
 	int i;
 
 	// is it a valid handle?
@@ -275,7 +275,7 @@ int gwinListGetSelected(GHandle gh) {
 }
 
 void gwinListItemSetParam(GHandle gh, int item, uint16_t param) {
-	gfxQueueASyncItem* qi;
+	const gfxQueueASyncItem* qi;
 	uint16_t i;
 
 	// is it a valid handle?
@@ -296,14 +296,14 @@ void gwinListItemSetParam(GHandle gh, int item, uint16_t param) {
 }
 
 void gwinListDeleteAll(GHandle gh) {
-	gfxQueueASyncItem* qi;
+	const gfxQueueASyncItem* qi;
 
 	while((qi = gfxQueueASyncGet(&((GListObject *)gh)->list_head)))
 		gfxFree((void *)qi);
 }
 
 void gwinListItemDelete(GHandle gh, int item) {
-	gfxQueueASyncItem* qi;
+	const gfxQueueASyncItem* qi;
 	uint16_t i;
 
 	// is it a valid handle?
@@ -326,7 +326,7 @@ void gwinListItemDelete(GHandle gh, int item) {
 }
 
 uint16_t gwinListItemGetParam(GHandle gh, int item) {
-	gfxQueueASyncItem* qi;
+	const gfxQueueASyncItem* qi;
 	uint16_t i;
 
 	// is it a valid handle?
@@ -347,7 +347,7 @@ uint16_t gwinListItemGetParam(GHandle gh, int item) {
 }
 
 bool_t gwinListItemIsSelected(GHandle gh, int item) {
-	gfxQueueASyncItem* qi;
+	const gfxQueueASyncItem* qi;
 	uint16_t i;
 
 	// is it a valid handle?
-- 
cgit v1.2.3


From c7fdb5df2a32e21905e21193bc018c5d6fc6d326 Mon Sep 17 00:00:00 2001
From: Joel Bodenmann <joel@unormal.org>
Date: Sun, 28 Jul 2013 02:06:27 +0200
Subject: list widget first implementation

---
 src/gwin/list.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/gwin/list.c b/src/gwin/list.c
index 8e1f2ef4..1d61f1c4 100644
--- a/src/gwin/list.c
+++ b/src/gwin/list.c
@@ -79,17 +79,17 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
 
 	uint16_t i, fheight;
 	const gfxQueueASyncItem* qi;
-	const GColorSet*	pcol;
 
 	fheight = gdispGetFontMetric(gwinGetDefaultFont(), fontHeight);	
 
-	gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, Black);
+	gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->enabled.edge);
 	
 	for (qi = gfxQueueASyncPeek(&gcw->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i += fheight + 2*BORDER) {
-		if (((ListItem*)qi)->flags & GLIST_FLG_SELECTED) 
-			gdispFillStringBox(gw->g.x + BORDER, gw->g.y + BORDER + i, gw->g.width - 2*BORDER, fheight, ((ListItem*)qi)->text, gwinGetDefaultFont(), White, Black, justifyLeft);
-		else
-			gdispFillStringBox(gw->g.x + BORDER, gw->g.y + BORDER + i, gw->g.width - 2*BORDER, fheight, ((ListItem*)qi)->text, gwinGetDefaultFont(), Black, White, justifyLeft);
+		if (((ListItem*)qi)->flags & GLIST_FLG_SELECTED) {
+			gdispFillStringBox(gw->g.x + BORDER, gw->g.y + BORDER + i, gw->g.width - 2*BORDER, fheight, ((ListItem*)qi)->text, gwinGetDefaultFont(), gw->pstyle->background, gw->pstyle->enabled.text, justifyLeft);
+		} else {
+			gdispFillStringBox(gw->g.x + BORDER, gw->g.y + BORDER + i, gw->g.width - 2*BORDER, fheight, ((ListItem*)qi)->text, gwinGetDefaultFont(), gw->pstyle->enabled.text, gw->pstyle->background, justifyLeft);
+		}
 	}
 
 	#undef gcw
-- 
cgit v1.2.3


From 4e3eacb9f762addc6049e28d39516724ef1beef8 Mon Sep 17 00:00:00 2001
From: Joel Bodenmann <joel@unormal.org>
Date: Sun, 28 Jul 2013 03:31:45 +0200
Subject: list widget doxygen

---
 include/gwin/list.h | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 121 insertions(+), 1 deletion(-)

diff --git a/include/gwin/list.h b/include/gwin/list.h
index 307226c9..7355623f 100644
--- a/include/gwin/list.h
+++ b/include/gwin/list.h
@@ -53,26 +53,146 @@ typedef struct GListObject {
 extern "C" {
 #endif
 
+/**
+ * @brief				Create a list widget
+ *
+ * @note				The drawing color and the background color get set to the current defaults. If you haven't called
+ *						@p gwinSetDefaultColor() or @p gwinSetDefaultBgColor() then these are Black and White.
+ * @note				The font gets set to the current default font. If you haven't called @p gwinSetDefaultFont() then
+ *						there is no default font and text drawing operations will not display anything.
+ * @note				A list remembers its normal drawing state. If there is a window manager then it is automatically
+ *						redrawn if the window is moved or its visibility state is changed.
+ * @note				The list contains no elements after creation.
+ * @note				A slider supports mouse, toggle and dial input.
+ * @note				When assigning a toggle, only one toggle is supported per role. If you try to assign more than
+ *						one toggle to a role, it will forget the previous toggle. Three roles are supported:
+ *						Role 0 = toggle for down, role 1 = toggle for up, role 2 = toggle for select.
+ * @note				When assigning a dial, only one dial is supported. If you try to assign more than one dial, it
+ *						will forget the previous dial. Only dial role 0 is supported.
+ *
+ * @param[in] widget	The GListObject structure to initialize. If this is NULL, the structure is dynamically allocated.
+ * @param[in] pInit		The initialization parameters to use
+ *
+ * @return				NULL if there is no resulting drawing area, otherwise a window handle.
+ *
+ * @api
+ */
 GHandle gwinListCreate(GListObject *widget, GWidgetInit *pInit);
 
+/**
+ * @brief				Add an item to the list
+ *
+ * @note				The ID you get returned is not static. If items get removed from the list, the list items get
+ * 						reordered.
+ *
+ * @param[in] gh		The widget handle (must be a list handle)
+ * @param[in] item		The string which shall be displayed in the list afterwards
+ * @param[in] useAlloc	If set to TRUE, the string will be dynamically allocated. A static buffer must be passed otherwise
+ *
+ * @return				The current ID of the item. The ID might change if you remove items from the middle of the list
+ *
+ * @api
+ */
 int gwinListAddItem(GHandle gh, const char* item, bool_t useAlloc);
 
+/**
+ * @brief				Get the name behind an item with a given ID
+ *
+ * @param[in] gh		The widget handle (must be a list handle)
+ * @param[in] item		The item ID
+ *
+ * @return				The string of the list item or NULL on error
+ *
+ * @api
+ */
 char* gwinListItemGetText(GHandle gh, int item);
 
+/**
+ * @brief				Get the ID of an item with a given name
+ *
+ * @param[in] gh		The widget handle (must be a list handle)
+ * @param[in] text		The item name
+ *
+ * @return				The id of the list item or -1 on error
+ *
+ * @api
+ */
 int gwinListFindText(GHandle gh, const char* text);
 
+/**
+ * @brief				Set the custom parameter of an item with a given ID
+ *
+ * @param[in] gh		The widget handle (must be a list handle)
+ * @param[in] item		The item ID
+ * @param[in] param		The parameter to be set
+ *
+ * @api
+ */
 void gwinListItemSetParam(GHandle gh, int item, uint16_t param);
 
+/**
+ * @brief				Get the custom parameter of an item with a given ID
+ *
+ * @param[in] gh		The widget handle (must be a list handle)
+ * @param[in] item		The item ID
+ *
+ * @return				The parameter
+ *
+ * @api
+ */
 uint16_t gwinListItemGetParam(GHandle gh, int item);
 
-void nListDeleteAll(GHandle gh);
+/**
+ * @brief				Delete all the items of the list
+ *
+ * @param[in] gh		The widget handle (must be a list handle)
+ *
+ * @api
+ */
+void ListDeleteAll(GHandle gh);
 
+/**
+ * @brief				Delete an item from the list
+ *
+ * @param[in] gh		The widget handle (must be a list handle)
+ * @param[in] item		The item ID
+ *
+ * @api
+ */
 void gwinListItemDelete(GHandle gh, int item);
 
+/**
+ * @brief				Get the amount of items within the list
+ *
+ * @param[in] gh		The widget handle (must be a list handle)
+ *
+ * @return				The amount of items in the list
+ *
+ * @api
+ */
 int gwinListItemCount(GHandle gh);
 
+/**
+ * @brief				Check if an item with a given ID is selected
+ *
+ * @param[in] gh		The widget handle (must be a list handle)
+ * @param[in] item		The item ID
+ *
+ * @return				TRUE if the item is selected, FALSE otherwise
+ *
+ * @api
+ */
 bool_t gwinListItemIsSelected(GHandle gh, int item);
 
+/**
+ * @brief				Get the ID of the selected item
+ *
+ * @param[in] gh		The widget handle (must be a list handle)
+ *
+ * @return				The ID of the list item
+ *
+ * @api
+ */
 int gwinListGetSelected(GHandle gh);
 
 #ifdef __cplusplus
-- 
cgit v1.2.3


From c66e5cd9cbcdea293d661c6886587b3c9ca35078 Mon Sep 17 00:00:00 2001
From: Joel Bodenmann <joel@unormal.org>
Date: Sun, 28 Jul 2013 07:00:08 +0200
Subject: some more list widget work

---
 src/gwin/list.c | 109 +++++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 89 insertions(+), 20 deletions(-)

diff --git a/src/gwin/list.c b/src/gwin/list.c
index 1d61f1c4..8f5530a2 100644
--- a/src/gwin/list.c
+++ b/src/gwin/list.c
@@ -22,7 +22,10 @@
 #include "gwin/class_gwin.h"
 #include <string.h>
 
-#define BORDER		3
+// user for the default drawing routine
+#define BORDER			3	// the border from the the text to the frame
+#define BORDER_SCROLL	20	// the border from the scroll buttons to the frame
+#define ARROW			10	// arrow side length
 
 #define widget(gh)	((GListObject *)gh)
 
@@ -30,20 +33,10 @@
 #define GLIST_FLG_HASIMAGES			(GWIN_FIRST_CONTROL_FLAG << 1)
 #define GLIST_FLG_SELECTED			(GWIN_FIRST_CONTROL_FLAG << 2)
 
-/*
-Use gw->pstyle->background for the unselected fill.
-Use gw->pstyle->enabled/disabled->text for unselected text color
-Use gw->pstyle->enabled/disabled->edge for the surounding box
-Use gw->pstyle->enabled/disabled->fill for the selected text fill
-or gw->pstyle->pressed->fill for the selected text fill (which ever looks best)
-and use gw->pstyle->pressed->text for the selected text color
-*/
-
 typedef struct ListItem {
 	gfxQueueASyncItem	q_item;		// This must be the first member in the struct
 
 	uint16_t			flags;
-	    #define LISTITEM_ALLOCEDTEXT      0x0001
 	uint16_t			param;		// A parameter the user can specify himself
 	const char*			text;
 	#if GWIN_LIST_IMAGES
@@ -51,6 +44,41 @@ typedef struct ListItem {
 	#endif
 } ListItem;
 
+void _selectUp(GWidgetObject *gw) {
+	#define gcw			((GListObject *)gw)
+
+	gfxQueueASyncItem	*qi;
+	uint16_t i;
+
+	for (i = 0, qi = gfxQueueASyncPeek(&gcw->list_head); qi; qi = gfxQueueASyncNext(qi), i++) {
+		if (((ListItem*)qi)->flags & GLIST_FLG_SELECTED && i < gcw->cnt - 1) {
+			((ListItem*)qi)->flags &=~ GLIST_FLG_SELECTED;
+			qi = gfxQueueASyncNext(qi);
+			((ListItem*)qi)->flags |= GLIST_FLG_SELECTED;	
+		}
+	}
+
+	_gwidgetRedraw((GHandle)gw);
+
+	#undef gcw
+}
+
+static void _selectDown(GWidgetObject *gw) {
+	#define gcw			((GListObject *)gw)
+
+	_gwidgetRedraw((GHandle)gw);
+
+	#undef gcw
+}
+
+static void _selectEnter(GWidgetObject *gw) {
+	#define gcw			((GListObject *)gw)
+
+
+
+	#undef gcw
+}
+
 static void sendListEvent(GWidgetObject *gw, int item) {
 	GSourceListener*	psl;
 	GEvent*				pe;
@@ -78,17 +106,29 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
 	(void)param;
 
 	uint16_t i, fheight;
+	const point upArrow[] = { {0, ARROW}, {ARROW, ARROW}, {ARROW/2, 0} };
+	const point downArrow[] = { {0, 0}, {ARROW, 0}, {ARROW/2, ARROW} };
 	const gfxQueueASyncItem* qi;
 
 	fheight = gdispGetFontMetric(gwinGetDefaultFont(), fontHeight);	
 
+	// the list frame
 	gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->enabled.edge);
+	gdispDrawLine(gw->g.x + gw->g.width - BORDER_SCROLL, gw->g.y, gw->g.x + gw->g.width - BORDER_SCROLL, gw->g.y + gw->g.height, gw->pstyle->enabled.edge);
+	gdispDrawLine(gw->g.x + gw->g.width - BORDER_SCROLL, gw->g.y + BORDER_SCROLL, gw->g.x + gw->g.width, gw->g.y + BORDER_SCROLL, gw->pstyle->enabled.edge);
+	gdispDrawLine(gw->g.x + gw->g.width - BORDER_SCROLL, gw->g.y + gw->g.height - BORDER_SCROLL, gw->g.x + gw->g.width, gw->g.y + gw->g.height - BORDER_SCROLL, gw->pstyle->enabled.edge);
+
+	// the up-button
+	gdispFillConvexPoly(gw->g.x + gw->g.width - BORDER_SCROLL + ARROW/2, gw->g.y + BORDER_SCROLL - ARROW - ARROW/2, upArrow, 3, gw->pstyle->enabled.edge);
 	
+	// the down-button
+	gdispFillConvexPoly(gw->g.x + gw->g.width - BORDER_SCROLL + ARROW/2, gw->g.y + gw->g.height - BORDER_SCROLL + ARROW/2, downArrow, 3, gw->pstyle->enabled.edge);
+
 	for (qi = gfxQueueASyncPeek(&gcw->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i += fheight + 2*BORDER) {
 		if (((ListItem*)qi)->flags & GLIST_FLG_SELECTED) {
-			gdispFillStringBox(gw->g.x + BORDER, gw->g.y + BORDER + i, gw->g.width - 2*BORDER, fheight, ((ListItem*)qi)->text, gwinGetDefaultFont(), gw->pstyle->background, gw->pstyle->enabled.text, justifyLeft);
+			gdispFillStringBox(gw->g.x + BORDER, gw->g.y + BORDER + i, gw->g.width - 2*BORDER - BORDER_SCROLL, fheight, ((ListItem*)qi)->text, gwinGetDefaultFont(), gw->pstyle->background, gw->pstyle->enabled.text, justifyLeft);
 		} else {
-			gdispFillStringBox(gw->g.x + BORDER, gw->g.y + BORDER + i, gw->g.width - 2*BORDER, fheight, ((ListItem*)qi)->text, gwinGetDefaultFont(), gw->pstyle->enabled.text, gw->pstyle->background, justifyLeft);
+			gdispFillStringBox(gw->g.x + BORDER, gw->g.y + BORDER + i, gw->g.width - 2*BORDER - BORDER_SCROLL, fheight, ((ListItem*)qi)->text, gwinGetDefaultFont(), gw->pstyle->enabled.text, gw->pstyle->background, justifyLeft);
 		}
 	}
 
@@ -96,7 +136,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
 }
 
 #if GINPUT_NEED_MOUSE
-	// A mouse down has occured over the list area
+	// a mouse down has occured over the list area
 	static void MouseDown(GWidgetObject* gw, coord_t x, coord_t y) {
 		#define gcw			((GListObject *)gw)
 		#define li			((ListItem *)qi)
@@ -106,7 +146,6 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
 		const gfxQueueASyncItem* qi;
 
 		item_height = gdispGetFontMetric(gwinGetDefaultFont(), fontHeight) + 2*BORDER;
-
 		item_id = (y - gw->g.y) / item_height;
 
 		for(qi = gfxQueueASyncPeek(&gcw->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
@@ -118,7 +157,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
 
 		_gwidgetRedraw((GHandle)gw);
 
-		// Do not generate an event if an empty section of the list has has been selected
+		// do not generate an event if an empty section of the list has has been selected
 		if (item_id < 0 || item_id > gcw->cnt - 1)
 			return;
 
@@ -129,6 +168,32 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
 	}
 #endif
 
+#if GINPUT_NEED_TOGGLE
+	// a toggle-on has occurred
+	static void ToggleOn(GWidgetObject *gw, uint16_t role) {
+		#define gcw			((GListObject *)gw)
+
+		switch (role) {
+			// select up
+			case 0:
+				_selectUp(gw);
+				break;
+
+			// select down
+			case 1:
+				_selectDown(gw);
+				break;
+
+			// select enter
+			case 2:
+				_selectEnter(gw);
+				break;
+		}
+
+		#undef gcw
+	}
+#endif
+
 static void _destroy(GHandle gh) {
 	const gfxQueueASyncItem* qi;
 
@@ -156,11 +221,11 @@ static const gwidgetVMT listVMT = {
 	#endif
 	#if GINPUT_NEED_TOGGLE
 		{
+			2,					// three toggle roles
+			ToggleAssin,		// Assign toggles
+			ToggleGet,			// get toggles
 			0,
-			0,
-			0,
-			0,
-			0,
+			ToggleOn,			// process toggle on event
 		},
 	#endif
 	#if GINPUT_NEED_DIAL
@@ -205,6 +270,10 @@ int gwinListAddItem(GHandle gh, const char* item_name, bool_t useAlloc) {
 	newItem->param = 0;
 	newItem->text = item_name;
 
+	// select the item if it's the first in the list
+	if (widget(gh)->cnt == 0)
+		newItem->flags |= GLIST_FLG_SELECTED;
+
 	// add the new item to the list
 	gfxQueueASyncPut(&widget(gh)->list_head, &newItem->q_item);
 
-- 
cgit v1.2.3


From 423c28b40e0849838615e575630d8e251f04739b Mon Sep 17 00:00:00 2001
From: Joel Bodenmann <joel@unormal.org>
Date: Sun, 28 Jul 2013 07:04:04 +0200
Subject: cleanup

---
 include/gwin/list.h |  4 ++--
 src/gwin/list.c     | 15 +--------------
 2 files changed, 3 insertions(+), 16 deletions(-)

diff --git a/include/gwin/list.h b/include/gwin/list.h
index 7355623f..ba83f24b 100644
--- a/include/gwin/list.h
+++ b/include/gwin/list.h
@@ -65,8 +65,8 @@ extern "C" {
  * @note				The list contains no elements after creation.
  * @note				A slider supports mouse, toggle and dial input.
  * @note				When assigning a toggle, only one toggle is supported per role. If you try to assign more than
- *						one toggle to a role, it will forget the previous toggle. Three roles are supported:
- *						Role 0 = toggle for down, role 1 = toggle for up, role 2 = toggle for select.
+ *						one toggle to a role, it will forget the previous toggle. Two roles are supported:
+ *						Role 0 = toggle for down, role 1 = toggle for up 
  * @note				When assigning a dial, only one dial is supported. If you try to assign more than one dial, it
  *						will forget the previous dial. Only dial role 0 is supported.
  *
diff --git a/src/gwin/list.c b/src/gwin/list.c
index 8f5530a2..f495ada4 100644
--- a/src/gwin/list.c
+++ b/src/gwin/list.c
@@ -71,14 +71,6 @@ static void _selectDown(GWidgetObject *gw) {
 	#undef gcw
 }
 
-static void _selectEnter(GWidgetObject *gw) {
-	#define gcw			((GListObject *)gw)
-
-
-
-	#undef gcw
-}
-
 static void sendListEvent(GWidgetObject *gw, int item) {
 	GSourceListener*	psl;
 	GEvent*				pe;
@@ -183,11 +175,6 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
 			case 1:
 				_selectDown(gw);
 				break;
-
-			// select enter
-			case 2:
-				_selectEnter(gw);
-				break;
 		}
 
 		#undef gcw
@@ -221,7 +208,7 @@ static const gwidgetVMT listVMT = {
 	#endif
 	#if GINPUT_NEED_TOGGLE
 		{
-			2,					// three toggle roles
+			2,					// two toggle roles
 			ToggleAssin,		// Assign toggles
 			ToggleGet,			// get toggles
 			0,
-- 
cgit v1.2.3


From 580cf977d07820774efd8abcf067f015422b7e55 Mon Sep 17 00:00:00 2001
From: Joel Bodenmann <joel@unormal.org>
Date: Sun, 28 Jul 2013 14:13:05 +0200
Subject: clear after mouse calibration to avoid silly display

---
 src/ginput/mouse.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/ginput/mouse.c b/src/ginput/mouse.c
index 28707d8b..5459a4cd 100644
--- a/src/ginput/mouse.c
+++ b/src/ginput/mouse.c
@@ -509,6 +509,13 @@ bool_t ginputCalibrateMouse(uint16_t instance) {
 			MouseConfig.fnsavecal(instance, (const uint8_t *)&MouseConfig.caldata, sizeof(MouseConfig.caldata));
 			MouseConfig.flags |= FLG_CAL_SAVED;
 		}
+
+		// Clear the screen using the GWIN default background color
+		#if GFX_USE_GWIN
+			gdispClear(gwinGetDefaultBgColor());
+		#else
+			gdispClear(White);
+		#endif
 	
 		return TRUE;
 	#endif
-- 
cgit v1.2.3


From 632566e243e1fa914dfee6ec87913d940856963c Mon Sep 17 00:00:00 2001
From: Joel Bodenmann <joel@unormal.org>
Date: Sun, 28 Jul 2013 15:26:59 +0200
Subject: list fix

---
 src/gwin/list.c | 55 +++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 45 insertions(+), 10 deletions(-)

diff --git a/src/gwin/list.c b/src/gwin/list.c
index f495ada4..54bac334 100644
--- a/src/gwin/list.c
+++ b/src/gwin/list.c
@@ -44,7 +44,8 @@ typedef struct ListItem {
 	#endif
 } ListItem;
 
-void _selectUp(GWidgetObject *gw) {
+// select the next item in the list
+static int _selectDown(GWidgetObject *gw) {
 	#define gcw			((GListObject *)gw)
 
 	gfxQueueASyncItem	*qi;
@@ -55,19 +56,44 @@ void _selectUp(GWidgetObject *gw) {
 			((ListItem*)qi)->flags &=~ GLIST_FLG_SELECTED;
 			qi = gfxQueueASyncNext(qi);
 			((ListItem*)qi)->flags |= GLIST_FLG_SELECTED;	
+
+			break;
 		}
 	}
 
 	_gwidgetRedraw((GHandle)gw);
 
+	return ++i;
+
 	#undef gcw
 }
 
-static void _selectDown(GWidgetObject *gw) {
+// select the previous item in the list
+static int _selectUp(GWidgetObject *gw) {
 	#define gcw			((GListObject *)gw)
 
+	gfxQueueASyncItem *qi;
+	gfxQueueASyncItem *qi2;
+	uint16_t i;
+
+	qi = gfxQueueASyncPeek(&gcw->list_head);
+	qi2 = qi;
+
+	for (i = 0; qi2; qi2 = gfxQueueASyncNext(qi), i++) {
+		if (((ListItem*)qi2)->flags & GLIST_FLG_SELECTED) {
+			((ListItem*)qi2)->flags &=~ GLIST_FLG_SELECTED;
+			((ListItem*)qi)->flags |= GLIST_FLG_SELECTED;
+		
+			break;
+		}
+
+		qi = qi2;
+	}
+
 	_gwidgetRedraw((GHandle)gw);
 
+	return --i;
+
 	#undef gcw
 }
 
@@ -137,14 +163,23 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
 		uint16_t i, item_id, item_height;
 		const gfxQueueASyncItem* qi;
 
-		item_height = gdispGetFontMetric(gwinGetDefaultFont(), fontHeight) + 2*BORDER;
-		item_id = (y - gw->g.y) / item_height;
-
-		for(qi = gfxQueueASyncPeek(&gcw->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
-			if (item_id == i)
-				li->flags |= GLIST_FLG_SELECTED;
-			else
-				li->flags &=~ GLIST_FLG_SELECTED;
+		item_id = -1;
+
+		if (x > gw->g.width - BORDER_SCROLL) {
+			if (y < BORDER_SCROLL)
+				item_id = _selectUp(gw);
+			else if (y > gw->g.height - BORDER_SCROLL)
+				item_id = _selectDown(gw);
+		} else if (x < gw->g.width - BORDER_SCROLL - BORDER) {
+			item_height = gdispGetFontMetric(gwinGetDefaultFont(), fontHeight) + 2*BORDER;
+			item_id = (y) / item_height;
+
+			for(qi = gfxQueueASyncPeek(&gcw->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
+				if (item_id == i)
+					li->flags |= GLIST_FLG_SELECTED;
+				else
+					li->flags &=~ GLIST_FLG_SELECTED;
+			}
 		}
 
 		_gwidgetRedraw((GHandle)gw);
-- 
cgit v1.2.3


From 31f355460248b2d39969590feefc9482e53c451f Mon Sep 17 00:00:00 2001
From: Joel Bodenmann <joel@unormal.org>
Date: Sun, 28 Jul 2013 23:18:59 +0200
Subject: list update

---
 include/gwin/list.h |  6 ++++++
 src/gwin/list.c     | 21 ++++++++++++++++-----
 2 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/include/gwin/list.h b/include/gwin/list.h
index ba83f24b..d28206d9 100644
--- a/include/gwin/list.h
+++ b/include/gwin/list.h
@@ -45,6 +45,12 @@ typedef struct GEventGWinList {
 // A list window
 typedef struct GListObject {
 	GWidgetObject	w;
+
+	#if GINPUT_NEED_TOGGLE
+		uint16_t	t_up;
+		uint16_t	t_dn;
+	#endif
+
 	int				cnt;		// Number of items currently in the list (quicker than counting each time)
 	gfxQueueASync	list_head;	// The list of items
 } GListObject;
diff --git a/src/gwin/list.c b/src/gwin/list.c
index 54bac334..2509260c 100644
--- a/src/gwin/list.c
+++ b/src/gwin/list.c
@@ -201,19 +201,30 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
 		#define gcw			((GListObject *)gw)
 
 		switch (role) {
-			// select up
+			// select down
 			case 0:
-				_selectUp(gw);
+				_selectDown(gw);
 				break;
 
-			// select down
+			// select up
 			case 1:
-				_selectDown(gw);
+				_selectUp(gw);
 				break;
 		}
 
 		#undef gcw
 	}
+
+	static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) {
+		if (role)
+			((GListObject *)gw)->t_up = instance;
+		else
+			((GListObject *)gw)->t_dn = instance;
+	}
+
+	static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role) {
+		return role ? ((GListObject *)gw)->t_up : ((GListObject *)gw)->t_dn;
+	}
 #endif
 
 static void _destroy(GHandle gh) {
@@ -244,7 +255,7 @@ static const gwidgetVMT listVMT = {
 	#if GINPUT_NEED_TOGGLE
 		{
 			2,					// two toggle roles
-			ToggleAssin,		// Assign toggles
+			ToggleAssign,		// Assign toggles
 			ToggleGet,			// get toggles
 			0,
 			ToggleOn,			// process toggle on event
-- 
cgit v1.2.3


From 06d339456e64f6257bd72eb9343d7c899ea0b20b Mon Sep 17 00:00:00 2001
From: inmarket <andrewh@inmarket.com.au>
Date: Thu, 1 Aug 2013 14:50:40 +1000
Subject: Update gwin widgets and lists demos

---
 demos/modules/gwin/list/gfxconf.h    |  2 +-
 demos/modules/gwin/list/main.c       | 31 ++++++++++++++++++-----------
 demos/modules/gwin/widgets/gfxconf.h |  1 +
 demos/modules/gwin/widgets/main.c    | 38 ++++++++++++++++++++++++++++++++----
 4 files changed, 56 insertions(+), 16 deletions(-)

diff --git a/demos/modules/gwin/list/gfxconf.h b/demos/modules/gwin/list/gfxconf.h
index 895d7c49..cf5f8690 100644
--- a/demos/modules/gwin/list/gfxconf.h
+++ b/demos/modules/gwin/list/gfxconf.h
@@ -40,7 +40,7 @@
 #define GDISP_NEED_CIRCLE			TRUE
 #define GDISP_NEED_ELLIPSE			TRUE
 #define GDISP_NEED_ARC				FALSE
-#define GDISP_NEED_CONVEX_POLYGON	FALSE
+#define GDISP_NEED_CONVEX_POLYGON	TRUE
 #define GDISP_NEED_SCROLL			FALSE
 #define GDISP_NEED_PIXELREAD		FALSE
 #define GDISP_NEED_CONTROL			FALSE
diff --git a/demos/modules/gwin/list/main.c b/demos/modules/gwin/list/main.c
index 35847be0..a3a17250 100644
--- a/demos/modules/gwin/list/main.c
+++ b/demos/modules/gwin/list/main.c
@@ -10,11 +10,11 @@ static void createWidgets(void) {
 	wi.customDraw = 0;
 	wi.customParam = 0;
 	wi.customStyle = 0;
-	wi.g.show = TRUE;
+	wi.g.show = FALSE;
 
 	// Apply the list parameters
-	wi.g.width = 300;
-	wi.g.height = 200;
+	wi.g.width = 100;
+	wi.g.height = 80;
 	wi.g.y = 10;
 	wi.g.x = 10;
 	wi.text = "List Name";
@@ -32,7 +32,7 @@ int main(void) {
 	// Set the widget defaults
 	gwinSetDefaultFont(gdispOpenFont("UI2"));
 	gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE);
-	gdispClear(White);
+	gdispClear(Red);
 
 	// Attach the mouse input
 	gwinAttachMouse(0);
@@ -45,13 +45,22 @@ int main(void) {
 	gwinAttachListener(&gl);
 
 	// Add some items to the list widget
-	gwinListAddItem(ghList1, "Item 0", TRUE);
-	gwinListAddItem(ghList1, "Item 1", TRUE);
-	gwinListAddItem(ghList1, "Item 2", TRUE);
-	gwinListAddItem(ghList1, "Item 3", TRUE);
-	gwinListAddItem(ghList1, "Item 4", TRUE);
-
-	gwinRedraw(ghList1);
+	gwinListAddItem(ghList1, "Item 0", FALSE);
+	gwinListAddItem(ghList1, "Item 1", FALSE);
+	gwinListAddItem(ghList1, "Item 2", FALSE);
+	gwinListAddItem(ghList1, "Item 3", FALSE);
+	gwinListAddItem(ghList1, "Item 4", FALSE);
+	gwinListAddItem(ghList1, "Item 5", FALSE);
+	gwinListAddItem(ghList1, "Item 6", FALSE);
+	gwinListAddItem(ghList1, "Item 7", FALSE);
+	gwinListAddItem(ghList1, "Item 8", FALSE);
+	gwinListAddItem(ghList1, "Item 9", FALSE);
+	gwinListAddItem(ghList1, "Item 10", FALSE);
+	gwinListAddItem(ghList1, "Item 11", FALSE);
+	gwinListAddItem(ghList1, "Item 12", FALSE);
+	gwinListAddItem(ghList1, "Item 13", FALSE);
+
+	gwinSetVisible(ghList1, TRUE);
 
 	while(1) {
 		// Get an Event
diff --git a/demos/modules/gwin/widgets/gfxconf.h b/demos/modules/gwin/widgets/gfxconf.h
index f8d8fe5f..10db7bbc 100644
--- a/demos/modules/gwin/widgets/gfxconf.h
+++ b/demos/modules/gwin/widgets/gfxconf.h
@@ -81,6 +81,7 @@
 #define GWIN_NEED_LABEL			TRUE
 #define GWIN_NEED_IMAGE			TRUE
 #define GWIN_NEED_RADIO			TRUE
+#define GWIN_NEED_LIST			TRUE
 #define GWIN_NEED_IMAGE_ANIMATION	TRUE
 
 
diff --git a/demos/modules/gwin/widgets/main.c b/demos/modules/gwin/widgets/main.c
index bff842f4..f2323b5c 100644
--- a/demos/modules/gwin/widgets/main.c
+++ b/demos/modules/gwin/widgets/main.c
@@ -69,13 +69,14 @@ static const GWidgetStyle YellowWidgetStyle = {
 /* The variables we need */
 static GListener	gl;
 static GHandle		ghConsole;
-static GHandle		ghTabButtons, ghTabSliders, ghTabCheckboxes, ghTabLabels, ghTabRadios, ghTabImages;
+static GHandle		ghTabButtons, ghTabSliders, ghTabCheckboxes, ghTabLabels, ghTabRadios, ghTabLists, ghTabImages;
 static GHandle		ghButton1, ghButton2, ghButton3, ghButton4;
 static GHandle		ghSlider1, ghSlider2, ghSlider3, ghSlider4;
 static GHandle		ghCheckbox1, ghCheckbox2, ghCheckDisableAll;
 static GHandle		ghLabel1;
 static GHandle		ghRadio1, ghRadio2;
 static GHandle		ghRadioBlack, ghRadioWhite, ghRadioYellow;
+static GHandle		ghList1;
 static GHandle		ghImage1;
 
 /* Some useful macros */
@@ -86,6 +87,8 @@ static GHandle		ghImage1;
 #define LABEL_HEIGHT		40
 #define BUTTON_WIDTH		50
 #define BUTTON_HEIGHT		30
+#define LIST_WIDTH			100
+#define LIST_HEIGHT			80
 #define SLIDER_WIDTH		20
 #define CHECKBOX_WIDTH		80
 #define CHECKBOX_HEIGHT		20
@@ -108,13 +111,14 @@ static void createWidgets(void) {
 
 	// Create the Tabs
 	wi.g.show = TRUE; wi.customDraw = gwinRadioDraw_Tab;
-	wi.g.width = ScrWidth/6; wi.g.height = TAB_HEIGHT; wi.g.y = 0;
+	wi.g.width = ScrWidth/7; wi.g.height = TAB_HEIGHT; wi.g.y = 0;
 	wi.g.x = 0*wi.g.width; wi.text = "Buttons";		ghTabButtons	= gwinRadioCreate(NULL, &wi, GROUP_TABS);
 	wi.g.x = 1*wi.g.width; wi.text = "Sliders";		ghTabSliders	= gwinRadioCreate(NULL, &wi, GROUP_TABS);
 	wi.g.x = 2*wi.g.width; wi.text = "Checkbox";	ghTabCheckboxes	= gwinRadioCreate(NULL, &wi, GROUP_TABS);
 	wi.g.x = 3*wi.g.width; wi.text = "Radios";		ghTabRadios		= gwinRadioCreate(NULL, &wi, GROUP_TABS);
-	wi.g.x = 4*wi.g.width; wi.text = "Labels";		ghTabLabels		= gwinRadioCreate(NULL, &wi, GROUP_TABS);
-	wi.g.x = 5*wi.g.width; wi.text = "Images";		ghTabImages		= gwinRadioCreate(NULL, &wi, GROUP_TABS);
+	wi.g.x = 4*wi.g.width; wi.text = "Lists";		ghTabLists		= gwinRadioCreate(NULL, &wi, GROUP_TABS);
+	wi.g.x = 5*wi.g.width; wi.text = "Labels";		ghTabLabels		= gwinRadioCreate(NULL, &wi, GROUP_TABS);
+	wi.g.x = 6*wi.g.width; wi.text = "Images";		ghTabImages		= gwinRadioCreate(NULL, &wi, GROUP_TABS);
 
 	// Buttons
 	wi.g.show = FALSE; wi.customDraw = 0;
@@ -156,6 +160,25 @@ static void createWidgets(void) {
 	wi.g.x = 2*wi.g.width; wi.text = "Yellow";	ghRadioYellow	= gwinRadioCreate(NULL, &wi, GROUP_COLORS);
 	gwinRadioPress(ghRadioWhite);
 
+	// Lists
+	wi.g.show = FALSE; wi.customDraw = 0;
+	wi.g.width = LIST_WIDTH; wi.g.height = LIST_HEIGHT; wi.g.y = TAB_HEIGHT+5;
+	wi.g.x = 0+0*(LIST_WIDTH+1); wi.text = "L1"; ghList1 = gwinListCreate(NULL, &wi);
+	gwinListAddItem(ghList1, "Item 0", FALSE);
+	gwinListAddItem(ghList1, "Item 1", FALSE);
+	gwinListAddItem(ghList1, "Item 2", FALSE);
+	gwinListAddItem(ghList1, "Item 3", FALSE);
+	gwinListAddItem(ghList1, "Item 4", FALSE);
+	gwinListAddItem(ghList1, "Item 5", FALSE);
+	gwinListAddItem(ghList1, "Item 6", FALSE);
+	gwinListAddItem(ghList1, "Item 7", FALSE);
+	gwinListAddItem(ghList1, "Item 8", FALSE);
+	gwinListAddItem(ghList1, "Item 9", FALSE);
+	gwinListAddItem(ghList1, "Item 10", FALSE);
+	gwinListAddItem(ghList1, "Item 11", FALSE);
+	gwinListAddItem(ghList1, "Item 12", FALSE);
+	gwinListAddItem(ghList1, "Item 13", FALSE);
+
 	// Image
 	wi.g.x = ScrWidth-210; wi.g.y = TAB_HEIGHT + 10; wi.g.width = 200; wi.g.height = 200;
 	ghImage1 = gwinImageCreate(NULL, &wi.g);
@@ -183,6 +206,7 @@ static void setTab(GHandle tab) {
 	gwinSetVisible(ghLabel1, FALSE);
 	gwinSetVisible(ghRadio1, FALSE);	gwinSetVisible(ghRadio2, FALSE);
 	gwinSetVisible(ghRadioWhite, FALSE);gwinSetVisible(ghRadioBlack, FALSE);gwinSetVisible(ghRadioYellow, FALSE);
+	gwinSetVisible(ghList1, FALSE);
 	gwinSetVisible(ghImage1, FALSE);
 
 	/* Turn on widgets depending on the tab selected */
@@ -199,6 +223,8 @@ static void setTab(GHandle tab) {
 	} else if (tab == ghTabRadios) {
 		gwinSetVisible(ghRadio1, TRUE);		gwinSetVisible(ghRadio2, TRUE);
 		gwinSetVisible(ghRadioWhite, TRUE);	gwinSetVisible(ghRadioBlack, TRUE);	gwinSetVisible(ghRadioYellow, TRUE);
+	} else if (tab == ghTabLists) {
+		gwinSetVisible(ghList1, TRUE);
 	} else if (tab == ghTabImages) {
 		gwinSetVisible(ghImage1, TRUE);
 	}
@@ -282,6 +308,10 @@ int main(void) {
 			}
 			break;
 
+		case GEVENT_GWIN_LIST:
+			gwinPrintf(ghConsole, "List %s Item %d\n", gwinGetText(((GEventGWinList *)pe)->list), ((GEventGWinList *)pe)->item);
+			break;
+
 		case GEVENT_GWIN_RADIO:
 			gwinPrintf(ghConsole, "Radio Group %u=%s\n", ((GEventGWinRadio *)pe)->group, gwinGetText(((GEventGWinRadio *)pe)->radio));
 
-- 
cgit v1.2.3


From 2d27673f0f45a1b96aa7b9d8de61807fadb020bc Mon Sep 17 00:00:00 2001
From: inmarket <andrewh@inmarket.com.au>
Date: Thu, 1 Aug 2013 14:51:40 +1000
Subject: Update GWIN widget demo

---
 demos/modules/gwin/widgets/gfxconf.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/demos/modules/gwin/widgets/gfxconf.h b/demos/modules/gwin/widgets/gfxconf.h
index 10db7bbc..9ca5580b 100644
--- a/demos/modules/gwin/widgets/gfxconf.h
+++ b/demos/modules/gwin/widgets/gfxconf.h
@@ -47,7 +47,7 @@
 #define GDISP_NEED_CIRCLE			TRUE
 #define GDISP_NEED_ELLIPSE			FALSE
 #define GDISP_NEED_ARC				FALSE
-#define GDISP_NEED_CONVEX_POLYGON	FALSE
+#define GDISP_NEED_CONVEX_POLYGON	TRUE
 #define GDISP_NEED_SCROLL			FALSE
 #define GDISP_NEED_PIXELREAD		FALSE
 #define GDISP_NEED_CONTROL			FALSE
-- 
cgit v1.2.3


From 9d2b0b667b9bfb2d8b6969ade0ff0bd8d646d7d7 Mon Sep 17 00:00:00 2001
From: inmarket <andrewh@inmarket.com.au>
Date: Thu, 1 Aug 2013 14:52:28 +1000
Subject: Add color blending to GDISP

---
 include/gdisp/gdisp.h | 13 +++++++++++++
 src/gdisp/gdisp.c     | 21 +++++++++++++++++++++
 2 files changed, 34 insertions(+)

diff --git a/include/gdisp/gdisp.h b/include/gdisp/gdisp.h
index ac741d3b..ca1844fd 100644
--- a/include/gdisp/gdisp.h
+++ b/include/gdisp/gdisp.h
@@ -800,6 +800,19 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color);
 	void gdispFillRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color);
 #endif
 
+
+/**
+ * @brief   Blend 2 colors according to the alpha
+ * @return	The combined color
+ *
+ * @param[in] fg		The foreground color
+ * @param[in] bg		The background color
+ * @param[in] alpha		The alpha value (0-255). 0 is all background, 255 is all foreground.
+ *
+ * @api
+ */
+color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha);
+
 /* Support routine for packed pixel formats */
 #if !defined(gdispPackPixels) || defined(__DOXYGEN__)
 	/**
diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c
index 4c005079..b59b571d 100644
--- a/src/gdisp/gdisp.c
+++ b/src/gdisp/gdisp.c
@@ -990,6 +990,27 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {
 	}
 #endif
 
+color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha)
+{
+	uint16_t fg_ratio = alpha + 1;
+	uint16_t bg_ratio = 256 - alpha;
+	uint16_t r, g, b;
+
+	r = RED_OF(fg) * fg_ratio;
+	g = GREEN_OF(fg) * fg_ratio;
+	b = BLUE_OF(fg) * fg_ratio;
+
+	r += RED_OF(bg) * bg_ratio;
+	g += GREEN_OF(bg) * bg_ratio;
+	b += BLUE_OF(bg) * bg_ratio;
+
+	r /= 256;
+	g /= 256;
+	b /= 256;
+
+	return RGB2COLOR(r, g, b);
+}
+
 #if (!defined(gdispPackPixels) && !defined(GDISP_PIXELFORMAT_CUSTOM))
 	void gdispPackPixels(pixel_t *buf, coord_t cx, coord_t x, coord_t y, color_t color) {
 		/* No mutex required as we only read static data */
-- 
cgit v1.2.3


From 58b52600138435073803de6844b4adb48b501307 Mon Sep 17 00:00:00 2001
From: inmarket <andrewh@inmarket.com.au>
Date: Thu, 1 Aug 2013 14:53:13 +1000
Subject: Update some GQUEUE prototypes

---
 include/gqueue/gqueue.h | 6 +++---
 src/gqueue/gqueue.c     | 6 +++---
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/include/gqueue/gqueue.h b/include/gqueue/gqueue.h
index 44a42247..b590846c 100644
--- a/include/gqueue/gqueue.h
+++ b/include/gqueue/gqueue.h
@@ -206,9 +206,9 @@ bool_t gfxQueueFSyncIsEmpty(gfxQueueFSync *pqueue);
  * @api
  * @{
  */
-bool_t gfxQueueASyncIsIn(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem);
-bool_t gfxQueueGSyncIsIn(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem);
-bool_t gfxQueueFSyncIsIn(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem);
+bool_t gfxQueueASyncIsIn(gfxQueueASync *pqueue, const gfxQueueASyncItem *pitem);
+bool_t gfxQueueGSyncIsIn(gfxQueueGSync *pqueue, const gfxQueueGSyncItem *pitem);
+bool_t gfxQueueFSyncIsIn(gfxQueueFSync *pqueue, const gfxQueueFSyncItem *pitem);
 /* @} */
 
 /**
diff --git a/src/gqueue/gqueue.c b/src/gqueue/gqueue.c
index f73c43df..7a4c0b7e 100644
--- a/src/gqueue/gqueue.c
+++ b/src/gqueue/gqueue.c
@@ -75,7 +75,7 @@
 	bool_t gfxQueueASyncIsEmpty(gfxQueueASync *pqueue) {
 		return pqueue->head == NULL;
 	}
-	bool_t gfxQueueASyncIsIn(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
+	bool_t gfxQueueASyncIsIn(gfxQueueASync *pqueue, const gfxQueueASyncItem *pitem) {
 		gfxQueueASyncItem *pi;
 
 		gfxSystemLock();
@@ -156,7 +156,7 @@
 	bool_t gfxQueueGSyncIsEmpty(gfxQueueGSync *pqueue) {
 		return pqueue->head == NULL;
 	}
-	bool_t gfxQueueGSyncIsIn(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
+	bool_t gfxQueueGSyncIsIn(gfxQueueGSync *pqueue, const gfxQueueGSyncItem *pitem) {
 		gfxQueueGSyncItem *pi;
 
 		gfxSystemLock();
@@ -248,7 +248,7 @@
 	bool_t gfxQueueFSyncIsEmpty(gfxQueueFSync *pqueue) {
 		return pqueue->head == NULL;
 	}
-	bool_t gfxQueueFSyncIsIn(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem) {
+	bool_t gfxQueueFSyncIsIn(gfxQueueFSync *pqueue, const gfxQueueFSyncItem *pitem) {
 		gfxQueueASyncItem *pi;
 
 		gfxSystemLock();
-- 
cgit v1.2.3


From b0b35396395c3eadc5a656df995a17b266c4b374 Mon Sep 17 00:00:00 2001
From: inmarket <andrewh@inmarket.com.au>
Date: Thu, 1 Aug 2013 14:54:25 +1000
Subject: Update GWIN list. Now supports item and page scrolling. A few bugs
 fixed.

---
 include/gwin/list.h |   3 +-
 src/gwin/list.c     | 422 +++++++++++++++++++++++++++-------------------------
 2 files changed, 218 insertions(+), 207 deletions(-)

diff --git a/include/gwin/list.h b/include/gwin/list.h
index d28206d9..99f5f532 100644
--- a/include/gwin/list.h
+++ b/include/gwin/list.h
@@ -52,6 +52,7 @@ typedef struct GListObject {
 	#endif
 
 	int				cnt;		// Number of items currently in the list (quicker than counting each time)
+	int				top;		// The element at the top of the visible list area
 	gfxQueueASync	list_head;	// The list of items
 } GListObject;
 
@@ -111,7 +112,7 @@ int gwinListAddItem(GHandle gh, const char* item, bool_t useAlloc);
  *
  * @api
  */
-char* gwinListItemGetText(GHandle gh, int item);
+const char* gwinListItemGetText(GHandle gh, int item);
 
 /**
  * @brief				Get the ID of an item with a given name
diff --git a/src/gwin/list.c b/src/gwin/list.c
index 2509260c..a938150f 100644
--- a/src/gwin/list.c
+++ b/src/gwin/list.c
@@ -23,11 +23,15 @@
 #include <string.h>
 
 // user for the default drawing routine
-#define BORDER			3	// the border from the the text to the frame
-#define BORDER_SCROLL	20	// the border from the scroll buttons to the frame
+#define SCROLLWIDTH		16	// the border from the scroll buttons to the frame
 #define ARROW			10	// arrow side length
+#define TEXTGAP			1	// extra vertical padding for text
 
-#define widget(gh)	((GListObject *)gh)
+#define gh2obj		((GListObject *)gh)
+#define gw2obj		((GListObject *)gw)
+#define qi2li		((ListItem *)qi)
+#define qix2li		((ListItem *)qix)
+#define ple			((GEventGWinList *)pe)
 
 #define GLIST_FLG_MULTISELECT		(GWIN_FIRST_CONTROL_FLAG << 0)
 #define GLIST_FLG_HASIMAGES			(GWIN_FIRST_CONTROL_FLAG << 1)
@@ -40,67 +44,13 @@ typedef struct ListItem {
 	uint16_t			param;		// A parameter the user can specify himself
 	const char*			text;
 	#if GWIN_LIST_IMAGES
-	gdispImage*			pimg;
+		gdispImage*		pimg;
 	#endif
 } ListItem;
 
-// select the next item in the list
-static int _selectDown(GWidgetObject *gw) {
-	#define gcw			((GListObject *)gw)
-
-	gfxQueueASyncItem	*qi;
-	uint16_t i;
-
-	for (i = 0, qi = gfxQueueASyncPeek(&gcw->list_head); qi; qi = gfxQueueASyncNext(qi), i++) {
-		if (((ListItem*)qi)->flags & GLIST_FLG_SELECTED && i < gcw->cnt - 1) {
-			((ListItem*)qi)->flags &=~ GLIST_FLG_SELECTED;
-			qi = gfxQueueASyncNext(qi);
-			((ListItem*)qi)->flags |= GLIST_FLG_SELECTED;	
-
-			break;
-		}
-	}
-
-	_gwidgetRedraw((GHandle)gw);
-
-	return ++i;
-
-	#undef gcw
-}
-
-// select the previous item in the list
-static int _selectUp(GWidgetObject *gw) {
-	#define gcw			((GListObject *)gw)
-
-	gfxQueueASyncItem *qi;
-	gfxQueueASyncItem *qi2;
-	uint16_t i;
-
-	qi = gfxQueueASyncPeek(&gcw->list_head);
-	qi2 = qi;
-
-	for (i = 0; qi2; qi2 = gfxQueueASyncNext(qi), i++) {
-		if (((ListItem*)qi2)->flags & GLIST_FLG_SELECTED) {
-			((ListItem*)qi2)->flags &=~ GLIST_FLG_SELECTED;
-			((ListItem*)qi)->flags |= GLIST_FLG_SELECTED;
-		
-			break;
-		}
-
-		qi = qi2;
-	}
-
-	_gwidgetRedraw((GHandle)gw);
-
-	return --i;
-
-	#undef gcw
-}
-
 static void sendListEvent(GWidgetObject *gw, int item) {
 	GSourceListener*	psl;
 	GEvent*				pe;
-	#define pse			((GEventGWinList *)pe)
 
 	// Trigger a GWIN list event
 	psl = 0;
@@ -109,128 +59,188 @@ static void sendListEvent(GWidgetObject *gw, int item) {
 		if (!(pe = geventGetEventBuffer(psl)))
 			continue;
 
-		pse->type = GEVENT_GWIN_LIST;
-		pse->list = (GHandle)gw;
-		pse->item = item;
+		ple->type = GEVENT_GWIN_LIST;
+		ple->list = (GHandle)gw;
+		ple->item = item;
 
 		geventSendEvent(psl);
 	}
-	
-	#undef pse	
 }
 
 static void gwinListDefaultDraw(GWidgetObject* gw, void* param) {
-	#define gcw			((GListObject *)gw)
 	(void)param;
 
-	uint16_t i, fheight;
-	const point upArrow[] = { {0, ARROW}, {ARROW, ARROW}, {ARROW/2, 0} };
-	const point downArrow[] = { {0, 0}, {ARROW, 0}, {ARROW/2, ARROW} };
-	const gfxQueueASyncItem* qi;
-
-	fheight = gdispGetFontMetric(gwinGetDefaultFont(), fontHeight);	
+	#if GDISP_NEED_CONVEX_POLYGON
+		static const point upArrow[] = { {0, ARROW}, {ARROW, ARROW}, {ARROW/2, 0} };
+		static const point downArrow[] = { {0, 0}, {ARROW, 0}, {ARROW/2, ARROW} };
+	#endif
 
-	// the list frame
-	gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->enabled.edge);
-	gdispDrawLine(gw->g.x + gw->g.width - BORDER_SCROLL, gw->g.y, gw->g.x + gw->g.width - BORDER_SCROLL, gw->g.y + gw->g.height, gw->pstyle->enabled.edge);
-	gdispDrawLine(gw->g.x + gw->g.width - BORDER_SCROLL, gw->g.y + BORDER_SCROLL, gw->g.x + gw->g.width, gw->g.y + BORDER_SCROLL, gw->pstyle->enabled.edge);
-	gdispDrawLine(gw->g.x + gw->g.width - BORDER_SCROLL, gw->g.y + gw->g.height - BORDER_SCROLL, gw->g.x + gw->g.width, gw->g.y + gw->g.height - BORDER_SCROLL, gw->pstyle->enabled.edge);
-
-	// the up-button
-	gdispFillConvexPoly(gw->g.x + gw->g.width - BORDER_SCROLL + ARROW/2, gw->g.y + BORDER_SCROLL - ARROW - ARROW/2, upArrow, 3, gw->pstyle->enabled.edge);
-	
-	// the down-button
-	gdispFillConvexPoly(gw->g.x + gw->g.width - BORDER_SCROLL + ARROW/2, gw->g.y + gw->g.height - BORDER_SCROLL + ARROW/2, downArrow, 3, gw->pstyle->enabled.edge);
-
-	for (qi = gfxQueueASyncPeek(&gcw->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i += fheight + 2*BORDER) {
-		if (((ListItem*)qi)->flags & GLIST_FLG_SELECTED) {
-			gdispFillStringBox(gw->g.x + BORDER, gw->g.y + BORDER + i, gw->g.width - 2*BORDER - BORDER_SCROLL, fheight, ((ListItem*)qi)->text, gwinGetDefaultFont(), gw->pstyle->background, gw->pstyle->enabled.text, justifyLeft);
+	const gfxQueueASyncItem*	qi;
+	int							i;
+	coord_t						y, iheight, iwidth;
+	const GColorSet *			ps;
+
+	ps = (gw->g.flags & GWIN_FLG_ENABLED) ? &gw->pstyle->enabled : &gw->pstyle->disabled;
+	iheight = gdispGetFontMetric(gwinGetDefaultFont(), fontHeight) + TEXTGAP;
+
+	// the scroll area
+	if (gw2obj->cnt > (gw->g.height-2) / iheight) {
+		iwidth = gw->g.width - (SCROLLWIDTH+3);
+		gdispFillArea(gw->g.x+iwidth+2, gw->g.y+1, SCROLLWIDTH, gw->g.height-2, gdispBlendColor(ps->fill, gw->pstyle->background, 128));
+		gdispDrawLine(gw->g.x+iwidth+1, gw->g.y+1, gw->g.x+iwidth+1, gw->g.y+gw->g.height-2, ps->edge);
+		#if GDISP_NEED_CONVEX_POLYGON
+			gdispFillConvexPoly(gw->g.x+iwidth+((SCROLLWIDTH-ARROW)/2+2), gw->g.y+(ARROW/2+1), upArrow, 3, ps->fill);
+			gdispFillConvexPoly(gw->g.x+iwidth+((SCROLLWIDTH-ARROW)/2+2), gw->g.y+gw->g.height-(ARROW+ARROW/2+1), downArrow, 3, ps->fill);
+		#else
+			#warning "GWIN: Lists display better when GDISP_NEED_CONVEX_POLGON is turned on"
+			gdispFillArea(gw->g.x+iwidth+((SCROLLWIDTH-ARROW)/2+2), gw->g.y+(ARROW/2+1), ARROW, ARROW, ps->fill);
+			gdispFillArea(gw->g.x+iwidth+((SCROLLWIDTH-ARROW)/2+2), gw->g.y+gw->g.height-(ARROW+ARROW/2+1), ARROW, ARROW, ps->fill);
+		#endif
+	} else
+		iwidth = gw->g.width - 2;
+
+
+	// Find the top item
+	for (qi = gfxQueueASyncPeek(&gw2obj->list_head), i = 0; i < gw2obj->top && qi; qi = gfxQueueASyncNext(qi), i++);
+
+	// Draw until we run out of room or items
+	for (y=1; y+iheight < gw->g.height-1 && qi; qi = gfxQueueASyncNext(qi), y += iheight) {
+		if (qi2li->flags & GLIST_FLG_SELECTED) {
+			//gdispFillStringBox(gw->g.x+1, gw->g.y+y, iwidth, iheight, qi2li->text, gwinGetDefaultFont(), gw->pstyle->background, ps->text, justifyLeft);
+			gdispFillStringBox(gw->g.x+1, gw->g.y+y, iwidth, iheight, qi2li->text, gwinGetDefaultFont(), ps->text, ps->fill, justifyLeft);
 		} else {
-			gdispFillStringBox(gw->g.x + BORDER, gw->g.y + BORDER + i, gw->g.width - 2*BORDER - BORDER_SCROLL, fheight, ((ListItem*)qi)->text, gwinGetDefaultFont(), gw->pstyle->enabled.text, gw->pstyle->background, justifyLeft);
+			gdispFillStringBox(gw->g.x+1, gw->g.y+y, iwidth, iheight, qi2li->text, gwinGetDefaultFont(), ps->text, gw->pstyle->background, justifyLeft);
 		}
 	}
 
-	#undef gcw
+	// Fill any remaining item space
+	if (y < gw->g.height-1)
+		gdispFillArea(gw->g.x+1, gw->g.y+y, iwidth, gw->g.height-1-y, gw->pstyle->background);
+
+	// the list frame
+	gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, ps->edge);
 }
 
 #if GINPUT_NEED_MOUSE
-	// a mouse down has occured over the list area
+	// a mouse down has occurred over the list area
 	static void MouseDown(GWidgetObject* gw, coord_t x, coord_t y) {
-		#define gcw			((GListObject *)gw)
-		#define li			((ListItem *)qi)
-		(void)				x;
-
-		uint16_t i, item_id, item_height;
-		const gfxQueueASyncItem* qi;
-
-		item_id = -1;
-
-		if (x > gw->g.width - BORDER_SCROLL) {
-			if (y < BORDER_SCROLL)
-				item_id = _selectUp(gw);
-			else if (y > gw->g.height - BORDER_SCROLL)
-				item_id = _selectDown(gw);
-		} else if (x < gw->g.width - BORDER_SCROLL - BORDER) {
-			item_height = gdispGetFontMetric(gwinGetDefaultFont(), fontHeight) + 2*BORDER;
-			item_id = (y) / item_height;
-
-			for(qi = gfxQueueASyncPeek(&gcw->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
-				if (item_id == i)
-					li->flags |= GLIST_FLG_SELECTED;
-				else
-					li->flags &=~ GLIST_FLG_SELECTED;
+		const gfxQueueASyncItem*	qi;
+		int							item, i, pgsz;
+		coord_t						iheight;
+		(void)						x;
+
+		iheight = gdispGetFontMetric(gwinGetDefaultFont(), fontHeight) + TEXTGAP;
+		pgsz = (gw->g.height-2)/iheight;
+		if (pgsz < 1) pgsz = 1;
+
+		// Handle click over the scroll bar
+		if (gw2obj->cnt > pgsz && x >= gw->g.width-(SCROLLWIDTH+2)) {
+			if (y < 2*ARROW) {
+				if (gw2obj->top > 0) {
+					gw2obj->top--;
+					_gwidgetRedraw(&gw->g);
+				}
+			} else if (y >= gw->g.height - 2*ARROW) {
+				if (gw2obj->top < gw2obj->cnt - pgsz) {
+					gw2obj->top++;
+					_gwidgetRedraw(&gw->g);
+				}
+			} else if (y < gw->g.height/2) {
+				if (gw2obj->top > 0) {
+					if (gw2obj->top > pgsz)
+						gw2obj->top -= pgsz;
+					else
+						gw2obj->top = 0;
+					_gwidgetRedraw(&gw->g);
+				}
+			} else {
+				if (gw2obj->top < gw2obj->cnt - pgsz) {
+					if (gw2obj->top < gw2obj->cnt - 2*pgsz)
+						gw2obj->top += pgsz;
+					else
+						gw2obj->top = gw2obj->cnt - pgsz;
+					_gwidgetRedraw(&gw->g);
+				}
 			}
+			return;
 		}
 
-		_gwidgetRedraw((GHandle)gw);
+		// Handle click over the list area
+		item = gw2obj->top + y / iheight;
 
-		// do not generate an event if an empty section of the list has has been selected
-		if (item_id < 0 || item_id > gcw->cnt - 1)
+		if (item < 0 || item >= gw2obj->cnt)
 			return;
 
-		sendListEvent(gw, item_id);
+		for(qi = gfxQueueASyncPeek(&gw2obj->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
+			if (item == i)
+				qi2li->flags |= GLIST_FLG_SELECTED;
+			else
+				qi2li->flags &=~ GLIST_FLG_SELECTED;
+		}
 
-		#undef gcw
-		#undef li
+		_gwidgetRedraw(&gw->g);
+		sendListEvent(gw, item);
 	}
 #endif
 
 #if GINPUT_NEED_TOGGLE
 	// a toggle-on has occurred
 	static void ToggleOn(GWidgetObject *gw, uint16_t role) {
-		#define gcw			((GListObject *)gw)
+		const gfxQueueASyncItem	*	qi;
+		const gfxQueueASyncItem	*	qix;
+		int							i;
 
 		switch (role) {
 			// select down
 			case 0:
-				_selectDown(gw);
+				for (i = 0, qi = gfxQueueASyncPeek(&gw2obj->list_head); qi; qi = gfxQueueASyncNext(qi), i++) {
+					if ((qi2li->flags & GLIST_FLG_SELECTED)) {
+						qix = gfxQueueASyncNext(qi);
+						if (qix) {
+							qi2li->flags &=~ GLIST_FLG_SELECTED;
+							qix2li->flags |= GLIST_FLG_SELECTED;
+							_gwidgetRedraw(&gw->g);
+						}
+						break;
+					}
+				}
 				break;
 
 			// select up
 			case 1:
-				_selectUp(gw);
+				qi = gfxQueueASyncPeek(&gw2obj->list_head);
+				qix = 0;
+
+				for (i = 0; qi; qix = qi, qi = gfxQueueASyncNext(qi), i++) {
+					if ((qi2li->flags & GLIST_FLG_SELECTED))
+						if (qix) {
+							qi2li->flags &=~ GLIST_FLG_SELECTED;
+							qix2li->flags |= GLIST_FLG_SELECTED;
+							_gwidgetRedraw(&gw->g);
+						}
+						break;
+					}
+				}
 				break;
 		}
-
-		#undef gcw
 	}
 
 	static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) {
 		if (role)
-			((GListObject *)gw)->t_up = instance;
+			gw2obj->t_up = instance;
 		else
-			((GListObject *)gw)->t_dn = instance;
+			gw2obj->t_dn = instance;
 	}
 
 	static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role) {
-		return role ? ((GListObject *)gw)->t_up : ((GListObject *)gw)->t_dn;
+		return role ? gw2obj->t_up : gw2obj->t_dn;
 	}
 #endif
 
 static void _destroy(GHandle gh) {
 	const gfxQueueASyncItem* qi;
 
-	while((qi = gfxQueueASyncGet(&((GListObject *)gh)->list_head)))
+	while((qi = gfxQueueASyncGet(&gh2obj->list_head)))
 		gfxFree((void *)qi);
 
 	_gwidgetDestroy(gh);
@@ -271,31 +281,32 @@ static const gwidgetVMT listVMT = {
 	#endif
 };
 
-GHandle gwinListCreate(GListObject* widget, GWidgetInit* pInit) {
-	if (!(widget = (GListObject *)_gwidgetCreate(&widget->w, pInit, &listVMT)))
+GHandle gwinListCreate(GListObject* gobj, GWidgetInit* pInit) {
+	if (!(gobj = (GListObject *)_gwidgetCreate(&gobj->w, pInit, &listVMT)))
 		return 0;
 
 	// initialize the item queue
-	gfxQueueASyncInit(&(widget->list_head));
-	widget->cnt = 0;
+	gfxQueueASyncInit(&gobj->list_head);
+	gobj->cnt = 0;
+	gobj->top = 0;
 
-	gwinSetVisible(&widget->w.g, pInit->g.show);
+	gwinSetVisible(&gobj->w.g, pInit->g.show);
 
-	return (GHandle)widget;
+	return (GHandle)gobj;
 }
 
 int gwinListAddItem(GHandle gh, const char* item_name, bool_t useAlloc) {
-	size_t		sz;
 	ListItem	*newItem;
 
-	sz = useAlloc ? sizeof(ListItem)+strlen(item_name)+1 : sizeof(ListItem);
-
-	if (!(newItem = (ListItem *)gfxAlloc(sz)))
-		return -1;
-
 	if (useAlloc) {
+		if (!(newItem = (ListItem *)gfxAlloc(sizeof(ListItem)+strlen(item_name)+1)))
+			return -1;
+
 		strcpy((char *)(newItem+1), item_name);
 		item_name = (const char *)(newItem+1);
+	} else {
+		if (!(newItem = (ListItem *)gfxAlloc(sizeof(ListItem))))
+			return -1;
 	}
 
 	// the item is not selected when added
@@ -304,43 +315,43 @@ int gwinListAddItem(GHandle gh, const char* item_name, bool_t useAlloc) {
 	newItem->text = item_name;
 
 	// select the item if it's the first in the list
-	if (widget(gh)->cnt == 0)
+	if (gh2obj->cnt == 0)
 		newItem->flags |= GLIST_FLG_SELECTED;
 
 	// add the new item to the list
-	gfxQueueASyncPut(&widget(gh)->list_head, &newItem->q_item);
+	gfxQueueASyncPut(&gh2obj->list_head, &newItem->q_item);
 
 	// increment the total amount of entries in the list widget
-	widget(gh)->cnt++;
+	gh2obj->cnt++;
+
+	_gwidgetRedraw(gh);
 
 	// return the position in the list (-1 because we start with index 0)
-	return widget(gh)->cnt-1;
+	return gh2obj->cnt-1;
 }
 
-char* gwinListItemGetText(GHandle gh, int item) {
-	const gfxQueueASyncItem* qi;
-	uint16_t i;
+const char* gwinListItemGetText(GHandle gh, int item) {
+	const gfxQueueASyncItem*	qi;
+	int							i;
 
 	// is it a valid handle?
 	if (gh->vmt != (gwinVMT *)&listVMT)
 		return 0;
 
 	// watch out for an invalid item
-	if (item < 0 || item > (widget(gh)->cnt) - 1)
+	if (item < 0 || item >= gh2obj->cnt)
 		return 0;
 
-	qi = gfxQueueASyncPeek(&widget(gh)->list_head);
-	
-	for (i = 0; i < item; i++) {
-		qi = gfxQueueASyncNext(qi);
+	for(qi = gfxQueueASyncPeek(&gh2obj->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
+		if (i == item)
+			return qi2li->text;
 	}
-
-	return ((ListItem*)qi)->text;
+	return 0;
 }
 
 int gwinListFindText(GHandle gh, const char* text) {
-	const gfxQueueASyncItem* qi;
-	uint16_t i;
+	const gfxQueueASyncItem*	qi;
+	int							i;
 
 	// is it a valid handle?
 	if (gh->vmt != (gwinVMT *)&listVMT)
@@ -350,9 +361,7 @@ int gwinListFindText(GHandle gh, const char* text) {
 	if (!text)
 		return -1;
 
-	qi = gfxQueueASyncPeek(&widget(gh)->list_head);
-	
-	for(qi = gfxQueueASyncPeek(&widget(gh)->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
+	for(qi = gfxQueueASyncPeek(&gh2obj->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
 		if (strcmp(((ListItem *)qi)->text, text) == 0)
 			return i;	
 	}
@@ -361,15 +370,15 @@ int gwinListFindText(GHandle gh, const char* text) {
 }
 
 int gwinListGetSelected(GHandle gh) {
-	const gfxQueueASyncItem	*qi;
-	int i;
+	const gfxQueueASyncItem	*	qi;
+	int							i;
 
 	// is it a valid handle?
 	if (gh->vmt != (gwinVMT *)&listVMT)
 		return -1;
 
-	for(qi = gfxQueueASyncPeek(&widget(gh)->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
-		if (((ListItem*)qi)->flags & GLIST_FLG_SELECTED)
+	for(qi = gfxQueueASyncPeek(&gh2obj->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
+		if (qi2li->flags & GLIST_FLG_SELECTED)
 			return i;
 	}
 
@@ -377,99 +386,100 @@ int gwinListGetSelected(GHandle gh) {
 }
 
 void gwinListItemSetParam(GHandle gh, int item, uint16_t param) {
-	const gfxQueueASyncItem* qi;
-	uint16_t i;
+	const gfxQueueASyncItem	*	qi;
+	int							i;
 
 	// is it a valid handle?
 	if (gh->vmt != (gwinVMT *)&listVMT)
 		return;
 
 	// watch out for an invalid item
-	if (item < 0 || item > (widget(gh)->cnt) - 1)
+	if (item < 0 || item > (gh2obj->cnt) - 1)
 		return;
 
-	qi = gfxQueueASyncPeek(&widget(gh)->list_head);
-	
-	for (i = 0; i < item; i++) {
-		((ListItem*)qi)->param = param;
+	for(qi = gfxQueueASyncPeek(&gh2obj->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
+		if (i == item) {
+			qi2li->param = param;
+			break;
+		}
 	}
-
-	return;	
 }
 
 void gwinListDeleteAll(GHandle gh) {
-	const gfxQueueASyncItem* qi;
+	gfxQueueASyncItem* qi;
 
-	while((qi = gfxQueueASyncGet(&((GListObject *)gh)->list_head)))
-		gfxFree((void *)qi);
+	// is it a valid handle?
+	if (gh->vmt != (gwinVMT *)&listVMT)
+		return;
+
+	while((qi = gfxQueueASyncGet(&gh2obj->list_head)))
+		gfxFree(qi);
+
+	gh2obj->cnt = 0;
+	gh2obj->top = 0;
+	_gwidgetRedraw(gh);
 }
 
 void gwinListItemDelete(GHandle gh, int item) {
-	const gfxQueueASyncItem* qi;
-	uint16_t i;
+	const gfxQueueASyncItem	*	qi;
+	int							i;
 
 	// is it a valid handle?
 	if (gh->vmt != (gwinVMT *)&listVMT)
 		return;
 
 	// watch out for an invalid item
-	if (item < 0 || item > (widget(gh)->cnt) - 1)
+	if (item < 0 || item >= gh2obj->cnt)
 		return;
 
-	qi = gfxQueueASyncPeek(&widget(gh)->list_head);
-
-	// get our item pointer	
-	for (i = 0; i < item; i++) {
-		qi = gfxQueueASyncNext(qi);
+	for(qi = gfxQueueASyncPeek(&gh2obj->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
+		if (i == item) {
+			gfxQueueASyncRemove(&gh2obj->list_head, (gfxQueueASyncItem*)qi);
+			gfxFree((void *)qi);
+			if (gh2obj->top >= item && gh2obj->top)
+				gh2obj->top--;
+			_gwidgetRedraw(gh);
+			break;
+		}
 	}
-
-	gfxQueueASyncRemove(&widget(gh)->list_head, qi);
-	gfxFree((void*)qi);
 }
 
 uint16_t gwinListItemGetParam(GHandle gh, int item) {
-	const gfxQueueASyncItem* qi;
-	uint16_t i;
+	const gfxQueueASyncItem	*	qi;
+	int							i;
 
 	// is it a valid handle?
 	if (gh->vmt != (gwinVMT *)&listVMT)
 		return 0;
 
 	// watch out for an invalid item
-	if (item < 0 || item > (widget(gh)->cnt) - 1)
+	if (item < 0 || item > (gh2obj->cnt) - 1)
 		return 0;
 
-	qi = gfxQueueASyncPeek(&widget(gh)->list_head);
-	
-	for (i = 0; i < item; i++) {
-		qi = gfxQueueASyncNext(qi);
+	for(qi = gfxQueueASyncPeek(&gh2obj->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
+		if (i == item)
+			return qi2li->param;
 	}
-
-	return ((ListItem*)qi)->param;
+	return 0;
 }
 
 bool_t gwinListItemIsSelected(GHandle gh, int item) {
-	const gfxQueueASyncItem* qi;
-	uint16_t i;
+	const gfxQueueASyncItem	*	qi;
+	int							i;
 
 	// is it a valid handle?
 	if (gh->vmt != (gwinVMT *)&listVMT)
 		return FALSE;
 
 	// watch out for an invalid item
-	if (item < 0 || item > (widget(gh)->cnt) - 1)
+	if (item < 0 || item > (gh2obj->cnt) - 1)
 		return FALSE;
 
-	qi = gfxQueueASyncPeek(&widget(gh)->list_head);
-	
-	for (i = 0; i < item; i++) {
-		qi = gfxQueueASyncNext(qi);
+	for(qi = gfxQueueASyncPeek(&gh2obj->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) {
+		if (i == item)
+			return (qi2li->flags &  GLIST_FLG_SELECTED) ? TRUE : FALSE;
 	}
-
-	if (((ListItem*)qi)->flags &  GLIST_FLG_SELECTED)
-		return TRUE;
-	else
-		return FALSE;
+	return FALSE;
 }
 
 int gwinListItemCount(GHandle gh) {
@@ -477,7 +487,7 @@ int gwinListItemCount(GHandle gh) {
 	if (gh->vmt != (gwinVMT *)&listVMT)
 		return 0;
 
-	return widget(gh)->cnt;
+	return gh2obj->cnt;
 }
 
 #endif // GFX_USE_GWIN && GWIN_NEED_LIST
-- 
cgit v1.2.3