aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demos/modules/gwin/list/gfxconf.h150
-rw-r--r--demos/modules/gwin/list/main.c63
-rw-r--r--include/gwin/list.h153
-rw-r--r--src/gwin/list.c425
4 files changed, 782 insertions, 9 deletions
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/include/gwin/list.h b/include/gwin/list.h
index 0b525b03..d28206d9 100644
--- a/include/gwin/list.h
+++ b/include/gwin/list.h
@@ -37,21 +37,170 @@
* @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;
+
+ #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;
#ifdef __cplusplus
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. 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.
+ *
+ * @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);
+
+/**
+ * @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
}
#endif
diff --git a/src/gwin/list.c b/src/gwin/list.c
index eae9bb46..2509260c 100644
--- a/src/gwin/list.c
+++ b/src/gwin/list.c
@@ -20,34 +20,245 @@
#if GFX_USE_GWIN && GWIN_NEED_LIST
#include "gwin/class_gwin.h"
+#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 ARROW 10 // arrow side length
+
+#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)
+
+typedef struct ListItem {
+ gfxQueueASyncItem q_item; // This must be the first member in the struct
+
+ uint16_t flags;
+ uint16_t param; // A parameter the user can specify himself
+ const char* text;
+ #if GWIN_LIST_IMAGES
+ 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;
+
+ while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) {
+ if (!(pe = geventGetEventBuffer(psl)))
+ continue;
+
+ pse->type = GEVENT_GWIN_LIST;
+ pse->list = (GHandle)gw;
+ pse->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);
+ // 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);
+ } 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);
+ }
+ }
+
+ #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)
+ #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;
+ }
+ }
+
+ _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
+ #undef li
+ }
+#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 down
+ case 0:
+ _selectDown(gw);
+ break;
+
+ // select up
+ case 1:
+ _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) {
+ 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
},
gwinListDefaultDraw, // default drawing routine
- #if GWINPUT_NEED_MOUSE
+ #if GINPUT_NEED_MOUSE
{
- 0,
+ MouseDown,
0,
0,
},
#endif
#if GINPUT_NEED_TOGGLE
{
+ 2, // two toggle roles
+ ToggleAssign, // Assign toggles
+ ToggleGet, // get toggles
0,
- 0,
- 0,
- 0,
- 0,
+ ToggleOn, // process toggle on event
},
#endif
#if GINPUT_NEED_DIAL
@@ -64,11 +275,211 @@ 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) {
+ size_t sz;
+ ListItem *newItem;
+
+ sz = useAlloc ? sizeof(ListItem)+strlen(item_name)+1 : sizeof(ListItem);
+
+ if (!(newItem = (ListItem *)gfxAlloc(sz)))
+ 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 = 0;
+ 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);
+
+ // 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) {
+ const 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) {
+ const 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;
+ 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)
+ return i;
+ }
+
+ return -1;
+}
+
+void gwinListItemSetParam(GHandle gh, int item, uint16_t param) {
+ const 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) {
+ const gfxQueueASyncItem* qi;
+
+ while((qi = gfxQueueASyncGet(&((GListObject *)gh)->list_head)))
+ gfxFree((void *)qi);
+}
+
+void gwinListItemDelete(GHandle gh, int item) {
+ const 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) {
+ const 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) {
+ const 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
/** @} */