aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi.dcr@tutanota.com>2022-09-20 17:22:10 +0200
committerXavier Del Campo Romero <xavi.dcr@tutanota.com>2022-09-20 17:34:25 +0200
commit8f9737b776bf98d0686a2f11685d1e307b2ef390 (patch)
tree261c2e64e6af535d7428ef57f9ea41e591ebbb68
parente3356fde2de41b29989b4e8884f04b2be763256f (diff)
Implement GUI line edit
-rw-r--r--res/CMakeLists.txt27
-rw-r--r--res/LICENSE6
-rw-r--r--res/line_edit_left.bmpbin0 -> 250 bytes
-rw-r--r--res/line_edit_left_24.bmpbin0 -> 654 bytes
-rw-r--r--res/line_edit_mid.bmpbin0 -> 546 bytes
-rw-r--r--res/line_edit_mid_24.bmpbin0 -> 2454 bytes
-rw-r--r--res/line_edit_right.bmpbin0 -> 250 bytes
-rw-r--r--res/line_edit_right_24.bmpbin0 -> 654 bytes
-rw-r--r--src/game/src/res.c28
-rw-r--r--src/gui/CMakeLists.txt1
-rw-r--r--src/gui/inc/gui/line_edit.h47
-rw-r--r--src/gui/src/line_edit.c195
12 files changed, 304 insertions, 0 deletions
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
--- /dev/null
+++ b/res/line_edit_left.bmp
Binary files differ
diff --git a/res/line_edit_left_24.bmp b/res/line_edit_left_24.bmp
new file mode 100644
index 0000000..f8f2b2b
--- /dev/null
+++ b/res/line_edit_left_24.bmp
Binary files differ
diff --git a/res/line_edit_mid.bmp b/res/line_edit_mid.bmp
new file mode 100644
index 0000000..656832a
--- /dev/null
+++ b/res/line_edit_mid.bmp
Binary files differ
diff --git a/res/line_edit_mid_24.bmp b/res/line_edit_mid_24.bmp
new file mode 100644
index 0000000..a4c7b1e
--- /dev/null
+++ b/res/line_edit_mid_24.bmp
Binary files differ
diff --git a/res/line_edit_right.bmp b/res/line_edit_right.bmp
new file mode 100644
index 0000000..ecbc24e
--- /dev/null
+++ b/res/line_edit_right.bmp
Binary files differ
diff --git a/res/line_edit_right_24.bmp b/res/line_edit_right_24.bmp
new file mode 100644
index 0000000..6cc59d4
--- /dev/null
+++ b/res/line_edit_right_24.bmp
Binary files 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 <gfx.h>
#include <gui/bar.h>
#include <gui/button.h>
+#include <gui/line_edit.h>
#include <gui/rounded_rect.h>
#include <resource.h>
#include <terrain.h>
@@ -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 <gui.h>
+#include <gui/label.h>
+#include <gfx.h>
+#include <util.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#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 <gui.h>
+#include <gui_private.h>
+#include <gui/label.h>
+#include <gui/line_edit.h>
+#include <camera.h>
+#include <gfx.h>
+#include <input.h>
+#include <mouse.h>
+#include <pad.h>
+#include <peripheral.h>
+#include <string.h>
+
+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);
+}