summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorA404M <ahmadmahmoudiprogrammer@gmail.com>2024-12-28 08:03:23 +0330
committerA404M <ahmadmahmoudiprogrammer@gmail.com>2024-12-28 08:03:23 +0330
commitd7802371b56734446a16962363322282ba772257 (patch)
tree8b5a62d12b080381e4a512b107e675a3ad14186b /src
parent55d29d0df8681efe01e88e0475c8512c44ec4bc4 (diff)
added many stuff which I can't even remember
Diffstat (limited to 'src')
-rw-r--r--src/main.c89
-rw-r--r--src/ui/text.c0
-rw-r--r--src/ui/text.h14
-rw-r--r--src/ui/tui.c350
-rw-r--r--src/ui/tui.h54
-rw-r--r--src/utils/time.c23
-rw-r--r--src/utils/time.h9
7 files changed, 376 insertions, 163 deletions
diff --git a/src/main.c b/src/main.c
index 549ddf5..61ee8e1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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();