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.c564
-rw-r--r--src/gwin/checkbox.c246
-rw-r--r--src/gwin/console.c56
-rw-r--r--src/gwin/graph.c73
-rw-r--r--src/gwin/gwidget.c376
-rw-r--r--src/gwin/gwin.c369
-rw-r--r--src/gwin/gwin.mk4
-rw-r--r--src/gwin/gwm.c144
-rw-r--r--src/gwin/slider.c467
12 files changed, 1540 insertions, 800 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..fc432cb4 100644
--- a/src/gwin/button.c
+++ b/src/gwin/button.c
@@ -19,392 +19,336 @@
#if (GFX_USE_GWIN && GWIN_NEED_BUTTON) || defined(__DOXYGEN__)
-/* 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
+// Our pressed state
+#define GBUTTON_FLG_PRESSED (GWIN_FIRST_CONTROL_FLAG<<0)
+
+// Prototypes for button VMT functions
+static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y);
+static void MouseUp(GWidgetObject *gw, coord_t x, coord_t y);
+static void ToggleOff(GWidgetObject *gw, uint16_t role);
+static void ToggleOn(GWidgetObject *gw, uint16_t role);
+static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance);
+static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role);
+
+// The button VMT table
+static const gwidgetVMT buttonVMT = {
+ {
+ "Button", // The classname
+ _gwidgetDestroy, // The destroy routine
+ _gwidgetRedraw, // The redraw routine
+ 0, // The after-clear routine
+ },
+ gwinButtonDraw_3D, // The default drawing routine
+ {
+ MouseDown, // Process mouse down events
+ MouseUp, // Process mouse up events
+ 0, // Process mouse move events (NOT USED)
+ },
+ {
+ 1, // 1 toggle role
+ ToggleAssign, // Assign Toggles
+ ToggleGet, // Get Toggles
+ ToggleOff, // Process toggle off events
+ ToggleOn, // Process toggle on events
+ },
+ {
+ 0, // No dial roles
+ 0, // Assign Dials (NOT USED)
+ 0, // Get Dials (NOT USED)
+ 0, // Process dial move events (NOT USED)
+ }
+};
-static const GButtonDrawStyle GButtonDefaultStyleUp = {
+// Default color scheme
+static const GButtonColors GButtonDefaultColorsUp = {
HTML2COLOR(0x404040), // color_up_edge;
HTML2COLOR(0xE0E0E0), // color_up_fill;
HTML2COLOR(0x000000), // color_up_txt;
};
-
-static const GButtonDrawStyle GButtonDefaultStyleDown = {
+static const GButtonColors GButtonDefaultColorsDown = {
HTML2COLOR(0x404040), // color_dn_edge;
HTML2COLOR(0x808080), // color_dn_fill;
HTML2COLOR(0x404040), // color_dn_txt;
};
+static const GButtonColors GButtonDefaultColorsDisabled = {
+ HTML2COLOR(0x808080), // color_dis_edge;
+ HTML2COLOR(0xE0E0E0), // color_dis_fill;
+ HTML2COLOR(0xC0C0C0), // color_dis_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;
-
- 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;
+// 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);
}
-void gwinSetButtonStyle(GHandle gh, GButtonShape shape, const GButtonDrawStyle *pUp, const GButtonDrawStyle *pDown) {
- #define gbw ((GButtonObject *)gh)
- if (gh->type != GW_BUTTON)
- return;
+// 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);
- 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
-
- #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;
- #endif
-
- case GBTN_CUSTOM: if (gbw->fn) break; /* Fall Through */
- case GBTN_3D: /* Fall through */
- default: gbw->fn = gwinButtonDraw_3D; break;
- }
- 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;
- }
- #undef gbw
+ #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
+
+ SendButtonEvent(gw);
}
-void gwinSetButtonText(GHandle gh, const char *txt, bool_t useAlloc) {
- #define gbw ((GButtonObject *)gh)
- if (gh->type != GW_BUTTON)
- return;
+// A toggle off has occurred
+static void ToggleOff(GWidgetObject *gw, uint16_t role) {
+ (void) role;
+ gw->g.flags &= ~GBUTTON_FLG_PRESSED;
+ _gwidgetRedraw((GHandle)gw);
+}
- // 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 = "";
- }
- }
- // 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;
- }
-
- gbw->txt = txt ? txt : "";
- #undef gbw
+// 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);
}
-void gwinButtonDraw(GHandle gh) {
- #define gbw ((GButtonObject *)gh)
-
- if (gh->type != GW_BUTTON)
- return;
+static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) {
+ (void) role;
+ ((GButtonObject *)gw)->toggle = instance;
+}
- #if GDISP_NEED_CLIP
- gdispSetClip(gh->x, gh->y, gh->width, gh->height);
- #endif
+static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role) {
+ (void) role;
+ return ((GButtonObject *)gw)->toggle;
+}
- 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);
+GHandle gwinCreateButton(GButtonObject *gw, coord_t x, coord_t y, coord_t width, coord_t height) {
+ if (!(gw = (GButtonObject *)_gwidgetCreate((GWidgetObject *)gw, x, y, width, height, sizeof(GButtonObject), &buttonVMT)))
+ return 0;
- #undef gbw
+ gw->toggle = GWIDGET_NO_INSTANCE;
+ gw->c_up = GButtonDefaultColorsUp;
+ gw->c_dn = GButtonDefaultColorsDown;
+ gw->c_dis = GButtonDefaultColorsDisabled;
+ return (GHandle)gw;
}
-void gwinSetButtonCustom(GHandle gh, GButtonDrawFunction fn, void *param) {
- #define gbw ((GButtonObject *)gh)
-
- if (gh->type != GW_BUTTON)
+void gwinSetButtonColors(GHandle gh, const GButtonColors *pUp, const GButtonColors *pDown, const GButtonColors *pDisabled) {
+ if (gh->vmt != (gwinVMT *)&buttonVMT)
return;
- gbw->fn = fn ? fn : gwinButtonDraw_3D;
- gbw->param = param;
+ if (pUp) ((GButtonObject *)gh)->c_up = *pUp;
+ if (pDown) ((GButtonObject *)gh)->c_dn = *pDown;
+ if (pDisabled) ((GButtonObject *)gh)->c_dis = *pDisabled;
+}
+
+bool_t gwinIsButtonPressed(GHandle gh) {
+ if (gh->vmt != (gwinVMT *)&buttonVMT)
+ return FALSE;
- #undef gbw
+ return (gh->flags & GBUTTON_FLG_PRESSED) ? TRUE : FALSE;
}
-void gwinButtonSetEnabled(GHandle gh, bool_t enabled) {
- if (gh->type != GW_BUTTON)
- return;
+/*----------------------------------------------------------
+ * Custom Draw Routines
+ *----------------------------------------------------------*/
- gh->enabled = enabled;
+static GButtonColors *getDrawColors(GWidgetObject *gw) {
+ if (!(gw->g.flags & GWIN_FLG_ENABLED)) return &((GButtonObject *)gw)->c_dis;
+ if ((gw->g.flags & GBUTTON_FLG_PRESSED)) return &((GButtonObject *)gw)->c_dn;
+ return &((GButtonObject *)gw)->c_up;
}
-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;
+void gwinButtonDraw_3D(GWidgetObject *gw, void *param) {
+ (void) param;
+ GButtonColors * pcol;
- 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);
+ 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->txt, gw->g.font, pcol->color_txt, pcol->color_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->color_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->color_edge);
}
-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_Box(GWidgetObject *gw, void *param) {
+ (void) param;
+ GButtonColors * pcol;
- 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+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, pcol->color_txt, pcol->color_fill, justifyCenter);
+ gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->color_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) {
+ (void) param;
+ GButtonColors * pcol;
+
+ if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
+ pcol = getDrawColors(gw);
+
+ 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->color_fill);
+ gdispDrawStringBox(gw->g.x+1, gw->g.y+RND_CNR_SIZE, gw->g.width-2, gw->g.height-(2*RND_CNR_SIZE), gw->txt, gw->g.font, pcol->color_txt, justifyCenter);
+ gdispDrawRoundedBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, RND_CNR_SIZE, pcol->color_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->txt, gw->g.font, pcol->color_txt, pcol->color_fill, justifyCenter);
+ gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->color_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) {
+ (void) param;
+ GButtonColors * pcol;
+
+ if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
+ pcol = getDrawColors(gw);
+
+ gdispFillEllipse(gw->g.x+1, gw->g.y+1, gw->g.width/2-1, gw->g.height/2-1, pcol->color_fill);
+ gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, pcol->color_txt, justifyCenter);
+ gdispDrawEllipse(gw->g.x, gw->g.y, gw->g.width/2, gw->g.height/2, pcol->color_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) {
+ (void) param;
+ GButtonColors * pcol;
+ 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;
+
+ gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_fill);
+ gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_edge);
+ gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, pcol->color_txt, 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) {
+ (void) param;
+ GButtonColors * pcol;
+ 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;
+
+ gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_fill);
+ gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_edge);
+ gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, pcol->color_txt, 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) {
+ (void) param;
+ GButtonColors * pcol;
+ 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;
+
+ gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_fill);
+ gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_edge);
+ gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, pcol->color_txt, 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) {
+ (void) param;
+ GButtonColors * pcol;
+ 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;
+
+ gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_fill);
+ gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_edge);
+ gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, pcol->color_txt, 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) {
+ GButtonColors * pcol;
+ coord_t sy;
- return geventAttachSource(&((GButtonObject *)gh)->listener, gsh, GLISTEN_MOUSEMETA);
- }
-#endif
+ if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
-#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)) {
+ pcol = &((GButtonObject *)gw)->c_dis;
+ sy = 2 * gw->g.height;
+ } else if ((gw->g.flags & GBUTTON_FLG_PRESSED)) {
+ pcol = &((GButtonObject *)gw)->c_dn;
+ sy = gw->g.height;
+ } else {
+ pcol = &((GButtonObject *)gw)->c_up;
+ 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->txt, gw->g.font, pcol->color_txt, justifyCenter);
}
#endif
diff --git a/src/gwin/checkbox.c b/src/gwin/checkbox.c
index faea0ef9..0282df42 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,160 @@
#if (GFX_USE_GWIN && GWIN_NEED_CHECKBOX) || defined(__DOXYGEN__)
-static const GCheckboxColor defaultColors = {
- Grey, // border
- Grey, // selected
- Black // background
+#include "gwin/class_gwin.h"
+
+// Our checked state
+#define GCHECKBOX_FLG_CHECKED (GWIN_FIRST_CONTROL_FLAG<<0)
+
+// Prototypes for button VMT functions
+static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y);
+static void ToggleOn(GWidgetObject *gw, uint16_t role);
+static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance);
+static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role);
+
+// The button VMT table
+static const gwidgetVMT checkboxVMT = {
+ {
+ "Checkbox", // The classname
+ _gwidgetDestroy, // The destroy routine
+ _gwidgetRedraw, // The redraw routine
+ 0, // The after-clear routine
+ },
+ gwinCheckboxDraw_CheckOnLeft, // The default drawing routine
+ {
+ MouseDown, // Process mouse down events
+ 0, // Process mouse up events (NOT USED)
+ 0, // Process mouse move events (NOT USED)
+ },
+ {
+ 1, // 1 toggle role
+ ToggleAssign, // Assign Toggles
+ ToggleGet, // Get Toggles
+ 0, // Process toggle off events (NOT USED)
+ ToggleOn, // Process toggle on events
+ },
+ {
+ 0, // No dial roles
+ 0, // Assign Dials (NOT USED)
+ 0, // Get Dials (NOT USED)
+ 0, // Process dial move events (NOT USED)
+ }
};
-/* default style drawing routine */
-static void gwinCheckboxDrawDefaultStyle(GHandle gh, bool_t enabled, bool_t isChecked, void* param) {
- #define gcw ((GCheckboxObject *)gh)
-
- (void) enabled;
- (void) param;
-
- gdispDrawBox(gh->x, gh->y, gh->width, gh->height, gcw->colors->border);
-
- 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);
-
- #undef gcw
-}
-
-/* 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) {
-
- gbw->isChecked = !gbw->isChecked;
+static const GCheckboxColors defaultColors = {
+ Black, // border
+ Grey, // selected
+ White, // background
+ Black, // text
+};
- gwinCheckboxDraw((GHandle)param);
- break;
- }
- return;
- #endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */
+// Send the checkbox event
+static void SendCheckboxEvent(GWidgetObject *gw) {
+ GSourceListener * psl;
+ GEvent * pe;
+ #define pce ((GEventGWinCheckbox *)pe)
- default:
- return;
- }
-
- // Trigger a GWIN checkbox event
+ // Trigger a GWIN Checkbox Event
psl = 0;
- while ((psl = geventGetSourceListener(gsh, psl))) {
+ while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) {
if (!(pe = geventGetEventBuffer(psl)))
continue;
- pbe->type = GEVENT_GWIN_CHECKBOX;
- pbe->checkbox = gh;
- pbe->isChecked = gbw->isChecked;
+ pce->type = GEVENT_GWIN_CHECKBOX;
+ pce->checkbox = &gw->g;
+ pce->isChecked = (gw->g.flags & GCHECKBOX_FLG_CHECKED) ? TRUE : FALSE;
geventSendEvent(psl);
- }
-
- #undef gh
- #undef pbe
- #undef pme
- #undef pte
- #undef pxe
- #undef gsh
- #undef gbw
-}
+ }
-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))))
- return 0;
+ #undef pce
+}
- 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
+// A mouse down has occurred over the checkbox
+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);
+}
- geventListenerInit(&gb->listener);
- geventRegisterCallback(&gb->listener, gwinCheckboxCallback, gb);
+// A toggle on has occurred
+static void ToggleOn(GWidgetObject *gw, uint16_t role) {
+ (void) role;
+ gw->g.flags ^= GCHECKBOX_FLG_CHECKED;
+ _gwidgetRedraw((GHandle)gw);
+ SendCheckboxEvent(gw);
+}
- // checkboxes are enabled by default
- gb->gwin.enabled = TRUE;
+static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) {
+ (void) role;
+ ((GCheckboxObject *)gw)->toggle = instance;
+}
- return (GHandle)gb;
+static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role) {
+ (void) role;
+ return ((GCheckboxObject *)gw)->toggle;
}
-void gwinCheckboxSetCustom(GHandle gh, GCheckboxDrawFunction fn, void *param) {
- #define gcw ((GCheckboxObject *)gh)
+GHandle gwinCreateCheckbox(GCheckboxObject *gb, coord_t x, coord_t y, coord_t width, coord_t height) {
+ if (!(gb = (GCheckboxObject *)_gwidgetCreate((GWidgetObject *)gb, x, y, width, height, sizeof(GCheckboxObject), &checkboxVMT)))
+ return 0;
- if (gh->type != GW_CHECKBOX)
- return;
+ gb->toggle = (uint16_t) -1;
+ gb->c = defaultColors; // assign the default colors
+ return (GHandle)gb;
+}
- gcw->fn = fn;
- gcw->param = param;
+bool_t gwinIsCheckboxChecked(GHandle gh) {
+ if (gh->vmt != (gwinVMT *)&checkboxVMT)
+ return FALSE;
- #undef gcw
+ return (gh->flags & GCHECKBOX_FLG_CHECKED) ? TRUE : FALSE;
}
-
-void gwinCheckboxSetEnabled(GHandle gh, bool_t enabled) {
- if (gh->type != GW_CHECKBOX)
+void gwinCheckboxSetColors(GHandle gh, GCheckboxColors *pColors) {
+ if (gh->vmt != (gwinVMT *)&checkboxVMT)
return;
- gh->enabled = enabled;
+ ((GCheckboxObject *)gh)->c = *pColors;
}
-void gwinCheckboxDraw(GHandle gh) {
- #define gcw ((GCheckboxObject *)gh)
+void gwinCheckboxDraw_CheckOnLeft(GWidgetObject *gw, void *param) {
+ #define gcw ((GCheckboxObject *)gw)
+ coord_t ld, df;
+ (void) param;
- if (gh->type != GW_CHECKBOX)
+ if (gw->g.vmt != (gwinVMT *)&checkboxVMT)
return;
- #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, gcw->c.color_bg);
+ gdispDrawBox(gw->g.x, gw->g.y, ld, ld, gcw->c.color_border);
- 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, gcw->c.color_checked);
+ gdispFillStringBox(gw->g.x+ld+1, gw->g.y, gw->g.width-ld-1, gw->g.height, gw->txt, gw->g.font, gcw->c.color_txt, gcw->c.color_bg, justifyLeft);
#undef gcw
}
-#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
- bool_t gwinCheckboxAttachMouse(GHandle gh, uint16_t instance) {
- GSourceHandle gsh;
-
- if (gh->type != GW_CHECKBOX || !(gsh = ginputGetMouse(instance)))
- return FALSE;
-
- 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)
+void gwinCheckboxDraw_CheckOnRight(GWidgetObject *gw, void *param) {
+ #define gcw ((GCheckboxObject *)gw)
+ coord_t ep, ld, df;
+ (void) param;
- if (gh->type != GW_CHECKBOX)
+ if (gw->g.vmt != (gwinVMT *)&checkboxVMT)
return;
- gcw->colors->border = border;
- gcw->colors->checked = checked,
- gcw->colors->bg = bg;
+ 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, gcw->c.color_bg);
+ gdispDrawBox(gw->g.x+ep, gw->g.y, ld, ld, gcw->c.color_border);
+
+ 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, gcw->c.color_checked);
+ gdispFillStringBox(gw->g.x, gw->g.y, ep, gw->g.height, gw->txt, gw->g.font, gcw->c.color_txt, gcw->c.color_bg, justifyRight);
#undef gcw
}
diff --git a/src/gwin/console.c b/src/gwin/console.c
index a4cd428c..38e2ea8b 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,11 +53,21 @@
};
#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
+ 0, // The destroy routine
+ 0, // The redraw routine
+ AfterClear, // The after-clear routine
+};
+
+GHandle gwinCreateConsole(GConsoleObject *gc, coord_t x, coord_t y, coord_t width, coord_t height) {
+ if (!(gc = (GConsoleObject *)_gwindowCreate((GWindowObject *)gc, x, y, width, height, sizeof(GConsoleObject), &consoleVMT, GWIN_FLG_VISIBLE)))
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
@@ -73,17 +78,21 @@ GHandle gwinCreateConsole(GConsoleObject *gc, coord_t x, coord_t y, coord_t widt
#if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM
BaseSequentialStream *gwinGetConsoleStream(GHandle gh) {
- if (gh->type != GW_CONSOLE)
+ 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 +100,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 +130,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 +209,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 +353,5 @@ void gwinPrintf(GHandle gh, const char *fmt, ...) {
}
#endif /* GFX_USE_GWIN && GWIN_NEED_CONSOLE */
-/** @} */
+
diff --git a/src/gwin/graph.c b/src/gwin/graph.c
index 72dcce9d..708b90cb 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,20 @@ static const GGraphStyle GGraphDefaultStyle = {
GWIN_GRAPH_STYLE_XAXIS_ARROWS|GWIN_GRAPH_STYLE_YAXIS_ARROWS // flags
};
+static const gwinVMT graphVMT = {
+ "Graph", // The classname
+ 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 +75,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
@@ -163,41 +165,26 @@ 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))))
+ if (!(gg = (GGraphObject *)_gwindowCreate((GWindowObject *)gg, x, y, width, height, sizeof(GGraphObject), &graphVMT, GWIN_FLG_VISIBLE)))
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);
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 +193,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 +206,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 +264,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 +273,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 +301,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 +331,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..9d634c58
--- /dev/null
+++ b/src/gwin/gwidget.c
@@ -0,0 +1,376 @@
+/*
+ * 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;
+
+/* 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, coord_t x, coord_t y, coord_t width, coord_t height, size_t size, const gwidgetVMT *vmt) {
+ if (!(pgw = (GWidgetObject *)_gwindowCreate((GWindowObject *)pgw, x, y, width, height, size, (const gwinVMT *)vmt, GWIN_FLG_WIDGET|GWIN_FLG_ENABLED)))
+ return 0;
+
+ pgw->txt = "";
+ pgw->fnDraw = vmt->DefaultDraw;
+ pgw->fnParam = 0;
+
+ return (GHandle)pgw;
+}
+
+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->txt);
+ }
+
+ #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 gwinSetEnabled(GHandle gh, bool_t enabled) {
+ if (!(gh->flags & GWIN_FLG_WIDGET))
+ return;
+
+ if (enabled) {
+ if (!(gh->flags & GWIN_FLG_ENABLED)) {
+ gh->flags |= GWIN_FLG_ENABLED;
+ _gwidgetRedraw(gh);
+ }
+ } else {
+ if ((gh->flags & GWIN_FLG_ENABLED)) {
+ gh->flags &= ~GWIN_FLG_ENABLED;
+ _gwidgetRedraw(gh);
+ }
+ }
+}
+
+void gwinSetText(GHandle gh, const char *txt, 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->txt) {
+ gfxFree((void *)gw->txt);
+ gw->txt = "";
+ }
+ }
+
+ // Alloc the new text if required
+ if (txt && !*txt) txt = 0;
+ if (txt && useAlloc) {
+ char *str;
+
+ if ((str = (char *)gfxAlloc(strlen(txt)+1))) {
+ gh->flags |= GWIN_FLG_ALLOCTXT;
+ strcpy(str, txt);
+ }
+ txt = (const char *)str;
+ }
+
+ gw->txt = txt ? txt : "";
+ _gwidgetRedraw(gh);
+}
+
+const char *gwinGetText(GHandle gh) {
+ if (!(gh->flags & GWIN_FLG_WIDGET))
+ return 0;
+
+ return gw->txt;
+}
+
+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..b918d297 100644
--- a/src/gwin/gwin.c
+++ b/src/gwin/gwin.c
@@ -9,127 +9,266 @@
#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
+ 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
+#if GWIN_NEED_WINDOWMANAGER
+ gfxQueueASync _GWINList;
+ extern GWindowManager GNullWindowManager;
+ static GWindowManager * cwm;
+#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 w, coord_t h) {
+ 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;
+ gh->x = x; gh->y = y;
+ gh->width = w; gh->height = h;
+ }
+#endif
+
+/*-----------------------------------------------
+ * Class Routines
+ *-----------------------------------------------*/
+
+void _gwinInit(void) {
+ #if GWIN_NEED_WIDGET
+ extern void _gwidgetInit(void);
+
+ _gwidgetInit();
+ #endif
+ #if GWIN_NEED_WINDOWMANAGER
+ gfxQueueASyncInit(&_GWINList);
+ cwm = &GNullWindowManager;
+ cwm->vmt->Init();
+ #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, coord_t x, coord_t y, coord_t width, coord_t height, size_t size, const gwinVMT *vmt, uint16_t flags) {
// Allocate the structure if necessary
- if (!gw) {
- if (!(gw = (GWindowObject *)gfxAlloc(size)))
+ if (!pgw) {
+ if (!(pgw = (GWindowObject *)gfxAlloc(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))))
- return 0;
- gw->type = GW_WINDOW;
- return (GHandle)gw;
-}
+ #if GWIN_NEED_WINDOWMANAGER
+ if (!cwm->vmt->Add(pgw, x, y, width, height)) {
+ if ((pgw->flags & GWIN_FLG_DYNAMIC))
+ gfxFree(pgw);
+ return 0;
+ }
+ #else
+ _gwm_redim(pgw, x, y, width, height);
+ if ((pgw->flags & GWIN_FLG_VISIBLE))
+ _gwm_vis(pgw);
+ #endif
-void gwinSetEnabled(GHandle gh, bool_t enabled) {
- (void)gh;
- (void)enabled;
+ return (GHandle)pgw;
}
-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);
+/*-----------------------------------------------
+ * Routines that affect all windows
+ *-----------------------------------------------*/
+
+#if GWIN_NEED_WINDOWMANAGER
+ void gwinSetWindowManager(struct GWindowManager *gwm) {
+ if (!gwm)
+ gwm = &GNullWindowManager;
+ if (cwm != gwm) {
+ cwm->vmt->DeInit();
+ cwm = gwm;
+ cwm->vmt->Init();
}
- 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;
+
+void gwinSetDefaultColor(color_t clr) {
+ defaultFgColor = clr;
+}
+
+void gwinSetDefaultBgColor(color_t bgclr) {
+ defaultBgColor = bgclr;
+}
+
+#if GDISP_NEED_TEXT
+ void gwinSetDefaultFont(font_t font) {
+ defaultFont = font;
}
+#endif
+
+/*-----------------------------------------------
+ * The GWindow Routines
+ *-----------------------------------------------*/
+
+GHandle gwinCreateWindow(GWindowObject *pgw, coord_t x, coord_t y, coord_t width, coord_t height) {
+ return _gwindowCreate(pgw, x, y, width, height, sizeof(GWindowObject), &basegwinVMT, GWIN_FLG_VISIBLE);
+}
+
+void gwinDestroy(GHandle gh) {
+ // Remove from the window manager
+ #if GWIN_NEED_WINDOWMANAGER
+ cwm->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
+ cwm->vmt->Visible(gh);
+ #else
+ _gwm_vis(gh);
+ #endif
+ }
+ } else {
+ if ((gh->flags & GWIN_FLG_VISIBLE)) {
+ gh->flags &= ~GWIN_FLG_VISIBLE;
+ #if GWIN_NEED_WINDOWMANAGER
+ cwm->vmt->Visible(gh);
+ #endif
+ }
}
}
-void gwinDraw(GHandle gh) {
- switch(gh->type) {
- #if GWIN_NEED_BUTTON
- case GW_BUTTON:
- gwinButtonDraw(gh);
- break;
+bool_t gwinGetVisible(GHandle gh) {
+ return (gh->flags & GWIN_FLG_VISIBLE) ? TRUE : FALSE;
+}
+
+void gwinMove(GHandle gh, coord_t x, coord_t y) {
+ #if GWIN_NEED_WINDOWMANAGER
+ cwm->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
+ cwm->vmt->Redim(gh, gh->x, gh->y, width, height);
+ #else
+ _gwm_redim(gh, gh->x, gh->y, width, height);
+ #endif
+}
+
+void gwinSetMinMax(GHandle gh, GWindowMinMax minmax) {
+ #if GWIN_NEED_WINDOWMANAGER
+ cwm->vmt->MinMax(gh, minmax);
+ #else
+ (void) gh;
+ (void) minmax;
+ #endif
+}
+
+void gwinRaise(GHandle gh) {
+ #if GWIN_NEED_WINDOWMANAGER
+ cwm->vmt->Raise(gh);
+ #else
+ 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
- }
+}
+
+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;
}
#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 +276,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 +286,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 +296,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 +306,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 +317,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 +327,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 +339,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 +349,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 +361,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 +371,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 +383,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 +395,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 +405,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 +415,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 +425,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 +435,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 +445,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 +457,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 +467,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
@@ -289,6 +479,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor
#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) {
+ 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..fb8fdfd1 100644
--- a/src/gwin/gwin.mk
+++ b/src/gwin/gwin.mk
@@ -1,7 +1,9 @@
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 \
diff --git a/src/gwin/gwm.c b/src/gwin/gwm.c
new file mode 100644
index 00000000..5a533c40
--- /dev/null
+++ b/src/gwin/gwm.c
@@ -0,0 +1,144 @@
+/*
+ * 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, coord_t x, coord_t y, coord_t w, coord_t h);
+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,
+};
+
+const GWindowManager GNullWindowManager = {
+ &GNullWindowManagerVMT,
+};
+
+/*-----------------------------------------------
+ * 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, coord_t x, coord_t y, coord_t w, coord_t h) {
+ // Put it on the queue
+ gfxQueueASyncPut(&_GWINList, &gh->wmq);
+
+ // Make sure the size is valid
+ WM_Redim(gh, x, y, w, h);
+
+ // Display it if it is visible
+ WM_Visible(gh);
+ return TRUE;
+}
+
+static void WM_Delete(GHandle gh) {
+ // A real window manager would make the window invisible
+ // (and then clear the area underneath)
+
+ // Just remove it from the queue
+ gfxQueueASyncRemove(&_GWINList, &gh->wmq);
+}
+
+static void WM_Visible(GHandle gh) {
+ 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);
+ } else
+ gwinClear(gh);
+ // A real window manager would also redraw the borders
+ }
+
+ // else
+ // A real window manager would make the window invisible
+ // (and then clear the area underneath)
+
+}
+
+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;
+ gh->x = x; gh->y = y;
+ gh->width = w; gh->height = h;
+}
+
+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/slider.c b/src/gwin/slider.c
index 01df189d..f2052524 100644
--- a/src/gwin/slider.c
+++ b/src/gwin/slider.c
@@ -19,140 +19,237 @@
#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;
+// Prototypes for slider VMT functions
+static void MouseUp(GWidgetObject *gw, coord_t x, coord_t y);
+static void MouseMove(GWidgetObject *gw, coord_t x, coord_t y);
+static void ToggleOn(GWidgetObject *gw, uint16_t role);
+static void DialMove(GWidgetObject *gw, uint16_t role, uint16_t value, uint16_t max);
+static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance);
+static void DialAssign(GWidgetObject *gw, uint16_t role, uint16_t instance);
+static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role);
+static uint16_t DialGet(GWidgetObject *gw, uint16_t role);
+
+// The button VMT table
+static const gwidgetVMT sliderVMT = {
+ {
+ "Slider", // The classname
+ _gwidgetDestroy, // The destroy routine
+ _gwidgetRedraw, // The redraw routine
+ 0, // The after-clear routine
+ },
+ gwinSliderDraw_Std, // The default drawing routine
+ {
+ 0, // Process mouse down events (NOT USED)
+ MouseUp, // Process mouse up events
+ MouseMove, // Process mouse move events
+ },
+ {
+ 2, // 1 toggle role
+ ToggleAssign, // Assign Toggles
+ ToggleGet, // Get Toggles
+ 0, // Process toggle off events (NOT USED)
+ ToggleOn, // Process toggle on events
+ },
+ {
+ 1, // 1 dial roles
+ DialAssign, // Assign Dials
+ DialGet, // Get Dials
+ DialMove, // Process dial move events
+ }
};
-// 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);
- }
- return;
- }
+static const GSliderColors GSliderDefaultColors = {
+ HTML2COLOR(0x404040), // color_edge
+ HTML2COLOR(0x000000), // color_thumb
+ HTML2COLOR(0x00E000), // color_active
+ HTML2COLOR(0xE0E0E0), // color_inactive
+ HTML2COLOR(0xFFFFFF), // color_txt
+};
- // 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;
- }
+// Send the slider event
+static void SendSliderEvent(GWidgetObject *gw) {
+ GSourceListener * psl;
+ GEvent * pe;
+ #define pse ((GEventGWinSlider *)pe)
+
+ // 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
+}
- // If mouse down - track movement
- if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT))
- trackSliderDraw(gh, pme->x-gh->x, pme->y-gh->y);
+// 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);
+}
+// 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
- #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));
- // Update the display
- gwinSliderDraw(gh);
+ // 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);
+ }
- // Generate the event
- break;
- #endif
+ ResetDisplayPos(gsw);
+ _gwidgetRedraw(gh);
- default:
- return;
+ // Generate the event
+ SendSliderEvent(gw);
+ #undef gh
+ #undef gsw
+}
+
+// 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;
}
- // 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);
+ // Update the display
+ _gwidgetRedraw(&gw->g);
+ #undef gsw
+}
+
+// A toggle on has occurred
+static void ToggleOn(GWidgetObject *gw, uint16_t role) {
+ #define gsw ((GSliderObject *)gw)
+
+ if (role) {
+ gwinSetSliderPosition((GHandle)gw, gsw->pos+(gsw->max-gsw->min)/GWIN_SLIDER_TOGGLE_INC);
+ SendSliderEvent(gw);
+ } else {
+ gwinSetSliderPosition((GHandle)gw, gsw->pos-(gsw->max-gsw->min)/GWIN_SLIDER_TOGGLE_INC);
+ SendSliderEvent(gw);
}
+ #undef gsw
+}
- #undef pse
- #undef pme
- #undef pxe
- #undef gsh
+// A dial move event
+static void DialMove(GWidgetObject *gw, uint16_t role, uint16_t value, uint16_t max) {
+#if GFX_USE_GINPUT && GINPUT_NEED_DIAL
+ #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);
+ gwinDraw(&gw->g);
+
+ // Generate the event
+ SendSliderEvent(gw);
#undef gsw
- #undef gh
+#else
+ (void)gw; (void)role; (void)value; (void)max;
+#endif
+}
+
+static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) {
+ if (role)
+ ((GSliderObject *)gw)->t_up = instance;
+ else
+ ((GSliderObject *)gw)->t_dn = instance;
+}
+
+static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role) {
+ return role ? ((GSliderObject *)gw)->t_up : ((GSliderObject *)gw)->t_dn;
+}
+
+static void DialAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) {
+ (void) role;
+ ((GSliderObject *)gw)->dial = instance;
+}
+
+static uint16_t DialGet(GWidgetObject *gw, uint16_t role) {
+ (void) role;
+ return ((GSliderObject *)gw)->dial;
}
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))))
+ if (!(gs = (GSliderObject *)_gwidgetCreate((GWidgetObject *)gs, x, y, width, height, sizeof(GSliderObject), &sliderVMT)))
return 0;
- gs->gwin.type = GW_SLIDER;
- gs->fn = gwinSliderDraw_Std;
- gs->param = 0;
- gwinSetSliderStyle(&gs->gwin, &GSliderDefaultStyle);
+ gs->t_dn = (uint16_t) -1;
+ gs->t_up = (uint16_t) -1;
+ gs->dial = (uint16_t) -1;
+ gs->c = GSliderDefaultColors;
gs->min = 0;
gs->max = 100;
gs->pos = 0;
- gs->tracking = FALSE;
- geventListenerInit(&gs->listener);
- geventRegisterCallback(&gs->listener, gwinSliderCallback, gs);
+ ResetDisplayPos(gs);
return (GHandle)gs;
}
void gwinSetSliderRange(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 +257,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) {
#define gsw ((GSliderObject *)gh)
- if (gh->type != GW_SLIDER)
+ if (gh->vmt != (gwinVMT *)&sliderVMT)
return;
if (gsw->min <= gsw->max) {
@@ -178,125 +276,96 @@ 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)
+void gwinSetSliderColors(GHandle gh, const GSliderColors *pColors) {
+ if (gh->vmt != (gwinVMT *)&sliderVMT)
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)
-
- #if GDISP_NEED_CLIP
- gdispSetClip(gh->x, gh->y, gh->width, gh->height);
- #endif
-
- 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)
- 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);
- 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
+ ((GSliderObject *)gh)->c = *pColors;
}
-void gwinSetSliderCustom(GHandle gh, GSliderDrawFunction fn, void *param) {
- #define gsw ((GSliderObject *)gh)
+void gwinSliderDraw_Std(GWidgetObject *gw, void *param) {
+ #define gsw ((GSliderObject *)gw)
+ (void) param;
- if (gh->type != GW_SLIDER)
+ if (gw->g.vmt != (gwinVMT *)&sliderVMT)
return;
- gsw->fn = fn ? fn : gwinSliderDraw_Std;
- gsw->param = param;
+ 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, gsw->c.color_active);
+ if (gsw->dpos != 0)
+ gdispFillArea(gw->g.x, gw->g.y, gw->g.width, gsw->dpos, gsw->c.color_inactive);
+ gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gsw->c.color_edge);
+ gdispDrawLine(gw->g.x, gw->g.y+gsw->dpos, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos, gsw->c.color_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, gsw->c.color_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, gsw->c.color_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, gsw->c.color_inactive);
+ if (gsw->dpos != 0)
+ gdispFillArea(gw->g.x, gw->g.y, gsw->dpos, gw->g.height, gsw->c.color_active);
+ gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gsw->c.color_edge);
+ gdispDrawLine(gw->g.x+gsw->dpos, gw->g.y, gw->g.x+gsw->dpos, gw->g.y+gw->g.height-1, gsw->c.color_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, gsw->c.color_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, gsw->c.color_thumb);
+ }
+ gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, gsw->c.color_txt, justifyCenter);
#undef gsw
}
-void gwinSliderSetEnabled(GHandle gh, bool_t enabled) {
- if (gh->type != GW_SLIDER)
- return;
+void gwinSliderDraw_Image(GWidgetObject *gw, void *param) {
+ #define gsw ((GSliderObject *)gw)
+ #define gi ((gdispImage *)param)
+ coord_t z, v;
- gh->enabled = enabled;
-}
+ if (gw->g.vmt != (gwinVMT *)&sliderVMT)
+ return;
-void gwinSliderDraw_Std(GHandle gh, bool_t isVertical, coord_t thumbpos, const GSliderDrawStyle *pstyle, void *param) {
- (void) param;
+ 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, gsw->c.color_inactive);
+ 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, gsw->c.color_edge);
+ gdispDrawLine(gw->g.x, gw->g.y+gsw->dpos, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos, gsw->c.color_thumb);
- 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, gsw->c.color_inactive);
+ 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, gsw->c.color_edge);
+ gdispDrawLine(gw->g.x+gsw->dpos, gw->g.y, gw->g.x+gsw->dpos, gw->g.y+gw->g.height-1, gsw->c.color_thumb);
}
-#endif
-
-#if GFX_USE_GINPUT && GINPUT_NEED_DIAL
- bool_t gwinAttachSliderDial(GHandle gh, uint16_t instance) {
- GSourceHandle gsh;
-
- if (gh->type != GW_SLIDER || !(gsh = ginputGetDial(instance)))
- return FALSE;
+ gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, gsw->c.color_txt, justifyCenter);
- return geventAttachSource(&((GSliderObject *)gh)->listener, gsh, 0);
- }
-#endif
+ #undef gsw
+}
#endif /* GFX_USE_GWIN && GWIN_NEED_BUTTON */
/** @} */