/* * This file is subject to the terms of the GFX License. If a copy of * the license was not distributed with this file, you can obtain one at: * * http://ugfx.org/license.html */ /** * @file src/gwin/gwin_list.c * @brief GWIN list widget header file */ #include "../../gfx.h" #if GFX_USE_GWIN && GWIN_NEED_LIST #include "gwin_class.h" #include #include // user for the default drawing routine #define LST_SCROLLWIDTH 16 // the border from the scroll buttons to the frame #define LST_ARROW_SZ 10 // arrow side length #define LST_HORIZ_PAD 5 // extra horizontal padding for text #define LST_VERT_PAD 2 // extra vertical padding for text // Macro's to assist in data type conversions #define gh2obj ((GListObject *)gh) #define gw2obj ((GListObject *)gw) #define qi2li ((ListItem *)qi) #define qix2li ((ListItem *)qix) #define ple ((GEventGWinList *)pe) static void sendListEvent(GWidgetObject *gw, int item) { GSourceListener* psl; GEvent* pe; // Trigger a GWIN list event psl = 0; while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) { if (!(pe = geventGetEventBuffer(psl))) continue; ple->type = GEVENT_GWIN_LIST; ple->gwin = (GHandle)gw; ple->item = item; #if GWIN_WIDGET_TAGS ple->tag = gw->tag; #endif geventSendEvent(psl); } } #if GINPUT_NEED_MOUSE static void ListMouseSelect(GWidgetObject* gw, gCoord x, gCoord y) { const gfxQueueASyncItem* qi; int item, i; gCoord iheight; (void) x; iheight = gdispGetFontMetric(gw->g.font, fontHeight) + LST_VERT_PAD; // Handle click over the list area item = (gw2obj->top + y) / iheight; if (item < 0 || item >= gw2obj->cnt) return; for(qi = gfxQueueASyncPeek(&gw2obj->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) { if ((gw->g.flags & GLIST_FLG_MULTISELECT)) { if (item == i) { qi2li->flags ^= GLIST_FLG_SELECTED; break; } } else { if (item == i) qi2li->flags |= GLIST_FLG_SELECTED; else qi2li->flags &=~ GLIST_FLG_SELECTED; } } _gwinUpdate(&gw->g); sendListEvent(gw, item); } // a mouse down has occurred over the list area static void ListMouseDown(GWidgetObject* gw, gCoord x, gCoord y) { gCoord iheight, pgsz; // Save our mouse start position gw2obj->start_mouse_x = x; gw2obj->start_mouse_y = y; gw2obj->last_mouse_y = y; // For smooth scrolling, scrolling is done in the ListMouseMove and selection is done on ListMouseUp if (gw->g.flags & GLIST_FLG_SCROLLSMOOTH) return; // Some initial stuff iheight = gdispGetFontMetric(gw->g.font, fontHeight) + LST_VERT_PAD; pgsz = gw->g.height-2; // Handle click over the scroll bar if (x >= gw->g.width-(LST_SCROLLWIDTH+2) && (gw2obj->cnt > pgsz/iheight || (gw->g.flags & GLIST_FLG_SCROLLALWAYS))) { if (y < 2*LST_ARROW_SZ) { if (gw2obj->top > 0) { gw2obj->top -= iheight; if (gw2obj->top < 0) gw2obj->top = 0; _gwinUpdate(&gw->g); } } else if (y >= gw->g.height - 2*LST_ARROW_SZ) { if (gw2obj->top < gw2obj->cnt * iheight - pgsz) { gw2obj->top += iheight; if (gw2obj->top > gw2obj->cnt * iheight - pgsz) gw2obj->top = gw2obj->cnt * iheight - pgsz; _gwinUpdate(&gw->g); } } else if (y < gw->g.height/2) { if (gw2obj->top > 0) { if (gw2obj->top > pgsz) gw2obj->top -= pgsz; else gw2obj->top = 0; _gwinUpdate(&gw->g); } } else { if (gw2obj->top < gw2obj->cnt * iheight - pgsz) { if (gw2obj->top < gw2obj->cnt * iheight - 2*pgsz) gw2obj->top += pgsz; else gw2obj->top = gw2obj->cnt * iheight - pgsz; _gwinUpdate(&gw->g); } } return; } ListMouseSelect(gw, x, y); } static void ListMouseUp(GWidgetObject* gw, gCoord x, gCoord y) { // Only act when we are a smooth scrolling list if (!(gw->g.flags & GLIST_FLG_SCROLLSMOOTH)) return; // Only allow selection when we did not scroll if (abs(gw2obj->start_mouse_x - x) > 4 || abs(gw2obj->start_mouse_y - y) > 4) return; ListMouseSelect(gw, x, y); } static void ListMouseMove(GWidgetObject* gw, gCoord x, gCoord y) { int iheight, oldtop; (void) x; if (!(gw->g.flags & GLIST_FLG_SCROLLSMOOTH)) return; if (gw2obj->last_mouse_y != y) { oldtop = gw2obj->top; iheight = gdispGetFontMetric(gw->g.font, fontHeight) + LST_VERT_PAD; gw2obj->top -= y - gw2obj->last_mouse_y; if (gw2obj->top >= gw2obj->cnt * iheight - (gw->g.height-2)) gw2obj->top = gw2obj->cnt * iheight - (gw->g.height-2) - 1; if (gw2obj->top < 0) gw2obj->top = 0; gw2obj->last_mouse_y = y; if (oldtop != gw2obj->top) _gwinUpdate(&gw->g); } } #endif #if GINPUT_NEED_TOGGLE // a toggle-on has occurred static void ListToggleOn(GWidgetObject *gw, uint16_t role) { const gfxQueueASyncItem * qi; const gfxQueueASyncItem * qix; int i; gCoord iheight; iheight = gdispGetFontMetric(gw->g.font, fontHeight) + LST_VERT_PAD; switch (role) { // select down case 0: 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; //if we need to scroll down if (((i+2)*iheight - gw2obj->top) > gw->g.height){ gw2obj->top += iheight; } _gwinUpdate(&gw->g); } break; } } break; // select up case 1: 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; //if we need to scroll up if (((i-1)*iheight) < gw2obj->top){ gw2obj->top -= iheight; if (gw2obj->top < 0) gw2obj->top = 0; } _gwinUpdate(&gw->g); } break; } } break; } } static void ListToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) { if (role) gw2obj->t_up = instance; else gw2obj->t_dn = instance; } static uint16_t ListToggleGet(GWidgetObject *gw, uint16_t role) { return role ? gw2obj->t_up : gw2obj->t_dn; } #endif static void ListDestroy(GHandle gh) { const gfxQueueASyncItem* qi; while((qi = gfxQueueASyncGet(&gh2obj->list_head))) gfxFree((void *)qi); _gwidgetDestroy(gh); } static const gwidgetVMT listVMT = { { "List", // The class name sizeof(GListObject), // The object size ListDestroy, // The destroy routine _gwidgetRedraw, // The redraw routine 0, // The after-clear routine }, gwinListDefaultDraw, // default drawing routine #if GINPUT_NEED_MOUSE { ListMouseDown, ListMouseUp, ListMouseMove, }, #endif #if GINPUT_NEED_KEYBOARD || GWIN_NEED_KEYBOARD { 0 // Process keyboard events }, #endif #if GINPUT_NEED_TOGGLE { 2, // two toggle roles ListToggleAssign, // Assign toggles ListToggleGet, // Get toggles 0, ListToggleOn, // Process toggle on event }, #endif #if GINPUT_NEED_DIAL { 0, 0, 0, 0, }, #endif }; GHandle gwinGListCreate(GDisplay *g, GListObject* gobj, GWidgetInit* pInit, gBool multiselect) { if (!(gobj = (GListObject *)_gwidgetCreate(g, &gobj->w, pInit, &listVMT))) return 0; // initialize the item queue gfxQueueASyncInit(&gobj->list_head); gobj->cnt = 0; gobj->top = 0; if (multiselect) gobj->w.g.flags |= GLIST_FLG_MULTISELECT; gobj->w.g.flags |= GLIST_FLG_SCROLLALWAYS; gobj->w.g.flags |= GLIST_FLG_ENABLERENDER; gwinSetVisible(&gobj->w.g, pInit->g.show); return (GHandle)gobj; } void gwinListEnableRender(GHandle gh, gBool ena) { // is it a valid handle? if (gh->vmt != (gwinVMT *)&listVMT) return; if (ena) { gh->flags |= GLIST_FLG_ENABLERENDER; gwinRedraw(gh); } else { gh->flags &=~ GLIST_FLG_ENABLERENDER; } } void gwinListSetScroll(GHandle gh, scroll_t flag) { // is it a valid handle? if (gh->vmt != (gwinVMT *)&listVMT) return; ((GListObject*)gh)->w.g.flags &=~(GLIST_FLG_SCROLLSMOOTH | GLIST_FLG_SCROLLALWAYS); switch (flag) { case scrollAlways: ((GListObject*)gh)->w.g.flags |= GLIST_FLG_SCROLLALWAYS; break; case scrollAuto: break; case scrollSmooth: ((GListObject*)gh)->w.g.flags |= GLIST_FLG_SCROLLSMOOTH; break; } } int gwinListAddItem(GHandle gh, const char* text, gBool useAlloc) { ListItem *newItem; // is it a valid handle? if (gh->vmt != (gwinVMT *)&listVMT) return -1; if (useAlloc) { size_t len = strlen(text)+1; if (!(newItem = gfxAlloc(sizeof(ListItem) + len))) return -1; memcpy((char *)(newItem+1), text, len); text = (const char *)(newItem+1); } else { if (!(newItem = gfxAlloc(sizeof(ListItem)))) return -1; } // the item is not selected when added newItem->flags = 0; newItem->param = 0; newItem->text = text; #if GWIN_NEED_LIST_IMAGES newItem->pimg = 0; #endif // select the item if it's the first in the list if (gh2obj->cnt == 0 && !(gh->flags & GLIST_FLG_MULTISELECT)) newItem->flags |= GLIST_FLG_SELECTED; // add the new item to the list gfxQueueASyncPut(&gh2obj->list_head, &newItem->q_item); // increment the total amount of entries in the list widget gh2obj->cnt++; _gwinUpdate(gh); // return the position in the list (-1 because we start with index 0) return gh2obj->cnt-1; } void gwinListItemSetText(GHandle gh, int item, const char* text, gBool useAlloc) { const gfxQueueASyncItem *qi; int i; ListItem *newItem; // is it a valid handle? if (gh->vmt != (gwinVMT *)&listVMT) return; // watch out for an invalid item if (item < 0 || item > (gh2obj->cnt) - 1) return; for(qi = gfxQueueASyncPeek(&gh2obj->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) { if (i == item) { // create the new object if (useAlloc) { size_t len = strlen(text)+1; if (!(newItem = gfxAlloc(sizeof(ListItem) + len))) return; memcpy((char *)(newItem+1), text, len); text = (const char *)(newItem+1); } else { if (!(newItem = gfxAlloc(sizeof(ListItem)))) return; } // copy the info from the existing object newItem->flags = qi2li->flags; newItem->param = qi2li->param; newItem->text = text; #if GWIN_NEED_LIST_IMAGES newItem->pimg = qi2li->pimg; #endif // add the new item to the list and remove the old item gfxQueueASyncInsert(&gh2obj->list_head, &newItem->q_item, &qi2li->q_item); gfxQueueASyncRemove(&gh2obj->list_head, &qi2li->q_item); gfxFree(qi2li); _gwinUpdate(gh); break; } } } 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 >= gh2obj->cnt) return 0; for(qi = gfxQueueASyncPeek(&gh2obj->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) { if (i == item) return qi2li->text; } return 0; } int gwinListFindText(GHandle gh, const char* text) { const gfxQueueASyncItem* qi; int i; // is it a valid handle? if (gh->vmt != (gwinVMT *)&listVMT) return -1; // watch out for NULL pointers if (!text) return -1; for(qi = gfxQueueASyncPeek(&gh2obj->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; // Multi-select always returns -1. Use gwinListItemIsSelected() instead if ((gh->flags & GLIST_FLG_MULTISELECT)) return -1; for(qi = gfxQueueASyncPeek(&gh2obj->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) { if (qi2li->flags & GLIST_FLG_SELECTED) return i; } return -1; } void gwinListItemSetParam(GHandle gh, int item, uint16_t param) { 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 > (gh2obj->cnt) - 1) return; for(qi = gfxQueueASyncPeek(&gh2obj->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) { if (i == item) { qi2li->param = param; break; } } } void gwinListDeleteAll(GHandle gh) { gfxQueueASyncItem* qi; // is it a valid handle? if (gh->vmt != (gwinVMT *)&listVMT) return; while((qi = gfxQueueASyncGet(&gh2obj->list_head))) gfxFree(qi); gh->flags &= ~GLIST_FLG_HASIMAGES; gh2obj->cnt = 0; gh2obj->top = 0; _gwinUpdate(gh); } void gwinListItemDelete(GHandle gh, int item) { 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 >= gh2obj->cnt) return; 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); gh2obj->cnt--; if (gh2obj->top >= item && gh2obj->top) gh2obj->top--; _gwinUpdate(gh); break; } } } uint16_t gwinListItemGetParam(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 > (gh2obj->cnt) - 1) return 0; for(qi = gfxQueueASyncPeek(&gh2obj->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) { if (i == item) return qi2li->param; } return 0; } gBool gwinListItemIsSelected(GHandle gh, int item) { const gfxQueueASyncItem * qi; int i; // is it a valid handle? if (gh->vmt != (gwinVMT *)&listVMT) return gFalse; // watch out for an invalid item if (item < 0 || item > (gh2obj->cnt) - 1) return gFalse; for(qi = gfxQueueASyncPeek(&gh2obj->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) { if (i == item) return (qi2li->flags & GLIST_FLG_SELECTED) ? gTrue : gFalse; } return gFalse; } int gwinListItemCount(GHandle gh) { // is it a valid handle? if (gh->vmt != (gwinVMT *)&listVMT) return 0; return gh2obj->cnt; } const char* gwinListGetSelectedText(GHandle gh) { // is it a valid handle? if (gh->vmt != (gwinVMT *)&listVMT) return 0; // return NULL if nothing is selected (or multi-select) if (gwinListGetSelected(gh) < 0) return 0; return gwinListItemGetText(gh, gwinListGetSelected(gh)); } void gwinListSetSelected(GHandle gh, int item, gBool doSelect) { 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 >= gh2obj->cnt) return; // If not a multiselect mode - clear previous selected item if (doSelect && !(gh->flags & GLIST_FLG_MULTISELECT)) { for(qi = gfxQueueASyncPeek(&gh2obj->list_head); qi; qi = gfxQueueASyncNext(qi)) { if (qi2li->flags & GLIST_FLG_SELECTED) { qi2li->flags &= ~GLIST_FLG_SELECTED; break; } } } // Find item and set selected or not for(qi = gfxQueueASyncPeek(&gh2obj->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) { if (i == item) { if (doSelect) qi2li->flags |= GLIST_FLG_SELECTED; else qi2li->flags &= ~GLIST_FLG_SELECTED; break; } } _gwinUpdate(gh); } void gwinListViewItem(GHandle gh, int item) { gCoord iheight; // is it a valid handle? if (gh->vmt != (gwinVMT *)&listVMT) return; // watch out for an invalid item if (item < 0 || item >= gh2obj->cnt) return; // Work out a possible new top for the list iheight = gdispGetFontMetric(gh->font, fontHeight) + LST_VERT_PAD; gh2obj->top = iheight * item; // Adjust the list if (gh2obj->top > gh2obj->cnt * iheight - gh->height-2) gh2obj->top = gh2obj->cnt * iheight - gh->height-2; if (gh2obj->top < 0) gh2obj->top = 0; _gwinUpdate(gh); } #if GWIN_NEED_LIST_IMAGES void gwinListItemSetImage(GHandle gh, int item, gdispImage *pimg) { 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 > (gh2obj->cnt) - 1) return; for(qi = gfxQueueASyncPeek(&gh2obj->list_head), i = 0; qi; qi = gfxQueueASyncNext(qi), i++) { if (i == item) { qi2li->pimg = pimg; if (pimg) gh->flags |= GLIST_FLG_HASIMAGES; break; } } } #endif void gwinListDefaultDraw(GWidgetObject* gw, void* param) { const gfxQueueASyncItem* qi; int i; gCoord x, y, iheight, iwidth; gColor fill; const GColorSet * ps; #if GWIN_NEED_LIST_IMAGES gCoord sy; #endif #if GDISP_NEED_CONVEX_POLYGON static const gPoint upArrow[] = { {0, LST_ARROW_SZ}, {LST_ARROW_SZ, LST_ARROW_SZ}, {LST_ARROW_SZ/2, 0} }; static const gPoint downArrow[] = { {0, 0}, {LST_ARROW_SZ, 0}, {LST_ARROW_SZ/2, LST_ARROW_SZ} }; #endif (void)param; // is it a valid handle? if (gw->g.vmt != (gwinVMT *)&listVMT) return; // don't render if render has been disabled if (!(gw->g.flags & GLIST_FLG_ENABLERENDER)) return; ps = (gw->g.flags & GWIN_FLG_SYSENABLED) ? &gw->pstyle->enabled : &gw->pstyle->disabled; iheight = gdispGetFontMetric(gw->g.font, fontHeight) + LST_VERT_PAD; x = 1; // the scroll area if (gw->g.flags & GLIST_FLG_SCROLLSMOOTH) { iwidth = gw->g.width - 2 - 4; if (gw2obj->cnt > 0) { int max_scroll_value = gw2obj->cnt * iheight - gw->g.height-2; if (max_scroll_value > 0) { int bar_height = (gw->g.height-2) * (gw->g.height-2) / (gw2obj->cnt * iheight); gdispGFillArea(gw->g.display, gw->g.x + gw->g.width-4, gw->g.y + 1, 2, gw->g.height-1, gw->pstyle->background); gdispGFillArea(gw->g.display, gw->g.x + gw->g.width-4, gw->g.y + gw2obj->top * ((gw->g.height-2)-bar_height) / max_scroll_value, 2, bar_height, ps->edge); } } } else if ((gw2obj->cnt > (gw->g.height-2) / iheight) || (gw->g.flags & GLIST_FLG_SCROLLALWAYS)) { iwidth = gw->g.width - (LST_SCROLLWIDTH+3); gdispGFillArea(gw->g.display, gw->g.x+iwidth+2, gw->g.y+1, LST_SCROLLWIDTH, gw->g.height-2, gdispBlendColor(ps->fill, gw->pstyle->background, 128)); gdispGDrawLine(gw->g.display, 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 gdispGFillConvexPoly(gw->g.display, gw->g.x+iwidth+((LST_SCROLLWIDTH-LST_ARROW_SZ)/2+2), gw->g.y+(LST_ARROW_SZ/2+1), upArrow, 3, ps->fill); gdispGFillConvexPoly(gw->g.display, gw->g.x+iwidth+((LST_SCROLLWIDTH-LST_ARROW_SZ)/2+2), gw->g.y+gw->g.height-(LST_ARROW_SZ+LST_ARROW_SZ/2+1), downArrow, 3, ps->fill); #else #if GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_DIRECT #warning "GWIN: Lists display better when GDISP_NEED_CONVEX_POLYGON is turned on" #elif GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_MACRO COMPILER_WARNING("GWIN: Lists display better when GDISP_NEED_CONVEX_POLYGON is turned on") #endif gdispGFillArea(gw->g.display, gw->g.x+iwidth+((LST_SCROLLWIDTH-LST_ARROW_SZ)/2+2), gw->g.y+(LST_ARROW_SZ/2+1), LST_ARROW_SZ, LST_ARROW_SZ, ps->fill); gdispGFillArea(gw->g.display, gw->g.x+iwidth+((LST_SCROLLWIDTH-LST_ARROW_SZ)/2+2), gw->g.y+gw->g.height-(LST_ARROW_SZ+LST_ARROW_SZ/2+1), LST_ARROW_SZ, LST_ARROW_SZ, ps->fill); #endif } else iwidth = gw->g.width - 2; #if GWIN_NEED_LIST_IMAGES if ((gw->g.flags & GLIST_FLG_HASIMAGES)) { x += iheight; iwidth -= iheight; } #endif // Find the top item for (qi = gfxQueueASyncPeek(&gw2obj->list_head), i = iheight - 1; i < gw2obj->top && qi; qi = gfxQueueASyncNext(qi), i+=iheight); // the list frame gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, ps->edge); // Set the clipping region so we do not override the frame. #if GDISP_NEED_CLIP gdispGSetClip(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2); #endif // Draw until we run out of room or items for (y = 1-(gw2obj->top%iheight); y < gw->g.height-2 && qi; qi = gfxQueueASyncNext(qi), y += iheight) { fill = (qi2li->flags & GLIST_FLG_SELECTED) ? ps->fill : gw->pstyle->background; gdispGFillArea(gw->g.display, gw->g.x+1, gw->g.y+y, iwidth, iheight, fill); #if GWIN_NEED_LIST_IMAGES if ((gw->g.flags & GLIST_FLG_HASIMAGES)) { // Clear the image area if (qi2li->pimg && gdispImageIsOpen(qi2li->pimg)) { // Calculate which image sy = (qi2li->flags & GLIST_FLG_SELECTED) ? 0 : (iheight-LST_VERT_PAD); if (!(gw->g.flags & GWIN_FLG_SYSENABLED)) sy += 2*(iheight-LST_VERT_PAD); while (sy > qi2li->pimg->height) sy -= iheight-LST_VERT_PAD; // Draw the image gdispImageSetBgColor(qi2li->pimg, fill); gdispGImageDraw(gw->g.display, qi2li->pimg, gw->g.x+1, gw->g.y+y, iheight-LST_VERT_PAD, iheight-LST_VERT_PAD, 0, sy); } } #endif gdispGFillStringBox(gw->g.display, gw->g.x+x+LST_HORIZ_PAD, gw->g.y+y, iwidth-LST_HORIZ_PAD, iheight, qi2li->text, gw->g.font, ps->text, fill, gJustifyLeft); } // Fill any remaining item space if (y < gw->g.height-1) gdispGFillArea(gw->g.display, gw->g.x+1, gw->g.y+y, iwidth, gw->g.height-1-y, gw->pstyle->background); } #undef gh2obj #undef gw2obj #undef qi2li #undef qix2li #undef ple #endif // GFX_USE_GWIN && GWIN_NEED_LIST