diff options
-rw-r--r-- | demos/modules/gwin/list/gfxconf.h | 150 | ||||
-rw-r--r-- | demos/modules/gwin/list/main.c | 63 | ||||
-rw-r--r-- | include/gwin/list.h | 153 | ||||
-rw-r--r-- | src/gwin/list.c | 425 |
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 /** @} */ |