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 }