diff options
| author | A404M <ahmadmahmoudiprogrammer@gmail.com> | 2024-12-28 08:03:23 +0330 | 
|---|---|---|
| committer | A404M <ahmadmahmoudiprogrammer@gmail.com> | 2024-12-28 08:03:23 +0330 | 
| commit | d7802371b56734446a16962363322282ba772257 (patch) | |
| tree | 8b5a62d12b080381e4a512b107e675a3ad14186b | |
| parent | 55d29d0df8681efe01e88e0475c8512c44ec4bc4 (diff) | |
added many stuff which I can't even remember
| -rw-r--r-- | Makefile | 3 | ||||
| -rw-r--r-- | a.txt | bin | 0 -> 416495 bytes | |||
| -rw-r--r-- | src/main.c | 89 | ||||
| -rw-r--r-- | src/ui/text.c | 0 | ||||
| -rw-r--r-- | src/ui/text.h | 14 | ||||
| -rw-r--r-- | src/ui/tui.c | 350 | ||||
| -rw-r--r-- | src/ui/tui.h | 54 | ||||
| -rw-r--r-- | src/utils/time.c | 23 | ||||
| -rw-r--r-- | src/utils/time.h | 9 | 
9 files changed, 377 insertions, 165 deletions
@@ -14,8 +14,7 @@ NC := \033[0m  INC_DIRS := $(SRC_DIR)  INC_FLAGS := $(addprefix -I,$(INC_DIRS)) -CFLAGS := $(INC_FLAGS) -Wall -Wextra -std=gnu23 -Ofast -march=native - +CFLAGS := $(INC_FLAGS) -Wall -Wextra -std=gnu23   EXEC_FILE := $(BUILD_DIR)/atui  all: $(EXEC_FILE) Binary files differ@@ -1,56 +1,113 @@  #include <stdint.h>  #include <stdio.h> +#include <string.h>  #include <unistd.h>  #include "ui/color.h" +#include "ui/text.h"  #include "ui/tui.h" +#include "utils/time.h"  constexpr COLOR BACKGROUND_COLOR = color_hex(0xFF2B2A33);  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; } + +char search[1000] = ""; + +void on_search_text_add(char c) { +  if (c == '\n') { +    // TODO: do something +  } else if (c == '\b') { +    size_t len = strlen(search); +    if (len != 0) { +      search[len - 1] = '\0'; +    } +  } else { +    strncat(search, &c, 1); +  } +} +  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, 1, NULL, color_init(0xFF42414D)), -                       tui_make_box(10, 1, +                       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))), +                                        "Search", color_init(0xFF000000), +                                        TEXT_STYLE_NORMAL)),                                      color_init(0xFFC4C3C9))))),                     COLOR_NO_COLOR),        1, 1, 10, 10);  } -// WIDGET *search_header() {} +bool selectedArray[] = { +    false, false, false, false, false, false, false, false, false, +    false, false, false, false, false, false, false, false, +}; + +WIDGET *search_result(int 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))))), +      0, 1, 0, 0); +} + +WIDGET *search_body() { +  return tui_make_padding( +      tui_make_column(tui_make_widget_array( +          search_result(0), search_result(1), search_result(2), +          search_result(3), search_result(4), search_result(5))), +      0, 0, 10, 10); +}  WIDGET *fps_counter(uint64_t last_frame) {    char fps_text[3 + 1 + 20 + 1]; -  sprintf(fps_text, "fps %ld", -          (last_frame == 0) ? 0 : (NANO_TO_SECOND / last_frame)); +  if (show_fps) { +    sprintf(fps_text, "%ld fps", +            (last_frame == 0) ? 0 : (NANO_TO_SECOND / last_frame)); +  } else { +    sprintf(fps_text, "%ld us", last_frame / 1000); +  }    return tui_make_padding( -      tui_make_box(MIN_WIDTH, 1, tui_make_text(fps_text, COLOR_FPS_TEXT), -                   COLOR_FPS_BACK), +      tui_make_button( +          tui_make_box(MIN_WIDTH, MIN_HEIGHT, +                       tui_make_padding(tui_make_text(fps_text, COLOR_FPS_TEXT, +                                                      TEXT_STYLE_NORMAL), +                                        0, 0, 1, 1), +                       COLOR_FPS_BACK), +          on_click),        0, 0, 2, 2);  }  WIDGET *ui_build(TUI *tui) {    return tui_make_box(        MAX_WIDTH, MAX_HEIGHT, -      tui_make_column(tui_make_widget_array( -          fps_counter(tui->last_frame), search_box(), -          tui_make_row(tui_make_widget_array(tui_make_center(tui_make_box( -              MIN_WIDTH, MIN_HEIGHT, -              tui_make_padding(tui_make_text("Hi here", color_init(0xFF0000FF)), -                               2, 2, 2, 2), -              color_init(0xFFFFFFFF))))))), +      tui_make_column(tui_make_widget_array(fps_counter(tui->last_frame), +                                            search_box(), search_body())),        BACKGROUND_COLOR);  }  int main() {    TUI *tui = tui_init(); -  tui_start_app(tui, ui_build, 144); +  tui_start_app(tui, ui_build, FRAME_UNLIMITED);    tui_delete(tui); diff --git a/src/ui/text.c b/src/ui/text.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/ui/text.c diff --git a/src/ui/text.h b/src/ui/text.h new file mode 100644 index 0000000..3606d88 --- /dev/null +++ b/src/ui/text.h @@ -0,0 +1,14 @@ +#pragma once + +typedef enum TEXT_STYLE { +  TEXT_STYLE_NORMAL = 0, +  TEXT_STYLE_BOLD = 1, +  TEXT_STYLE_SHADOWED = 2, +  TEXT_STYLE_ITALIC = 3, +  TEXT_STYLE_UNDER_STROKE = 4, +  TEXT_STYLE_BLINKING = 5, +  TEXT_STYLE_BLINKING2 = 6, +  TEXT_STYLE_REVERSED = 7, +  TEXT_STYLE_INVISIBLE = 8, +  TEXT_STYLE_STROCK_TRHOUGH = 9, +} TEXT_STYLE; diff --git a/src/ui/tui.c b/src/ui/tui.c index 901cbc1..835e228 100644 --- a/src/ui/tui.c +++ b/src/ui/tui.c @@ -10,6 +10,8 @@  #include <unistd.h>  #include "ui/color.h" +#include "ui/text.h" +#include "utils/time.h"  const int MAX_WIDTH = -1;  const int MAX_HEIGHT = -1; @@ -24,7 +26,9 @@ void _tui_clear_cells(TUI *tui) {        .c = ' ',        .color = COLOR_NO_COLOR,        .background_color = COLOR_NO_COLOR, -      .on_click_callback = NULL, +      .style = TEXT_STYLE_NORMAL, +      .on_action_callback.on_raw_input_callback = NULL, +      .on_action_callback.metadata = NULL,    };    for (size_t i = 0; i < tui->cells_length; ++i) {      tui->cells[i] = EMPTY_CELL; @@ -33,7 +37,7 @@ void _tui_clear_cells(TUI *tui) {  void _tui_init_cells(TUI *tui) {    tui->cells_length = tui_get_width(tui) * tui_get_height(tui); -  tui->cells = malloc(tui->cells_length * sizeof(TERMINAL_CELL)); +  tui->cells = malloc(tui->cells_length * sizeof(*tui->cells));    _tui_clear_cells(tui);  } @@ -48,6 +52,20 @@ TUI *tui_init() {    TUI *tui = malloc(sizeof(TUI)); +  constexpr TUI tui_clean = { +      .cells = NULL, +      .cells_length = 0, +      .original = {}, +      .init_cursor_x = 0, +      .init_cursor_y = 0, +      .raw = {}, +      .size = {}, +      .helper = {}, +      .last_frame = 0, +  }; + +  *tui = tui_clean; +    tui_get_cursor_pos(tui, &tui->init_cursor_x, &tui->init_cursor_y);    // Save original serial communication configuration for stdin @@ -113,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) { -  char buf[8]; +  char buf[8] = "";    char cmd[] = "\033[6n";    tcgetattr(0, &tui->raw);    cfmakeraw(&tui->helper); @@ -151,13 +169,8 @@ void _tui_set_cell_color(TUI *tui, int x, int y, COLOR color) {    tui->cells[_tui_get_cell_index(tui, x, y)].color = color;  } -void _tui_set_cell_background_color(TUI *tui, int x, int y, -                                    COLOR background_color) { -  if (color_equals(background_color, COLOR_NO_COLOR)) { -    return; -  } -  tui->cells[_tui_get_cell_index(tui, x, y)].background_color = -      background_color; +void _tui_set_cell_style(TUI *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, @@ -171,18 +184,19 @@ void _tui_set_cell_background_color_if_not_set(TUI *tui, int x, int y,    }  } -void _tui_set_cell_on_click_callback(TUI *tui, int x, int y, -                                     ON_CLICK_CALLBACK on_click_callback) { -  tui->cells[_tui_get_cell_index(tui, x, y)].on_click_callback = -      on_click_callback; +void _tui_set_cell_on_action_callback(TUI *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_mouse_action(TUI *tui, const MOUSE_ACTION *mouse_action) { -  const ON_CLICK_CALLBACK callback = -      tui->cells[_tui_get_cell_index(tui, mouse_action->x, mouse_action->y)] -          .on_click_callback; -  if (callback != NULL) { -    callback(mouse_action); +void tui_handle_input_action(TUI *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); +    }    }  } @@ -196,18 +210,24 @@ bool handle_input(TUI *tui) {      read(STDIN_FILENO, &buff, 5);      switch (buff[1]) {        case 77: { -        const MOUSE_ACTION mouse_action = { -            .button = buff[2], +        const INPUT_ACTION mouse_action = { +            .type = INPUT_TYPE_MOUSE, +            .action.mouse_button = buff[2],              .x = buff[3] - 32 - 1,  // starts at 0              .y = buff[4] - 32 - 1,  // starts at 0          }; -        tui_handle_mouse_action(tui, &mouse_action); +        tui_move_to(mouse_action.x, mouse_action.y); +        tui_handle_input_action(tui, mouse_action);          /*printf("button:%u\n\rx:%u\n\ry:%u\n\n\r", mouse_action.button,*/          /*       mouse_action.x, mouse_action.y);*/        } break;      }    } else { -    switch (buff[0]) { +    char c = buff[0]; +    int x, y; +    tui_get_cursor_pos(tui, &x, &y); +    switch (c) { +      /*        case 'h':          tui_move_left(1);          break; @@ -222,25 +242,22 @@ bool handle_input(TUI *tui) {          break;        case 'q':          return true; -      case '\r': {  // <ENTER> -        int x, y; -        tui_get_cursor_pos(tui, &x, &y); -        const MOUSE_ACTION mouse_action = { -            .button = MOUSE_BUTTON_LEFT_CLICK, -            .x = x, -            .y = y, -        }; -        tui_handle_mouse_action(tui, &mouse_action); -      } break; +      */ +      case '\r': +        c = '\n'; +        break;        case '\b':        case 127:  // back space -        tui_delete_before(); -        break; -      default: -        /*printf("unknown:%c,%d\n\r", buff[0], buff[0]);*/ -        /*sleep(1);*/ +        c = '\b';          break;      } +    const INPUT_ACTION key_action = { +        .type = INPUT_TYPE_KEYBOARD, +        .action.key = c, +        .x = x, +        .y = y, +    }; +    tui_handle_input_action(tui, key_action);    }    return false;  } @@ -249,44 +266,74 @@ void tui_start_app(TUI *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) { +  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); +  } +} + +void _tui_on_text_input_handler(INPUT_ACTION input_action, void *metadata) { +  if (input_action.type == INPUT_TYPE_KEYBOARD) { +    ((ON_TEXT_INPUT)metadata)(input_action.action.key); +  } +} + +void _tui_draw_text_to_cells(TUI *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) { +  const int width_diff = width_end - width_begin; +  const size_t text_len = strlen(text); +  size_t inserted_index = 0; +  int height = height_begin; +  int max_width = width_begin; +  for (; height < height_end; ++height) { +    for (int j = 0; j < width_diff; ++j) { +    START_OF_HORIZONTAL_LOOP: +      if (inserted_index < text_len) { +        const int x = width_begin + j; +        const int y = height; +        const char c = text[inserted_index]; +        inserted_index += 1; +        if (c == '\n') {  // do for other spaces +          height += 1; +          j = 0; +          goto START_OF_HORIZONTAL_LOOP; +        } else { +          if (max_width < x) { +            max_width = x; +          } +          _tui_set_cell_color(tui, x, y, color); +          _tui_set_cell_char(tui, x, y, c); +          _tui_set_cell_style(tui, x, y, style); +        } +      } else { +        goto END_OF_TEXT; +      } +    } +  } +END_OF_TEXT: +  *child_height = height + 1; +  *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) { +  if (widget == NULL) { +    return; +  }    switch (widget->type) {      case WIDGET_TYPE_TEXT: {        const TEXT_METADATA *metadata = widget->metadata; -      const int width_diff = width_end - width_begin; -      const size_t text_len = strlen(metadata->text); -      size_t inserted_index = 0; -      int height = height_begin; -      int max_width = width_begin; -      for (; height < height_end; ++height) { -        for (int j = 0; j < width_diff; ++j) { -        START_OF_HORIZONTAL_LOOP: -          if (inserted_index < text_len) { -            const int x = width_begin + j; -            const int y = height; -            const char c = metadata->text[inserted_index]; -            inserted_index += 1; -            if (c == '\n') {  // do for other spaces -              height += 1; -              j = 0; -              goto START_OF_HORIZONTAL_LOOP; -            } else { -              if (max_width < x) { -                max_width = x; -              } -              _tui_set_cell_color(tui, x, y, metadata->color); -              _tui_set_cell_char(tui, x, y, c); -            } -          } else { -            goto END_OF_TEXT; -          } -        } -      } -    END_OF_TEXT: -      *child_height = height + 1; -      *child_width = max_width + 1; +      _tui_draw_text_to_cells( +          tui, metadata->text, metadata->color, metadata->style, width_begin, +          width_end, height_begin, height_end, child_width, child_height);      }        return;      case WIDGET_TYPE_BUTTON: { @@ -295,9 +342,13 @@ void _tui_draw_widget_to_cells(TUI *tui, const WIDGET *widget, int width_begin,          _tui_draw_widget_to_cells(tui, metadata->child, width_begin, width_end,                                    height_begin, height_end, child_width,                                    child_height); +        const ON_ACTION_CALLBACK on_action_callback = { +            .on_raw_input_callback = _tui_on_button_click_handler, +            .metadata = metadata->callback, +        };          for (int i = width_begin; i < *child_width; ++i) {            for (int j = height_begin; j < *child_height; ++j) { -            _tui_set_cell_on_click_callback(tui, i, j, metadata->callback); +            _tui_set_cell_on_action_callback(tui, i, j, on_action_callback);            }          }        } @@ -433,47 +484,74 @@ void _tui_draw_widget_to_cells(TUI *tui, const WIDGET *widget, int width_begin,        }      }        return; +    case WIDGET_TYPE_TEXT_INPUT: { +      const TEXT_INPUT_METADATA *metadata = widget->metadata; +      _tui_draw_text_to_cells( +          tui, metadata->text, metadata->color, metadata->style, width_begin, +          width_end, height_begin, height_end, child_width, child_height); + +      const ON_ACTION_CALLBACK on_action_callback = { +          .on_raw_input_callback = _tui_on_text_input_handler, +          .metadata = metadata->on_text_input, +      }; +      for (int i = width_begin; i < width_end; ++i) { +        for (int j = height_begin; j < height_end; ++j) { +          _tui_set_cell_on_action_callback(tui, i, j, on_action_callback); +        } +      } +    } +      return;    }    fprintf(stderr, "widget type '%d' went wrong in %s %d\n", widget->type,            __FILE_NAME__, __LINE__);    exit(1);  } +void _tui_get_text_size(const char *text, int width_begin, int width_end, +                        int height_begin, int height_end, int *widget_width, +                        int *widget_height) { +  const int width_diff = width_end - width_begin; +  const size_t text_len = strlen(text); +  size_t inserted_index = 0; +  int height = height_begin; +  int max_width = width_begin; +  for (; height < height_end; ++height) { +    for (int j = 0; j < width_diff; ++j) { +    START_OF_HORIZONTAL_LOOP: +      if (inserted_index < text_len) { +        const int x = width_begin + j; +        const char c = text[inserted_index]; +        inserted_index += 1; +        if (c == '\n') {  // do for other spaces +          height += 1; +          j = 0; +          goto START_OF_HORIZONTAL_LOOP; +        } else { +          if (max_width < x) { +            max_width = x; +          } +        } +      } else { +        goto END_OF_TEXT; +      } +    } +  } +END_OF_TEXT: +  *widget_height = height + 1; +  *widget_width = max_width + 1; +} +  void _tui_get_widget_size(const WIDGET *widget, int width_begin, int width_end,                            int height_begin, int height_end, int *widget_width,                            int *widget_height) { +  if (widget == NULL) { +    return; +  }    switch (widget->type) {      case WIDGET_TYPE_TEXT: {        const TEXT_METADATA *metadata = widget->metadata; -      const int width_diff = width_end - width_begin; -      const size_t text_len = strlen(metadata->text); -      size_t inserted_index = 0; -      int height = height_begin; -      int max_width = width_begin; -      for (; height < height_end; ++height) { -        for (int j = 0; j < width_diff; ++j) { -        START_OF_HORIZONTAL_LOOP: -          if (inserted_index < text_len) { -            const int x = width_begin + j; -            const char c = metadata->text[inserted_index]; -            inserted_index += 1; -            if (c == '\n') {  // do for other spaces -              height += 1; -              j = 0; -              goto START_OF_HORIZONTAL_LOOP; -            } else { -              if (max_width < x) { -                max_width = x; -              } -            } -          } else { -            goto END_OF_TEXT; -          } -        } -      } -    END_OF_TEXT: -      *widget_height = height + 1; -      *widget_width = max_width + 1; +      _tui_get_text_size(metadata->text, width_begin, width_end, height_begin, +                         height_end, widget_width, widget_height);      }        return;      case WIDGET_TYPE_BUTTON: { @@ -554,7 +632,7 @@ void _tui_get_widget_size(const WIDGET *widget, int width_begin, int width_end,        }      }        return; -    case WIDGET_TYPE_PADDING: +    case WIDGET_TYPE_PADDING: {        const PADDING_METADATA *metadata = widget->metadata;        if (metadata != NULL) {          _tui_get_widget_size(metadata->child, width_begin, width_end, @@ -569,6 +647,13 @@ void _tui_get_widget_size(const WIDGET *widget, int width_begin, int width_end,            *widget_height = height_end;          }        } +    } +      return; +    case WIDGET_TYPE_TEXT_INPUT: { +      const TEXT_INPUT_METADATA *metadata = widget->metadata; +      _tui_get_text_size(metadata->text, width_begin, width_end, height_begin, +                         height_end, widget_width, widget_height); +    }        return;    }    fprintf(stderr, "widget type '%d' went wrong in %s %d", widget->type, @@ -640,37 +725,46 @@ int _tui_get_background_color_ascii(COLOR color) {  */  void _tui_draw_cells_to_terminal(TUI *tui) { -  const size_t size_of_cell = 5 + 5 + sizeof(char) + 5; +  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];    _tui_move_to_start_in_str(str); -  char cell_str[20]; +  char cell_str[size_of_cell];    COLOR last_color = COLOR_NO_COLOR;    COLOR last_background_color = COLOR_NO_COLOR; +  TEXT_STYLE last_style = TEXT_STYLE_NORMAL;    for (size_t i = 0; i < tui->cells_length; ++i) {      const TERMINAL_CELL cell = tui->cells[i];      if (color_not_equals(last_color, cell.color) || -        color_not_equals(last_background_color, cell.background_color)) { +        color_not_equals(last_background_color, cell.background_color) || +        last_style != cell.style) {        sprintf(cell_str, "\033[0m");        strcat(str, cell_str);        last_color = cell.color;        last_background_color = cell.background_color; +      last_style = cell.style; + +      if (cell.style != TEXT_STYLE_NORMAL) { +        sprintf(cell_str, "\033[%dm", cell.style); +        strcat(str, cell_str); +      } +        if (color_not_equals(cell.color, COLOR_NO_COLOR)) {          sprintf(cell_str, "\033[38;2;%d;%d;%dm", cell.color.r, cell.color.g,                  cell.color.b); +        strcat(str, cell_str);        } -      strcat(str, cell_str);        if (color_not_equals(cell.background_color, COLOR_NO_COLOR)) {          sprintf(cell_str, "\033[48;2;%d;%d;%dm", cell.background_color.r,                  cell.background_color.g, cell.background_color.b); +        strcat(str, cell_str);        } -      strcat(str, cell_str);      }      strncat(str, &cell.c, 1);    } @@ -679,12 +773,12 @@ void _tui_draw_cells_to_terminal(TUI *tui) {    write(STDOUT_FILENO, str, len);  } -int kbhit() { +bool kbhit() {    struct timeval tv = {0L, 0L};    fd_set fds;    FD_ZERO(&fds);    FD_SET(0, &fds); -  return select(1, &fds, NULL, NULL, &tv) > 0; +  return select(1, &fds, NULL, NULL, &tv);  }  bool tui_widget_array_eqauls(const WIDGET_ARRAY *restrict left, @@ -766,25 +860,6 @@ bool tui_widget_eqauls(const WIDGET *restrict left,    exit(1);  } -int64_t nano_sleep(uint64_t nano_seconds) { -  struct timespec remaining, -      request = {nano_seconds / NANO_TO_SECOND, nano_seconds % NANO_TO_SECOND}; -  nanosleep(&request, &remaining); -  int64_t ret = remaining.tv_sec * NANO_TO_SECOND + remaining.tv_nsec; -  if (ret < 0 || ret > NANO_TO_SECOND) {  // TODO: fix later -    return 0; -  } else { -    return ret; -  } -} - -int64_t nano_time() { -  struct timespec t = {0, 0}; -  clock_gettime(CLOCK_MONOTONIC, &t); -  return t.tv_sec * NANO_TO_SECOND + t.tv_nsec; -} - -uint64_t frame_count = 0;  void tui_main_loop(TUI *tui, WIDGET_BUILDER widget_builder, int fps) {    const uint64_t frame_nano =        (fps == FRAME_UNLIMITED) ? 0 : NANO_TO_SECOND / fps; @@ -810,8 +885,7 @@ void tui_main_loop(TUI *tui, WIDGET_BUILDER widget_builder, int fps) {        last_remaining = nano_sleep(frame_nano - diff + last_remaining);      }      tui->last_frame = nano_time() - start; -    ++frame_count; -    if (kbhit()) { +    while (kbhit()) {        if (handle_input(tui)) {          return;        } @@ -863,15 +937,18 @@ RETURN_SUCCESS:    free(widget);  } -WIDGET *tui_make_text(char *restrict text, COLOR color) { -  return tui_new_widget(WIDGET_TYPE_TEXT, _tui_make_text_metadata(text, color)); +WIDGET *tui_make_text(char *restrict text, COLOR color, TEXT_STYLE style) { +  return tui_new_widget(WIDGET_TYPE_TEXT, +                        _tui_make_text_metadata(text, color, style));  } -TEXT_METADATA *_tui_make_text_metadata(char *restrict text, COLOR color) { +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);    metadata->color = color; +  metadata->style = style;    return metadata;  } @@ -991,17 +1068,20 @@ 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) {    return tui_new_widget(        WIDGET_TYPE_TEXT_INPUT, -      _tui_make_text_input_metadata(text, color, on_text_input)); +      _tui_make_text_input_metadata(text, color, style, on_text_input));  }  extern TEXT_INPUT_METADATA *_tui_make_text_input_metadata( -    char *restrict text, COLOR color, ON_TEXT_INPUT on_text_input) { +    char *restrict text, COLOR color, TEXT_STYLE style, +    ON_TEXT_INPUT on_text_input) {    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;    return metadata;  } diff --git a/src/ui/tui.h b/src/ui/tui.h index 605376f..731ec76 100644 --- a/src/ui/tui.h +++ b/src/ui/tui.h @@ -6,6 +6,8 @@  #include <termios.h>  #include <ui/color.h> +#include "ui/text.h" +  extern const int MAX_WIDTH;  extern const int MAX_HEIGHT; @@ -14,7 +16,7 @@ extern const int MIN_HEIGHT;  extern const int FRAME_UNLIMITED; -typedef enum MOUSE_BUTTON { +typedef enum MOUSE_BUTTON : uint8_t {    MOUSE_BUTTON_LEFT_CLICK = 32,    MOUSE_BUTTON_MIDDLE_CLICK = 33,    MOUSE_BUTTON_RIGHT_CLICK = 34, @@ -22,13 +24,38 @@ typedef enum MOUSE_BUTTON {    MOUSE_BUTTON_SCROLL_DOWN = 97,  } MOUSE_BUTTON; +typedef enum INPUT_TYPE : uint8_t { +  INPUT_TYPE_NONE, +  INPUT_TYPE_MOUSE, +  INPUT_TYPE_KEYBOARD, +} INPUT_TYPE; +  typedef struct MOUSE_ACTION {    MOUSE_BUTTON button; -  unsigned int x; -  unsigned int y; +  uint x; +  uint y;  } MOUSE_ACTION; -typedef void (*ON_CLICK_CALLBACK)(const MOUSE_ACTION *mouse_action); +typedef struct INPUT_ACTION { +  union { +    MOUSE_BUTTON mouse_button; +    char key; +  } action; +  INPUT_TYPE type; +  uint x; +  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 struct ON_ACTION_CALLBACK { +  ON_RAW_INPUT_CALLBACK on_raw_input_callback; +  void *metadata; +} ON_ACTION_CALLBACK;  #ifndef __cplusplus    #if (__STDC_VERSION__ < 202000L) @@ -40,7 +67,8 @@ typedef struct TERMINAL_CELL {    char c;    COLOR color;    COLOR background_color; -  ON_CLICK_CALLBACK on_click_callback; +  TEXT_STYLE style; +  ON_ACTION_CALLBACK on_action_callback;  } TERMINAL_CELL;  typedef struct TUI { @@ -52,8 +80,6 @@ typedef struct TUI {    uint64_t last_frame;  // in nanoseconds  } TUI; -constexpr int64_t NANO_TO_SECOND = 1000000000; -  typedef enum WIDGET_TYPE {    WIDGET_TYPE_TEXT,    WIDGET_TYPE_BUTTON, @@ -78,6 +104,7 @@ typedef struct WIDGET_ARRAY {  typedef struct TEXT_METADATA {    char *text;    COLOR color; +  TEXT_STYLE style;  } TEXT_METADATA;  typedef struct BUTTON_METADATA { @@ -110,11 +137,10 @@ typedef struct PADDING_METADATA {    int padding_right;  } PADDING_METADATA; -typedef void (*ON_TEXT_INPUT)(char c); -  typedef struct TEXT_INPUT_METADATA {    char *text;    COLOR color; +  TEXT_STYLE style;    ON_TEXT_INPUT on_text_input;  } TEXT_INPUT_METADATA; @@ -155,8 +181,10 @@ extern void tui_main_loop(TUI *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); -extern WIDGET *tui_make_text(char *restrict text, COLOR color); -extern TEXT_METADATA *_tui_make_text_metadata(char *restrict text, COLOR color); +extern WIDGET *tui_make_text(char *restrict text, COLOR color, +                             TEXT_STYLE style); +extern TEXT_METADATA *_tui_make_text_metadata(char *restrict text, COLOR color, +                                              TEXT_STYLE style);  extern void _tui_delete_text(WIDGET *restrict text);  extern WIDGET *tui_make_button(WIDGET *restrict child, @@ -185,9 +213,11 @@ extern CENTER_METADATA *_tui_make_center_metadata(WIDGET *restrict child);  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);  extern TEXT_INPUT_METADATA *_tui_make_text_input_metadata( -    char *restrict text, COLOR color, ON_TEXT_INPUT on_text_input); +    char *restrict text, COLOR color, TEXT_STYLE style, +    ON_TEXT_INPUT on_text_input);  extern void _tui_delete_input_text(WIDGET *restrict text_input);  extern WIDGET *tui_make_padding(WIDGET *restrict child, int padding_top, diff --git a/src/utils/time.c b/src/utils/time.c new file mode 100644 index 0000000..b6bc960 --- /dev/null +++ b/src/utils/time.c @@ -0,0 +1,23 @@ +#include "time.h" + +#include <time.h> + +int64_t nano_sleep(uint64_t nano_seconds) { +  struct timespec remaining, +      request = {nano_seconds / NANO_TO_SECOND, nano_seconds % NANO_TO_SECOND}; +  nanosleep(&request, &remaining); +  int64_t ret = remaining.tv_sec * NANO_TO_SECOND + remaining.tv_nsec; +  if (ret < 0 || ret > NANO_TO_SECOND) {  // TODO: fix later +    return 0; +  } else { +    return ret; +  } +} + +int64_t nano_time() { +  struct timespec t = {0, 0}; +  clock_gettime(CLOCK_MONOTONIC, &t); +  return t.tv_sec * NANO_TO_SECOND + t.tv_nsec; +} + + diff --git a/src/utils/time.h b/src/utils/time.h new file mode 100644 index 0000000..f7e9361 --- /dev/null +++ b/src/utils/time.h @@ -0,0 +1,9 @@ +#pragma once + +#include <stdint.h> + +constexpr int64_t NANO_TO_SECOND = 1000000000; + +int64_t nano_sleep(uint64_t nano_seconds); + +int64_t nano_time();  |