text input wip
This commit is contained in:
parent
97711b0970
commit
c017e93695
@ -114,23 +114,11 @@
|
||||
// TODO: Eventually hard-code to something like 128 if we ever decide to support Apple M-series
|
||||
#define IsolationSize 64
|
||||
|
||||
//- Windows NTDDI version
|
||||
// TODO: Remove this
|
||||
#if 0
|
||||
#if IsCompilerMsvc
|
||||
#define NTDDI_WIN11_DT 0x0C0A0000
|
||||
#define NTDDI_VERSION 0x0A000000
|
||||
#if IsRtcEnabled
|
||||
#define _ALLOW_RTCc_IN_STL 1
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ C headers
|
||||
|
||||
#if IsCpu
|
||||
// C standard library
|
||||
//- C standard library
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <memory.h>
|
||||
@ -150,7 +138,7 @@
|
||||
// -wmmintrin.h AES
|
||||
// -immintrin.h AVX, AVX2, FMA
|
||||
#include <intrin.h>
|
||||
#include <nmmintrin.h> // SSE4.2
|
||||
#include <nmmintrin.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@ -139,7 +139,8 @@ Struct(ControllerEvent)
|
||||
b32 is_repeat;
|
||||
|
||||
// ControllerEventKind_Text
|
||||
u32 text_codepoint;
|
||||
u32 text_chars_count;
|
||||
u8 text_chars[4];
|
||||
|
||||
// ControllerEventKind_CursorMove
|
||||
Vec2 cursor_pos;
|
||||
|
||||
@ -258,6 +258,213 @@ void V_DrawPoint(Vec2 p, Vec4 srgb)
|
||||
V_DrawShape(ui_shape, AffineIdentity, srgb, 24, V_DrawFlag_None);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Text box
|
||||
|
||||
void V_ApplyTextBoxDelta(V_TextBoxState *tb, V_TextBoxDelta delta)
|
||||
{
|
||||
V_TextBoxDeltaNode tbd_node = { .delta = delta };
|
||||
V_ApplyTextBoxDeltas(tb, (V_TextBoxDeltaList) { .first = &tbd_node, .last = &tbd_node });
|
||||
}
|
||||
|
||||
void V_ApplyTextBoxDeltas(V_TextBoxState *tb, V_TextBoxDeltaList deltas)
|
||||
{
|
||||
for (V_TextBoxDeltaNode *tbd_node = deltas.first; tbd_node; tbd_node = tbd_node->next)
|
||||
{
|
||||
V_TextBoxDelta delta = tbd_node->delta;
|
||||
|
||||
// if (!(delta.flags & V_TextBoxDeltaFlag_DontUpdateCursor))
|
||||
// {
|
||||
// tb->start = ClampI64(delta.start, 0, tb->len);
|
||||
// tb->end = ClampI64(delta.end, 0, tb->len);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
// Navigate
|
||||
{
|
||||
{
|
||||
if (delta.flags & V_TextBoxDeltaFlag_NavDirect)
|
||||
{
|
||||
tb->start = delta.direct_start;
|
||||
tb->end = delta.direct_end;
|
||||
}
|
||||
if (delta.flags & V_TextBoxDeltaFlag_NavLeft)
|
||||
{
|
||||
if (delta.flags & V_TextBoxDeltaFlag_NavLine)
|
||||
{
|
||||
// FIXME: Real line start
|
||||
tb->end = 0;
|
||||
}
|
||||
else if (delta.flags & V_TextBoxDeltaFlag_NavWord)
|
||||
{
|
||||
for (i64 pos = ClampI64(tb->end - 1, 0, tb->len); pos >= 0; --pos)
|
||||
{
|
||||
tb->end = pos - 1;
|
||||
if (tb->text[pos] == ' ')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tb->end -= 1;
|
||||
}
|
||||
}
|
||||
if (delta.flags & V_TextBoxDeltaFlag_NavRight)
|
||||
{
|
||||
if (delta.flags & V_TextBoxDeltaFlag_NavLine)
|
||||
{
|
||||
// FIXME: Real line end
|
||||
tb->end = I64Max;
|
||||
}
|
||||
else if (delta.flags & V_TextBoxDeltaFlag_NavWord)
|
||||
{
|
||||
for (i64 pos = ClampI64(tb->end + 1, 0, tb->len); pos < tb->len; ++pos)
|
||||
{
|
||||
tb->end = pos + 1;
|
||||
if (tb->text[pos] == ' ')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tb->end += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(delta.flags & V_TextBoxDeltaFlag_NavSelect))
|
||||
{
|
||||
tb->start = tb->end;
|
||||
}
|
||||
tb->start = ClampI64(tb->start, 0, tb->len);
|
||||
tb->end = ClampI64(tb->end, 0, tb->len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 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;
|
||||
|
||||
// // Remove selected text
|
||||
// {
|
||||
// replace = RNGI64(MinI64(delta.start, delta.end), MaxI64(delta.start, delta.end));
|
||||
// replace.min = MaxI64(replace.min, 0);
|
||||
// replace.max = MinI64(replace.max, tb->len);
|
||||
// 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;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
String V_StringFromTextBox(V_TextBoxState *tb)
|
||||
{
|
||||
return STRING(tb->len, tb->text);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Timeline helpers
|
||||
|
||||
@ -802,7 +1009,9 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
NET_PipeStatistics vis_pipe_stats = NET_StatsFromPipe(net_pipe);
|
||||
|
||||
//////////////////////////////
|
||||
//- Process controller events into vis cmds
|
||||
//- Process controller events
|
||||
|
||||
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_keyboard_focus = 1;
|
||||
@ -839,6 +1048,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
ControllerEvent cev = window_frame.controller_events.events[cev_idx];
|
||||
b32 down = cev.kind == ControllerEventKind_ButtonDown;
|
||||
b32 up = cev.kind == ControllerEventKind_ButtonUp;
|
||||
String text = cev.kind == ControllerEventKind_Text ? STRING(cev.text_chars_count, cev.text_chars) : STRING(0, 0);
|
||||
|
||||
b32 ignore = 0;
|
||||
if (down)
|
||||
@ -877,10 +1087,70 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shortcut != 0 && down)
|
||||
if (down && shortcut)
|
||||
{
|
||||
V_PushVisCmd(shortcut->cmd_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
V_TextBoxDelta delta = Zi;
|
||||
{
|
||||
if (down && cev.button == Button_Left)
|
||||
{
|
||||
delta.flags |= V_TextBoxDeltaFlag_NavLeft;
|
||||
}
|
||||
if (down && cev.button == Button_Right)
|
||||
{
|
||||
delta.flags |= V_TextBoxDeltaFlag_NavRight;
|
||||
}
|
||||
if (down && cev.button == Button_Home)
|
||||
{
|
||||
delta.flags |= V_TextBoxDeltaFlag_NavLeft | V_TextBoxDeltaFlag_NavLine;
|
||||
}
|
||||
if (down && cev.button == Button_End)
|
||||
{
|
||||
delta.flags |= V_TextBoxDeltaFlag_NavRight | V_TextBoxDeltaFlag_NavLine;
|
||||
}
|
||||
if (down && cev.button == Button_A && frame->held_buttons[Button_Ctrl])
|
||||
{
|
||||
delta.flags |= V_TextBoxDeltaFlag_NavSelect | V_TextBoxDeltaFlag_NavDirect;
|
||||
delta.direct_start = 0;
|
||||
delta.direct_end = I64Max;
|
||||
}
|
||||
if (down && cev.button == Button_Backspace)
|
||||
{
|
||||
delta.text = Lit("");
|
||||
delta.flags |= V_TextBoxDeltaFlag_NavSelect | V_TextBoxDeltaFlag_NavLeft | V_TextBoxDeltaFlag_UpdateText;
|
||||
}
|
||||
if (down && cev.button == Button_Delete)
|
||||
{
|
||||
delta.text = Lit("");
|
||||
delta.flags |= V_TextBoxDeltaFlag_NavSelect | V_TextBoxDeltaFlag_NavRight | V_TextBoxDeltaFlag_UpdateText;
|
||||
}
|
||||
if (text.len > 0)
|
||||
{
|
||||
delta.flags |= V_TextBoxDeltaFlag_UpdateText;
|
||||
delta.text = text;
|
||||
}
|
||||
if (delta.flags)
|
||||
{
|
||||
if (frame->held_buttons[Button_Shift])
|
||||
{
|
||||
delta.flags |= V_TextBoxDeltaFlag_NavSelect;
|
||||
}
|
||||
if (frame->held_buttons[Button_Ctrl])
|
||||
{
|
||||
delta.flags |= V_TextBoxDeltaFlag_NavWord;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (delta.flags)
|
||||
{
|
||||
V_TextBoxDeltaNode *tbd_node = PushStruct(frame->arena, V_TextBoxDeltaNode);
|
||||
tbd_node->delta = delta;
|
||||
SllQueuePush(text_input_deltas.first, text_input_deltas.last, tbd_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
frame->held_buttons[hotkey.button] = down;
|
||||
}
|
||||
@ -3990,6 +4260,9 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
if (palette->is_showing || palette->show > 0.001)
|
||||
{
|
||||
f32 item_size_px = UI_FNT(1.5, 1).v;
|
||||
f32 tweak_size_px = UI_FNT(1.25, 1).v;
|
||||
|
||||
palette->key = UI_KeyF("command palette");
|
||||
UI_Checkpoint palette_cp = UI_PushCP(UI_NilKey);
|
||||
{
|
||||
@ -4061,6 +4334,257 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
UI_PopCP(UI_TopCP());
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Build searchbox
|
||||
|
||||
b32 is_searching = 0;
|
||||
String search_text = Zi;
|
||||
{
|
||||
UI_Size search_height = UI_PIX(item_size_px * 1.25, 1);
|
||||
|
||||
UI_SetNext(ChildAlignment, UI_Region_Left);
|
||||
UI_PushCP(UI_BuildRow());
|
||||
{
|
||||
//- Search icon
|
||||
{
|
||||
f32 size_px = UI_Top(FontSize) * 1.25;
|
||||
|
||||
UI_SetNext(Rounding, UI_RGROW(0.75 * theme.rounding));
|
||||
UI_SetNext(ChildAlignment, UI_Region_Center);
|
||||
UI_SetNext(BackgroundColor, 0);
|
||||
// UI_SetNext(BorderColor, reset_bd);
|
||||
UI_SetNext(BorderSize, 0);
|
||||
UI_SetNext(Rounding, 0);
|
||||
UI_SetNext(TextColor, theme.col.hint);
|
||||
UI_SetNext(Width, UI_PIX(size_px * 1.5, 1));
|
||||
UI_SetNext(Height, UI_PIX(size_px * 1.5, 1));
|
||||
// UI_SetNext(Flags, UI_BoxFlag_CaptureMouse);
|
||||
UI_SetNext(FontSize, size_px * theme.h6);
|
||||
UI_BuildIcon(theme.icon_font, UI_Icon_Search);
|
||||
// UI_BuildRow();
|
||||
}
|
||||
|
||||
//- Search box
|
||||
{
|
||||
UI_Key search_box = UI_KeyF("search box");
|
||||
UI_BoxReport search_report = UI_ReportsFromKey(search_box).draw;
|
||||
V_TextBoxState *search_state = &palette->search_state;
|
||||
|
||||
// if (search_report.m1.downs)
|
||||
if (search_report.m1.downs || !UI_MatchKey(search_box, V.keyboard_focus_box))
|
||||
{
|
||||
V.keyboard_focus_box = search_box;
|
||||
V.text_input_ns = frame->time_ns;
|
||||
}
|
||||
b32 has_focus = UI_MatchKey(search_box, V.keyboard_focus_box);
|
||||
|
||||
if (search_report.is_hot)
|
||||
{
|
||||
WND_SetCursor(window_frame, WND_CursorKind_Text);
|
||||
}
|
||||
|
||||
if (has_focus && text_input_deltas.first)
|
||||
{
|
||||
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
|
||||
// if (frame->held_buttons[Button_Left] && !prev_frame->held_buttons[Button_Left])
|
||||
// {
|
||||
// delta.flags |= V_TextBoxDeltaFlag_NavLeft;
|
||||
// }
|
||||
// if (frame->held_buttons[Button_Right] && !prev_frame->held_buttons[Button_Right])
|
||||
// {
|
||||
// delta.flags |= V_TextBoxDeltaFlag_NavRight;
|
||||
// }
|
||||
|
||||
// if (delta.flags)
|
||||
// {
|
||||
// if (frame->held_buttons[Button_Shift])
|
||||
// {
|
||||
// delta.flags |= V_TextBoxDeltaFlag_NavSelect;
|
||||
// }
|
||||
// if (frame->held_buttons[Button_Ctrl])
|
||||
// {
|
||||
// delta.flags |= V_TextBoxDeltaFlag_NavWord;
|
||||
// }
|
||||
// V_ApplyTextBoxDelta(search_state, delta);
|
||||
// V.text_input_ns = frame->time_ns;
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
search_text = V_StringFromTextBox(search_state);
|
||||
is_searching = search_text.len != 0;
|
||||
|
||||
|
||||
String display_text = search_text;
|
||||
Vec4 display_text_color = Color_White;
|
||||
if (!is_searching)
|
||||
{
|
||||
display_text_color = theme.col.hint;
|
||||
display_text = Lit(" Search...");
|
||||
}
|
||||
|
||||
// Vec4 raah_color = Color_Black;
|
||||
Vec4 raah_color = Zi;
|
||||
|
||||
UI_SetNext(Height, search_height);
|
||||
UI_SetNext(Width, UI_GROW(1, 0));
|
||||
UI_SetNext(BackgroundColor, raah_color);
|
||||
// UI_SetNext(BorderColor, item_border_color);
|
||||
UI_SetNext(BorderSize, 0);
|
||||
// UI_SetNext(Rounding, UI_RPIX(5));
|
||||
UI_SetNext(ChildAlignment, UI_Region_Left);
|
||||
UI_SetNext(TextColor, display_text_color);
|
||||
UI_SetNext(Text, display_text);
|
||||
UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_CaptureMouse);
|
||||
UI_PushCP(UI_BuildRowEx(search_box));
|
||||
{
|
||||
f32 font_size = UI_Top(FontSize);
|
||||
GC_FontKey font = UI_Top(Font);
|
||||
|
||||
//- Text caret/selection
|
||||
if (has_focus)
|
||||
{
|
||||
UI_Key caret_box = UI_KeyF("search caret");
|
||||
UI_Key selection_box = UI_KeyF("search selection");
|
||||
|
||||
|
||||
UI_Size caret_width = UI_PIX(1, 1);
|
||||
UI_Size caret_height = UI_PIX(search_height.v, 1);
|
||||
|
||||
|
||||
Vec4 selection_color = VEC4(0, 0.25, 0.75, 0.5);
|
||||
|
||||
Vec4 caret_color = VEC4(1, 1, 1, 0.75);
|
||||
// caret_color.a = AbsF32(SinF32(SecondsFromNs(frame->time_ns - V.text_input_ns) * 4));
|
||||
// caret_color.a = SinF32(SecondsFromNs(frame->time_ns - V.text_input_ns)) > 0.5 ? 1 : 0;
|
||||
// caret_color.a = (CosF32(SecondsFromNs(frame->time_ns - V.text_input_ns) * 5) + 1) * 0.5;
|
||||
caret_color.a *= AbsF32(CosF32(SecondsFromNs(frame->time_ns - V.text_input_ns) * 3));
|
||||
|
||||
f32 start_offset_px = 0;
|
||||
f32 end_offset_px = 0;
|
||||
|
||||
// caret_offset_px = TweakFloat("RAAAAAAAAAAAAAAAAAAAH", 0, 0, 100);
|
||||
|
||||
// caret_offset_px =
|
||||
|
||||
|
||||
|
||||
|
||||
// FIXME: Remove this, use UI computed run
|
||||
if (search_text.len > 0)
|
||||
{
|
||||
String32 codepoints = String32FromString(frame->arena, search_text);
|
||||
GC_Run run = GC_RunFromString32(frame->arena, codepoints, font, font_size);
|
||||
|
||||
// FIXME: Don't use rect idx
|
||||
// FIXME: Selection
|
||||
// FIXME: Offset & scissor
|
||||
for (i64 rect_idx = 0; rect_idx < (i64)run.rects_count; ++rect_idx)
|
||||
{
|
||||
if (rect_idx < search_state->start)
|
||||
{
|
||||
GC_RunRect rect = run.rects[rect_idx];
|
||||
start_offset_px = rect.baseline_pos + rect.advance;
|
||||
}
|
||||
if (rect_idx < search_state->end)
|
||||
{
|
||||
GC_RunRect rect = run.rects[rect_idx];
|
||||
end_offset_px = rect.baseline_pos + rect.advance;
|
||||
}
|
||||
if (rect_idx >= search_state->start && rect_idx >= search_state->end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// {
|
||||
// i64 offset_
|
||||
// }
|
||||
|
||||
// Selection
|
||||
{
|
||||
f32 min = MinF32(start_offset_px, end_offset_px);
|
||||
f32 max = MaxF32(start_offset_px, end_offset_px);
|
||||
|
||||
UI_SetNext(Width, UI_PIX(max - min, 1));
|
||||
UI_SetNext(Height, caret_height);
|
||||
UI_SetNext(FloatingPos, VEC2(min, 0));
|
||||
UI_SetNext(Anchor, UI_Region_Left);
|
||||
UI_SetNext(Flags, UI_BoxFlag_Floating, UI_BoxFlag_CaptureMouse);
|
||||
UI_SetNext(BorderSize, 0);
|
||||
UI_SetNext(BackgroundColor, selection_color);
|
||||
UI_SetNext(FontSize, font_size);
|
||||
UI_BuildBoxEx(selection_box);
|
||||
}
|
||||
|
||||
// Caret
|
||||
{
|
||||
UI_SetNext(Width, caret_width);
|
||||
UI_SetNext(Height, caret_height);
|
||||
UI_SetNext(FloatingPos, VEC2(end_offset_px, 0));
|
||||
UI_SetNext(Anchor, UI_Region_Left);
|
||||
UI_SetNext(Flags, UI_BoxFlag_Floating, UI_BoxFlag_CaptureMouse);
|
||||
UI_SetNext(BorderSize, 0);
|
||||
UI_SetNext(BackgroundColor, caret_color);
|
||||
UI_SetNext(FontSize, font_size);
|
||||
UI_BuildBoxEx(caret_box);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
UI_PopCP(UI_TopCP());
|
||||
}
|
||||
}
|
||||
UI_PopCP(UI_TopCP());
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Build palette items list
|
||||
|
||||
@ -4178,9 +4702,6 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
item_border_color = LerpSrgb(item_border_color, theme.col.button_active, item_rep.hot);
|
||||
}
|
||||
|
||||
f32 item_size_px = UI_FNT(1.5, 1).v;
|
||||
f32 tweak_size_px = UI_FNT(1.25, 1).v;
|
||||
|
||||
UI_SetNext(Tint, 0);
|
||||
UI_PushCP(UI_BuildRow());
|
||||
{
|
||||
|
||||
@ -154,16 +154,63 @@ Struct(V_Notif)
|
||||
String msg;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Text box types
|
||||
|
||||
#define V_MaxTextBoxLen 1024
|
||||
|
||||
Enum(V_TextBoxDeltaFlag)
|
||||
{
|
||||
V_TextBoxDeltaFlag_None = 0,
|
||||
V_TextBoxDeltaFlag_UpdateText = (1 << 0),
|
||||
V_TextBoxDeltaFlag_NavDirect = (1 << 1),
|
||||
V_TextBoxDeltaFlag_NavLeft = (1 << 2),
|
||||
V_TextBoxDeltaFlag_NavRight = (1 << 3),
|
||||
V_TextBoxDeltaFlag_NavWord = (1 << 4),
|
||||
V_TextBoxDeltaFlag_NavLine = (1 << 5),
|
||||
V_TextBoxDeltaFlag_NavSelect = (1 << 6),
|
||||
};
|
||||
|
||||
Struct(V_TextBoxDelta)
|
||||
{
|
||||
V_TextBoxDeltaFlag flags;
|
||||
String text;
|
||||
i64 direct_start;
|
||||
i64 direct_end;
|
||||
};
|
||||
|
||||
Struct(V_TextBoxDeltaNode)
|
||||
{
|
||||
V_TextBoxDeltaNode *next;
|
||||
V_TextBoxDelta delta;
|
||||
};
|
||||
|
||||
Struct(V_TextBoxDeltaList)
|
||||
{
|
||||
V_TextBoxDeltaNode *first;
|
||||
V_TextBoxDeltaNode *last;
|
||||
};
|
||||
|
||||
Struct(V_TextBoxState)
|
||||
{
|
||||
i64 len;
|
||||
u8 text[V_MaxTextBoxLen];
|
||||
|
||||
i64 start;
|
||||
i64 end;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Palette types
|
||||
|
||||
Struct(V_Palette)
|
||||
{
|
||||
// Persistent state
|
||||
Vec2 pos;
|
||||
UI_Key key;
|
||||
b32 is_showing;
|
||||
f32 show;
|
||||
|
||||
V_TextBoxState search_state;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -303,6 +350,9 @@ Struct(V_Ctx)
|
||||
V_Panel *root_panel;
|
||||
V_Window *dragging_window;
|
||||
|
||||
UI_Key keyboard_focus_box;
|
||||
i64 text_input_ns;
|
||||
|
||||
i64 connect_try_ns;
|
||||
|
||||
V_ObservationBin observation_bins[V_ObservationBinsCount];
|
||||
@ -349,6 +399,14 @@ void V_DrawLine(Vec2 p0, Vec2 p1, Vec4 srgb);
|
||||
void V_DrawRect(Rng2 rect, Vec4 srgb, V_DrawFlag flags);
|
||||
void V_DrawPoint(Vec2 p, Vec4 srgb);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Text box
|
||||
|
||||
void V_ApplyTextBoxDelta(V_TextBoxState *tb, V_TextBoxDelta delta);
|
||||
void V_ApplyTextBoxDeltas(V_TextBoxState *tb, V_TextBoxDeltaList deltas);
|
||||
|
||||
String V_StringFromTextBox(V_TextBoxState *tb);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Timeline helpers
|
||||
|
||||
|
||||
@ -1536,6 +1536,7 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
|
||||
GC_Run raw_run_unscaled = box->glyph_run;
|
||||
GC_Run raw_run = UI_ScaleRun(frame->arena, raw_run_unscaled, box->solved_scale);
|
||||
|
||||
// TODO: Check that sprite image is not empty
|
||||
b32 is_visible = 1;
|
||||
is_visible = is_visible && (box->desc.tint.w >= 0.0025);
|
||||
is_visible = is_visible && (box->screen_rect.p1.x - box->screen_rect.p0.x > 0.0025);
|
||||
|
||||
@ -328,9 +328,11 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
|
||||
}
|
||||
if ((codepoint >= 32 && codepoint != 127) || codepoint == '\t' || codepoint == '\n')
|
||||
{
|
||||
Utf8EncodeResult encoded = EncodeUtf8(codepoint);
|
||||
ControllerEvent event = Zi;
|
||||
event.kind = ControllerEventKind_Text;
|
||||
event.text_codepoint = codepoint;
|
||||
event.text_chars_count = MinU32(encoded.count8, countof(event.text_chars));
|
||||
CopyBytes(event.text_chars, encoded.chars8, event.text_chars_count);
|
||||
WND_W32_PushEvent(window, event);
|
||||
}
|
||||
} break;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user