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 0000000..f81cac5 Binary files /dev/null and b/res/line_edit_left.bmp differ diff --git a/res/line_edit_left_24.bmp b/res/line_edit_left_24.bmp new file mode 100644 index 0000000..f8f2b2b Binary files /dev/null and b/res/line_edit_left_24.bmp differ diff --git a/res/line_edit_mid.bmp b/res/line_edit_mid.bmp new file mode 100644 index 0000000..656832a Binary files /dev/null and b/res/line_edit_mid.bmp differ diff --git a/res/line_edit_mid_24.bmp b/res/line_edit_mid_24.bmp new file mode 100644 index 0000000..a4c7b1e Binary files /dev/null and b/res/line_edit_mid_24.bmp differ diff --git a/res/line_edit_right.bmp b/res/line_edit_right.bmp new file mode 100644 index 0000000..ecbc24e Binary files /dev/null and b/res/line_edit_right.bmp differ diff --git a/res/line_edit_right_24.bmp b/res/line_edit_right_24.bmp new file mode 100644 index 0000000..6cc59d4 Binary files /dev/null and b/res/line_edit_right_24.bmp differ diff --git a/src/game/src/res.c b/src/game/src/res.c index c41af47..da07f96 100644 --- a/src/game/src/res.c +++ b/src/game/src/res.c @@ -5,6 +5,7 @@ #include #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); +}