M file-browser/include/extern_file_access.h => file-browser/include/extern_file_access.h +18 -1
@@ 3,7 3,24 @@
#include "file_access.h"
-fileaccess_state_t extern_fileaccess_init_state(void *data);
+/**
+ * @brief Initialize extern fileaccess state with given path to device
+ *
+ * @param data path to device
+ * @return fileaccess_state_t
+ */
+fileaccess_state_t extern_fileaccess_init_state(void *device);
+
+/**
+ * @brief Deinitialize extern fileaccess state
+ *
+ * All allocated memory for the state will be freed and
+ * associated device unmounted so it can be ejected
+ *
+ * @param state
+ * @return true Everything was cleaned
+ * @return false Could not clean everything
+ */
bool extern_fileaccess_deinit_state(fileaccess_state_t state);
directory_or_error_t extern_fileaccess_directory_list(fileaccess_state_t state,
M file-browser/include/file_execute.h => file-browser/include/file_execute.h +35 -5
@@ 1,17 1,47 @@
#include <unistd.h>
#include <stdbool.h>
+/**
+ * @brief This structure holds information about executing subprocess
+ *
+ */
typedef struct {
- pid_t pid;
- int output_signal;
- bool exited;
+ pid_t pid;/**< PID of the running process */
+ int output_signal;/**< Exit code of the process*/
+ bool exited;/**< Whether the process has ended */
} executing_file_t;
+/**
+ * @brief This structure holds error or executing subprocess
+ *
+ */
typedef struct {
- bool error;
- executing_file_t file;
+ bool error; /**< in case there was an error, this is true*/
+ executing_file_t file; /**< executing file if error is false*/
} executing_file_error_t;
+/**
+ * @brief Start executing given file
+ *
+ * @param path path to the executable
+ * @param args arguments to start the executable with
+ * @return executing_file_error_t with either error or process information set
+ */
executing_file_error_t executing_file_execute(char *path, char *args);
+
+/**
+ * @brief Wait for the process to exit
+ *
+ * @param file
+ * @return int exit code
+ */
int executing_file_wait(executing_file_t *file);
+
+/**
+ * @brief Check whether the process has ended and return immediatelly
+ *
+ * @param file
+ * @return true when the process has ended
+ * @return false when the process is still running
+ */
bool executing_file_has_ended(executing_file_t *file);
M lib-gui/include/gui.h => lib-gui/include/gui.h +66 -3
@@ 39,17 39,36 @@ typedef enum {
CONT_ONE,
} container_type_t;
-typedef bool (*render_item)(void *state, uint32_t index, renderer_t *renderer, int16_t beg_x, int16_t beg_y);
+/**
+ * @brief Summary
+ * @details Description
+ * @param[inout] state
+ * @param[in] index Index of the item to render
+ * @param[out] renderer
+ * @param[in] beg_x Begin x coordinate
+ * @param[in] beg_y Begin y coordinate
+ * @return Whether item was rendered
+ */
+typedef bool (*render_item)(void *state, uint32_t index, renderer_t *renderer, int16_t beg_x, int16_t beg_y, display_pixel_t foreground);
typedef struct {
void *state;
render_item render_item_fn;
render_item render_header_fn;
uint32_t items_count;
+ uint32_t selected_index;
uint16_t item_height;
- int16_t scroll_x;
- int16_t scroll_y;
+ int32_t scroll_x;
+ int32_t scroll_y;
+
+ display_pixel_t regular_foreground;
+ display_pixel_t regular_background;
+
+ display_pixel_t selected_foreground;
+ display_pixel_t selected_background;
+
+ uint16_t item_padding;
} list_container_t;
typedef struct {
@@ 310,16 329,60 @@ void gui_group_container_render(gui_t *gui, container_t *container);
void gui_group_container_update(gui_t *gui, container_t *container);
// list_container.c
+
+/**
+ * @brief Create list container
+ *
+ * @param[inout] state Custom state of items to pass to render function
+ * @param[in] items_count Count of items to show
+ * @param[in] item_height The height of item
+ * @param[in] render_it Function to render item
+ * @param[in] render_header Function to render header
+ * @return Container with list data
+ */
container_t gui_list_container_create(void *state, uint32_t items_count,
uint16_t item_height,
render_item render_it,
render_item render_header);
+/**
+ * @brief Get current selected index based on scroll
+ *
+ * @param[inout] container
+ * @return Current selected index
+ */
+uint32_t gui_list_get_selected_index(container_t *container);
+
+/**
+ * @brief Scroll list container by x, y
+ * @details Increase scroll coordinates by x, y so different view arrea is shown
+ * @param[inout] container
+ * @param[in] x x coordinate
+ * @param[in] y y coordinate
+ */
void gui_list_scroll(container_t *container, int16_t x, int16_t y);
+
+/**
+ * @brief List container set new state
+ *
+ * @param[inout] container
+ * @param[out] state Custom state of items
+ * @param[in] items_count The count of items
+ * @return Whether the state was set correctly
+ */
bool gui_list_container_set_state(container_t *container, void *state,
uint32_t items_count);
+
+/**
+ * @brief List container set new item height
+ *
+ * @param[inout] container
+ * @param[in] item_height The height of item
+ * @return Whether the item was set correctly
+ */
bool gui_list_container_set_item_height(container_t *container,
uint16_t item_height);
+
bool gui_list_container_set_render_function(container_t *container,
render_item render_it,
render_item render_header);
M lib-gui/src/gui_list_container.c => lib-gui/src/gui_list_container.c +61 -9
@@ 1,3 1,4 @@
+#include "display_utils.h"
#include "gui.h"
#include "renderer.h"
@@ 11,8 12,14 @@ container_t gui_list_container_create(void *state, uint32_t 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 = {
@@ 30,7 37,11 @@ container_t gui_list_container_create(void *state, uint32_t items_count,
void gui_list_scroll(container_t *container, int16_t x, int16_t y) {
container->inner.list.scroll_x += x;
- container->inner.list.scroll_y += y;
+ 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,
@@ 55,7 66,7 @@ bool gui_list_container_set_render_function(container_t *container, render_item
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, gui->size.x, gui->size.y);
+ renderer_set_draw_area(gui->renderer, container->width, container->height);
list_container_t list = container->inner.list;
if (list.scroll_x < 0) {
@@ 68,24 79,65 @@ void gui_list_container_render(gui_t *gui, container_t *container) {
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_height;
+ 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_height;
+
+ 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_height;
+ int32_t beg_y = -list.scroll_y + first_index * item_full_height;
+
+ uint32_t selected_index = gui_list_get_selected_index(container);
- for (int i = first_index; i < end_index; i++) {
- int32_t y = beg_y + i * item_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;
- list.render_item_fn(list.state, i, gui->renderer, beg_x, y);
+ if (selected_index == i) {
+ fgcolor = list.selected_foreground;
+ bgcolor = list.selected_background;
+ }
+
+ renderer_render_rectangle(gui->renderer, beg_x, y, 1000, 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_container_update(gui_t *gui, container_t *container) {
- // do nothing :)
+ 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 = container->height / item_full_height - 1;
+ uint32_t last_visible_index = first_visible_index + items_count;
+
+ uint32_t selected_index = list.selected_index;
+
+ if (selected_index < first_visible_index) {
+ list.scroll_y = selected_index * item_full_height;
+ } else if (selected_index > last_visible_index) {
+ list.scroll_y = (selected_index - items_count) * item_full_height;
+ }
+
+
+ container->inner.list = list;
}