// These two sub-functions set/clear system enable recursively. void gwinSetEnabled(GHandle gh, bool_t enabled) { if (enabled) { // Mark us as enabled gh->flags |= GWIN_FLG_ENABLED; // Do we change our real enabled state if (!(gh->flags & GWIN_FLG_SYSENABLED) && (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSENABLED))) { // Check each window's enabled state is consistent with its parents for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { if ((gh->flags & (GWIN_FLG_SYSENABLED|GWIN_FLG_ENABLED)) == GWIN_FLG_ENABLED && (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSENABLED))) { gh->flags |= GWIN_FLG_SYSENABLED; // Fix it _gwinUpdate(gh); } } } } else { gh->flags &= ~GWIN_FLG_ENABLED; // Do we need to change our real enabled state if ((gh->flags & GWIN_FLG_SYSENABLED)) { // Check each window's visibility is consistent with its parents for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { if ((gh->flags & GWIN_FLG_SYSENABLED) && (!(gh->flags & GWIN_FLG_ENABLED) || (gh->parent && !(gh->parent->flags & GWIN_FLG_SYSENABLED)))) { gh->flags &= ~GWIN_FLG_SYSENABLED; // Fix it _gwinUpdate(gh); } } } } }
// a mouse down has occurred over the list area static void ListMouseDown(GWidgetObject* gw, coord_t x, coord_t y) { coord_t 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); }
void gwinSetEnabled(GHandle gh, bool_t enabled) { if (enabled) { if (!(gh->flags & GWIN_FLG_ENABLED)) { gh->flags |= (GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED); _gwinUpdate(gh); } } else { if ((gh->flags & GWIN_FLG_ENABLED)) { gh->flags &= ~(GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED); _gwinUpdate(gh); } } }
void gwinSetVisible(GHandle gh, bool_t visible) { if (visible) { if (!(gh->flags & GWIN_FLG_VISIBLE)) { gh->flags |= (GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE|GWIN_FLG_BGREDRAW); _gwinUpdate(gh); } } else { if ((gh->flags & GWIN_FLG_VISIBLE)) { gh->flags &= ~(GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE); gh->flags |= GWIN_FLG_BGREDRAW; _gwinUpdate(gh); } } }
void gwinRadioPress(GHandle gh) { GHandle gx; if (gh->vmt != (gwinVMT *)&radioVMT || (gh->flags & GRADIO_FLG_PRESSED)) return; if ((gx = gwinRadioGetActive(((GRadioObject *)gh)->group))) { gx->flags &= ~GRADIO_FLG_PRESSED; _gwinUpdate(gx); } gh->flags |= GRADIO_FLG_PRESSED; _gwinUpdate(gh); SendRadioEvent((GWidgetObject *)gh); }
void gwinListSetSelected(GHandle gh, int item, bool_t 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); }
// A toggle on has occurred static void ToggleOn(GWidgetObject *gw, uint16_t role) { (void) role; gw->g.flags |= GBUTTON_FLG_PRESSED; _gwinUpdate((GHandle)gw); // Trigger the event on button down (different than for mouse/touch) _gwinSendEvent(&gw->g, GEVENT_GWIN_BUTTON); }
void gwinSetText(GHandle gh, const char *text, bool_t useAlloc) { if (!(gh->flags & GWIN_FLG_WIDGET)) return; // Dispose of the old string if ((gh->flags & GWIN_FLG_ALLOCTXT)) { gh->flags &= ~GWIN_FLG_ALLOCTXT; if (gw->text) { gfxFree((void *)gw->text); gw->text = ""; } } // Alloc the new text if required if (!text || !*text) gw->text = ""; else if (useAlloc) { char *str; if ((str = gfxAlloc(strlen(text)+1))) { gh->flags |= GWIN_FLG_ALLOCTXT; strcpy(str, text); } gw->text = (const char *)str; } else gw->text = text; _gwinUpdate(gh); }
static void ListMouseSelect(GWidgetObject* gw, coord_t x, coord_t y) { const gfxQueueASyncItem* qi; int item, i; coord_t 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); }
void gwinRedrawDisplay(GDisplay *g, bool_t preserve) { GHandle gh; for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { // Skip if it is for a different display if (g && gh->display != g) continue; #if GWIN_NEED_CONTAINERS // Skip if it is not a top level window (parents internally take care of their children) if (gh->parent) continue; #endif // Only visible windows are to be redrawn if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) continue; if (!preserve) gh->flags |= GWIN_FLG_BGREDRAW; _gwinUpdate(gh); } }
void gwinResize(GHandle gh, coord_t width, coord_t height) { gh->width = width; gh->height = height; if (gh->width < MIN_WIN_WIDTH) { gh->width = MIN_WIN_WIDTH; } if (gh->height < MIN_WIN_HEIGHT) { gh->height = MIN_WIN_HEIGHT; } if (gh->x+gh->width > gdispGGetWidth(gh->display)) gh->width = gdispGGetWidth(gh->display) - gh->x; if (gh->y+gh->height > gdispGGetHeight(gh->display)) gh->height = gdispGGetHeight(gh->display) - gh->y; _gwinUpdate(gh); }
void gwinSetCustomDraw(GHandle gh, CustomWidgetDrawFunction fn, void *param) { if (!(gh->flags & GWIN_FLG_WIDGET)) return; gw->fnDraw = fn ? fn : wvmt->DefaultDraw; gw->fnParam = param; _gwinUpdate(gh); }
void gwinMove(GHandle gh, coord_t x, coord_t y) { gh->x = x; gh->y = y; if (gh->x < 0) gh->x = 0; if (gh->y < 0) gh->y = 0; if (gh->x > gdispGGetWidth(gh->display)-MIN_WIN_WIDTH) gh->x = gdispGGetWidth(gh->display)-MIN_WIN_WIDTH; if (gh->y > gdispGGetHeight(gh->display)-MIN_WIN_HEIGHT) gh->y = gdispGGetHeight(gh->display)-MIN_WIN_HEIGHT; if (gh->x+gh->width > gdispGGetWidth(gh->display)) gh->width = gdispGGetWidth(gh->display) - gh->x; if (gh->y+gh->height > gdispGGetHeight(gh->display)) gh->height = gdispGGetHeight(gh->display) - gh->y; _gwinUpdate(gh); }
static void WM_Raise(GHandle gh) { // Take it off the list and then put it back on top // The order of the list then reflects the z-order. gfxQueueASyncRemove(&_GWINList, &gh->wmq); gfxQueueASyncPut(&_GWINList, &gh->wmq); // Redraw the window _gwinUpdate(gh); }
bool_t gwinSetFocus(GHandle gh) { GHandle oldFocus; // Do we already have the focus? if (gh == _widgetInFocus) return TRUE; // The new window must be NULLL or a visible enabled widget with a keyboard handler if (!gh || ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED|GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE)) == (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED|GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE) && ((gwidgetVMT*)gh->vmt)->KeyboardEvent)) { // Move the current focus oldFocus = _widgetInFocus; _widgetInFocus = gh; if (oldFocus) _gwinUpdate(oldFocus); if (gh) _gwinUpdate(gh); return TRUE; } return FALSE; }
void gwinSetStyle(GHandle gh, const GWidgetStyle *pstyle) { if (!(gh->flags & GWIN_FLG_WIDGET)) return; gw->pstyle = pstyle ? pstyle : defaultStyle; gh->bgcolor = pstyle->background; gh->color = pstyle->enabled.text; _gwinUpdate(gh); }
// A mouse up has occurred (it may or may not be over the button) static void MouseUp(GWidgetObject *gw, coord_t x, coord_t y) { (void) x; (void) y; gw->g.flags &= ~GBUTTON_FLG_PRESSED; _gwinUpdate((GHandle)gw); #if !GWIN_BUTTON_LAZY_RELEASE // If the mouse up was not over the button then cancel the event if (x < 0 || y < 0 || x >= gw->g.width || y >= gw->g.height) return; #endif _gwinSendEvent(&gw->g, GEVENT_GWIN_BUTTON); }
// a toggle-on has occurred static void ListToggleOn(GWidgetObject *gw, uint16_t role) { const gfxQueueASyncItem * qi; const gfxQueueASyncItem * qix; int i; 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; _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; _gwinUpdate(&gw->g); } break; } } break; } }
void gwinCheckboxCheck(GHandle gh, bool_t isChecked) { if (gh->vmt != (gwinVMT *)&checkboxVMT) return; if (isChecked) { if ((gh->flags & GCHECKBOX_FLG_CHECKED)) return; gh->flags |= GCHECKBOX_FLG_CHECKED; } else { if (!(gh->flags & GCHECKBOX_FLG_CHECKED)) return; gh->flags &= ~GCHECKBOX_FLG_CHECKED; } _gwinUpdate(gh); SendCheckboxEvent((GWidgetObject *)gh); }
bool_t gwinImageOpenGFile(GHandle gh, GFILE *f) { // is it a valid handle? if (gh->vmt != (gwinVMT *)&imageVMT) return FALSE; if (gdispImageIsOpen(&gw->image)) gdispImageClose(&gw->image); if ((gdispImageOpenGFile(&gw->image, f) & GDISP_IMAGE_ERR_UNRECOVERABLE)) return FALSE; _gwinUpdate(gh); return TRUE; }
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 gwinProgressbarIncrement(GHandle gh) { #define gsw ((GProgressbarObject *)gh) if (gh->vmt != (gwinVMT *)&progressbarVMT) return; if (gsw->max - gsw->pos > gsw->res) gsw->pos += gsw->res; else gsw->pos = gsw->max; PBResetDisplayPos(gsw); _gwinUpdate(gh); #undef gsw }
int gwinListAddItem(GHandle gh, const char* item_name, bool_t useAlloc) { ListItem *newItem; // is it a valid handle? if (gh->vmt != (gwinVMT *)&listVMT) return -1; if (useAlloc) { size_t len = strlen(item_name)+1; if (!(newItem = gfxAlloc(sizeof(ListItem) + len))) return -1; memcpy((char *)(newItem+1), item_name, len); item_name = (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 = item_name; #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; }
static void ListMouseMove(GWidgetObject* gw, coord_t x, coord_t 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); } }
void gwinProgressbarSetPosition(GHandle gh, int pos) { #define gsw ((GProgressbarObject *)gh) if (gh->vmt != (gwinVMT *)&progressbarVMT) return; if (gsw->min <= gsw->max) { if (pos < gsw->min) gsw->pos = gsw->min; else if (pos > gsw->max) gsw->pos = gsw->max; else gsw->pos = pos; } else { if (pos > gsw->min) gsw->pos = gsw->min; else if (pos < gsw->max) gsw->pos = gsw->max; else gsw->pos = pos; } PBResetDisplayPos(gsw); _gwinUpdate(gh); #undef gsw }
// Function that allows to set the cursor to any position in the string // This should be optimized. Currently it is an O(n^2) problem and therefore very // slow. An optimized version would copy the behavior of mf_get_string_width() // and do the comparation directly inside of that loop so we only iterate // the string once. static void TextEditMouseDown(GWidgetObject* gw, coord_t x, coord_t y) { uint16_t i = 0; (void)y; // Directly jump to the end of the string if (x > gdispGetStringWidth(gw->text, gw->g.font)) { gw2obj->cursorPos = strlen(gw->text); // Otherwise iterate through each character and get the size in pixels to compare } else { i = 1; while (gdispGetStringWidthCount(gw->text, gw->g.font, i) < x) { i++; } gw2obj->cursorPos = i-1; } _gwinUpdate((GHandle)gw); }
static void FlashTimerFn(void *param) { GHandle gh; (void) param; // Assume we will be stopping RedrawPending &= ~DOREDRAW_FLASHRUNNING; // Swap the flash state _gwinFlashState = !_gwinFlashState; // Redraw all flashing windows for(gh = (GHandle)gfxQueueASyncPeek(&_GWINList); gh; gh = (GHandle)gfxQueueASyncNext(&gh->wmq)) { if ((gh->flags & GWIN_FLG_FLASHING)) { RedrawPending |= DOREDRAW_FLASHRUNNING; _gwinUpdate(gh); } } // Do we have no flashers left? if (!(RedrawPending & DOREDRAW_FLASHRUNNING)) gtimerStop(&FlashTimer); }
void gwinListViewItem(GHandle gh, int item) { coord_t 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); }
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); if (gh2obj->top >= item && gh2obj->top) gh2obj->top--; _gwinUpdate(gh); break; } } }
void gwinSetFlashing(GHandle gh, bool_t flash) { // Start flashing? if (flash) { gh->flags |= GWIN_FLG_FLASHING; // A redraw will occur on the next flash period. // Start the flash timer if needed if (!(RedrawPending & DOREDRAW_FLASHRUNNING)) { RedrawPending |= DOREDRAW_FLASHRUNNING; // Ensure we start the timer with flash bit on _gwinFlashState = FALSE; FlashTimerFn(0); // First flash gtimerStart(&FlashTimer, FlashTimerFn, 0, TRUE, GWIN_FLASHING_PERIOD); // Subsequent flashes } // Stop flashing? } else if ((gh->flags & GWIN_FLG_FLASHING)) { gh->flags &= ~GWIN_FLG_FLASHING; // We need to manually redraw as the timer is now turned off for this window _gwinUpdate(gh); } }