summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.c30
-rw-r--r--src/ui/color.h11
-rw-r--r--src/ui/tui.c105
-rw-r--r--src/ui/tui.h17
4 files changed, 111 insertions, 52 deletions
diff --git a/src/main.c b/src/main.c
index 2515014..549ddf5 100644
--- a/src/main.c
+++ b/src/main.c
@@ -5,6 +5,10 @@
#include "ui/color.h"
#include "ui/tui.h"
+constexpr COLOR BACKGROUND_COLOR = color_hex(0xFF2B2A33);
+constexpr COLOR COLOR_FPS_BACK = color_hex(0xFFCCCCCC);
+constexpr COLOR COLOR_FPS_TEXT = color_hex(0xFF000000);
+
WIDGET *search_box() {
return tui_make_padding(
tui_make_box(MAX_WIDTH, 1,
@@ -18,19 +22,29 @@ WIDGET *search_box() {
1, 1, 10, 10);
}
-WIDGET *search_header() {}
+// WIDGET *search_header() {}
+
+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));
+ return tui_make_padding(
+ tui_make_box(MIN_WIDTH, 1, tui_make_text(fps_text, COLOR_FPS_TEXT),
+ COLOR_FPS_BACK),
+ 0, 0, 2, 2);
+}
WIDGET *ui_build(TUI *tui) {
return tui_make_box(
MAX_WIDTH, MAX_HEIGHT,
tui_make_column(tui_make_widget_array(
- search_box(),
- tui_make_row(tui_make_widget_array(tui_make_center(
- tui_make_box(MIN_WIDTH, 3,
- tui_make_center(tui_make_text(
- "Hi here", color_init(0xFF0000FF))),
- color_init(0xFFFFFFFF))))))),
- color_init(0xFF2B2A33));
+ 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))))))),
+ BACKGROUND_COLOR);
}
int main() {
diff --git a/src/ui/color.h b/src/ui/color.h
index 43005a6..75df571 100644
--- a/src/ui/color.h
+++ b/src/ui/color.h
@@ -6,11 +6,12 @@ typedef struct COLOR {
uint8_t b, g, r, a;
} COLOR;
-#define color_hex(value) \
- (uint8_t)((uint32_t)value >> 3), \
- (uint8_t)((uint32_t)value >> 2), \
- (uint8_t)((uint32_t)value >> 1), \
- (uint8_t)((uint32_t)value >> 0) \
+#define color_hex(value) { \
+ (uint8_t)(((uint32_t)value >> 8*0)&0xFF), \
+ (uint8_t)(((uint32_t)value >> 8*1)&0xFF), \
+ (uint8_t)(((uint32_t)value >> 8*2)&0xFF), \
+ (uint8_t)(((uint32_t)value >> 8*3)&0xFF), \
+}
constexpr COLOR COLOR_NO_COLOR = {
.a = 0,
diff --git a/src/ui/tui.c b/src/ui/tui.c
index 62eb585..901cbc1 100644
--- a/src/ui/tui.c
+++ b/src/ui/tui.c
@@ -20,12 +20,14 @@ const int MIN_HEIGHT = -2;
const int FRAME_UNLIMITED = 0;
void _tui_clear_cells(TUI *tui) {
- const TERMINAL_CELL empty = {.c = ' ',
- .color = COLOR_NO_COLOR,
- .background_color = COLOR_NO_COLOR,
- .on_click_callback = NULL};
+ constexpr TERMINAL_CELL EMPTY_CELL = {
+ .c = ' ',
+ .color = COLOR_NO_COLOR,
+ .background_color = COLOR_NO_COLOR,
+ .on_click_callback = NULL,
+ };
for (size_t i = 0; i < tui->cells_length; ++i) {
- tui->cells[i] = empty;
+ tui->cells[i] = EMPTY_CELL;
}
}
@@ -184,26 +186,6 @@ void tui_handle_mouse_action(TUI *tui, const MOUSE_ACTION *mouse_action) {
}
}
-/*
-int tui_change_terminal_text_color(COLOR color) {
- if (color_equals(color, COLOR_NO_COLOR)) {
- return 0;
- } else if (color == COLOR_RESET) {
- return printf("\033[%dm", COLOR_RESET);
- }
- return printf("\033[%dm", color + 30);
-}
-
-int tui_change_terminal_background_color(COLOR color) {
- if (color == COLOR_NO_COLOR) {
- return 0;
- } else if (color == COLOR_RESET) {
- return printf("\033[%dm", COLOR_RESET);
- }
- return printf("\033[%dm", color + 40);
-}
-*/
-
bool handle_input(TUI *tui) {
unsigned char buff[6];
read(STDIN_FILENO, &buff, 1);
@@ -418,12 +400,12 @@ void _tui_draw_widget_to_cells(TUI *tui, const WIDGET *widget, int width_begin,
if (metadata != NULL) {
_tui_get_widget_size(metadata, width_begin, width_end, height_begin,
height_end, child_width, child_height);
- const int horizontalPadding = width_end - *child_width;
- const int verticalPadding = height_end - *child_height;
- const int leftPadding = horizontalPadding / 2;
- const int rightPadding = horizontalPadding - leftPadding;
- const int bottomPadding = verticalPadding / 2;
- const int topPadding = verticalPadding - bottomPadding;
+ const uint horizontalPadding = width_end - *child_width;
+ const uint verticalPadding = height_end - *child_height;
+ const uint leftPadding = horizontalPadding / 2;
+ const uint rightPadding = horizontalPadding - leftPadding;
+ const uint bottomPadding = verticalPadding / 2;
+ const uint topPadding = verticalPadding - bottomPadding;
_tui_draw_widget_to_cells(
tui, metadata, width_begin + leftPadding, width_end - rightPadding,
@@ -440,6 +422,14 @@ void _tui_draw_widget_to_cells(TUI *tui, const WIDGET *widget, int width_begin,
width_end - metadata->padding_right,
height_begin + metadata->padding_top,
height_end - metadata->padding_bottom, child_width, child_height);
+ *child_width += metadata->padding_left + metadata->padding_right;
+ *child_height += metadata->padding_top + metadata->padding_bottom;
+ if (*child_width > width_end) {
+ *child_width = width_end;
+ }
+ if (*child_height > height_end) {
+ *child_height = height_end;
+ }
}
}
return;
@@ -579,6 +569,7 @@ void _tui_get_widget_size(const WIDGET *widget, int width_begin, int width_end,
*widget_height = height_end;
}
}
+ return;
}
fprintf(stderr, "widget type '%d' went wrong in %s %d", widget->type,
__FILE_NAME__, __LINE__);
@@ -591,6 +582,7 @@ bool _tui_is_max_width(const WIDGET *widget) {
}
switch (widget->type) {
case WIDGET_TYPE_TEXT:
+ case WIDGET_TYPE_TEXT_INPUT:
return false;
case WIDGET_TYPE_BUTTON:
return _tui_is_max_width(((BUTTON_METADATA *)widget->metadata)->child);
@@ -762,32 +754,43 @@ bool tui_widget_eqauls(const WIDGET *restrict left,
left_data->padding_left == right_data->padding_left &&
left_data->padding_right == right_data->padding_right;
}
+ case WIDGET_TYPE_TEXT_INPUT: {
+ const TEXT_INPUT_METADATA *left_data = left->metadata;
+ const TEXT_INPUT_METADATA *right_data = right->metadata;
+ return color_equals(left_data->color, right_data->color) &&
+ strcmp(left_data->text, right_data->text) == 0 &&
+ left_data->on_text_input == right_data->on_text_input;
+ }
}
fprintf(stderr, "Type error '%d' in %s %d\n", left->type, __FILE__, __LINE__);
exit(1);
}
-const int NANO_TO_SECOND = 1000000000;
-
-int64_t nano_sleep(long int nano_seconds) {
+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);
- return remaining.tv_sec * NANO_TO_SECOND + remaining.tv_nsec;
+ 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;
+ }
}
-long int nano_time() {
+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 long int frame_nano =
+ const uint64_t frame_nano =
(fps == FRAME_UNLIMITED) ? 0 : NANO_TO_SECOND / fps;
int64_t last_remaining = 0;
while (1) {
- const long int start = nano_time();
+ const int64_t start = nano_time();
tui_save_cursor();
tui_refresh(tui);
WIDGET *root_widget = widget_builder(tui);
@@ -803,10 +806,11 @@ void tui_main_loop(TUI *tui, WIDGET_BUILDER widget_builder, int fps) {
/*printf("%ld\t%ld", last_frame_time, frame_nano);*/
tui_restore_cursor();
if (fps != FRAME_UNLIMITED) {
- const long int diff = nano_time() - start;
+ const int64_t diff = nano_time() - start;
last_remaining = nano_sleep(frame_nano - diff + last_remaining);
}
tui->last_frame = nano_time() - start;
+ ++frame_count;
if (kbhit()) {
if (handle_input(tui)) {
return;
@@ -848,6 +852,9 @@ void tui_delete_widget(WIDGET *restrict widget) {
case WIDGET_TYPE_PADDING:
_tui_delete_padding(widget);
goto RETURN_SUCCESS;
+ case WIDGET_TYPE_TEXT_INPUT:
+ _tui_delete_input_text(widget);
+ goto RETURN_SUCCESS;
}
fprintf(stderr, "Type error '%d' in %s %d\n", widget->type, __FILE__,
__LINE__);
@@ -983,6 +990,26 @@ void _tui_delete_padding(WIDGET *restrict padding) {
free(padding->metadata);
}
+extern WIDGET *tui_make_text_input(char *restrict text, COLOR color,
+ ON_TEXT_INPUT on_text_input) {
+ return tui_new_widget(
+ WIDGET_TYPE_TEXT_INPUT,
+ _tui_make_text_input_metadata(text, color, on_text_input));
+}
+extern TEXT_INPUT_METADATA *_tui_make_text_input_metadata(
+ char *restrict text, COLOR color, 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->on_text_input = on_text_input;
+ return metadata;
+}
+extern void _tui_delete_input_text(WIDGET *restrict text_input) {
+ free(((TEXT_INPUT_METADATA *)text_input->metadata)->text);
+ free(text_input->metadata);
+}
+
WIDGET_ARRAY *tui_make_widget_array_raw(size_t size, ...) {
va_list arg_pointer;
va_start(arg_pointer, size);
diff --git a/src/ui/tui.h b/src/ui/tui.h
index 8678804..605376f 100644
--- a/src/ui/tui.h
+++ b/src/ui/tui.h
@@ -52,6 +52,8 @@ 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,
@@ -60,6 +62,7 @@ typedef enum WIDGET_TYPE {
WIDGET_TYPE_BOX,
WIDGET_TYPE_CENTER,
WIDGET_TYPE_PADDING,
+ WIDGET_TYPE_TEXT_INPUT,
} WIDGET_TYPE;
typedef struct WIDGET {
@@ -107,6 +110,14 @@ 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;
+ ON_TEXT_INPUT on_text_input;
+} TEXT_INPUT_METADATA;
+
typedef WIDGET *(*WIDGET_BUILDER)(TUI *tui);
extern TUI *tui_init();
@@ -173,6 +184,12 @@ extern WIDGET *tui_make_center(WIDGET *restrict child);
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,
+ 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);
+extern void _tui_delete_input_text(WIDGET *restrict text_input);
+
extern WIDGET *tui_make_padding(WIDGET *restrict child, int padding_top,
int padding_bottom, int padding_left,
int padding_right);