1 /* This is a small demo of the high-performance GUIX graphics framework. */
2
3 #include "demo_guix_washing_machine.h"
4
5 #define MEMORY_BUFFER_SIZE (MAIN_DISPLAY_X_RESOLUTION * MAIN_DISPLAY_Y_RESOLUTION * 4)
6 #define ID_TIMER_WAVE_ANIMATION 1
7 #define ID_TIMER_PROGRESS_BAR_ANIMATION 2
8 #define ID_TIMER_TIME 3
9
10 #define PROGRESS_DOT_SPACE 9
11 #define PROGRESS_ALPHA_SHIFT 10
12
13 #define ROTATION_DISTANCE 25
14 #define WASH_CYCLE_TEMPERATURE_RING_WIDTH 52
15
16 /* Define variables. */
17 TX_BYTE_POOL memory_pool;
18 GX_CHAR memory_buffer[MEMORY_BUFFER_SIZE];
19 GX_WINDOW_ROOT *root;
20
21 INT wave_rotation_angle = 0; /* Used for wave animation in water cycle and temperature window. */
22 INT wash_cycle_remain_seconds = 3600; /* Wash cyle remain time. */
23 INT progress_alpha_start = 0; /* Used for progress bar animation. */
24
25 /* Define prototypes. */
26 VOID guix_setup(void);
27 extern UINT win32_graphics_driver_setup_24xrgb(GX_DISPLAY* display);
28
29 /******************************************************************************************/
30 /* Application entry. */
31 /******************************************************************************************/
main(int argc,char ** argv)32 int main(int argc, char ** argv)
33 {
34 tx_kernel_enter();
35 return(0);
36 }
37
38 /******************************************************************************************/
39 /* Define memory allocator function. */
40 /******************************************************************************************/
memory_allocate(ULONG size)41 VOID *memory_allocate(ULONG size)
42 {
43 VOID *memptr;
44
45 if (tx_byte_allocate(&memory_pool, &memptr, size, TX_NO_WAIT) == TX_SUCCESS)
46 {
47 return memptr;
48 }
49 return NULL;
50 }
51
52 /******************************************************************************************/
53 /* Define memory de-allocator function. */
54 /******************************************************************************************/
memory_free(VOID * mem)55 void memory_free(VOID *mem)
56 {
57 tx_byte_release(mem);
58 }
59
60 /******************************************************************************************/
61 /* Define tx_application_define function. */
62 /******************************************************************************************/
tx_application_define(void * first_unused_memory)63 VOID tx_application_define(void *first_unused_memory)
64 {
65
66 /* Create byte pool. */
67 tx_byte_pool_create(&memory_pool, "memory_buffer", memory_buffer, MEMORY_BUFFER_SIZE);
68
69 guix_setup();
70 }
71
72 /******************************************************************************************/
73 /* Define custom button selection function to remove GX_STYLE_BUTTON_PUSHED style before */
74 /* call the default button select route, so that button selected event can be send no */
75 /* mater the selected button is pushed already or not. */
76 /******************************************************************************************/
repeat_selection_style_button_select(GX_WIDGET * button)77 VOID repeat_selection_style_button_select(GX_WIDGET *button)
78 {
79 button->gx_widget_style &= ~GX_STYLE_BUTTON_PUSHED;
80
81 gx_button_select((GX_BUTTON *)button);
82 }
83
84 /******************************************************************************************/
85 /* Initiate and run GUIX. */
86 /******************************************************************************************/
guix_setup()87 VOID guix_setup()
88 {
89
90 /* Initialize GUIX. */
91 gx_system_initialize();
92
93 /* Install memory allocator and de-allocator. */
94 gx_system_memory_allocator_set(memory_allocate, memory_free);
95
96 /* Configure display. */
97 gx_studio_display_configure(MAIN_DISPLAY, win32_graphics_driver_setup_24xrgb,
98 LANGUAGE_ENGLISH, MAIN_DISPLAY_THEME_1, &root);
99
100 /* Create the main screen and attach it to root window. */
101 gx_studio_named_widget_create("main_screen", (GX_WIDGET *)root, GX_NULL);
102
103 /* Change button select handler of wash cycle button. */
104 main_screen.main_screen_btn_wash_cycle.gx_button_select_handler = repeat_selection_style_button_select;
105
106 /* Create wash cycle window. */
107 gx_studio_named_widget_create("wash_cycle_window", (GX_WIDGET *)&main_screen, GX_NULL);
108
109 /* Initialize wash cycle window. */
110 wash_cycle_window_init(wash_cycle_remain_seconds);
111
112 /* Create mode select window. */
113 gx_studio_named_widget_create("mode_select_window", GX_NULL, GX_NULL);
114
115 /* Initialize mode select window. */
116 mode_select_window_init();
117
118 /* Create temperature window. */
119 gx_studio_named_widget_create("temperature_window", GX_NULL, GX_NULL);
120
121 /* Create water level window. */
122 gx_studio_named_widget_create("water_level_window", GX_NULL, GX_NULL);
123
124 /* Initialize water level window. */
125 water_level_window_init();
126
127 /* Show the root window to make it and wash cycle screen visible. */
128 gx_widget_show(root);
129
130 /* Let GUIX run. */
131 gx_system_start();
132 }
133
134 /******************************************************************************************/
135 /* Mark wave animation parent dirty. */
136 /******************************************************************************************/
mark_wave_animation_parent_dirty()137 VOID mark_wave_animation_parent_dirty()
138 {
139 GX_RECTANGLE dirty_area;
140 GX_WIDGET *parent;
141
142 if (wash_cycle_window.gx_widget_status & GX_STATUS_VISIBLE)
143 {
144 parent = (GX_WIDGET *)&wash_cycle_window;
145 }
146 else if (temperature_window.gx_widget_status & GX_STATUS_VISIBLE)
147 {
148 parent = (GX_WIDGET *)&temperature_window;
149 }
150 else
151 {
152 return;
153 }
154
155 /* Calculate wave area. */
156 dirty_area = parent->gx_widget_size;
157 dirty_area.gx_rectangle_left = (GX_VALUE)(dirty_area.gx_rectangle_left + WASH_CYCLE_TEMPERATURE_RING_WIDTH);
158 dirty_area.gx_rectangle_top = (GX_VALUE)(dirty_area.gx_rectangle_top + WASH_CYCLE_TEMPERATURE_RING_WIDTH);
159 dirty_area.gx_rectangle_right = (GX_VALUE)(dirty_area.gx_rectangle_right - WASH_CYCLE_TEMPERATURE_RING_WIDTH);
160 dirty_area.gx_rectangle_bottom = (GX_VALUE)(dirty_area.gx_rectangle_bottom - WASH_CYCLE_TEMPERATURE_RING_WIDTH);
161
162 /* Mark wave area as dirty. */
163 gx_system_dirty_partial_add(parent, &dirty_area);
164 }
165
166 /******************************************************************************************/
167 /* Update wash cycle remain time that displayed in various windows. */
168 /******************************************************************************************/
wash_cycle_remain_time_update(INT remain_reconds)169 VOID wash_cycle_remain_time_update(INT remain_reconds)
170 {
171 /* Update remain time in wash cycle window. */
172 wash_cycle_window_remain_time_update(remain_reconds);
173
174 /* Update remain time in mode select window. */
175 mode_select_window_remain_time_update(remain_reconds);
176 }
177
178 /******************************************************************************************/
179 /* Set wash cycle remain time. */
180 /******************************************************************************************/
remain_time_set(INT seconds)181 VOID remain_time_set(INT seconds)
182 {
183 /* Set current wash cycle remain time. */
184 wash_cycle_remain_seconds = seconds;
185
186 /* Update wash cycle remain time that displayed in various windows. */
187 wash_cycle_remain_time_update(wash_cycle_remain_seconds);
188 }
189
190 /******************************************************************************************/
191 /* Override the default event processing of "main_screen" to handle signals from my child */
192 /* widgets. */
193 /******************************************************************************************/
main_screen_event_process(GX_WINDOW * window,GX_EVENT * event_ptr)194 UINT main_screen_event_process(GX_WINDOW* window, GX_EVENT* event_ptr)
195 {
196 switch (event_ptr->gx_event_type)
197 {
198 case GX_SIGNAL(ID_BTN_WASH_CYCLE, GX_EVENT_RADIO_SELECT):
199
200 if (wash_cycle_window.gx_widget_status & GX_STATUS_VISIBLE)
201 {
202 /* Dettach wash cycle window. */
203 gx_widget_detach(&wash_cycle_window);
204
205 /* Attach mode select window. */
206 gx_widget_attach((GX_WIDGET*)window, &mode_select_window);
207 }
208 else
209 {
210 if (mode_select_window.gx_widget_status & GX_STATUS_VISIBLE)
211 {
212 /* Dettach mode select window. */
213 gx_widget_detach(&mode_select_window);
214 }
215
216 /* Attach wash cycle window. */
217 gx_widget_attach((GX_WIDGET*)window, &wash_cycle_window);
218 }
219 break;
220
221 case GX_SIGNAL(ID_BTN_WASH_CYCLE, GX_EVENT_RADIO_DESELECT):
222
223 if (mode_select_window.gx_widget_status & GX_STATUS_VISIBLE)
224 {
225 /* Dettach wash cycle window. */
226 gx_widget_detach(&mode_select_window);
227 }
228 else
229 {
230 /* Dettach mode select window. */
231 gx_widget_detach(&wash_cycle_window);
232 }
233 break;
234
235 case GX_SIGNAL(ID_BTN_TEMPERATURE, GX_EVENT_RADIO_SELECT):
236
237 /* Attach temperature window. */
238 gx_widget_attach((GX_WIDGET*)window, &temperature_window);
239 break;
240
241 case GX_SIGNAL(ID_BTN_TEMPERATURE, GX_EVENT_RADIO_DESELECT):
242
243 /* Dettach temperature window. */
244 gx_widget_detach(&temperature_window);
245 break;
246
247 case GX_SIGNAL(ID_BTN_WATER_LEVEL, GX_EVENT_RADIO_SELECT):
248
249 /* Attach water level window. */
250 gx_widget_attach((GX_WIDGET*)window, &water_level_window);
251 break;
252
253 case GX_SIGNAL(ID_BTN_WATER_LEVEL, GX_EVENT_RADIO_DESELECT):
254
255 /* Dettach water level page. */
256 gx_widget_detach(&water_level_window);
257 break;
258
259 case GX_SIGNAL(ID_BTN_PLAY, GX_EVENT_TOGGLE_ON):
260 gx_system_timer_start(window, ID_TIMER_TIME, GX_TICKS_SECOND, GX_TICKS_SECOND);
261 gx_system_timer_start(window, ID_TIMER_PROGRESS_BAR_ANIMATION, 40 / GX_SYSTEM_TIMER_MS, 40 / GX_SYSTEM_TIMER_MS);
262 gx_system_timer_start(window, ID_TIMER_WAVE_ANIMATION, 1, 1);
263 break;
264
265 case GX_SIGNAL(ID_BTN_PLAY, GX_EVENT_TOGGLE_OFF):
266 gx_system_timer_stop(window, 0);
267
268 mark_wave_animation_parent_dirty();
269 gx_system_dirty_mark(&main_screen.main_screen_wash_cycle_progress_bar);
270 break;
271
272 case GX_EVENT_TIMER:
273 if (event_ptr->gx_event_payload.gx_event_timer_id == ID_TIMER_WAVE_ANIMATION)
274 {
275 wave_rotation_angle = (358 + wave_rotation_angle) % 360;
276
277 mark_wave_animation_parent_dirty();
278 }
279 if(event_ptr->gx_event_payload.gx_event_timer_id == ID_TIMER_PROGRESS_BAR_ANIMATION)
280 {
281 gx_system_dirty_mark(&main_screen.main_screen_wash_cycle_progress_bar);
282 }
283 if(event_ptr->gx_event_payload.gx_event_timer_id == ID_TIMER_TIME)
284 {
285 wash_cycle_remain_seconds--;
286
287 if (wash_cycle_remain_seconds >= 0)
288 {
289 wash_cycle_remain_time_update(wash_cycle_remain_seconds);
290 }
291 }
292 break;
293
294 default:
295 return gx_window_event_process(window, event_ptr);
296 }
297
298 return 0;
299 }
300
301 /******************************************************************************************/
302 /* Define custom prompt draw function for child prompts of a button. */
303 /******************************************************************************************/
btn_text_draw(GX_PROMPT * prompt)304 VOID btn_text_draw(GX_PROMPT *prompt)
305 {
306 if (prompt->gx_widget_parent->gx_widget_style & GX_STYLE_BUTTON_PUSHED)
307 {
308 prompt->gx_widget_style |= GX_STYLE_DRAW_SELECTED;
309 }
310 else
311 {
312 prompt->gx_widget_style &= (~GX_STYLE_DRAW_SELECTED);
313 }
314
315 gx_prompt_draw(prompt);
316 }
317
318 /******************************************************************************************/
319 /* Define custom numeric prompt draw function for child numeric prompts of a button. */
320 /******************************************************************************************/
btn_numeric_text_draw(GX_NUMERIC_PROMPT * prompt)321 VOID btn_numeric_text_draw(GX_NUMERIC_PROMPT* prompt)
322 {
323 if (prompt->gx_widget_parent->gx_widget_style & GX_STYLE_BUTTON_PUSHED)
324 {
325 prompt->gx_widget_style |= GX_STYLE_DRAW_SELECTED;
326 }
327 else
328 {
329 prompt->gx_widget_style &= (~GX_STYLE_DRAW_SELECTED);
330 }
331
332 gx_prompt_draw((GX_PROMPT *)prompt);
333 }
334
335 /******************************************************************************************/
336 /* Define format function for numeric prompt to show time. */
337 /******************************************************************************************/
time_format(GX_NUMERIC_PROMPT * prompt,INT value)338 VOID time_format(GX_NUMERIC_PROMPT* prompt, INT value)
339 {
340 if (value < 10)
341 {
342 prompt->gx_numeric_prompt_buffer[0] = '0';
343 prompt->gx_numeric_prompt_buffer[1] = '0' + value;
344 }
345 else if (value < 100)
346 {
347 prompt->gx_numeric_prompt_buffer[0] = '0' + (value / 10);
348 prompt->gx_numeric_prompt_buffer[1] = '0' + (value % 10);
349 }
350 }
351
352 /******************************************************************************************/
353 /* Draw animation wave in the center of specified window. */
354 /******************************************************************************************/
animation_wave_draw(GX_WINDOW * window)355 VOID animation_wave_draw(GX_WINDOW* window)
356 {
357 GX_RECTANGLE *size = &window->gx_widget_size;
358 INT scaled_angle;
359 INT xdist;
360 INT ydist;
361 INT xcenter;
362 INT ycenter;
363 INT width;
364 INT height;
365 GX_PIXELMAP *map;
366
367 gx_context_pixelmap_get(GX_PIXELMAP_ID_WAVE, &map);
368
369 width = size->gx_rectangle_right - size->gx_rectangle_left + 1;
370 height = size->gx_rectangle_bottom - size->gx_rectangle_top + 1;
371 xcenter = size->gx_rectangle_left + (width >> 1);
372 ycenter = size->gx_rectangle_top + (height >> 1);
373
374 gx_context_brush_define(GX_COLOR_ID_WHITE, GX_COLOR_ID_WHITE, GX_BRUSH_ALIAS | GX_BRUSH_SOLID_FILL);
375 gx_context_brush_width_set(1);
376
377 scaled_angle = GX_FIXED_VAL_MAKE(wave_rotation_angle);
378 xdist = GX_FIXED_VAL_TO_INT(gx_utility_math_cos(scaled_angle) * ROTATION_DISTANCE);
379 ydist = GX_FIXED_VAL_TO_INT(gx_utility_math_sin(scaled_angle) * ROTATION_DISTANCE);
380
381 width = (map->gx_pixelmap_width >> 1);
382 height = (map->gx_pixelmap_height >> 1);
383
384 gx_canvas_pixelmap_draw(xcenter + xdist - width, ycenter + ydist - height, map);
385
386 scaled_angle = GX_FIXED_VAL_MAKE(wave_rotation_angle + 60);
387 xdist = GX_FIXED_VAL_TO_INT(gx_utility_math_cos(scaled_angle) * ROTATION_DISTANCE);
388 ydist = GX_FIXED_VAL_TO_INT(gx_utility_math_sin(scaled_angle) * ROTATION_DISTANCE);
389
390 gx_canvas_pixelmap_draw(xcenter + xdist - width, ycenter + ydist - height, map);
391
392 scaled_angle = GX_FIXED_VAL_MAKE(wave_rotation_angle + 120);
393 xdist = GX_FIXED_VAL_TO_INT(gx_utility_math_cos(scaled_angle) * ROTATION_DISTANCE);
394 ydist = GX_FIXED_VAL_TO_INT(gx_utility_math_sin(scaled_angle) * ROTATION_DISTANCE);
395
396 gx_canvas_pixelmap_draw(xcenter + xdist - width, ycenter + ydist - height, map);
397 }
398
399 /******************************************************************************************/
400 /* Define custom progress bar draw function. */
401 /******************************************************************************************/
wash_cycle_progress_bar_draw(GX_PROGRESS_BAR * progress_bar)402 VOID wash_cycle_progress_bar_draw(GX_PROGRESS_BAR* progress_bar)
403 {
404 GX_PIXELMAP *map;
405 INT xpos;
406 INT ypos;
407 INT selected_dist;
408 GX_RECTANGLE *size = &progress_bar->gx_widget_size;
409 GX_BRUSH *brush;
410 INT alpha_shift;
411
412 gx_context_pixelmap_get(GX_PIXELMAP_ID_CYCLE_PROGRESS_DOT, &map);
413
414 ypos = size->gx_rectangle_top;
415
416 /* Draw background dots. */
417 gx_context_brush_get(&brush);
418 gx_context_fill_color_set(GX_COLOR_ID_WHITE);
419
420 brush->gx_brush_alpha = 100;
421 for (xpos = size->gx_rectangle_left; xpos < size->gx_rectangle_right; xpos += PROGRESS_DOT_SPACE)
422 {
423 gx_canvas_pixelmap_draw(xpos, ypos, map);
424 }
425
426 brush->gx_brush_alpha = 255;
427
428 selected_dist = (size->gx_rectangle_right - size->gx_rectangle_left) * progress_bar->gx_progress_bar_info.gx_progress_bar_info_current_val / 100;
429
430 /* Draw selected dots. */
431 if (main_screen.main_screen_btn_play.gx_widget_style & GX_STYLE_BUTTON_PUSHED)
432 {
433 if (selected_dist / PROGRESS_DOT_SPACE)
434 {
435 alpha_shift = 255 / (selected_dist / PROGRESS_DOT_SPACE);
436 }
437 else
438 {
439 alpha_shift = 255;
440 }
441
442 brush->gx_brush_alpha = progress_alpha_start;
443 for (xpos = size->gx_rectangle_left; xpos < size->gx_rectangle_left + selected_dist; xpos += PROGRESS_DOT_SPACE)
444 {
445 gx_canvas_pixelmap_draw(xpos, ypos, map);
446 if (brush->gx_brush_alpha + alpha_shift < 255)
447 {
448 brush->gx_brush_alpha += alpha_shift;
449 }
450 else
451 {
452 brush->gx_brush_alpha = 0;
453 }
454 }
455
456 brush->gx_brush_alpha = 255;
457
458 if (progress_alpha_start > PROGRESS_ALPHA_SHIFT)
459 {
460 progress_alpha_start -= PROGRESS_ALPHA_SHIFT;
461 }
462 else
463 {
464 progress_alpha_start = 255;
465 }
466 }
467 else
468 {
469 for (xpos = size->gx_rectangle_left; xpos < size->gx_rectangle_left + selected_dist; xpos += PROGRESS_DOT_SPACE)
470 {
471 gx_canvas_pixelmap_draw(xpos, ypos, map);
472 }
473 }
474 }