text input box
This commit is contained in:
parent
6d2594db2d
commit
972c9b581d
@ -138,7 +138,7 @@ fn void? Ctx.push_sprite(&ctx, Rect bounds, Rect texture, Id texture_id, int z_i
|
|||||||
ctx.push_cmd(&cmd, z_index)!;
|
ctx.push_cmd(&cmd, z_index)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void? Ctx.push_string(&ctx, Rect bounds, String text, int z_index, Color hue = 0xffffffffu.to_rgba())
|
fn void? Ctx.push_string(&ctx, Rect bounds, char[] text, int z_index, Color hue = 0xffffffffu.to_rgba())
|
||||||
{
|
{
|
||||||
if (text.len == 0) {
|
if (text.len == 0) {
|
||||||
return;
|
return;
|
||||||
@ -158,7 +158,7 @@ fn void? Ctx.push_string(&ctx, Rect bounds, String text, int z_index, Color hue
|
|||||||
short line_len;
|
short line_len;
|
||||||
Codepoint cp;
|
Codepoint cp;
|
||||||
usz off, x;
|
usz off, x;
|
||||||
while ((cp = str_to_codepoint(text[off..], &x)) != 0) {
|
while (off < text.len && (cp = str_to_codepoint(text[off..], &x)) != 0) {
|
||||||
off += x;
|
off += x;
|
||||||
Glyph* gp;
|
Glyph* gp;
|
||||||
if (!ascii::is_cntrl((char)cp)) {
|
if (!ascii::is_cntrl((char)cp)) {
|
||||||
|
@ -34,6 +34,7 @@ bitstruct ElemEvents : uint {
|
|||||||
bool mouse_release : 5;
|
bool mouse_release : 5;
|
||||||
bool mouse_hold : 6;
|
bool mouse_hold : 6;
|
||||||
bool update : 7;
|
bool update : 7;
|
||||||
|
bool text_input : 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
// element structure
|
// element structure
|
||||||
@ -111,7 +112,7 @@ struct Ctx {
|
|||||||
struct keyboard {
|
struct keyboard {
|
||||||
char[TEXT_MAX] text;
|
char[TEXT_MAX] text;
|
||||||
usz text_len;
|
usz text_len;
|
||||||
ModKeys down;
|
ModKeys modkeys;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,6 +344,7 @@ fn ElemEvents Ctx.get_elem_events(&ctx, Elem *elem)
|
|||||||
.mouse_press = hover && focus && ctx.is_mouse_pressed(BTN_ANY),
|
.mouse_press = hover && focus && ctx.is_mouse_pressed(BTN_ANY),
|
||||||
.mouse_release = hover && focus && ctx.is_mouse_released(BTN_ANY),
|
.mouse_release = hover && focus && ctx.is_mouse_released(BTN_ANY),
|
||||||
.mouse_hold = hover && focus && ctx.is_mouse_down(BTN_ANY),
|
.mouse_hold = hover && focus && ctx.is_mouse_down(BTN_ANY),
|
||||||
|
.text_input = focus && (ctx.input.keyboard.text_len || ctx.input.keyboard.modkeys & KMOD_TXT),
|
||||||
};
|
};
|
||||||
return ev;
|
return ev;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ bitstruct MouseButtons : uint {
|
|||||||
|
|
||||||
// FIXME: all of these names were prefixed with key_ idk if this is better,
|
// FIXME: all of these names were prefixed with key_ idk if this is better,
|
||||||
// if it is remove the prefix on MouseButtons as well
|
// if it is remove the prefix on MouseButtons as well
|
||||||
// Modifier Keys, same as SDL
|
// Modifier Keys, intended as any key that is not text
|
||||||
bitstruct ModKeys : uint {
|
bitstruct ModKeys : uint {
|
||||||
bool lshift : 0;
|
bool lshift : 0;
|
||||||
bool rshift : 1;
|
bool rshift : 1;
|
||||||
@ -39,12 +39,20 @@ bitstruct ModKeys : uint {
|
|||||||
bool caps : 9;
|
bool caps : 9;
|
||||||
bool mode : 10;
|
bool mode : 10;
|
||||||
bool scroll : 11;
|
bool scroll : 11;
|
||||||
|
bool bkspc : 12;
|
||||||
|
bool del : 13;
|
||||||
|
// arrow keys
|
||||||
|
bool up : 14;
|
||||||
|
bool down : 15;
|
||||||
|
bool left : 16;
|
||||||
|
bool right : 17;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ModKeys KMOD_CTRL = {.lctrl = true, .rctrl = true};
|
const ModKeys KMOD_CTRL = {.lctrl = true, .rctrl = true};
|
||||||
const ModKeys KMOD_SHIFT = {.lshift = true, .rshift = true};
|
const ModKeys KMOD_SHIFT = {.lshift = true, .rshift = true};
|
||||||
const ModKeys KMOD_ALT = {.lalt = true, .ralt = true};
|
const ModKeys KMOD_ALT = {.lalt = true, .ralt = true};
|
||||||
const ModKeys KMOD_GUI = {.lgui = true, .rgui = true};
|
const ModKeys KMOD_GUI = {.lgui = true, .rgui = true};
|
||||||
|
const ModKeys KMOD_TXT = {.bkspc = true, .del = true}; // modkeys that act like text input
|
||||||
const ModKeys KMOD_NONE = {};
|
const ModKeys KMOD_NONE = {};
|
||||||
const ModKeys KMOD_ANY = (ModKeys)(ModKeys.inner.max);
|
const ModKeys KMOD_ANY = (ModKeys)(ModKeys.inner.max);
|
||||||
|
|
||||||
@ -60,7 +68,7 @@ const ModKeys KEY_ANY = (ModKeys)(ModKeys.inner.max);
|
|||||||
|
|
||||||
fn bool Ctx.check_key_combo(&ctx, ModKeys mod, String keys)
|
fn bool Ctx.check_key_combo(&ctx, ModKeys mod, String keys)
|
||||||
{
|
{
|
||||||
bool is_mod = (bool)(ctx.input.keyboard.down & mod);
|
bool is_mod = (bool)(ctx.input.keyboard.modkeys & mod);
|
||||||
bool is_keys = true;
|
bool is_keys = true;
|
||||||
String haystack = (String)ctx.input.keyboard.text[0..ctx.input.keyboard.text_len];
|
String haystack = (String)ctx.input.keyboard.text[0..ctx.input.keyboard.text_len];
|
||||||
char[2] needle;
|
char[2] needle;
|
||||||
@ -187,9 +195,10 @@ fn void Ctx.input_char(&ctx, char c)
|
|||||||
ctx.input_text_utf8(b[..]);
|
ctx.input_text_utf8(b[..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mouse Buttons down
|
// Modifier keys, like control or backspace
|
||||||
|
// TODO: make this call repetible to input modkeys one by one
|
||||||
fn void Ctx.input_mod_keys(&ctx, ModKeys modkeys)
|
fn void Ctx.input_mod_keys(&ctx, ModKeys modkeys)
|
||||||
{
|
{
|
||||||
ctx.input.keyboard.down = modkeys;
|
ctx.input.keyboard.modkeys = modkeys;
|
||||||
ctx.input.events.mod_key = (uint)ctx.input.keyboard.down != 0;
|
ctx.input.events.mod_key = (uint)ctx.input.keyboard.modkeys != 0;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,8 @@ module ugui;
|
|||||||
import std::io;
|
import std::io;
|
||||||
|
|
||||||
struct ElemText {
|
struct ElemText {
|
||||||
char* str;
|
char[] str;
|
||||||
|
usz cursor; // cursor offset
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void? Ctx.text_unbounded(&ctx, String label, String text)
|
fn void? Ctx.text_unbounded(&ctx, String label, String text)
|
||||||
@ -28,3 +29,66 @@ fn void? Ctx.text_unbounded(&ctx, String label, String text)
|
|||||||
|
|
||||||
ctx.push_string(elem.bounds, text, parent.div.z_index)!;
|
ctx.push_string(elem.bounds, text, parent.div.z_index)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ElemEvents? Ctx.text_box(&ctx, String label, Rect size, char[] text, usz* text_len)
|
||||||
|
{
|
||||||
|
Id id = ctx.gen_id(label)!;
|
||||||
|
|
||||||
|
Elem *parent = ctx.get_parent()!;
|
||||||
|
Elem *elem = ctx.get_elem(id)!;
|
||||||
|
// add it to the tree
|
||||||
|
ctx.tree.add(id, ctx.active_div)!;
|
||||||
|
|
||||||
|
// 1. Fill the element fields
|
||||||
|
// this resets the flags
|
||||||
|
elem.type = ETYPE_TEXT;
|
||||||
|
elem.text.str = text;
|
||||||
|
|
||||||
|
// layout the text box
|
||||||
|
elem.bounds = ctx.position_element(parent, size, true);
|
||||||
|
|
||||||
|
// check input and update the text
|
||||||
|
elem.events = ctx.get_elem_events(elem);
|
||||||
|
|
||||||
|
if (elem.events.text_input) {
|
||||||
|
usz l = ctx.input.keyboard.text_len;
|
||||||
|
char[] t = ctx.input.keyboard.text[..l];
|
||||||
|
|
||||||
|
if (l != 0 && l < text.len - *text_len) {
|
||||||
|
text[*text_len..*text_len+l] = t[..];
|
||||||
|
*text_len += l;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.input.keyboard.modkeys.bkspc) {
|
||||||
|
*text_len = *text_len > 0 ? *text_len-1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
elem.text.cursor = *text_len;
|
||||||
|
|
||||||
|
// draw the box
|
||||||
|
short line_height = (short)ctx.font.line_height();
|
||||||
|
Rect text_box = elem.bounds.sub({0,0,0,line_height});
|
||||||
|
Rect input_box = {
|
||||||
|
.x = elem.bounds.x,
|
||||||
|
.y = elem.bounds.y + elem.bounds.h - line_height,
|
||||||
|
.w = elem.bounds.w,
|
||||||
|
.h = line_height,
|
||||||
|
};
|
||||||
|
Rect cursor;
|
||||||
|
Point b = ctx.get_cursor_position((String)text[:elem.text.cursor])!;
|
||||||
|
cursor = {
|
||||||
|
.x = b.x,
|
||||||
|
.y = b.y,
|
||||||
|
.w = 3,
|
||||||
|
.h = line_height,
|
||||||
|
};
|
||||||
|
cursor = cursor.off(elem.bounds.position());
|
||||||
|
|
||||||
|
ctx.push_rect(text_box, 0xabababffu.to_rgba(), parent.div.z_index, do_border: true)!;
|
||||||
|
ctx.push_string(text_box, text[:*text_len], parent.div.z_index)!;
|
||||||
|
ctx.push_rect(input_box, 0x424242ffu.to_rgba(), parent.div.z_index)!;
|
||||||
|
ctx.push_rect(cursor, 0x00000042u.to_rgba(), parent.div.z_index)!;
|
||||||
|
|
||||||
|
return elem.events;
|
||||||
|
}
|
||||||
|
24
src/main.c3
24
src/main.c3
@ -62,9 +62,9 @@ fn int main(String[] args)
|
|||||||
defer ui.free();
|
defer ui.free();
|
||||||
|
|
||||||
ren::Renderer ren;
|
ren::Renderer ren;
|
||||||
ren.init("Ugui Test", 640, 480, true);
|
ren.init("Ugui Test", 800, 600, true);
|
||||||
defer ren.free();
|
defer ren.free();
|
||||||
ui.input_window_size(640, 480)!!;
|
ui.input_window_size(800, 600)!!;
|
||||||
|
|
||||||
//
|
//
|
||||||
// FONT LOADING
|
// FONT LOADING
|
||||||
@ -145,6 +145,7 @@ fn int main(String[] args)
|
|||||||
case EVENT_KEY_DOWN:
|
case EVENT_KEY_DOWN:
|
||||||
mod.rctrl = e.key.key == K_RCTRL ? !!(e.type == EVENT_KEY_DOWN) : mod.rctrl;
|
mod.rctrl = e.key.key == K_RCTRL ? !!(e.type == EVENT_KEY_DOWN) : mod.rctrl;
|
||||||
mod.lctrl = e.key.key == K_LCTRL ? !!(e.type == EVENT_KEY_DOWN) : mod.lctrl;
|
mod.lctrl = e.key.key == K_LCTRL ? !!(e.type == EVENT_KEY_DOWN) : mod.lctrl;
|
||||||
|
mod.bkspc = e.key.key == K_BACKSPACE ? !!(e.type == EVENT_KEY_DOWN) : mod.bkspc;
|
||||||
|
|
||||||
// pressing ctrl+key or alt+key does not generate a character as such no
|
// pressing ctrl+key or alt+key does not generate a character as such no
|
||||||
// TEXT_INPUT event is generated. When those keys are pressed we have to
|
// TEXT_INPUT event is generated. When those keys are pressed we have to
|
||||||
@ -155,6 +156,8 @@ fn int main(String[] args)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e.type == EVENT_KEY_DOWN && e.key.key == K_RETURN) ui.input_char('\n');
|
||||||
|
|
||||||
case EVENT_TEXT_INPUT:
|
case EVENT_TEXT_INPUT:
|
||||||
ui.input_text_utf8(e.text.text.str_view());
|
ui.input_text_utf8(e.text.text.str_view());
|
||||||
case EVENT_WINDOW_RESIZED:
|
case EVENT_WINDOW_RESIZED:
|
||||||
@ -226,19 +229,13 @@ fn int main(String[] args)
|
|||||||
static bool check;
|
static bool check;
|
||||||
ui.checkbox("check1", "", {}, &check, "tick")!!;
|
ui.checkbox("check1", "", {}, &check, "tick")!!;
|
||||||
ui.toggle("toggle1", "", {}, &toggle)!!;
|
ui.toggle("toggle1", "", {}, &toggle)!!;
|
||||||
|
|
||||||
/*
|
|
||||||
ui.layout_set_column()!!;
|
|
||||||
ui.button_label(" A ")!!;
|
|
||||||
ui.button_label(" B ")!!;
|
|
||||||
ui.layout_next_column()!!;
|
|
||||||
ui.button_label(" C ")!!;
|
|
||||||
ui.button_label(" D ")!!;
|
|
||||||
ui.layout_next_row()!!;
|
|
||||||
ui.button_label(" E ")!!;
|
|
||||||
*/
|
|
||||||
};
|
};
|
||||||
ui.draw_sprite("sprite1", "tux")!!;
|
ui.draw_sprite("sprite1", "tux")!!;
|
||||||
|
|
||||||
|
static char[128] text_box = "ciao mamma";
|
||||||
|
static usz text_len = "ciao mamma".len;
|
||||||
|
ui.text_box("text input", {0,0,200,200}, text_box[..], &text_len)!!;
|
||||||
|
|
||||||
ui.div_end()!!;
|
ui.div_end()!!;
|
||||||
|
|
||||||
ui.div_begin("second", ugui::DIV_FILL, scroll_x: true, scroll_y: true)!!;
|
ui.div_begin("second", ugui::DIV_FILL, scroll_x: true, scroll_y: true)!!;
|
||||||
@ -280,7 +277,6 @@ fn int main(String[] args)
|
|||||||
};
|
};
|
||||||
ui.div_end()!!;
|
ui.div_end()!!;
|
||||||
|
|
||||||
|
|
||||||
ui.frame_end()!!;
|
ui.frame_end()!!;
|
||||||
/* End UI Handling */
|
/* End UI Handling */
|
||||||
ui_times.push(clock.mark());
|
ui_times.push(clock.mark());
|
||||||
|
Loading…
Reference in New Issue
Block a user