~ruther/CTU-FEE-B0B35APO-Semestral-project

91a6432c83e495f7b4d352dd0a70d0a3a02c8190 — František Boháček 3 years ago 7fcd884
refactor: split textviewer to more functions and files
M text-viewer/include/text_viewer.h => text-viewer/include/text_viewer.h +1 -22
@@ 4,28 4,7 @@
#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;
#include "text_viewer_loader.h"

/**
 * @brief Create text viewer struct

A text-viewer/include/text_viewer_handlers.h => text-viewer/include/text_viewer_handlers.h +8 -0
@@ 0,0 1,8 @@
#ifndef __TEXT_VIEWER_HANDLERS_H__
#define __TEXT_VIEWER_HANDLERS_H__

#include "gui.h"

void gui_text_view_register_commands(gui_t *gui, component_t *text_view);

#endif // __TEXT_VIEWER_HANDLERS_H__

A text-viewer/include/text_viewer_loader.h => text-viewer/include/text_viewer_loader.h +32 -0
@@ 0,0 1,32 @@
#ifndef __TEXT_VIEWER_LOADER_H__
#define __TEXT_VIEWER_LOADER_H__

#include "mzapo_pheripherals.h"
#include "gui.h"
#include "gui_component_text_view.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;

file_error_t text_viewer_load_file(text_viewer_t *text_viewer);

#endif // __TEXT_VIEWER_LOADER_H__

M text-viewer/src/main.c => text-viewer/src/main.c +44 -39
@@ 21,44 21,14 @@ typedef enum {
  ERROR_PHERIPHERALS,
} error_t;

int main(int argc, char *argv[]) {
  #ifdef COMPUTER
  mzapo_sdl_init();
  #endif
error_t text_viewer_start(logger_t *logger, char* file_name, mzapo_rgb_led_t rgb_leds) {
  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);
    }
  }

  mzapo_rgb_led_t rgb_leds = mzapo_create_rgb_led();
  rgb_led_clear(&rgb_leds, LED_LEFT);
  rgb_led_clear(&rgb_leds, LED_RIGHT);

  if (argc < 2) {
    logger_error(&logger, __FILE__, __FUNCTION__, __LINE__, "Not enough arguments");
    rgb_led_set_red(&rgb_leds, LED_LEFT);
    return ERROR_NOT_ENOUGH_ARGUMENTS;
  }

  display_t display = mzapo_create_display();
  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.");
    logger_error(logger, __FILE__, __FUNCTION__, __LINE__, "Could not initialize some of the pheripherals.");
    rgb_led_set_red(&rgb_leds, LED_LEFT);
    return ERROR_PHERIPHERALS;
  }


@@ 69,28 39,63 @@ int main(int argc, char *argv[]) {
  font.size = 20;
  font.char_spacing = 2;

  text_viewer_t text_viewer = text_viewer_create(argv[1], pheripherals, &logger, font);
  text_viewer_t text_viewer = text_viewer_create(file_name, pheripherals, logger, font);

  logger_info(&logger, __FILE__, __FUNCTION__, __LINE__,
  logger_info(logger, __FILE__, __FUNCTION__, __LINE__,
              "Loading file");
  file_error_t error = text_viewer_load_file(&text_viewer);
  if (error != FILER_SUCCESS) {
    file_error_log(&logger, error);
    file_error_log(logger, error);
    rgb_led_set_red(&rgb_leds, LED_RIGHT);
    return ERROR_CANT_OPEN_FILE;
  }

  file_set_nonblocking(STDIN_FILENO, &oldstdin);
  logger_info(&logger, __FILE__, __FUNCTION__, __LINE__,
  logger_info(logger, __FILE__, __FUNCTION__, __LINE__,
              "Starting text viewer");
  text_viewer_start_loop(&text_viewer);
  logger_info(&logger, __FILE__, __FUNCTION__, __LINE__,
  logger_info(logger, __FILE__, __FUNCTION__, __LINE__,
              "Closing application");

  text_viewer_destroy(&text_viewer);
  display_deinit(&display);
  mzapo_pheripherals_clear(&pheripherals);

  file_set_blocking(STDIN_FILENO, &oldstdin);
  return ERROR_SUCCESS;
}

int main(int argc, char *argv[]) {
  #ifdef COMPUTER
  mzapo_sdl_init();
  #endif

  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);
    }
  }

  mzapo_rgb_led_t rgb_leds = mzapo_create_rgb_led();
  rgb_led_clear(&rgb_leds, LED_LEFT);
  rgb_led_clear(&rgb_leds, LED_RIGHT);

  if (argc < 2) {
    logger_error(&logger, __FILE__, __FUNCTION__, __LINE__, "Not enough arguments");
    rgb_led_set_red(&rgb_leds, LED_LEFT);
    return ERROR_NOT_ENOUGH_ARGUMENTS;
  }

  error_t rerror = text_viewer_start(&logger, argv[1], rgb_leds);

  serialize_unlock();
  


@@ 100,5 105,5 @@ int main(int argc, char *argv[]) {
#ifdef COMPUTER
  mzapo_sdl_deinit();
#endif
  return ERROR_SUCCESS;
  return rerror;
}

M text-viewer/src/text_viewer.c => text-viewer/src/text_viewer.c +1 -174
@@ 1,6 1,7 @@
#include "text_viewer.h"
#include "direction.h"
#include "display_utils.h"
#include "text_viewer_handlers.h"
#include "gui.h"
#include "gui_component_line.h"
#include "gui_component_text.h"


@@ 44,79 45,6 @@ void text_viewer_destroy(text_viewer_t *text_viewer) {
  }
}

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 + 2));
  data[fsize - 1] = '\0';
  data[fsize] = '\0';
  data[fsize + 1] = '\0';

  if (data == NULL) {
    return FILER_UNKNOWN;
  }

  long read = 0;
  const int perc = 5;
  const int iters = 100 / perc;
  for (int i = 0; i < iters; i++) {
    long to_read = fsize / iters;
    if (to_read == 0) {
      i = iters - 1;
    }

    if (i == iters - 1) {
      to_read = fsize - read - 1;
    }

    if (to_read == 0 || fsize == read) {
      break;
    }

    long result = fread(data + read, sizeof(char), to_read, file);
    read += result;

    if (result != to_read) {
      fclose(file);
      return FILER_CANNOT_READ;
    }

    ledstrip_progress_bar_step(text_viewer->pheripherals.ledstrip, i * perc);
  }

  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;

  ledstrip_clear(text_viewer->pheripherals.ledstrip);
  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,


@@ 180,70 108,6 @@ static component_t *text_viewer_gui_add_text_view(text_viewer_t *text_viewer,
  return gui_one_container_set_component(view_container, text_view);
}

static void command_handler_move(void *state, direction_t direction,
                                 int amount) {
  component_t *text_view = (component_t *)state;
  if (text_view->focused) {
    int32_t x = 0;
    int32_t y = 0;
    direction_move_xy(direction, &x, &y, amount);
    gui_text_view_scroll(text_view, x, y);
  }
}

static void command_handler_move_down(void *state, int amount) {
  command_handler_move(state, DOWN, amount);
}

static void command_handler_move_up(void *state, int amount) {
  command_handler_move(state, UP, amount);
}

static void command_handler_move_left(void *state, int amount) {
  command_handler_move(state, LEFT, amount);
}
static void command_handler_move_right(void *state, int amount) {
  command_handler_move(state, RIGHT, amount);
}

static void command_handler_reset(void *state, int amount) {
  gui_text_view_reset_scroll((component_t *)state);
}

static void command_handler_full_scroll(void *state, int amount) {
  gui_text_view_full_scroll((component_t *)state);
}

static void command_handler_zoom_in(void *state, int amount) {
  component_t *component = (component_t *)state;
  multiline_text_t* text = (multiline_text_t*) (component)->state;
  uint16_t old_size = text->font->size;

  amount = amount > 1 ? 1 : -1;
  text->font->size += amount;
  if (text->font->size == 0) {
    text->font->size = 1;
  }

  component->y += amount * (component->y / (old_size + text->font->line_spacing));
}

static void command_handler_zoom_out(void *state, int amount) {
  command_handler_zoom_in(state, -amount);
}

static void command_handler_zoom_reset(void *state, int amount) {
  component_t *component = (component_t *)state;
  multiline_text_t *text = (multiline_text_t *)(component)->state;
  uint16_t old_size = text->font->size;
  text->font->size = text->font->font.height;


  amount = text->font->size - old_size;
  component->y +=
      amount * (component->y / (old_size + text->font->line_spacing));
}

component_t gui_text_view_create(gui_t *gui, multiline_text_t *text, int16_t x,
                                 int16_t y) {
  component_t text_view = gui_component_create(x, y, 1, 1, gui_text_view_render,


@@ 254,43 118,6 @@ component_t gui_text_view_create(gui_t *gui, multiline_text_t *text, int16_t x,
  return text_view;
}

void gui_text_view_register_commands(gui_t *gui, component_t *text_view) {
  commands_register(gui->commands, IN_KEYBOARD, KEYBOARD_LEFT,
                    command_handler_move_left, text_view);
  commands_register(gui->commands, IN_KEYBOARD, KEYBOARD_RIGHT,
                    command_handler_move_right, text_view);
  commands_register(gui->commands, IN_KEYBOARD, KEYBOARD_DOWN,
                    command_handler_move_down, text_view);
  commands_register(gui->commands, IN_KEYBOARD, KEYBOARD_UP,
                    command_handler_move_up, text_view);
  commands_register(gui->commands, IN_KEYBOARD, 'r', command_handler_reset,
                    text_view);
  commands_register(gui->commands, IN_KEYBOARD, 't',
                    command_handler_full_scroll, text_view);
  commands_register(gui->commands, IN_KEYBOARD, 'f',
                    command_handler_zoom_reset, text_view);

  commands_register(gui->commands, IN_ENCODER_ROTATE,
                    ROTATION_ENCODER_HORIZONTAL, command_handler_move_right,
                    text_view);

  commands_register(gui->commands, IN_KEYBOARD, KEYBOARD_ZOOM_IN,
                    command_handler_zoom_in, text_view);
  commands_register(gui->commands, IN_KEYBOARD, KEYBOARD_ZOOM_OUT,
                    command_handler_zoom_out, text_view);

  commands_register(gui->commands, IN_ENCODER_ROTATE, ROTATION_ENCODER_ZOOM,
                    command_handler_zoom_in, text_view);

  commands_register(gui->commands, IN_ENCODER_ROTATE, ROTATION_ENCODER_VERTICAL,
                    command_handler_move_down, text_view);

  commands_register(gui->commands, IN_ENCODER_CLICK, ROTATION_ENCODER_VERTICAL,
                    command_handler_reset, text_view);
  commands_register(gui->commands, IN_ENCODER_CLICK, ROTATION_ENCODER_ZOOM,
                    command_handler_full_scroll, text_view);
}

void text_viewer_start_loop(text_viewer_t *text_viewer) {
  command_t command_arr[20];
  commands_t commands =

A text-viewer/src/text_viewer_handlers.c => text-viewer/src/text_viewer_handlers.c +106 -0
@@ 0,0 1,106 @@
#include "text_viewer_handlers.h"
#include "direction.h"
#include "gui_component_text_view.h"
#include "keyboard_const.h"
#include "rotation_const.h"

static void command_handler_move(void *state, direction_t direction,
                                 int amount) {
  component_t *text_view = (component_t *)state;
  if (text_view->focused) {
    int32_t x = 0;
    int32_t y = 0;
    direction_move_xy(direction, &x, &y, amount);
    gui_text_view_scroll(text_view, x, y);
  }
}

static void command_handler_move_down(void *state, int amount) {
  command_handler_move(state, DOWN, amount);
}

static void command_handler_move_up(void *state, int amount) {
  command_handler_move(state, UP, amount);
}

static void command_handler_move_left(void *state, int amount) {
  command_handler_move(state, LEFT, amount);
}
static void command_handler_move_right(void *state, int amount) {
  command_handler_move(state, RIGHT, amount);
}

static void command_handler_reset(void *state, int amount) {
  gui_text_view_reset_scroll((component_t *)state);
}

static void command_handler_full_scroll(void *state, int amount) {
  gui_text_view_full_scroll((component_t *)state);
}

static void command_handler_zoom_in(void *state, int amount) {
  component_t *component = (component_t *)state;
  multiline_text_t* text = (multiline_text_t*) (component)->state;
  uint16_t old_size = text->font->size;

  amount = amount > 1 ? 1 : -1;
  text->font->size += amount;
  if (text->font->size == 0) {
    text->font->size = 1;
  }

  component->y += amount * (component->y / (old_size + text->font->line_spacing));
}

static void command_handler_zoom_out(void *state, int amount) {
  command_handler_zoom_in(state, -amount);
}

static void command_handler_zoom_reset(void *state, int amount) {
  component_t *component = (component_t *)state;
  multiline_text_t *text = (multiline_text_t *)(component)->state;
  uint16_t old_size = text->font->size;
  text->font->size = text->font->font.height;


  amount = text->font->size - old_size;
  component->y +=
      amount * (component->y / (old_size + text->font->line_spacing));
}

void gui_text_view_register_commands(gui_t *gui, component_t *text_view) {
  commands_register(gui->commands, IN_KEYBOARD, KEYBOARD_LEFT,
                    command_handler_move_left, text_view);
  commands_register(gui->commands, IN_KEYBOARD, KEYBOARD_RIGHT,
                    command_handler_move_right, text_view);
  commands_register(gui->commands, IN_KEYBOARD, KEYBOARD_DOWN,
                    command_handler_move_down, text_view);
  commands_register(gui->commands, IN_KEYBOARD, KEYBOARD_UP,
                    command_handler_move_up, text_view);
  commands_register(gui->commands, IN_KEYBOARD, 'r', command_handler_reset,
                    text_view);
  commands_register(gui->commands, IN_KEYBOARD, 't',
                    command_handler_full_scroll, text_view);
  commands_register(gui->commands, IN_KEYBOARD, 'f',
                    command_handler_zoom_reset, text_view);

  commands_register(gui->commands, IN_ENCODER_ROTATE,
                    ROTATION_ENCODER_HORIZONTAL, command_handler_move_right,
                    text_view);

  commands_register(gui->commands, IN_KEYBOARD, KEYBOARD_ZOOM_IN,
                    command_handler_zoom_in, text_view);
  commands_register(gui->commands, IN_KEYBOARD, KEYBOARD_ZOOM_OUT,
                    command_handler_zoom_out, text_view);

  commands_register(gui->commands, IN_ENCODER_ROTATE, ROTATION_ENCODER_ZOOM,
                    command_handler_zoom_in, text_view);

  commands_register(gui->commands, IN_ENCODER_ROTATE, ROTATION_ENCODER_VERTICAL,
                    command_handler_move_down, text_view);

  commands_register(gui->commands, IN_ENCODER_CLICK, ROTATION_ENCODER_VERTICAL,
                    command_handler_reset, text_view);
  commands_register(gui->commands, IN_ENCODER_CLICK, ROTATION_ENCODER_ZOOM,
                    command_handler_full_scroll, text_view);
}

A text-viewer/src/text_viewer_loader.c => text-viewer/src/text_viewer_loader.c +77 -0
@@ 0,0 1,77 @@
#include "text_viewer_loader.h"
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

static 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 + 2));
  data[fsize - 1] = '\0';
  data[fsize] = '\0';
  data[fsize + 1] = '\0';

  if (data == NULL) {
    return FILER_UNKNOWN;
  }

  long read = 0;
  const int perc = 5;
  const int iters = 100 / perc;
  for (int i = 0; i < iters; i++) {
    long to_read = fsize / iters;
    if (to_read == 0) {
      i = iters - 1;
    }

    if (i == iters - 1) {
      to_read = fsize - read - 1;
    }

    if (to_read == 0 || fsize == read) {
      break;
    }

    long result = fread(data + read, sizeof(char), to_read, file);
    read += result;

    if (result != to_read) {
      fclose(file);
      return FILER_CANNOT_READ;
    }

    ledstrip_progress_bar_step(text_viewer->pheripherals.ledstrip, i * perc);
  }

  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;

  ledstrip_clear(text_viewer->pheripherals.ledstrip);
  return FILER_SUCCESS;
}

Do not follow this link