aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gfx.c2
-rw-r--r--src/ginput/dial.c2
-rw-r--r--src/gqueue/gqueue.c37
-rw-r--r--src/gwin/button.c558
-rw-r--r--src/gwin/checkbox.c264
-rw-r--r--src/gwin/console.c60
-rw-r--r--src/gwin/gimage.c175
-rw-r--r--src/gwin/graph.c77
-rw-r--r--src/gwin/gwidget.c461
-rw-r--r--src/gwin/gwin.c383
-rw-r--r--src/gwin/gwin.mk9
-rw-r--r--src/gwin/gwm.c201
-rw-r--r--src/gwin/label.c118
-rw-r--r--src/gwin/radio.c229
-rw-r--r--src/gwin/slider.c487
15 files changed, 2239 insertions, 824 deletions
diff --git a/src/gfx.c b/src/gfx.c
index 6a73d672..1791ef89 100644
--- a/src/gfx.c
+++ b/src/gfx.c
@@ -19,7 +19,7 @@ void DEPRECATED("Use gfxInit() instead") gdispInit() { gfxInit(); }
/* These init functions are defined by each module but not published */
extern void _gosInit(void);
-#if GFX_USE_GDISP && (GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC)
+#if GFX_USE_GDISP
extern void _gdispInit(void);
#endif
#if GFX_USE_TDISP
diff --git a/src/ginput/dial.c b/src/ginput/dial.c
index 3afb4796..d978aa65 100644
--- a/src/ginput/dial.c
+++ b/src/ginput/dial.c
@@ -57,6 +57,7 @@ static void DialCallback(uint16_t instance, uint16_t rawvalue) {
pe->type = GEVENT_DIAL;
pe->instance = instance;
pe->value = pds->lastvalue;
+ pe->maxvalue = pds->max;
geventSendEvent(psl);
}
}
@@ -144,6 +145,7 @@ bool_t ginputGetDialStatus(uint16_t instance, GEventDial *pdial) {
pdial->type = GEVENT_DIAL;
pdial->instance = instance;
pdial->value = DialStatus[instance].lastvalue;
+ pdial->maxvalue = DialStatus[instance].max;
return TRUE;
}
diff --git a/src/gqueue/gqueue.c b/src/gqueue/gqueue.c
index 7cd1c9d9..beb42a2e 100644
--- a/src/gqueue/gqueue.c
+++ b/src/gqueue/gqueue.c
@@ -9,6 +9,9 @@
* @file src/gqueue/gqueue.c
* @brief GQUEUE source file.
*/
+
+#include "gfx.h"
+
#if GFX_USE_GQUEUE
#if GQUEUE_NEED_ASYNC
@@ -22,7 +25,8 @@
gfxSystemLock();
if ((pi = pqueue->head))
pqueue->head = pi->next;
- gfxSytemUnlock();
+ pi->next = 0;
+ gfxSystemUnlock();
return pi;
}
void gfxQueueASyncPut(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
@@ -46,17 +50,21 @@
gfxSystemUnlock();
}
void gfxQueueASyncRemove(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
+ gfxQueueASyncItem *pi;
+
if (!pitem) return;
gfxSystemLock();
if (pqueue->head) {
if (pqueue->head == pitem) {
pqueue->head = pitem->next;
+ pitem->next = 0;
} else {
- for(gfxQueueASyncItem *pi = pqueue->head; pi->next; pi = pi->next) {
+ for(pi = pqueue->head; pi->next; pi = pi->next) {
if (pi->next == pitem) {
pi->next = pitem->next;
if (pqueue->tail == pitem)
pqueue->tail = pi;
+ pitem->next = 0;
break;
}
}
@@ -68,8 +76,10 @@
return pqueue->head == NULL;
}
bool_t gfxQueueASyncIsIn(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) {
+ gfxQueueASyncItem *pi;
+
gfxSystemLock();
- for(gfxQueueASyncItem *pi = pqueue->head; pi; pi = pi->next) {
+ for(pi = pqueue->head; pi; pi = pi->next) {
if (pi == pitem) {
gfxSystemUnlock();
return TRUE;
@@ -92,6 +102,7 @@
gfxSystemLock();
pi = pqueue->head;
pqueue->head = pi->next;
+ pi->next = 0;
gfxSytemUnlock();
return pi;
}
@@ -120,17 +131,21 @@
gfxSemSignal(&pqueue->sem);
}
void gfxQueueGSyncRemove(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
+ gfxQueueGSyncItem *pi;
+
if (!pitem) return;
gfxSystemLock();
if (pqueue->head) {
if (pqueue->head == pitem) {
pqueue->head = pitem->next;
+ pitem->next = 0;
} else {
- for(gfxQueueGSyncItem *pi = pqueue->head; pi->next; pi = pi->next) {
+ for(pi = pqueue->head; pi->next; pi = pi->next) {
if (pi->next == pitem) {
pi->next = pitem->next;
if (pqueue->tail == pitem)
pqueue->tail = pi;
+ pitem->next = 0;
break;
}
}
@@ -142,8 +157,10 @@
return pqueue->head == NULL;
}
bool_t gfxQueueGSyncIsIn(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) {
+ gfxQueueGSyncItem *pi;
+
gfxSystemLock();
- for(gfxQueueGSyncItem *pi = pqueue->head; pi; pi = pi->next) {
+ for(pi = pqueue->head; pi; pi = pi->next) {
if (pi == pitem) {
gfxSystemUnlock();
return TRUE;
@@ -166,6 +183,7 @@
gfxSystemLock();
pi = pqueue->head;
pqueue->head = pi->next;
+ pi->next = 0;
gfxSytemUnlock();
gfxSemSignalI(&pi->sem);
@@ -202,18 +220,21 @@
return gfxSemWait(&pitem->sem, ms);
}
void gfxQueueFSyncRemove(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem) {
+ gfxQueueFSyncItem *pi;
+
if (!pitem) return;
gfxSystemLock();
if (pqueue->head) {
if (pqueue->head == pitem) {
pqueue->head = pitem->next;
found:
+ pitem->next = 0;
gfxSystemUnlock();
gfxSemSignal(&pitem->sem);
gfxSemDestroy(&pitem->sem);
return;
}
- for(gfxQueueFSyncItem *pi = pqueue->head; pi->next; pi = pi->next) {
+ for(pi = pqueue->head; pi->next; pi = pi->next) {
if (pi->next == pitem) {
pi->next = pitem->next;
if (pqueue->tail == pitem)
@@ -228,8 +249,10 @@
return pqueue->head == NULL;
}
bool_t gfxQueueFSyncIsIn(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem) {
+ gfxQueueASyncItem *pi;
+
gfxSystemLock();
- for(gfxQueueFSyncItem *pi = pqueue->head; pi; pi = pi->next) {
+ for(pi = pqueue->head; pi; pi = pi->next) {
if (pi == pitem) {
gfxSystemUnlock();
return TRUE;
diff --git a/src/gwin/button.c b/src/gwin/button.c
index 6b7306b5..e6f628c3 100644
--- a/src/gwin/button.c
+++ b/src/gwin/button.c
@@ -17,394 +17,308 @@
#include "gfx.h"
-#if (GFX_USE_GWIN && GWIN_NEED_BUTTON) || defined(__DOXYGEN__)
+#if GFX_USE_GWIN && GWIN_NEED_BUTTON
-/* Parameters for various shapes */
+#include "gwin/class_gwin.h"
+
+// Parameters for various shapes
#define RND_CNR_SIZE 5 // Rounded corner size for rounded buttons
#define ARROWHEAD_DIVIDER 4 // A quarter of the height for the arrow head
#define ARROWBODY_DIVIDER 4 // A quarter of the width for the arrow body
-#include <string.h>
-
-#include "gwin/internal.h"
-
-#define GWIN_BUTTON_DEFAULT_SHAPE GBTN_3D
-
-static const GButtonDrawStyle GButtonDefaultStyleUp = {
- HTML2COLOR(0x404040), // color_up_edge;
- HTML2COLOR(0xE0E0E0), // color_up_fill;
- HTML2COLOR(0x000000), // color_up_txt;
-};
-
-static const GButtonDrawStyle GButtonDefaultStyleDown = {
- HTML2COLOR(0x404040), // color_dn_edge;
- HTML2COLOR(0x808080), // color_dn_fill;
- HTML2COLOR(0x404040), // color_dn_txt;
-};
-
-// Process an event callback
-static void gwinButtonCallback(void *param, GEvent *pe) {
- GSourceListener *psl;
- #define gh ((GHandle)param)
- #define gbw ((GButtonObject *)param)
- #define gsh ((GSourceHandle)param)
- #define pme ((GEventMouse *)pe)
- #define pte ((GEventTouch *)pe)
- #define pxe ((GEventToggle *)pe)
- #define pbe ((GEventGWinButton *)pe)
-
- // check if button is disabled
- if (!gh->enabled)
- return;
-
- switch (pe->type) {
- #if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
- case GEVENT_MOUSE:
- case GEVENT_TOUCH:
- // Ignore anything other than the primary mouse button going up or down
- if (!((pme->current_buttons ^ pme->last_buttons) & GINPUT_MOUSE_BTN_LEFT))
- return;
-
- if (gbw->state == GBTN_UP) {
- // Our button is UP: Test for button down over the button
- if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)
- && pme->x >= gbw->gwin.x && pme->x < gbw->gwin.x + gbw->gwin.width
- && pme->y >= gbw->gwin.y && pme->y < gbw->gwin.y + gbw->gwin.height) {
- gbw->state = GBTN_DOWN;
- gwinButtonDraw((GHandle)param);
- }
- return;
- }
-
- // Our button is DOWN
-
- // Skip more mouse downs
- if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT))
- return;
-
- // This must be a mouse up - set the button as UP
- gbw->state = GBTN_UP;
- gwinButtonDraw((GHandle)param);
-
- #if GWIN_BUTTON_LAZY_RELEASE
- break;
- #else
- // If the mouse up was over the button then create the event
- if (pme->x >= gbw->gwin.x && pme->x < gbw->gwin.x + gbw->gwin.width
- && pme->y >= gbw->gwin.y && pme->y < gbw->gwin.y + gbw->gwin.height)
- break;
+// Our pressed state
+#define GBUTTON_FLG_PRESSED (GWIN_FIRST_CONTROL_FLAG<<0)
- return;
- #endif
- #endif
-
- #if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
- case GEVENT_TOGGLE:
- // State has changed - update the button
- gbw->state = pxe->on ? GBTN_DOWN : GBTN_UP;
- gwinButtonDraw((GHandle)param);
-
- // Trigger the event on button down (different than for mouse/touch)
- if (gbw->state == GBTN_DOWN)
- break;
-
- return;
- #endif
-
- default:
- return;
- }
+// Send the button event
+static void SendButtonEvent(GWidgetObject *gw) {
+ GSourceListener * psl;
+ GEvent * pe;
+ #define pbe ((GEventGWinButton *)pe)
// Trigger a GWIN Button Event
psl = 0;
- while ((psl = geventGetSourceListener(gsh, psl))) {
+ while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) {
if (!(pe = geventGetEventBuffer(psl)))
continue;
pbe->type = GEVENT_GWIN_BUTTON;
- pbe->button = gh;
+ pbe->button = (GHandle)gw;
geventSendEvent(psl);
}
#undef pbe
- #undef pme
- #undef pte
- #undef pxe
- #undef gsh
- #undef gbw
- #undef gh
}
-GHandle gwinCreateButton(GButtonObject *gb, coord_t x, coord_t y, coord_t width, coord_t height, font_t font, GButtonType type) {
- if (!(gb = (GButtonObject *)_gwinInit((GWindowObject *)gb, x, y, width, height, sizeof(GButtonObject))))
- return 0;
-
- gb->gwin.type = GW_BUTTON;
- gb->fn = 0;
- gb->param = 0;
- gwinSetFont(&gb->gwin, font);
- gwinSetButtonStyle(&gb->gwin, GWIN_BUTTON_DEFAULT_SHAPE, &GButtonDefaultStyleUp, &GButtonDefaultStyleDown);
- gb->type = type;
- gb->state = GBTN_UP;
- gb->txt = "";
- geventListenerInit(&gb->listener);
- geventRegisterCallback(&gb->listener, gwinButtonCallback, gb);
-
- // buttons are enabled by default
- gb->gwin.enabled = TRUE;
-
- return (GHandle)gb;
-}
-
-void gwinSetButtonStyle(GHandle gh, GButtonShape shape, const GButtonDrawStyle *pUp, const GButtonDrawStyle *pDown) {
- #define gbw ((GButtonObject *)gh)
- if (gh->type != GW_BUTTON)
- return;
+#if GINPUT_NEED_MOUSE
+ // A mouse down has occurred over the button
+ static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) {
+ (void) x; (void) y;
+ gw->g.flags |= GBUTTON_FLG_PRESSED;
+ _gwidgetRedraw((GHandle)gw);
+ }
- switch(shape) {
- case GBTN_SQUARE: gbw->fn = gwinButtonDraw_Square; break;
- #if GDISP_NEED_ARC
- case GBTN_ROUNDED: gbw->fn = gwinButtonDraw_Rounded; break;
- #endif
- #if GDISP_NEED_ELLIPSE
- case GBTN_ELLIPSE: gbw->fn = gwinButtonDraw_Ellipse; break;
- #endif
+ // 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;
+ _gwidgetRedraw((GHandle)gw);
- #if GDISP_NEED_CONVEX_POLYGON
- case GBTN_ARROW_UP: gbw->fn = gwinButtonDraw_ArrowUp; break;
- case GBTN_ARROW_DOWN: gbw->fn = gwinButtonDraw_ArrowDown; break;
- case GBTN_ARROW_LEFT: gbw->fn = gwinButtonDraw_ArrowLeft; break;
- case GBTN_ARROW_RIGHT: gbw->fn = gwinButtonDraw_ArrowRight; break;
+ #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
- case GBTN_CUSTOM: if (gbw->fn) break; /* Fall Through */
- case GBTN_3D: /* Fall through */
- default: gbw->fn = gwinButtonDraw_3D; break;
+ SendButtonEvent(gw);
}
- if (pUp) {
- gbw->up.color_edge = pUp->color_edge;
- gbw->up.color_fill = pUp->color_fill;
- gbw->up.color_txt = pUp->color_txt;
- }
- if (pDown) {
- gbw->dn.color_edge = pDown->color_edge;
- gbw->dn.color_fill = pDown->color_fill;
- gbw->dn.color_txt = pDown->color_txt;
+#endif
+
+#if GINPUT_NEED_TOGGLE
+ // A toggle off has occurred
+ static void ToggleOff(GWidgetObject *gw, uint16_t role) {
+ (void) role;
+ gw->g.flags &= ~GBUTTON_FLG_PRESSED;
+ _gwidgetRedraw((GHandle)gw);
}
- #undef gbw
-}
-void gwinSetButtonText(GHandle gh, const char *txt, bool_t useAlloc) {
- #define gbw ((GButtonObject *)gh)
- if (gh->type != GW_BUTTON)
- return;
-
- // Dispose of the old string
- if ((gh->flags & GBTN_FLG_ALLOCTXT)) {
- gh->flags &= ~GBTN_FLG_ALLOCTXT;
- if (gbw->txt) {
- gfxFree((void *)gbw->txt);
- gbw->txt = "";
- }
+ // A toggle on has occurred
+ static void ToggleOn(GWidgetObject *gw, uint16_t role) {
+ (void) role;
+ gw->g.flags |= GBUTTON_FLG_PRESSED;
+ _gwidgetRedraw((GHandle)gw);
+ // Trigger the event on button down (different than for mouse/touch)
+ SendButtonEvent(gw);
}
- // Alloc the new text if required
- if (txt && useAlloc) {
- char *str;
-
- if ((str = (char *)gfxAlloc(strlen(txt)+1))) {
- gh->flags |= GBTN_FLG_ALLOCTXT;
- strcpy(str, txt);
- }
- txt = (const char *)str;
+
+ static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) {
+ (void) role;
+ ((GButtonObject *)gw)->toggle = instance;
}
-
- gbw->txt = txt ? txt : "";
- #undef gbw
-}
-void gwinButtonDraw(GHandle gh) {
- #define gbw ((GButtonObject *)gh)
-
- if (gh->type != GW_BUTTON)
- return;
+ static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role) {
+ (void) role;
+ return ((GButtonObject *)gw)->toggle;
+ }
+#endif
- #if GDISP_NEED_CLIP
- gdispSetClip(gh->x, gh->y, gh->width, gh->height);
+// The button VMT table
+static const gwidgetVMT buttonVMT = {
+ {
+ "Button", // The classname
+ sizeof(GButtonObject), // The object size
+ _gwidgetDestroy, // The destroy routine
+ _gwidgetRedraw, // The redraw routine
+ 0, // The after-clear routine
+ },
+ gwinButtonDraw_3D, // The default drawing routine
+ #if GINPUT_NEED_MOUSE
+ {
+ MouseDown, // Process mouse down events
+ MouseUp, // Process mouse up events
+ 0, // Process mouse move events (NOT USED)
+ },
#endif
+ #if GINPUT_NEED_TOGGLE
+ {
+ 1, // 1 toggle role
+ ToggleAssign, // Assign Toggles
+ ToggleGet, // Get Toggles
+ ToggleOff, // Process toggle off events
+ ToggleOn, // Process toggle on events
+ },
+ #endif
+ #if GINPUT_NEED_DIAL
+ {
+ 0, // No dial roles
+ 0, // Assign Dials (NOT USED)
+ 0, // Get Dials (NOT USED)
+ 0, // Process dial move events (NOT USED)
+ },
+ #endif
+};
- gbw->fn(gh,
- gbw->gwin.enabled,
- gbw->state == GBTN_DOWN,
- gh->font && gbw->txt ? gbw->txt : "",
- gbw->state == GBTN_DOWN ? &gbw->dn : &gbw->up,
- gbw->param);
-
- #undef gbw
-}
-
-void gwinSetButtonCustom(GHandle gh, GButtonDrawFunction fn, void *param) {
- #define gbw ((GButtonObject *)gh)
-
- if (gh->type != GW_BUTTON)
- return;
-
- gbw->fn = fn ? fn : gwinButtonDraw_3D;
- gbw->param = param;
+GHandle gwinButtonCreate(GButtonObject *gw, const GWidgetInit *pInit) {
+ if (!(gw = (GButtonObject *)_gwidgetCreate(&gw->w, pInit, &buttonVMT)))
+ return 0;
- #undef gbw
+ #if GINPUT_NEED_TOGGLE
+ gw->toggle = GWIDGET_NO_INSTANCE;
+ #endif
+ gwinSetVisible((GHandle)gw, pInit->g.show);
+ return (GHandle)gw;
}
-void gwinButtonSetEnabled(GHandle gh, bool_t enabled) {
- if (gh->type != GW_BUTTON)
- return;
+bool_t gwinButtonIsPressed(GHandle gh) {
+ if (gh->vmt != (gwinVMT *)&buttonVMT)
+ return FALSE;
- gh->enabled = enabled;
+ return (gh->flags & GBUTTON_FLG_PRESSED) ? TRUE : FALSE;
}
-void gwinButtonDraw_3D(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) {
- (void) enabled;
- (void) isdown;
- (void) param;
+/*----------------------------------------------------------
+ * Custom Draw Routines
+ *----------------------------------------------------------*/
- gdispFillStringBox(gh->x, gh->y, gh->width-1, gh->height-1, txt, gh->font, pstyle->color_txt, pstyle->color_fill, justifyCenter);
- gdispDrawLine(gh->x+gh->width-1, gh->y, gh->x+gh->width-1, gh->y+gh->height-1, pstyle->color_edge);
- gdispDrawLine(gh->x, gh->y+gh->height-1, gh->x+gh->width-2, gh->y+gh->height-1, pstyle->color_edge);
+static const GColorSet *getDrawColors(GWidgetObject *gw) {
+ if (!(gw->g.flags & GWIN_FLG_ENABLED)) return &gw->pstyle->disabled;
+ if ((gw->g.flags & GBUTTON_FLG_PRESSED)) return &gw->pstyle->pressed;
+ return &gw->pstyle->enabled;
}
-void gwinButtonDraw_Square(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) {
- (void) enabled;
- (void) isdown;
- (void) param;
+void gwinButtonDraw_3D(GWidgetObject *gw, void *param) {
+ const GColorSet * pcol;
+ (void) param;
- gdispFillStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, pstyle->color_fill, justifyCenter);
- gdispDrawBox(gh->x, gh->y, gh->width, gh->height, pstyle->color_edge);
+ if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
+ pcol = getDrawColors(gw);
+
+ gdispFillStringBox(gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter);
+ gdispDrawLine(gw->g.x+gw->g.width-1, gw->g.y, gw->g.x+gw->g.width-1, gw->g.y+gw->g.height-1, pcol->edge);
+ gdispDrawLine(gw->g.x, gw->g.y+gw->g.height-1, gw->g.x+gw->g.width-2, gw->g.y+gw->g.height-1, pcol->edge);
}
#if GDISP_NEED_ARC
- void gwinButtonDraw_Rounded(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) {
- (void) enabled;
- (void) isdown;
- (void) param;
-
- if (gh->width >= 2*RND_CNR_SIZE+10) {
- gdispFillRoundedBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, RND_CNR_SIZE-1, pstyle->color_fill);
- gdispDrawStringBox(gh->x+1, gh->y+RND_CNR_SIZE, gh->width-2, gh->height-(2*RND_CNR_SIZE), txt, gh->font, pstyle->color_txt, justifyCenter);
- gdispDrawRoundedBox(gh->x, gh->y, gh->width, gh->height, RND_CNR_SIZE, pstyle->color_edge);
+ void gwinButtonDraw_Rounded(GWidgetObject *gw, void *param) {
+ const GColorSet * pcol;
+ (void) param;
+
+ if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
+ pcol = getDrawColors(gw);
+
+ gdispFillArea(gw->g.x, gw->g.y, ld, ld, gw->pstyle->background);
+ if (gw->g.width >= 2*RND_CNR_SIZE+10) {
+ gdispFillRoundedBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, RND_CNR_SIZE-1, pcol->fill);
+ gdispDrawStringBox(gw->g.x+1, gw->g.y+RND_CNR_SIZE, gw->g.width-2, gw->g.height-(2*RND_CNR_SIZE), gw->text, gw->g.font, pcol->text, justifyCenter);
+ gdispDrawRoundedBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, RND_CNR_SIZE, pcol->edge);
} else {
- gdispFillStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, pstyle->color_fill, justifyCenter);
- gdispDrawBox(gh->x, gh->y, gh->width, gh->height, pstyle->color_edge);
+ gdispFillStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter);
+ gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge);
}
}
#endif
#if GDISP_NEED_ELLIPSE
- void gwinButtonDraw_Ellipse(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) {
- (void) enabled;
- (void) isdown;
- (void) param;
-
- gdispFillEllipse(gh->x+1, gh->y+1, gh->width/2-1, gh->height/2-1, pstyle->color_fill);
- gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter);
- gdispDrawEllipse(gh->x, gh->y, gh->width/2, gh->height/2, pstyle->color_edge);
+ void gwinButtonDraw_Ellipse(GWidgetObject *gw, void *param) {
+ const GColorSet * pcol;
+ (void) param;
+
+ if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
+ pcol = getDrawColors(gw);
+
+ gdispFillArea(gw->g.x, gw->g.y, ld, ld, gw->pstyle->background);
+ gdispFillEllipse(gw->g.x+1, gw->g.y+1, gw->g.width/2-1, gw->g.height/2-1, pcol->fill);
+ gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter);
+ gdispDrawEllipse(gw->g.x, gw->g.y, gw->g.width/2, gw->g.height/2, pcol->edge);
}
#endif
#if GDISP_NEED_CONVEX_POLYGON
- void gwinButtonDraw_ArrowUp(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) {
- (void) enabled;
- (void) isdown;
- (void) param;
- point arw[7];
-
- arw[0].x = gh->width/2; arw[0].y = 0;
- arw[1].x = gh->width-1; arw[1].y = gh->height/ARROWHEAD_DIVIDER;
- arw[2].x = (gh->width + gh->width/ARROWBODY_DIVIDER)/2; arw[2].y = gh->height/ARROWHEAD_DIVIDER;
- arw[3].x = (gh->width + gh->width/ARROWBODY_DIVIDER)/2; arw[3].y = gh->height-1;
- arw[4].x = (gh->width - gh->width/ARROWBODY_DIVIDER)/2; arw[4].y = gh->height-1;
- arw[5].x = (gh->width - gh->width/ARROWBODY_DIVIDER)/2; arw[5].y = gh->height/ARROWHEAD_DIVIDER;
- arw[6].x = 0; arw[6].y = gh->height/ARROWHEAD_DIVIDER;
-
- gdispFillConvexPoly(gh->x, gh->y, arw, 7, pstyle->color_fill);
- gdispDrawPoly(gh->x, gh->y, arw, 7, pstyle->color_edge);
- gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter);
+ void gwinButtonDraw_ArrowUp(GWidgetObject *gw, void *param) {
+ const GColorSet * pcol;
+ (void) param;
+ point arw[7];
+
+ if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
+ pcol = getDrawColors(gw);
+
+ arw[0].x = gw->g.width/2; arw[0].y = 0;
+ arw[1].x = gw->g.width-1; arw[1].y = gw->g.height/ARROWHEAD_DIVIDER;
+ arw[2].x = (gw->g.width + gw->g.width/ARROWBODY_DIVIDER)/2; arw[2].y = gw->g.height/ARROWHEAD_DIVIDER;
+ arw[3].x = (gw->g.width + gw->g.width/ARROWBODY_DIVIDER)/2; arw[3].y = gw->g.height-1;
+ arw[4].x = (gw->g.width - gw->g.width/ARROWBODY_DIVIDER)/2; arw[4].y = gw->g.height-1;
+ arw[5].x = (gw->g.width - gw->g.width/ARROWBODY_DIVIDER)/2; arw[5].y = gw->g.height/ARROWHEAD_DIVIDER;
+ arw[6].x = 0; arw[6].y = gw->g.height/ARROWHEAD_DIVIDER;
+
+ gdispFillArea(gw->g.x, gw->g.y, ld, ld, gw->pstyle->background);
+ gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->fill);
+ gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->edge);
+ gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter);
}
- void gwinButtonDraw_ArrowDown(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) {
- (void) enabled;
- (void) isdown;
- (void) param;
- point arw[7];
-
- arw[0].x = gh->width/2; arw[0].y = gh->height-1;
- arw[1].x = gh->width-1; arw[1].y = gh->height-1-gh->height/ARROWHEAD_DIVIDER;
- arw[2].x = (gh->width + gh->width/ARROWBODY_DIVIDER)/2; arw[2].y = gh->height-1-gh->height/ARROWHEAD_DIVIDER;
- arw[3].x = (gh->width + gh->width/ARROWBODY_DIVIDER)/2; arw[3].y = 0;
- arw[4].x = (gh->width - gh->width/ARROWBODY_DIVIDER)/2; arw[4].y = 0;
- arw[5].x = (gh->width - gh->width/ARROWBODY_DIVIDER)/2; arw[5].y = gh->height-1-gh->height/ARROWHEAD_DIVIDER;
- arw[6].x = 0; arw[6].y = gh->height-1-gh->height/ARROWHEAD_DIVIDER;
-
- gdispFillConvexPoly(gh->x, gh->y, arw, 7, pstyle->color_fill);
- gdispDrawPoly(gh->x, gh->y, arw, 7, pstyle->color_edge);
- gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter);
+ void gwinButtonDraw_ArrowDown(GWidgetObject *gw, void *param) {
+ const GColorSet * pcol;
+ (void) param;
+ point arw[7];
+
+ if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
+ pcol = getDrawColors(gw);
+
+ arw[0].x = gw->g.width/2; arw[0].y = gw->g.height-1;
+ arw[1].x = gw->g.width-1; arw[1].y = gw->g.height-1-gw->g.height/ARROWHEAD_DIVIDER;
+ arw[2].x = (gw->g.width + gw->g.width/ARROWBODY_DIVIDER)/2; arw[2].y = gw->g.height-1-gw->g.height/ARROWHEAD_DIVIDER;
+ arw[3].x = (gw->g.width + gw->g.width/ARROWBODY_DIVIDER)/2; arw[3].y = 0;
+ arw[4].x = (gw->g.width - gw->g.width/ARROWBODY_DIVIDER)/2; arw[4].y = 0;
+ arw[5].x = (gw->g.width - gw->g.width/ARROWBODY_DIVIDER)/2; arw[5].y = gw->g.height-1-gw->g.height/ARROWHEAD_DIVIDER;
+ arw[6].x = 0; arw[6].y = gw->g.height-1-gw->g.height/ARROWHEAD_DIVIDER;
+
+ gdispFillArea(gw->g.x, gw->g.y, ld, ld, gw->pstyle->background);
+ gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->fill);
+ gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->edge);
+ gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter);
}
- void gwinButtonDraw_ArrowLeft(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) {
- (void) enabled;
- (void) isdown;
- (void) param;
- point arw[7];
-
- arw[0].x = 0; arw[0].y = gh->height/2;
- arw[1].x = gh->width/ARROWHEAD_DIVIDER; arw[1].y = 0;
- arw[2].x = gh->width/ARROWHEAD_DIVIDER; arw[2].y = (gh->height - gh->height/ARROWBODY_DIVIDER)/2;
- arw[3].x = gh->width-1; arw[3].y = (gh->height - gh->height/ARROWBODY_DIVIDER)/2;
- arw[4].x = gh->width-1; arw[4].y = (gh->height + gh->height/ARROWBODY_DIVIDER)/2;
- arw[5].x = gh->width/ARROWHEAD_DIVIDER; arw[5].y = (gh->height + gh->height/ARROWBODY_DIVIDER)/2;
- arw[6].x = gh->width/ARROWHEAD_DIVIDER; arw[6].y = gh->height-1;
-
- gdispFillConvexPoly(gh->x, gh->y, arw, 7, pstyle->color_fill);
- gdispDrawPoly(gh->x, gh->y, arw, 7, pstyle->color_edge);
- gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter);
+ void gwinButtonDraw_ArrowLeft(GWidgetObject *gw, void *param) {
+ const GColorSet * pcol;
+ (void) param;
+ point arw[7];
+
+ if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
+ pcol = getDrawColors(gw);
+
+ arw[0].x = 0; arw[0].y = gw->g.height/2;
+ arw[1].x = gw->g.width/ARROWHEAD_DIVIDER; arw[1].y = 0;
+ arw[2].x = gw->g.width/ARROWHEAD_DIVIDER; arw[2].y = (gw->g.height - gw->g.height/ARROWBODY_DIVIDER)/2;
+ arw[3].x = gw->g.width-1; arw[3].y = (gw->g.height - gw->g.height/ARROWBODY_DIVIDER)/2;
+ arw[4].x = gw->g.width-1; arw[4].y = (gw->g.height + gw->g.height/ARROWBODY_DIVIDER)/2;
+ arw[5].x = gw->g.width/ARROWHEAD_DIVIDER; arw[5].y = (gw->g.height + gw->g.height/ARROWBODY_DIVIDER)/2;
+ arw[6].x = gw->g.width/ARROWHEAD_DIVIDER; arw[6].y = gw->g.height-1;
+
+ gdispFillArea(gw->g.x, gw->g.y, ld, ld, gw->pstyle->background);
+ gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->fill);
+ gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->edge);
+ gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter);
}
- void gwinButtonDraw_ArrowRight(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) {
- (void) enabled;
- (void) isdown;
- (void) param;
- point arw[7];
-
- arw[0].x = gh->width-1; arw[0].y = gh->height/2;
- arw[1].x = gh->width-1-gh->width/ARROWHEAD_DIVIDER; arw[1].y = 0;
- arw[2].x = gh->width-1-gh->width/ARROWHEAD_DIVIDER; arw[2].y = (gh->height - gh->height/ARROWBODY_DIVIDER)/2;
- arw[3].x = 0; arw[3].y = (gh->height - gh->height/ARROWBODY_DIVIDER)/2;
- arw[4].x = 0; arw[4].y = (gh->height + gh->height/ARROWBODY_DIVIDER)/2;
- arw[5].x = gh->width-1-gh->width/ARROWHEAD_DIVIDER; arw[5].y = (gh->height + gh->height/ARROWBODY_DIVIDER)/2;
- arw[6].x = gh->width-1-gh->width/ARROWHEAD_DIVIDER; arw[6].y = gh->height-1;
-
- gdispFillConvexPoly(gh->x, gh->y, arw, 7, pstyle->color_fill);
- gdispDrawPoly(gh->x, gh->y, arw, 7, pstyle->color_edge);
- gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter);
+ void gwinButtonDraw_ArrowRight(GWidgetObject *gw, void *param) {
+ const GColorSet * pcol;
+ (void) param;
+ point arw[7];
+
+ if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
+ pcol = getDrawColors(gw);
+
+ arw[0].x = gw->g.width-1; arw[0].y = gw->g.height/2;
+ arw[1].x = gw->g.width-1-gw->g.width/ARROWHEAD_DIVIDER; arw[1].y = 0;
+ arw[2].x = gw->g.width-1-gw->g.width/ARROWHEAD_DIVIDER; arw[2].y = (gw->g.height - gw->g.height/ARROWBODY_DIVIDER)/2;
+ arw[3].x = 0; arw[3].y = (gw->g.height - gw->g.height/ARROWBODY_DIVIDER)/2;
+ arw[4].x = 0; arw[4].y = (gw->g.height + gw->g.height/ARROWBODY_DIVIDER)/2;
+ arw[5].x = gw->g.width-1-gw->g.width/ARROWHEAD_DIVIDER; arw[5].y = (gw->g.height + gw->g.height/ARROWBODY_DIVIDER)/2;
+ arw[6].x = gw->g.width-1-gw->g.width/ARROWHEAD_DIVIDER; arw[6].y = gw->g.height-1;
+
+ gdispFillArea(gw->g.x, gw->g.y, ld, ld, gw->pstyle->background);
+ gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->fill);
+ gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->edge);
+ gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter);
}
#endif
-#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
- bool_t gwinAttachButtonMouse(GHandle gh, uint16_t instance) {
- GSourceHandle gsh;
-
- if (gh->type != GW_BUTTON || !(gsh = ginputGetMouse(instance)))
- return FALSE;
+#if GDISP_NEED_IMAGE || defined(__DOXYGEN__)
+ void gwinButtonDraw_Image(GWidgetObject *gw, void *param) {
+ const GColorSet * pcol;
+ coord_t sy;
- return geventAttachSource(&((GButtonObject *)gh)->listener, gsh, GLISTEN_MOUSEMETA);
- }
-#endif
+ if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
+ pcol = getDrawColors(gw);
-#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
- bool_t gwinAttachButtonToggle(GHandle gh, uint16_t instance) {
- GSourceHandle gsh;
-
- if (gh->type != GW_BUTTON || !(gsh = ginputGetToggle(instance)))
- return FALSE;
+ if (!(gw->g.flags & GWIN_FLG_ENABLED)) {
+ sy = 2 * gw->g.height;
+ } else if ((gw->g.flags & GBUTTON_FLG_PRESSED)) {
+ sy = gw->g.height;
+ } else {
+ sy = 0;
+ }
- return geventAttachSource(&((GButtonObject *)gh)->listener, gsh, GLISTEN_TOGGLE_OFF|GLISTEN_TOGGLE_ON);
+ gdispImageDraw((gdispImage *)param, gw->g.x, gw->g.y, gw->g.width, gw->g.height, 0, sy);
+ gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter);
}
#endif
diff --git a/src/gwin/checkbox.c b/src/gwin/checkbox.c
index faea0ef9..84eb3b9f 100644
--- a/src/gwin/checkbox.c
+++ b/src/gwin/checkbox.c
@@ -7,7 +7,7 @@
/**
* @file src/gwin/checkbox.c
- * @brief GWIN sub-system checkbox code.
+ * @brief GWIN sub-system button code.
*
* @defgroup Checkbox Checkbox
* @ingroup GWIN
@@ -19,168 +19,178 @@
#if (GFX_USE_GWIN && GWIN_NEED_CHECKBOX) || defined(__DOXYGEN__)
-static const GCheckboxColor defaultColors = {
- Grey, // border
- Grey, // selected
- Black // background
-};
-
-/* default style drawing routine */
-static void gwinCheckboxDrawDefaultStyle(GHandle gh, bool_t enabled, bool_t isChecked, void* param) {
- #define gcw ((GCheckboxObject *)gh)
+#include "gwin/class_gwin.h"
- (void) enabled;
- (void) param;
+// Our checked state
+#define GCHECKBOX_FLG_CHECKED (GWIN_FIRST_CONTROL_FLAG<<0)
- gdispDrawBox(gh->x, gh->y, gh->width, gh->height, gcw->colors->border);
+// Send the checkbox event
+static void SendCheckboxEvent(GWidgetObject *gw) {
+ GSourceListener * psl;
+ GEvent * pe;
+ #define pce ((GEventGWinCheckbox *)pe)
- if (isChecked)
- gdispFillArea(gh->x+2, gh->y+2, gh->width-4, gh->height-4, gcw->colors->checked);
- else
- gdispFillArea(gh->x+2, gh->y+2, gh->width-4, gh->height-4, gcw->colors->bg);
+ // Trigger a GWIN Checkbox Event
+ psl = 0;
+ while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) {
+ if (!(pe = geventGetEventBuffer(psl)))
+ continue;
+ pce->type = GEVENT_GWIN_CHECKBOX;
+ pce->checkbox = &gw->g;
+ pce->isChecked = (gw->g.flags & GCHECKBOX_FLG_CHECKED) ? TRUE : FALSE;
+ geventSendEvent(psl);
+ }
- #undef gcw
+ #undef pce
}
-/* process an event callback */
-static void gwinCheckboxCallback(void *param, GEvent *pe) {
- GSourceListener *psl;
- #define gh ((GHandle)param)
- #define gbw ((GCheckboxObject *)param)
- #define gsh ((GSourceHandle)param)
- #define pme ((GEventMouse *)pe)
- #define pte ((GEventTouch *)pe)
- #define pxe ((GEventToggle *)pe)
- #define pbe ((GEventGWinCheckbox *)pe)
-
- /* check if checkbox is disabled */
- if (!gh->enabled)
- return;
-
- switch (pe->type) {
- #if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
- case GEVENT_MOUSE:
- case GEVENT_TOUCH:
-
- // Ignore anything other than the primary mouse button going up or down
- if (!((pme->current_buttons ^ pme->last_buttons) & GINPUT_MOUSE_BTN_LEFT))
- return;
-
- if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)
- && pme->x >= gbw->gwin.x && pme->x < gbw->gwin.x + gbw->gwin.width
- && pme->y >= gbw->gwin.y && pme->y < gbw->gwin.y + gbw->gwin.height) {
+#if GINPUT_NEED_MOUSE
+ static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) {
+ (void) x; (void) y;
+ gw->g.flags ^= GCHECKBOX_FLG_CHECKED;
+ _gwidgetRedraw((GHandle)gw);
+ SendCheckboxEvent(gw);
+ }
+#endif
- gbw->isChecked = !gbw->isChecked;
+#if GINPUT_NEED_TOGGLE
+ static void ToggleOn(GWidgetObject *gw, uint16_t role) {
+ (void) role;
+ gw->g.flags ^= GCHECKBOX_FLG_CHECKED;
+ _gwidgetRedraw((GHandle)gw);
+ SendCheckboxEvent(gw);
+ }
- gwinCheckboxDraw((GHandle)param);
- break;
- }
- return;
- #endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */
+ static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) {
+ (void) role;
+ ((GCheckboxObject *)gw)->toggle = instance;
+ }
- default:
- return;
+ static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role) {
+ (void) role;
+ return ((GCheckboxObject *)gw)->toggle;
}
+#endif
- // Trigger a GWIN checkbox event
- psl = 0;
- while ((psl = geventGetSourceListener(gsh, psl))) {
- if (!(pe = geventGetEventBuffer(psl)))
- continue;
- pbe->type = GEVENT_GWIN_CHECKBOX;
- pbe->checkbox = gh;
- pbe->isChecked = gbw->isChecked;
- geventSendEvent(psl);
- }
-
- #undef gh
- #undef pbe
- #undef pme
- #undef pte
- #undef pxe
- #undef gsh
- #undef gbw
-}
+// The checkbox VMT table
+static const gwidgetVMT checkboxVMT = {
+ {
+ "Checkbox", // The classname
+ sizeof(GCheckboxObject),// The object size
+ _gwidgetDestroy, // The destroy routine
+ _gwidgetRedraw, // The redraw routine
+ 0, // The after-clear routine
+ },
+ gwinCheckboxDraw_CheckOnLeft, // The default drawing routine
+ #if GINPUT_NEED_MOUSE
+ {
+ MouseDown, // Process mouse down events
+ 0, // Process mouse up events (NOT USED)
+ 0, // Process mouse move events (NOT USED)
+ },
+ #endif
+ #if GINPUT_NEED_TOGGLE
+ {
+ 1, // 1 toggle role
+ ToggleAssign, // Assign Toggles
+ ToggleGet, // Get Toggles
+ 0, // Process toggle off events (NOT USED)
+ ToggleOn, // Process toggle on events
+ },
+ #endif
+ #if GINPUT_NEED_DIAL
+ {
+ 0, // No dial roles
+ 0, // Assign Dials (NOT USED)
+ 0, // Get Dials (NOT USED)
+ 0, // Process dial move events (NOT USED)
+ },
+ #endif
+};
-GHandle gwinCheckboxCreate(GCheckboxObject *gb, coord_t x, coord_t y, coord_t width, coord_t height) {
- if (!(gb = (GCheckboxObject *)_gwinInit((GWindowObject *)gb, x, y, width, height, sizeof(GCheckboxObject))))
+GHandle gwinCheckboxCreate(GCheckboxObject *gb, const GWidgetInit *pInit) {
+ if (!(gb = (GCheckboxObject *)_gwidgetCreate(&gb->w, pInit, &checkboxVMT)))
return 0;
- gb->gwin.type = GW_CHECKBOX; // create a window of the type checkbox
- gb->fn = gwinCheckboxDrawDefaultStyle; // set the default style drawing routine
- gb->colors = &defaultColors; // asign the default colors
- gb->param = 0; // some safe value here
- gb->isChecked = GCHBX_UNCHECKED; // checkbox is currently unchecked
- gb->gwin.enabled = TRUE; // checkboxes are enabled by default
-
- geventListenerInit(&gb->listener);
- geventRegisterCallback(&gb->listener, gwinCheckboxCallback, gb);
-
- // checkboxes are enabled by default
- gb->gwin.enabled = TRUE;
-
+ #if GINPUT_NEED_TOGGLE
+ gb->toggle = GWIDGET_NO_INSTANCE;
+ #endif
+ gwinSetVisible((GHandle)gb, pInit->g.show);
return (GHandle)gb;
}
-void gwinCheckboxSetCustom(GHandle gh, GCheckboxDrawFunction fn, void *param) {
- #define gcw ((GCheckboxObject *)gh)
-
- if (gh->type != GW_CHECKBOX)
+void gwinCheckboxCheck(GHandle gh, bool_t isChecked) {
+ if (gh->vmt != (gwinVMT *)&checkboxVMT)
return;
- gcw->fn = fn;
- gcw->param = param;
-
- #undef gcw
+ 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;
+ }
+ _gwidgetRedraw(gh);
+ SendCheckboxEvent((GWidgetObject *)gh);
}
+bool_t gwinCheckboxIsChecked(GHandle gh) {
+ if (gh->vmt != (gwinVMT *)&checkboxVMT)
+ return FALSE;
-void gwinCheckboxSetEnabled(GHandle gh, bool_t enabled) {
- if (gh->type != GW_CHECKBOX)
- return;
+ return (gh->flags & GCHECKBOX_FLG_CHECKED) ? TRUE : FALSE;
+}
+
+/*----------------------------------------------------------
+ * Custom Draw Routines
+ *----------------------------------------------------------*/
- gh->enabled = enabled;
+static const GColorSet *getDrawColors(GWidgetObject *gw) {
+ if (!(gw->g.flags & GWIN_FLG_ENABLED)) return &gw->pstyle->disabled;
+ if ((gw->g.flags & GCHECKBOX_FLG_CHECKED)) return &gw->pstyle->pressed;
+ return &gw->pstyle->enabled;
}
-void gwinCheckboxDraw(GHandle gh) {
- #define gcw ((GCheckboxObject *)gh)
+void gwinCheckboxDraw_CheckOnLeft(GWidgetObject *gw, void *param) {
+ #define gcw ((GCheckboxObject *)gw)
+ coord_t ld, df;
+ const GColorSet * pcol;
+ (void) param;
- if (gh->type != GW_CHECKBOX)
- return;
+ if (gw->g.vmt != (gwinVMT *)&checkboxVMT) return;
+ pcol = getDrawColors(gw);
- #if GDISP_NEED_CLIP
- //gdispSetClip(gh->x, gh->y, gh->width, gh->height);
- #endif
+ ld = gw->g.width < gw->g.height ? gw->g.width : gw->g.height;
+ gdispFillArea(gw->g.x+1, gw->g.y+1, ld, ld-2, gw->pstyle->background);
+ gdispDrawBox(gw->g.x, gw->g.y, ld, ld, pcol->edge);
- gcw->fn(gh,
- gcw->gwin.enabled,
- gcw->isChecked,
- gcw->param);
+ df = ld < 4 ? 1 : 2;
+ if (gw->g.flags & GCHECKBOX_FLG_CHECKED)
+ gdispFillArea(gw->g.x+df, gw->g.y+df, ld-2*df, ld-2*df, pcol->fill);
+ gdispFillStringBox(gw->g.x+ld+1, gw->g.y, gw->g.width-ld-1, gw->g.height, gw->text, gw->g.font, pcol->text, gw->pstyle->background, justifyLeft);
#undef gcw
}
-#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
- bool_t gwinCheckboxAttachMouse(GHandle gh, uint16_t instance) {
- GSourceHandle gsh;
+void gwinCheckboxDraw_CheckOnRight(GWidgetObject *gw, void *param) {
+ #define gcw ((GCheckboxObject *)gw)
+ coord_t ep, ld, df;
+ const GColorSet * pcol;
+ (void) param;
- if (gh->type != GW_CHECKBOX || !(gsh = ginputGetMouse(instance)))
- return FALSE;
+ if (gw->g.vmt != (gwinVMT *)&checkboxVMT) return;
+ pcol = getDrawColors(gw);
- return geventAttachSource(&((GCheckboxObject *)gh)->listener, gsh, GLISTEN_MOUSEMETA);
- }
-#endif
-
-void gwinCheckboxSetColors(GHandle gh, color_t border, color_t checked, color_t bg) {
- #define gcw ((GCheckboxObject *)gh)
-
- if (gh->type != GW_CHECKBOX)
- return;
+ ld = gw->g.width < gw->g.height ? gw->g.width : gw->g.height;
+ ep = gw->g.width-ld-1;
+ gdispFillArea(gw->g.x+ep-1, gw->g.y+1, ld, ld-2, gw->pstyle->background);
+ gdispDrawBox(gw->g.x+ep, gw->g.y, ld, ld, pcol->edge);
- gcw->colors->border = border;
- gcw->colors->checked = checked,
- gcw->colors->bg = bg;
+ df = ld < 4 ? 1 : 2;
+ if (gw->g.flags & GCHECKBOX_FLG_CHECKED)
+ gdispFillArea(gw->g.x+ep+df, gw->g.y+df, ld-2*df, ld-2*df, pcol->fill);
+ gdispFillStringBox(gw->g.x, gw->g.y, ep, gw->g.height, gw->text, gw->g.font, pcol->text, gw->pstyle->background, justifyRight);
#undef gcw
}
diff --git a/src/gwin/console.c b/src/gwin/console.c
index a4cd428c..06648e9b 100644
--- a/src/gwin/console.c
+++ b/src/gwin/console.c
@@ -8,20 +8,15 @@
/**
* @file src/gwin/console.c
* @brief GWIN sub-system console code.
- *
- * @defgroup Console Console
- * @ingroup GWIN
- *
- * @{
*/
#include "gfx.h"
-#if (GFX_USE_GWIN && GWIN_NEED_CONSOLE) || defined(__DOXYGEN__)
+#if GFX_USE_GWIN && GWIN_NEED_CONSOLE
#include <string.h>
-#include "gwin/internal.h"
+#include "gwin/class_gwin.h"
#define GWIN_CONSOLE_USE_CLEAR_LINES TRUE
#define GWIN_CONSOLE_USE_FILLED_CHARS FALSE
@@ -58,32 +53,48 @@
};
#endif
-GHandle gwinCreateConsole(GConsoleObject *gc, coord_t x, coord_t y, coord_t width, coord_t height, font_t font) {
- if (!(gc = (GConsoleObject *)_gwinInit((GWindowObject *)gc, x, y, width, height, sizeof(GConsoleObject))))
+static void AfterClear(GWindowObject *gh) {
+ ((GConsoleObject *)gh)->cx = 0;
+ ((GConsoleObject *)gh)->cy = 0;
+}
+
+static const gwinVMT consoleVMT = {
+ "Console", // The classname
+ sizeof(GConsoleObject), // The object size
+ 0, // The destroy routine
+ 0, // The redraw routine
+ AfterClear, // The after-clear routine
+};
+
+GHandle gwinConsoleCreate(GConsoleObject *gc, const GWindowInit *pInit) {
+ if (!(gc = (GConsoleObject *)_gwindowCreate(&gc->g, pInit, &consoleVMT, 0)))
return 0;
- gc->gwin.type = GW_CONSOLE;
- gwinSetFont(&gc->gwin, font);
#if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM
gc->stream.vmt = &GWindowConsoleVMT;
#endif
gc->cx = 0;
gc->cy = 0;
+ gwinSetVisible((GHandle)gc, pInit->show);
return (GHandle)gc;
}
#if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM
- BaseSequentialStream *gwinGetConsoleStream(GHandle gh) {
- if (gh->type != GW_CONSOLE)
+ BaseSequentialStream *gwinConsoleGetStream(GHandle gh) {
+ if (gh->vmt != &consoleVMT)
return 0;
return (BaseSequentialStream *)&(((GConsoleObject *)(gh))->stream);
}
#endif
void gwinPutChar(GHandle gh, char c) {
- uint8_t width;
#define gcw ((GConsoleObject *)gh)
+ uint8_t width, fy, fp;
+
+ if (gh->vmt != &consoleVMT || !gh->font)
+ return;
- if (gh->type != GW_CONSOLE || !gh->font) return;
+ fy = gdispGetFontMetric(gh->font, fontHeight);
+ fp = gdispGetFontMetric(gh->font, fontCharPadding);
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
@@ -91,24 +102,24 @@ void gwinPutChar(GHandle gh, char c) {
if (c == '\n') {
gcw->cx = 0;
- gcw->cy += gcw->fy;
+ gcw->cy += fy;
// We use lazy scrolling here and only scroll when the next char arrives
} else if (c == '\r') {
// gcw->cx = 0;
} else {
- width = gdispGetCharWidth(c, gh->font) + gcw->fp;
+ width = gdispGetCharWidth(c, gh->font) + fp;
if (gcw->cx + width >= gh->width) {
gcw->cx = 0;
- gcw->cy += gcw->fy;
+ gcw->cy += fy;
}
- if (gcw->cy + gcw->fy > gh->height) {
+ if (gcw->cy + fy > gh->height) {
#if GDISP_NEED_SCROLL
/* scroll the console */
- gdispVerticalScroll(gh->x, gh->y, gh->width, gh->height, gcw->fy, gh->bgcolor);
+ gdispVerticalScroll(gh->x, gh->y, gh->width, gh->height, fy, gh->bgcolor);
/* reset the cursor to the start of the last line */
gcw->cx = 0;
- gcw->cy = (((coord_t)(gh->height/gcw->fy))-1)*gcw->fy;
+ gcw->cy = (((coord_t)(gh->height/fy))-1)*fy;
#else
/* clear the console */
gdispFillArea(gh->x, gh->y, gh->width, gh->height, gh->bgcolor);
@@ -121,7 +132,7 @@ void gwinPutChar(GHandle gh, char c) {
#if GWIN_CONSOLE_USE_CLEAR_LINES
/* clear to the end of the line */
if (gcw->cx == 0)
- gdispFillArea(gh->x, gh->y + gcw->cy, gh->width, gcw->fy, gh->bgcolor);
+ gdispFillArea(gh->x, gh->y + gcw->cy, gh->width, fy, gh->bgcolor);
#endif
#if GWIN_CONSOLE_USE_FILLED_CHARS
gdispFillChar(gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, gh->color, gh->bgcolor);
@@ -200,7 +211,8 @@ void gwinPrintf(GHandle gh, const char *fmt, ...) {
char tmpbuf[MAX_FILLER + 1];
#endif
- if (gh->type != GW_CONSOLE || !gh->font) return;
+ if (gh->vmt != &consoleVMT || !gh->font)
+ return;
va_start(ap, fmt);
while (TRUE) {
@@ -343,5 +355,5 @@ void gwinPrintf(GHandle gh, const char *fmt, ...) {
}
#endif /* GFX_USE_GWIN && GWIN_NEED_CONSOLE */
-/** @} */
+
diff --git a/src/gwin/gimage.c b/src/gwin/gimage.c
new file mode 100644
index 00000000..2dcba4ba
--- /dev/null
+++ b/src/gwin/gimage.c
@@ -0,0 +1,175 @@
+/*
+ * 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://chibios-gfx.com/license.html
+ */
+
+/**
+ * @file src/gwin/image.c
+ * @brief GWIN sub-system image code.
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GWIN && GWIN_NEED_IMAGE
+
+#include "gwin/class_gwin.h"
+
+#define widget(gh) ((GImageObject *)gh)
+
+static void _destroy(GWindowObject *gh) {
+ if (gdispImageIsOpen(&widget(gh)->image))
+ gdispImageClose(&widget(gh)->image);
+}
+
+static void _redraw(GHandle gh) {
+ coord_t x, y, w, h, dx, dy;
+ color_t bg;
+
+ // The default display area
+ x = gh->x;
+ y = gh->y;
+ w = gh->width;
+ h = gh->height;
+ bg = gwinGetDefaultBgColor();
+
+ // If the image isn't open just clear the area
+ if (!gdispImageIsOpen(&widget(gh)->image)) {
+ gdispFillArea(x, y, w, h, bg);
+ return;
+ }
+
+ // Center horizontally if the area is larger than the image
+ if (widget(gh)->image.width < w) {
+ w = widget(gh)->image.width;
+ dx = (gh->width-w)/2;
+ x += dx;
+ if (dx)
+ gdispFillArea(gh->x, y, dx, h, bg);
+ gdispFillArea(x+w, y, gh->width-dx-w, h, bg);
+ dx = 0;
+ }
+
+ // Center image horizontally if the area is smaller than the image
+ else if (widget(gh)->image.width > w) {
+ dx = (widget(gh)->image.width - w)/2;
+ }
+
+ // Center vertically if the area is larger than the image
+ if (widget(gh)->image.height < h) {
+ h = widget(gh)->image.height;
+ dy = (gh->height-h)/2;
+ y += dy;
+ if (dy)
+ gdispFillArea(x, gh->y, w, dy, bg);
+ gdispFillArea(x, y+h, w, gh->height-dy-h, bg);
+ dy = 0;
+ }
+
+ // Center image vertically if the area is smaller than the image
+ else if (widget(gh)->image.height > h) {
+ dy = (widget(gh)->image.height - h)/2;
+ }
+
+ // Reset the background color in case it has changed
+ gdispImageSetBgColor(&widget(gh)->image, bg);
+
+ // Display the image
+ gdispImageDraw(&widget(gh)->image, x, y, w, h, dx, dy);
+}
+
+
+static const gwinVMT imageVMT = {
+ "Image", // The class name
+ sizeof(GImageObject), // The object size
+ _destroy, // The destroy routine
+ _redraw, // The redraw routine
+ 0, // The after-clear routine
+};
+
+GHandle gwinImageCreate(GImageObject *gobj, GWindowInit *pInit) {
+ if (!(gobj = (GImageObject *)_gwindowCreate(&gobj->g, pInit, &imageVMT, 0)))
+ return 0;
+
+ // Ensure the gdispImageIsOpen() gives valid results
+ gobj->image.type = 0;
+
+ gwinSetVisible((GHandle)gobj, pInit->show);
+
+ return (GHandle)gobj;
+}
+
+bool_t gwinImageOpenMemory(GHandle gh, const void* memory) {
+ if (gdispImageIsOpen(&widget(gh)->image))
+ gdispImageClose(&widget(gh)->image);
+
+ if (!gdispImageSetMemoryReader(&widget(gh)->image, memory))
+ return FALSE;
+
+ if (gdispImageOpen(&widget(gh)->image) != GDISP_IMAGE_ERR_OK)
+ return FALSE;
+
+ if ((gh->flags & GWIN_FLG_VISIBLE)) {
+ // Setting the clip here shouldn't be necessary if the redraw doesn't overdraw
+ // but we put it in for safety anyway
+ #if GDISP_NEED_CLIP
+ gdispSetClip(gh->x, gh->y, gh->width, gh->height);
+ #endif
+ _redraw(gh);
+ }
+ return TRUE;
+}
+
+#if defined(WIN32) || GFX_USE_OS_WIN32 || GFX_USE_OS_POSIX || defined(__DOXYGEN__)
+bool_t gwinImageOpenFile(GHandle gh, const char* filename) {
+ if (gdispImageIsOpen(&widget(gh)->image))
+ gdispImageClose(&widget(gh)->image);
+
+ if (!gdispImageSetFileReader(&widget(gh)->image, filename))
+ return FALSE;
+
+ if (gdispImageOpen(&widget(gh)->image) != GDISP_IMAGE_ERR_OK)
+ return FALSE;
+
+ if ((gh->flags & GWIN_FLG_VISIBLE)) {
+ // Setting the clip here shouldn't be necessary if the redraw doesn't overdraw
+ // but we put it in for safety anyway
+ #if GDISP_NEED_CLIP
+ gdispSetClip(gh->x, gh->y, gh->width, gh->height);
+ #endif
+ _redraw(gh);
+ }
+ return TRUE;
+}
+#endif
+
+#if GFX_USE_OS_CHIBIOS || defined(__DOXYGEN__)
+bool_t gwinImageOpenStream(GHandle gh, void *streamPtr) {
+ if (gdispImageIsOpen(&widget(gh)->image))
+ gdispImageClose(&widget(gh)->image);
+
+ if (!gdispImageSetBaseFileStreamReader(&widget(gh)->image, streamPtr))
+ return FALSE;
+
+ if (gdispImageOpen(&widget(gh)->image) != GDISP_IMAGE_ERR_OK)
+ return FALSE;
+
+ if ((gh->flags & GWIN_FLG_VISIBLE)) {
+ // Setting the clip here shouldn't be necessary if the redraw doesn't overdraw
+ // but we put it in for safety anyway
+ #if GDISP_NEED_CLIP
+ gdispSetClip(gh->x, gh->y, gh->width, gh->height);
+ #endif
+ _redraw(gh);
+ }
+ return TRUE;
+}
+#endif
+
+gdispImageError gwinImageCache(GHandle gh) {
+ return gdispImageCache(&widget(gh)->image);
+}
+
+#endif // GFX_USE_GWIN && GWIN_NEED_IMAGE
+/** @} */
diff --git a/src/gwin/graph.c b/src/gwin/graph.c
index 72dcce9d..de447f4f 100644
--- a/src/gwin/graph.c
+++ b/src/gwin/graph.c
@@ -8,18 +8,13 @@
/**
* @file src/gwin/graph.c
* @brief GWIN sub-system button code.
- *
- * @defgroup Graph Graph
- * @ingroup GWIN
- *
- * @{
*/
#include "gfx.h"
-#if (GFX_USE_GWIN && GWIN_NEED_GRAPH) || defined(__DOXYGEN__)
+#if GFX_USE_GWIN && GWIN_NEED_GRAPH
-#include "gwin/internal.h"
+#include "gwin/class_gwin.h"
#define GGRAPH_FLG_CONNECTPOINTS (GWIN_FIRST_CONTROL_FLAG<<0)
#define GGRAPH_ARROW_SIZE 5
@@ -34,13 +29,21 @@ static const GGraphStyle GGraphDefaultStyle = {
GWIN_GRAPH_STYLE_XAXIS_ARROWS|GWIN_GRAPH_STYLE_YAXIS_ARROWS // flags
};
+static const gwinVMT graphVMT = {
+ "Graph", // The classname
+ sizeof(GGraphObject), // The object size
+ 0, // The destroy routine
+ 0, // The redraw routine
+ 0, // The after-clear routine
+};
+
static void pointto(GGraphObject *gg, coord_t x, coord_t y, const GGraphPointStyle *style) {
if (style->type == GGRAPH_POINT_NONE)
return;
// Convert to device space. Note the y-axis is inverted.
- x += gg->gwin.x + gg->xorigin;
- y = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y;
+ x += gg->g.x + gg->xorigin;
+ y = gg->g.y + gg->g.height - 1 - gg->yorigin - y;
if (style->size <= 1) {
gdispDrawPixel(x, y, style->color);
@@ -73,10 +76,10 @@ static void lineto(GGraphObject *gg, coord_t x0, coord_t y0, coord_t x1, coord_t
return;
// Convert to device space. Note the y-axis is inverted.
- x0 += gg->gwin.x + gg->xorigin;
- y0 = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y0;
- x1 += gg->gwin.x + gg->xorigin;
- y1 = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y1;
+ x0 += gg->g.x + gg->xorigin;
+ y0 = gg->g.y + gg->g.height - 1 - gg->yorigin - y0;
+ x1 += gg->g.x + gg->xorigin;
+ y1 = gg->g.y + gg->g.height - 1 - gg->yorigin - y1;
if (style->size <= 0) {
// Use the driver to draw a solid line
@@ -162,42 +165,28 @@ static void lineto(GGraphObject *gg, coord_t x0, coord_t y0, coord_t x1, coord_t
}
}
-GHandle gwinCreateGraph(GGraphObject *gg, coord_t x, coord_t y, coord_t width, coord_t height) {
- if (!(gg = (GGraphObject *)_gwinInit((GWindowObject *)gg, x, y, width, height, sizeof(GGraphObject))))
+GHandle gwinGraphCreate(GGraphObject *gg, const GWindowInit *pInit) {
+ if (!(gg = (GGraphObject *)_gwindowCreate(&gg->g, pInit, &graphVMT, 0)))
return 0;
- gg->gwin.type = GW_GRAPH;
gg->xorigin = gg->yorigin = 0;
gg->lastx = gg->lasty = 0;
- gwinGraphSetStyle(&gg->gwin, &GGraphDefaultStyle);
+ gwinGraphSetStyle((GHandle)gg, &GGraphDefaultStyle);
+ gwinSetVisible((GHandle)gg, pInit->show);
return (GHandle)gg;
}
void gwinGraphSetStyle(GHandle gh, const GGraphStyle *pstyle) {
#define gg ((GGraphObject *)gh)
- if (gh->type != GW_GRAPH)
+ if (gh->vmt != &graphVMT)
return;
- gg->style.point.type = pstyle->point.type;
- gg->style.point.size = pstyle->point.size;
- gg->style.point.color = pstyle->point.color;
- gg->style.line.type = pstyle->line.type;
- gg->style.line.size = pstyle->line.size;
- gg->style.line.color = pstyle->line.color;
- gg->style.xaxis.type = pstyle->xaxis.type;
- gg->style.xaxis.size = pstyle->xaxis.size;
- gg->style.xaxis.color = pstyle->xaxis.color;
- gg->style.yaxis.type = pstyle->yaxis.type;
- gg->style.yaxis.size = pstyle->yaxis.size;
- gg->style.yaxis.color = pstyle->yaxis.color;
- gg->style.xgrid.type = pstyle->xgrid.type;
- gg->style.xgrid.size = pstyle->xgrid.size;
- gg->style.xgrid.color = pstyle->xgrid.color;
- gg->style.xgrid.spacing = pstyle->xgrid.spacing;
- gg->style.ygrid.type = pstyle->ygrid.type;
- gg->style.ygrid.size = pstyle->ygrid.size;
- gg->style.ygrid.color = pstyle->ygrid.color;
- gg->style.ygrid.spacing = pstyle->ygrid.spacing;
+ gg->style.point = pstyle->point;
+ gg->style.line = pstyle->line;
+ gg->style.xaxis = pstyle->xaxis;
+ gg->style.yaxis = pstyle->yaxis;
+ gg->style.xgrid = pstyle->xgrid;
+ gg->style.ygrid = pstyle->ygrid;
gg->style.flags = pstyle->flags;
#undef gg
@@ -206,7 +195,7 @@ void gwinGraphSetStyle(GHandle gh, const GGraphStyle *pstyle) {
void gwinGraphSetOrigin(GHandle gh, coord_t x, coord_t y) {
#define gg ((GGraphObject *)gh)
- if (gh->type != GW_GRAPH)
+ if (gh->vmt != &graphVMT)
return;
gg->xorigin = x;
@@ -219,7 +208,7 @@ void gwinGraphDrawAxis(GHandle gh) {
#define gg ((GGraphObject *)gh)
coord_t i, xmin, ymin, xmax, ymax;
- if (gh->type != GW_GRAPH)
+ if (gh->vmt != &graphVMT)
return;
xmin = -gg->xorigin;
@@ -277,7 +266,7 @@ void gwinGraphDrawAxis(GHandle gh) {
}
void gwinGraphStartSet(GHandle gh) {
- if (gh->type != GW_GRAPH)
+ if (gh->vmt != &graphVMT)
return;
gh->flags &= ~GGRAPH_FLG_CONNECTPOINTS;
@@ -286,7 +275,7 @@ void gwinGraphStartSet(GHandle gh) {
void gwinGraphDrawPoint(GHandle gh, coord_t x, coord_t y) {
#define gg ((GGraphObject *)gh)
- if (gh->type != GW_GRAPH)
+ if (gh->vmt != &graphVMT)
return;
if ((gh->flags & GGRAPH_FLG_CONNECTPOINTS)) {
@@ -314,7 +303,7 @@ void gwinGraphDrawPoints(GHandle gh, const point *points, unsigned count) {
unsigned i;
const point *p;
- if (gh->type != GW_GRAPH)
+ if (gh->vmt != &graphVMT)
return;
// Draw the connecting lines
@@ -344,5 +333,3 @@ void gwinGraphDrawPoints(GHandle gh, const point *points, unsigned count) {
}
#endif /* GFX_USE_GWIN && GWIN_NEED_GRAPH */
-/** @} */
-
diff --git a/src/gwin/gwidget.c b/src/gwin/gwidget.c
new file mode 100644
index 00000000..8fc6ba77
--- /dev/null
+++ b/src/gwin/gwidget.c
@@ -0,0 +1,461 @@
+/*
+ * 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://chibios-gfx.com/license.html
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GWIN && GWIN_NEED_WIDGET
+
+#include <string.h>
+
+#include "gwin/class_gwin.h"
+
+/* Our listener for events for widgets */
+static GListener gl;
+
+/* Our default style - a white background theme */
+const GWidgetStyle WhiteWidgetStyle = {
+ HTML2COLOR(0xFFFFFF), // window background
+
+ // enabled color set
+ {
+ HTML2COLOR(0x000000), // text
+ HTML2COLOR(0x404040), // edge
+ HTML2COLOR(0xE0E0E0), // fill
+ HTML2COLOR(0xE0E0E0), // progress - inactive area
+ },
+
+ // disabled color set
+ {
+ HTML2COLOR(0xC0C0C0), // text
+ HTML2COLOR(0x808080), // edge
+ HTML2COLOR(0xE0E0E0), // fill
+ HTML2COLOR(0xC0E0C0), // progress - active area
+ },
+
+ // pressed color set
+ {
+ HTML2COLOR(0x404040), // text
+ HTML2COLOR(0x404040), // edge
+ HTML2COLOR(0x808080), // fill
+ HTML2COLOR(0x00E000), // progress - active area
+ },
+};
+
+/* Our black style */
+const GWidgetStyle BlackWidgetStyle = {
+ HTML2COLOR(0x000000), // window background
+
+ // enabled color set
+ {
+ HTML2COLOR(0xC0C0C0), // text
+ HTML2COLOR(0xC0C0C0), // edge
+ HTML2COLOR(0x606060), // fill
+ HTML2COLOR(0x404040), // progress - inactive area
+ },
+
+ // disabled color set
+ {
+ HTML2COLOR(0x808080), // text
+ HTML2COLOR(0x404040), // edge
+ HTML2COLOR(0x404040), // fill
+ HTML2COLOR(0x004000), // progress - active area
+ },
+
+ // pressed color set
+ {
+ HTML2COLOR(0xFFFFFF), // text
+ HTML2COLOR(0xC0C0C0), // edge
+ HTML2COLOR(0xE0E0E0), // fill
+ HTML2COLOR(0x008000), // progress - active area
+ },
+};
+
+static const GWidgetStyle * defaultStyle = &BlackWidgetStyle;
+
+/* We use these everywhere in this file */
+#define gw ((GWidgetObject *)gh)
+#define wvmt ((gwidgetVMT *)gh->vmt)
+
+/* Process an event */
+static void gwidgetEvent(void *param, GEvent *pe) {
+ #define gh QItem2GWindow(qi)
+ #define pme ((GEventMouse *)pe)
+ #define pte ((GEventToggle *)pe)
+ #define pde ((GEventDial *)pe)
+
+ const gfxQueueASyncItem * qi;
+ #if GFX_USE_GINPUT && (GINPUT_NEED_TOGGLE || GINPUT_NEED_DIAL)
+ uint16_t role;
+ #endif
+ (void) param;
+
+ // Process various events
+ switch (pe->type) {
+
+ #if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
+ case GEVENT_MOUSE:
+ case GEVENT_TOUCH:
+ // Cycle through all windows
+ for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) {
+
+ // check if it a widget that is enabled and visible
+ if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE))
+ continue;
+
+ // Are we captured?
+ if ((gw->g.flags & GWIN_FLG_MOUSECAPTURE)) {
+ if ((pme->last_buttons & ~pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)) {
+ gw->g.flags &= ~GWIN_FLG_MOUSECAPTURE;
+ if (wvmt->MouseUp)
+ wvmt->MouseUp(gw, pme->x - gw->g.x, pme->y - gw->g.y);
+ } else if (wvmt->MouseMove)
+ wvmt->MouseMove(gw, pme->x - gw->g.x, pme->y - gw->g.y);
+
+ // We are not captured - look for mouse downs over the widget
+ } else if ((~pme->last_buttons & pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)
+ && pme->x >= gw->g.x && pme->x < gw->g.x + gw->g.width
+ && pme->y >= gw->g.y && pme->y < gw->g.y + gw->g.height) {
+ gw->g.flags |= GWIN_FLG_MOUSECAPTURE;
+ if (wvmt->MouseDown)
+ wvmt->MouseDown(gw, pme->x - gw->g.x, pme->y - gw->g.y);
+ }
+ }
+ break;
+ #endif
+
+ #if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
+ case GEVENT_TOGGLE:
+ // Cycle through all windows
+ for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) {
+
+ // check if it a widget that is enabled and visible
+ if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE))
+ continue;
+
+ for(role = 0; role < wvmt->toggleroles; role++) {
+ if (wvmt->ToggleGet(gw, role) == pte->instance) {
+ if (pte->on) {
+ if (wvmt->ToggleOn)
+ wvmt->ToggleOn(gw, role);
+ } else {
+ if (wvmt->ToggleOff)
+ wvmt->ToggleOff(gw, role);
+ }
+ }
+ }
+ }
+ break;
+ #endif
+
+ #if GFX_USE_GINPUT && GINPUT_NEED_DIAL
+ case GEVENT_DIAL:
+ // Cycle through all windows
+ for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) {
+
+ // check if it a widget that is enabled and visible
+ if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE))
+ continue;
+
+ for(role = 0; role < wvmt->dialroles; role++) {
+ if (wvmt->DialGet(gw, role) == pte->instance) {
+ if (wvmt->DialMove)
+ wvmt->DialMove(gw, role, pde->value, pde->maxvalue);
+ }
+ }
+ }
+ break;
+ #endif
+
+ default:
+ break;
+ }
+
+ #undef gh
+ #undef pme
+ #undef pte
+ #undef pde
+}
+
+#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
+ static GHandle FindToggleUser(uint16_t instance) {
+ #define gh QItem2GWindow(qi)
+ const gfxQueueASyncItem * qi;
+ uint16_t role;
+
+ for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) {
+ if (!(gh->flags & GWIN_FLG_WIDGET)) // check if it a widget
+ continue;
+
+ for(role = 0; role < wvmt->toggleroles; role++) {
+ if (wvmt->ToggleGet(gw, role) == instance)
+ return gh;
+ }
+ }
+ return 0;
+ #undef gh
+ }
+#endif
+
+#if GFX_USE_GINPUT && GINPUT_NEED_DIAL
+ static GHandle FindDialUser(uint16_t instance) {
+ #define gh QItem2GWindow(qi)
+ const gfxQueueASyncItem * qi;
+ uint16_t role;
+
+ for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) {
+ if (!(gh->flags & GWIN_FLG_WIDGET)) // check if it a widget
+ continue;
+
+ for(role = 0; role < wvmt->dialroles; role++) {
+ if (wvmt->DialGet(gw, role) == instance)
+ return gh;
+ }
+ }
+ return 0;
+ #undef gh
+ }
+#endif
+
+void _gwidgetInit(void) {
+ geventListenerInit(&gl);
+ geventRegisterCallback(&gl, gwidgetEvent, 0);
+}
+
+GHandle _gwidgetCreate(GWidgetObject *pgw, const GWidgetInit *pInit, const gwidgetVMT *vmt) {
+ if (!(pgw = (GWidgetObject *)_gwindowCreate(&pgw->g, &pInit->g, &vmt->g, GWIN_FLG_WIDGET|GWIN_FLG_ENABLED)))
+ return 0;
+
+ pgw->text = pInit->text ? pInit->text : "";
+ pgw->fnDraw = pInit->customDraw ? pInit->customDraw : vmt->DefaultDraw;
+ pgw->fnParam = pInit->customParam;
+ pgw->pstyle = pInit->customStyle ? pInit->customStyle : defaultStyle;
+
+ return &pgw->g;
+}
+
+void _gwidgetDestroy(GHandle gh) {
+ #if GFX_USE_GINPUT && (GINPUT_NEED_TOGGLE || GINPUT_NEED_DIAL)
+ uint16_t role, instance;
+ #endif
+
+ // Deallocate the text (if necessary)
+ if ((gh->flags & GWIN_FLG_ALLOCTXT)) {
+ gh->flags &= ~GWIN_FLG_ALLOCTXT;
+ gfxFree((void *)gw->text);
+ }
+
+ #if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
+ // Detach any toggles from this object
+ for(role = 0; role < wvmt->toggleroles; role++) {
+ instance = wvmt->ToggleGet(gw, role);
+ if (instance != GWIDGET_NO_INSTANCE) {
+ wvmt->ToggleAssign(gw, role, GWIDGET_NO_INSTANCE);
+ if (!FindToggleUser(instance))
+ geventDetachSource(&gl, ginputGetToggle(instance));
+ }
+ }
+ #endif
+
+ #if GFX_USE_GINPUT && GINPUT_NEED_DIAL
+ // Detach any dials from this object
+ for(role = 0; role < wvmt->dialroles; role++) {
+ instance = wvmt->DialGet(gw, role);
+ if (instance != GWIDGET_NO_INSTANCE) {
+ wvmt->DialAssign(gw, role, GWIDGET_NO_INSTANCE);
+ if (!FindDialUser(instance))
+ geventDetachSource(&gl, ginputGetDial(instance));
+ }
+ }
+ #endif
+
+ // Remove any listeners on this object.
+ geventDetachSourceListeners((GSourceHandle)gh);
+}
+
+void _gwidgetRedraw(GHandle gh) {
+ if (!(gh->flags & GWIN_FLG_VISIBLE))
+ return;
+
+ #if GDISP_NEED_CLIP
+ gdispSetClip(gh->x, gh->y, gh->width, gh->height);
+ #endif
+
+ gw->fnDraw(gw, gw->fnParam);
+}
+
+void gwinSetDefaultStyle(const GWidgetStyle *pstyle, bool_t updateAll) {
+ if (!pstyle)
+ pstyle = &BlackWidgetStyle;
+
+ if (updateAll) {
+ const gfxQueueASyncItem * qi;
+ GHandle gh;
+
+ for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) {
+ gh = QItem2GWindow(qi);
+ if ((gh->flags & GWIN_FLG_WIDGET) && ((GWidgetObject *)gh)->pstyle == defaultStyle)
+ gwinSetStyle(gh, pstyle);
+ }
+ }
+ gwinSetDefaultBgColor(pstyle->background);
+ defaultStyle = pstyle;
+}
+
+/**
+ * @brief Get the current default style.
+ *
+ * @api
+ */
+const GWidgetStyle *gwinGetDefaultStyle(void) {
+ return defaultStyle;
+}
+
+
+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 = (char *)gfxAlloc(strlen(text)+1))) {
+ gh->flags |= GWIN_FLG_ALLOCTXT;
+ strcpy(str, text);
+ }
+ gw->text = (const char *)str;
+ } else
+ gw->text = text;
+ _gwidgetRedraw(gh);
+}
+
+const char *gwinGetText(GHandle gh) {
+ if (!(gh->flags & GWIN_FLG_WIDGET))
+ return 0;
+
+ return gw->text;
+}
+
+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;
+ _gwidgetRedraw(gh);
+}
+
+const GWidgetStyle *gwinGetStyle(GHandle gh) {
+ return gw->pstyle;
+}
+
+void gwinSetCustomDraw(GHandle gh, CustomWidgetDrawFunction fn, void *param) {
+ if (!(gh->flags & GWIN_FLG_WIDGET))
+ return;
+
+ gw->fnDraw = fn ? fn : wvmt->DefaultDraw;
+ gw->fnParam = param;
+ _gwidgetRedraw(gh);
+}
+
+bool_t gwinAttachListener(GListener *pl) {
+ return geventAttachSource(pl, GWIDGET_SOURCE, 0);
+}
+
+#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
+ bool_t gwinAttachMouse(uint16_t instance) {
+ GSourceHandle gsh;
+
+ if (!(gsh = ginputGetMouse(instance)))
+ return FALSE;
+
+ return geventAttachSource(&gl, gsh, GLISTEN_MOUSEMETA|GLISTEN_MOUSEDOWNMOVES);
+ }
+#endif
+
+#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
+ bool_t gwinAttachToggle(GHandle gh, uint16_t role, uint16_t instance) {
+ GSourceHandle gsh;
+ uint16_t oi;
+
+ // Is this a widget
+ if (!(gh->flags & GWIN_FLG_WIDGET))
+ return FALSE;
+
+ // Is the role valid
+ if (role >= wvmt->toggleroles)
+ return FALSE;
+
+ // Is this a valid device
+ if (!(gsh = ginputGetToggle(instance)))
+ return FALSE;
+
+ // Is this already done?
+ oi = wvmt->ToggleGet(gw, role);
+ if (instance == oi)
+ return TRUE;
+
+ // Remove the old instance
+ if (oi != GWIDGET_NO_INSTANCE) {
+ wvmt->ToggleAssign(gw, role, GWIDGET_NO_INSTANCE);
+ if (!FindToggleUser(oi))
+ geventDetachSource(&gl, ginputGetToggle(oi));
+ }
+
+ // Assign the new
+ wvmt->ToggleAssign(gw, role, instance);
+ return geventAttachSource(&gl, gsh, GLISTEN_TOGGLE_ON|GLISTEN_TOGGLE_OFF);
+ }
+#endif
+
+#if GFX_USE_GINPUT && GINPUT_NEED_DIAL
+ bool_t gwinAttachDial(GHandle gh, uint16_t role, uint16_t instance) {
+ GSourceHandle gsh;
+ uint16_t oi;
+
+ if (!(gh->flags & GWIN_FLG_WIDGET))
+ return FALSE;
+
+ // Is the role valid
+ if (role >= wvmt->dialroles)
+ return FALSE;
+
+ // Is this a valid device
+ if (!(gsh = ginputGetDial(instance)))
+ return FALSE;
+
+ // Is this already done?
+ oi = wvmt->DialGet(gw, role);
+ if (instance == oi)
+ return TRUE;
+
+ // Remove the old instance
+ if (oi != GWIDGET_NO_INSTANCE) {
+ wvmt->DialAssign(gw, role, GWIDGET_NO_INSTANCE);
+ if (!FindDialUser(oi))
+ geventDetachSource(&gl, ginputGetDial(oi));
+ }
+
+ // Assign the new
+ wvmt->DialAssign(gw, role, instance);
+ return geventAttachSource(&gl, gsh, 0);
+ }
+#endif
+
+#endif /* GFX_USE_GWIN && GWIN_NEED_WIDGET */
+/** @} */
diff --git a/src/gwin/gwin.c b/src/gwin/gwin.c
index 2f9d2dfd..e5997bc8 100644
--- a/src/gwin/gwin.c
+++ b/src/gwin/gwin.c
@@ -9,127 +9,278 @@
#if GFX_USE_GWIN
-#include "gwin/internal.h"
+#include "gwin/class_gwin.h"
+
+// Needed if there is no window manager
+#define MIN_WIN_WIDTH 1
+#define MIN_WIN_HEIGHT 1
+
+/*-----------------------------------------------
+ * Data
+ *-----------------------------------------------*/
+
+static const gwinVMT basegwinVMT = {
+ "GWIN", // The classname
+ sizeof(GWindowObject), // The object size
+ 0, // The destroy routine
+ 0, // The redraw routine
+ 0, // The after-clear routine
+};
+
+static color_t defaultFgColor = White;
+static color_t defaultBgColor = Black;
+#if GDISP_NEED_TEXT
+ static font_t defaultFont;
+#endif
+
+/*-----------------------------------------------
+ * Helper Routines
+ *-----------------------------------------------*/
+
+#if !GWIN_NEED_WINDOWMANAGER
+ static void _gwm_vis(GHandle gh) {
+ if (gh->vmt->Redraw) {
+ #if GDISP_NEED_CLIP
+ gdispSetClip(gh->x, gh->y, gh->width, gh->height);
+ #endif
+ gh->vmt->Redraw(gh);
+ } else
+ gwinClear(gh);
+ }
+ static void _gwm_redim(GHandle gh, coord_t x, coord_t y, coord_t width, coord_t height) {
+ gh->x = x; gh->y = y;
+ gh->width = width; gh->height = height;
+ if (gh->x < 0) { gh->width += gh->x; gh->x = 0; }
+ if (gh->y < 0) { gh->height += gh->y; gh->y = 0; }
+ if (gh->x > gdispGetWidth()-MIN_WIN_WIDTH) gh->x = gdispGetWidth()-MIN_WIN_WIDTH;
+ if (gh->y > gdispGetHeight()-MIN_WIN_HEIGHT) gh->y = gdispGetHeight()-MIN_WIN_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 > gdispGetWidth()) gh->width = gdispGetWidth() - gh->x;
+ if (gh->y+gh->height > gdispGetHeight()) gh->height = gdispGetHeight() - gh->y;
+
+ // Redraw the window
+ if ((gh->flags & GWIN_FLG_VISIBLE)) {
+ if (gh->vmt->Redraw) {
+ #if GDISP_NEED_CLIP
+ gdispSetClip(gh->x, gh->y, gh->width, gh->height);
+ #endif
+ gh->vmt->Redraw(gh);
+ }
+ }
+ }
+#endif
+
+/*-----------------------------------------------
+ * Class Routines
+ *-----------------------------------------------*/
+
+void _gwinInit(void) {
+ #if GWIN_NEED_WIDGET
+ extern void _gwidgetInit(void);
+
+ _gwidgetInit();
+ #endif
+ #if GWIN_NEED_WINDOWMANAGER
+ extern void _gwmInit(void);
+
+ _gwmInit();
+ #endif
+}
// Internal routine for use by GWIN components only
-// Initialise a window creating it dynamicly if required.
-GHandle _gwinInit(GWindowObject *gw, coord_t x, coord_t y, coord_t width, coord_t height, size_t size) {
- coord_t w, h;
-
- // Check the window size against the screen size
- w = gdispGetWidth();
- h = gdispGetHeight();
- if (x < 0) { width += x; x = 0; }
- if (y < 0) { height += y; y = 0; }
- if (x >= w || y >= h) return 0;
- if (x+width > w) width = w - x;
- if (y+height > h) height = h - y;
-
+// Initialise a window creating it dynamically if required.
+GHandle _gwindowCreate(GWindowObject *pgw, const GWindowInit *pInit, const gwinVMT *vmt, uint16_t flags) {
// Allocate the structure if necessary
- if (!gw) {
- if (!(gw = (GWindowObject *)gfxAlloc(size)))
+ if (!pgw) {
+ if (!(pgw = (GWindowObject *)gfxAlloc(vmt->size)))
return 0;
- gw->flags = GWIN_FLG_DYNAMIC;
+ pgw->flags = flags|GWIN_FLG_DYNAMIC;
} else
- gw->flags = 0;
+ pgw->flags = flags;
- // Initialise all basic fields (except the type)
- gw->x = x;
- gw->y = y;
- gw->width = width;
- gw->height = height;
- gw->color = White;
- gw->bgcolor = Black;
+ // Initialise all basic fields
+ pgw->vmt = vmt;
+ pgw->color = defaultFgColor;
+ pgw->bgcolor = defaultBgColor;
#if GDISP_NEED_TEXT
- gw->font = 0;
+ pgw->font = defaultFont;
#endif
- return (GHandle)gw;
-}
-GHandle gwinCreateWindow(GWindowObject *gw, coord_t x, coord_t y, coord_t width, coord_t height) {
- if (!(gw = (GWindowObject *)_gwinInit((GWindowObject *)gw, x, y, width, height, sizeof(GWindowObject))))
+#if GWIN_NEED_WINDOWMANAGER
+ if (!_GWINwm->vmt->Add(pgw, pInit)) {
+ if ((pgw->flags & GWIN_FLG_DYNAMIC))
+ gfxFree(pgw);
return 0;
- gw->type = GW_WINDOW;
- return (GHandle)gw;
+ }
+#else
+ _gwm_redim(pgw, pInit->x, pInit->y, pInit->width, pInit->height);
+#endif
+
+ return (GHandle)pgw;
}
-void gwinSetEnabled(GHandle gh, bool_t enabled) {
- (void)gh;
- (void)enabled;
+/*-----------------------------------------------
+ * Routines that affect all windows
+ *-----------------------------------------------*/
+
+void gwinSetDefaultColor(color_t clr) {
+ defaultFgColor = clr;
}
-void gwinDestroyWindow(GHandle gh) {
- // Clean up any type specific dynamic memory allocations
- switch(gh->type) {
-#if GWIN_NEED_BUTTON
- case GW_BUTTON:
- if ((gh->flags & GBTN_FLG_ALLOCTXT)) {
- gh->flags &= ~GBTN_FLG_ALLOCTXT; // To be sure, to be sure
- gfxFree((void *)((GButtonObject *)gh)->txt);
- }
- geventDetachSource(&((GButtonObject *)gh)->listener, 0);
- geventDetachSourceListeners((GSourceHandle)gh);
- break;
-#endif
-#if GWIN_NEED_SLIDER
- case GW_SLIDER:
- geventDetachSource(&((GSliderObject *)gh)->listener, 0);
- geventDetachSourceListeners((GSourceHandle)gh);
- break;
-#endif
- default:
- break;
+color_t gwinGetDefaultColor(void) {
+ return defaultFgColor;
+}
+
+void gwinSetDefaultBgColor(color_t bgclr) {
+ defaultBgColor = bgclr;
+}
+
+color_t gwinGetDefaultBgColor(void) {
+ return defaultBgColor;
+}
+
+#if GDISP_NEED_TEXT
+ void gwinSetDefaultFont(font_t font) {
+ defaultFont = font;
+ }
+
+ font_t gwinGetDefaultFont(void) {
+ return defaultFont;
}
+#endif
+
+/*-----------------------------------------------
+ * The GWindow Routines
+ *-----------------------------------------------*/
+
+GHandle gwinWindowCreate(GWindowObject *pgw, const GWindowInit *pInit) {
+ if (!(pgw = _gwindowCreate(pgw, pInit, &basegwinVMT, 0)))
+ return 0;
+ gwinSetVisible(pgw, pInit->show);
+ return pgw;
+}
+
+void gwinDestroy(GHandle gh) {
+ // Remove from the window manager
+ #if GWIN_NEED_WINDOWMANAGER
+ _GWINwm->vmt->Delete(gh);
+ #endif
+
+ // Class destroy routine
+ if (gh->vmt->Destroy)
+ gh->vmt->Destroy(gh);
// Clean up the structure
- if (gh->flags & GWIN_FLG_DYNAMIC) {
- gh->flags = 0; // To be sure, to be sure
+ if (gh->flags & GWIN_FLG_DYNAMIC)
gfxFree((void *)gh);
+
+ gh->flags = 0; // To be sure, to be sure
+}
+
+const char *gwinGetClassName(GHandle gh) {
+ return gh->vmt->classname;
+}
+
+void gwinSetVisible(GHandle gh, bool_t visible) {
+ if (visible) {
+ if (!(gh->flags & GWIN_FLG_VISIBLE)) {
+ gh->flags |= GWIN_FLG_VISIBLE;
+ #if GWIN_NEED_WINDOWMANAGER
+ _GWINwm->vmt->Visible(gh);
+ #else
+ _gwm_vis(gh);
+ #endif
+ }
+ } else {
+ if ((gh->flags & GWIN_FLG_VISIBLE)) {
+ gh->flags &= ~GWIN_FLG_VISIBLE;
+ #if GWIN_NEED_WINDOWMANAGER
+ _GWINwm->vmt->Visible(gh);
+ #endif
+ }
+ }
+}
+
+bool_t gwinGetVisible(GHandle gh) {
+ return (gh->flags & GWIN_FLG_VISIBLE) ? TRUE : FALSE;
+}
+
+void gwinSetEnabled(GHandle gh, bool_t enabled) {
+ if (enabled) {
+ if (!(gh->flags & GWIN_FLG_ENABLED)) {
+ gh->flags |= GWIN_FLG_ENABLED;
+ if ((gh->flags & GWIN_FLG_VISIBLE) && gh->vmt->Redraw) {
+ #if GDISP_NEED_CLIP
+ gdispSetClip(gh->x, gh->y, gh->width, gh->height);
+ #endif
+ gh->vmt->Redraw(gh);
+ }
+ }
+ } else {
+ if ((gh->flags & GWIN_FLG_ENABLED)) {
+ gh->flags &= ~GWIN_FLG_ENABLED;
+ if ((gh->flags & GWIN_FLG_VISIBLE) && gh->vmt->Redraw) {
+ #if GDISP_NEED_CLIP
+ gdispSetClip(gh->x, gh->y, gh->width, gh->height);
+ #endif
+ gh->vmt->Redraw(gh);
+ }
+ }
}
}
-void gwinDraw(GHandle gh) {
- switch(gh->type) {
- #if GWIN_NEED_BUTTON
- case GW_BUTTON:
- gwinButtonDraw(gh);
- break;
+bool_t gwinGetEnabled(GHandle gh) {
+ return (gh->flags & GWIN_FLG_ENABLED) ? TRUE : FALSE;
+}
+
+void gwinMove(GHandle gh, coord_t x, coord_t y) {
+ #if GWIN_NEED_WINDOWMANAGER
+ _GWINwm->vmt->Redim(gh, x, y, gh->width, gh->height);
+ #else
+ _gwm_redim(gh, x, y, gh->width, gh->height);
#endif
- #if GWIN_NEED_SLIDER
- case GW_SLIDER:
- gwinSliderDraw(gh);
- break;
+}
+
+void gwinResize(GHandle gh, coord_t width, coord_t height) {
+ #if GWIN_NEED_WINDOWMANAGER
+ _GWINwm->vmt->Redim(gh, gh->x, gh->y, width, height);
+ #else
+ _gwm_redim(gh, gh->x, gh->y, width, height);
+ #endif
+}
+
+void gwinRedraw(GHandle gh) {
+ #if GWIN_NEED_WINDOWMANAGER
+ gwinRaise(gh);
+ #else
+ if ((gh->flags & GWIN_FLG_VISIBLE))
+ _gwm_vis(gh);
#endif
- }
}
#if GDISP_NEED_TEXT
void gwinSetFont(GHandle gh, font_t font) {
gh->font = font;
- #if GWIN_NEED_CONSOLE
- if (font && gh->type == GW_CONSOLE) {
- ((GConsoleObject *)gh)->fy = gdispGetFontMetric(font, fontHeight);
- ((GConsoleObject *)gh)->fp = gdispGetFontMetric(font, fontCharPadding);
- }
- #endif
}
#endif
void gwinClear(GHandle gh) {
+ if (!((gh->flags & GWIN_FLG_VISIBLE)))
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
gdispFillArea(gh->x, gh->y, gh->width, gh->height, gh->bgcolor);
-
- #if GWIN_NEED_CONSOLE
- if (gh->type == GW_CONSOLE) {
- ((GConsoleObject *)gh)->cx = 0;
- ((GConsoleObject *)gh)->cy = 0;
- }
- #endif
+ if (gh->vmt->AfterClear)
+ gh->vmt->AfterClear(gh);
}
void gwinDrawPixel(GHandle gh, coord_t x, coord_t y) {
+ if (!((gh->flags & GWIN_FLG_VISIBLE)))
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
@@ -137,6 +288,9 @@ void gwinDrawPixel(GHandle gh, coord_t x, coord_t y) {
}
void gwinDrawLine(GHandle gh, coord_t x0, coord_t y0, coord_t x1, coord_t y1) {
+ if (!((gh->flags & GWIN_FLG_VISIBLE)))
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
@@ -144,6 +298,9 @@ void gwinDrawLine(GHandle gh, coord_t x0, coord_t y0, coord_t x1, coord_t y1) {
}
void gwinDrawBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) {
+ if (!((gh->flags & GWIN_FLG_VISIBLE)))
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
@@ -151,6 +308,9 @@ void gwinDrawBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) {
}
void gwinFillArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) {
+ if (!((gh->flags & GWIN_FLG_VISIBLE)))
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
@@ -158,6 +318,9 @@ void gwinFillArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) {
}
void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) {
+ if (!((gh->flags & GWIN_FLG_VISIBLE)))
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
@@ -166,6 +329,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor
#if GDISP_NEED_CIRCLE
void gwinDrawCircle(GHandle gh, coord_t x, coord_t y, coord_t radius) {
+ if (!((gh->flags & GWIN_FLG_VISIBLE)))
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
@@ -173,6 +339,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor
}
void gwinFillCircle(GHandle gh, coord_t x, coord_t y, coord_t radius) {
+ if (!((gh->flags & GWIN_FLG_VISIBLE)))
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
@@ -182,6 +351,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor
#if GDISP_NEED_ELLIPSE
void gwinDrawEllipse(GHandle gh, coord_t x, coord_t y, coord_t a, coord_t b) {
+ if (!((gh->flags & GWIN_FLG_VISIBLE)))
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
@@ -189,6 +361,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor
}
void gwinFillEllipse(GHandle gh, coord_t x, coord_t y, coord_t a, coord_t b) {
+ if (!((gh->flags & GWIN_FLG_VISIBLE)))
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
@@ -198,6 +373,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor
#if GDISP_NEED_ARC
void gwinDrawArc(GHandle gh, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle) {
+ if (!((gh->flags & GWIN_FLG_VISIBLE)))
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
@@ -205,6 +383,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor
}
void gwinFillArc(GHandle gh, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle) {
+ if (!((gh->flags & GWIN_FLG_VISIBLE)))
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
@@ -214,6 +395,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor
#if GDISP_NEED_PIXELREAD
color_t gwinGetPixelColor(GHandle gh, coord_t x, coord_t y) {
+ if (!((gh->flags & GWIN_FLG_VISIBLE)))
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
@@ -223,7 +407,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor
#if GDISP_NEED_TEXT
void gwinDrawChar(GHandle gh, coord_t x, coord_t y, char c) {
- if (!gh->font) return;
+ if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font)
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
@@ -231,7 +417,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor
}
void gwinFillChar(GHandle gh, coord_t x, coord_t y, char c) {
- if (!gh->font) return;
+ if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font)
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
@@ -239,7 +427,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor
}
void gwinDrawString(GHandle gh, coord_t x, coord_t y, const char *str) {
- if (!gh->font) return;
+ if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font)
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
@@ -247,7 +437,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor
}
void gwinFillString(GHandle gh, coord_t x, coord_t y, const char *str) {
- if (!gh->font) return;
+ if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font)
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
@@ -255,7 +447,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor
}
void gwinDrawStringBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify) {
- if (!gh->font) return;
+ if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font)
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
@@ -263,7 +457,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor
}
void gwinFillStringBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify) {
- if (!gh->font) return;
+ if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font)
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
@@ -273,6 +469,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor
#if GDISP_NEED_CONVEX_POLYGON
void gwinDrawPoly(GHandle gh, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt) {
+ if (!((gh->flags & GWIN_FLG_VISIBLE)))
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
@@ -280,6 +479,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor
}
void gwinFillConvexPoly(GHandle gh, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt) {
+ if (!((gh->flags & GWIN_FLG_VISIBLE)))
+ return;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
@@ -288,7 +490,10 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor
#endif
#if GDISP_NEED_IMAGE
- gdispImageError gwinImageDraw(GHandle gh, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) {
+ gdispImageError gwinDrawImage(GHandle gh, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) {
+ if (!((gh->flags & GWIN_FLG_VISIBLE)))
+ return GDISP_IMAGE_ERR_OK;
+
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
diff --git a/src/gwin/gwin.mk b/src/gwin/gwin.mk
index be6301c6..92b10b7b 100644
--- a/src/gwin/gwin.mk
+++ b/src/gwin/gwin.mk
@@ -1,7 +1,12 @@
GFXSRC += $(GFXLIB)/src/gwin/gwin.c \
+ $(GFXLIB)/src/gwin/gwidget.c \
+ $(GFXLIB)/src/gwin/gwm.c \
$(GFXLIB)/src/gwin/console.c \
+ $(GFXLIB)/src/gwin/graph.c \
$(GFXLIB)/src/gwin/button.c \
$(GFXLIB)/src/gwin/slider.c \
- $(GFXLIB)/src/gwin/graph.c \
$(GFXLIB)/src/gwin/checkbox.c \
-
+ $(GFXLIB)/src/gwin/gimage.c \
+ $(GFXLIB)/src/gwin/label.c \
+ $(GFXLIB)/src/gwin/radio.c \
+
diff --git a/src/gwin/gwm.c b/src/gwin/gwm.c
new file mode 100644
index 00000000..f9f56838
--- /dev/null
+++ b/src/gwin/gwm.c
@@ -0,0 +1,201 @@
+/*
+ * 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://chibios-gfx.com/license.html
+ */
+
+#include "gfx.h"
+
+// Used by the NULL window manager
+#define MIN_WIN_WIDTH 3
+#define MIN_WIN_HEIGHT 3
+
+/*-----------------------------------------------
+ * The default window manager (GNullWindowManager)
+ *-----------------------------------------------*/
+
+#if GFX_USE_GWIN && GWIN_NEED_WINDOWMANAGER
+
+#include "gwin/class_gwin.h"
+
+/*-----------------------------------------------
+ * Data
+ *-----------------------------------------------*/
+
+static void WM_Init(void);
+static void WM_DeInit(void);
+static bool_t WM_Add(GHandle gh, const GWindowInit *pInit);
+static void WM_Delete(GHandle gh);
+static void WM_Visible(GHandle gh);
+static void WM_Redim(GHandle gh, coord_t x, coord_t y, coord_t w, coord_t h);
+static void WM_Raise(GHandle gh);
+static void WM_MinMax(GHandle gh, GWindowMinMax minmax);
+
+static const gwmVMT GNullWindowManagerVMT = {
+ WM_Init,
+ WM_DeInit,
+ WM_Add,
+ WM_Delete,
+ WM_Visible,
+ WM_Redim,
+ WM_Raise,
+ WM_MinMax,
+};
+
+static const GWindowManager GNullWindowManager = {
+ &GNullWindowManagerVMT,
+};
+
+gfxQueueASync _GWINList;
+GWindowManager * _GWINwm;
+
+/*-----------------------------------------------
+ * Window Routines
+ *-----------------------------------------------*/
+
+void _gwmInit(void) {
+ gfxQueueASyncInit(&_GWINList);
+ _GWINwm = (GWindowManager *)&GNullWindowManager;
+ _GWINwm->vmt->Init();
+}
+
+void gwinSetWindowManager(struct GWindowManager *gwm) {
+ if (!gwm)
+ gwm = (GWindowManager *)&GNullWindowManager;
+ if (_GWINwm != gwm) {
+ _GWINwm->vmt->DeInit();
+ _GWINwm = gwm;
+ _GWINwm->vmt->Init();
+ }
+}
+
+void gwinSetMinMax(GHandle gh, GWindowMinMax minmax) {
+ _GWINwm->vmt->MinMax(gh, minmax);
+}
+
+void gwinRaise(GHandle gh) {
+ _GWINwm->vmt->Raise(gh);
+}
+
+GWindowMinMax gwinGetMinMax(GHandle gh) {
+ if (gh->flags & GWIN_FLG_MINIMIZED)
+ return GWIN_MINIMIZE;
+ if (gh->flags & GWIN_FLG_MAXIMIZED)
+ return GWIN_MAXIMIZE;
+ return GWIN_NORMAL;
+}
+
+/*-----------------------------------------------
+ * Window Manager Routines
+ *-----------------------------------------------*/
+
+static void WM_Init(void) {
+ // We don't need to do anything here.
+ // A full window manager would move the windows around, add borders etc
+
+ // clear the screen
+ // cycle through the windows already defined displaying them
+ // or cut all the window areas out of the screen and clear the remainder
+}
+
+static void WM_DeInit(void) {
+ // We don't need to do anything here.
+ // A full window manager would remove any borders etc
+}
+
+static bool_t WM_Add(GHandle gh, const GWindowInit *pInit) {
+ // Note the window will not be marked as visible yet
+
+ // Put it on the queue
+ gfxQueueASyncPut(&_GWINList, &gh->wmq);
+
+ // Make sure the size is valid
+ WM_Redim(gh, pInit->x, pInit->y, pInit->width, pInit->height);
+ return TRUE;
+}
+
+static void WM_Delete(GHandle gh) {
+ // Make the window invisible and clear the area underneath
+ if ((gh->flags & GWIN_FLG_VISIBLE)) {
+ gh->flags &= ~GWIN_FLG_VISIBLE;
+ gdispFillArea(gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor());
+ }
+
+ // Remove it from the queue
+ gfxQueueASyncRemove(&_GWINList, &gh->wmq);
+}
+
+static void WM_Visible(GHandle gh) {
+ #if GDISP_NEED_CLIP
+ gdispSetClip(gh->x, gh->y, gh->width, gh->height);
+ #endif
+ if ((gh->flags & GWIN_FLG_VISIBLE)) {
+ if (gh->vmt->Redraw)
+ gh->vmt->Redraw(gh);
+ else
+ gdispFillArea(gh->x, gh->y, gh->width, gh->height, gh->bgcolor);
+ // A real window manager would also redraw the borders here
+ } else
+ gdispFillArea(gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor());
+}
+
+static void WM_Redim(GHandle gh, coord_t x, coord_t y, coord_t w, coord_t h) {
+ // This is the simplest way of doing it - just clip the the screen
+ // If it won't fit on the screen move it around until it does.
+ if (x < 0) { w += x; x = 0; }
+ if (y < 0) { h += y; y = 0; }
+ if (x > gdispGetWidth()-MIN_WIN_WIDTH) x = gdispGetWidth()-MIN_WIN_WIDTH;
+ if (y > gdispGetHeight()-MIN_WIN_HEIGHT) y = gdispGetHeight()-MIN_WIN_HEIGHT;
+ if (w < MIN_WIN_WIDTH) { w = MIN_WIN_WIDTH; }
+ if (h < MIN_WIN_HEIGHT) { h = MIN_WIN_HEIGHT; }
+ if (x+w > gdispGetWidth()) w = gdispGetWidth() - x;
+ if (y+h > gdispGetHeight()) h = gdispGetHeight() - y;
+
+ // If there has been no resize just exit
+ if (gh->x == x && gh->y == y && gh->width == w && gh->height == h)
+ return;
+
+ // Clear the old area
+ if ((gh->flags & GWIN_FLG_VISIBLE))
+ gdispFillArea(gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor());
+
+ // Set the new size
+ gh->x = x; gh->y = y;
+ gh->width = w; gh->height = h;
+
+ // Redraw the window (if possible)
+ if ((gh->flags & GWIN_FLG_VISIBLE)) {
+ if (gh->vmt->Redraw) {
+ #if GDISP_NEED_CLIP
+ gdispSetClip(gh->x, gh->y, gh->width, gh->height);
+ #endif
+ gh->vmt->Redraw(gh);
+ }
+ }
+}
+
+static void WM_MinMax(GHandle gh, GWindowMinMax minmax) {
+ (void)gh; (void) minmax;
+ // We don't support minimising, maximising or restoring
+}
+
+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
+ if ((gh->flags & GWIN_FLG_VISIBLE)) {
+ if (gh->vmt->Redraw) {
+ #if GDISP_NEED_CLIP
+ gdispSetClip(gh->x, gh->y, gh->width, gh->height);
+ #endif
+ gh->vmt->Redraw(gh);
+ }
+ }
+}
+
+#endif /* GFX_USE_GWIN && GWIN_NEED_WINDOWMANAGER */
+/** @} */
diff --git a/src/gwin/label.c b/src/gwin/label.c
new file mode 100644
index 00000000..71ed18eb
--- /dev/null
+++ b/src/gwin/label.c
@@ -0,0 +1,118 @@
+/*
+ * 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://chibios-gfx.com/license.html
+ */
+
+/**
+ * @file include/gwin/label.h
+ * @brief GWIN label widget header file.
+ *
+ * @defgroup Label Label
+ * @ingroup GWIN
+ *
+ * @{
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GWIN && GWIN_NEED_LABEL
+
+#include "gwin/class_gwin.h"
+
+#define GLABEL_FLG_WAUTO (GWIN_FIRST_CONTROL_FLAG<<0)
+#define GLABEL_FLG_HAUTO (GWIN_FIRST_CONTROL_FLAG<<1)
+
+// Simple: single line with no wrapping
+static coord_t getwidth(const char *text, font_t font, coord_t maxwidth) {
+ (void) maxwidth;
+ return gdispGetStringWidth(text, font)+2; // Allow one pixel of padding on each side
+}
+
+// Simple: single line with no wrapping
+static coord_t getheight(const char *text, font_t font, coord_t maxwidth) {
+ (void) text;
+ (void) maxwidth;
+
+ return gdispGetFontMetric(font, fontHeight);
+}
+
+static void gwinLabelDefaultDraw(GWidgetObject *gw, void *param) {
+ coord_t w, h;
+ (void) param;
+
+ w = (gw->g.flags & GLABEL_FLG_WAUTO) ? getwidth(gw->text, gw->g.font, gdispGetWidth() - gw->g.x) : gw->g.width;
+ h = (gw->g.flags & GLABEL_FLG_HAUTO) ? getheight(gw->text, gw->g.font, gdispGetWidth() - gw->g.x) : gw->g.height;
+
+ if (gw->g.width != w || gw->g.height != h) {
+ gwinResize(&gw->g, w, h);
+ return;
+ }
+
+ gdispFillStringBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->text, gw->g.font,
+ (gw->g.flags & GWIN_FLG_ENABLED) ? gw->pstyle->enabled.text : gw->pstyle->disabled.text, gw->pstyle->background,
+ justifyLeft);
+}
+
+static const gwidgetVMT labelVMT = {
+ {
+ "Label", // The class name
+ sizeof(GLabelObject), // The object size
+ _gwidgetDestroy, // The destroy routine
+ _gwidgetRedraw, // The redraw routine
+ 0, // The after-clear routine
+ },
+ gwinLabelDefaultDraw, // default drawing routine
+ #if GINPUT_NEED_MOUSE
+ {
+ 0, // Process mose down events (NOT USED)
+ 0, // Process mouse up events (NOT USED)
+ 0, // Process mouse move events (NOT USED)
+ },
+ #endif
+ #if GINPUT_NEED_TOGGLE
+ {
+ 0, // No toggle role
+ 0, // Assign Toggles (NOT USED)
+ 0, // Get Toggles (NOT USED)
+ 0, // Process toggle off event (NOT USED)
+ 0, // Process toggle on event (NOT USED)
+ },
+ #endif
+ #if GINPUT_NEED_DIAL
+ {
+ 0, // No dial roles
+ 0, // Assign Dials (NOT USED)
+ 0, // Get Dials (NOT USED)
+ 0, // Procees dial move events (NOT USED)
+ },
+ #endif
+};
+
+GHandle gwinLabelCreate(GLabelObject *widget, GWidgetInit *pInit) {
+ uint16_t flags = 0;
+
+ // auto assign width
+ if (pInit->g.width <= 0) {
+ flags |= GLABEL_FLG_WAUTO;
+ pInit->g.width = getwidth(pInit->text, gwinGetDefaultFont(), gdispGetWidth() - pInit->g.x);
+ }
+
+ // auto assign height
+ if (pInit->g.height <= 0) {
+ flags |= GLABEL_FLG_HAUTO;
+ pInit->g.height = getheight(pInit->text, gwinGetDefaultFont(), gdispGetWidth() - pInit->g.x);
+ }
+
+ if (!(widget = (GLabelObject *)_gwidgetCreate(&widget->w, pInit, &labelVMT)))
+ return 0;
+
+ widget->w.g.flags |= flags;
+
+ gwinSetVisible(&widget->w.g, pInit->g.show);
+ return (GHandle)widget;
+}
+
+#endif // GFX_USE_GWIN && GFX_NEED_LABEL
+
diff --git a/src/gwin/radio.c b/src/gwin/radio.c
new file mode 100644
index 00000000..26ff0b83
--- /dev/null
+++ b/src/gwin/radio.c
@@ -0,0 +1,229 @@
+/*
+ * 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://chibios-gfx.com/license.html
+ */
+
+/**
+ * @file src/gwin/radio.c
+ * @brief GWIN sub-system radio button code.
+ *
+ * @defgroup RadioButton RadioButton
+ * @ingroup GWIN
+ *
+ * @{
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GWIN && GWIN_NEED_RADIO
+
+#include "gwin/class_gwin.h"
+
+// Our pressed state
+#define GRADIO_FLG_PRESSED (GWIN_FIRST_CONTROL_FLAG<<0)
+
+// Send the button event
+static void SendRadioEvent(GWidgetObject *gw) {
+ GSourceListener * psl;
+ GEvent * pe;
+ #define pbe ((GEventGWinRadio *)pe)
+
+ // Trigger a GWIN Button Event
+ psl = 0;
+ while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) {
+ if (!(pe = geventGetEventBuffer(psl)))
+ continue;
+ pbe->type = GEVENT_GWIN_RADIO;
+ pbe->radio = (GHandle)gw;
+ pbe->group = ((GRadioObject *)gw)->group;
+ geventSendEvent(psl);
+ }
+
+ #undef pbe
+}
+
+#if GINPUT_NEED_MOUSE
+ // A mouse down has occurred over the button
+ static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) {
+ (void) x; (void) y;
+
+ gwinRadioPress((GHandle)gw);
+ }
+#endif
+
+#if GINPUT_NEED_TOGGLE
+ // A toggle on has occurred
+ static void ToggleOn(GWidgetObject *gw, uint16_t role) {
+ (void) role;
+
+ gwinRadioPress((GHandle)gw);
+ }
+
+ static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) {
+ (void) role;
+ ((GRadioObject *)gw)->toggle = instance;
+ }
+
+ static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role) {
+ (void) role;
+ return ((GRadioObject *)gw)->toggle;
+ }
+#endif
+
+// The radio button VMT table
+static const gwidgetVMT radioVMT = {
+ {
+ "Radio", // The classname
+ sizeof(GRadioObject), // The object size
+ _gwidgetDestroy, // The destroy routine
+ _gwidgetRedraw, // The redraw routine
+ 0, // The after-clear routine
+ },
+ gwinRadioDraw_Radio, // The default drawing routine
+ #if GINPUT_NEED_MOUSE
+ {
+ MouseDown, // Process mouse down events
+ 0, // Process mouse up events (NOT USED)
+ 0, // Process mouse move events (NOT USED)
+ },
+ #endif
+ #if GINPUT_NEED_TOGGLE
+ {
+ 1, // 1 toggle role
+ ToggleAssign, // Assign Toggles
+ ToggleGet, // Get Toggles
+ 0, // Process toggle off events (NOT USED)
+ ToggleOn, // Process toggle on events
+ },
+ #endif
+ #if GINPUT_NEED_DIAL
+ {
+ 0, // No dial roles
+ 0, // Assign Dials (NOT USED)
+ 0, // Get Dials (NOT USED)
+ 0, // Process dial move events (NOT USED)
+ },
+ #endif
+};
+
+GHandle gwinRadioCreate(GRadioObject *gw, const GWidgetInit *pInit, uint16_t group) {
+ if (!(gw = (GRadioObject *)_gwidgetCreate(&gw->w, pInit, &radioVMT)))
+ return 0;
+
+ #if GINPUT_NEED_TOGGLE
+ gw->toggle = GWIDGET_NO_INSTANCE;
+ #endif
+ gw->group = group;
+ gwinSetVisible((GHandle)gw, pInit->g.show);
+ return (GHandle)gw;
+}
+
+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;
+ _gwidgetRedraw(gx);
+ }
+ gh->flags |= GRADIO_FLG_PRESSED;
+ _gwidgetRedraw(gh);
+ SendRadioEvent((GWidgetObject *)gh);
+}
+
+bool_t gwinRadioIsPressed(GHandle gh) {
+ if (gh->vmt != (gwinVMT *)&radioVMT)
+ return FALSE;
+
+ return (gh->flags & GRADIO_FLG_PRESSED) ? TRUE : FALSE;
+}
+
+GHandle gwinRadioGetActive(uint16_t group) {
+ const gfxQueueASyncItem * qi;
+ GHandle gh;
+
+ for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) {
+ gh = QItem2GWindow(qi);
+ if (gh->vmt == (gwinVMT *)&radioVMT && ((GRadioObject *)gh)->group == group && (gh->flags & GRADIO_FLG_PRESSED))
+ return gh;
+ }
+ return 0;
+}
+
+/*----------------------------------------------------------
+ * Custom Draw Routines
+ *----------------------------------------------------------*/
+
+static const GColorSet *getDrawColors(GWidgetObject *gw) {
+ if (!(gw->g.flags & GWIN_FLG_ENABLED)) return &gw->pstyle->disabled;
+ if ((gw->g.flags & GRADIO_FLG_PRESSED)) return &gw->pstyle->pressed;
+ return &gw->pstyle->enabled;
+}
+
+void gwinRadioDraw_Radio(GWidgetObject *gw, void *param) {
+ #define gcw ((GRadioObject *)gw)
+ coord_t ld, df;
+ const GColorSet * pcol;
+ (void) param;
+
+ if (gw->g.vmt != (gwinVMT *)&radioVMT) return;
+ pcol = getDrawColors(gw);
+
+ ld = gw->g.width < gw->g.height ? gw->g.width : gw->g.height;
+
+ #if GDISP_NEED_CIRCLE
+ df = (ld-1)/2;
+ gdispFillArea(gw->g.x, gw->g.y, ld, ld, gw->pstyle->background);
+ gdispDrawCircle(gw->g.x+df, gw->g.y+df, df, pcol->edge);
+
+ if (gw->g.flags & GRADIO_FLG_PRESSED)
+ gdispFillCircle(gw->g.x+df, gw->g.y+df, df <= 2 ? 1 : (df-2), pcol->fill);
+ #else
+ gdispFillArea(gw->g.x+1, gw->g.y+1, ld, ld-2, gw->pstyle->background);
+ gdispDrawBox(gw->g.x, gw->g.y, ld, ld, pcol->edge);
+
+ df = ld < 4 ? 1 : 2;
+ if (gw->g.flags & GRADIO_FLG_PRESSED)
+ gdispFillArea(gw->g.x+df, gw->g.y+df, ld-2*df, ld-2*df, pcol->fill);
+ #endif
+
+ gdispFillStringBox(gw->g.x+ld+1, gw->g.y, gw->g.width-ld-1, gw->g.height, gw->text, gw->g.font, pcol->text, gw->pstyle->background, justifyLeft);
+ #undef gcw
+}
+
+void gwinRadioDraw_Button(GWidgetObject *gw, void *param) {
+ const GColorSet * pcol;
+ (void) param;
+
+ if (gw->g.vmt != (gwinVMT *)&radioVMT) return;
+ pcol = getDrawColors(gw);
+
+ gdispFillStringBox(gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter);
+ gdispDrawLine(gw->g.x+gw->g.width-1, gw->g.y, gw->g.x+gw->g.width-1, gw->g.y+gw->g.height-1, pcol->edge);
+ gdispDrawLine(gw->g.x, gw->g.y+gw->g.height-1, gw->g.x+gw->g.width-2, gw->g.y+gw->g.height-1, pcol->edge);
+}
+
+void gwinRadioDraw_Tab(GWidgetObject *gw, void *param) {
+ const GColorSet * pcol;
+ (void) param;
+
+ if (gw->g.vmt != (gwinVMT *)&radioVMT) return;
+ pcol = getDrawColors(gw);
+
+ if ((gw->g.flags & GRADIO_FLG_PRESSED)) {
+ gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge);
+ gdispFillStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter);
+ } else {
+ gdispFillStringBox(gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter);
+ gdispDrawLine(gw->g.x+gw->g.width-1, gw->g.y, gw->g.x+gw->g.width-1, gw->g.y+gw->g.height-1, pcol->edge);
+ gdispDrawLine(gw->g.x, gw->g.y+gw->g.height-1, gw->g.x+gw->g.width-2, gw->g.y+gw->g.height-1, pcol->edge);
+ }
+}
+
+#endif /* GFX_USE_GWIN && GWIN_NEED_BUTTON */
+/** @} */
+
diff --git a/src/gwin/slider.c b/src/gwin/slider.c
index 01df189d..4d9c3510 100644
--- a/src/gwin/slider.c
+++ b/src/gwin/slider.c
@@ -19,140 +19,232 @@
#if (GFX_USE_GWIN && GWIN_NEED_SLIDER) || defined(__DOXYGEN__)
-#include "gwin/internal.h"
+#include "gwin/class_gwin.h"
#ifndef GWIN_SLIDER_DEAD_BAND
#define GWIN_SLIDER_DEAD_BAND 5
#endif
-#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
- static void trackSliderDraw(GHandle gh, coord_t x, coord_t y);
+#ifndef GWIN_SLIDER_TOGGLE_INC
+ #define GWIN_SLIDER_TOGGLE_INC 20 // How many toggles to go from minimum to maximum
#endif
-static const GSliderDrawStyle GSliderDefaultStyle = {
- HTML2COLOR(0x404040), // color_edge;
- HTML2COLOR(0x000000), // color_thumb;
- HTML2COLOR(0x00E000), // color_active;
- HTML2COLOR(0xE0E0E0), // color_inactive;
-};
+// Send the slider event
+static void SendSliderEvent(GWidgetObject *gw) {
+ GSourceListener * psl;
+ GEvent * pe;
+ #define pse ((GEventGWinSlider *)pe)
-// Process an event callback
-static void gwinSliderCallback(void *param, GEvent *pe) {
- GSourceListener *psl;
- #define gh ((GHandle)param)
- #define gsw ((GSliderObject *)param)
- #define gsh ((GSourceHandle)param)
- #define pme ((GEventMouse *)pe)
- #define pde ((GEventDial *)pe)
- #define pse ((GEventGWinSlider *)pe)
-
- switch (pe->type) {
- #if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
- case GEVENT_MOUSE:
- case GEVENT_TOUCH:
- // If not tracking we only only interested in a mouse down over the slider
- if (!gsw->tracking) {
- if ((pme->meta & GMETA_MOUSE_DOWN)
- && pme->x >= gh->x && pme->x < gh->x + gh->width
- && pme->y >= gh->y && pme->y < gh->y + gh->height) {
- gsw->tracking = TRUE;
- trackSliderDraw(gh, pme->x-gh->x, pme->y-gh->y);
- }
+ // Trigger a GWIN Button Event
+ psl = 0;
+ while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) {
+ if (!(pe = geventGetEventBuffer(psl)))
+ continue;
+ pse->type = GEVENT_GWIN_SLIDER;
+ pse->slider = (GHandle)gw;
+ pse->position = ((GSliderObject *)gw)->pos;
+ geventSendEvent(psl);
+ }
+
+ #undef pse
+}
+
+// Reset the display position back to the value predicted by the saved slider position
+static void ResetDisplayPos(GSliderObject *gsw) {
+ if (gsw->w.g.width < gsw->w.g.height)
+ gsw->dpos = gsw->w.g.height-1-((gsw->w.g.height-1)*(gsw->pos-gsw->min))/(gsw->max-gsw->min);
+ else
+ gsw->dpos = ((gsw->w.g.width-1)*(gsw->pos-gsw->min))/(gsw->max-gsw->min);
+}
+
+#if GINPUT_NEED_MOUSE
+ // A mouse up event
+ static void MouseUp(GWidgetObject *gw, coord_t x, coord_t y) {
+ #define gsw ((GSliderObject *)gw)
+ #define gh ((GHandle)gw)
+
+ #if GWIN_BUTTON_LAZY_RELEASE
+ // Clip to the slider
+ if (x < 0) x = 0;
+ else if (x >= gh->width) x = gh->width-1;
+ if (y < 0) y = 0;
+ else if (y >= gh->height) x = gh->height-1;
+ #else
+ // Are we over the slider?
+ if (x < 0 || x >= gh->width || y < 0 || y >= gh->height) {
+ // No - restore the slider
+ ResetDisplayPos(gsw);
+ _gwidgetRedraw(gh);
return;
}
+ #endif
- // We are tracking the mouse
-
- // Test for button up
- if ((pme->meta & GMETA_MOUSE_UP)) {
- gsw->tracking = FALSE;
-
- #if !GWIN_BUTTON_LAZY_RELEASE
- // Are we over the slider?
- if (pme->x < gh->x || pme->x >= gh->x + gh->width
- || pme->y < gh->y || pme->y >= gh->y + gh->height) {
- // No - restore the slider
- gwinSliderDraw(gh);
- return;
- }
- #endif
-
- // Set the new position
- if (gh->width < gh->height)
- gwinSetSliderPosition(gh,
- (uint16_t)((uint32_t)(gh->height-1-pme->y+gh->y-GWIN_SLIDER_DEAD_BAND)*(gsw->max-gsw->min)/(gh->height-2*GWIN_SLIDER_DEAD_BAND) + gsw->min));
- else
- gwinSetSliderPosition(gh,
- (uint16_t)((uint32_t)(pme->x-gh->x-GWIN_SLIDER_DEAD_BAND)*(gsw->max-gsw->min)/(gh->width-2*GWIN_SLIDER_DEAD_BAND) + gsw->min));
-
- // Update the display
- gwinSliderDraw(gh);
-
- // Generate the event
- break;
- }
+ // Set the new position
+ if (gh->width < gh->height) {
+ if (y > gh->height-GWIN_SLIDER_DEAD_BAND)
+ gsw->pos = gsw->min;
+ else if (y < GWIN_SLIDER_DEAD_BAND)
+ gsw->pos = gsw->max;
+ else
+ gsw->pos = (uint16_t)((int32_t)(gh->height-1-y-GWIN_SLIDER_DEAD_BAND)*(gsw->max-gsw->min)/(gh->height-2*GWIN_SLIDER_DEAD_BAND) + gsw->min);
+ } else {
+ if (x > gh->width-GWIN_SLIDER_DEAD_BAND)
+ gsw->pos = gsw->max;
+ else if (x < GWIN_SLIDER_DEAD_BAND)
+ gsw->pos = gsw->min;
+ else
+ gsw->pos = (uint16_t)((int32_t)(x-GWIN_SLIDER_DEAD_BAND)*(gsw->max-gsw->min)/(gh->width-2*GWIN_SLIDER_DEAD_BAND) + gsw->min);
+ }
+
+ ResetDisplayPos(gsw);
+ _gwidgetRedraw(gh);
+
+ // Generate the event
+ SendSliderEvent(gw);
+ #undef gh
+ #undef gsw
+ }
- // If mouse down - track movement
- if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT))
- trackSliderDraw(gh, pme->x-gh->x, pme->y-gh->y);
+ // A mouse move (or mouse down) event
+ static void MouseMove(GWidgetObject *gw, coord_t x, coord_t y) {
+ #define gsw ((GSliderObject *)gw)
+
+ // Determine the temporary display position (with range checking)
+ if (gw->g.width < gw->g.height) {
+ if (y < 0)
+ gsw->dpos = 0;
+ else if (y >= gw->g.height)
+ gsw->dpos = gw->g.height-1;
+ else
+ gsw->dpos = y;
+ } else {
+ if (x < 0)
+ gsw->dpos = 0;
+ else if (x >= gw->g.width)
+ gsw->dpos = gw->g.width-1;
+ else
+ gsw->dpos = x;
+ }
+
+ // Update the display
+ _gwidgetRedraw(&gw->g);
+ #undef gsw
+ }
+#endif
- return;
- #endif
- #if GFX_USE_GINPUT && GINPUT_NEED_DIAL
- case GEVENT_DIAL:
- // Set the new position
- gwinSetSliderPosition(gh, (uint16_t)((uint32_t)pde->value*(gsw->max-gsw->min)/ginputGetDialRange(pde->instance) + gsw->min));
+#if GINPUT_NEED_TOGGLE
+ // A toggle on has occurred
+ static void ToggleOn(GWidgetObject *gw, uint16_t role) {
+ #define gsw ((GSliderObject *)gw)
+
+ if (role) {
+ gwinSliderSetPosition((GHandle)gw, gsw->pos+(gsw->max-gsw->min)/GWIN_SLIDER_TOGGLE_INC);
+ SendSliderEvent(gw);
+ } else {
+ gwinSliderSetPosition((GHandle)gw, gsw->pos-(gsw->max-gsw->min)/GWIN_SLIDER_TOGGLE_INC);
+ SendSliderEvent(gw);
+ }
+ #undef gsw
+ }
- // Update the display
- gwinSliderDraw(gh);
+ static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) {
+ if (role)
+ ((GSliderObject *)gw)->t_up = instance;
+ else
+ ((GSliderObject *)gw)->t_dn = instance;
+ }
- // Generate the event
- break;
- #endif
+ static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role) {
+ return role ? ((GSliderObject *)gw)->t_up : ((GSliderObject *)gw)->t_dn;
+ }
+#endif
- default:
- return;
+#if GINPUT_NEED_DIAL
+ // A dial move event
+ static void DialMove(GWidgetObject *gw, uint16_t role, uint16_t value, uint16_t max) {
+ #define gsw ((GSliderObject *)gw)
+ (void) role;
+
+ // Set the new position
+ gsw->pos = (uint16_t)((uint32_t)value*(gsw->max-gsw->min)/max + gsw->min);
+
+ ResetDisplayPos(gsw);
+ _gwidgetRedraw((GHandle)gw);
+
+ // Generate the event
+ SendSliderEvent(gw);
+ #undef gsw
}
- // Trigger a GWIN Slider Event
- psl = 0;
- while ((psl = geventGetSourceListener(gsh, psl))) {
- if (!(pe = geventGetEventBuffer(psl)))
- continue;
- pse->type = GEVENT_GWIN_SLIDER;
- pse->slider = gh;
- pse->position = gsw->pos;
- geventSendEvent(psl);
+ static void DialAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) {
+ (void) role;
+ ((GSliderObject *)gw)->dial = instance;
}
- #undef pse
- #undef pme
- #undef pxe
- #undef gsh
- #undef gsw
- #undef gh
-}
+ static uint16_t DialGet(GWidgetObject *gw, uint16_t role) {
+ (void) role;
+ return ((GSliderObject *)gw)->dial;
+ }
+#endif
+
+// The slider VMT table
+static const gwidgetVMT sliderVMT = {
+ {
+ "Slider", // The classname
+ sizeof(GSliderObject), // The object size
+ _gwidgetDestroy, // The destroy routine
+ _gwidgetRedraw, // The redraw routine
+ 0, // The after-clear routine
+ },
+ gwinSliderDraw_Std, // The default drawing routine
+ #if GINPUT_NEED_MOUSE
+ {
+ 0, // Process mouse down events (NOT USED)
+ MouseUp, // Process mouse up events
+ MouseMove, // Process mouse move events
+ },
+ #endif
+ #if GINPUT_NEED_TOGGLE
+ {
+ 2, // 1 toggle role
+ ToggleAssign, // Assign Toggles
+ ToggleGet, // Get Toggles
+ 0, // Process toggle off events (NOT USED)
+ ToggleOn, // Process toggle on events
+ },
+ #endif
+ #if GINPUT_NEED_DIAL
+ {
+ 1, // 1 dial roles
+ DialAssign, // Assign Dials
+ DialGet, // Get Dials
+ DialMove, // Process dial move events
+ },
+ #endif
+};
-GHandle gwinCreateSlider(GSliderObject *gs, coord_t x, coord_t y, coord_t width, coord_t height) {
- if (!(gs = (GSliderObject *)_gwinInit((GWindowObject *)gs, x, y, width, height, sizeof(GSliderObject))))
+GHandle gwinSliderCreate(GSliderObject *gs, const GWidgetInit *pInit) {
+ if (!(gs = (GSliderObject *)_gwidgetCreate(&gs->w, pInit, &sliderVMT)))
return 0;
- gs->gwin.type = GW_SLIDER;
- gs->fn = gwinSliderDraw_Std;
- gs->param = 0;
- gwinSetSliderStyle(&gs->gwin, &GSliderDefaultStyle);
+ #if GINPUT_NEED_TOGGLE
+ gs->t_dn = GWIDGET_NO_INSTANCE;
+ gs->t_up = GWIDGET_NO_INSTANCE;
+ #endif
+ #if GINPUT_NEED_DIAL
+ gs->dial = GWIDGET_NO_INSTANCE;
+ #endif
gs->min = 0;
gs->max = 100;
gs->pos = 0;
- gs->tracking = FALSE;
- geventListenerInit(&gs->listener);
- geventRegisterCallback(&gs->listener, gwinSliderCallback, gs);
+ ResetDisplayPos(gs);
+ gwinSetVisible((GHandle)gs, pInit->g.show);
return (GHandle)gs;
}
-void gwinSetSliderRange(GHandle gh, int min, int max) {
+void gwinSliderSetRange(GHandle gh, int min, int max) {
#define gsw ((GSliderObject *)gh)
- if (gh->type != GW_SLIDER)
+ if (gh->vmt != (gwinVMT *)&sliderVMT)
return;
if (min == max) // prevent divide by 0 errors.
@@ -160,13 +252,14 @@ void gwinSetSliderRange(GHandle gh, int min, int max) {
gsw->min = min;
gsw->max = max;
gsw->pos = min;
+ ResetDisplayPos(gsw);
#undef gsw
}
-void gwinSetSliderPosition(GHandle gh, int pos) {
+void gwinSliderSetPosition(GHandle gh, int pos) {
#define gsw ((GSliderObject *)gh)
- if (gh->type != GW_SLIDER)
+ if (gh->vmt != (gwinVMT *)&sliderVMT)
return;
if (gsw->min <= gsw->max) {
@@ -178,125 +271,105 @@ void gwinSetSliderPosition(GHandle gh, int pos) {
else if (pos < gsw->max) gsw->pos = gsw->max;
else gsw->pos = pos;
}
+ ResetDisplayPos(gsw);
#undef gsw
}
-void gwinSetSliderStyle(GHandle gh, const GSliderDrawStyle *pStyle) {
- #define gsw ((GSliderObject *)gh)
-
- if (gh->type != GW_SLIDER)
- return;
-
- gsw->style.color_edge = pStyle->color_edge;
- gsw->style.color_thumb = pStyle->color_thumb;
- gsw->style.color_active = pStyle->color_active;
- gsw->style.color_inactive = pStyle->color_inactive;
- #undef gsw
-}
-
-#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
- static void trackSliderDraw(GHandle gh, coord_t x, coord_t y) {
- #define gsw ((GSliderObject *)gh)
+/*----------------------------------------------------------
+ * Custom Draw Routines
+ *----------------------------------------------------------*/
- #if GDISP_NEED_CLIP
- gdispSetClip(gh->x, gh->y, gh->width, gh->height);
- #endif
+void gwinSliderDraw_Std(GWidgetObject *gw, void *param) {
+ #define gsw ((GSliderObject *)gw)
+ const GColorSet * pcol;
+ (void) param;
- if (gh->height <= gh->width)
- gsw->fn(gh, FALSE, x, &gsw->style, gsw->param);
- else
- gsw->fn(gh, TRUE, y, &gsw->style, gsw->param);
-
- #undef gbw
- }
-#endif
-
-void gwinSliderDraw(GHandle gh) {
- #define gsw ((GSliderObject *)gh)
-
- if (gh->type != GW_SLIDER)
+ if (gw->g.vmt != (gwinVMT *)&sliderVMT)
return;
- #if GDISP_NEED_CLIP
- gdispSetClip(gh->x, gh->y, gh->width, gh->height);
- #endif
-
- if (gh->height <= gh->width)
- gsw->fn(gh, FALSE, ((gh->width-1)*(gsw->pos-gsw->min))/(gsw->max-gsw->min), &gsw->style, gsw->param);
+ if ((gw->g.flags & GWIN_FLG_ENABLED))
+ pcol = &gw->pstyle->pressed;
else
- gsw->fn(gh, TRUE, gh->height-1-((gh->height-1)*(gsw->pos-gsw->min))/(gsw->max-gsw->min), &gsw->style, gsw->param);
-
- #undef gbw
-}
-
-void gwinSetSliderCustom(GHandle gh, GSliderDrawFunction fn, void *param) {
- #define gsw ((GSliderObject *)gh)
-
- if (gh->type != GW_SLIDER)
- return;
-
- gsw->fn = fn ? fn : gwinSliderDraw_Std;
- gsw->param = param;
+ pcol = &gw->pstyle->disabled;
+
+ if (gw->g.width < gw->g.height) { // Vertical slider
+ if (gsw->dpos != gw->g.height-1)
+ gdispFillArea(gw->g.x, gw->g.y+gsw->dpos, gw->g.width, gw->g.height - gsw->dpos, pcol->progress); // Active Area
+ if (gsw->dpos != 0)
+ gdispFillArea(gw->g.x, gw->g.y, gw->g.width, gsw->dpos, gw->pstyle->enabled.progress); // Inactive area
+ gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); // Edge
+ gdispDrawLine(gw->g.x, gw->g.y+gsw->dpos, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos, pcol->edge); // Thumb
+ if (gsw->dpos >= 2)
+ gdispDrawLine(gw->g.x, gw->g.y+gsw->dpos-2, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos-2, pcol->edge); // Thumb
+ if (gsw->dpos <= gw->g.height-2)
+ gdispDrawLine(gw->g.x, gw->g.y+gsw->dpos+2, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos+2, pcol->edge); // Thumb
+
+ // Horizontal slider
+ } else {
+ if (gsw->dpos != gw->g.width-1)
+ gdispFillArea(gw->g.x+gsw->dpos, gw->g.y, gw->g.width-gsw->dpos, gw->g.height, gw->pstyle->enabled.progress); // Inactive area
+ if (gsw->dpos != 0)
+ gdispFillArea(gw->g.x, gw->g.y, gsw->dpos, gw->g.height, pcol->progress); // Active Area
+ gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); // Edge
+ gdispDrawLine(gw->g.x+gsw->dpos, gw->g.y, gw->g.x+gsw->dpos, gw->g.y+gw->g.height-1, pcol->edge); // Thumb
+ if (gsw->dpos >= 2)
+ gdispDrawLine(gw->g.x+gsw->dpos-2, gw->g.y, gw->g.x+gsw->dpos-2, gw->g.y+gw->g.height-1, pcol->edge); // Thumb
+ if (gsw->dpos <= gw->g.width-2)
+ gdispDrawLine(gw->g.x+gsw->dpos+2, gw->g.y, gw->g.x+gsw->dpos+2, gw->g.y+gw->g.height-1, pcol->edge); // Thumb
+ }
+ gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter);
#undef gsw
}
-void gwinSliderSetEnabled(GHandle gh, bool_t enabled) {
- if (gh->type != GW_SLIDER)
+void gwinSliderDraw_Image(GWidgetObject *gw, void *param) {
+ #define gsw ((GSliderObject *)gw)
+ #define gi ((gdispImage *)param)
+ const GColorSet * pcol;
+ coord_t z, v;
+
+ if (gw->g.vmt != (gwinVMT *)&sliderVMT)
return;
- gh->enabled = enabled;
-}
+ if ((gw->g.flags & GWIN_FLG_ENABLED))
+ pcol = &gw->pstyle->pressed;
+ else
+ pcol = &gw->pstyle->disabled;
+
+ if (gw->g.width < gw->g.height) { // Vertical slider
+ if (gsw->dpos != 0) // The unfilled area
+ gdispFillArea(gw->g.x, gw->g.y, gw->g.width, gsw->dpos, gw->pstyle->enabled.progress); // Inactive area
+ if (gsw->dpos != gw->g.height-1) { // The filled area
+ for(z=gw->g.height, v=gi->height; z > gsw->dpos;) {
+ z -= v;
+ if (z < gsw->dpos) {
+ v -= gsw->dpos - z;
+ z = gsw->dpos;
+ }
+ gdispImageDraw(gi, gw->g.x, gw->g.y+z, gw->g.width, v, 0, gi->height-v);
+ }
+ }
+ gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); // Edge
+ gdispDrawLine(gw->g.x, gw->g.y+gsw->dpos, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos, pcol->edge); // Thumb
-void gwinSliderDraw_Std(GHandle gh, bool_t isVertical, coord_t thumbpos, const GSliderDrawStyle *pstyle, void *param) {
- (void) param;
-
- if (isVertical) {
- if (thumbpos != gh->height-1)
- gdispFillArea(gh->x, gh->y+thumbpos, gh->width, gh->height - thumbpos, pstyle->color_active);
- if (thumbpos != 0)
- gdispFillArea(gh->x, gh->y, gh->width, thumbpos, pstyle->color_inactive);
- gdispDrawBox(gh->x, gh->y, gh->width, gh->height, pstyle->color_edge);
- gdispDrawLine(gh->x, gh->y+thumbpos, gh->x+gh->width-1, gh->y+thumbpos, pstyle->color_thumb);
- if (thumbpos >= 2)
- gdispDrawLine(gh->x, gh->y+thumbpos-2, gh->x+gh->width-1, gh->y+thumbpos-2, pstyle->color_thumb);
- if (thumbpos <= gh->height-2)
- gdispDrawLine(gh->x, gh->y+thumbpos+2, gh->x+gh->width-1, gh->y+thumbpos+2, pstyle->color_thumb);
+ // Horizontal slider
} else {
- if (thumbpos != gh->width-1)
- gdispFillArea(gh->x+thumbpos, gh->y, gh->width-thumbpos, gh->height, pstyle->color_inactive);
- if (thumbpos != 0)
- gdispFillArea(gh->x, gh->y, thumbpos, gh->height, pstyle->color_active);
- gdispDrawBox(gh->x, gh->y, gh->width, gh->height, pstyle->color_edge);
- gdispDrawLine(gh->x+thumbpos, gh->y, gh->x+thumbpos, gh->y+gh->height-1, pstyle->color_thumb);
- if (thumbpos >= 2)
- gdispDrawLine(gh->x+thumbpos-2, gh->y, gh->x+thumbpos-2, gh->y+gh->height-1, pstyle->color_thumb);
- if (thumbpos <= gh->width-2)
- gdispDrawLine(gh->x+thumbpos+2, gh->y, gh->x+thumbpos+2, gh->y+gh->height-1, pstyle->color_thumb);
- }
-}
-
-#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
- bool_t gwinAttachSliderMouse(GHandle gh, uint16_t instance) {
- GSourceHandle gsh;
-
- if (gh->type != GW_SLIDER || !(gsh = ginputGetMouse(instance)))
- return FALSE;
-
- return geventAttachSource(&((GSliderObject *)gh)->listener, gsh, GLISTEN_MOUSEMETA|GLISTEN_MOUSEDOWNMOVES);
+ if (gsw->dpos != gw->g.width-1) // The unfilled area
+ gdispFillArea(gw->g.x+gsw->dpos, gw->g.y, gw->g.width-gsw->dpos, gw->g.height, gw->pstyle->enabled.progress); // Inactive area
+ if (gsw->dpos != 0) { // The filled area
+ for(z=0, v=gi->width; z < gsw->dpos; z += v) {
+ if (z+v > gsw->dpos)
+ v -= z+v - gsw->dpos;
+ gdispImageDraw(gi, gw->g.x+z, gw->g.y, v, gw->g.height, 0, 0);
+ }
+ }
+ gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); // Edge
+ gdispDrawLine(gw->g.x+gsw->dpos, gw->g.y, gw->g.x+gsw->dpos, gw->g.y+gw->g.height-1, pcol->edge); // Thumb
}
-#endif
-
-#if GFX_USE_GINPUT && GINPUT_NEED_DIAL
- bool_t gwinAttachSliderDial(GHandle gh, uint16_t instance) {
- GSourceHandle gsh;
+ gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter);
- if (gh->type != GW_SLIDER || !(gsh = ginputGetDial(instance)))
- return FALSE;
-
- return geventAttachSource(&((GSliderObject *)gh)->listener, gsh, 0);
- }
-#endif
+ #undef gsw
+}
#endif /* GFX_USE_GWIN && GWIN_NEED_BUTTON */
/** @} */