diff --git a/Core/Inc/graphics/graphics.h b/Core/Inc/graphics/graphics.h index daf7cab..3ea7d6b 100644 --- a/Core/Inc/graphics/graphics.h +++ b/Core/Inc/graphics/graphics.h @@ -3,8 +3,27 @@ #include "display.h" #include "stdint.h" +#include "stdbool.h" +#include "fonts/font.h" void DisplayTest(pixel_t color); void DrawBox(uint32_t topleft_x_loc, uint32_t topleft_y_loc, uint32_t width, uint32_t height, pixel_t color); +/* +* All fields have default values when not provided +*/ +typedef struct +{ + uint16_t x; + uint16_t y; + uint16_t width; + uint16_t height; + pixel_t on_color; + pixel_t off_color; + pixel_t inner_padding_pixels; + bool value; +} toggle_switch_t; + +void draw_toggle_switch(volatile pixel_t *const framebuffer, const toggle_switch_t *const toggle_switch); + #endif \ No newline at end of file diff --git a/Core/Inc/graphics/menu.h b/Core/Inc/graphics/menu.h index 1bb10bf..99c24d0 100644 --- a/Core/Inc/graphics/menu.h +++ b/Core/Inc/graphics/menu.h @@ -5,41 +5,42 @@ #include "stdbool.h" #include "display.h" -typedef void (*menu_callback_t)(void *args); -typedef struct _graphical_menu_layout_t graphical_menu_layout_t; typedef struct _graphical_menu_t graphical_menu_t; +typedef struct _menu_entry_size_t menu_entry_size_t; +typedef void (*menu_callback_t)(void *const args); -// TODO -// typedef struct { -// uint16_t x; -// uint16_t y; -// uint16_t width; -// uint16_t height; -// } graphical_menu_position_t; +/* +* Extra draw function is called after the menu entry is drawn +* It is used to draw additional graphics on top of the menu entry +* It is passed the size of the menu entry and the args +*/ +typedef void (*extra_draw_function_t)(const menu_entry_size_t *const menu_entry_size, void *const args); typedef struct { const char *const title; - const bool enabled; // not enabled = grayed out, unhighlightable + bool disabled; const menu_callback_t highlighted_callback_function; void *const highlighted_callback_function_args; const menu_callback_t selected_callback_function; void *const selected_callback_function_args; + const extra_draw_function_t extra_draw_function; // called after the menu entry is drawn + void *const extra_draw_function_args; } graphical_menu_entry_t; - -struct _graphical_menu_layout_t { - graphical_menu_t *const parent_menu; - const uint8_t num_entries; - const graphical_menu_entry_t *const entries; -}; - struct _graphical_menu_t { - const graphical_menu_layout_t *const layout; - uint8_t selected_entry_idx; + graphical_menu_t *const parent_menu; + const uint8_t num_children; + uint8_t highlighted_child_idx; + graphical_menu_entry_t *const children; }; - +struct _menu_entry_size_t { + const uint16_t x; + const uint16_t y; + const uint16_t width; + const uint16_t height; +}; void draw_menu(volatile pixel_t *const framebuffer, const graphical_menu_t *const menu); void partial_redraw_menu(volatile pixel_t *const framebuffer, graphical_menu_t *const menu, uint8_t old_highlighted_entry_idx, uint8_t new_highlighted_entry_idx); diff --git a/Core/Inc/main.h b/Core/Inc/main.h index a1fc20c..b0ef578 100644 --- a/Core/Inc/main.h +++ b/Core/Inc/main.h @@ -384,6 +384,14 @@ void Error_Handler(void); #define OK_BUTTON_PRESSED() (HAL_GPIO_ReadPin(BUTTON4_GPIO_Port, BUTTON4_Pin) == GPIO_PIN_RESET) #define UP_BUTTON_PRESSED() (HAL_GPIO_ReadPin(BUTTON5_GPIO_Port, BUTTON5_Pin) == GPIO_PIN_RESET) +#define LED1_ON() (HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_SET)) +#define LED1_OFF() (HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_RESET)) +#define LED1_TOGGLE() (HAL_GPIO_TogglePin(LD3_GPIO_Port, LD3_Pin)) + +#define LED2_ON() (HAL_GPIO_WritePin(LD4_GPIO_Port, LD4_Pin, GPIO_PIN_SET)) +#define LED2_OFF() (HAL_GPIO_WritePin(LD4_GPIO_Port, LD4_Pin, GPIO_PIN_RESET)) +#define LED2_TOGGLE() (HAL_GPIO_TogglePin(LD4_GPIO_Port, LD4_Pin)) + /* USER CODE END Private defines */ #ifdef __cplusplus diff --git a/Core/Src/graphics/graphics.c b/Core/Src/graphics/graphics.c index eedcd86..ac65fd2 100644 --- a/Core/Src/graphics/graphics.c +++ b/Core/Src/graphics/graphics.c @@ -25,4 +25,30 @@ void DrawBox(uint32_t topleft_x_loc, uint32_t topleft_y_loc, uint32_t width, uin } } } +} + +void draw_toggle_switch(volatile pixel_t *const framebuffer, const toggle_switch_t *const toggle_switch) +{ + const uint16_t x_loc = toggle_switch->x; + const uint16_t y_loc = toggle_switch->y; + const uint16_t width = toggle_switch->width ? toggle_switch->width : 50; + const uint16_t height = toggle_switch->height ? toggle_switch->height : 20; + const pixel_t on_color = toggle_switch->on_color ? toggle_switch->on_color : MAKE_PIXEL(0, 255, 0); + const pixel_t off_color = toggle_switch->off_color ? toggle_switch->off_color : MAKE_PIXEL(160, 20, 20); + const bool value = toggle_switch->value; + + DrawBox(x_loc, y_loc, width, height, value ? on_color : off_color); + if (value) + { + const uint16_t inner_switchbox_width = height - (toggle_switch->inner_padding_pixels * 2); + const uint16_t inner_switchbox_x_loc = x_loc + width - toggle_switch->inner_padding_pixels - inner_switchbox_width; + const uint16_t inner_switchbox_y_loc = y_loc + toggle_switch->inner_padding_pixels; + DrawBox(inner_switchbox_x_loc, inner_switchbox_y_loc, inner_switchbox_width, inner_switchbox_width, MAKE_PIXEL(255, 255, 255)); + + } else { + const uint16_t inner_switchbox_width = height - (toggle_switch->inner_padding_pixels * 2); + const uint16_t inner_switchbox_x_loc = x_loc + toggle_switch->inner_padding_pixels; + const uint16_t inner_switchbox_y_loc = y_loc + toggle_switch->inner_padding_pixels; + DrawBox(inner_switchbox_x_loc, inner_switchbox_y_loc, inner_switchbox_width, inner_switchbox_width, MAKE_PIXEL(255, 255, 255)); + } } \ No newline at end of file diff --git a/Core/Src/graphics/menu.c b/Core/Src/graphics/menu.c index 0e49f48..bc688a4 100644 --- a/Core/Src/graphics/menu.c +++ b/Core/Src/graphics/menu.c @@ -15,8 +15,8 @@ static const pixel_t highlighted_text_color = MAKE_PIXEL(255, 255, 0); void draw_menu_entry(volatile pixel_t *const framebuffer, const graphical_menu_t *const menu, uint8_t entry_idx) { const uint16_t y_pos = entry_idx * entry_height; - const graphical_menu_entry_t *entry = &menu->layout->entries[entry_idx]; - const bool is_highlighted = (entry_idx == menu->selected_entry_idx) && entry->enabled; + const graphical_menu_entry_t *entry = &menu->children[entry_idx]; + const bool is_highlighted = (entry_idx == menu->highlighted_child_idx) && !entry->disabled; // Draw entry background - use highlighted color if this is the selected entry pixel_t bg_color = is_highlighted ? highlighted_bg_color : entry_bg_color; @@ -30,7 +30,7 @@ void draw_menu_entry(volatile pixel_t *const framebuffer, const graphical_menu_t } else { - text_color = entry->enabled ? enabled_text_color : disabled_text_color; + text_color = !entry->disabled ? enabled_text_color : disabled_text_color; } // Calculate baseline from top position: baseline = top + (line_height - base_line) @@ -44,7 +44,7 @@ void draw_menu(volatile pixel_t *const framebuffer, const graphical_menu_t *cons { DrawBox(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, entry_bg_color); - for (uint8_t i = 0; i < menu->layout->num_entries; i++) + for (uint8_t i = 0; i < menu->num_children; i++) { draw_menu_entry(framebuffer, menu, i); } @@ -60,15 +60,15 @@ void partial_redraw_menu(volatile pixel_t *const framebuffer, graphical_menu_t * void select_menu_entry(graphical_menu_t *const menu) { // Ensure selected_entry_idx is within bounds - if (menu->selected_entry_idx >= menu->layout->num_entries) + if (menu->highlighted_child_idx >= menu->num_children) { return; } - const graphical_menu_entry_t *entry = &menu->layout->entries[menu->selected_entry_idx]; + const graphical_menu_entry_t *entry = &menu->children[menu->highlighted_child_idx]; // Only select if the entry is enabled - if (entry->enabled && entry->selected_callback_function != NULL) + if (!entry->disabled && entry->selected_callback_function != NULL) { entry->selected_callback_function(entry->selected_callback_function_args); } @@ -76,22 +76,22 @@ void select_menu_entry(graphical_menu_t *const menu) void set_selected_menu_entry_idx(volatile pixel_t *const framebuffer, graphical_menu_t *const menu, uint8_t idx) { - const uint16_t old_highlighted_entry_idx = menu->selected_entry_idx; + const uint16_t old_highlighted_entry_idx = menu->highlighted_child_idx; // Handle case where the last entry is disabled - if (idx == menu->layout->num_entries - 1) + if (idx == menu->num_children - 1) { - while (!menu->layout->entries[idx].enabled) + while (!menu->children[idx].disabled) { idx--; } } // Only allow selecting enabled entries - while (!menu->layout->entries[idx].enabled) + while (menu->children[idx].disabled) { - if (idx > menu->selected_entry_idx) + if (idx > menu->highlighted_child_idx) { idx--; } @@ -102,32 +102,32 @@ void set_selected_menu_entry_idx(volatile pixel_t *const framebuffer, graphical_ } // Clamp the index to valid range - if (idx >= menu->layout->num_entries) + if (idx >= menu->num_children) { - if (menu->layout->num_entries == 0) return; - idx = menu->layout->num_entries - 1; + if (menu->num_children == 0) return; + idx = menu->num_children - 1; } - menu->selected_entry_idx = idx; + menu->highlighted_child_idx = idx; partial_redraw_menu(framebuffer, menu, old_highlighted_entry_idx, idx); } void decrement_selected_menu_entry_idx(volatile pixel_t *const framebuffer, graphical_menu_t *const menu) { - if (menu->selected_entry_idx == 0) + if (menu->highlighted_child_idx == 0) { - set_selected_menu_entry_idx(framebuffer, menu, menu->layout->num_entries - 1); + set_selected_menu_entry_idx(framebuffer, menu, menu->num_children - 1); return; } - set_selected_menu_entry_idx(framebuffer, menu, menu->selected_entry_idx - 1); + set_selected_menu_entry_idx(framebuffer, menu, menu->highlighted_child_idx - 1); } void increment_selected_menu_entry_idx(volatile pixel_t *const framebuffer, graphical_menu_t *const menu) { - if (menu->selected_entry_idx == menu->layout->num_entries - 1) + if (menu->highlighted_child_idx == menu->num_children - 1) { set_selected_menu_entry_idx(framebuffer, menu, 0); return; } - set_selected_menu_entry_idx(framebuffer, menu, menu->selected_entry_idx + 1); + set_selected_menu_entry_idx(framebuffer, menu, menu->highlighted_child_idx + 1); } \ No newline at end of file diff --git a/Core/Src/ui.c b/Core/Src/ui.c index adb1526..a7ed457 100644 --- a/Core/Src/ui.c +++ b/Core/Src/ui.c @@ -1,8 +1,14 @@ #include "ui.h" #include "menu.h" #include "display.h" +#include "main.h" +#include "graphics/graphics.h" void ui_enter_submenu(void *const args); +void ui_toggle_led1(void *const args); +void ui_toggle_led2(void *const args); +void ui_toggle_led1_switch(const menu_entry_size_t *const menu_entry_size, void *const args); +void ui_toggle_led2_switch(const menu_entry_size_t *const menu_entry_size, void *const args); /******************* */ /* Menu declarations */ @@ -15,40 +21,41 @@ static graphical_menu_t runescape_memes_menu; /* Menu definitions */ /******************* */ - -static const graphical_menu_layout_t main_menu_layout = { - .parent_menu = 0, - .num_entries = 3, - .entries = (graphical_menu_entry_t[]){ - {.title = "runescape memes", .enabled = true, .highlighted_callback_function = 0, .highlighted_callback_function_args = 0, .selected_callback_function = ui_enter_submenu, .selected_callback_function_args = &runescape_memes_menu}, - {.title = "Settings", .enabled = true, .highlighted_callback_function = 0, .highlighted_callback_function_args = 0, .selected_callback_function = 0, .selected_callback_function_args = 0}, - {.title = "About", .enabled = true, .highlighted_callback_function = 0, .highlighted_callback_function_args = 0, .selected_callback_function = 0, .selected_callback_function_args = 0}, - } -}; - -static const graphical_menu_layout_t runescape_memes_menu_layout = { - .parent_menu = &main_menu, - .num_entries = 7, - .entries = (graphical_menu_entry_t[]){ - {.title = "where varock", .enabled = true, .highlighted_callback_function = 0, .highlighted_callback_function_args = 0, .selected_callback_function = 0, .selected_callback_function_args = 0}, - {.title = "buying gf", .enabled = true, .highlighted_callback_function = 0, .highlighted_callback_function_args = 0, .selected_callback_function = 0, .selected_callback_function_args = 0}, - {.title = "you chop the tree", .enabled = true, .highlighted_callback_function = 0, .highlighted_callback_function_args = 0, .selected_callback_function = 0, .selected_callback_function_args = 0}, - {.title = "you chop the tree", .enabled = true, .highlighted_callback_function = 0, .highlighted_callback_function_args = 0, .selected_callback_function = 0, .selected_callback_function_args = 0}, - {.title = "you chop the tree", .enabled = true, .highlighted_callback_function = 0, .highlighted_callback_function_args = 0, .selected_callback_function = 0, .selected_callback_function_args = 0}, - {.title = "you chop the tree", .enabled = true, .highlighted_callback_function = 0, .highlighted_callback_function_args = 0, .selected_callback_function = 0, .selected_callback_function_args = 0}, - {.title = "you chop the tree", .enabled = true, .highlighted_callback_function = 0, .highlighted_callback_function_args = 0, .selected_callback_function = 0, .selected_callback_function_args = 0}, - } -}; - - static graphical_menu_t main_menu = { - .layout = &main_menu_layout, - .selected_entry_idx = 0, + .parent_menu = 0, + .num_children = 3, + .highlighted_child_idx = 0, + .children = (graphical_menu_entry_t[]){ + { + .title = "runescape memes menu", + .selected_callback_function = ui_enter_submenu, + .selected_callback_function_args = &runescape_memes_menu + }, + { + .title = "Toggle LED1", + .disabled = true, + .selected_callback_function = ui_toggle_led1, + .selected_callback_function_args = 0, + .extra_draw_function = ui_toggle_led1_switch, + }, + { + .title = "Toggle LED2", + .selected_callback_function = ui_toggle_led2, + .selected_callback_function_args = 0, + .extra_draw_function = ui_toggle_led2_switch, + } + } }; static graphical_menu_t runescape_memes_menu = { - .layout = &runescape_memes_menu_layout, - .selected_entry_idx = 0, + .parent_menu = &main_menu, + .num_children = 4, + .highlighted_child_idx = 0, + .children = (graphical_menu_entry_t[]){ + {.title = "where varock", .disabled = false, .highlighted_callback_function = 0, .highlighted_callback_function_args = 0, .selected_callback_function = 0, .selected_callback_function_args = 0}, + {.title = "you chop the tree", .disabled = false, .highlighted_callback_function = 0, .highlighted_callback_function_args = 0, .selected_callback_function = 0, .selected_callback_function_args = 0}, + {.title = "you chop the tree", .disabled = false, .highlighted_callback_function = 0, .highlighted_callback_function_args = 0, .selected_callback_function = 0, .selected_callback_function_args = 0}, + } }; @@ -64,6 +71,50 @@ static bool redraw_requested = true; // static enum ui_state_t ui_state = UI_STATE_MENU; static graphical_menu_t *current_menu = &main_menu; +/********************** */ +/* UI callback functions */ +/********************** */ + +void ui_toggle_led1(void *const args) +{ + LED1_TOGGLE(); +} + +void ui_toggle_led2(void *const args) +{ + LED2_TOGGLE(); +} + +void ui_toggle_led1_switch(const menu_entry_size_t *const menu_entry_size, void *const args) +{ + const uint16_t width_padding = 10; + const uint16_t height_padding = 10; + const uint16_t x = menu_entry_size->x + (menu_entry_size->width + width_padding); + const uint16_t y = menu_entry_size->y + height_padding; + const toggle_switch_t toggle_switch = { + .x = x, + .y = y, + .value = HAL_GPIO_ReadPin(LD3_GPIO_Port, LD3_Pin) == GPIO_PIN_SET, + }; + + draw_toggle_switch(next_framebuffer, &toggle_switch); +} + +void ui_toggle_led2_switch(const menu_entry_size_t *const menu_entry_size, void *const args) +{ + const uint16_t width_padding = 10; + const uint16_t height_padding = 10; + const uint16_t x = menu_entry_size->x + (menu_entry_size->width + width_padding); + const uint16_t y = menu_entry_size->y + height_padding; + const toggle_switch_t toggle_switch = { + .x = x, + .y = y, + .value = HAL_GPIO_ReadPin(LD4_GPIO_Port, LD4_Pin) == GPIO_PIN_SET, + }; + + draw_toggle_switch(next_framebuffer, &toggle_switch); +} + /************************* */ /* UI function definitions */ /************************* */ @@ -76,11 +127,11 @@ void ui_enter_submenu(void *const args) void ui_exit_submenu(void) { - if (current_menu->layout->parent_menu == 0) + if (current_menu->parent_menu == 0) { return; } - current_menu = current_menu->layout->parent_menu; + current_menu = current_menu->parent_menu; redraw_requested = true; }