From 6cdbe8cb11f690bc7f3a4ab77852e6c90ae3e696 Mon Sep 17 00:00:00 2001 From: Dylan Smith Date: Mon, 12 Jan 2026 16:25:36 -0500 Subject: [PATCH] WIP --- Core/Inc/graphics/fonts/font.h | 4 +- Core/Inc/graphics/graphics.h | 2 +- Core/Inc/graphics/menu.h | 15 ++++-- Core/Src/graphics/fonts/font.c | 15 +++--- Core/Src/graphics/graphics.c | 2 +- Core/Src/graphics/menu.c | 91 +++++++++++++++++++++++++++++++++- Core/Src/main.c | 23 +++++---- STM32Make.make | 2 + 8 files changed, 128 insertions(+), 26 deletions(-) diff --git a/Core/Inc/graphics/fonts/font.h b/Core/Inc/graphics/fonts/font.h index eec889d..43c51fd 100644 --- a/Core/Inc/graphics/fonts/font.h +++ b/Core/Inc/graphics/fonts/font.h @@ -14,8 +14,8 @@ extern lv_font_t roboto_bold_font; extern lv_font_t roboto_bold_large_font; #endif -uint16_t draw_character(rgb565_pixel_t *framebuffer, const lv_font_t *font, const uint16_t x_loc, const uint16_t y_loc, const uint8_t character, rgb565_pixel_t color); +uint16_t draw_character(pixel_t *framebuffer, const lv_font_t *font, const uint16_t x_loc, const uint16_t y_loc, const uint8_t character, pixel_t color); -void draw_string(rgb565_pixel_t *framebuffer, const lv_font_t *font, const uint16_t x_loc, const uint16_t y_loc, const uint8_t *string, rgb565_pixel_t color); +void draw_string(pixel_t *framebuffer, const lv_font_t *font, const uint16_t x_loc, const uint16_t y_loc, const uint8_t *string, pixel_t color); #endif \ No newline at end of file diff --git a/Core/Inc/graphics/graphics.h b/Core/Inc/graphics/graphics.h index de811e2..daf7cab 100644 --- a/Core/Inc/graphics/graphics.h +++ b/Core/Inc/graphics/graphics.h @@ -5,6 +5,6 @@ #include "stdint.h" void DisplayTest(pixel_t color); -void DrawBox(uint32_t topleft_x_loc, uint32_t topleft_y_loc, uint32_t height, uint32_t width, pixel_t color); +void DrawBox(uint32_t topleft_x_loc, uint32_t topleft_y_loc, uint32_t width, uint32_t height, pixel_t color); #endif \ No newline at end of file diff --git a/Core/Inc/graphics/menu.h b/Core/Inc/graphics/menu.h index d0a3eaf..777a00e 100644 --- a/Core/Inc/graphics/menu.h +++ b/Core/Inc/graphics/menu.h @@ -4,13 +4,16 @@ #include "stdint.h" #include "stdbool.h" +typedef void (*menu_callback_t)(void *args); typedef struct { uint8_t *title; - bool enabled; // not enabled = grayed out, unselectable - void *highlighted_callback_function; - void *selected_callback_function; + bool enabled; // not enabled = grayed out, unhighlightable + menu_callback_t highlighted_callback_function; + void *highlighted_callback_function_args; + menu_callback_t selected_callback_function; + void *selected_callback_function_args; } graphical_menu_entry_t; @@ -18,8 +21,12 @@ typedef struct _graphical_menu_t graphical_menu_t; struct _graphical_menu_t { graphical_menu_t *parent_menu; uint8_t num_entries; - uint8_t highlighted_idx; graphical_menu_entry_t *entries; }; +void draw_menu(const graphical_menu_t *const menu); +void select_menu_entry(const graphical_menu_t *const menu); +uint8_t get_selected_menu_entry_idx(void); +void set_selected_menu_entry_idx(const graphical_menu_t *const menu, uint8_t idx); + #endif \ No newline at end of file diff --git a/Core/Src/graphics/fonts/font.c b/Core/Src/graphics/fonts/font.c index 997daa8..2901b91 100644 --- a/Core/Src/graphics/fonts/font.c +++ b/Core/Src/graphics/fonts/font.c @@ -71,7 +71,7 @@ const void * lv_font_get_bitmap_fmt_txt(lv_font_fmt_txt_glyph_dsc_t * g_dsc, lv_ * @note If the character is not found in the font's character map, the function returns * 0 without drawing anything. */ -uint16_t draw_character(rgb565_pixel_t *framebuffer, const lv_font_t *font, const uint16_t x_loc, const uint16_t y_loc, const uint8_t character, rgb565_pixel_t color) +uint16_t draw_character(pixel_t *framebuffer, const lv_font_t *font, const uint16_t x_loc, const uint16_t y_loc, const uint8_t character, pixel_t color) { const lv_font_fmt_txt_dsc_t *font_dsc = (lv_font_fmt_txt_dsc_t *)font->dsc; lv_font_fmt_txt_glyph_dsc_t glyph_dsc; @@ -88,15 +88,18 @@ uint16_t draw_character(rgb565_pixel_t *framebuffer, const lv_font_t *font, cons { const uint8_t current_bit_in_byte = bitmap_pixel_index % 8; const uint16_t bitmap_byte_index = glyph_dsc.bitmap_index + (bitmap_pixel_index / 8); - const uint32_t fb_pixel_x = x_loc + (bitmap_pixel_index % glyph_width) + glyph_ofs_x; - const uint32_t line_top = y_loc + font->base_line - glyph_height; - const uint32_t fb_pixel_y = line_top + (bitmap_pixel_index / glyph_width) - glyph_ofs_y; + const int32_t fb_pixel_x = x_loc + (bitmap_pixel_index % glyph_width) + glyph_ofs_x; + const int32_t line_top = y_loc + font->base_line - glyph_height; + const int32_t fb_pixel_y = line_top + (bitmap_pixel_index / glyph_width) - glyph_ofs_y; const uint32_t fb_pixel_index = (fb_pixel_y * DISPLAY_WIDTH) + fb_pixel_x; const bool bit_on = font_dsc->glyph_bitmap[bitmap_byte_index] & (0x80 >> current_bit_in_byte); if (bit_on) { - framebuffer[fb_pixel_index] = color; + if (fb_pixel_x >= 0 && fb_pixel_x < DISPLAY_WIDTH && fb_pixel_y >= 0 && fb_pixel_y < DISPLAY_HEIGHT) + { + framebuffer[fb_pixel_index] = color; + } } } @@ -138,7 +141,7 @@ uint16_t draw_character(rgb565_pixel_t *framebuffer, const lv_font_t *font, cons * @note All characters in the string are drawn on the same horizontal baseline (y_loc * remains constant for all characters). */ -void draw_string(rgb565_pixel_t *framebuffer, const lv_font_t *font, const uint16_t x_loc, const uint16_t y_loc, const uint8_t *string, rgb565_pixel_t color) +void draw_string(pixel_t *framebuffer, const lv_font_t *font, const uint16_t x_loc, const uint16_t y_loc, const uint8_t *string, pixel_t color) { uint32_t current_x = x_loc << 4; diff --git a/Core/Src/graphics/graphics.c b/Core/Src/graphics/graphics.c index 1da2f72..43b14c9 100644 --- a/Core/Src/graphics/graphics.c +++ b/Core/Src/graphics/graphics.c @@ -12,7 +12,7 @@ void DisplayTest(pixel_t color) } -void DrawBox(uint32_t topleft_x_loc, uint32_t topleft_y_loc, uint32_t height, uint32_t width, pixel_t color) +void DrawBox(uint32_t topleft_x_loc, uint32_t topleft_y_loc, uint32_t width, uint32_t height, pixel_t color) { for (uint32_t y = topleft_y_loc; y < (topleft_y_loc + height); y++) { diff --git a/Core/Src/graphics/menu.c b/Core/Src/graphics/menu.c index 51cce86..184894c 100644 --- a/Core/Src/graphics/menu.c +++ b/Core/Src/graphics/menu.c @@ -1,6 +1,95 @@ #include "menu.h" +#include "graphics.h" +#include "fonts/font.h" +#include "display.h" -void draw_menu(graphical_menu_t *menu) +static uint8_t selected_entry_idx = 0; + +void draw_menu(const graphical_menu_t *const menu) { + const uint16_t entry_height = 40; + const uint16_t padding_x = 10; + const uint16_t padding_y = 0; + const pixel_t enabled_text_color = MAKE_PIXEL(31, 63, 31); // White text + const pixel_t disabled_text_color = MAKE_PIXEL(15, 31, 15); // Gray text for disabled + const pixel_t entry_bg_color = MAKE_PIXEL(15, 15, 15); // Slightly darker for entry background + const pixel_t highlighted_bg_color = MAKE_PIXEL(0, 31, 63); // Blue background for highlighted entry + const pixel_t highlighted_text_color = MAKE_PIXEL(31, 63, 31); // White text for highlighted entry + + // Ensure selected_entry_idx is within bounds + if (selected_entry_idx >= menu->num_entries) + { + selected_entry_idx = 0; + } + + for (uint8_t i = 0; i < menu->num_entries; i++) + { + const uint16_t y_pos = i * entry_height; + const graphical_menu_entry_t *entry = &menu->entries[i]; + const bool is_highlighted = (i == selected_entry_idx) && entry->enabled; + + // Draw entry background - use highlighted color if this is the selected entry + pixel_t bg_color = is_highlighted ? highlighted_bg_color : entry_bg_color; + DrawBox(0, y_pos, DISPLAY_WIDTH, entry_height, bg_color); + + // Draw entry text - use highlighted color if selected, otherwise use enabled/disabled color + pixel_t text_color; + if (is_highlighted) + { + text_color = highlighted_text_color; + } + else + { + text_color = entry->enabled ? enabled_text_color : disabled_text_color; + } + + // Calculate baseline from top position: baseline = top + (line_height - base_line) + const uint16_t text_baseline_y = y_pos + padding_y + (roboto_bold_font.line_height - roboto_bold_font.base_line); + draw_string((pixel_t *)framebuffer, &roboto_bold_font, + padding_x, text_baseline_y, + entry->title, text_color); + } +} +void select_menu_entry(const graphical_menu_t *const menu) +{ + // Ensure selected_entry_idx is within bounds + if (selected_entry_idx >= menu->num_entries) + { + return; + } + + const graphical_menu_entry_t *entry = &menu->entries[selected_entry_idx]; + + // Only select if the entry is enabled + if (entry->enabled && entry->selected_callback_function != NULL) + { + entry->selected_callback_function(entry->selected_callback_function_args); + } +} + +uint8_t get_selected_menu_entry_idx(void) +{ + return selected_entry_idx; +} + +void set_selected_menu_entry_idx(const graphical_menu_t *const menu, uint8_t idx) +{ + // Clamp the index to valid range + if (idx >= menu->num_entries) + { + idx = menu->num_entries > 0 ? menu->num_entries - 1 : 0; + } + + // Only allow selecting enabled entries + if (menu->entries[idx].enabled) + { + selected_entry_idx = idx; + + // Call highlighted callback if it exists + if (menu->entries[idx].highlighted_callback_function != NULL) + { + menu->entries[idx].highlighted_callback_function(menu->entries[idx].highlighted_callback_function_args); + } + } } \ No newline at end of file diff --git a/Core/Src/main.c b/Core/Src/main.c index e99933a..448d92f 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -19,6 +19,7 @@ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "cmsis_os.h" +#include "graphics.h" #include "stm32f4xx_hal_ltdc.h" #include "stm32f4xx_hal_spi.h" #include "usb_host.h" @@ -27,6 +28,7 @@ /* USER CODE BEGIN Includes */ #include "display.h" #include "font.h" +#include "menu.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ @@ -903,6 +905,15 @@ static void MX_GPIO_Init(void) /* USER CODE BEGIN 4 */ +const graphical_menu_t menu_main = { + .num_entries = 3, + .entries = (graphical_menu_entry_t[]){ + {.title = "Home", .enabled = true, .highlighted_callback_function = NULL, .highlighted_callback_function_args = NULL, .selected_callback_function = NULL, .selected_callback_function_args = NULL}, + {.title = "Settings", .enabled = true, .highlighted_callback_function = NULL, .highlighted_callback_function_args = NULL, .selected_callback_function = NULL, .selected_callback_function_args = NULL}, + {.title = "About", .enabled = true, .highlighted_callback_function = NULL, .highlighted_callback_function_args = NULL, .selected_callback_function = NULL, .selected_callback_function_args = NULL}, + } +}; + /* USER CODE END 4 */ /* USER CODE BEGIN Header_StartDefaultTask */ @@ -916,25 +927,15 @@ void StartDefaultTask(void const * argument) { /* init code for USB_HOST */ /* USER CODE BEGIN 5 */ - times_changed = 0; ILI9341_Init(); uint8_t time_string[20] = {0}; DisplayTest(0xFFFF); + draw_menu(&menu_main); - draw_string(framebuffer, &roboto_bold_font, 10, 75, "Number of beans:", 0x0000); - /* Infinite loop */ for(;;) { - uint32_t t = HAL_GetTick() / 100; - // Convert milliseconds to string - uint32_to_string(t, time_string, sizeof(time_string)); - DrawBox(25, 0, 40, 80, 0xffff); - draw_string(framebuffer, &roboto_bold_font, 25, 25, time_string, 0x0000); - DrawBox(25, 100, 40, 150, 0xffff); - draw_string(framebuffer, &roboto_bold_large_font, 25, 125, time_string, 0x001f); - osDelay(100); } /* USER CODE END 5 */ diff --git a/STM32Make.make b/STM32Make.make index 995adc9..a4c1e40 100644 --- a/STM32Make.make +++ b/STM32Make.make @@ -80,6 +80,8 @@ Core/Src/graphics/display.c \ Core/Src/graphics/fonts/font.c \ Core/Src/graphics/fonts/roboto_bold_font.c \ Core/Src/graphics/fonts/roboto_bold_large_font.c \ +Core/Src/graphics/graphics.c \ +Core/Src/graphics/menu.c \ Core/Src/main.c \ Core/Src/stm32f4xx_hal_msp.c \ Core/Src/stm32f4xx_hal_timebase_tim.c \