rts/src/gui/src/line_edit.c

196 lines
4.1 KiB
C

#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);
}