functional textbox input

This commit is contained in:
jacob 2026-03-29 00:28:08 -05:00
parent c017e93695
commit ff8f222527
4 changed files with 296 additions and 161 deletions

View File

@ -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];

View File

@ -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;

View File

@ -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

View File

@ -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;