WIP sliders and incrimenting

This commit is contained in:
Dylan Smith
2026-01-16 14:45:38 -05:00
parent 6711b5dcc1
commit 7dc4bf493d
6 changed files with 178 additions and 73 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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));
}
}

View File

@@ -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);
}

View File

@@ -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;
}