aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demos/modules/gwin/widgets/gfxconf.h1
-rw-r--r--demos/modules/gwin/widgets/main.c102
-rw-r--r--include/gfx_rules.h9
-rw-r--r--include/gwin/gwidget.h3
-rw-r--r--include/gwin/options.h7
-rw-r--r--include/gwin/radio.h169
-rw-r--r--src/gwin/gwin.mk1
-rw-r--r--src/gwin/radio.c260
8 files changed, 532 insertions, 20 deletions
diff --git a/demos/modules/gwin/widgets/gfxconf.h b/demos/modules/gwin/widgets/gfxconf.h
index 5cf344e4..1665047c 100644
--- a/demos/modules/gwin/widgets/gfxconf.h
+++ b/demos/modules/gwin/widgets/gfxconf.h
@@ -80,6 +80,7 @@
#define GWIN_NEED_CHECKBOX TRUE
#define GWIN_NEED_LABEL TRUE
#define GWIN_NEED_IMAGE TRUE
+#define GWIN_NEED_RADIO TRUE
/* Features for the GINPUT sub-system. */
#define GINPUT_NEED_MOUSE TRUE
diff --git a/demos/modules/gwin/widgets/main.c b/demos/modules/gwin/widgets/main.c
index fdd5ed43..e44ce6b0 100644
--- a/demos/modules/gwin/widgets/main.c
+++ b/demos/modules/gwin/widgets/main.c
@@ -30,19 +30,36 @@
static GListener gl;
static GHandle ghConsole;
+static GHandle ghTabButtons, ghTabSliders, ghTabCheckboxes, ghTabLabels, ghTabRadios, ghTabImages;
static GHandle ghButton1, ghButton2, ghButton3, ghButton4;
static GHandle ghSlider1, ghSlider2, ghSlider3, ghSlider4;
static GHandle ghCheckbox1, ghCheckbox2;
static GHandle ghLabel1;
+static GHandle ghRadio1, ghRadio2;
+//static GHandle ghImage1;
#define ScrWidth gdispGetWidth()
#define ScrHeight gdispGetHeight()
+#define TAB_HEIGHT 30
#define BUTTON_WIDTH 50
#define BUTTON_HEIGHT 30
#define SLIDER_WIDTH 20
#define CHECKBOX_WIDTH 80
#define CHECKBOX_HEIGHT 20
+#define RADIO_WIDTH 50
+#define RADIO_HEIGHT 20
+#define GROUP_TABS 0
+#define GROUP_R1R2 1
+
+static GHandle createTab(GWidgetInit *pwi) {
+ GHandle gh;
+
+ gh = gwinCreateRadio(NULL, pwi, GROUP_TABS);
+ gwinSetCustomDraw(gh, gwinRadioDraw_Tab, 0);
+ gwinSetVisible(gh, TRUE);
+ return gh;
+}
int main(void) {
GEvent * pe;
@@ -69,10 +86,17 @@ int main(void) {
{
GWidgetInit wi;
- wi.g.show = TRUE;
+ // Create the Tabs
+ wi.g.show = FALSE; wi.g.width = ScrWidth/6; wi.g.height = TAB_HEIGHT; wi.g.y = 0;
+ wi.g.x = 0*wi.g.width; wi.text = "Buttons"; ghTabButtons = createTab(&wi);
+ wi.g.x = 1*wi.g.width; wi.text = "Sliders"; ghTabSliders = createTab(&wi);
+ wi.g.x = 2*wi.g.width; wi.text = "Checkbox"; ghTabCheckboxes = createTab(&wi);
+ wi.g.x = 3*wi.g.width; wi.text = "Labels"; ghTabLabels = createTab(&wi);
+ wi.g.x = 4*wi.g.width; wi.text = "Radios"; ghTabRadios = createTab(&wi);
+ wi.g.x = 5*wi.g.width; wi.text = "Images"; ghTabImages = createTab(&wi);
// Buttons
- wi.g.width = BUTTON_WIDTH; wi.g.height = BUTTON_HEIGHT; wi.g.y = 0;
+ wi.g.width = BUTTON_WIDTH; wi.g.height = BUTTON_HEIGHT; wi.g.y = TAB_HEIGHT+5;
wi.g.x = 0+0*(BUTTON_WIDTH+1); wi.text = "B1"; ghButton1 = gwinCreateButton(NULL, &wi);
wi.g.x = 0+1*(BUTTON_WIDTH+1); wi.text = "B2"; ghButton2 = gwinCreateButton(NULL, &wi);
wi.g.x = 0+2*(BUTTON_WIDTH+1); wi.text = "B3"; ghButton3 = gwinCreateButton(NULL, &wi);
@@ -90,24 +114,25 @@ int main(void) {
// Checkboxes - for the 2nd checkbox we apply special drawing before making it visible
wi.g.width = CHECKBOX_WIDTH; wi.g.height = CHECKBOX_HEIGHT; wi.g.x = 0;
- wi.g.y = BUTTON_HEIGHT+1+0*(CHECKBOX_HEIGHT+1); wi.text = "C1"; ghCheckbox1 = gwinCreateCheckbox(NULL, &wi);
- wi.g.show = FALSE;
- wi.g.y = BUTTON_HEIGHT+1+1*(CHECKBOX_HEIGHT+1); wi.text = "C2"; ghCheckbox2 = gwinCreateCheckbox(NULL, &wi);
+ wi.g.y = TAB_HEIGHT+5+0*(CHECKBOX_HEIGHT+1); wi.text = "C1"; ghCheckbox1 = gwinCreateCheckbox(NULL, &wi);
+ wi.g.y = TAB_HEIGHT+5+1*(CHECKBOX_HEIGHT+1); wi.text = "C2"; ghCheckbox2 = gwinCreateCheckbox(NULL, &wi);
gwinSetCustomDraw(ghCheckbox2, gwinCheckboxDraw_CheckOnRight, 0);
- gwinSetVisible(ghCheckbox2, TRUE);
- wi.g.show = TRUE; wi.g.width = 0;
- wi.g.y = BUTTON_HEIGHT+1+2*(CHECKBOX_HEIGHT+1); wi.text = "L1"; ghLabel1 = gwinLabelCreate(NULL, &wi);
+ // Labels
+ wi.g.width = 0; // dynamic width
+ wi.g.y = TAB_HEIGHT+5+2*(CHECKBOX_HEIGHT+1); wi.text = "L1"; ghLabel1 = gwinLabelCreate(NULL, &wi);
+
+ // Radio Buttons
+ wi.g.width = RADIO_WIDTH; wi.g.height = RADIO_HEIGHT; wi.g.y = TAB_HEIGHT+5;
+ wi.g.x = 0*wi.g.width; wi.text = "Yes"; ghRadio1 = gwinCreateRadio(NULL, &wi, GROUP_R1R2);
+ wi.g.x = 1*wi.g.width; wi.text = "No"; ghRadio2 = gwinCreateRadio(NULL, &wi, GROUP_R1R2);
// Console - we apply some special colors before making it visible
- wi.g.show = FALSE;
wi.g.width = ScrWidth/2-1; wi.g.height = ScrHeight/2-1;
wi.g.x = ScrWidth/2+1; wi.g.y = ScrHeight/2+1;
ghConsole = gwinCreateConsole(NULL, &wi.g);
gwinSetColor(ghConsole, Yellow);
gwinSetBgColor(ghConsole, Black);
- gwinSetVisible(ghConsole, TRUE);
- gwinClear(ghConsole);
}
// Assign toggles and dials to the buttons & sliders etc.
@@ -120,15 +145,12 @@ int main(void) {
gwinAttachDial(ghSlider3, 0, 1);
#endif
- gfxSleepMilliseconds(5000);
- gwinSetBgColor(ghLabel1, Blue);
- gwinSetColor(ghLabel1, Yellow);
- gwinSetText(ghLabel1, "Very Big Label", FALSE);
+ // Make the console visible
+ gwinSetVisible(ghConsole, TRUE);
+ gwinClear(ghConsole);
- gfxSleepMilliseconds(5000);
- gwinSetBgColor(ghLabel1, Yellow);
- gwinSetColor(ghLabel1, Red);
- gwinSetText(ghLabel1, "L1", FALSE);
+ // Press the Buttons Tab
+ gwinPressRadio(ghTabButtons);
while(1) {
// Get an Event
@@ -144,6 +166,48 @@ int main(void) {
case GEVENT_GWIN_CHECKBOX:
gwinPrintf(ghConsole, "Checkbox %s=%s\n", gwinGetText(((GEventGWinCheckbox *)pe)->checkbox), ((GEventGWinCheckbox *)pe)->isChecked ? "Checked" : "UnChecked");
break;
+ case GEVENT_GWIN_RADIO:
+ gwinPrintf(ghConsole, "Radio Group %u=%s\n", ((GEventGWinRadio *)pe)->group, gwinGetText(((GEventGWinRadio *)pe)->radio));
+
+ // Is this the tab radio's
+ if (((GEventGWinRadio *)pe)->group == GROUP_TABS) {
+
+ // Do some special animation for Label1
+ if (((GEventGWinRadio *)pe)->radio == ghTabLabels) {
+ gwinSetBgColor(ghLabel1, gwinGetDefaultBgColor());
+ gwinSetColor(ghLabel1, gwinGetDefaultColor());
+ }
+
+ // Set control visibility depending on the tab selected
+ gwinSetVisible(ghButton1, ((GEventGWinRadio *)pe)->radio == ghTabButtons);
+ gwinSetVisible(ghButton2, ((GEventGWinRadio *)pe)->radio == ghTabButtons);
+ gwinSetVisible(ghButton3, ((GEventGWinRadio *)pe)->radio == ghTabButtons);
+ gwinSetVisible(ghButton4, ((GEventGWinRadio *)pe)->radio == ghTabButtons);
+ gwinSetVisible(ghSlider1, ((GEventGWinRadio *)pe)->radio == ghTabSliders);
+ gwinSetVisible(ghSlider2, ((GEventGWinRadio *)pe)->radio == ghTabSliders);
+ gwinSetVisible(ghSlider3, ((GEventGWinRadio *)pe)->radio == ghTabSliders);
+ gwinSetVisible(ghSlider4, ((GEventGWinRadio *)pe)->radio == ghTabSliders);
+ gwinSetVisible(ghCheckbox1, ((GEventGWinRadio *)pe)->radio == ghTabCheckboxes);
+ gwinSetVisible(ghCheckbox2, ((GEventGWinRadio *)pe)->radio == ghTabCheckboxes);
+ gwinSetVisible(ghLabel1, ((GEventGWinRadio *)pe)->radio == ghTabLabels);
+ gwinSetVisible(ghRadio1, ((GEventGWinRadio *)pe)->radio == ghTabRadios);
+ gwinSetVisible(ghRadio2, ((GEventGWinRadio *)pe)->radio == ghTabRadios);
+ //gwinSetVisible(ghImage1, ((GEventGWinRadio *)pe)->radio == ghTabImages);
+
+ // Do some special animation for Label1
+ if (((GEventGWinRadio *)pe)->radio == ghTabLabels) {
+ gfxSleepMilliseconds(1000);
+ gwinSetBgColor(ghLabel1, Blue);
+ gwinSetColor(ghLabel1, Yellow);
+ gwinSetText(ghLabel1, "Very Big Label", FALSE);
+
+ gfxSleepMilliseconds(1000);
+ gwinSetBgColor(ghLabel1, Yellow);
+ gwinSetColor(ghLabel1, Red);
+ gwinSetText(ghLabel1, "L1", FALSE);
+ }
+ }
+ break;
default:
gwinPrintf(ghConsole, "Unknown %d\n", pe->type);
break;
diff --git a/include/gfx_rules.h b/include/gfx_rules.h
index bfe017d3..ddad82a7 100644
--- a/include/gfx_rules.h
+++ b/include/gfx_rules.h
@@ -51,7 +51,14 @@
#error "GWIN: GDISP_NEED_IMAGE is required when GWIN_NEED_IMAGE is TRUE."
#endif
#endif
- #if GWIN_NEED_BUTTON || GWIN_NEED_SLIDER || GWIN_NEED_CHECKBOX || GWIN_NEED_LABEL
+ #if GWIN_NEED_RADIO
+ #if !GDISP_NEED_CIRCLE
+ #if GFX_DISPLAY_RULE_WARNINGS
+ #warning "GWIN: GDISP_NEED_CIRCLE should be set to TRUE for much nicer radio button widgets."
+ #endif
+ #endif
+ #endif
+ #if GWIN_NEED_BUTTON || GWIN_NEED_SLIDER || GWIN_NEED_CHECKBOX || GWIN_NEED_LABEL || GWIN_NEED_RADIO
#if !GWIN_NEED_WIDGET
#if GFX_DISPLAY_RULE_WARNINGS
#warning "GWIN: GWIN_NEED_WIDGET is required when a Widget is used. It has been turned on for you."
diff --git a/include/gwin/gwidget.h b/include/gwin/gwidget.h
index a2cf7337..ffd8e26f 100644
--- a/include/gwin/gwidget.h
+++ b/include/gwin/gwidget.h
@@ -195,6 +195,9 @@ bool_t gwinAttachListener(GListener *pl);
#if GWIN_NEED_CHECKBOX || defined(__DOXYGEN__)
#include "gwin/checkbox.h"
#endif
+#if GWIN_NEED_RADIO || defined(__DOXYGEN__)
+ #include "gwin/radio.h"
+#endif
#endif /* _GWIDGET_H */
/** @} */
diff --git a/include/gwin/options.h b/include/gwin/options.h
index 11ab7d44..5de2e43b 100644
--- a/include/gwin/options.h
+++ b/include/gwin/options.h
@@ -83,6 +83,13 @@
#ifndef GWIN_NEED_LABEL
#define GWIN_NEED_LABEL FALSE
#endif
+ /**
+ * @brief Should radio button functions be included.
+ * @details Defaults to FALSE
+ */
+ #ifndef GWIN_NEED_RADIO
+ #define GWIN_NEED_RADIO FALSE
+ #endif
/**
* @}
*
diff --git a/include/gwin/radio.h b/include/gwin/radio.h
new file mode 100644
index 00000000..8d4e32a7
--- /dev/null
+++ b/include/gwin/radio.h
@@ -0,0 +1,169 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://chibios-gfx.com/license.html
+ */
+
+/**
+ * @file include/gwin/radio.h
+ * @brief GWIN Graphic window subsystem header file.
+ *
+ * @defgroup RadioButton RadioButton
+ * @ingroup GWIN
+ *
+ * @details GWIN allows it to easily create radio buttons with different styles.
+ *
+ * @pre GFX_USE_GWIN must be set to TRUE in your gfxconf.h
+ * @pre GWIN_NEED_RADIO must be set to TRUE in your gfxconf.h
+ * @{
+ */
+
+#ifndef _GWIN_RADIO_H
+#define _GWIN_RADIO_H
+
+/* This file is included within "gwin/gwidget.h" */
+
+/**
+ * @brief The Event Type for a Radio Event
+ */
+#define GEVENT_GWIN_RADIO (GEVENT_GWIN_FIRST+3)
+
+/**
+ * @brief A Button Event
+ * @note There are currently no GEventGWinRadio listening flags - use 0 as the flags to @p gwinAttachListener()
+ */
+typedef struct GEventGWinRadio {
+ GEventType type; // The type of this event (GEVENT_GWIN_RADIO)
+ GHandle radio; // The radio button that has been depressed
+ uint16_t group; // The group for this radio button
+} GEventGWinRadio;
+
+/**
+ * @brief Button colors
+ */
+typedef struct GRadioColors {
+ color_t color_edge;
+ color_t color_fill;
+ color_t color_txt;
+} GRadioColors;
+
+/**
+ * @brief The radio button widget structure
+ * @note Do not use the members directly - treat it as a black-box.
+ */
+typedef struct GRadioObject_t {
+ GWidgetObject w;
+ #if GINPUT_NEED_TOGGLE
+ uint16_t toggle;
+ #endif
+ uint16_t group;
+ GRadioColors c_up;
+ GRadioColors c_dn;
+ GRadioColors c_dis;
+} GRadioObject;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Create a radio widget.
+ * @return NULL if there is no resultant drawing area, otherwise a window handle.
+ *
+ * @param[in] gb The GRadioObject structure to initialise. If this is NULL the structure is dynamically allocated.
+ * @param[in] pInit The initialisation parameters
+ * @param[in] group The group of radio buttons this radio button belongs to.
+ *
+ * @note Only one radio button in any group is ever pressed at one time. Pressing one radio button will
+ * release all others in the group.
+ * @note The drawing color and the background color get set to the current defaults. If you haven't called
+ * @p gwinSetDefaultColor() or @p gwinSetDefaultBgColor() then these are White and Black respectively.
+ * @note The font gets set to the current default font. If you haven't called @p gwinSetDefaultFont() then there
+ * is no default font and text drawing operations will no nothing.
+ * @note A radio button remembers its normal drawing state. If there is a window manager then it is automatically
+ * redrawn if the window is moved or its visibility state is changed.
+ * @note A radio button supports mouse and a toggle input.
+ * @note When assigning a toggle, only one toggle is supported. If you try to assign more than one toggle it will
+ * forget the previous toggle. When assigning a toggle the role parameter must be 0.
+ *
+ * @api
+ */
+GHandle gwinCreateRadio(GRadioObject *gb, const GWidgetInit *pInit, uint16_t group);
+
+/**
+ * @brief Set the colors of a button.
+ *
+ * @param[in] gh The window handle (must be a radio widget)
+ * @param[in] pUp The colors for the button when in the up state.
+ * @param[in] pDown The colors for the button when in the down state.
+ * @param[in] pDisabled The colors for the button when it is disabled.
+ *
+ * @note The button is not automatically redrawn. Call gwinButtonDraw() after changing the button style
+ * @note The button style is copied into the internal button structure - there is no need to
+ * maintain static style structures (they can be temporary structures on the stack).
+ * @note The pUp, pDown and pDisabled parameters can be NULL. If they are then the existing color styles
+ * are not changed for that button state.
+ * @note Some custom drawn buttons will ignore he specified colors
+ *
+ * @api
+ */
+void gwinSetRadioColors(GHandle gh, const GRadioColors *pUp, const GRadioColors *pDown, const GRadioColors *pDisabled);
+
+/**
+ * @brief Press this radio button (and by definition unset any others in the group)
+ *
+ * @param[in] gh The window handle (must be a radio widget)
+ *
+ * @api
+ */
+void gwinPressRadio(GHandle gh);
+
+/**
+ * @brief Is the radio button currently pressed
+ * @return TRUE if the button is pressed
+ *
+ * @param[in] gh The window handle (must be a radio widget)
+ *
+ * @api
+ */
+bool_t gwinIsRadioPressed(GHandle gh);
+
+/**
+ * @brief Find the currently pressed radio button in the specified group
+ * @return The handle of the pressed radio button or NULL if none are pressed
+ *
+ * @param[in] gh The window handle (must be a radio widget)
+ *
+ * @api
+ */
+GHandle gwinActiveRadio(uint16_t group);
+
+/**
+ * @brief Some custom radio button drawing routines
+ * @details These function may be passed to @p gwinSetCustomDraw() to get different radio button drawing styles
+ *
+ * @param[in] gw The widget object (in this case a radio button)
+ * @param[in] param A parameter passed in from the user
+ *
+ * @note In your custom radio drawing function you may optionally call these
+ * standard functions and then draw your extra details on top.
+ * @note The standard functions below ignore the param parameter.
+ * @note These custom drawing routines don't have to worry about setting clipping as the framework
+ * sets clipping to the object window prior to calling these routines.
+ *
+ * @api
+ * @{
+ */
+void gwinRadioDraw_Radio(GWidgetObject *gw, void *param); // @< A standard radio button
+void gwinRadioDraw_Button(GWidgetObject *gw, void *param); // @< Draw as a button
+void gwinRadioDraw_Tab(GWidgetObject *gw, void *param); // @< Draw as a tab
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GWIN_RADIO_H */
+/** @} */
+
diff --git a/src/gwin/gwin.mk b/src/gwin/gwin.mk
index b9e6a9ee..92b10b7b 100644
--- a/src/gwin/gwin.mk
+++ b/src/gwin/gwin.mk
@@ -8,4 +8,5 @@ GFXSRC += $(GFXLIB)/src/gwin/gwin.c \
$(GFXLIB)/src/gwin/checkbox.c \
$(GFXLIB)/src/gwin/gimage.c \
$(GFXLIB)/src/gwin/label.c \
+ $(GFXLIB)/src/gwin/radio.c \
diff --git a/src/gwin/radio.c b/src/gwin/radio.c
new file mode 100644
index 00000000..d1c65dbc
--- /dev/null
+++ b/src/gwin/radio.c
@@ -0,0 +1,260 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://chibios-gfx.com/license.html
+ */
+
+/**
+ * @file src/gwin/radio.c
+ * @brief GWIN sub-system radio button code.
+ *
+ * @defgroup RadioButton RadioButton
+ * @ingroup GWIN
+ *
+ * @{
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GWIN && GWIN_NEED_RADIO
+
+#include "gwin/class_gwin.h"
+
+// Our pressed state
+#define GRADIO_FLG_PRESSED (GWIN_FIRST_CONTROL_FLAG<<0)
+
+// Default color scheme
+static const GRadioColors GRadioDefaultColorsUp = {
+ HTML2COLOR(0x404040), // color_up_edge;
+ HTML2COLOR(0xE0E0E0), // color_up_fill;
+ HTML2COLOR(0x000000), // color_up_txt;
+};
+static const GRadioColors GRadioDefaultColorsDown = {
+ HTML2COLOR(0x404040), // color_dn_edge;
+ HTML2COLOR(0x808080), // color_dn_fill;
+ HTML2COLOR(0x404040), // color_dn_txt;
+};
+static const GRadioColors GRadioDefaultColorsDisabled = {
+ HTML2COLOR(0x808080), // color_dis_edge;
+ HTML2COLOR(0xE0E0E0), // color_dis_fill;
+ HTML2COLOR(0xC0C0C0), // color_dis_txt;
+};
+
+// Send the button event
+static void SendButtonEvent(GWidgetObject *gw) {
+ GSourceListener * psl;
+ GEvent * pe;
+ #define pbe ((GEventGWinRadio *)pe)
+
+ // Trigger a GWIN Button Event
+ psl = 0;
+ while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) {
+ if (!(pe = geventGetEventBuffer(psl)))
+ continue;
+ pbe->type = GEVENT_GWIN_RADIO;
+ pbe->radio = (GHandle)gw;
+ pbe->group = ((GRadioObject *)gw)->group;
+ geventSendEvent(psl);
+ }
+
+ #undef pbe
+}
+
+#if GINPUT_NEED_MOUSE
+ // A mouse down has occurred over the button
+ static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) {
+ (void) x; (void) y;
+
+ gwinPressRadio((GHandle)gw);
+ }
+#endif
+
+#if GINPUT_NEED_TOGGLE
+ // A toggle on has occurred
+ static void ToggleOn(GWidgetObject *gw, uint16_t role) {
+ (void) role;
+
+ gwinPressRadio((GHandle)gw);
+ }
+
+ static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) {
+ (void) role;
+ ((GRadioObject *)gw)->toggle = instance;
+ }
+
+ static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role) {
+ (void) role;
+ return ((GRadioObject *)gw)->toggle;
+ }
+#endif
+
+// The radio button VMT table
+static const gwidgetVMT radioVMT = {
+ {
+ "Radio", // The classname
+ sizeof(GRadioObject), // The object size
+ _gwidgetDestroy, // The destroy routine
+ _gwidgetRedraw, // The redraw routine
+ 0, // The after-clear routine
+ },
+ gwinRadioDraw_Radio, // The default drawing routine
+ #if GINPUT_NEED_MOUSE
+ {
+ MouseDown, // Process mouse down events
+ 0, // Process mouse up events (NOT USED)
+ 0, // Process mouse move events (NOT USED)
+ },
+ #endif
+ #if GINPUT_NEED_TOGGLE
+ {
+ 1, // 1 toggle role
+ ToggleAssign, // Assign Toggles
+ ToggleGet, // Get Toggles
+ 0, // Process toggle off events (NOT USED)
+ ToggleOn, // Process toggle on events
+ },
+ #endif
+ #if GINPUT_NEED_DIAL
+ {
+ 0, // No dial roles
+ 0, // Assign Dials (NOT USED)
+ 0, // Get Dials (NOT USED)
+ 0, // Process dial move events (NOT USED)
+ },
+ #endif
+};
+
+GHandle gwinCreateRadio(GRadioObject *gw, const GWidgetInit *pInit, uint16_t group) {
+ if (!(gw = (GRadioObject *)_gwidgetCreate(&gw->w, pInit, &radioVMT)))
+ return 0;
+
+ #if GINPUT_NEED_TOGGLE
+ gw->toggle = GWIDGET_NO_INSTANCE;
+ #endif
+ gw->group = group;
+ gw->c_up = GRadioDefaultColorsUp;
+ gw->c_dn = GRadioDefaultColorsDown;
+ gw->c_dis = GRadioDefaultColorsDisabled;
+ gwinSetVisible((GHandle)gw, pInit->g.show);
+ return (GHandle)gw;
+}
+
+void gwinSetRadioColors(GHandle gh, const GRadioColors *pUp, const GRadioColors *pDown, const GRadioColors *pDisabled) {
+ if (gh->vmt != (gwinVMT *)&radioVMT)
+ return;
+
+ if (pUp) ((GRadioObject *)gh)->c_up = *pUp;
+ if (pDown) ((GRadioObject *)gh)->c_dn = *pDown;
+ if (pDisabled) ((GRadioObject *)gh)->c_dis = *pDisabled;
+}
+
+void gwinPressRadio(GHandle gh) {
+ GHandle gx;
+
+ if (gh->vmt != (gwinVMT *)&radioVMT || (gh->flags & GRADIO_FLG_PRESSED))
+ return;
+
+ if ((gx = gwinActiveRadio(((GRadioObject *)gh)->group))) {
+ gx->flags &= ~GRADIO_FLG_PRESSED;
+ _gwidgetRedraw(gx);
+ }
+ gh->flags |= GRADIO_FLG_PRESSED;
+ _gwidgetRedraw(gh);
+ SendButtonEvent((GWidgetObject *)gh);
+}
+
+bool_t gwinIsRadioPressed(GHandle gh) {
+ if (gh->vmt != (gwinVMT *)&radioVMT)
+ return FALSE;
+
+ return (gh->flags & GRADIO_FLG_PRESSED) ? TRUE : FALSE;
+}
+
+/**
+ * @brief Find the currently pressed radio button in the specified group
+ * @return The handle of the pressed radio button or NULL if none are pressed
+ *
+ * @param[in] gh The window handle (must be a radio widget)
+ *
+ * @api
+ */
+GHandle gwinActiveRadio(uint16_t group) {
+ const gfxQueueASyncItem * qi;
+ GHandle gh;
+
+ for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) {
+ gh = QItem2GWindow(qi);
+ if (gh->vmt == (gwinVMT *)&radioVMT && ((GRadioObject *)gh)->group == group && (gh->flags & GRADIO_FLG_PRESSED))
+ return gh;
+ }
+ return 0;
+}
+
+/*----------------------------------------------------------
+ * Custom Draw Routines
+ *----------------------------------------------------------*/
+
+static GRadioColors *getDrawColors(GWidgetObject *gw) {
+ if (!(gw->g.flags & GWIN_FLG_ENABLED)) return &((GRadioObject *)gw)->c_dis;
+ if ((gw->g.flags & GRADIO_FLG_PRESSED)) return &((GRadioObject *)gw)->c_dn;
+ return &((GRadioObject *)gw)->c_up;
+}
+
+void gwinRadioDraw_Radio(GWidgetObject *gw, void *param) {
+ #define gcw ((GRadioObject *)gw)
+ coord_t ld, df;
+ GRadioColors * pcol;
+ (void) param;
+
+ if (gw->g.vmt != (gwinVMT *)&radioVMT) return;
+ pcol = getDrawColors(gw);
+
+ ld = gw->g.width < gw->g.height ? gw->g.width : gw->g.height;
+
+ #if GDISP_NEED_CIRCLE
+ df = ld/2;
+ gdispFillArea(gw->g.x, gw->g.y, ld, ld, gw->g.bgcolor);
+ gdispDrawCircle(gw->g.x+df, gw->g.y+df, df, pcol->color_edge);
+
+ if (gw->g.flags & GRADIO_FLG_PRESSED)
+ gdispFillCircle(gw->g.x+df, gw->g.y+df, df <= 2 ? 1 : (df-2), pcol->color_fill);
+ #else
+ gdispFillArea(gw->g.x+1, gw->g.y+1, ld, ld-2, gw->g.bgcolor);
+ gdispDrawBox(gw->g.x, gw->g.y, ld, ld, pcol->color_edge);
+
+ df = ld < 4 ? 1 : 2;
+ if (gw->g.flags & GRADIO_FLG_PRESSED)
+ gdispFillArea(gw->g.x+df, gw->g.y+df, ld-2*df, ld-2*df, pcol->color_fill);
+ #endif
+
+ gdispFillStringBox(gw->g.x+ld+1, gw->g.y, gw->g.width-ld-1, gw->g.height, gw->txt, gw->g.font, pcol->color_txt, gw->g.bgcolor, justifyLeft);
+ #undef gcw
+}
+
+void gwinRadioDraw_Button(GWidgetObject *gw, void *param) {
+ (void) param;
+ GRadioColors * pcol;
+
+ if (gw->g.vmt != (gwinVMT *)&radioVMT) return;
+ pcol = getDrawColors(gw);
+
+ gdispFillStringBox(gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->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 gwinRadioDraw_Tab(GWidgetObject *gw, void *param) {
+ (void) param;
+ GRadioColors * pcol;
+
+ if (gw->g.vmt != (gwinVMT *)&radioVMT) 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);
+}
+
+#endif /* GFX_USE_GWIN && GWIN_NEED_BUTTON */
+/** @} */
+