From 8e259f037b5fe34ea491da713dcc5776fa98883c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Sun, 20 Jun 2021 21:19:34 +0200 Subject: [PATCH] feat: add text viewer main --- text-viewer/include/text_viewer.h | 39 +++++++ text-viewer/src/main.c | 81 ++++++++++++++ text-viewer/src/text_viewer.c | 179 ++++++++++++++++++++++++++++++ 3 files changed, 299 insertions(+) create mode 100644 text-viewer/include/text_viewer.h create mode 100644 text-viewer/src/main.c create mode 100644 text-viewer/src/text_viewer.c diff --git a/text-viewer/include/text_viewer.h b/text-viewer/include/text_viewer.h new file mode 100644 index 0000000000000000000000000000000000000000..4c5048f8dd7346a19630c24128e5dcd53bf09d25 --- /dev/null +++ b/text-viewer/include/text_viewer.h @@ -0,0 +1,39 @@ +#ifndef __TEXT_VIEWER_H__ +#define __TEXT_VIEWER_H__ + +#include "gui.h" +#include "gui_component_text_view.h" +#include "mzapo_pheripherals.h" + +typedef enum { + FILER_SUCCESS, + FILER_NOT_FOUND, + FILER_NO_PERMISSIONS, + FILER_FILE_CANT_OPEN, + FILER_CANNOT_READ, + FILER_UNKNOWN, +} file_error_t; + +typedef struct { + gui_t gui; + char *path; + + mzapo_pheripherals_t pheripherals; + multiline_text_t *multiline_text; + logger_t *logger; + + bool running; + + font_t font; +} text_viewer_t; + +text_viewer_t text_viewer_create(char *path, mzapo_pheripherals_t pheripherals, + logger_t *logger, font_t font); + +void text_viewer_destroy(text_viewer_t *text_viewer); + +file_error_t text_viewer_load_file(text_viewer_t *text_viewer); + +void text_viewer_start_loop(text_viewer_t *text_viewer); + +#endif // __TEXT_VIEWER_H__ diff --git a/text-viewer/src/main.c b/text-viewer/src/main.c new file mode 100644 index 0000000000000000000000000000000000000000..eb234095ddb05327b0dbfe248be8000b9554c6a1 --- /dev/null +++ b/text-viewer/src/main.c @@ -0,0 +1,81 @@ +#include "font.h" +#include "mzapo_led_strip.h" +#include "nonblocking_io.h" +#include "serialize_lock.h" +#include +#include +#include "logger.h" +#include "display_utils.h" +#include "mzapo_pheripherals.h" +#include "text_viewer.h" + +typedef enum { + SUCCESS, +} error_t; + +int main(int argc, char *argv[]) { + struct termios oldstdin; + + logger_t logger = + logger_create(LOG_DEBUG, stdout, stdout, stderr, stderr, NULL); + + /* Try to acquire lock the first */ + if (serialize_lock(1) <= 0) { + printf("System is occupied\n"); + logger_warn(&logger, __FILE__, __FUNCTION__, __LINE__, "System is occupied"); + + if (1) { + /* Wait till application holding lock releases IT or exits */ + logger_info(&logger, __FILE__, __FUNCTION__, __LINE__, + "Waiting"); + serialize_lock(0); + } + } + + if (argc < 2) { + logger_info(&logger, __FILE__, __FUNCTION__, __LINE__, "Not enough arguments"); + } + + display_t display = mzapo_create_display(); + mzapo_rgb_led_t rgb_leds = mzapo_create_rgb_led(); + mzapo_ledstrip_t ledstrip = mzapo_create_ledstrip(); + void* knobs = mzapo_get_knobs_address(); + + if (!mzapo_check_pheripherals(&ledstrip, &rgb_leds, &display, &knobs)) { + logger_error(&logger, __FILE__, __FUNCTION__, __LINE__, "Could not initialize some of the pheripherals."); + } + + mzapo_pheripherals_t pheripherals = mzapo_pheripherals_create(&ledstrip, &rgb_leds, &display, &knobs); + + font_t font = font_create(font_rom8x16); + font.char_spacing = 2; + + text_viewer_t text_viewer = text_viewer_create(argv[1], pheripherals, &logger, font); + + logger_info(&logger, __FILE__, __FUNCTION__, __LINE__, + "Loading file"); + file_error_t error = text_viewer_load_file(&text_viewer); + if (error != FILER_SUCCESS) { + logger_error(&logger, __FILE__, __FUNCTION__, __LINE__, "Could not load file."); + return 1; + } + + file_set_nonblocking(STDIN_FILENO, &oldstdin); + logger_info(&logger, __FILE__, __FUNCTION__, __LINE__, + "Starting text viewer"); + text_viewer_start_loop(&text_viewer); + logger_info(&logger, __FILE__, __FUNCTION__, __LINE__, + "Closing application"); + + text_viewer_destroy(&text_viewer); + display_deinit(&display); + + file_set_blocking(STDIN_FILENO, &oldstdin); + + serialize_unlock(); + + logger_info(&logger, __FILE__, __FUNCTION__, __LINE__, + "Application quit"); + + return SUCCESS; +} diff --git a/text-viewer/src/text_viewer.c b/text-viewer/src/text_viewer.c new file mode 100644 index 0000000000000000000000000000000000000000..e60ec047591c3081c5e794248c8beaef843f275e --- /dev/null +++ b/text-viewer/src/text_viewer.c @@ -0,0 +1,179 @@ +#include "text_viewer.h" +#include "display_utils.h" +#include "gui.h" +#include "gui_component_line.h" +#include "input.h" +#include "renderer.h" +#include +#include +#include +#include "gui_component_text.h" +#include "gui_component_text_view.h" +#include +#include + +text_viewer_t text_viewer_create(char *path, mzapo_pheripherals_t pheripherals, + logger_t *logger, font_t font) { + text_viewer_t text_viewer = { + .pheripherals = pheripherals, + .multiline_text = NULL, + .path = path, + .logger = logger, + .font = font + }; + + return text_viewer; +} + +void text_viewer_destroy(text_viewer_t *text_viewer) { + if (text_viewer->multiline_text != NULL && + text_viewer->multiline_text->text != NULL) { + free(text_viewer->multiline_text->text); + } +} + +file_error_t file_error_from_errno() { + switch (errno) { + case ENOENT: + return FILER_NOT_FOUND; + case EACCES: + return FILER_NO_PERMISSIONS; + default: + return FILER_FILE_CANT_OPEN; + } +} + +file_error_t text_viewer_load_file(text_viewer_t *text_viewer) { + FILE *file = fopen(text_viewer->path, "r"); + + if (file == NULL) { + return file_error_from_errno(); + } + + fseek(file, 0, SEEK_END); + long fsize = ftell(file); + fseek(file, 0, SEEK_SET); + + char *data = malloc(sizeof(char) * (fsize + 1)); + data[fsize] = '\0'; + if (data == NULL) { + return FILER_UNKNOWN; + } + + long result = fread(data, sizeof(char), fsize, file); + if (result != fsize) { + fclose(file); + return FILER_CANNOT_READ; + } + + fclose(file); + + multiline_text_t *text = gui_multiline_text_create(&text_viewer->font, WHITE_PIXEL, data); + if (text == NULL) { + return FILER_UNKNOWN; + } + + text_viewer->multiline_text = text; + + return FILER_SUCCESS; +} + +static void text_viewer_init_gui(text_viewer_t *text_viewer, + commands_t *commands, renderer_t *renderer) { + gui_t gui = gui_create(text_viewer->logger, commands, renderer, + &text_viewer->pheripherals); + + text_viewer->gui = gui; +} + +static void command_handle_exit(void *state, int amount) { + text_viewer_t *text_viewer = (text_viewer_t*)state; + text_viewer->running = false; +} + +static void text_viewer_register_commands(text_viewer_t *text_viewer, commands_t *commands) { + commands_register(commands, IN_KEYBOARD, 'e', command_handle_exit, + text_viewer); + commands_register(commands, IN_ENCODER_CLICK, 0, command_handle_exit, + text_viewer); +} + +static container_t *text_viewer_gui_add_name_and_line(text_viewer_t *text_viewer, window_t *window, text_t *name_text, component_t *name_and_line_components) { + container_t name_and_line = + gui_group_container_create(0, 0, name_and_line_components, 2); + + component_t name = gui_text_create(name_text, 5, 3, 0, 0); + component_t line = gui_line_create(&WHITE_PIXEL, 0, name.height + name.y, + text_viewer->gui.size.x, 1); + + gui_group_container_add_component(&name_and_line, name); + gui_group_container_add_component(&name_and_line, line); + + name_and_line.width = text_viewer->gui.size.x; + name_and_line.height = name.height + line.height + 3; + return gui_window_add_container(window, name_and_line); +} + +static container_t *text_viewer_gui_add_view_container(text_viewer_t *text_viewer, container_t *name_and_line, window_t *window) { + container_t text_view_container = + gui_one_container_create(0, name_and_line->y + name_and_line->height + 2); + + text_view_container.width = text_viewer->gui.size.x; + text_view_container.height = text_viewer->gui.size.y - name_and_line->height; + + text_view_container.focused = true; + return gui_window_add_container(window, text_view_container); +} + +static component_t *text_viewer_gui_add_text_view(text_viewer_t *text_viewer, container_t *view_container) { + component_t text_view = gui_text_view_create( + &text_viewer->gui, text_viewer->multiline_text, 0, 0); + + return gui_one_container_set_component(view_container, text_view); +} + +void text_viewer_start_loop(text_viewer_t *text_viewer) { + command_t command_arr[20]; + commands_t commands = + commands_create(command_arr, 20, *text_viewer->pheripherals.knobs); + renderer_t renderer = renderer_create(text_viewer->pheripherals.display); + + text_viewer_init_gui(text_viewer, &commands, &renderer); + + // window + container_t containers[2]; + window_t text_viewer_window = gui_window_create(containers, 2); + + // name and line + component_t name_and_line_components[2]; + text_t name_text = {.font = &text_viewer->font, + .line = basename(text_viewer->path), + .color = WHITE_PIXEL}; + container_t *name_and_line = text_viewer_gui_add_name_and_line( + text_viewer, &text_viewer_window, &name_text, name_and_line_components); + + // text viewer + container_t *text_view_container = text_viewer_gui_add_view_container( + text_viewer, name_and_line, &text_viewer_window); + component_t *text_view = + text_viewer_gui_add_text_view(text_viewer, text_view_container); + + gui_set_active_window(&text_viewer->gui, &text_viewer_window); + + gui_text_view_register_commands(&text_viewer->gui, + text_view); // TODO: rethink this design + + text_viewer_register_commands(text_viewer, &commands); + + // main loop + text_viewer->running = true; + while (text_viewer->running) { + commands_check_input(&commands); + + gui_update(&text_viewer->gui); + gui_render(&text_viewer->gui); + } + + renderer_clear(&renderer); + renderer_render(&renderer); +}