M file-browser/include/file_access.h => file-browser/include/file_access.h +5 -1
@@ 5,6 5,7 @@
#include <stdint.h>
#include <sys/types.h>
#include "file_execute.h"
+#include "logger.h"
typedef struct directory_t directory_t;
@@ 52,6 53,8 @@ typedef enum {
FILOPER_UNKNOWN,
} file_operation_error_t;
+extern const char *file_operation_error_strings[];
+
typedef struct {
bool error;
union {
@@ 156,9 159,10 @@ extern const fileaccess_t
extern const fileaccess_t
temp_file_access; // state is /tmp directory descriptor
-extern uint8_t fileaccess_connectors_count;
extern fileaccess_connector_t fileaccess_connectors[(FA_COUNT-1)*FA_COUNT];
+void fileaccess_log_error(logger_t *logger, file_operation_error_t error);
+
fileaccess_state_t fileaccess_init(const fileaccess_t *fileaccess, void *data);
bool fileaccess_deinit(fileaccess_state_t state);
A file-browser/include/window_browser.h => file-browser/include/window_browser.h +11 -0
@@ 0,0 1,11 @@
+#ifndef __WINDOW_BROWSER_H__
+#define __WINDOW_BROWSER_H__
+
+#include "gui.h"
+#include <stdbool.h>
+#include "file_access.h"
+
+bool window_browser_open_local(gui_t *gui, font_t *font);
+bool window_browser_open(gui_t *gui, font_t *font, fileaccess_state_t state);
+
+#endif // __WINDOW_BROWSER_H__
M file-browser/src/file_access.c => file-browser/src/file_access.c +24 -1
@@ 1,8 1,31 @@
#include "file_access.h"
+#include "logger.h"
#include <string.h>
#include <errno.h>
+/*
+ FILOPER_SUCCESS,
+ FILOPER_PERMISSIONS,
+ FILOPER_DOES_NOT_EXIST,
+ FILOPER_USED,
+ FILOPER_ALREADY_EXISTS,
+ FILOPER_NOT_ENOUGH_SPACE,
+ FILOPER_UNKNOWN,
+ */
-uint8_t connectors_count = 1;
+const char *file_operation_error_strings[] = {
+ "Success",
+ "No permissions",
+ "No such file or directory",
+ "File is in use",
+ "File already exists",
+ "Not enough space on device",
+ "Unknown error",
+};
+
+void fileaccess_log_error(logger_t *logger, file_operation_error_t error) {
+ logger_error(logger, __FILE__, __FUNCTION__, __LINE__,
+ "File operation error: %s", file_operation_error_strings[error]);
+}
fileaccess_state_t fileaccess_init(const fileaccess_t *fileaccess, void *data) {
return fileaccess->init(data);
M file-browser/src/gui_list_commands.c => file-browser/src/gui_list_commands.c +2 -0
@@ 56,6 56,8 @@ static void command_handler_move_up(void *state, int amount) {
void gui_list_commands_register(commands_t *commands, gui_list_command_state_t *state) {
commands_register(commands, IN_KEYBOARD, 13, command_handler_gui_list_clicked, state);
+ commands_register(commands, IN_KEYBOARD, 'v', command_handler_gui_list_clicked,
+ state);
commands_register(commands, IN_KEYBOARD, KEYBOARD_DOWN,
command_handler_move_down, state);
M file-browser/src/local_file_access.c => file-browser/src/local_file_access.c +45 -31
@@ 23,18 23,28 @@ bool local_fileaccess_deinit_state(fileaccess_state_t data) {
return true;
}
-static file_operation_error_t file_get_information(void **malloced,
- uint64_t *offset, uint64_t *bytes_malloced,
+static uint64_t directory_get_needed_bytes(char *name, uint32_t *dirs_count, DIR *dirptr) {
+ uint64_t size = sizeof(directory_t) + strlen(name) + 1;
+
+ struct dirent *dir;
+ errno = 0;
+ *dirs_count = 0;
+ while ((dir = readdir(dirptr)) != NULL) {
+ size += sizeof(file_t);
+ size += strlen(dir->d_name) + 1;
+ (*dirs_count)++;
+ }
+
+ rewinddir(dirptr);
+ return size;
+}
+
+static file_operation_error_t file_get_information(void *malloced,
+ uint64_t *file_offset,
+ uint64_t *names_offset,
fileaccess_state_t state,
file_t file) {
size_t name_len = strlen(file.name);
- bytes_malloced += sizeof(file_t) + name_len + 1;
- void *new = realloc(*malloced, *bytes_malloced);
- if (new == NULL) {
- free(*malloced);
- return FILOPER_UNKNOWN;
- }
- *malloced = new;
char full_path[file_get_full_path_memory_size(state, file.directory, &file)];
file_get_full_path(state, file.directory, &file, full_path);
@@ 44,8 54,8 @@ static file_operation_error_t file_get_information(void **malloced,
int status = stat(full_path, &stats);
if (status == -1) {
- free(new);
- return file_operation_error_from_errno(errno);
+ //free(new);
+ //return file_operation_error_from_errno(errno);
}
file.size = stats.st_size;
@@ 53,13 63,13 @@ static file_operation_error_t file_get_information(void **malloced,
file.uid = stats.st_uid;
file.permissions = stats.st_mode;
- file_t *stored = new + *offset;
+ file_t *stored = malloced + *file_offset;
*stored = file;
- *offset += sizeof(file_t);
+ *file_offset += sizeof(file_t);
- strcpy(new + *offset, file.name);
- stored->name = new + *offset;
- *offset += name_len + 1;
+ strcpy(malloced + *names_offset, file.name);
+ stored->name = malloced + *names_offset;
+ *names_offset += name_len + 1;
return FILOPER_SUCCESS;
}
@@ 70,9 80,18 @@ directory_or_error_t local_fileaccess_directory_list(fileaccess_state_t state,
char full_path[path_join_memory_size(state.payload.local.path, path)];
path_join((char *)state.payload.local.path, path, full_path);
- uint64_t malloc_offset = sizeof(directory_t) + strlen(path) + 1;
- uint64_t bytes_malloced = sizeof(directory_t) + strlen(path) + 1;
- directory_t *directory = malloc(malloc_offset);
+ DIR *dirptr = opendir(full_path);
+ if (dirptr == NULL) {
+ ret.error = true;
+ ret.payload.error = file_operation_error_from_errno(errno);
+ return ret;
+ }
+
+ uint32_t files_count = 0;
+ uint64_t size = directory_get_needed_bytes(path, &files_count, dirptr);
+ uint64_t files_offset = sizeof(directory_t) + strlen(path) + 1;
+ uint64_t names_offset = files_count * sizeof(file_t) + files_offset;
+ directory_t *directory = malloc(size);
void *malloced = directory;
if (directory == NULL) {
@@ 82,17 101,10 @@ directory_or_error_t local_fileaccess_directory_list(fileaccess_state_t state,
}
directory->path = malloced + sizeof(directory_t);
+ directory->files = malloced + files_offset;
+ directory->files_count = 0;
strcpy(directory->path, path);
-
- DIR *dirptr = opendir(full_path);
- if (dirptr == NULL) {
- ret.error = true;
- ret.payload.error = file_operation_error_from_errno(errno);
- free(malloced);
- return ret;
- }
-
struct dirent * dir;
errno = 0;
while ((dir = readdir(dirptr)) != NULL) {
@@ 115,17 127,19 @@ directory_or_error_t local_fileaccess_directory_list(fileaccess_state_t state,
break;
}
- ret.payload.error = file_get_information(&malloced, &malloc_offset,
- &bytes_malloced, state, file);
+ ret.payload.error = file_get_information(malloced, &files_offset,
+ &names_offset, state, file);
+ errno = 0;
if (ret.payload.error != FILOPER_SUCCESS) {
ret.error = true;
- free(malloced);
return ret;
}
directory->files_count++;
}
+ closedir(dirptr);
+
if (errno != 0) {
ret.error = true;
ret.payload.error = file_operation_error_from_errno(errno);
M file-browser/src/local_file_utils.c => file-browser/src/local_file_utils.c +5 -1
@@ 10,7 10,11 @@
static int nfw_callback(const char *fpath, const struct stat *sb, int typeflag);
size_t file_get_full_path_memory_size(fileaccess_state_t state, directory_t *directory, file_t *file) {
- return strlen(file->name) + strlen(state.payload.local.path) + strlen(file->name) + 3;
+ size_t root = strlen(state.payload.local.path);
+ size_t dir = strlen(directory->path);
+ size_t file_name = strlen(file->name);
+
+ return root + 1 + dir + 1 + file_name + 1;
}
bool file_get_full_path(fileaccess_state_t state,
A file-browser/src/window_browser.c => file-browser/src/window_browser.c +181 -0
@@ 0,0 1,181 @@
+#include "window_browser.h"
+#include "display_utils.h"
+#include "file_access.h"
+#include "gui.h"
+#include "gui_component_text.h"
+#include "gui_container_info.h"
+#include "gui_list_commands.h"
+#include "gui_component_line.h"
+#include "gui_window_info.h"
+#include "input.h"
+#include "logger.h"
+#include "renderer.h"
+
+typedef struct {
+ bool running;
+ gui_t *gui;
+
+ container_t *list_container;
+ window_t *browser_window;
+
+ font_t *font;
+
+ gui_list_command_state_t click_state;
+ text_t text_state;
+
+ directory_t *current_directory;
+ fileaccess_state_t state;
+} browser_window_state_t;
+
+static bool browser_window_list_render_item(void *state, uint32_t index,
+ renderer_t *renderer, int16_t beg_x,
+ int16_t beg_y,
+ display_pixel_t color);
+
+static bool browser_window_list_render_header(void *state, uint32_t index,
+ renderer_t *renderer,
+ int16_t beg_x, int16_t beg_y,
+ display_pixel_t color);
+
+static void browser_window_item_clicked(container_t *container, void *state,
+ uint32_t selected_index);
+
+static void *browser_window_construct(window_t *window, void *state);
+static bool browser_window_running(void *state);
+static void browser_window_job(void *state);
+
+gui_container_info_t window_browser_containers[] = {
+ {.type = CONT_TABLE,
+ .payload.list = {.render_item_fn = browser_window_list_render_item,
+ .render_header_fn = browser_window_list_render_header,
+ .item_height = 16}},
+ {.type = CONT_GROUP, .payload.group.components_count = 2},
+};
+
+window_info_t window_browser_info = {
+ .construct = browser_window_construct,
+ .containers_count = 2,
+ .containers = window_browser_containers,
+};
+
+bool window_browser_open_local(gui_t *gui, font_t *font) {
+ fileaccess_state_t state = fileaccess_init(&local_file_access, NULL);
+ return window_browser_open(gui, font, state);
+}
+
+bool window_browser_open(gui_t *gui, font_t *font, fileaccess_state_t state) {
+ directory_or_error_t root = fileaccess_root_list(state);
+
+ if (root.error) {
+ fileaccess_log_error(gui->logger, root.error);
+ // TODO: dialog
+ return false;
+ }
+
+ browser_window_state_t bstate = {
+ .state = state,
+ .gui = gui,
+ .font = font,
+ .current_directory = root.payload.directory,
+ .running = true,
+ };
+
+ uint16_t commands_state = commands_save_state(gui->commands);
+ gui_window_init_and_loop(gui, &bstate, window_browser_info, browser_window_running,
+ browser_window_job);
+ commands_restore_state(gui->commands, commands_state);
+
+ return true;
+}
+
+static void command_handler_exit(void *state, int amount) {
+ browser_window_state_t *bstate = (browser_window_state_t *)state;
+ if (bstate->gui->active_window == bstate->browser_window) {
+ bstate->running = false;
+ }
+}
+
+static void *browser_window_construct(window_t *window, void *state) {
+ browser_window_state_t *bstate = (browser_window_state_t *)state;
+ logger_t *logger = bstate->gui->logger;
+ logger_info(logger, __FILE__, __FUNCTION__, __LINE__,
+ "Constructing browser window");
+ bstate->list_container = &window->containers[0];
+ bstate->browser_window = window;
+
+ bstate->click_state.container = bstate->list_container;
+ bstate->click_state.state = state;
+ bstate->click_state.clicked = browser_window_item_clicked;
+ bstate->click_state.font = bstate->font;
+ bstate->click_state.gui = bstate->gui;
+ bstate->click_state.window = window;
+
+ bstate->text_state.font = bstate->font;
+ bstate->text_state.line = bstate->current_directory->path;
+ bstate->text_state.color = WHITE_PIXEL;
+
+ // containers init
+ // group components init
+ component_t path_text = gui_text_create(&bstate->text_state, 3, 3, 0, 0);
+ component_t line_component = gui_line_create(&WHITE_PIXEL, 0, path_text.height + path_text.y + 3, 1000, 1);
+
+ gui_group_container_add_component(&window->containers[1], path_text);
+ gui_group_container_add_component(&window->containers[1], line_component);
+
+ // list init
+ gui_container_info_init(bstate->list_container, bstate,
+ bstate->current_directory->files_count, 5,
+ 5 + line_component.height + 5);
+ bstate->list_container->width = bstate->gui->size.x - 20;
+ bstate->list_container->height = bstate->gui->size.y - bstate->list_container->y - 20;
+
+ // commands register
+ gui_list_commands_register(bstate->gui->commands, &bstate->click_state);
+ commands_register(bstate->gui->commands, IN_KEYBOARD, 'e',
+ command_handler_exit, state);
+
+ return state;
+}
+
+static void browser_window_item_clicked(container_t *container, void *state,
+ uint32_t selected_index) {
+
+ browser_window_state_t *bstate = (browser_window_state_t *)state;
+ logger_t *logger = bstate->gui->logger;
+
+ logger_info(logger, __FILE__, __FUNCTION__, __LINE__, "Item was clicked.");
+}
+
+static bool browser_window_list_render_item(void *state, uint32_t index,
+ renderer_t *renderer, int16_t beg_x,
+ int16_t beg_y,
+ display_pixel_t color) {
+ browser_window_state_t *bstate = (browser_window_state_t *)state;
+ file_t file = bstate->current_directory->files[index];
+ renderer_write_string(renderer, beg_x, beg_y, 0, bstate->font, file.name,
+ color);
+ return true;
+}
+
+static bool browser_window_list_render_header(void *state, uint32_t index,
+ renderer_t *renderer,
+ int16_t beg_x, int16_t beg_y,
+ display_pixel_t color) {
+
+ browser_window_state_t *bstate = (browser_window_state_t *)state;
+ renderer_write_string(renderer, beg_x, beg_y, 0, bstate->font, "This is header", color);
+ return true;
+}
+
+static bool browser_window_running(void *state) {
+ browser_window_state_t *bstate = (browser_window_state_t*)state;
+ return bstate->running;
+}
+
+static void browser_window_job(void *state) {
+ browser_window_state_t *bstate = (browser_window_state_t *)state;
+ if (!bstate->running) {
+ // cleanup
+ fileaccess_directory_close(bstate->state, bstate->current_directory);
+ }
+}
M file-browser/src/window_initial.c => file-browser/src/window_initial.c +7 -1
@@ 9,6 9,7 @@
#include "input.h"
#include "logger.h"
#include "renderer.h"
+#include "window_browser.h"
#include <stdbool.h>
@@ 100,7 101,9 @@ static bool initial_window_list_render_item(void *state, uint32_t index,
static void command_handler_exit(void *state, int amount) {
initial_window_state_t *istate = (initial_window_state_t *)state;
- istate->running = false;
+ if (istate->gui->active_window == istate->initial_window) {
+ istate->running = false;
+ }
}
static void *initial_window_construct(window_t *window, void *state) {
@@ 140,6 143,8 @@ static void initial_window_job(void *state) {
(initial_window_state_t *)state;
initial_window_state->list_container->inner.list.scroll_x = 0;
+ gui_list_container_set_item_height(initial_window_state->list_container,
+ initial_window_state->font.size);
// do nothing?
}
@@ 156,6 161,7 @@ static void initial_window_item_clicked(container_t *container, void *state,
case INITIAL_WINDOW_LOCAL_INDEX:
logger_info(logger, __FILE__, __FUNCTION__, __LINE__,
"Clicked local root filesystem");
+ window_browser_open_local(istate->gui, &istate->font);
break;
case INITIAL_WINDOW_MOUNT_INDEX:
logger_info(logger, __FILE__, __FUNCTION__, __LINE__,
M lib-gui/src/gui_list_container.c => lib-gui/src/gui_list_container.c +34 -26
@@ 7,30 7,28 @@ container_t gui_list_container_create(void *state, uint32_t items_count,
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,
+ .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
- };
+ container_t container = {.focusable = true,
+ .focused = false,
+ .height = item_height * items_count,
+ .width = 0,
+ .inner.list = list,
+ .x = 0,
+ .y = 0};
return container;
}
@@ 57,7 55,8 @@ bool gui_list_container_set_item_height(container_t *container,
return true;
}
-bool gui_list_container_set_render_function(container_t *container, render_item render_it,
+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;
@@ 94,6 93,14 @@ void gui_list_container_render(gui_t *gui, container_t *container) {
uint32_t selected_index = gui_list_get_selected_index(container);
+ if (list.render_header_fn &&
+ list.render_header_fn(list.state, 0, gui->renderer, 0 + 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;
@@ 104,8 111,10 @@ void gui_list_container_render(gui_t *gui, container_t *container) {
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);
+ 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);
}
}
@@ 138,6 147,5 @@ void gui_list_container_update(gui_t *gui, container_t *container) {
list.scroll_y = (selected_index - items_count) * item_full_height;
}
-
container->inner.list = list;
}
M lib-gui/src/gui_window_info.c => lib-gui/src/gui_window_info.c +1 -0
@@ 1,6 1,7 @@
#include "gui_window_info.h"
#include "gui.h"
#include "gui_container_info.h"
+#include "logger.h"
bool gui_window_init_and_loop(gui_t *gui, void *state, window_info_t info,
gui_loop_running_fn loop_running,
M lib-pheripherals/src/nonblocking_io.c => lib-pheripherals/src/nonblocking_io.c +3 -1
@@ 35,7 35,9 @@ int file_set_nonblocking(int file, struct termios *old)
tcgetattr(file, old);
}
- cfmakeraw(&attrs);
+ attrs.c_lflag &= ~ICANON;
+ attrs.c_lflag &= ~ECHO;
+ //cfmakeraw(&attrs);
tcsetattr(file, TCSANOW, &attrs);
return 1;