#include "display_utils.h" #include "gui.h" #include "renderer.h" container_t gui_list_container_create(void *state, uint32_t items_count, uint16_t item_height, render_item render_it, render_item render_header) { list_container_t list = { .item_height = item_height, .items_count = items_count, .state = state, .scroll_x = 0, .scroll_y = 0, .selected_index = 0, .render_header_fn = render_header, .render_item_fn = render_it, .regular_background = BLACK_PIXEL, .regular_foreground = WHITE_PIXEL, .selected_background = WHITE_PIXEL, .selected_foreground = BLACK_PIXEL, .item_padding = 3, }; container_t container = {.focusable = true, .focused = false, .height = item_height * items_count, .width = 0, .inner.list = list, .x = 0, .y = 0}; return container; } void gui_list_scroll(container_t *container, int16_t x, int16_t y) { container->inner.list.scroll_x += x; if (y < 0) { container->inner.list.selected_index--; } else if (y > 0) { container->inner.list.selected_index++; } } bool gui_list_container_set_state(container_t *container, void *state, uint32_t items_count) { container->inner.list.state = state; container->inner.list.items_count = items_count; container->inner.list.selected_index = 0; return true; } bool gui_list_container_set_item_height(container_t *container, uint16_t item_height) { container->inner.list.item_height = item_height; return true; } bool gui_list_container_set_render_function(container_t *container, render_item render_it, render_item render_header) { container->inner.list.render_item_fn = render_it; container->inner.list.render_header_fn = render_header; return true; } void gui_list_container_render(gui_t *gui, container_t *container) { renderer_translate(gui->renderer, container->x, container->y); renderer_set_draw_area(gui->renderer, container->width, container->height); list_container_t list = container->inner.list; if (list.scroll_x < 0) { list.scroll_x = 0; } if (list.scroll_y < 0) { list.scroll_y = 0; } container->inner.list = list; uint16_t item_height = list.item_height; uint16_t item_full_height = item_height + list.item_padding * 2; int32_t first_index = list.scroll_y / item_full_height; if (first_index < 0) { first_index = 0; } uint32_t items_count = gui->size.y / item_full_height + 1; uint32_t end_index = first_index + items_count; int32_t beg_x = -list.scroll_x; int32_t beg_y = -list.scroll_y + first_index * item_full_height; uint32_t selected_index = gui_list_get_selected_index(container); if (list.render_header_fn && list.render_header_fn(list.state, 0, gui->renderer, beg_x + list.item_padding, 0 + list.item_padding, WHITE_PIXEL)) { // if header was rendered, translate initial position renderer_translate(gui->renderer, 0, item_full_height); renderer_set_draw_area(gui->renderer, container->width, container->height - item_full_height); } for (uint32_t i = first_index; i < end_index && i < list.items_count; i++) { int32_t y = beg_y + (i - first_index) * item_full_height; display_pixel_t fgcolor = list.regular_foreground; display_pixel_t bgcolor = list.regular_background; if (selected_index == i) { fgcolor = list.selected_foreground; bgcolor = list.selected_background; } renderer_render_rectangle(gui->renderer, beg_x, y, 10000, item_full_height, bgcolor); list.render_item_fn(list.state, i, gui->renderer, beg_x + list.item_padding, y + list.item_padding, fgcolor); } } uint32_t gui_list_get_selected_index(container_t *container) { return container->inner.list.selected_index; } void gui_list_set_selected_index(container_t *container, uint32_t index) { if (index >= container->inner.list.items_count) { index = container->inner.list.items_count - 1; } container->inner.list.selected_index = index; } uint32_t gui_list_get_items_count(container_t *container) { return container->inner.list.items_count; } uint32_t gui_list_get_visible_items_count(container_t *container) { list_container_t list = container->inner.list; uint16_t item_full_height = list.item_height + list.item_padding * 2; uint32_t container_height = container->height; bool header = list.render_header_fn != NULL; if (header) { container_height -= item_full_height; } return (double)(container_height) / item_full_height - 1; } void gui_list_container_update(gui_t *gui, container_t *container) { list_container_t list = container->inner.list; if (list.selected_index == UINT32_MAX) { list.selected_index = 0; } else if (list.selected_index > list.items_count - 1) { list.selected_index = list.items_count - 1; } uint16_t item_full_height = list.item_height + list.item_padding * 2; int32_t first_visible_index = list.scroll_y / item_full_height; if (first_visible_index < 0) { first_visible_index = 0; } uint32_t items_count = gui_list_get_visible_items_count(container); uint32_t selected_index = list.selected_index; uint32_t last_scroll = (selected_index - items_count) * item_full_height; uint32_t first_scroll = selected_index * item_full_height; if (list.scroll_y > first_scroll) { list.scroll_y = first_scroll; } else if (list.scroll_y < last_scroll) { list.scroll_y = last_scroll; } container->inner.list = list; }