functional textbox input
This commit is contained in:
parent
c017e93695
commit
ff8f222527
@ -139,6 +139,7 @@ Struct(ControllerEvent)
|
|||||||
b32 is_repeat;
|
b32 is_repeat;
|
||||||
|
|
||||||
// ControllerEventKind_Text
|
// ControllerEventKind_Text
|
||||||
|
u32 text_codepoint;
|
||||||
u32 text_chars_count;
|
u32 text_chars_count;
|
||||||
u8 text_chars[4];
|
u8 text_chars[4];
|
||||||
|
|
||||||
|
|||||||
@ -261,19 +261,20 @@ void V_DrawPoint(Vec2 p, Vec4 srgb)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Text box
|
//~ Text box
|
||||||
|
|
||||||
void V_ApplyTextBoxDelta(V_TextBoxState *tb, V_TextBoxDelta delta)
|
void V_ApplyTextboxDelta(V_TextboxState *tb, V_TextboxDelta delta)
|
||||||
{
|
{
|
||||||
V_TextBoxDeltaNode tbd_node = { .delta = delta };
|
V_TextboxDeltaNode tbd_node = { .delta = delta };
|
||||||
V_ApplyTextBoxDeltas(tb, (V_TextBoxDeltaList) { .first = &tbd_node, .last = &tbd_node });
|
V_ApplyTextboxDeltas(tb, (V_TextboxDeltaList) { .first = &tbd_node, .last = &tbd_node });
|
||||||
}
|
}
|
||||||
|
|
||||||
void V_ApplyTextBoxDeltas(V_TextBoxState *tb, V_TextBoxDeltaList deltas)
|
void V_ApplyTextboxDeltas(V_TextboxState *tb, V_TextboxDeltaList deltas)
|
||||||
{
|
{
|
||||||
for (V_TextBoxDeltaNode *tbd_node = deltas.first; tbd_node; tbd_node = tbd_node->next)
|
TempArena scratch = BeginScratchNoConflict();
|
||||||
|
for (V_TextboxDeltaNode *tbd_node = deltas.first; tbd_node; tbd_node = tbd_node->next)
|
||||||
{
|
{
|
||||||
V_TextBoxDelta delta = tbd_node->delta;
|
V_TextboxDelta delta = tbd_node->delta;
|
||||||
|
|
||||||
// if (!(delta.flags & V_TextBoxDeltaFlag_DontUpdateCursor))
|
// if (!(delta.flags & V_TextboxDeltaFlag_DontUpdateCursor))
|
||||||
// {
|
// {
|
||||||
// tb->start = ClampI64(delta.start, 0, tb->len);
|
// tb->start = ClampI64(delta.start, 0, tb->len);
|
||||||
// tb->end = ClampI64(delta.end, 0, tb->len);
|
// tb->end = ClampI64(delta.end, 0, tb->len);
|
||||||
@ -284,60 +285,81 @@ void V_ApplyTextBoxDeltas(V_TextBoxState *tb, V_TextBoxDeltaList deltas)
|
|||||||
|
|
||||||
// Navigate
|
// Navigate
|
||||||
{
|
{
|
||||||
|
b32 navigated = 0;
|
||||||
|
if (!(delta.flags & V_TextboxDeltaFlag_OnlyNavIfSelectionEmpty) || tb->start == tb->end)
|
||||||
{
|
{
|
||||||
if (delta.flags & V_TextBoxDeltaFlag_NavDirect)
|
if (delta.flags & V_TextboxDeltaFlag_NavDirect)
|
||||||
{
|
{
|
||||||
tb->start = delta.direct_start;
|
navigated = 1;
|
||||||
tb->end = delta.direct_end;
|
tb->start = ClampI64(delta.direct_start, 0, tb->len);
|
||||||
|
tb->end = ClampI64(delta.direct_end, 0, tb->len);
|
||||||
}
|
}
|
||||||
if (delta.flags & V_TextBoxDeltaFlag_NavLeft)
|
if (delta.flags & V_TextboxDeltaFlag_NavLeft)
|
||||||
{
|
{
|
||||||
if (delta.flags & V_TextBoxDeltaFlag_NavLine)
|
navigated = 1;
|
||||||
|
if (delta.flags & V_TextboxDeltaFlag_NavLine)
|
||||||
{
|
{
|
||||||
// FIXME: Real line start
|
// TODO: Real line start
|
||||||
tb->end = 0;
|
tb->end = 0;
|
||||||
}
|
}
|
||||||
else if (delta.flags & V_TextBoxDeltaFlag_NavWord)
|
else if (delta.flags & V_TextboxDeltaFlag_NavWord)
|
||||||
{
|
{
|
||||||
for (i64 pos = ClampI64(tb->end - 1, 0, tb->len); pos >= 0; --pos)
|
if (tb->end > 0 && tb->text[tb->end - 1] == ' ')
|
||||||
{
|
{
|
||||||
tb->end = pos - 1;
|
for (i64 pos = tb->end - 1; pos >= 0 && tb->text[pos] == ' '; --pos)
|
||||||
if (tb->text[pos] == ' ')
|
|
||||||
{
|
{
|
||||||
break;
|
tb->end = pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (i64 pos = tb->end - 1; pos >= 0 && tb->text[pos] != ' '; --pos)
|
||||||
|
{
|
||||||
|
tb->end = pos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tb->end -= 1;
|
tb->end -= 1;
|
||||||
|
// Skip utf-8 continuations
|
||||||
|
// for (i64 pos = tb->end - 1; pos >= 0 && (tb->text[pos] & 0xC0) == 0x80; --pos)
|
||||||
|
// {
|
||||||
|
// tb->end = pos;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (delta.flags & V_TextBoxDeltaFlag_NavRight)
|
if (delta.flags & V_TextboxDeltaFlag_NavRight)
|
||||||
{
|
{
|
||||||
if (delta.flags & V_TextBoxDeltaFlag_NavLine)
|
navigated = 1;
|
||||||
|
if (delta.flags & V_TextboxDeltaFlag_NavLine)
|
||||||
{
|
{
|
||||||
// FIXME: Real line end
|
// TODO: Real line end
|
||||||
tb->end = I64Max;
|
tb->end = I64Max;
|
||||||
}
|
}
|
||||||
else if (delta.flags & V_TextBoxDeltaFlag_NavWord)
|
else if (delta.flags & V_TextboxDeltaFlag_NavWord)
|
||||||
{
|
{
|
||||||
for (i64 pos = ClampI64(tb->end + 1, 0, tb->len); pos < tb->len; ++pos)
|
if (tb->end < tb->len && tb->text[tb->end] == ' ')
|
||||||
|
{
|
||||||
|
for (i64 pos = tb->end; pos < tb->len && tb->text[pos] == ' '; ++pos)
|
||||||
{
|
{
|
||||||
tb->end = pos + 1;
|
tb->end = pos + 1;
|
||||||
if (tb->text[pos] == ' ')
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (i64 pos = tb->end; pos < tb->len && tb->text[pos] != ' '; ++pos)
|
||||||
|
{
|
||||||
|
tb->end = pos + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tb->end += 1;
|
tb->end += 1;
|
||||||
|
// Skip utf-8 continuations
|
||||||
|
// for (i64 pos = tb->end; pos < tb->len && (tb->text[pos] & 0xC0) == 0x80; ++pos)
|
||||||
|
// {
|
||||||
|
// tb->end = pos + 1;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!(delta.flags & V_TextBoxDeltaFlag_NavSelect))
|
if (navigated && !(delta.flags & V_TextboxDeltaFlag_NavSelect))
|
||||||
{
|
{
|
||||||
tb->start = tb->end;
|
tb->start = tb->end;
|
||||||
}
|
}
|
||||||
@ -345,60 +367,104 @@ void V_ApplyTextBoxDeltas(V_TextBoxState *tb, V_TextBoxDeltaList deltas)
|
|||||||
tb->end = ClampI64(tb->end, 0, tb->len);
|
tb->end = ClampI64(tb->end, 0, tb->len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (delta.flags & V_TextboxDeltaFlag_InheritTextFromClipboard)
|
||||||
|
{
|
||||||
|
delta.text = PLT_GetClipboardText(scratch.arena);
|
||||||
|
}
|
||||||
|
|
||||||
// Update text
|
// Update text
|
||||||
if (delta.flags & V_TextBoxDeltaFlag_UpdateText)
|
if (delta.flags & V_TextboxDeltaFlag_UpdateText)
|
||||||
{
|
{
|
||||||
RngI64 replace = Zi;
|
|
||||||
|
|
||||||
// Remove selected text
|
// Remove selected text
|
||||||
{
|
{
|
||||||
replace = RNGI64(MinI64(tb->start, tb->end), MaxI64(tb->start, tb->end));
|
RngI64 remove = RNGI64(MinI64(tb->start, tb->end), MaxI64(tb->start, tb->end));
|
||||||
if (replace.max > replace.min)
|
if (remove.max > remove.min)
|
||||||
{
|
{
|
||||||
// FIXME: Truncate
|
// FIXME: Truncate
|
||||||
i64 move_len = ClampI64(tb->len - replace.max, 0, countof(tb->text) - replace.max);
|
RngI64 move = RNGI64(remove.max, tb->len);
|
||||||
for (i64 src_pos = replace.max; src_pos < (replace.max + move_len); ++src_pos)
|
i64 move_stride = remove.max - remove.min;
|
||||||
|
for (i64 src_idx = move.min; src_idx < move.max; ++src_idx)
|
||||||
{
|
{
|
||||||
i64 dst_pos = src_pos + move_len;
|
i64 dst_idx = src_idx - move_stride;
|
||||||
tb->text[dst_pos] = tb->text[src_pos];
|
tb->text[dst_idx] = tb->text[src_idx];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tb->len -= replace.max - replace.min;
|
|
||||||
|
// FIXME
|
||||||
|
tb->len -= remove.max - remove.min;
|
||||||
|
tb->start = tb->end = remove.min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Insert new text
|
// Insert new text
|
||||||
if (delta.text.len > 0)
|
|
||||||
{
|
{
|
||||||
i64 insert_len = ClampI64(delta.text.len, 0, countof(tb->text) - replace.min);
|
|
||||||
|
|
||||||
// Make room
|
|
||||||
// FIXME: Truncate
|
// FIXME: Truncate
|
||||||
i64 move_len = ClampI64(tb->len - replace.min, 0, countof(tb->text) - replace.min);
|
i64 insert_pos = tb->end;
|
||||||
for (i64 src_pos = replace.min; src_pos < (replace.min + move_len); ++src_pos)
|
i64 insert_len = MinI64(delta.text.len, countof(tb->text) - insert_pos);
|
||||||
|
if (insert_len > 0)
|
||||||
{
|
{
|
||||||
i64 dst_pos = src_pos + move_len;
|
RngI64 move_dst = Zi;
|
||||||
tb->text[dst_pos] = tb->text[src_pos];
|
move_dst.min = insert_pos + insert_len;
|
||||||
|
move_dst.max = move_dst.min + (tb->len - insert_pos);
|
||||||
|
move_dst.min = ClampI64(move_dst.min, 0, countof(tb->text));
|
||||||
|
move_dst.max = ClampI64(move_dst.max, move_dst.min, countof(tb->text));
|
||||||
|
|
||||||
|
i64 move_stride = insert_len;
|
||||||
|
|
||||||
|
for (i64 dst_idx = move_dst.max - 1; dst_idx >= move_dst.min; --dst_idx)
|
||||||
|
{
|
||||||
|
i64 src_idx = dst_idx - move_stride;
|
||||||
|
tb->text[dst_idx] = tb->text[src_idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy from delta
|
for (i64 src_idx = 0; src_idx < insert_len; ++src_idx)
|
||||||
for (i64 src_pos = 0; src_pos < insert_len; ++src_pos)
|
|
||||||
{
|
{
|
||||||
i64 dst_pos = replace.min + src_pos;
|
i64 dst_idx = insert_pos + src_idx;
|
||||||
tb->text[dst_pos] = delta.text.text[src_pos];
|
tb->text[dst_idx] = delta.text.text[src_idx];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
tb->start = tb->end = insert_pos + insert_len;
|
||||||
tb->len += insert_len;
|
tb->len += insert_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Expand selection on insert
|
|
||||||
// tb->start = ClampI64(tb->start, 0, tb->len);
|
|
||||||
// tb->end = ClampI64(tb->end, 0, tb->len);
|
|
||||||
|
|
||||||
tb->end = ClampI64(tb->end, 0, tb->len);
|
|
||||||
tb->start = tb->end;
|
// // Insert new text
|
||||||
|
// if (delta.text.len > 0)
|
||||||
|
// {
|
||||||
|
// i64 insert_len = ClampI64(delta.text.len, 0, countof(tb->text) - replace.min);
|
||||||
|
|
||||||
|
// // Make room
|
||||||
|
// // FIXME: Truncate
|
||||||
|
// i64 move_len = ClampI64(tb->len - replace.min, 0, countof(tb->text) - replace.min);
|
||||||
|
// for (i64 src_pos = replace.min; src_pos < (replace.min + move_len); ++src_pos)
|
||||||
|
// {
|
||||||
|
// i64 dst_pos = src_pos + move_len;
|
||||||
|
// tb->text[dst_pos] = tb->text[src_pos];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Copy from delta
|
||||||
|
// for (i64 src_pos = 0; src_pos < insert_len; ++src_pos)
|
||||||
|
// {
|
||||||
|
// i64 dst_pos = replace.min + src_pos;
|
||||||
|
// tb->text[dst_pos] = delta.text.text[src_pos];
|
||||||
|
// }
|
||||||
|
// tb->len += insert_len;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// tb->end = ClampI64(tb->end, 0, tb->len);
|
||||||
|
// tb->start = tb->end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delta.flags & V_TextboxDeltaFlag_CopySelectionToClipboard)
|
||||||
|
{
|
||||||
|
String selection = V_StringFromTextboxSelection(tb);
|
||||||
|
if (selection.len > 0)
|
||||||
|
{
|
||||||
|
PLT_SetClipboardText(selection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -412,7 +478,74 @@ void V_ApplyTextBoxDeltas(V_TextBoxState *tb, V_TextBoxDeltaList deltas)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// if (!(delta.flags & V_TextBoxDeltaFlag_DontUpdateText))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// // Update text
|
||||||
|
// if (delta.flags & V_TextboxDeltaFlag_UpdateText)
|
||||||
|
// {
|
||||||
|
// RngI64 replace = Zi;
|
||||||
|
|
||||||
|
// // Remove selected text
|
||||||
|
// {
|
||||||
|
// replace = RNGI64(MinI64(tb->start, tb->end), MaxI64(tb->start, tb->end));
|
||||||
|
// if (replace.max > replace.min)
|
||||||
|
// {
|
||||||
|
// // FIXME: Truncate
|
||||||
|
// i64 move_len = ClampI64(tb->len - replace.max, 0, countof(tb->text) - replace.max);
|
||||||
|
// for (i64 src_pos = replace.max; src_pos < (replace.max + move_len); ++src_pos)
|
||||||
|
// {
|
||||||
|
// i64 dst_pos = src_pos + move_len;
|
||||||
|
// tb->text[dst_pos] = tb->text[src_pos];
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// tb->len -= replace.max - replace.min;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Insert new text
|
||||||
|
// if (delta.text.len > 0)
|
||||||
|
// {
|
||||||
|
// i64 insert_len = ClampI64(delta.text.len, 0, countof(tb->text) - replace.min);
|
||||||
|
|
||||||
|
// // Make room
|
||||||
|
// // FIXME: Truncate
|
||||||
|
// i64 move_len = ClampI64(tb->len - replace.min, 0, countof(tb->text) - replace.min);
|
||||||
|
// for (i64 src_pos = replace.min; src_pos < (replace.min + move_len); ++src_pos)
|
||||||
|
// {
|
||||||
|
// i64 dst_pos = src_pos + move_len;
|
||||||
|
// tb->text[dst_pos] = tb->text[src_pos];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Copy from delta
|
||||||
|
// for (i64 src_pos = 0; src_pos < insert_len; ++src_pos)
|
||||||
|
// {
|
||||||
|
// i64 dst_pos = replace.min + src_pos;
|
||||||
|
// tb->text[dst_pos] = delta.text.text[src_pos];
|
||||||
|
// }
|
||||||
|
// tb->len += insert_len;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // FIXME: Expand selection on insert
|
||||||
|
// // tb->start = ClampI64(tb->start, 0, tb->len);
|
||||||
|
// // tb->end = ClampI64(tb->end, 0, tb->len);
|
||||||
|
|
||||||
|
// tb->end = ClampI64(tb->end, 0, tb->len);
|
||||||
|
// tb->start = tb->end;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// if (!(delta.flags & V_TextboxDeltaFlag_DontUpdateText))
|
||||||
// {
|
// {
|
||||||
// RngI64 replace = Zi;
|
// RngI64 replace = Zi;
|
||||||
|
|
||||||
@ -458,13 +591,21 @@ void V_ApplyTextBoxDeltas(V_TextBoxState *tb, V_TextBoxDeltaList deltas)
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
EndScratch(scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
String V_StringFromTextBox(V_TextBoxState *tb)
|
String V_StringFromTextbox(V_TextboxState *tb)
|
||||||
{
|
{
|
||||||
return STRING(tb->len, tb->text);
|
return STRING(tb->len, tb->text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String V_StringFromTextboxSelection(V_TextboxState *tb)
|
||||||
|
{
|
||||||
|
i64 min = MinI64(tb->start, tb->end);
|
||||||
|
i64 max = MaxI64(tb->start, tb->end);
|
||||||
|
return STRING(max - min, tb->text + min);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Timeline helpers
|
//~ Timeline helpers
|
||||||
|
|
||||||
@ -1011,7 +1152,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Process controller events
|
//- Process controller events
|
||||||
|
|
||||||
V_TextBoxDeltaList text_input_deltas = Zi;
|
V_TextboxDeltaList text_input_deltas = Zi;
|
||||||
|
|
||||||
frame->has_mouse_focus = UI_IsKeyNil(ui_frame->hot_box) || UI_MatchKey(ui_frame->hot_box, vis_box);
|
frame->has_mouse_focus = UI_IsKeyNil(ui_frame->hot_box) || UI_MatchKey(ui_frame->hot_box, vis_box);
|
||||||
frame->has_keyboard_focus = 1;
|
frame->has_keyboard_focus = 1;
|
||||||
@ -1093,60 +1234,69 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
V_TextBoxDelta delta = Zi;
|
// Generate text input delta
|
||||||
|
V_TextboxDelta delta = Zi;
|
||||||
{
|
{
|
||||||
if (down && cev.button == Button_Left)
|
if (down && cev.button == Button_Left)
|
||||||
{
|
{
|
||||||
delta.flags |= V_TextBoxDeltaFlag_NavLeft;
|
delta.flags |= V_TextboxDeltaFlag_NavLeft;
|
||||||
}
|
}
|
||||||
if (down && cev.button == Button_Right)
|
if (down && cev.button == Button_Right)
|
||||||
{
|
{
|
||||||
delta.flags |= V_TextBoxDeltaFlag_NavRight;
|
delta.flags |= V_TextboxDeltaFlag_NavRight;
|
||||||
}
|
}
|
||||||
if (down && cev.button == Button_Home)
|
if (down && cev.button == Button_Home)
|
||||||
{
|
{
|
||||||
delta.flags |= V_TextBoxDeltaFlag_NavLeft | V_TextBoxDeltaFlag_NavLine;
|
delta.flags |= V_TextboxDeltaFlag_NavLeft | V_TextboxDeltaFlag_NavLine;
|
||||||
}
|
}
|
||||||
if (down && cev.button == Button_End)
|
if (down && cev.button == Button_End)
|
||||||
{
|
{
|
||||||
delta.flags |= V_TextBoxDeltaFlag_NavRight | V_TextBoxDeltaFlag_NavLine;
|
delta.flags |= V_TextboxDeltaFlag_NavRight | V_TextboxDeltaFlag_NavLine;
|
||||||
}
|
}
|
||||||
if (down && cev.button == Button_A && frame->held_buttons[Button_Ctrl])
|
if (down && cev.button == Button_A && frame->held_buttons[Button_Ctrl])
|
||||||
{
|
{
|
||||||
delta.flags |= V_TextBoxDeltaFlag_NavSelect | V_TextBoxDeltaFlag_NavDirect;
|
delta.flags |= V_TextboxDeltaFlag_NavSelect | V_TextboxDeltaFlag_NavDirect;
|
||||||
delta.direct_start = 0;
|
delta.direct_start = 0;
|
||||||
delta.direct_end = I64Max;
|
delta.direct_end = V_MaxTextboxLen;
|
||||||
}
|
}
|
||||||
if (down && cev.button == Button_Backspace)
|
if (down && cev.button == Button_Backspace)
|
||||||
{
|
{
|
||||||
delta.text = Lit("");
|
delta.text = Lit("");
|
||||||
delta.flags |= V_TextBoxDeltaFlag_NavSelect | V_TextBoxDeltaFlag_NavLeft | V_TextBoxDeltaFlag_UpdateText;
|
delta.flags |= V_TextboxDeltaFlag_OnlyNavIfSelectionEmpty | V_TextboxDeltaFlag_NavSelect | V_TextboxDeltaFlag_NavLeft | V_TextboxDeltaFlag_UpdateText;
|
||||||
}
|
}
|
||||||
if (down && cev.button == Button_Delete)
|
if (down && cev.button == Button_Delete)
|
||||||
{
|
{
|
||||||
delta.text = Lit("");
|
delta.text = Lit("");
|
||||||
delta.flags |= V_TextBoxDeltaFlag_NavSelect | V_TextBoxDeltaFlag_NavRight | V_TextBoxDeltaFlag_UpdateText;
|
delta.flags |= V_TextboxDeltaFlag_OnlyNavIfSelectionEmpty | V_TextboxDeltaFlag_NavSelect | V_TextboxDeltaFlag_NavRight | V_TextboxDeltaFlag_UpdateText;
|
||||||
}
|
}
|
||||||
if (text.len > 0)
|
if (down && cev.button == Button_C && frame->held_buttons[Button_Ctrl])
|
||||||
{
|
{
|
||||||
delta.flags |= V_TextBoxDeltaFlag_UpdateText;
|
delta.flags |= V_TextboxDeltaFlag_CopySelectionToClipboard;
|
||||||
|
}
|
||||||
|
else if (down && cev.button == Button_V && frame->held_buttons[Button_Ctrl])
|
||||||
|
{
|
||||||
|
delta.flags |= V_TextboxDeltaFlag_InheritTextFromClipboard | V_TextboxDeltaFlag_UpdateText;
|
||||||
|
}
|
||||||
|
else if (text.len > 0 && !MatchString(text, Lit("\n")) && !MatchString(text, Lit("\t")) && !MatchString(text, Lit("\r")))
|
||||||
|
{
|
||||||
|
delta.flags |= V_TextboxDeltaFlag_UpdateText;
|
||||||
delta.text = text;
|
delta.text = text;
|
||||||
}
|
}
|
||||||
if (delta.flags)
|
if (delta.flags)
|
||||||
{
|
{
|
||||||
if (frame->held_buttons[Button_Shift])
|
if (frame->held_buttons[Button_Shift])
|
||||||
{
|
{
|
||||||
delta.flags |= V_TextBoxDeltaFlag_NavSelect;
|
delta.flags |= V_TextboxDeltaFlag_NavSelect;
|
||||||
}
|
}
|
||||||
if (frame->held_buttons[Button_Ctrl])
|
if (frame->held_buttons[Button_Ctrl])
|
||||||
{
|
{
|
||||||
delta.flags |= V_TextBoxDeltaFlag_NavWord;
|
delta.flags |= V_TextboxDeltaFlag_NavWord;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (delta.flags)
|
if (delta.flags != 0)
|
||||||
{
|
{
|
||||||
V_TextBoxDeltaNode *tbd_node = PushStruct(frame->arena, V_TextBoxDeltaNode);
|
V_TextboxDeltaNode *tbd_node = PushStruct(frame->arena, V_TextboxDeltaNode);
|
||||||
tbd_node->delta = delta;
|
tbd_node->delta = delta;
|
||||||
SllQueuePush(text_input_deltas.first, text_input_deltas.last, tbd_node);
|
SllQueuePush(text_input_deltas.first, text_input_deltas.last, tbd_node);
|
||||||
}
|
}
|
||||||
@ -4368,87 +4518,63 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
{
|
{
|
||||||
UI_Key search_box = UI_KeyF("search box");
|
UI_Key search_box = UI_KeyF("search box");
|
||||||
UI_BoxReport search_report = UI_ReportsFromKey(search_box).draw;
|
UI_BoxReport search_report = UI_ReportsFromKey(search_box).draw;
|
||||||
V_TextBoxState *search_state = &palette->search_state;
|
V_TextboxState *search_state = &palette->search_state;
|
||||||
|
|
||||||
|
b32 has_focus = UI_MatchKey(search_box, prev_frame->keyboard_focus_box);
|
||||||
|
|
||||||
|
// FIXME: Remove this
|
||||||
|
has_focus = 1;
|
||||||
|
|
||||||
// if (search_report.m1.downs)
|
// if (search_report.m1.downs)
|
||||||
if (search_report.m1.downs || !UI_MatchKey(search_box, V.keyboard_focus_box))
|
if (search_report.m1.downs)
|
||||||
{
|
{
|
||||||
V.keyboard_focus_box = search_box;
|
has_focus = 1;
|
||||||
V.text_input_ns = frame->time_ns;
|
V.text_input_ns = frame->time_ns;
|
||||||
}
|
}
|
||||||
b32 has_focus = UI_MatchKey(search_box, V.keyboard_focus_box);
|
|
||||||
|
|
||||||
if (search_report.is_hot)
|
if (search_report.is_hot)
|
||||||
{
|
{
|
||||||
WND_SetCursor(window_frame, WND_CursorKind_Text);
|
WND_SetCursor(window_frame, WND_CursorKind_Text);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_focus && text_input_deltas.first)
|
if (has_focus)
|
||||||
{
|
{
|
||||||
V_ApplyTextBoxDeltas(search_state, text_input_deltas);
|
frame->keyboard_focus_box = search_box;
|
||||||
|
if (text_input_deltas.first)
|
||||||
|
{
|
||||||
|
V.text_input_ns = frame->time_ns;
|
||||||
|
V_ApplyTextboxDeltas(search_state, text_input_deltas);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// FIXME: Remove this
|
|
||||||
if (frame->held_buttons[Button_B] && !prev_frame->held_buttons[Button_B])
|
|
||||||
{
|
|
||||||
V_TextBoxDelta delta = Zi;
|
|
||||||
// delta.kind = V_DeltaKind_
|
|
||||||
delta.text = Lit("Hi");
|
|
||||||
// delta.range = RNGI64(I64Max, I64Max);
|
|
||||||
|
|
||||||
// delta.start = search_state->start;
|
|
||||||
// delta.end = search_state->end;
|
|
||||||
|
|
||||||
// delta.start = 0;
|
|
||||||
// delta.end = 1;
|
|
||||||
|
|
||||||
delta.flags |= V_TextBoxDeltaFlag_UpdateText;
|
|
||||||
|
|
||||||
V_ApplyTextBoxDelta(search_state, delta);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// {
|
|
||||||
// V_TextBoxDelta delta = Zi;
|
|
||||||
|
|
||||||
// // FIXME: Remove this
|
// // FIXME: Remove this
|
||||||
// if (frame->held_buttons[Button_Left] && !prev_frame->held_buttons[Button_Left])
|
// if (frame->held_buttons[Button_B] && !prev_frame->held_buttons[Button_B])
|
||||||
// {
|
// {
|
||||||
// delta.flags |= V_TextBoxDeltaFlag_NavLeft;
|
// V_TextboxDelta delta = Zi;
|
||||||
// }
|
// // delta.kind = V_DeltaKind_
|
||||||
// if (frame->held_buttons[Button_Right] && !prev_frame->held_buttons[Button_Right])
|
// delta.text = Lit("Hi");
|
||||||
// {
|
// // delta.range = RNGI64(I64Max, I64Max);
|
||||||
// delta.flags |= V_TextBoxDeltaFlag_NavRight;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (delta.flags)
|
// // delta.start = search_state->start;
|
||||||
// {
|
// // delta.end = search_state->end;
|
||||||
// if (frame->held_buttons[Button_Shift])
|
|
||||||
// {
|
// // delta.start = 0;
|
||||||
// delta.flags |= V_TextBoxDeltaFlag_NavSelect;
|
// // delta.end = 1;
|
||||||
// }
|
|
||||||
// if (frame->held_buttons[Button_Ctrl])
|
// delta.flags |= V_TextboxDeltaFlag_UpdateText;
|
||||||
// {
|
|
||||||
// delta.flags |= V_TextBoxDeltaFlag_NavWord;
|
// V_ApplyTextboxDelta(search_state, delta);
|
||||||
// }
|
|
||||||
// V_ApplyTextBoxDelta(search_state, delta);
|
|
||||||
// V.text_input_ns = frame->time_ns;
|
|
||||||
// }
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
search_text = V_StringFromTextbox(search_state);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
search_text = V_StringFromTextBox(search_state);
|
|
||||||
is_searching = search_text.len != 0;
|
is_searching = search_text.len != 0;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -157,44 +157,47 @@ Struct(V_Notif)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Text box types
|
//~ Text box types
|
||||||
|
|
||||||
#define V_MaxTextBoxLen 1024
|
#define V_MaxTextboxLen 1024
|
||||||
|
|
||||||
Enum(V_TextBoxDeltaFlag)
|
Enum(V_TextboxDeltaFlag)
|
||||||
{
|
{
|
||||||
V_TextBoxDeltaFlag_None = 0,
|
V_TextboxDeltaFlag_None = 0,
|
||||||
V_TextBoxDeltaFlag_UpdateText = (1 << 0),
|
V_TextboxDeltaFlag_UpdateText = (1 << 0),
|
||||||
V_TextBoxDeltaFlag_NavDirect = (1 << 1),
|
V_TextboxDeltaFlag_OnlyNavIfSelectionEmpty = (1 << 1),
|
||||||
V_TextBoxDeltaFlag_NavLeft = (1 << 2),
|
V_TextboxDeltaFlag_CopySelectionToClipboard = (1 << 2),
|
||||||
V_TextBoxDeltaFlag_NavRight = (1 << 3),
|
V_TextboxDeltaFlag_InheritTextFromClipboard = (1 << 3),
|
||||||
V_TextBoxDeltaFlag_NavWord = (1 << 4),
|
V_TextboxDeltaFlag_NavDirect = (1 << 4),
|
||||||
V_TextBoxDeltaFlag_NavLine = (1 << 5),
|
V_TextboxDeltaFlag_NavLeft = (1 << 5),
|
||||||
V_TextBoxDeltaFlag_NavSelect = (1 << 6),
|
V_TextboxDeltaFlag_NavRight = (1 << 6),
|
||||||
|
V_TextboxDeltaFlag_NavWord = (1 << 7),
|
||||||
|
V_TextboxDeltaFlag_NavLine = (1 << 8),
|
||||||
|
V_TextboxDeltaFlag_NavSelect = (1 << 9),
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct(V_TextBoxDelta)
|
Struct(V_TextboxDelta)
|
||||||
{
|
{
|
||||||
V_TextBoxDeltaFlag flags;
|
V_TextboxDeltaFlag flags;
|
||||||
String text;
|
String text;
|
||||||
i64 direct_start;
|
i64 direct_start;
|
||||||
i64 direct_end;
|
i64 direct_end;
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct(V_TextBoxDeltaNode)
|
Struct(V_TextboxDeltaNode)
|
||||||
{
|
{
|
||||||
V_TextBoxDeltaNode *next;
|
V_TextboxDeltaNode *next;
|
||||||
V_TextBoxDelta delta;
|
V_TextboxDelta delta;
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct(V_TextBoxDeltaList)
|
Struct(V_TextboxDeltaList)
|
||||||
{
|
{
|
||||||
V_TextBoxDeltaNode *first;
|
V_TextboxDeltaNode *first;
|
||||||
V_TextBoxDeltaNode *last;
|
V_TextboxDeltaNode *last;
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct(V_TextBoxState)
|
Struct(V_TextboxState)
|
||||||
{
|
{
|
||||||
i64 len;
|
i64 len;
|
||||||
u8 text[V_MaxTextBoxLen];
|
u8 text[V_MaxTextboxLen];
|
||||||
|
|
||||||
i64 start;
|
i64 start;
|
||||||
i64 end;
|
i64 end;
|
||||||
@ -210,7 +213,7 @@ Struct(V_Palette)
|
|||||||
b32 is_showing;
|
b32 is_showing;
|
||||||
f32 show;
|
f32 show;
|
||||||
|
|
||||||
V_TextBoxState search_state;
|
V_TextboxState search_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
@ -325,6 +328,8 @@ Struct(V_Frame)
|
|||||||
Button held_buttons[Button_COUNT];
|
Button held_buttons[Button_COUNT];
|
||||||
V_Palette palette;
|
V_Palette palette;
|
||||||
|
|
||||||
|
UI_Key keyboard_focus_box;
|
||||||
|
|
||||||
String window_restore;
|
String window_restore;
|
||||||
|
|
||||||
// Vis commands
|
// Vis commands
|
||||||
@ -350,7 +355,6 @@ Struct(V_Ctx)
|
|||||||
V_Panel *root_panel;
|
V_Panel *root_panel;
|
||||||
V_Window *dragging_window;
|
V_Window *dragging_window;
|
||||||
|
|
||||||
UI_Key keyboard_focus_box;
|
|
||||||
i64 text_input_ns;
|
i64 text_input_ns;
|
||||||
|
|
||||||
i64 connect_try_ns;
|
i64 connect_try_ns;
|
||||||
@ -402,10 +406,11 @@ void V_DrawPoint(Vec2 p, Vec4 srgb);
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Text box
|
//~ Text box
|
||||||
|
|
||||||
void V_ApplyTextBoxDelta(V_TextBoxState *tb, V_TextBoxDelta delta);
|
void V_ApplyTextboxDelta(V_TextboxState *tb, V_TextboxDelta delta);
|
||||||
void V_ApplyTextBoxDeltas(V_TextBoxState *tb, V_TextBoxDeltaList deltas);
|
void V_ApplyTextboxDeltas(V_TextboxState *tb, V_TextboxDeltaList deltas);
|
||||||
|
|
||||||
String V_StringFromTextBox(V_TextBoxState *tb);
|
String V_StringFromTextbox(V_TextboxState *tb);
|
||||||
|
String V_StringFromTextboxSelection(V_TextboxState *tb);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Timeline helpers
|
//~ Timeline helpers
|
||||||
|
|||||||
@ -331,6 +331,7 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
|
|||||||
Utf8EncodeResult encoded = EncodeUtf8(codepoint);
|
Utf8EncodeResult encoded = EncodeUtf8(codepoint);
|
||||||
ControllerEvent event = Zi;
|
ControllerEvent event = Zi;
|
||||||
event.kind = ControllerEventKind_Text;
|
event.kind = ControllerEventKind_Text;
|
||||||
|
event.text_codepoint = codepoint;
|
||||||
event.text_chars_count = MinU32(encoded.count8, countof(event.text_chars));
|
event.text_chars_count = MinU32(encoded.count8, countof(event.text_chars));
|
||||||
CopyBytes(event.text_chars, encoded.chars8, event.text_chars_count);
|
CopyBytes(event.text_chars, encoded.chars8, event.text_chars_count);
|
||||||
WND_W32_PushEvent(window, event);
|
WND_W32_PushEvent(window, event);
|
||||||
@ -348,10 +349,12 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
|
|||||||
case WM_XBUTTONDOWN:
|
case WM_XBUTTONDOWN:
|
||||||
{
|
{
|
||||||
ControllerEvent event = Zi;
|
ControllerEvent event = Zi;
|
||||||
b32 is_down = msg == WM_LBUTTONDOWN ||
|
b32 is_down = (
|
||||||
|
msg == WM_LBUTTONDOWN ||
|
||||||
msg == WM_MBUTTONDOWN ||
|
msg == WM_MBUTTONDOWN ||
|
||||||
msg == WM_RBUTTONDOWN ||
|
msg == WM_RBUTTONDOWN ||
|
||||||
msg == WM_XBUTTONDOWN;
|
msg == WM_XBUTTONDOWN
|
||||||
|
);
|
||||||
if (is_down)
|
if (is_down)
|
||||||
{
|
{
|
||||||
event.kind = ControllerEventKind_ButtonDown;
|
event.kind = ControllerEventKind_ButtonDown;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user