From 21bdd5f172df21566c78dc6e2af9a1770e67557e Mon Sep 17 00:00:00 2001 From: Alexander Zhylin Date: Mon, 1 Dec 2025 18:01:12 +0200 Subject: [PATCH] element groups: initial support, improves login dialog init --- Makefile | 3 ++ TODO.md | 2 +- src/deps.mk | 12 ++++--- src/main.c | 15 ++++----- src/ui/modals/login.c | 28 ++++++++++++++++ src/ui/modals/login.h | 7 ++++ src/ui/widget.h | 13 ++++++-- src/ui/widget/button.c | 38 ++++++++++++++++++++++ src/ui/widget/button.h | 9 ++++-- src/ui/widget/dialogue.c | 6 ++-- src/ui/widget/dialogue.h | 3 +- src/ui/widget/group.c | 69 ++++++++++++++++++++++++++++++++++++++++ src/ui/widget/group.h | 27 ++++++++++++++++ 13 files changed, 211 insertions(+), 21 deletions(-) create mode 100644 src/ui/modals/login.c create mode 100644 src/ui/modals/login.h create mode 100644 src/ui/widget/button.c create mode 100644 src/ui/widget/group.c create mode 100644 src/ui/widget/group.h diff --git a/Makefile b/Makefile index ae8def9..1904c76 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,9 @@ $(OBJ_DIR)/ui/%.o: $(SRC_DIR)/ui/%.c $(SRC_DIR)/ui/%.h $(OBJ_DIR)/ui/widget/%.o: $(SRC_DIR)/ui/widget/%.c $(SRC_DIR)/ui/widget/%.h $(CC) $(CFLAGS) -c $< -o $@ +$(OBJ_DIR)/ui/modals/%.o: $(SRC_DIR)/ui/modals/%.c $(SRC_DIR)/ui/modals/%.h + $(CC) $(CFLAGS) -c $< -o $@ + bbs-client: $(OBJS) $(CC) $(CFLAGS) $^ -o $(BIN_DIR)/$@ diff --git a/TODO.md b/TODO.md index 5c3d246..341ab40 100644 --- a/TODO.md +++ b/TODO.md @@ -1,3 +1,3 @@ TODO: -- [ ] More universal Makefile +- [x] More universal Makefile - [ ] Check and fix registration and login \ No newline at end of file diff --git a/src/deps.mk b/src/deps.mk index 7a21821..22899d9 100644 --- a/src/deps.mk +++ b/src/deps.mk @@ -3,14 +3,16 @@ client.o: src/client.c src/file_processor.h src/main.h src/types.h \ connection.o: src/connection.c src/main.h src/types.h file_processor.o: src/file_processor.c src/client.h src/main.h \ src/types.h src/query.h -main.o: src/main.c src/main.h src/types.h src/ui/app.h \ - src/ui/widget/dialogue.h src/ui/widget/../widget.h \ - src/ui/widget/../../main.h src/ui/widget/button.h \ - src/ui/widget/../../main.h src/ui/widget/dialogue.h +main.o: src/main.c src/ui/app.h src/ui/widget/dialogue.h \ + src/ui/widget/../widget.h src/ui/widget/../../main.h \ + src/ui/widget/../../types.h src/ui/widget/button.h \ + src/ui/widget/../../main.h src/ui/widget/group.h \ + src/ui/widget/dialogue.h src/ui/modals/login.h \ + src/ui/modals/../widget/dialogue.h modal.o: src/modal.c src/ui/app.h src/ui/widget/dialogue.h \ src/ui/widget/../widget.h src/ui/widget/../../main.h \ src/ui/widget/../../types.h src/ui/widget/button.h \ - src/ui/widget/../../main.h + src/ui/widget/../../main.h src/ui/widget/group.h query.o: src/query.c src/file_processor.h src/main.h src/types.h \ src/connection.h src/client.h src/server.h server.o: src/server.c src/client.h src/main.h src/types.h \ diff --git a/src/main.c b/src/main.c index 697875e..7848d12 100644 --- a/src/main.c +++ b/src/main.c @@ -1,16 +1,17 @@ -#include "main.h" -#include -#include #include +#include #include #include +#include #include #include #include +#include #include "ui/app.h" #include "ui/widget/dialogue.h" -#include +#include "ui/modals/login.h" + void event_loop(app_t *app); @@ -27,10 +28,8 @@ int main(int argc, char **argv) { // temporal app->modal.active = login; - dialogue_t *dialogue = init_dialogue("Login", - "Select your login " - "option", - 50, 20); + + dialogue_t *dialogue = init_login_modal(); draw_dialogue(dialogue, app->cur_x, app->cur_y); event_loop(app); diff --git a/src/ui/modals/login.c b/src/ui/modals/login.c new file mode 100644 index 0000000..9ea4adf --- /dev/null +++ b/src/ui/modals/login.c @@ -0,0 +1,28 @@ +#include "../widget/dialogue.h" +#include "../widget/group.h" +#include + +typedef struct { + button_t *element; + enum w_type type; +} group_bt_t; + +/* TODO: improve init process (make it more readable) */ + +dialogue_t *init_login_modal() { + group_el_t children[] = {{.type = w_button}, + {.type = w_button}, + {.type = w_button}, + {.type = w_end}}; + + dialogue_t *d = init_dialogue("Login", + "Select your login " + "option", + 50, 20); + d->ch_group = init_group(children); + group_bt_t *ch_btns = (group_bt_t *)d->ch_group->elements; + strcpy(ch_btns[0].element->w.title, "Anonymous"); + strcpy(ch_btns[1].element->w.title, "User"); + strcpy(ch_btns[2].element->w.title, "Register"); + return d; +} \ No newline at end of file diff --git a/src/ui/modals/login.h b/src/ui/modals/login.h new file mode 100644 index 0000000..54cefcd --- /dev/null +++ b/src/ui/modals/login.h @@ -0,0 +1,7 @@ +#ifndef LOGIN_MODAL_H +#define LOGIN_MODAL_H + +#include "../widget/dialogue.h" +dialogue_t *init_login_modal(); + +#endif \ No newline at end of file diff --git a/src/ui/widget.h b/src/ui/widget.h index 110b48e..3fb6539 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h @@ -2,16 +2,23 @@ #define WIDGET_H #include "../main.h" -#include #include +#include + +enum w_type { + w_button, + w_box, + w_group, + w_end, +}; typedef struct { + uint32_t id; char title[DIALOGUE_TITLE]; uint32_t x; uint32_t y; uint32_t m_x; uint32_t m_y; - char color_pair; } widget_t; enum pmt_attrs { @@ -23,4 +30,6 @@ int32_t get_max_line_len(const char *text); uint32_t print_multiline_text(WINDOW *win, const char *text, const uint32_t win_width, const uint32_t y, const uint32_t x, const uint16_t attrs); + +typedef void (*callback_t) (widget_t*, void*); #endif \ No newline at end of file diff --git a/src/ui/widget/button.c b/src/ui/widget/button.c new file mode 100644 index 0000000..2328d43 --- /dev/null +++ b/src/ui/widget/button.c @@ -0,0 +1,38 @@ +#include "button.h" +#include +#include +#include + +button_t *init_button() { + button_t *btn = malloc(sizeof(button_t)); + btn->is_disabled = 0; + btn->is_focused = 0; + btn->is_hovered = 0; + btn->callback = NULL; + return btn; +} + +int32_t draw_button(WINDOW *win, button_t *btn, uint32_t cur_x, uint32_t cur_y) { + char title[DIALOGUE_TITLE + 6]; + + if (btn->is_focused) { + sprintf(title, "[< %s >]", btn->w.title); + } else { + sprintf(title, "[ %s ]", btn->w.title); + } + + if (btn->is_hovered) { + wattrset(win, COLOR_PAIR(1) | A_BOLD | A_REVERSE); + } else { + wattrset(win, COLOR_PAIR(1) | A_BOLD); + } + + mvwprintw(win, cur_y, cur_x, "%s", title); + + wattroff(win, A_REVERSE | A_BOLD); + return strlen(title); +} + +void destroy_button(button_t *btn) { + free(btn); +} \ No newline at end of file diff --git a/src/ui/widget/button.h b/src/ui/widget/button.h index 524c0e7..398c637 100644 --- a/src/ui/widget/button.h +++ b/src/ui/widget/button.h @@ -6,10 +6,15 @@ #include typedef struct { - widget_t widget; - char value; + widget_t w; + char hotkey; uint32_t is_focused : 1; uint32_t is_disabled : 1; + uint32_t is_hovered : 1; + callback_t *callback; } button_t; +button_t *init_button(); +int32_t draw_button(WINDOW *win, button_t *btn, uint32_t cur_x, uint32_t cur_y); +void destroy_button(button_t *btn); #endif \ No newline at end of file diff --git a/src/ui/widget/dialogue.c b/src/ui/widget/dialogue.c index c9b5a3e..413aa6a 100644 --- a/src/ui/widget/dialogue.c +++ b/src/ui/widget/dialogue.c @@ -1,5 +1,6 @@ #include "dialogue.h" #include "../app.h" +#include "group.h" #include #include #include @@ -9,7 +10,7 @@ dialogue_t *init_dialogue(const char title[], const char text[], const uint32_t width, const uint32_t height) { dialogue_t *dialogue = malloc(sizeof(dialogue_t)); dialogue->win = 0; - dialogue->buttons = NULL; + dialogue->ch_group = NULL; dialogue->w.x = width; dialogue->w.y = height; strcpy(dialogue->w.title, title); @@ -23,7 +24,6 @@ int32_t draw_dialogue(dialogue_t *d, uint32_t cur_x, uint32_t cur_y) { d->win = newwin(d->w.y, d->w.x, d->w.m_y, d->w.m_x); - color_set(MODAL_COLOR_PAIR, NULL); wattrset(d->win, COLOR_PAIR(MODAL_COLOR_PAIR) | A_BOLD | A_REVERSE); /* background */ @@ -43,6 +43,8 @@ int32_t draw_dialogue(dialogue_t *d, uint32_t cur_x, uint32_t cur_y) { /* text */ print_multiline_text(d->win, d->text, d->w.x, 1, 1, PMT_ALIGN_CENTER); wattroff(d->win, A_REVERSE); + // temp!!! + draw_group(d->win, d->ch_group, 1, 4); wrefresh(d->win); return 0; diff --git a/src/ui/widget/dialogue.h b/src/ui/widget/dialogue.h index 7c0a20e..242b147 100644 --- a/src/ui/widget/dialogue.h +++ b/src/ui/widget/dialogue.h @@ -4,11 +4,12 @@ #include #include "../widget.h" #include "button.h" +#include "group.h" typedef struct { WINDOW *win; widget_t w; - button_t *buttons; // ! should be NULL-terminated + group_t *ch_group; char text[DIALOGUE_TEXT]; } dialogue_t; diff --git a/src/ui/widget/group.c b/src/ui/widget/group.c new file mode 100644 index 0000000..3a24288 --- /dev/null +++ b/src/ui/widget/group.c @@ -0,0 +1,69 @@ +#include "group.h" +#include "button.h" +#include +#include +#include +#include + +group_t *init_group(group_el_t *children) { + group_t *group = malloc(sizeof(group_t)); + + /* count elements */ + uint32_t count = 0; + for (count = 0; children[count].type != w_end; count++) + ; + count++; /* TODO: improve counting */ + group->elements = malloc(sizeof(group_el_t) * count); + memcpy(group->elements, children, sizeof(group_el_t) * count); + + /* init child elements */ + for (int i = 0; group->elements[i].type != w_end; i++) { + group_el_t *el = &(group->elements)[i]; + switch (el->type) { + case w_button: + el->element = init_button(); + break; + case w_box: + case w_group: + case w_end: + break; + } + } + group->direction = horizontal; /* horizontal by default */ + return group; +} + +void draw_group(WINDOW *win, group_t *group, uint32_t cur_x, uint32_t cur_y) { + group_el_t *children = group->elements; + int32_t x_used = 0; /* used space */ + for (int i = 0; children[i].type != w_end; i++) { + group_el_t *el = &children[i]; + switch (el->type) { + case w_button: + x_used += draw_button(win, (button_t *)el->element, cur_x + x_used + 1 * i, cur_y); + break; + case w_box: + case w_group: + case w_end: + break; + } + } +} + +void destroy_group(group_t *group) { + group_el_t *children = group->elements; + for (int i = 0; children[i].type != w_end; i++) { + group_el_t *el = &children[i]; + switch (el->type) { + case w_button: + destroy_button(el->element); + break; + case w_box: + case w_group: + case w_end: + break; + } + } + free(group->elements); + free(group); +} \ No newline at end of file diff --git a/src/ui/widget/group.h b/src/ui/widget/group.h new file mode 100644 index 0000000..93a6291 --- /dev/null +++ b/src/ui/widget/group.h @@ -0,0 +1,27 @@ +#ifndef GROUP_H +#define GROUP_H + +#include "../widget.h" + +enum g_direction { + horizontal, + vertical, +}; + +typedef struct { + void *element; + enum w_type type; +} group_el_t; + +typedef struct { + group_el_t *elements; + widget_t w; + uint32_t w_active_id; + enum g_direction direction; +} group_t; + +group_t *init_group(group_el_t *children); +void draw_group(WINDOW *win, group_t *group, uint32_t cur_x, uint32_t cur_y); +void destroy_group(group_t *group); + +#endif \ No newline at end of file