diff options
| author | A404M <ahmadmahmoudiprogrammer@gmail.com> | 2024-12-28 09:35:59 +0330 | 
|---|---|---|
| committer | A404M <ahmadmahmoudiprogrammer@gmail.com> | 2024-12-28 09:35:59 +0330 | 
| commit | 5a94037a19cee399d951b0e54937cffa82edecc2 (patch) | |
| tree | 39b2a9aa3002a28d30f9b98d8b1ca5123b88b87f | |
| parent | d7802371b56734446a16962363322282ba772257 (diff) | |
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 9 | ||||
| -rw-r--r-- | src/main.c | 67 | ||||
| -rw-r--r-- | src/ui/tui.c | 94 | ||||
| -rw-r--r-- | src/ui/tui.h | 40 | 
5 files changed, 125 insertions, 86 deletions
@@ -1,3 +1,4 @@  build/  .cache/  compile_commands.json +val.log* @@ -14,7 +14,9 @@ NC := \033[0m  INC_DIRS := $(SRC_DIR)  INC_FLAGS := $(addprefix -I,$(INC_DIRS)) -CFLAGS := $(INC_FLAGS) -Wall -Wextra -std=gnu23  +CFLAGS := $(INC_FLAGS) -Wall -Wextra -std=gnu23 -Ofast -march=native +# CFLAGS := $(INC_FLAGS) -Wall -Wextra -std=gnu23 -g +  EXEC_FILE := $(BUILD_DIR)/atui  all: $(EXEC_FILE) @@ -37,7 +39,10 @@ run: $(EXEC_FILE)  	$(EXEC_FILE) $(args)  val-run: $(EXEC_FILE) -	valgrind --leak-check=full --track-origins=yes --show-leak-kinds=all -s $(EXEC_FILE) $(args) +	valgrind --log-file="val.log" --leak-check=full --track-origins=yes --show-leak-kinds=all -s $(EXEC_FILE) $(args) + +gdb-run: $(EXEC_FILE) +	gdb $(EXEC_FILE) $(args)  # $@ = left hand of :  # $< = right hand of : first one of them @@ -13,11 +13,11 @@ constexpr COLOR COLOR_FPS_BACK = color_hex(0xFFCCCCCC);  constexpr COLOR COLOR_FPS_TEXT = color_hex(0xFF000000);  bool show_fps = true; -void on_click(MOUSE_ACTION) { show_fps = !show_fps; } +void on_click(MOUSE_ACTION, void *) { show_fps = !show_fps; }  char search[1000] = ""; -void on_search_text_add(char c) { +void on_search_text_add(char c, void *) {    if (c == '\n') {      // TODO: do something    } else if (c == '\b') { @@ -32,19 +32,20 @@ void on_search_text_add(char c) {  WIDGET *search_box() {    return tui_make_padding( -      tui_make_box(MAX_WIDTH, 1, -                   tui_make_center(tui_make_row(tui_make_widget_array( -                       tui_make_box(MAX_WIDTH, MAX_HEIGHT, -                                    tui_make_text_input( -                                        search, color_init(0xFFFFFFFF), -                                        TEXT_STYLE_NORMAL, on_search_text_add), -                                    color_init(0xFF42414D)), -                       tui_make_box(10, MAX_HEIGHT, -                                    tui_make_center(tui_make_text( -                                        "Search", color_init(0xFF000000), -                                        TEXT_STYLE_NORMAL)), -                                    color_init(0xFFC4C3C9))))), -                   COLOR_NO_COLOR), +      tui_make_box( +          MAX_WIDTH, 1, +          tui_make_center(tui_make_row(tui_make_widget_array( +              tui_make_box(MAX_WIDTH, MAX_HEIGHT, +                           tui_make_text_input(search, color_init(0xFFFFFFFF), +                                               TEXT_STYLE_NORMAL, +                                               on_search_text_add, NULL), +                           color_init(0xFF42414D)), +              tui_make_box( +                  10, MAX_HEIGHT, +                  tui_make_center(tui_make_text( +                      "Search", color_init(0xFF000000), TEXT_STYLE_NORMAL)), +                  color_init(0xFFC4C3C9))))), +          COLOR_NO_COLOR),        1, 1, 10, 10);  } @@ -52,20 +53,32 @@ bool selectedArray[] = {      false, false, false, false, false, false, false, false, false,      false, false, false, false, false, false, false, false,  }; +size_t selectedArray_size = sizeof(selectedArray) / sizeof(*selectedArray); -WIDGET *search_result(int index) { +void search_result_on_click(MOUSE_ACTION, void *data) { +  for (size_t i = 0; i < selectedArray_size; ++i) { +    selectedArray[i] = false; +  } +  selectedArray[(size_t)data] = true; +} + +WIDGET *search_result(size_t index) {    bool isSelected = selectedArray[index];    return tui_make_padding( -      tui_make_row(tui_make_widget_array( -          isSelected ? tui_make_box(1, 5, NULL, color_init(0xFF0000FF)) -                     : tui_make_box(0, 5, NULL, COLOR_NO_COLOR), -          isSelected ? tui_make_box(1, 0, NULL, COLOR_NO_COLOR) : NULL, -          tui_make_column(tui_make_widget_array( -              tui_make_text("https://something.something/", -                            color_init(0xFFE8E6E3), TEXT_STYLE_ITALIC), -              tui_make_text("Hello", color_init(0xFF7093E0), TEXT_STYLE_BOLD), -              tui_make_text("Hello this is somehing which can be seen", -                            color_init(0xFFE8E6E3), TEXT_STYLE_SHADOWED))))), +      tui_make_button( +          tui_make_row(tui_make_widget_array( +              isSelected ? tui_make_box(1, 5, NULL, color_init(0xFF0000FF)) +                         : tui_make_box(0, 5, NULL, COLOR_NO_COLOR), +              isSelected ? tui_make_box(1, 0, NULL, COLOR_NO_COLOR) : NULL, +              tui_make_column(tui_make_widget_array( +                  tui_make_text("https://something.something/", +                                color_init(0xFFE8E6E3), TEXT_STYLE_ITALIC), +                  tui_make_text("Hello", color_init(0xFF7093E0), +                                TEXT_STYLE_BOLD), +                  tui_make_text("Hello this is somehing which can be seen", +                                color_init(0xFFE8E6E3), +                                TEXT_STYLE_SHADOWED))))), +          search_result_on_click, (void *)index),        0, 1, 0, 0);  } @@ -92,7 +105,7 @@ WIDGET *fps_counter(uint64_t last_frame) {                                                        TEXT_STYLE_NORMAL),                                          0, 0, 1, 1),                         COLOR_FPS_BACK), -          on_click), +          on_click, NULL),        0, 0, 2, 2);  } diff --git a/src/ui/tui.c b/src/ui/tui.c index 835e228..0e6a936 100644 --- a/src/ui/tui.c +++ b/src/ui/tui.c @@ -21,7 +21,7 @@ const int MIN_HEIGHT = -2;  const int FRAME_UNLIMITED = 0; -void _tui_clear_cells(TUI *tui) { +void _tui_clear_cells(TUI *restrict tui) {    constexpr TERMINAL_CELL EMPTY_CELL = {        .c = ' ',        .color = COLOR_NO_COLOR, @@ -29,19 +29,20 @@ void _tui_clear_cells(TUI *tui) {        .style = TEXT_STYLE_NORMAL,        .on_action_callback.on_raw_input_callback = NULL,        .on_action_callback.metadata = NULL, +      .on_action_callback.data = NULL,    };    for (size_t i = 0; i < tui->cells_length; ++i) {      tui->cells[i] = EMPTY_CELL;    }  } -void _tui_init_cells(TUI *tui) { +void _tui_init_cells(TUI *restrict tui) {    tui->cells_length = tui_get_width(tui) * tui_get_height(tui);    tui->cells = malloc(tui->cells_length * sizeof(*tui->cells));    _tui_clear_cells(tui);  } -void _tui_delete_cells(TUI *tui) { +void _tui_delete_cells(TUI *restrict tui) {    tui->cells_length = 0;    free(tui->cells);    tui->cells = NULL; @@ -50,7 +51,7 @@ void _tui_delete_cells(TUI *tui) {  TUI *tui_init() {    setbuf(stdout, NULL); -  TUI *tui = malloc(sizeof(TUI)); +  TUI *restrict tui = malloc(sizeof(TUI));    constexpr TUI tui_clean = {        .cells = NULL, @@ -100,7 +101,7 @@ void tui_delete(TUI *restrict tui) {    free(tui);  } -void tui_refresh(TUI *tui) { +void tui_refresh(TUI *restrict tui) {    const int width = tui_get_width(tui);    const int height = tui_get_height(tui); @@ -112,9 +113,9 @@ void tui_refresh(TUI *tui) {    }  } -int tui_get_width(TUI *tui) { return tui->size.ws_col; } +uint16_t tui_get_width(TUI *restrict tui) { return tui->size.ws_col; } -int tui_get_height(TUI *tui) { return tui->size.ws_row; } +uint16_t tui_get_height(TUI *restrict tui) { return tui->size.ws_row; }  int tui_clear_screen() { return printf("\033[2J\r"); } @@ -130,7 +131,7 @@ int tui_save_cursor() { return printf("\0337"); }  int tui_restore_cursor() { return printf("\0338"); } -void tui_get_cursor_pos(TUI *tui, int *x, int *y) { +void tui_get_cursor_pos(TUI *restrict tui, int *x, int *y) {    char buf[8] = "";    char cmd[] = "\033[6n";    tcgetattr(0, &tui->raw); @@ -153,54 +154,56 @@ int tui_delete_before() { return printf("\b \b"); }  int tui_delete_under_cursor() { return printf(" \b"); } -int _tui_get_cell_index(TUI *tui, int x, int y) { -  const int width = tui_get_width(tui); -  return x + width * y; +size_t _tui_get_cell_index(TUI *restrict tui, size_t x, size_t y) { +  const size_t width = tui_get_width(tui); +  const size_t result = x + width * y; +  return result >= tui->cells_length?0:result; // in resizing it will overflow in some time  } -void _tui_set_cell_char(TUI *tui, int x, int y, char c) { +void _tui_set_cell_char(TUI *restrict tui, int x, int y, char c) {    tui->cells[_tui_get_cell_index(tui, x, y)].c = c;  } -void _tui_set_cell_color(TUI *tui, int x, int y, COLOR color) { +void _tui_set_cell_color(TUI *restrict tui, int x, int y, COLOR color) {    if (color_equals(color, COLOR_NO_COLOR)) {      return;    }    tui->cells[_tui_get_cell_index(tui, x, y)].color = color;  } -void _tui_set_cell_style(TUI *tui, int x, int y, TEXT_STYLE style) { +void _tui_set_cell_style(TUI *restrict tui, int x, int y, TEXT_STYLE style) {    tui->cells[_tui_get_cell_index(tui, x, y)].style = style;  } -void _tui_set_cell_background_color_if_not_set(TUI *tui, int x, int y, +void _tui_set_cell_background_color_if_not_set(TUI *restrict tui, int x, int y,                                                 COLOR background_color) {    if (color_equals(background_color, COLOR_NO_COLOR)) {      return;    } -  TERMINAL_CELL *cell = &tui->cells[_tui_get_cell_index(tui, x, y)]; +  TERMINAL_CELL *const cell = &tui->cells[_tui_get_cell_index(tui, x, y)];    if (color_equals(cell->background_color, COLOR_NO_COLOR)) {      cell->background_color = background_color;    }  } -void _tui_set_cell_on_action_callback(TUI *tui, int x, int y, +void _tui_set_cell_on_action_callback(TUI *restrict tui, int x, int y,                                        ON_ACTION_CALLBACK on_action_callback) {    tui->cells[_tui_get_cell_index(tui, x, y)].on_action_callback =        on_action_callback;  } -void tui_handle_input_action(TUI *tui, INPUT_ACTION input_action) { +void tui_handle_input_action(TUI *restrict tui, INPUT_ACTION input_action) {    const size_t index = _tui_get_cell_index(tui, input_action.x, input_action.y);    if (index < tui->cells_length) {      const ON_ACTION_CALLBACK callback = tui->cells[index].on_action_callback;      if (callback.on_raw_input_callback != NULL) { -      callback.on_raw_input_callback(input_action, callback.metadata); +      callback.on_raw_input_callback(input_action, callback.metadata, +                                     callback.data);      }    }  } -bool handle_input(TUI *tui) { +bool handle_input(TUI *restrict tui) {    unsigned char buff[6];    read(STDIN_FILENO, &buff, 1);    if (buff[0] == 3) {  // User pressd Ctr+C @@ -262,28 +265,30 @@ bool handle_input(TUI *tui) {    return false;  } -void tui_start_app(TUI *tui, WIDGET_BUILDER widget_builder, int fps) { +void tui_start_app(TUI *restrict tui, WIDGET_BUILDER widget_builder, int fps) {    tui_main_loop(tui, widget_builder, fps);  } -void _tui_on_button_click_handler(INPUT_ACTION input_action, void *metadata) { +void _tui_on_button_click_handler(INPUT_ACTION input_action, void *metadata, +                                  void *data) {    if (input_action.type == INPUT_TYPE_MOUSE) {      const MOUSE_ACTION mouse_action = {          .button = input_action.action.mouse_button,          .x = input_action.x,          .y = input_action.y,      }; -    ((ON_CLICK_CALLBACK)metadata)(mouse_action); +    ((ON_CLICK_CALLBACK)metadata)(mouse_action, data);    }  } -void _tui_on_text_input_handler(INPUT_ACTION input_action, void *metadata) { +void _tui_on_text_input_handler(INPUT_ACTION input_action, void *metadata, +                                void *data) {    if (input_action.type == INPUT_TYPE_KEYBOARD) { -    ((ON_TEXT_INPUT)metadata)(input_action.action.key); +    ((ON_TEXT_INPUT)metadata)(input_action.action.key, data);    }  } -void _tui_draw_text_to_cells(TUI *tui, const char *text, COLOR color, +void _tui_draw_text_to_cells(TUI *restrict tui, const char *text, COLOR color,                               TEXT_STYLE style, int width_begin, int width_end,                               int height_begin, int height_end, int *child_width,                               int *child_height) { @@ -322,9 +327,10 @@ END_OF_TEXT:    *child_width = max_width + 1;  } -void _tui_draw_widget_to_cells(TUI *tui, const WIDGET *widget, int width_begin, -                               int width_end, int height_begin, int height_end, -                               int *child_width, int *child_height) { +void _tui_draw_widget_to_cells(TUI *restrict tui, const WIDGET *widget, +                               int width_begin, int width_end, int height_begin, +                               int height_end, int *child_width, +                               int *child_height) {    if (widget == NULL) {      return;    } @@ -345,6 +351,7 @@ void _tui_draw_widget_to_cells(TUI *tui, const WIDGET *widget, int width_begin,          const ON_ACTION_CALLBACK on_action_callback = {              .on_raw_input_callback = _tui_on_button_click_handler,              .metadata = metadata->callback, +            .data = metadata->data,          };          for (int i = width_begin; i < *child_width; ++i) {            for (int j = height_begin; j < *child_height; ++j) { @@ -493,6 +500,7 @@ void _tui_draw_widget_to_cells(TUI *tui, const WIDGET *widget, int width_begin,        const ON_ACTION_CALLBACK on_action_callback = {            .on_raw_input_callback = _tui_on_text_input_handler,            .metadata = metadata->on_text_input, +          .data = metadata->data,        };        for (int i = width_begin; i < width_end; ++i) {          for (int j = height_begin; j < height_end; ++j) { @@ -724,7 +732,7 @@ int _tui_get_background_color_ascii(COLOR color) {  }  */ -void _tui_draw_cells_to_terminal(TUI *tui) { +void _tui_draw_cells_to_terminal(TUI *restrict tui) {    const size_t size_of_cell = 30;  // TODO: recalc    const size_t size = tui->cells_length * size_of_cell;    char str[(size + 2) * sizeof(char) + 1]; @@ -860,7 +868,7 @@ bool tui_widget_eqauls(const WIDGET *restrict left,    exit(1);  } -void tui_main_loop(TUI *tui, WIDGET_BUILDER widget_builder, int fps) { +void tui_main_loop(TUI *restrict tui, WIDGET_BUILDER widget_builder, int fps) {    const uint64_t frame_nano =        (fps == FRAME_UNLIMITED) ? 0 : NANO_TO_SECOND / fps;    int64_t last_remaining = 0; @@ -944,9 +952,11 @@ WIDGET *tui_make_text(char *restrict text, COLOR color, TEXT_STYLE style) {  TEXT_METADATA *_tui_make_text_metadata(char *restrict text, COLOR color,                                         TEXT_STYLE style) { -  TEXT_METADATA *metadata = malloc(sizeof(TEXT_METADATA)); -  metadata->text = malloc(strlen(text) + 1); -  strcpy(metadata->text, text); +  TEXT_METADATA *metadata = malloc(sizeof(*metadata)); +  const size_t text_len = strlen(text); +  metadata->text = malloc(text_len + 1); +  strncpy(metadata->text, text, text_len); +  metadata->text[text_len] = '\0';    metadata->color = color;    metadata->style = style;    return metadata; @@ -957,16 +967,19 @@ void _tui_delete_text(WIDGET *restrict text) {    free(text->metadata);  } -WIDGET *tui_make_button(WIDGET *restrict child, ON_CLICK_CALLBACK callback) { +WIDGET *tui_make_button(WIDGET *restrict child, ON_CLICK_CALLBACK callback, +                        void *data) {    return tui_new_widget(WIDGET_TYPE_BUTTON, -                        _tui_make_button_metadata(child, callback)); +                        _tui_make_button_metadata(child, callback, data));  }  BUTTON_METADATA *_tui_make_button_metadata(WIDGET *restrict child, -                                           ON_CLICK_CALLBACK callback) { +                                           ON_CLICK_CALLBACK callback, +                                           void *data) {    BUTTON_METADATA *metadata = malloc(sizeof(BUTTON_METADATA));    metadata->child = child;    metadata->callback = callback; +  metadata->data = data;    return metadata;  } @@ -1069,20 +1082,21 @@ void _tui_delete_padding(WIDGET *restrict padding) {  extern WIDGET *tui_make_text_input(char *restrict text, COLOR color,                                     TEXT_STYLE style, -                                   ON_TEXT_INPUT on_text_input) { +                                   ON_TEXT_INPUT on_text_input, void *data) {    return tui_new_widget(        WIDGET_TYPE_TEXT_INPUT, -      _tui_make_text_input_metadata(text, color, style, on_text_input)); +      _tui_make_text_input_metadata(text, color, style, on_text_input, data));  }  extern TEXT_INPUT_METADATA *_tui_make_text_input_metadata(      char *restrict text, COLOR color, TEXT_STYLE style, -    ON_TEXT_INPUT on_text_input) { +    ON_TEXT_INPUT on_text_input, void *data) {    TEXT_INPUT_METADATA *metadata = malloc(sizeof(*metadata));    metadata->text = malloc(strlen(text) + 1);    strcpy(metadata->text, text);    metadata->color = color;    metadata->style = style;    metadata->on_text_input = on_text_input; +  metadata->data = data;    return metadata;  }  extern void _tui_delete_input_text(WIDGET *restrict text_input) { diff --git a/src/ui/tui.h b/src/ui/tui.h index 731ec76..83451c8 100644 --- a/src/ui/tui.h +++ b/src/ui/tui.h @@ -46,15 +46,16 @@ typedef struct INPUT_ACTION {    uint y;  } INPUT_ACTION; -typedef void (*ON_TEXT_INPUT)(char c); -typedef void (*ON_CLICK_CALLBACK)(MOUSE_ACTION mouse_action); -typedef void (*ON_INPUT_CALLBACK)(INPUT_ACTION input_action); -typedef void (*ON_RAW_INPUT_CALLBACK)(INPUT_ACTION input_action, -                                      void *metadata); +typedef void (*ON_TEXT_INPUT)(char c, void *data); +typedef void (*ON_CLICK_CALLBACK)(MOUSE_ACTION mouse_action, void *data); +typedef void (*ON_INPUT_CALLBACK)(INPUT_ACTION input_action, void *data); +typedef void (*ON_RAW_INPUT_CALLBACK)(INPUT_ACTION input_action, void *metadata, +                                      void *data);  typedef struct ON_ACTION_CALLBACK {    ON_RAW_INPUT_CALLBACK on_raw_input_callback;    void *metadata; +  void *data;  } ON_ACTION_CALLBACK;  #ifndef __cplusplus @@ -110,6 +111,7 @@ typedef struct TEXT_METADATA {  typedef struct BUTTON_METADATA {    WIDGET *child;    ON_CLICK_CALLBACK callback; +  void *data;  } BUTTON_METADATA;  typedef struct COLUMN_METADATA { @@ -142,24 +144,26 @@ typedef struct TEXT_INPUT_METADATA {    COLOR color;    TEXT_STYLE style;    ON_TEXT_INPUT on_text_input; +  void *data;  } TEXT_INPUT_METADATA; -typedef WIDGET *(*WIDGET_BUILDER)(TUI *tui); +typedef WIDGET *(*WIDGET_BUILDER)(TUI *restrict tui);  extern TUI *tui_init();  extern void tui_delete(TUI *restrict tui); -extern void tui_refresh(TUI *tui); +extern void tui_refresh(TUI *restrict tui); -extern int tui_get_width(TUI *tui); -extern int tui_get_height(TUI *tui); +extern uint16_t tui_get_width(TUI *restrict tui); +extern uint16_t tui_get_height(TUI *restrict tui); -extern void tui_get_cursor_pos(TUI *tui, int *x, int *y); +extern void tui_get_cursor_pos(TUI *restrict tui, int *x, int *y);  extern int tui_move_to(int x, int y);  extern int tui_clear_screen(); -extern void tui_start_app(TUI *tui, WIDGET_BUILDER widget_builder, int fps); -extern void _tui_draw_widget_to_cells(TUI *tui, const WIDGET *widget, +extern void tui_start_app(TUI *restrict tui, WIDGET_BUILDER widget_builder, +                          int fps); +extern void _tui_draw_widget_to_cells(TUI *restrict tui, const WIDGET *widget,                                        int width_begin, int width_end,                                        int height_begin, int height_end,                                        int *child_width, int *child_height); @@ -176,7 +180,8 @@ extern bool tui_widget_eqauls(const WIDGET *restrict left,  extern bool tui_widget_array_eqauls(const WIDGET_ARRAY *restrict left,                                      const WIDGET_ARRAY *restrict right); -extern void tui_main_loop(TUI *tui, WIDGET_BUILDER widget_builder, int fps); +extern void tui_main_loop(TUI *restrict tui, WIDGET_BUILDER widget_builder, +                          int fps);  extern WIDGET *tui_new_widget(WIDGET_TYPE type, void *metadata);  extern void tui_delete_widget(WIDGET *restrict widget); @@ -188,9 +193,10 @@ extern TEXT_METADATA *_tui_make_text_metadata(char *restrict text, COLOR color,  extern void _tui_delete_text(WIDGET *restrict text);  extern WIDGET *tui_make_button(WIDGET *restrict child, -                               ON_CLICK_CALLBACK callback); +                               ON_CLICK_CALLBACK callback, void *data);  extern BUTTON_METADATA *_tui_make_button_metadata(WIDGET *restrict child, -                                                  ON_CLICK_CALLBACK callback); +                                                  ON_CLICK_CALLBACK callback, +                                                  void *data);  extern void _tui_delete_button(WIDGET *restrict button);  extern WIDGET *tui_make_column(WIDGET_ARRAY *restrict children); @@ -214,10 +220,10 @@ extern void _tui_delete_center(WIDGET *restrict center);  extern WIDGET *tui_make_text_input(char *restrict text, COLOR color,                                     TEXT_STYLE style, -                                   ON_TEXT_INPUT on_text_input); +                                   ON_TEXT_INPUT on_text_input, void *data);  extern TEXT_INPUT_METADATA *_tui_make_text_input_metadata(      char *restrict text, COLOR color, TEXT_STYLE style, -    ON_TEXT_INPUT on_text_input); +    ON_TEXT_INPUT on_text_input, void *data);  extern void _tui_delete_input_text(WIDGET *restrict text_input);  extern WIDGET *tui_make_padding(WIDGET *restrict child, int padding_top,  |