WIP
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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++)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 \
|
||||
|
||||
Reference in New Issue
Block a user