1
0
mirror of https://github.com/azure-rtos/guix.git synced 2025-02-04 07:13:17 +08:00
guix/samples/demo_guix_washing_machine/demo_guix_washing_machine.c
2022-04-20 05:09:15 +00:00

474 lines
17 KiB
C

/* This is a small demo of the high-performance GUIX graphics framework. */
#include "demo_guix_washing_machine.h"
#define MEMORY_BUFFER_SIZE (MAIN_DISPLAY_X_RESOLUTION * MAIN_DISPLAY_Y_RESOLUTION * 4)
#define ID_TIMER_WAVE_ANIMATION 1
#define ID_TIMER_PROGRESS_BAR_ANIMATION 2
#define ID_TIMER_TIME 3
#define PROGRESS_DOT_SPACE 9
#define PROGRESS_ALPHA_SHIFT 10
#define ROTATION_DISTANCE 25
#define WASH_CYCLE_TEMPERATURE_RING_WIDTH 52
/* Define variables. */
TX_BYTE_POOL memory_pool;
GX_CHAR memory_buffer[MEMORY_BUFFER_SIZE];
GX_WINDOW_ROOT *root;
INT wave_rotation_angle = 0; /* Used for wave animation in water cycle and temperature window. */
INT wash_cycle_remain_seconds = 3600; /* Wash cyle remain time. */
INT progress_alpha_start = 0; /* Used for progress bar animation. */
/* Define prototypes. */
VOID guix_setup(void);
extern UINT win32_graphics_driver_setup_24xrgb(GX_DISPLAY* display);
/******************************************************************************************/
/* Application entry. */
/******************************************************************************************/
int main(int argc, char ** argv)
{
tx_kernel_enter();
return(0);
}
/******************************************************************************************/
/* Define memory allocator function. */
/******************************************************************************************/
VOID *memory_allocate(ULONG size)
{
VOID *memptr;
if (tx_byte_allocate(&memory_pool, &memptr, size, TX_NO_WAIT) == TX_SUCCESS)
{
return memptr;
}
return NULL;
}
/******************************************************************************************/
/* Define memory de-allocator function. */
/******************************************************************************************/
void memory_free(VOID *mem)
{
tx_byte_release(mem);
}
/******************************************************************************************/
/* Define tx_application_define function. */
/******************************************************************************************/
VOID tx_application_define(void *first_unused_memory)
{
/* Create byte pool. */
tx_byte_pool_create(&memory_pool, "memory_buffer", memory_buffer, MEMORY_BUFFER_SIZE);
guix_setup();
}
/******************************************************************************************/
/* Define custom button selection function to remove GX_STYLE_BUTTON_PUSHED style before */
/* call the default button select route, so that button selected event can be send no */
/* mater the selected button is pushed already or not. */
/******************************************************************************************/
VOID repeat_selection_style_button_select(GX_WIDGET *button)
{
button->gx_widget_style &= ~GX_STYLE_BUTTON_PUSHED;
gx_button_select((GX_BUTTON *)button);
}
/******************************************************************************************/
/* Initiate and run GUIX. */
/******************************************************************************************/
VOID guix_setup()
{
/* Initialize GUIX. */
gx_system_initialize();
/* Install memory allocator and de-allocator. */
gx_system_memory_allocator_set(memory_allocate, memory_free);
/* Configure display. */
gx_studio_display_configure(MAIN_DISPLAY, win32_graphics_driver_setup_24xrgb,
LANGUAGE_ENGLISH, MAIN_DISPLAY_THEME_1, &root);
/* Create the main screen and attach it to root window. */
gx_studio_named_widget_create("main_screen", (GX_WIDGET *)root, GX_NULL);
/* Change button select handler of wash cycle button. */
main_screen.main_screen_btn_wash_cycle.gx_button_select_handler = repeat_selection_style_button_select;
/* Create wash cycle window. */
gx_studio_named_widget_create("wash_cycle_window", (GX_WIDGET *)&main_screen, GX_NULL);
/* Initialize wash cycle window. */
wash_cycle_window_init(wash_cycle_remain_seconds);
/* Create mode select window. */
gx_studio_named_widget_create("mode_select_window", GX_NULL, GX_NULL);
/* Initialize mode select window. */
mode_select_window_init();
/* Create temperature window. */
gx_studio_named_widget_create("temperature_window", GX_NULL, GX_NULL);
/* Create water level window. */
gx_studio_named_widget_create("water_level_window", GX_NULL, GX_NULL);
/* Initialize water level window. */
water_level_window_init();
/* Show the root window to make it and wash cycle screen visible. */
gx_widget_show(root);
/* Let GUIX run. */
gx_system_start();
}
/******************************************************************************************/
/* Mark wave animation parent dirty. */
/******************************************************************************************/
VOID mark_wave_animation_parent_dirty()
{
GX_RECTANGLE dirty_area;
GX_WIDGET *parent;
if (wash_cycle_window.gx_widget_status & GX_STATUS_VISIBLE)
{
parent = (GX_WIDGET *)&wash_cycle_window;
}
else if (temperature_window.gx_widget_status & GX_STATUS_VISIBLE)
{
parent = (GX_WIDGET *)&temperature_window;
}
else
{
return;
}
/* Calculate wave area. */
dirty_area = parent->gx_widget_size;
dirty_area.gx_rectangle_left = (GX_VALUE)(dirty_area.gx_rectangle_left + WASH_CYCLE_TEMPERATURE_RING_WIDTH);
dirty_area.gx_rectangle_top = (GX_VALUE)(dirty_area.gx_rectangle_top + WASH_CYCLE_TEMPERATURE_RING_WIDTH);
dirty_area.gx_rectangle_right = (GX_VALUE)(dirty_area.gx_rectangle_right - WASH_CYCLE_TEMPERATURE_RING_WIDTH);
dirty_area.gx_rectangle_bottom = (GX_VALUE)(dirty_area.gx_rectangle_bottom - WASH_CYCLE_TEMPERATURE_RING_WIDTH);
/* Mark wave area as dirty. */
gx_system_dirty_partial_add(parent, &dirty_area);
}
/******************************************************************************************/
/* Update wash cycle remain time that displayed in various windows. */
/******************************************************************************************/
VOID wash_cycle_remain_time_update(INT remain_reconds)
{
/* Update remain time in wash cycle window. */
wash_cycle_window_remain_time_update(remain_reconds);
/* Update remain time in mode select window. */
mode_select_window_remain_time_update(remain_reconds);
}
/******************************************************************************************/
/* Set wash cycle remain time. */
/******************************************************************************************/
VOID remain_time_set(INT seconds)
{
/* Set current wash cycle remain time. */
wash_cycle_remain_seconds = seconds;
/* Update wash cycle remain time that displayed in various windows. */
wash_cycle_remain_time_update(wash_cycle_remain_seconds);
}
/******************************************************************************************/
/* Override the default event processing of "main_screen" to handle signals from my child */
/* widgets. */
/******************************************************************************************/
UINT main_screen_event_process(GX_WINDOW* window, GX_EVENT* event_ptr)
{
switch (event_ptr->gx_event_type)
{
case GX_SIGNAL(ID_BTN_WASH_CYCLE, GX_EVENT_RADIO_SELECT):
if (wash_cycle_window.gx_widget_status & GX_STATUS_VISIBLE)
{
/* Dettach wash cycle window. */
gx_widget_detach(&wash_cycle_window);
/* Attach mode select window. */
gx_widget_attach((GX_WIDGET*)window, &mode_select_window);
}
else
{
if (mode_select_window.gx_widget_status & GX_STATUS_VISIBLE)
{
/* Dettach mode select window. */
gx_widget_detach(&mode_select_window);
}
/* Attach wash cycle window. */
gx_widget_attach((GX_WIDGET*)window, &wash_cycle_window);
}
break;
case GX_SIGNAL(ID_BTN_WASH_CYCLE, GX_EVENT_RADIO_DESELECT):
if (mode_select_window.gx_widget_status & GX_STATUS_VISIBLE)
{
/* Dettach wash cycle window. */
gx_widget_detach(&mode_select_window);
}
else
{
/* Dettach mode select window. */
gx_widget_detach(&wash_cycle_window);
}
break;
case GX_SIGNAL(ID_BTN_TEMPERATURE, GX_EVENT_RADIO_SELECT):
/* Attach temperature window. */
gx_widget_attach((GX_WIDGET*)window, &temperature_window);
break;
case GX_SIGNAL(ID_BTN_TEMPERATURE, GX_EVENT_RADIO_DESELECT):
/* Dettach temperature window. */
gx_widget_detach(&temperature_window);
break;
case GX_SIGNAL(ID_BTN_WATER_LEVEL, GX_EVENT_RADIO_SELECT):
/* Attach water level window. */
gx_widget_attach((GX_WIDGET*)window, &water_level_window);
break;
case GX_SIGNAL(ID_BTN_WATER_LEVEL, GX_EVENT_RADIO_DESELECT):
/* Dettach water level page. */
gx_widget_detach(&water_level_window);
break;
case GX_SIGNAL(ID_BTN_PLAY, GX_EVENT_TOGGLE_ON):
gx_system_timer_start(window, ID_TIMER_TIME, GX_TICKS_SECOND, GX_TICKS_SECOND);
gx_system_timer_start(window, ID_TIMER_PROGRESS_BAR_ANIMATION, 40 / GX_SYSTEM_TIMER_MS, 40 / GX_SYSTEM_TIMER_MS);
gx_system_timer_start(window, ID_TIMER_WAVE_ANIMATION, 1, 1);
break;
case GX_SIGNAL(ID_BTN_PLAY, GX_EVENT_TOGGLE_OFF):
gx_system_timer_stop(window, 0);
mark_wave_animation_parent_dirty();
gx_system_dirty_mark(&main_screen.main_screen_wash_cycle_progress_bar);
break;
case GX_EVENT_TIMER:
if (event_ptr->gx_event_payload.gx_event_timer_id == ID_TIMER_WAVE_ANIMATION)
{
wave_rotation_angle = (358 + wave_rotation_angle) % 360;
mark_wave_animation_parent_dirty();
}
if(event_ptr->gx_event_payload.gx_event_timer_id == ID_TIMER_PROGRESS_BAR_ANIMATION)
{
gx_system_dirty_mark(&main_screen.main_screen_wash_cycle_progress_bar);
}
if(event_ptr->gx_event_payload.gx_event_timer_id == ID_TIMER_TIME)
{
wash_cycle_remain_seconds--;
if (wash_cycle_remain_seconds >= 0)
{
wash_cycle_remain_time_update(wash_cycle_remain_seconds);
}
}
break;
default:
return gx_window_event_process(window, event_ptr);
}
return 0;
}
/******************************************************************************************/
/* Define custom prompt draw function for child prompts of a button. */
/******************************************************************************************/
VOID btn_text_draw(GX_PROMPT *prompt)
{
if (prompt->gx_widget_parent->gx_widget_style & GX_STYLE_BUTTON_PUSHED)
{
prompt->gx_widget_style |= GX_STYLE_DRAW_SELECTED;
}
else
{
prompt->gx_widget_style &= (~GX_STYLE_DRAW_SELECTED);
}
gx_prompt_draw(prompt);
}
/******************************************************************************************/
/* Define custom numeric prompt draw function for child numeric prompts of a button. */
/******************************************************************************************/
VOID btn_numeric_text_draw(GX_NUMERIC_PROMPT* prompt)
{
if (prompt->gx_widget_parent->gx_widget_style & GX_STYLE_BUTTON_PUSHED)
{
prompt->gx_widget_style |= GX_STYLE_DRAW_SELECTED;
}
else
{
prompt->gx_widget_style &= (~GX_STYLE_DRAW_SELECTED);
}
gx_prompt_draw((GX_PROMPT *)prompt);
}
/******************************************************************************************/
/* Define format function for numeric prompt to show time. */
/******************************************************************************************/
VOID time_format(GX_NUMERIC_PROMPT* prompt, INT value)
{
if (value < 10)
{
prompt->gx_numeric_prompt_buffer[0] = '0';
prompt->gx_numeric_prompt_buffer[1] = '0' + value;
}
else if (value < 100)
{
prompt->gx_numeric_prompt_buffer[0] = '0' + (value / 10);
prompt->gx_numeric_prompt_buffer[1] = '0' + (value % 10);
}
}
/******************************************************************************************/
/* Draw animation wave in the center of specified window. */
/******************************************************************************************/
VOID animation_wave_draw(GX_WINDOW* window)
{
GX_RECTANGLE *size = &window->gx_widget_size;
INT scaled_angle;
INT xdist;
INT ydist;
INT xcenter;
INT ycenter;
INT width;
INT height;
GX_PIXELMAP *map;
gx_context_pixelmap_get(GX_PIXELMAP_ID_WAVE, &map);
width = size->gx_rectangle_right - size->gx_rectangle_left + 1;
height = size->gx_rectangle_bottom - size->gx_rectangle_top + 1;
xcenter = size->gx_rectangle_left + (width >> 1);
ycenter = size->gx_rectangle_top + (height >> 1);
gx_context_brush_define(GX_COLOR_ID_WHITE, GX_COLOR_ID_WHITE, GX_BRUSH_ALIAS | GX_BRUSH_SOLID_FILL);
gx_context_brush_width_set(1);
scaled_angle = GX_FIXED_VAL_MAKE(wave_rotation_angle);
xdist = GX_FIXED_VAL_TO_INT(gx_utility_math_cos(scaled_angle) * ROTATION_DISTANCE);
ydist = GX_FIXED_VAL_TO_INT(gx_utility_math_sin(scaled_angle) * ROTATION_DISTANCE);
width = (map->gx_pixelmap_width >> 1);
height = (map->gx_pixelmap_height >> 1);
gx_canvas_pixelmap_draw(xcenter + xdist - width, ycenter + ydist - height, map);
scaled_angle = GX_FIXED_VAL_MAKE(wave_rotation_angle + 60);
xdist = GX_FIXED_VAL_TO_INT(gx_utility_math_cos(scaled_angle) * ROTATION_DISTANCE);
ydist = GX_FIXED_VAL_TO_INT(gx_utility_math_sin(scaled_angle) * ROTATION_DISTANCE);
gx_canvas_pixelmap_draw(xcenter + xdist - width, ycenter + ydist - height, map);
scaled_angle = GX_FIXED_VAL_MAKE(wave_rotation_angle + 120);
xdist = GX_FIXED_VAL_TO_INT(gx_utility_math_cos(scaled_angle) * ROTATION_DISTANCE);
ydist = GX_FIXED_VAL_TO_INT(gx_utility_math_sin(scaled_angle) * ROTATION_DISTANCE);
gx_canvas_pixelmap_draw(xcenter + xdist - width, ycenter + ydist - height, map);
}
/******************************************************************************************/
/* Define custom progress bar draw function. */
/******************************************************************************************/
VOID wash_cycle_progress_bar_draw(GX_PROGRESS_BAR* progress_bar)
{
GX_PIXELMAP *map;
INT xpos;
INT ypos;
INT selected_dist;
GX_RECTANGLE *size = &progress_bar->gx_widget_size;
GX_BRUSH *brush;
INT alpha_shift;
gx_context_pixelmap_get(GX_PIXELMAP_ID_CYCLE_PROGRESS_DOT, &map);
ypos = size->gx_rectangle_top;
/* Draw background dots. */
gx_context_brush_get(&brush);
gx_context_fill_color_set(GX_COLOR_ID_WHITE);
brush->gx_brush_alpha = 100;
for (xpos = size->gx_rectangle_left; xpos < size->gx_rectangle_right; xpos += PROGRESS_DOT_SPACE)
{
gx_canvas_pixelmap_draw(xpos, ypos, map);
}
brush->gx_brush_alpha = 255;
selected_dist = (size->gx_rectangle_right - size->gx_rectangle_left) * progress_bar->gx_progress_bar_info.gx_progress_bar_info_current_val / 100;
/* Draw selected dots. */
if (main_screen.main_screen_btn_play.gx_widget_style & GX_STYLE_BUTTON_PUSHED)
{
if (selected_dist / PROGRESS_DOT_SPACE)
{
alpha_shift = 255 / (selected_dist / PROGRESS_DOT_SPACE);
}
else
{
alpha_shift = 255;
}
brush->gx_brush_alpha = progress_alpha_start;
for (xpos = size->gx_rectangle_left; xpos < size->gx_rectangle_left + selected_dist; xpos += PROGRESS_DOT_SPACE)
{
gx_canvas_pixelmap_draw(xpos, ypos, map);
if (brush->gx_brush_alpha + alpha_shift < 255)
{
brush->gx_brush_alpha += alpha_shift;
}
else
{
brush->gx_brush_alpha = 0;
}
}
brush->gx_brush_alpha = 255;
if (progress_alpha_start > PROGRESS_ALPHA_SHIFT)
{
progress_alpha_start -= PROGRESS_ALPHA_SHIFT;
}
else
{
progress_alpha_start = 255;
}
}
else
{
for (xpos = size->gx_rectangle_left; xpos < size->gx_rectangle_left + selected_dist; xpos += PROGRESS_DOT_SPACE)
{
gx_canvas_pixelmap_draw(xpos, ypos, map);
}
}
}