From 102bb6dc3691babe8cbe3725c50a82c8791a257d Mon Sep 17 00:00:00 2001 From: jacob Date: Wed, 31 Dec 2025 20:56:57 -0600 Subject: [PATCH] tweak palette sliders --- src/base/base_math.c | 9 + src/base/base_math.h | 11 +- src/base/base_string.c | 106 ++++++++- src/base/base_string.h | 7 + src/base/base_tweak.c | 76 +++++-- src/base/base_tweak.h | 22 +- src/glyph_cache/glyph_cache.c | 8 +- src/gpu/gpu_dx12/gpu_dx12_core.c | 10 +- src/meta/meta.c | 2 +- src/platform/platform_win32/platform_win32.c | 1 - src/pp/pp_vis/pp_vis_core.c | 219 +++++++++++++++---- src/pp/pp_vis/pp_vis_core.h | 3 +- src/ui/ui_core.c | 10 +- src/ui/ui_core.h | 11 +- 14 files changed, 406 insertions(+), 89 deletions(-) diff --git a/src/base/base_math.c b/src/base/base_math.c index 27f56693..5e46367a 100644 --- a/src/base/base_math.c +++ b/src/base/base_math.c @@ -385,6 +385,15 @@ Vec2 NormVec2(Vec2 a) return Vec2WithLen(a, 1.f); } +//- Clamp + +Vec2 ClampVec2(Vec2 v, Rng2 r) +{ + Vec2 result = Zi; + result.x = ClampF32(v.x, r.p0.x, r.p1.x); + result.y = ClampF32(v.y, r.p0.y, r.p1.y); + return result; +} //- Dot diff --git a/src/base/base_math.h b/src/base/base_math.h index 277f19bb..b020a11c 100644 --- a/src/base/base_math.h +++ b/src/base/base_math.h @@ -101,12 +101,14 @@ Struct(Vec4Array) { Vec4 *points; u64 count; }; //- Rng1 Struct(Rng) { f32 min, max; }; +Struct(RngF64) { f64 min, max; }; Struct(RngI32) { i32 min, max; }; Struct(RngI64) { i64 min, max; }; Struct(RngU32) { u32 min, max; }; Struct(RngU64) { u64 min, max; }; #define RNG(min, max) (Rng) { (min), (max) } +#define RNGF64(min, max) (RngF46) { (min), (max) } #define RNGI32(min, max) (RngI32) { (min), (max) } #define RNGI64(min, max) (RngI64) { (min), (max) } #define RNGU32(min, max) (RngU32) { (min), (max) } @@ -115,12 +117,14 @@ Struct(RngU64) { u64 min, max; }; //- Rng2 Struct(Rng2) { Vec2 p0, p1; }; +Struct(Rng2F64) { Vec2F64 p0, p1; }; Struct(Rng2I32) { Vec2I32 p0, p1; }; Struct(Rng2I64) { Vec2I64 p0, p1; }; Struct(Rng2U32) { Vec2U32 p0, p1; }; Struct(Rng2U64) { Vec2U64 p0, p1; }; #define RNG2(p0, p1) (Rng2) { (p0), (p1) } +#define RNG2F64(p0, p1) (Rng2F46) { (p0), (p1) } #define RNG2I32(p0, p1) (Rng2I32) { (p0), (p1) } #define RNG2I64(p0, p1) (Rng2I64) { (p0), (p1) } #define RNG2U32(p0, p1) (Rng2U32) { (p0), (p1) } @@ -129,12 +133,14 @@ Struct(Rng2U64) { Vec2U64 p0, p1; }; //- Rng3 Struct(Rng3) { Vec3 p0, p1; }; +Struct(Rng3F64) { Vec3F64 p0, p1; }; Struct(Rng3I32) { Vec3I32 p0, p1; }; Struct(Rng3I64) { Vec3I64 p0, p1; }; Struct(Rng3U32) { Vec3U32 p0, p1; }; Struct(Rng3U64) { Vec3U64 p0, p1; }; #define RNG3(p0, p1) (Rng3) { (p0), (p1) } +#define RNG3F64(p0, p1) (Rng3F46) { (p0), (p1) } #define RNG3I32(p0, p1) (Rng3I32) { (p0), (p1) } #define RNG3I64(p0, p1) (Rng3I64) { (p0), (p1) } #define RNG3U32(p0, p1) (Rng3U32) { (p0), (p1) } @@ -319,9 +325,12 @@ Vec2 SubVec2(Vec2 a, Vec2 b); f32 Vec2Len(Vec2 a); f32 Vec2LenSq(Vec2 a); Vec2 Vec2WithLen(Vec2 a, f32 len); -Vec2 ClampVec2Len(Vec2 a, f32 max); f32 Vec2Distance(Vec2 a, Vec2 b); Vec2 NormVec2(Vec2 a); +Vec2 ClampVec2Len(Vec2 a, f32 max); + +//- Clamp +Vec2 ClampVec2(Vec2 v, Rng2 r); //- Dot f32 DotVec2(Vec2 a, Vec2 b); diff --git a/src/base/base_string.c b/src/base/base_string.c index ac8d97ac..a0cc86f5 100644 --- a/src/base/base_string.c +++ b/src/base/base_string.c @@ -1,6 +1,11 @@ //////////////////////////////////////////////////////////// //~ Conversion helpers +String StringFromBool(Arena *arena, b32 b) +{ + return b ? PushString(arena, Lit("true")) : PushString(arena, Lit("false")); +} + String StringFromChar(Arena *arena, char c) { u8 *dst = PushStructNoZero(arena, u8); @@ -124,7 +129,7 @@ String StringFromFloat(Arena *arena, f64 f, u32 precision) f += 0.5 / (f64)PowU64(10, (u8)precision); f64 part_whole = TruncF64(f); - f64 part_decimal = f - part_whole; + f64 part_frac = f - part_whole; // Print whole part { @@ -147,15 +152,15 @@ String StringFromFloat(Arena *arena, f64 f, u32 precision) } } - // Print decimal part + // Print frac part if (precision > 0) { StringFromChar(arena, '.'); for (u64 i = 0; i < precision; ++i) { - part_decimal *= 10.0; - u64 digit = (u64)part_decimal; - part_decimal -= digit; + part_frac *= 10.0; + u64 digit = (u64)part_frac; + part_frac -= digit; StringFromChar(arena, IntChars[digit % 10]); } result.len += (u64)precision + 1; @@ -213,6 +218,97 @@ String StringFromUid(Arena *arena, Uid uid) return result; } +//////////////////////////////////////////////////////////// +//~ Parsing helpers + +b32 BoolFromString(String str) +{ + b32 result = 0; + result = MatchString(str, Lit("true")); + return result; +} + +f64 FloatFromString(String str) +{ + f64 result = 0; + + b32 ok = 1; + + // Eat sign + u64 whole_start_idx = 0; + i32 sign = 1; + if (ok && str.len > 0) + { + if (whole_start_idx < str.len) + { + u8 c = str.text[whole_start_idx]; + if (c == '-') + { + sign = -1; + whole_start_idx += 1; + } + else if (c == '+') + { + whole_start_idx += 1; + } + } + } + + // Find decimal place + u64 frac_start_idx = whole_start_idx; + for (; ok && frac_start_idx < str.len; ++frac_start_idx) + { + u8 c = str.text[frac_start_idx]; + if (c == '.') + { + break; + } + } + + // Parse whole part + u64 whole_part = 0; + for (u64 char_idx = whole_start_idx; ok && char_idx < frac_start_idx; ++char_idx) + { + u8 c = str.text[char_idx]; + if (c >= '0' && c <= '9') + { + u8 digit = c - '0'; + whole_part += digit * PowU64(10, frac_start_idx - (char_idx + 1)); + } + else + { + ok = 0; + } + } + + // Parse frac part + u64 frac_part = 0; + for (u64 char_idx = frac_start_idx + 1; ok && char_idx < str.len; ++char_idx) + { + u8 c = str.text[char_idx]; + if (c >= '0' && c <= '9') + { + u8 digit = c - '0'; + frac_part += digit * PowU64(10, str.len - (char_idx + 1)); + } + else + { + ok = 0; + } + } + + if (ok) + { + result = (f64)whole_part + ((f64)frac_part / PowU64(10, str.len - (frac_start_idx + 1))); + } + else + { + result = 0; + } + + return result; +} + //////////////////////////////////////////////////////////// //~ String helpers diff --git a/src/base/base_string.h b/src/base/base_string.h index 548c51fb..45714a02 100644 --- a/src/base/base_string.h +++ b/src/base/base_string.h @@ -77,6 +77,7 @@ Struct(CodepointIter) //////////////////////////////////////////////////////////// //~ Conversion helpers +String StringFromBool(Arena *arena, b32 b); String StringFromChar(Arena *arena, char c); String StringFromUint(Arena *arena, u64 n, u64 base, u64 zfill); String StringFromUints(Arena *arena, u64 uints_count, u64 *uints, u64 base, u64 zfill); @@ -86,6 +87,12 @@ String StringFromPtr(Arena *arena, void *ptr); String StringFromhandle(Arena *arena, u64 v0, u64 v1); String StringFromUid(Arena *arena, Uid uid); +//////////////////////////////////////////////////////////// +//~ Parsing helpers + +b32 BoolFromString(String str); +f64 FloatFromString(String str); + //////////////////////////////////////////////////////////// //~ String helpers diff --git a/src/base/base_tweak.c b/src/base/base_tweak.c index 2bb5de80..ad66190e 100644 --- a/src/base/base_tweak.c +++ b/src/base/base_tweak.c @@ -9,9 +9,10 @@ void BootstrapTweakVars(void) //////////////////////////////////////////////////////////// //~ Tweak var operations -TweakVar TweakEx(String name, TweakKind kind, TweakValue value, b32 set_new_value) +String TweakEx(Arena *arena, String name, TweakDesc desc, String new_value, b32 set_to_new_value) { - TweakVar result = Zi; + String result = Zi; + Arena *perm = PermArena(); u64 hash = MixU64(HashFnv64(Fnv64Basis, name)); TweakVarEntryBin *bin = &Base.tweak.entry_bins[hash % countof(Base.tweak.entry_bins)]; LockTicketMutex(&Base.tweak.tm); @@ -24,33 +25,38 @@ TweakVar TweakEx(String name, TweakKind kind, TweakValue value, b32 set_new_valu break; } } - if (e) + if (!e) { - if (set_new_value) - { - e->v.value = value; - } - result = e->v; - } - else - { - Arena *perm = PermArena(); PushAlign(perm, CachelineSize); e = PushStruct(perm, TweakVarEntry); e->hash = hash; { + // FIXME: Not perm + String store_value = PushString(perm, new_value); + TweakVar *v = &e->v; v->name = PushString(perm, name); - v->kind = kind; - v->value = value; - v->default_value = value; - result = *v; + v->desc = desc; + v->value = store_value; + v->default_value = store_value; } PushAlign(perm, CachelineSize); SllQueuePushN(bin->first, bin->last, e, next_in_bin); SllQueuePushN(Base.tweak.first_entry, Base.tweak.last_entry, e, next_in_list); Base.tweak.entries_count += 1; } + else if (set_to_new_value) + { + if (!MatchString(e->v.value, new_value)) + { + // FIXME: Not perm + String store_value = PushString(perm, new_value); + + // FIXME: free old value + e->v.value = store_value; + } + } + result = PushString(arena, e->v.value); } UnlockTicketMutex(&Base.tweak.tm); return result; @@ -67,7 +73,11 @@ TweakVarArray GetAllTweakVars(Arena *arena) i64 var_idx = 0; for (TweakVarEntry *e = Base.tweak.first_entry; e; e = e->next_in_list) { - result.v[var_idx] = e->v; + TweakVar *src = &e->v; + TweakVar *dst = &result.v[var_idx]; + *dst = *src; + dst->value = PushString(arena, src->value); + dst->default_value = PushString(arena, src->default_value); var_idx += 1; } } @@ -76,7 +86,35 @@ TweakVarArray GetAllTweakVars(Arena *arena) return result; } -b32 MatchTweakValue(TweakValue a, TweakValue b) +//////////////////////////////////////////////////////////// +//~ Tweak var retrieval helpers + +b32 TweakBool(String name, b32 default_value) { - return MatchStruct(&a, &b); + b32 result = 0; + TempArena scratch = BeginScratchNoConflict(); + { + TweakDesc desc = Zi; + desc.kind = TweakKind_Bool; + String tweak_str = TweakEx(scratch.arena, name, desc, StringFromBool(scratch.arena, default_value), 0); + result = BoolFromString(tweak_str); + } + EndScratch(scratch); + return result; +} + +f64 TweakFloat(String name, f64 default_value, f64 min, f64 max) +{ + f64 result = 0; + TempArena scratch = BeginScratchNoConflict(); + { + TweakDesc desc = Zi; + desc.kind = TweakKind_Float; + desc.range.min = min; + desc.range.max = max; + String tweak_str = TweakEx(scratch.arena, name, desc, StringFromFloat(scratch.arena, default_value, 6), 0); + result = FloatFromString(tweak_str); + } + EndScratch(scratch); + return result; } diff --git a/src/base/base_tweak.h b/src/base/base_tweak.h index 96f87c50..449b945a 100644 --- a/src/base/base_tweak.h +++ b/src/base/base_tweak.h @@ -4,19 +4,21 @@ Enum(TweakKind) { TweakKind_Bool, + TweakKind_Float, }; -Struct(TweakValue) +Struct(TweakDesc) { - f64 x, y, z, w; + TweakKind kind; + RngF64 range; }; Struct(TweakVar) { String name; - TweakKind kind; - TweakValue value; - TweakValue default_value; + TweakDesc desc; + String value; + String default_value; }; Struct(TweakVarArray) @@ -64,9 +66,11 @@ void BootstrapTweakVars(void); //////////////////////////////////////////////////////////// //~ Tweak var operations -TweakVar TweakEx(String name, TweakKind kind, TweakValue value, b32 set_new_value); +String TweakEx(Arena *arena, String name, TweakDesc desc, String new_value, b32 set_to_new_value); TweakVarArray GetAllTweakVars(Arena *arena); -//- Helpers -b32 MatchTweakValue(TweakValue a, TweakValue b); -#define TweakB32(_name, _default_value) (TweakEx(Lit(_name), TweakKind_Bool, (TweakValue) { .x = !!(_default_value) }, 0).value.x >= 0.5) +//////////////////////////////////////////////////////////// +//~ Tweak var retrieval helpers + +b32 TweakBool(String name, b32 default_value); +f64 TweakFloat(String name, f64 default_value, f64 min, f64 max); diff --git a/src/glyph_cache/glyph_cache.c b/src/glyph_cache/glyph_cache.c index e0eb81a7..dd73d73f 100644 --- a/src/glyph_cache/glyph_cache.c +++ b/src/glyph_cache/glyph_cache.c @@ -180,15 +180,15 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size GC_RunRect *rect = &result.rects[glyph_idx]; f32 advance = glyph->advance; - if (TweakB32("Ceil glyph advances", 0)) + if (TweakBool(Lit("Ceil glyph advances"), 0)) { advance = CeilF32(advance); } - if (TweakB32("Floor glyph advances", 0)) + if (TweakBool(Lit("Floor glyph advances"), 0)) { advance = FloorF32(advance); } - if (TweakB32("Round glyph advances", 1)) + if (TweakBool(Lit("Round glyph advances"), 1)) { advance = RoundF32(advance); } @@ -288,7 +288,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncFrameLaneCtx *frame) GC_Glyph *glyph = cmd->glyph; ResourceKey resource = glyph->desc.font.r; GC_GlyphDesc desc = glyph->desc; - TTF_GlyphResult ttf_result = TTF_RasterizeGlyphFromCodepoint(frame->arena, desc.codepoint, resource, desc.font_size);; + TTF_GlyphResult ttf_result = TTF_RasterizeGlyphFromCodepoint(frame->arena, desc.codepoint, resource, desc.font_size); glyph->font_size = desc.font_size; glyph->font_ascent = ttf_result.font_ascent; glyph->font_descent = ttf_result.font_descent; diff --git a/src/gpu/gpu_dx12/gpu_dx12_core.c b/src/gpu/gpu_dx12/gpu_dx12_core.c index a62ce0bd..7cc80507 100644 --- a/src/gpu/gpu_dx12/gpu_dx12_core.c +++ b/src/gpu/gpu_dx12/gpu_dx12_core.c @@ -472,10 +472,12 @@ G_D12_Pipeline *G_D12_PipelineFromDesc(G_D12_PipelineDesc desc) { Arena *perm = PermArena(); PushAlign(perm, CachelineSize); - pipeline = PushStruct(perm, G_D12_Pipeline); - pipeline->desc = desc; - pipeline->hash = hash; - is_pipeline_new = 1; + { + pipeline = PushStruct(perm, G_D12_Pipeline); + pipeline->desc = desc; + pipeline->hash = hash; + is_pipeline_new = 1; + } PushAlign(perm, CachelineSize); SllStackPushN(bin->first, pipeline, next_in_bin); } diff --git a/src/meta/meta.c b/src/meta/meta.c index d8e8e687..6c285e66 100644 --- a/src/meta/meta.c +++ b/src/meta/meta.c @@ -460,7 +460,7 @@ void BuildEntryPoint(WaveLaneCtx *lane) M_TokenFileList lexed = M_TokensFromSrcDirs(perm, src_dirs); // Parse - M_LayerList parsed = M_LayersFromTokenFiles(perm, lexed);; + M_LayerList parsed = M_LayersFromTokenFiles(perm, lexed); // Flatten StringList starting_layer_names = Zi; diff --git a/src/platform/platform_win32/platform_win32.c b/src/platform/platform_win32/platform_win32.c index 2fbf93cb..6f2e48e1 100644 --- a/src/platform/platform_win32/platform_win32.c +++ b/src/platform/platform_win32/platform_win32.c @@ -407,7 +407,6 @@ String P_ReadFile(Arena *arena, P_File file) { // ReadFile returns non-zero on success // TODO: error checking - PushAlign(arena, CachelineSize); result.text = PushStructsNoZero(arena, u8, size); ReadFile( (HANDLE)file.handle, diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 23fc5238..c5209671 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -90,15 +90,18 @@ V_WidgetTheme V_GetWidgetTheme(void) theme.h5 = 0.83; theme.h6 = 0.67; + // theme.rounding = 0; + // theme.rounding = 1; + theme.rounding = TweakFloat(Lit("Rounding"), 1, 0, 1); + theme.text_padding_x = 5; theme.text_padding_y = 5; - // theme.font_size = TweakI32("Font size", 14, RNGI32(5, 100)); + theme.font_size = TweakFloat(Lit("Font size"), 14, 10, 50); theme.window_background_color = Rgb32(0xff1a1d1e); theme.window_border_color = Rgb32(0xff343a3b); theme.window_border = 1; - theme.window_width = 500; theme.window_padding = theme.window_border - 1; theme.divider_color = theme.window_border_color; @@ -811,10 +814,13 @@ void V_TickForever(WaveLaneCtx *lane) UI_Report child_rep = UI_ReportFromKey(resize_panel->key); UI_Report divider_rep = UI_ReportFromKey(resize_panel->divider_key); + f32 drag_offset = ui_frame->last_mouse_down_cursor_pos.v[panel->axis] - divider_rep.last_mouse_down_screen_anchor.v[panel->axis]; + f32 child_pref_size = 0; child_pref_size += frame->ui_cursor.v[panel->axis]; child_pref_size -= child_rep.screen_anchor.v[panel->axis]; - child_pref_size -= divider_rep.last_cursor_down_anchor_offset.v[panel->axis]; + // child_pref_size -= divider_rep.last_cursor_down_anchor_offset.v[panel->axis]; + child_pref_size -= drag_offset; f32 ratio_diff = (child_pref_size / panel_size) - resize_panel->pref_ratio; f32 min_ratio = 0.05; @@ -985,7 +991,7 @@ void V_TickForever(WaveLaneCtx *lane) f32 drag_threshold = 20; if (tab_rep.m1.held) { - Vec2 drag_start = AddVec2(tab_rep.screen_anchor, tab_rep.last_cursor_down_anchor_offset); + Vec2 drag_start = ui_frame->last_mouse_down_cursor_pos; if (Vec2Len(SubVec2(frame->ui_cursor, drag_start)) > drag_threshold) { V.dragging_window = window; @@ -1288,7 +1294,7 @@ void V_TickForever(WaveLaneCtx *lane) V_Palette *palette = &frame->palette; { f32 palette_ease = 30.0 * frame->dt; - if (TweakB32("Slow palette ease", 0)) + if (TweakBool(Lit("Slow palette ease"), 0)) { palette_ease = 1.0 * frame->dt; } @@ -1311,7 +1317,8 @@ void V_TickForever(WaveLaneCtx *lane) Vec4 divider_color = theme.divider_color; if (titlebar_rep.m1.held) { - palette->pos = SubVec2(frame->ui_cursor, palette_rep.last_cursor_down_anchor_offset); + Vec2 drag_offset = SubVec2(ui_frame->last_mouse_down_cursor_pos, palette_rep.last_mouse_down_screen_anchor); + palette->pos = SubVec2(frame->ui_cursor, drag_offset); } window_border_color = LerpSrgb(window_border_color, Rgb32(0x0078a6), titlebar_rep.hot); @@ -1322,8 +1329,8 @@ void V_TickForever(WaveLaneCtx *lane) UI_Push(BackgroundColor, window_background_color); UI_Push(BorderColor, window_border_color); UI_Push(Border, theme.window_border); - UI_Push(Rounding, UI_RPIX(15)); - UI_Push(Width, UI_PIX(theme.window_width, 0)); + UI_Push(Rounding, UI_RPIX(15 * theme.rounding)); + UI_Push(Width, UI_FNT(50, 0)); UI_Push(Height, UI_SHRINK(0, 0)); UI_Push(ChildLayoutAxis, Axis_Y); UI_Push(FloatingPos, palette->pos); @@ -1368,12 +1375,12 @@ void V_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Build palette items list - f32 padding = theme.window_border; + f32 window_padding = theme.window_border; UI_SetNext(Tint, 0); UI_SetNext(Rounding, 0); UI_PushCP(UI_BuildRow()); { - UI_BuildSpacer(UI_PIX(padding, 1), Axis_X); + UI_BuildSpacer(UI_PIX(window_padding, 1), Axis_X); { UI_SetNext(Tint, 0); UI_SetNext(Rounding, 0); @@ -1452,6 +1459,8 @@ void V_TickForever(WaveLaneCtx *lane) for (PaletteItem *item = first_item; item; item = item->next) { + f32 spacing = 20; + // Divider UI_BuildDivider(UI_PIX(1, 1), divider_color, Axis_Y); @@ -1490,7 +1499,7 @@ void V_TickForever(WaveLaneCtx *lane) UI_Push(Tag, item->key.hash); // Begin spacer - UI_BuildSpacer(UI_PIX(20, 1), Axis_X); + UI_BuildSpacer(UI_PIX(spacing, 1), Axis_X); // Command label UI_SetNext(ChildAlignment, UI_Region_Left); @@ -1503,46 +1512,178 @@ void V_TickForever(WaveLaneCtx *lane) if (item->flags & PaletteItemFlag_IsTweakVar) { TweakVar tweak_var = item->tweak_var; - UI_Key tweak_key = UI_KeyF("tweak"); - UI_Report tweak_rep = UI_ReportFromKey(tweak_key); - TweakValue new_tweak_value = tweak_var.value; + TweakDesc tweak_desc = tweak_var.desc; + String old_tweak_str = tweak_var.value; + String new_tweak_str = tweak_var.value; - switch (tweak_var.kind) + // Tweak label + UI_BuildSpacer(UI_PIX(spacing, 1), Axis_X); + UI_BuildLabel(new_tweak_str); + + // Reset button + if (!MatchString(new_tweak_str, tweak_var.default_value)) { - // Tweak checkbox + UI_BuildSpacer(UI_PIX(spacing * 0.5, 1), Axis_X); + UI_Key reset_key = UI_KeyF("reset"); + UI_Report reset_rep = UI_ReportFromKey(reset_key); + + if (reset_rep.m1.presses > 0) + { + new_tweak_str = tweak_var.default_value; + } + + Vec4 reset_bg_color = Zi; + Vec4 reset_border_color = theme.window_border_color; + reset_bg_color = LerpSrgb(reset_bg_color, theme.button_hot_color, reset_rep.hot); + reset_bg_color = LerpSrgb(reset_bg_color, theme.button_active_color, reset_rep.active); + reset_border_color = LerpSrgb(reset_border_color, theme.button_active_color, reset_rep.hot); + // reset_border_color = LerpSrgb(reset_border_color, theme.button_active_color, reset_rep.active); + UI_SetNext(BackgroundColor, reset_bg_color); + UI_SetNext(BorderColor, reset_border_color); + UI_SetNext(Rounding, UI_RGROW(theme.rounding)); + UI_SetNext(Border, 2); + UI_SetNext(Width, UI_FNT(1.25, 1)); + UI_SetNext(Height, UI_FNT(1.25, 1)); + UI_SetNext(Flags, UI_BoxFlag_Interactable); + UI_PushCP(UI_BuildRowEx(reset_key)); + { + } + UI_PopCP(UI_TopCP()); + } + + switch (tweak_desc.kind) + { + // Boolean tweak case TweakKind_Bool: { - // Vec4 tweak_bg_color = LerpSrgb(theme.color_negative, theme.color_positive, new_tweak_value.x); - Vec4 tweak_bg_color = Zi; - tweak_bg_color = LerpSrgb(tweak_bg_color, theme.color_positive, new_tweak_value.x); + UI_Key cb_key = UI_KeyF("tweak checkbox"); + UI_Report cb_rep = UI_ReportFromKey(cb_key); - Vec4 tweak_border_color = theme.window_border_color; - // tweak_border_color = LerpSrgb(tweak_border_color, theme.button_hot_color, tweak_rep.hot); - // tweak_border_color = LerpSrgb(tweak_border_color, theme.button_active_color, tweak_rep.active); - tweak_border_color = LerpSrgb(tweak_border_color, theme.button_active_color, tweak_rep.hot); - - if (tweak_rep.m1.downs) + b32 tweak_bool = BoolFromString(new_tweak_str); + if (cb_rep.m1.downs) { - new_tweak_value.x = !new_tweak_value.x; + tweak_bool = !tweak_bool; + new_tweak_str = StringFromBool(frame->arena, tweak_bool); } - UI_SetNext(BackgroundColor, tweak_bg_color); - UI_SetNext(BorderColor, tweak_border_color); - UI_SetNext(Rounding, UI_RGROW(1)); + UI_BuildSpacer(UI_PIX(spacing, 1), Axis_X); + + // Tweak checkbox + Vec4 cb_bg_color = Zi; + Vec4 cb_border_color = theme.window_border_color; + cb_bg_color = LerpSrgb(cb_bg_color, theme.color_positive, tweak_bool); + cb_border_color = LerpSrgb(cb_border_color, theme.button_active_color, cb_rep.hot); + + UI_SetNext(BackgroundColor, cb_bg_color); + UI_SetNext(BorderColor, cb_border_color); + UI_SetNext(Rounding, UI_RGROW(theme.rounding)); UI_SetNext(Border, 2); UI_SetNext(Width, UI_FNT(1.25, 1)); UI_SetNext(Height, UI_FNT(1.25, 1)); UI_SetNext(Flags, UI_BoxFlag_Interactable); - UI_PushCP(UI_BuildRowEx(tweak_key)); + UI_PushCP(UI_BuildRowEx(cb_key)); { } UI_PopCP(UI_TopCP()); - - if (!MatchTweakValue(tweak_var.value, new_tweak_value)) - { - TweakEx(tweak_var.name, tweak_var.kind, new_tweak_value, 1); - } } break; + + // Float tweak + case TweakKind_Float: + { + UI_Key slider_key = UI_KeyF("tweak slider"); + UI_Key marker_key = UI_KeyF("tweak slider marker"); + + UI_Report slider_rep = UI_ReportFromKey(slider_key); + UI_Report marker_rep = UI_ReportFromKey(marker_key); + + Vec2 slider_pos = slider_rep.screen_rect.p0; + Vec2 slider_dims = DimsFromRng2(slider_rep.screen_rect); + + f64 range_min = tweak_desc.range.min; + f64 range_max = tweak_desc.range.max; + if (range_max <= range_min) + { + range_max = range_min + 1; + } + + if (TweakFloat(Lit("Test"), 0.5, 0, 1)) + { + } + + f64 tweak_float = FloatFromString(new_tweak_str); + + { + Axis slider_axis = Axis_X; + if (slider_rep.m1.held) + { + + Vec2 initial_start = slider_rep.last_mouse_down_screen_rect.p0; + Vec2 initial_end = slider_rep.last_mouse_down_screen_rect.p1; + Vec2 initial_dims = SubVec2(initial_end, initial_start); + + Vec2 initial_marker_offset = SubVec2(marker_rep.last_mouse_down_screen_anchor, initial_start); + Vec2 initial_cursor = ui_frame->last_mouse_down_cursor_pos; + + Vec2 virtual_start = SubVec2(initial_cursor, initial_marker_offset); + Vec2 virtual_end = AddVec2(virtual_start, initial_dims); + Vec2 virtual_cursor_offset = SubVec2(frame->ui_cursor, virtual_start); + Vec2 virtual_cursor_ratio = DivVec2Vec2(virtual_cursor_offset, initial_dims); + virtual_cursor_ratio = ClampVec2(virtual_cursor_ratio, RNG2(VEC2(0, 0), VEC2(1, 1))); + + f32 precision = 3; // FIXME: Remove this + tweak_float = LerpF64(range_min, range_max, virtual_cursor_ratio.v[slider_axis]); + new_tweak_str = StringFromFloat(frame->arena, tweak_float, precision); + } + if (slider_rep.is_hot) + { + WND_PushCmd( + window_frame, + .kind = WND_CmdKind_SetCursor, + slider_axis == Axis_X ? WND_CursorKind_HorizontalResize : WND_CursorKind_VerticalResize + ); + } + } + + UI_BuildSpacer(UI_PIX(spacing, 1), Axis_X); + + // Tweak slider + Vec4 slider_bg_color = Zi; + Vec4 slider_border_color = theme.window_border_color; + slider_border_color = LerpSrgb(slider_border_color, theme.button_active_color, slider_rep.hot); + + UI_SetNext(BackgroundColor, slider_bg_color); + UI_SetNext(BorderColor, slider_border_color); + UI_SetNext(Rounding, UI_RGROW(theme.rounding)); + UI_SetNext(Border, 2); + UI_SetNext(Width, UI_FNT(10, 1)); + UI_SetNext(Height, UI_FNT(1.25, 1)); + UI_SetNext(Flags, UI_BoxFlag_Interactable); + UI_PushCP(UI_BuildRowEx(slider_key)); + { + // FIXME: Marker pos should account for marker width + f32 ratio = 0; + ratio = (tweak_float - range_min) / (range_max - range_min); + ratio = ClampF32(ratio, 0, 1); + f32 marker_pos = ratio * slider_dims.x; + + UI_SetNext(BackgroundColor, slider_bg_color); + UI_SetNext(BorderColor, slider_border_color); + UI_SetNext(Rounding, UI_RGROW(theme.rounding)); + UI_SetNext(Border, 2); + UI_SetNext(Width, UI_FNT(1.25, 1)); + UI_SetNext(Height, UI_FNT(1.25, 1)); + UI_SetNext(Anchor, UI_Region_Center); + UI_SetNext(FloatingPos, VEC2(marker_pos, 0)); + UI_SetNext(Flags, UI_BoxFlag_Floating); + UI_BuildBoxEx(marker_key); + } + UI_PopCP(UI_TopCP()); + } break; + } + + if (!MatchString(old_tweak_str, new_tweak_str)) + { + TweakEx(frame->arena, tweak_var.name, tweak_desc, new_tweak_str, 1); } } @@ -1593,7 +1734,7 @@ void V_TickForever(WaveLaneCtx *lane) } // End spacer - UI_BuildSpacer(UI_PIX(20, 1), Axis_X); + UI_BuildSpacer(UI_PIX(spacing, 1), Axis_X); } UI_PopCP(UI_TopCP()); } @@ -1602,11 +1743,11 @@ void V_TickForever(WaveLaneCtx *lane) } UI_PopCP(UI_TopCP()); } - UI_BuildSpacer(UI_PIX(padding, 1), Axis_X); + UI_BuildSpacer(UI_PIX(window_padding, 1), Axis_X); } UI_PopCP(UI_TopCP()); - UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y); + UI_BuildSpacer(UI_PIX(window_padding, 1), Axis_Y); } // UI_PopCP(UI_TopCP()); UI_PopCP(palette_cp); @@ -1622,7 +1763,7 @@ void V_TickForever(WaveLaneCtx *lane) Vec2 dbg_dims = DimsFromRng2(dbg_rep.screen_rect); f32 padding = 20; - f32 rounding = 0; + f32 rounding = 15 * theme.rounding; Vec4 color = VEC4(0, 0, 0, 0.75); UI_SetNext(Flags, UI_BoxFlag_Floating); UI_SetNext(FloatingPos, VEC2(0, frame->ui_dims.y - dbg_dims.y)); diff --git a/src/pp/pp_vis/pp_vis_core.h b/src/pp/pp_vis/pp_vis_core.h index 86080194..0689bd96 100644 --- a/src/pp/pp_vis/pp_vis_core.h +++ b/src/pp/pp_vis/pp_vis_core.h @@ -30,12 +30,13 @@ Struct(V_WidgetTheme) f32 h5; f32 h6; + f32 rounding; + Vec4 window_background_color; Vec4 window_border_color; Vec4 divider_color; f32 window_border; f32 window_padding; - f32 window_width; Vec4 button_color; Vec4 button_hot_color; diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index 93bd17a5..e2d759c4 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -518,6 +518,7 @@ UI_Key UI_BuildBoxEx(UI_Key semantic_key) n->cmd.box.border = UI_Top(Border); n->cmd.box.font = UI_Top(Font); n->cmd.box.font_size = UI_Top(FontSize); + n->cmd.box.rounding = UI_Top(Rounding); n->cmd.box.text = UI_Top(Text); n->cmd.box.anchor = UI_Top(Anchor); @@ -635,6 +636,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color) //- Process controller events frame->cursor_pos = last_frame->cursor_pos; + frame->last_mouse_down_cursor_pos = last_frame->last_mouse_down_cursor_pos; if (last_frame->boxes_pre != 0) { @@ -828,10 +830,16 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color) if (mouse_downs > 0) { - report->last_cursor_down_anchor_offset = SubVec2(frame->cursor_pos, box->screen_anchor); + report->last_mouse_down_screen_rect = box->screen_rect; + report->last_mouse_down_screen_anchor = box->screen_anchor; } } + if (mouse_downs > 0) + { + frame->last_mouse_down_cursor_pos = frame->cursor_pos; + } + frame->top_hovered_box = top_hovered_box ? top_hovered_box->key : UI_NilKey; frame->hot_box = hot_box ? hot_box->key : UI_NilKey; frame->active_box = active_box ? active_box->key : UI_NilKey; diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h index 6d1a8d79..b2311601 100644 --- a/src/ui/ui_core.h +++ b/src/ui/ui_core.h @@ -118,7 +118,7 @@ Enum(UI_BoxFlag) X(FloatingPos, Vec2) \ X(Rounding, UI_Round) \ X(Font, GC_FontKey) \ - X(FontSize, u32) \ + X(FontSize, f32) \ X(Text, String) \ X(BackgroundTexture, G_Texture2DRef) \ X(BackgroundTextureSliceUv, Rng2) \ @@ -203,15 +203,17 @@ Struct(UI_Report) f32 active; f32 selected; - // Mouse button info - Vec2 last_cursor_down_anchor_offset; UI_MouseReport m1; UI_MouseReport m2; UI_MouseReport m3; - // Where was this box last rendered in screen coordinates + // Where was this box rendered in screen coordinates Rng2 screen_rect; Vec2 screen_anchor; + + // Where was this box rendered during the last mouse press + Rng2 last_mouse_down_screen_rect; + Vec2 last_mouse_down_screen_anchor; }; //////////////////////////////////////////////////////////// @@ -378,6 +380,7 @@ Struct(UI_Frame) // Control Vec2 cursor_pos; + Vec2 last_mouse_down_cursor_pos; UI_Key top_hovered_box; UI_Key hot_box; UI_Key active_box;