From 8f9737b776bf98d0686a2f11685d1e307b2ef390 Mon Sep 17 00:00:00 2001 From: Xavier Del Campo Romero Date: Tue, 20 Sep 2022 17:22:10 +0200 Subject: [PATCH] Implement GUI line edit --- res/CMakeLists.txt | 27 +++++ res/LICENSE | 6 ++ res/line_edit_left.bmp | Bin 0 -> 250 bytes res/line_edit_left_24.bmp | Bin 0 -> 654 bytes res/line_edit_mid.bmp | Bin 0 -> 546 bytes res/line_edit_mid_24.bmp | Bin 0 -> 2454 bytes res/line_edit_right.bmp | Bin 0 -> 250 bytes res/line_edit_right_24.bmp | Bin 0 -> 654 bytes src/game/src/res.c | 28 ++++++ src/gui/CMakeLists.txt | 1 + src/gui/inc/gui/line_edit.h | 47 +++++++++ src/gui/src/line_edit.c | 195 ++++++++++++++++++++++++++++++++++++ 12 files changed, 304 insertions(+) create mode 100644 res/line_edit_left.bmp create mode 100644 res/line_edit_left_24.bmp create mode 100644 res/line_edit_mid.bmp create mode 100644 res/line_edit_mid_24.bmp create mode 100644 res/line_edit_right.bmp create mode 100644 res/line_edit_right_24.bmp create mode 100644 src/gui/inc/gui/line_edit.h create mode 100644 src/gui/src/line_edit.c diff --git a/res/CMakeLists.txt b/res/CMakeLists.txt index ff4f923..d77daaf 100644 --- a/res/CMakeLists.txt +++ b/res/CMakeLists.txt @@ -184,6 +184,30 @@ sprite(NAME btn_mid CY 493 TRANSPARENT FALSE) +sprite(NAME line_edit_left + X 368 + Y 148 + BPP 4 + CX 368 + CY 492 + TRANSPARENT FALSE) + +sprite(NAME line_edit_mid + X 370 + Y 148 + BPP 4 + CX 368 + CY 491 + TRANSPARENT FALSE) + +sprite(NAME line_edit_right + X 378 + Y 148 + BPP 4 + CX 368 + CY 491 + TRANSPARENT FALSE) + sound(NAME acknowledge_01) sound(NAME acknowledge_02) sound(NAME selected_01) @@ -213,6 +237,9 @@ container(NAME rts sel_down_right sel_mid sel_mid_v + line_edit_left + line_edit_mid + line_edit_right SOUNDS acknowledge_01 acknowledge_02 diff --git a/res/LICENSE b/res/LICENSE index 1c85acb..e252ace 100644 --- a/res/LICENSE +++ b/res/LICENSE @@ -51,6 +51,12 @@ btn_mid.bmp: btn_mid_24.bmp: btn_right.bmp: btn_right_24.bmp: +line_edit_left.bmp: +line_edit_left_24.bmp: +line_edit_mid.bmp: +line_edit_mid_24.bmp: +line_edit_right.bmp: +line_edit_right_24.bmp: Derived works from ui_sheet.png font.bmp: diff --git a/res/line_edit_left.bmp b/res/line_edit_left.bmp new file mode 100644 index 0000000000000000000000000000000000000000..f81cac5fd5c51a11a6dfc1995aec3bde91d2f383 GIT binary patch literal 250 zcmZ?r{lx$Q(|}YC5OV;rBoH$)umDL0h7=&)zz@OfKsE?Fxd#;kDUtvanrd!7AqEi% z1qLNGeFj}aD+UWE4+a;n2nLtH2nJ&y04Zk@6cl7t4Gm=#U|?VsNK0cCa3d4DxPZ+7 LnHL%w3Njl2?>re) literal 0 HcmV?d00001 diff --git a/res/line_edit_left_24.bmp b/res/line_edit_left_24.bmp new file mode 100644 index 0000000000000000000000000000000000000000..f8f2b2b00e93985858cc74fd197c1a5932b7762e GIT binary patch literal 654 zcmZ?r?PFp912Z700mK|YED6Mn3=%++fgu7Yzkwfu!2&=+*U$jlc(GVC7fzc2cgdt$z-vSJl`qh6npVC*!)YBp0IjM` Aga7~l literal 0 HcmV?d00001 diff --git a/res/line_edit_right.bmp b/res/line_edit_right.bmp new file mode 100644 index 0000000000000000000000000000000000000000..ecbc24e49fcf08f92ac63b7bdb59c1c206ebe7dd GIT binary patch literal 250 zcmZ?r{lx$Q(|}YC5OV;rBoH$)umDL0h7=&)zz@OfKsE?Fxd#;kDUtvanrd!7AqEi% z1qLNGeFj}aD+UWE4+a;n2nLtH2nJ&y04Wy~6ch*z4HaNuU=>J9BOklCv4YJI6chrP IrvNe=0CjI0h5!Hn literal 0 HcmV?d00001 diff --git a/res/line_edit_right_24.bmp b/res/line_edit_right_24.bmp new file mode 100644 index 0000000000000000000000000000000000000000..6cc59d4075a29fdcdfd849cfcf3afb9fa5f2f6f1 GIT binary patch literal 654 zcmZ?r?PFp912Z700mK|YED6Mn3=%++fgu7Yzkwfu!2&=+*U$ #include #include +#include #include #include #include @@ -246,6 +247,33 @@ static const struct container c[] = .sprite = &gui_button_sprites[GUI_BUTTON_RIGHT] } }, + + { + .path = "line_edit_left", + .type = CONTAINER_TYPE_SPRITE, + .data = + { + .sprite = &gui_line_edit_sprites[GUI_LINE_EDIT_LEFT] + } + }, + + { + .path = "line_edit_mid", + .type = CONTAINER_TYPE_SPRITE, + .data = + { + .sprite = &gui_line_edit_sprites[GUI_LINE_EDIT_MID] + } + }, + + { + .path = "line_edit_right", + .type = CONTAINER_TYPE_SPRITE, + .data = + { + .sprite = &gui_line_edit_sprites[GUI_LINE_EDIT_RIGHT] + } + } }; static bool init; diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 6ff3a71..f96d927 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -5,6 +5,7 @@ add_library(gui "src/container.c" "src/gui.c" "src/label.c" + "src/line_edit.c" "src/progress_bar.c" "src/rounded_rect.c" ) diff --git a/src/gui/inc/gui/line_edit.h b/src/gui/inc/gui/line_edit.h new file mode 100644 index 0000000..3a0f027 --- /dev/null +++ b/src/gui/inc/gui/line_edit.h @@ -0,0 +1,47 @@ +#ifndef GUI_LINE_EDIT_H +#define GUI_LINE_EDIT_H + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +struct gui_line_edit +{ + struct gui_common common; + struct gui_label label; + short w; + bool focus, blink; + unsigned blt; + char *text; + size_t i, sz; +}; + +void gui_line_edit_init(struct gui_line_edit *l, char *buf, size_t sz); + +UTIL_STATIC_ASSERT(!offsetof(struct gui_line_edit, common), + "unexpected offset for struct gui_line_edit"); + +enum +{ + GUI_LINE_EDIT_LEFT, + GUI_LINE_EDIT_MID, + GUI_LINE_EDIT_RIGHT, + + MAX_GUI_LINE_EDIT_SPRITES +}; + +extern struct sprite gui_line_edit_sprites[MAX_GUI_LINE_EDIT_SPRITES]; + +#ifdef __cplusplus +} +#endif + +#endif /* GUI_LINE_EDIT_H */ diff --git a/src/gui/src/line_edit.c b/src/gui/src/line_edit.c new file mode 100644 index 0000000..a5c01a7 --- /dev/null +++ b/src/gui/src/line_edit.c @@ -0,0 +1,195 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct sprite gui_line_edit_sprites[MAX_GUI_LINE_EDIT_SPRITES]; + +/* Alias for readability. */ +static const struct sprite *const refs = gui_line_edit_sprites; + +static int render_left(const struct gui_line_edit *const l, + short *const x, const short y) +{ + sprite_get_or_ret(s, -1); + + if (sprite_clone(&refs[GUI_LINE_EDIT_LEFT], s)) + return -1; + + s->x = *x; + s->y = y; + sprite_sort(s); + *x = s->x + s->w; + return 0; +} + +static int render_mid(const struct gui_line_edit *const l, + short *const x, const short y) +{ + const short mid_w = refs[GUI_LINE_EDIT_MID].w, + lw = refs[GUI_LINE_EDIT_LEFT].w, + rw = refs[GUI_LINE_EDIT_RIGHT].w, + w = l->w - lw - rw; + + if (w > 0) + { + const short rem_mid = w > 0 ? w % mid_w : 0, + whole_mid = w / mid_w, + n_mid = rem_mid ? whole_mid + 1 : whole_mid; + + for (struct + { + size_t i; + short x; + } a = {.x = lw}; + a.i < n_mid; + a.i++, a.x += mid_w) + { + sprite_get_or_ret(m, -1); + + if (sprite_clone(&refs[GUI_LINE_EDIT_MID], m)) + return -1; + + m->x = *x; + m->y = y; + + if (rem_mid && a.i + 1 == n_mid) + m->w = rem_mid; + else + m->w = mid_w; + + sprite_sort(m); + *x += m->w; + } + } + else + return -1; + + return 0; +} + +static int render_right(const short x, const short y) +{ + sprite_get_or_ret(s, -1); + + if (sprite_clone(&refs[GUI_LINE_EDIT_RIGHT], s)) + return -1; + + s->x = x; + s->y = y; + sprite_sort(s); + return 0; +} + +static int render(const struct gui_common *const g) +{ + const struct gui_line_edit *const l = (const struct gui_line_edit *)g; + short x, y; + + gui_coords(&l->common, &x, &y); + + if (render_left(l, &x, y) + || render_mid(l, &x, y) + || render_right(x, y)) + return -1; + + return 0; +} + +static void get_dim(const struct gui_common *const g, + short *const w, short *const h) +{ + struct gui_line_edit *const l = (struct gui_line_edit *)g; + + *w = l->w; + *h = refs->h; +} + +static void on_char(const char ch, void *const user) +{ + struct gui_line_edit *const l = user; + + if (l->i + 1 < l->sz) + l->text[l->i++] = ch; +} + +static void on_erase(void *const user) +{ + struct gui_line_edit *const l = user; + + if (l->i) + l->text[--l->i] = '\0'; +} + +static int update(struct gui_common *const g, + const union peripheral *const p, const struct camera *const c, + struct input *const in) +{ + struct gui_line_edit *const l = (struct gui_line_edit *)g; + + if (gui_pressed(&l->common, in, p, c, l->w, refs->h)) + { + l->focus = true; + + *in = (const struct input) + { + .cb = on_char, + .erase = on_erase, + .user = l + }; + } + else if (l->focus && gui_released(&l->common, p, c, l->w, refs->h)) + { + l->focus = false; + + if (in->user == l) + *in = (const struct input){0}; + } + + return 0; +} + +static void deinit(struct gui_common *const g, struct input *const in) +{ + struct gui_line_edit *const l = (struct gui_line_edit *)g; + + if (l->focus) + *in = (const struct input){0}; +} + +void gui_line_edit_init(struct gui_line_edit *const l, char *const buf, + const size_t sz) +{ + static const struct gui_common_cb cb = + { + .get_dim = get_dim, + .update = update, + .render = render, + .deinit = deinit + }; + + *l = (const struct gui_line_edit) + { + .common = + { + .cb = &cb + }, + + .text = buf, + .sz = sz + }; + + gui_label_init(&l->label); + memset(l->text, '\0', l->sz); + l->label.common.hcentered = true; + l->label.common.vcentered = true; + l->label.text = l->text; + gui_add_child(&l->common, &l->label.common); +}