µGFX  2.9
version 2.9
gwin_radio.c
Go to the documentation of this file.
1 /*
2  * This file is subject to the terms of the GFX License. If a copy of
3  * the license was not distributed with this file, you can obtain one at:
4  *
5  * http://ugfx.io/license.html
6  */
7 
8 /**
9  * @file src/gwin/gwin_radio.c
10  * @brief GWIN sub-system radio button code
11  */
12 
13 #include "../../gfx.h"
14 
15 #if GFX_USE_GWIN && GWIN_NEED_RADIO
16 
17 #include "gwin_class.h"
18 
19 #define GRADIO_TAB_CNR 8 // Diagonal corner on active tab
20 #define GRADIO_TOP_FADE 50 // (GRADIO_TOP_FADE/255)% fade to white for top of tab/button
21 #define GRADIO_BOTTOM_FADE 25 // (GRADIO_BOTTOM_FADE/255)% fade to black for bottom of tab/button
22 #define GRADIO_OUTLINE_FADE 128 // (GRADIO_OUTLINE_FADE/255)% fade to background for active tab edge
23 
24 // Send the button event
25 static void SendRadioEvent(GWidgetObject *gw) {
26  GSourceListener * psl;
27  GEvent * pe;
28  #define pbe ((GEventGWinRadio *)pe)
29 
30  // Trigger a GWIN Button Event
31  psl = 0;
32  while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) {
33  if (!(pe = geventGetEventBuffer(psl)))
34  continue;
35  pbe->type = GEVENT_GWIN_RADIO;
36  pbe->gwin = (GHandle)gw;
37  pbe->group = ((GRadioObject *)gw)->group;
38  #if GWIN_WIDGET_TAGS
39  pbe->tag = gw->tag;
40  #endif
41  geventSendEvent(psl);
42  }
43 
44  #undef pbe
45 }
46 
47 #if GINPUT_NEED_MOUSE
48  // A mouse down has occurred over the button
49  static void RadioMouseDown(GWidgetObject *gw, gCoord x, gCoord y) {
50  (void) x; (void) y;
51 
53  }
54 #endif
55 
56 #if GINPUT_NEED_KEYBOARD || GWIN_NEED_KEYBOARD
57  static void RadioKeyboard(GWidgetObject* gw, GEventKeyboard* pke)
58  {
59  // Only react on KEYDOWN events. Ignore KEYUP events.
60  if ((pke->keystate & GKEYSTATE_KEYUP))
61  return;
62 
63  // ENTER and SPACE keys to check/uncheck the checkbox
64  if (pke->c[0] == GKEY_ENTER || pke->c[0] == GKEY_SPACE) {
66  }
67  }
68 #endif
69 
70 #if GINPUT_NEED_TOGGLE
71  // A toggle on has occurred
72  static void RadioToggleOn(GWidgetObject *gw, gU16 role) {
73  (void) role;
74 
76  }
77 
78  static void RadioToggleAssign(GWidgetObject *gw, gU16 role, gU16 instance) {
79  (void) role;
80  ((GRadioObject *)gw)->toggle = instance;
81  }
82 
83  static gU16 RadioToggleGet(GWidgetObject *gw, gU16 role) {
84  (void) role;
85  return ((GRadioObject *)gw)->toggle;
86  }
87 #endif
88 
89 // The radio button VMT table
90 static const gwidgetVMT radioVMT = {
91  {
92  "Radio", // The classname
93  sizeof(GRadioObject), // The object size
94  _gwidgetDestroy, // The destroy routine
95  _gwidgetRedraw, // The redraw routine
96  0, // The after-clear routine
97  },
98  gwinRadioDraw_Radio, // The default drawing routine
99  #if GINPUT_NEED_MOUSE
100  {
101  RadioMouseDown, // Process mouse down events
102  0, // Process mouse up events (NOT USED)
103  0, // Process mouse move events (NOT USED)
104  },
105  #endif
106  #if GINPUT_NEED_KEYBOARD || GWIN_NEED_KEYBOARD
107  {
108  RadioKeyboard // Process keyboard events
109  },
110  #endif
111  #if GINPUT_NEED_TOGGLE
112  {
113  1, // 1 toggle role
114  RadioToggleAssign, // Assign Toggles
115  RadioToggleGet, // Get Toggles
116  0, // Process toggle off events (NOT USED)
117  RadioToggleOn, // Process toggle on events
118  },
119  #endif
120  #if GINPUT_NEED_DIAL
121  {
122  0, // No dial roles
123  0, // Assign Dials (NOT USED)
124  0, // Get Dials (NOT USED)
125  0, // Process dial move events (NOT USED)
126  },
127  #endif
128 };
129 
130 GHandle gwinGRadioCreate(GDisplay *g, GRadioObject *gw, const GWidgetInit *pInit, gU16 group) {
131  if (!(gw = (GRadioObject *)_gwidgetCreate(g, &gw->w, pInit, &radioVMT)))
132  return 0;
133 
134  #if GINPUT_NEED_TOGGLE
135  gw->toggle = GWIDGET_NO_INSTANCE;
136  #endif
137  gw->group = group;
138  gwinSetVisible((GHandle)gw, pInit->g.show);
139  return (GHandle)gw;
140 }
141 
142 void gwinRadioPress(GHandle gh) {
143  GHandle gx;
144 
145  if (gh->vmt != (gwinVMT *)&radioVMT || (gh->flags & GRADIO_FLG_PRESSED))
146  return;
147 
148  if ((gx = gwinRadioGetActive(((GRadioObject *)gh)->group))) {
149  gx->flags &= ~GRADIO_FLG_PRESSED;
150  _gwinUpdate(gx);
151  }
152  gh->flags |= GRADIO_FLG_PRESSED;
153  _gwinUpdate(gh);
154  SendRadioEvent((GWidgetObject *)gh);
155 }
156 
157 gBool gwinRadioIsPressed(GHandle gh) {
158  if (gh->vmt != (gwinVMT *)&radioVMT)
159  return gFalse;
160 
161  return (gh->flags & GRADIO_FLG_PRESSED) ? gTrue : gFalse;
162 }
163 
164 GHandle gwinRadioGetActive(gU16 group) {
165  GHandle gh;
166 
167  for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) {
168  if (gh->vmt == (gwinVMT *)&radioVMT && ((GRadioObject *)gh)->group == group && (gh->flags & GRADIO_FLG_PRESSED))
169  return gh;
170  }
171  return 0;
172 }
173 
174 /*----------------------------------------------------------
175  * Custom Draw Routines
176  *----------------------------------------------------------*/
177 
178 static const GColorSet *getDrawColors(GWidgetObject *gw) {
179  if (!(gw->g.flags & GWIN_FLG_SYSENABLED)) return &gw->pstyle->disabled;
180  if ((gw->g.flags & GRADIO_FLG_PRESSED)) return &gw->pstyle->pressed;
181  return &gw->pstyle->enabled;
182 }
183 
184 void gwinRadioDraw_Radio(GWidgetObject *gw, void *param) {
185  #define gcw ((GRadioObject *)gw)
186  gCoord ld, df;
187  const GColorSet * pcol;
188  (void) param;
189 
190  if (gw->g.vmt != (gwinVMT *)&radioVMT) return;
191  pcol = getDrawColors(gw);
192 
193  ld = gw->g.width < gw->g.height ? gw->g.width : gw->g.height;
194 
195  #if GDISP_NEED_CIRCLE
196  df = (ld-1)/2;
197  gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, ld, ld, gw->pstyle->background);
198  gdispGDrawCircle(gw->g.display, gw->g.x+df, gw->g.y+df, df, pcol->edge);
199 
200  if (gw->g.flags & GRADIO_FLG_PRESSED)
201  gdispGFillCircle(gw->g.display, gw->g.x+df, gw->g.y+df, df <= 2 ? 1 : (df-2), pcol->fill);
202  #else
203  gdispGFillArea(gw->g.display, gw->g.x+1, gw->g.y+1, ld, ld-2, gw->pstyle->background);
204  gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, ld, ld, pcol->edge);
205 
206  df = ld < 4 ? 1 : 2;
207  if (gw->g.flags & GRADIO_FLG_PRESSED)
208  gdispGFillArea(gw->g.display, gw->g.x+df, gw->g.y+df, ld-2*df, ld-2*df, pcol->fill);
209  #endif
210 
211  _gwidgetDrawFocusCircle(gw, df);
212 
213  gdispGFillStringBox(gw->g.display, gw->g.x+ld+1, gw->g.y, gw->g.width-ld-1, gw->g.height, gw->text, gw->g.font, pcol->text, gw->pstyle->background, gJustifyLeft);
214  #undef gcw
215 }
216 
217 #if GWIN_FLAT_STYLING
218  void gwinRadioDraw_Button(GWidgetObject *gw, void *param) {
219  const GColorSet * pcol;
220  (void) param;
221 
222  if (gw->g.vmt != (gwinVMT *)&radioVMT) return;
223  pcol = getDrawColors(gw);
224 
225  #if GWIN_NEED_FLASHING
226  // Flash only the on state.
227  pcol = _gwinGetFlashedColor(gw, pcol, gFalse);
228  #endif
229 
230  gdispGFillStringBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, gJustifyCenter);
231  gdispGDrawLine(gw->g.display, gw->g.x+gw->g.width-1, gw->g.y, gw->g.x+gw->g.width-1, gw->g.y+gw->g.height-1, pcol->edge);
232  gdispGDrawLine(gw->g.display, gw->g.x, gw->g.y+gw->g.height-1, gw->g.x+gw->g.width-2, gw->g.y+gw->g.height-1, pcol->edge);
233 
234  // Render highlighted border if focused
235  _gwidgetDrawFocusRect(gw, 1, 1, gw->g.width-2, gw->g.height-2);
236  }
237  void gwinRadioDraw_Tab(GWidgetObject *gw, void *param) {
238  const GColorSet * pcol;
239  (void) param;
240 
241  if (gw->g.vmt != (gwinVMT *)&radioVMT) return;
242  pcol = getDrawColors(gw);
243 
244  #if GWIN_NEED_FLASHING
245  // Flash only the on state.
246  pcol = _gwinGetFlashedColor(gw, pcol, gFalse);
247  #endif
248 
249  if ((gw->g.flags & GRADIO_FLG_PRESSED)) {
250  gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge);
251  gdispGFillStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, gJustifyCenter);
252  } else {
253  gdispGFillStringBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, gJustifyCenter);
254  gdispGDrawLine(gw->g.display, gw->g.x+gw->g.width-1, gw->g.y, gw->g.x+gw->g.width-1, gw->g.y+gw->g.height-1, pcol->edge);
255  gdispGDrawLine(gw->g.display, gw->g.x, gw->g.y+gw->g.height-1, gw->g.x+gw->g.width-2, gw->g.y+gw->g.height-1, pcol->edge);
256  }
257 
258  // Render highlighted border if focused
259  _gwidgetDrawFocusRect(gw, 0, 0, gw->g.width-1, gw->g.height-1);
260  }
261 #else
262  void gwinRadioDraw_Button(GWidgetObject *gw, void *param) {
263  const GColorSet * pcol;
264  fixed alpha;
265  fixed dalpha;
266  gCoord i;
267  gColor tcol, bcol;
268  (void) param;
269 
270  if (gw->g.vmt != (gwinVMT *)&radioVMT) return;
271  pcol = getDrawColors(gw);
272 
273  /* Fill the box blended from variants of the fill color */
274  tcol = gdispBlendColor(GFX_WHITE, pcol->fill, GRADIO_TOP_FADE);
275  bcol = gdispBlendColor(GFX_BLACK, pcol->fill, GRADIO_BOTTOM_FADE);
276  dalpha = FIXED(255)/gw->g.height;
277  for(alpha = 0, i = 0; i < gw->g.height; i++, alpha += dalpha)
278  gdispGDrawLine(gw->g.display, gw->g.x, gw->g.y+i, gw->g.x+gw->g.width-2, gw->g.y+i, gdispBlendColor(bcol, tcol, NONFIXED(alpha)));
279 
280  gdispGDrawStringBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->text, gw->g.font, pcol->text, gJustifyCenter);
281  gdispGDrawLine(gw->g.display, gw->g.x+gw->g.width-1, gw->g.y, gw->g.x+gw->g.width-1, gw->g.y+gw->g.height-1, pcol->edge);
282  gdispGDrawLine(gw->g.display, gw->g.x, gw->g.y+gw->g.height-1, gw->g.x+gw->g.width-2, gw->g.y+gw->g.height-1, pcol->edge);
283 
284  // Render highlighted border if focused
285  _gwidgetDrawFocusRect(gw, 0, 0, gw->g.width-1, gw->g.height-1);
286  }
287  void gwinRadioDraw_Tab(GWidgetObject *gw, void *param) {
288  const GColorSet * pcol;
289  fixed alpha;
290  fixed dalpha;
291  gCoord i;
292  gColor tcol, bcol;
293  (void) param;
294 
295  if (gw->g.vmt != (gwinVMT *)&radioVMT) return;
296  pcol = getDrawColors(gw);
297 
298  if ((gw->g.flags & GRADIO_FLG_PRESSED)) {
299  tcol = gdispBlendColor(pcol->edge, gw->pstyle->background, GRADIO_OUTLINE_FADE);
300  gdispGFillStringBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->text, gw->g.font, pcol->text, gw->g.bgcolor, gJustifyCenter);
301  gdispGDrawLine(gw->g.display, gw->g.x, gw->g.y, gw->g.x+gw->g.width-(GRADIO_TAB_CNR+1), gw->g.y, tcol);
302  gdispGDrawLine(gw->g.display, gw->g.x+gw->g.width-(GRADIO_TAB_CNR+1), gw->g.y, gw->g.x+gw->g.width-1, gw->g.y+GRADIO_TAB_CNR, tcol);
303  gdispGDrawLine(gw->g.display, gw->g.x+gw->g.width-1, gw->g.y+GRADIO_TAB_CNR, gw->g.x+gw->g.width-1, gw->g.y+gw->g.height-1, tcol);
304  } else {
305  /* Fill the box blended from variants of the fill color */
306  tcol = gdispBlendColor(GFX_WHITE, pcol->fill, GRADIO_TOP_FADE);
307  bcol = gdispBlendColor(GFX_BLACK, pcol->fill, GRADIO_BOTTOM_FADE);
308  dalpha = FIXED(255)/gw->g.height;
309  for(alpha = 0, i = 0; i < gw->g.height; i++, alpha += dalpha)
310  gdispGDrawLine(gw->g.display, gw->g.x, gw->g.y+i, gw->g.x+gw->g.width-2, gw->g.y+i, gdispBlendColor(bcol, tcol, NONFIXED(alpha)));
311  gdispGDrawLine(gw->g.display, gw->g.x+gw->g.width-1, gw->g.y, gw->g.x+gw->g.width-1, gw->g.y+gw->g.height-1, pcol->edge);
312  gdispGDrawStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, gJustifyCenter);
313  }
314 
315  // Render highlighted border if focused
316  _gwidgetDrawFocusRect(gw, 0, 0, gw->g.width-1, gw->g.height-1);
317  }
318 #endif
319 
320 #endif /* GFX_USE_GWIN && GWIN_NEED_BUTTON */
COLOR_TYPE gColor
The color type definition.
Definition: gdisp_colors.h:437
gColor gdispBlendColor(gColor fg, gColor bg, gU8 alpha)
Blend 2 colors according to the alpha.
void gdispGFillCircle(GDisplay *g, gCoord x, gCoord y, gCoord radius, gColor color)
Draw a filled circle.
void gdispGDrawStringBox(GDisplay *g, gCoord x, gCoord y, gCoord cx, gCoord cy, const char *str, gFont font, gColor color, gJustify justify)
Draw a text string vertically centered within the specified box.
void gdispGDrawCircle(GDisplay *g, gCoord x, gCoord y, gCoord radius, gColor color)
Draw a circle.
void gdispGFillArea(GDisplay *g, gCoord x, gCoord y, gCoord cx, gCoord cy, gColor color)
Fill an area with a color.
void gdispGDrawLine(GDisplay *g, gCoord x0, gCoord y0, gCoord x1, gCoord y1, gColor color)
Draw a line.
void gdispGFillStringBox(GDisplay *g, gCoord x, gCoord y, gCoord cx, gCoord cy, const char *str, gFont font, gColor color, gColor bgColor, gJustify justify)
Draw a text string vertically centered within the specified box. The box background is filled with th...
gI16 gCoord
The type for a coordinate or length on the screen.
Definition: gdisp.h:39
void gdispGDrawBox(GDisplay *g, gCoord x, gCoord y, gCoord cx, gCoord cy, gColor color)
Draw a rectangular box.
@ gJustifyCenter
Definition: gdisp.h:62
@ gJustifyLeft
Definition: gdisp.h:61
GEvent * geventGetEventBuffer(GSourceListener *psl)
Get the event buffer from the GSourceListener.
Definition: gevent.c:187
void geventSendEvent(GSourceListener *psl)
Called by a source to indicate the listener's event buffer has been filled.
Definition: gevent.c:200
GSourceListener * geventGetSourceListener(GSourceHandle gsh, GSourceListener *lastlr)
Called by a source with a possible event to get a listener record.
Definition: gevent.c:163
gI32 fixed
The type for a fixed point type.
Definition: gmisc.h:60
#define FIXED(x)
Macros to convert to and from a fixed point.
Definition: gmisc.h:66
GHandle gwinGRadioCreate(GDisplay *g, GRadioObject *gb, const GWidgetInit *pInit, gU16 group)
Create a radio widget.
struct GRadioObject GRadioObject
The radio button widget structure.
GHandle gwinRadioGetActive(gU16 group)
Find the currently pressed radio button in the specified group.
#define GEVENT_GWIN_RADIO
The Event Type for a Radio Event.
Definition: gwin_radio.h:33
void gwinRadioPress(GHandle gh)
Press this radio button (and by definition unset any others in the group)
gBool gwinRadioIsPressed(GHandle gh)
Is the radio button currently pressed.
#define GRADIO_FLG_PRESSED
The internal radio button object flags.
Definition: gwin_radio.h:53
void gwinRadioDraw_Button(GWidgetObject *gw, void *param)
Renders the radiobutton in form of a regular rectangular button.
void gwinRadioDraw_Radio(GWidgetObject *gw, void *param)
The default rendering function for the radiobutton widget.
void gwinRadioDraw_Tab(GWidgetObject *gw, void *param)
Used to render tabbed menus.
void gwinSetVisible(GHandle gh, gBool visible)
Sets whether a window is visible or not.
GHandle gwinGetNextWindow(GHandle gh)
Get the next window in the z-order.
The GColorSet structure.
Definition: gwin_widget.h:37
gColor fill
Definition: gwin_widget.h:40
gColor text
Definition: gwin_widget.h:38
gColor edge
Definition: gwin_widget.h:39
The radio button widget structure.
Definition: gwin_radio.h:60
The structure to initialise a widget.
Definition: gwin_widget.h:97
GWindowInit g
Definition: gwin_widget.h:98
The GWIN Widget structure.
Definition: gwin_widget.h:118
GWindowObject g
Definition: gwin_widget.h:119
const GWidgetStyle * pstyle
Definition: gwin_widget.h:123
WidgetTag tag
Definition: gwin_widget.h:125
const char * text
Definition: gwin_widget.h:120
gColor background
Definition: gwin_widget.h:53
GColorSet disabled
Definition: gwin_widget.h:56
GColorSet enabled
Definition: gwin_widget.h:55
GColorSet pressed
Definition: gwin_widget.h:57
gBool show
Definition: gwin.h:80
A window object structure.
Definition: gwin.h:40
gColor bgcolor
Definition: gwin.h:52
GDisplay * display
Definition: gwin.h:46
gCoord x
Definition: gwin.h:47
gCoord width
Definition: gwin.h:49
const struct gwinVMT * vmt
Definition: gwin.h:45
gU32 flags
Definition: gwin.h:53
gCoord y
Definition: gwin.h:48
gCoord height
Definition: gwin.h:50
The Virtual Method Table for a widget.
Definition: gwin_class.h:85
The Virtual Method Table for a GWIN window.
Definition: gwin_class.h:55