tweak palette sliders

This commit is contained in:
jacob 2025-12-31 20:56:57 -06:00
parent 4f36aaf07a
commit 102bb6dc36
14 changed files with 406 additions and 89 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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