version 2.8
gwin_frame.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.org/license.html
6  */
7 
8 /**
9  * @file src/gwin/gwin_frame.c
10  * @brief GWIN sub-system frame code.
11  */
12 
13 #include "../../gfx.h"
14 
15 #if GFX_USE_GWIN && GWIN_NEED_FRAME
16 
17 #include "gwin_class.h"
18 
19 /* Some position values */
20 #define FRM_BUTTON_X 18 // Button Width
21 #define FRM_BUTTON_Y 18 // Button Height
22 #define FRM_BUTTON_I 3 // Button inner margin
23 #define FRM_BUTTON_T 2 // Gap from top of window to button
24 #define FRM_BUTTON_B 2 // Gap from button to the bottom of the frame title area
25 #define FRM_BORDER_L 2 // Left Border
26 #define FRM_BORDER_R 2 // Right Border
27 #define FRM_BORDER_T (FRM_BUTTON_Y+FRM_BUTTON_T+FRM_BUTTON_B) // Top Border (Title area)
28 #define FRM_BORDER_B 2 // Bottom Border
29 
30 /* Internal state flags */
31 #define GWIN_FRAME_USER_FLAGS (GWIN_FRAME_CLOSE_BTN|GWIN_FRAME_MINMAX_BTN|GWIN_FRAME_KEEPONCLOSE)
32 
33 #if GWIN_FRAME_CLOSE_BTN < GWIN_FIRST_CONTROL_FLAG
34  #error "GWIN Frame: - Flag definitions don't match"
35 #endif
36 #if GWIN_FRAME_REDRAW_FRAME > GWIN_LAST_CONTROL_FLAG
37  #error "GWIN Frame: - Flag definitions don't match"
38 #endif
39 
40 static coord_t FrameBorderSizeL(GHandle gh) { (void)gh; return FRM_BORDER_L; }
41 static coord_t FrameBorderSizeR(GHandle gh) { (void)gh; return FRM_BORDER_R; }
42 static coord_t FrameBorderSizeT(GHandle gh) { (void)gh; return FRM_BORDER_T; }
43 static coord_t FrameBorderSizeB(GHandle gh) { (void)gh; return FRM_BORDER_B; }
44 
45 static void forceFrameRedraw(GWidgetObject *gw) {
46  // Force a redraw of just the frame.
47  // This is a big naughty but who really cares.
48  gw->g.flags |= GWIN_FRAME_REDRAW_FRAME;
49  gw->fnDraw(gw, gw->fnParam);
50  gw->g.flags &= ~GWIN_FRAME_REDRAW_FRAME;
51 }
52 
53 #if GINPUT_NEED_MOUSE
54  static void FrameMouseDown(GWidgetObject *gw, coord_t x, coord_t y) {
55  coord_t pos;
56 
57  // We must be clicking on the frame button area to be of interest
58  if (y < FRM_BUTTON_T || y >= FRM_BUTTON_T+FRM_BUTTON_Y)
59  return;
60 
61  pos = gw->g.width - (FRM_BORDER_R+FRM_BUTTON_X);
62  if ((gw->g.flags & GWIN_FRAME_CLOSE_BTN)) {
63  if (x >= pos && x < pos+FRM_BUTTON_X) {
64  // Close is pressed - force redraw the frame only
66  forceFrameRedraw(gw);
67  return;
68  }
69  pos -= FRM_BUTTON_X;
70  }
71  if ((gw->g.flags & GWIN_FRAME_MINMAX_BTN)) {
72  if (x >= pos && x < pos+FRM_BUTTON_X) {
73  // Close is pressed - force redraw the frame only
74  gw->g.flags |= GWIN_FRAME_MAX_PRESSED;
75  forceFrameRedraw(gw);
76  return;
77  }
78  pos -= FRM_BUTTON_X;
79  if (x >= pos && x < pos+FRM_BUTTON_X) {
80  // Close is pressed - force redraw the frame only
81  gw->g.flags |= GWIN_FRAME_MIN_PRESSED;
82  forceFrameRedraw(gw);
83  return;
84  }
85  pos -= FRM_BUTTON_X;
86  }
87  }
88 
89  static void FrameMouseUp(GWidgetObject *gw, coord_t x, coord_t y) {
90  #if GWIN_BUTTON_LAZY_RELEASE
91  if ((gw->g.flags & GWIN_FRAME_CLOSE_PRESSED)) {
92  // Close is released - destroy the window
93  gw->g.flags &= ~(GWIN_FRAME_CLOSE_PRESSED|GWIN_FRAME_MAX_PRESSED|GWIN_FRAME_MIN_PRESSED);
94  forceFrameRedraw(gw);
95  _gwinSendEvent(&gw->g, GEVENT_GWIN_CLOSE);
96  if (!(gw->g.flags & GWIN_FRAME_KEEPONCLOSE))
97  _gwinDestroy(&gw->g, REDRAW_INSESSION);
98  return;
99  }
100  if ((gw->g.flags & GWIN_FRAME_MAX_PRESSED)) {
101  // Max is released - maximize the window
102  gw->g.flags &= ~(GWIN_FRAME_CLOSE_PRESSED|GWIN_FRAME_MAX_PRESSED|GWIN_FRAME_MIN_PRESSED);
103  forceFrameRedraw(gw);
104  gwinSetMinMax(&gw->g, GWIN_MAXIMIZE);
105  return;
106  }
107  if ((gw->g.flags & GWIN_FRAME_MIN_PRESSED)) {
108  // Min is released - minimize the window
109  gw->g.flags &= ~(GWIN_FRAME_CLOSE_PRESSED|GWIN_FRAME_MAX_PRESSED|GWIN_FRAME_MIN_PRESSED);
110  forceFrameRedraw(gw);
111  gwinSetMinMax(&gw->g, GWIN_MINIMIZE);
112  return;
113  }
114  #else
115  // If nothing is pressed we have nothing to do.
116  if (!(gw->g.flags & (GWIN_FRAME_CLOSE_PRESSED|GWIN_FRAME_MAX_PRESSED|GWIN_FRAME_MIN_PRESSED)))
117  return;
118 
119  // We must be releasing over the button
120  if (y >= FRM_BUTTON_T && y < FRM_BUTTON_T+FRM_BUTTON_Y) {
121  coord_t pos;
122 
123  pos = gw->g.width - (FRM_BORDER_R+FRM_BUTTON_X);
124  if ((gw->g.flags & GWIN_FRAME_CLOSE_BTN)) {
125  if ((gw->g.flags & GWIN_FRAME_CLOSE_PRESSED) && x >= pos && x <= pos+FRM_BUTTON_X) {
126  // Close is released - destroy the window. This is tricky as we already have the drawing lock.
127  gw->g.flags &= ~(GWIN_FRAME_CLOSE_PRESSED|GWIN_FRAME_MAX_PRESSED|GWIN_FRAME_MIN_PRESSED);
128  forceFrameRedraw(gw);
129  _gwinSendEvent(&gw->g, GEVENT_GWIN_CLOSE);
130  if (!(gw->g.flags & GWIN_FRAME_KEEPONCLOSE))
131  _gwinDestroy(&gw->g, REDRAW_INSESSION);
132  return;
133  }
134  pos -= FRM_BUTTON_X;
135  }
136  if ((gw->g.flags & GWIN_FRAME_MINMAX_BTN)) {
137  if ((gw->g.flags & GWIN_FRAME_MAX_PRESSED) && x >= pos && x <= pos+FRM_BUTTON_X) {
138  // Max is released - maximize the window
139  gw->g.flags &= ~(GWIN_FRAME_CLOSE_PRESSED|GWIN_FRAME_MAX_PRESSED|GWIN_FRAME_MIN_PRESSED);
140  forceFrameRedraw(gw);
141  gwinSetMinMax(&gw->g, GWIN_MAXIMIZE);
142  return;
143  }
144  pos -= FRM_BUTTON_X;
145  if ((gw->g.flags & GWIN_FRAME_MIN_PRESSED) && x >= pos && x <= pos+FRM_BUTTON_X) {
146  // Min is released - minimize the window
147  gw->g.flags &= ~(GWIN_FRAME_CLOSE_PRESSED|GWIN_FRAME_MAX_PRESSED|GWIN_FRAME_MIN_PRESSED);
148  forceFrameRedraw(gw);
149  gwinSetMinMax(&gw->g, GWIN_MINIMIZE);
150  return;
151  }
152  pos -= FRM_BUTTON_X;
153  }
154  }
155 
156  // Clear any flags and redraw the frame
157  gw->g.flags &= ~(GWIN_FRAME_CLOSE_PRESSED|GWIN_FRAME_MAX_PRESSED|GWIN_FRAME_MIN_PRESSED);
158  forceFrameRedraw(gw);
159  #endif
160  }
161 #endif
162 
163 static const gcontainerVMT frameVMT = {
164  {
165  {
166  "Frame", // The classname
167  sizeof(GFrameObject), // The object size
168  _gcontainerDestroy, // The destroy routine
169  _gcontainerRedraw, // The redraw routine
170  0, // The after-clear routine
171  },
172  gwinFrameDraw_Std, // The default drawing routine
174  {
175  FrameMouseDown, // Process mouse down event
176  FrameMouseUp, // Process mouse up events
177  0, // Process mouse move events
178  },
179  #endif
180  #if GINPUT_NEED_KEYBOARD || GWIN_NEED_KEYBOARD
181  {
182  0 // Process keyboard events
183  },
184  #endif
185  #if GINPUT_NEED_TOGGLE
186  {
187  0, // 1 toggle role
188  0, // Assign Toggles
189  0, // Get Toggles
190  0, // Process toggle off events
191  0, // Process toggle on events
192  },
193  #endif
194  #if GINPUT_NEED_DIAL
195  {
196  0, // 1 dial roles
197  0, // Assign Dials
198  0, // Get Dials
199  0, // Process dial move events
200  },
201  #endif
202  },
203  FrameBorderSizeL, // The size of the left border (mandatory)
204  FrameBorderSizeT, // The size of the top border (mandatory)
205  FrameBorderSizeR, // The size of the right border (mandatory)
206  FrameBorderSizeB, // The size of the bottom border (mandatory)
207  0, // A child has been added (optional)
208  0, // A child has been deleted (optional)
209 };
210 
211 GHandle gwinGFrameCreate(GDisplay *g, GFrameObject *fo, GWidgetInit *pInit, uint32_t flags) {
212  if (!(fo = (GFrameObject *)_gcontainerCreate(g, (GContainerObject *)fo, pInit, &frameVMT)))
213  return 0;
214 
215  // Make sure we only have "safe" flags.
216  flags &= GWIN_FRAME_USER_FLAGS;
217 
218  /* Apply flags. We apply these here so the controls above are outside the child area */
219  fo->g.flags |= flags;
220 
221  gwinSetVisible(&fo->g, pInit->g.show);
222 
223  return &fo->g;
224 }
225 
226 ///////////////////////////////////////////////////////////////////////////////////////////////////
227 // Default render routines //
228 ///////////////////////////////////////////////////////////////////////////////////////////////////
229 
230 void gwinFrameDraw_Transparent(GWidgetObject *gw, void *param) {
231  const GColorSet *pcol;
232  coord_t pos;
233  color_t contrast;
234  color_t btn;
235  (void)param;
236 
237  if (gw->g.vmt != (gwinVMT *)&frameVMT)
238  return;
239 
240  pcol = (gw->g.flags & GWIN_FLG_SYSENABLED) ? &gw->pstyle->enabled : &gw->pstyle->disabled;
241  contrast = gdispContrastColor(pcol->edge);
242  btn = gdispBlendColor(pcol->edge, contrast, 128);
243 
244  // Render the frame
245  gdispGFillStringBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, FRM_BORDER_T, gw->text, gw->g.font, contrast, pcol->edge, justifyCenter);
246  gdispGFillArea(gw->g.display, gw->g.x, gw->g.y+FRM_BORDER_T, FRM_BORDER_L, gw->g.height-(FRM_BORDER_T+FRM_BORDER_B), pcol->edge);
247  gdispGFillArea(gw->g.display, gw->g.x+gw->g.width-FRM_BORDER_R, gw->g.y+FRM_BORDER_T, FRM_BORDER_R, gw->g.height-(FRM_BORDER_T+FRM_BORDER_B), pcol->edge);
248  gdispGFillArea(gw->g.display, gw->g.x, gw->g.y+gw->g.height-FRM_BORDER_B, gw->g.width, FRM_BORDER_B, pcol->edge);
249 
250  // Add the buttons
251  pos = gw->g.x+gw->g.width - (FRM_BORDER_R+FRM_BUTTON_X);
252 
253  if ((gw->g.flags & GWIN_FRAME_CLOSE_BTN)) {
254  if ((gw->g.flags & GWIN_FRAME_CLOSE_PRESSED))
255  gdispFillArea(pos, gw->g.y+FRM_BUTTON_T, FRM_BUTTON_X, FRM_BUTTON_Y, btn);
256  gdispDrawLine(pos+FRM_BUTTON_I, gw->g.y+(FRM_BUTTON_T+FRM_BUTTON_I), pos+(FRM_BUTTON_X-FRM_BUTTON_I-1), gw->g.y+(FRM_BUTTON_T+FRM_BUTTON_Y-FRM_BUTTON_I-1), contrast);
257  gdispDrawLine(pos+(FRM_BUTTON_X-FRM_BUTTON_I-1), gw->g.y+(FRM_BUTTON_T+FRM_BUTTON_I), pos+FRM_BUTTON_I, gw->g.y+(FRM_BUTTON_T+FRM_BUTTON_Y-FRM_BUTTON_I-1), contrast);
258  pos -= FRM_BUTTON_X;
259  }
260 
261  if ((gw->g.flags & GWIN_FRAME_MINMAX_BTN)) {
262  if ((gw->g.flags & GWIN_FRAME_MAX_PRESSED))
263  gdispFillArea(pos, gw->g.y+FRM_BUTTON_T, FRM_BUTTON_X, FRM_BUTTON_Y, btn);
264  // the symbol
265  gdispDrawBox(pos+FRM_BUTTON_I, gw->g.y+(FRM_BUTTON_T+FRM_BUTTON_I), FRM_BUTTON_X-2*FRM_BUTTON_I, FRM_BUTTON_Y-2*FRM_BUTTON_I, contrast);
266  gdispDrawLine(pos+(FRM_BUTTON_I+1), gw->g.y+(FRM_BUTTON_T+FRM_BUTTON_I+1), pos+(FRM_BUTTON_X-FRM_BUTTON_I-2), gw->g.y+(FRM_BUTTON_T+FRM_BUTTON_I+1), contrast);
267  gdispDrawLine(pos+(FRM_BUTTON_I+1), gw->g.y+(FRM_BUTTON_T+FRM_BUTTON_I+2), pos+(FRM_BUTTON_X-FRM_BUTTON_I-2), gw->g.y+(FRM_BUTTON_T+FRM_BUTTON_I+2), contrast);
268  pos -= FRM_BUTTON_X;
269  if ((gw->g.flags & GWIN_FRAME_MIN_PRESSED))
270  gdispFillArea(pos, gw->g.y+FRM_BUTTON_T, FRM_BUTTON_X, FRM_BUTTON_Y, btn);
271  gdispDrawLine(pos+FRM_BUTTON_I, gw->g.y+(FRM_BUTTON_T+FRM_BUTTON_Y-FRM_BUTTON_I-1), pos+(FRM_BUTTON_X-FRM_BUTTON_I-1), gw->g.y+(FRM_BUTTON_T+FRM_BUTTON_Y-FRM_BUTTON_I-1), contrast);
272  pos -= FRM_BUTTON_X;
273  }
274 
275  // Don't touch the client area
276 }
277 
278 void gwinFrameDraw_Std(GWidgetObject *gw, void *param) {
279  (void)param;
280 
281  if (gw->g.vmt != (gwinVMT *)&frameVMT)
282  return;
283 
284  // Draw the frame
285  gwinFrameDraw_Transparent(gw, param);
286 
287  // Drop out if that is all we want to draw
288  if ((gw->g.flags & GWIN_FRAME_REDRAW_FRAME))
289  return;
290 
291  // Draw the client area
292  gdispGFillArea(gw->g.display, gw->g.x + FRM_BORDER_L, gw->g.y + FRM_BORDER_T, gw->g.width - (FRM_BORDER_L+FRM_BORDER_R), gw->g.height - (FRM_BORDER_T+FRM_BORDER_B), gw->pstyle->background);
293 }
294 
295 #if GDISP_NEED_IMAGE
296  void gwinFrameDraw_Image(GWidgetObject *gw, void *param) {
297  #define gi ((gdispImage *)param)
298  coord_t x, y, iw, ih, mx, my;
299 
300  if (gw->g.vmt != (gwinVMT *)&frameVMT)
301  return;
302 
303  // Draw the frame
304  gwinFrameDraw_Transparent(gw, param);
305 
306  // Drop out if that is all we want to draw
307  if ((gw->g.flags & GWIN_FRAME_REDRAW_FRAME))
308  return;
309 
310  // Draw the client area by tiling the image
311  mx = gw->g.x+gw->g.width - FRM_BORDER_R;
312  my = gw->g.y+gw->g.height - FRM_BORDER_B;
313  for(y = gw->g.y+FRM_BORDER_T, ih = gi->height; y < my; y += ih) {
314  if (ih > my - y)
315  ih = my - y;
316  for(x = gw->g.x+FRM_BORDER_L, iw = gi->width; x < mx; x += iw) {
317  if (iw > mx - x)
318  iw = mx - x;
319  gdispGImageDraw(gw->g.display, gi, x, y, iw, ih, 0, 0);
320  }
321  }
322 
323  #undef gi
324  }
325 #endif
326 
327 #endif /* (GFX_USE_GWIN && GWIN_NEED_FRAME) || defined(__DOXYGEN__) */
void gdispGFillStringBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, const char *str, font_t font, color_t color, color_t bgColor, justify_t justify)
Draw a text string vertically centered within the specified box. The box background is filled with th...
color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha)
Blend 2 colors according to the alpha.
const struct gwinVMT * vmt
Definition: gwin.h:45
void gwinSetMinMax(GHandle gh, GWindowMinMax minmax)
Minimize, Maximize or Restore a window.
uint32_t flags
Definition: gwin.h:53
int16_t coord_t
The type for a coordinate or length on the screen.
Definition: gdisp.h:39
The structure to initialise a widget.
Definition: gwin_widget.h:97
The Virtual Method Table for a container.
Definition: gwin_class.h:132
color_t background
Definition: gwin_widget.h:53
void gwinFrameDraw_Image(GWidgetObject *gw, void *param)
Renders the frame widget and uses the specified image for the client area.
coord_t y
Definition: gwin.h:48
coord_t x
Definition: gwin.h:47
GWindowInit g
Definition: gwin_widget.h:98
#define GINPUT_NEED_MOUSE
Should mouse/touch functions be included.
The GColorSet structure.
Definition: gwin_widget.h:37
GWindowObject g
Definition: gwin_widget.h:119
GColorSet disabled
Definition: gwin_widget.h:56
void gdispGFillArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color)
Fill an area with a color.
GColorSet enabled
Definition: gwin_widget.h:55
const char * text
Definition: gwin_widget.h:120
#define GWIN_FRAME_MINMAX_BTN
Definition: gwin_frame.h:36
void gwinSetVisible(GHandle gh, bool_t visible)
Sets whether a window is visible or not.
const GWidgetStyle * pstyle
Definition: gwin_widget.h:123
CustomWidgetDrawFunction fnDraw
Definition: gwin_widget.h:121
The GWIN Widget structure.
Definition: gwin_widget.h:118
#define GWIN_FRAME_KEEPONCLOSE
Definition: gwin_frame.h:37
bool_t show
Definition: gwin.h:80
GDisplay * display
Definition: gwin.h:46
coord_t height
Definition: gwin.h:50
coord_t width
Definition: gwin.h:49
gdispImageError gdispGImageDraw(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy)
Draw the image.
The Virtual Method Table for a GWIN window.
Definition: gwin_class.h:55
A window object structure.
Definition: gwin.h:40
color_t gdispContrastColor(color_t color)
Find a contrasting color.
COLOR_TYPE color_t
The color type definition.
Definition: gdisp_colors.h:412
void * fnParam
Definition: gwin_widget.h:122
GHandle gwinGFrameCreate(GDisplay *g, GFrameObject *fo, GWidgetInit *pInit, uint32_t flags)
Create a frame widget.
void gwinFrameDraw_Std(GWidgetObject *gw, void *param)
The default rendering function for the frame widget.
void gwinFrameDraw_Transparent(GWidgetObject *gw, void *param)
Renders the frame widget with a transparent client area.
#define GWIN_FRAME_CLOSE_PRESSED
The internal frame flags.
Definition: gwin_frame.h:45
color_t edge
Definition: gwin_widget.h:39
#define GWIN_FRAME_CLOSE_BTN
Definition: gwin_frame.h:35