Revert "Format all"

This reverts commit c7bb89fd6d.
This commit is contained in:
2026-03-12 16:30:04 -04:00
parent 48f2c51d92
commit d5d2f6db8e
31 changed files with 3191 additions and 3280 deletions

View File

@@ -1,31 +0,0 @@
BasedOnStyle: LLVM
IndentWidth: 4
TabWidth: 4
UseTab: Never
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
AlignConsecutiveDeclarations: true
AlignConsecutiveAssignments: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
AlignConsecutiveMacros: true
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: true
Cpp11BracedListStyle: false
ColumnLimit: 0

View File

@@ -1,8 +1,8 @@
#include "audio/audio.h"
#include <math.h>
#include <windows.h>
#include <objbase.h>
#include <string.h>
#include <windows.h>
#include <math.h>
#define AUDIO_MAX_DEVICES 32
#define AUDIO_MAX_CHANNELS 32

View File

@@ -1,9 +1,9 @@
#include "audio/audio.h"
#include <AudioToolbox/AudioToolbox.h>
#include <CoreAudio/CoreAudio.h>
#include <string.h>
#include <math.h>
#include <stdatomic.h>
#include <string.h>
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
@@ -44,11 +44,9 @@ static OSStatus audio_render_callback(void *inRefCon,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData) {
(void)inRefCon;
(void)ioActionFlags;
(void)inTimeStamp;
(void)inBusNumber;
AudioBufferList *ioData)
{
(void)inRefCon; (void)ioActionFlags; (void)inTimeStamp; (void)inBusNumber;
AudioEngine *engine = g_audio_engine;
if (!engine) {
@@ -87,8 +85,7 @@ static OSStatus audio_render_callback(void *inRefCon,
// Advance phase using first channel's traversal
phase += phase_inc * samples_to_gen;
while (phase >= 2.0 * AUDIO_PI)
phase -= 2.0 * AUDIO_PI;
while (phase >= 2.0 * AUDIO_PI) phase -= 2.0 * AUDIO_PI;
engine->test_tone_phase = phase;
S32 new_remaining = atomic_fetch_sub(&engine->test_tone_samples_remaining, samples_to_gen);

View File

@@ -2,11 +2,11 @@
// base_core.h - Fundamental types, macros, and linked list helpers
// Inspired by raddebugger's base_core.h
#include <math.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
////////////////////////////////
// Codebase keywords
@@ -60,8 +60,7 @@ typedef double F64;
#define Max(A, B) (((A) > (B)) ? (A) : (B))
#define ClampTop(A, X) Min(A, X)
#define ClampBot(X, B) Max(X, B)
#define Clamp(A, X, B) (((X) < (A)) ? (A) : ((X) > (B)) ? (B) \
: (X))
#define Clamp(A, X, B) (((X) < (A)) ? (A) : ((X) > (B)) ? (B) : (X))
////////////////////////////////
// Alignment / Sizing
@@ -110,12 +109,7 @@ typedef double F64;
#define Glue_(A, B) A##B
#define Glue(A, B) Glue_(A, B)
#define Swap(T, a, b) \
do { \
T t__ = a; \
a = b; \
b = t__; \
} while (0)
#define Swap(T, a, b) do { T t__ = a; a = b; b = t__; } while (0)
////////////////////////////////
// Assert
@@ -128,10 +122,7 @@ typedef double F64;
# define Trap() (*(volatile int *)0 = 0)
#endif
#define AssertAlways(x) \
do { \
if (!(x)) { Trap(); } \
} while (0)
#define AssertAlways(x) do { if (!(x)) { Trap(); } } while (0)
#ifdef _DEBUG
# define Assert(x) AssertAlways(x)
@@ -151,9 +142,14 @@ typedef double F64;
// Doubly-linked-list (with nil support)
#define DLLInsert_NPZ(nil, f, l, p, n, next, prev) \
(CheckNil(nil, f) ? ((f) = (l) = (n), SetNil(nil, (n)->next), SetNil(nil, (n)->prev)) : CheckNil(nil, p) ? ((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil, (n)->prev)) \
: ((p) == (l)) ? ((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) \
: (((!CheckNil(nil, p) && CheckNil(nil, (p)->next)) ? (0) : ((p)->next->prev = (n))), ((n)->next = (p)->next), ((p)->next = (n)), ((n)->prev = (p))))
(CheckNil(nil, f) ? \
((f) = (l) = (n), SetNil(nil, (n)->next), SetNil(nil, (n)->prev)) : \
CheckNil(nil, p) ? \
((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil, (n)->prev)) : \
((p) == (l)) ? \
((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) : \
(((!CheckNil(nil, p) && CheckNil(nil, (p)->next)) ? (0) : ((p)->next->prev = (n))), \
((n)->next = (p)->next), ((p)->next = (n)), ((n)->prev = (p))))
#define DLLPushBack_NPZ(nil, f, l, n, next, prev) DLLInsert_NPZ(nil, f, l, l, n, next, prev)
#define DLLPushFront_NPZ(nil, f, l, n, next, prev) DLLInsert_NPZ(nil, l, f, f, n, prev, next)
@@ -171,7 +167,9 @@ typedef double F64;
// Singly-linked queue (doubly-headed)
#define SLLQueuePush_NZ(nil, f, l, n, next) \
(CheckNil(nil, f) ? ((f) = (l) = (n), SetNil(nil, (n)->next)) : ((l)->next = (n), (l) = (n), SetNil(nil, (n)->next)))
(CheckNil(nil, f) ? \
((f) = (l) = (n), SetNil(nil, (n)->next)) : \
((l)->next = (n), (l) = (n), SetNil(nil, (n)->next)))
#define SLLQueuePush(f, l, n) SLLQueuePush_NZ(0, f, l, n, next)
#define SLLQueuePushFront(f, l, n) (((n)->next = (f)), ((f) = (n)))

View File

@@ -2,7 +2,7 @@
// base_inc.h - Umbrella include for the base layer
// Include this one header to get all base types.
#include "base/base_arena.h"
#include "base/base_core.h"
#include "base/base_arena.h"
#include "base/base_math.h"
#include "base/base_strings.h"

View File

@@ -30,31 +30,17 @@ enum Corner {
////////////////////////////////
// Vector types
struct Vec2F32 {
F32 x, y;
};
struct Vec2S32 {
S32 x, y;
};
struct Vec3F32 {
F32 x, y, z;
};
struct Vec4F32 {
F32 x, y, z, w;
};
struct Vec2F32 { F32 x, y; };
struct Vec2S32 { S32 x, y; };
struct Vec3F32 { F32 x, y, z; };
struct Vec4F32 { F32 x, y, z, w; };
////////////////////////////////
// Range types
struct Rng1F32 {
F32 min, max;
};
struct Rng1S64 {
S64 min, max;
};
struct Rng2F32 {
Vec2F32 p0, p1;
};
struct Rng1F32 { F32 min, max; };
struct Rng1S64 { S64 min, max; };
struct Rng2F32 { Vec2F32 p0, p1; };
////////////////////////////////
// Constructors
@@ -79,8 +65,7 @@ static inline Vec2F32 scale_2f32(Vec2F32 v, F32 s) { return { v.x * s, v.y * s }
// Axis-indexed access
static inline F32 v2f32_axis(Vec2F32 v, Axis2 a) { return a == Axis2_X ? v.x : v.y; }
static inline void v2f32_set_axis(Vec2F32 *v, Axis2 a, F32 val) {
if (a == Axis2_X) v->x = val;
else v->y = val;
if (a == Axis2_X) v->x = val; else v->y = val;
}
////////////////////////////////

View File

@@ -4,34 +4,34 @@
#include <mach/mach_time.h>
#endif
// [h]
#include "audio/audio.h"
#include "base/base_inc.h"
#include "midi/midi.h"
#include "platform/platform.h"
#include "renderer/renderer.h"
#include "midi/midi.h"
#include "audio/audio.h"
#include "ui/ui_core.h"
#include "ui/ui_icons.h"
#include "ui/ui_piano.h"
#include "ui/ui_popups.h"
#include "ui/ui_widgets.h"
#include "ui/ui_popups.h"
#include "ui/ui_piano.h"
// [cpp]
#include "base/base_inc.cpp"
#include "ui/ui_core.cpp"
#include "ui/ui_icons.cpp"
#include "ui/ui_piano.cpp"
#include "ui/ui_popups.cpp"
#include "ui/ui_widgets.cpp"
#include "ui/ui_popups.cpp"
#include "ui/ui_piano.cpp"
#ifdef __APPLE__
#include "audio/audio_coreaudio.cpp"
#include "midi/midi_coremidi.cpp"
#include "platform/platform_macos.mm"
#include "renderer/renderer_metal.mm"
#include "midi/midi_coremidi.cpp"
#include "audio/audio_coreaudio.cpp"
#else
#include "audio/audio_asio.cpp"
#include "midi/midi_win32.cpp"
#include "platform/platform_win32.cpp"
#include "renderer/renderer_vulkan.cpp"
#include "midi/midi_win32.cpp"
#include "audio/audio_asio.cpp"
#endif
#include "menus.cpp"
@@ -182,7 +182,9 @@ static void build_browser_panel(AppState *app) {
.sizing = { .width = CLAY_SIZING_FIXED(uis(app->browser_width)), .height = CLAY_SIZING_GROW() },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
},
.backgroundColor = bp_top, .custom = { .customData = bp_grad }, ) {
.backgroundColor = bp_top,
.custom = { .customData = bp_grad },
) {
{
S32 sel = 0;
static const char *browser_tabs[] = { "Browser" };
@@ -195,11 +197,13 @@ static void build_browser_panel(AppState *app) {
.padding = { uip(8), uip(8), uip(6), uip(6) },
.childGap = uip(4),
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}) {
}
) {
// Top highlight (beveled edge)
CLAY(CLAY_ID("BrowserHighlight"),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } },
.backgroundColor = g_theme.bg_lighter) {}
.backgroundColor = g_theme.bg_lighter
) {}
CLAY_TEXT(CLAY_STRING("Instruments"), &g_text_config_normal);
}
}
@@ -215,7 +219,9 @@ static void build_main_panel(AppState *app) {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
},
.backgroundColor = mp_top, .custom = { .customData = mp_grad }) {
.backgroundColor = mp_top,
.custom = { .customData = mp_grad }
) {
{
S32 sel = 0;
static const char *main_tabs[] = { "Main" };
@@ -226,7 +232,8 @@ static void build_main_panel(AppState *app) {
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}) {
}
) {
CLAY(CLAY_ID("MainContent"),
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
@@ -234,11 +241,13 @@ static void build_main_panel(AppState *app) {
.childGap = uip(12),
.layoutDirection = CLAY_TOP_TO_BOTTOM,
},
.clip = { .vertical = true, .childOffset = Clay_GetScrollOffset() }, ) {
.clip = { .vertical = true, .childOffset = Clay_GetScrollOffset() },
) {
// Top highlight (beveled edge)
CLAY(CLAY_ID("MainHighlight"),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } },
.backgroundColor = g_theme.bg_lighter) {}
.backgroundColor = g_theme.bg_lighter
) {}
// Section: Buttons
ui_label("LblButtons", "Buttons");
CLAY(CLAY_ID("ButtonRow"),
@@ -246,7 +255,8 @@ static void build_main_panel(AppState *app) {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
.childGap = uip(8),
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}) {
}
) {
if (ui_button("BtnHello", "Click Me")) {
app->demo_button_count++;
}
@@ -262,7 +272,8 @@ static void build_main_panel(AppState *app) {
// Separator
CLAY(CLAY_ID("Sep1"),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } },
.backgroundColor = g_theme.border) {}
.backgroundColor = g_theme.border
) {}
// Section: Checkboxes
ui_label("LblCheckboxes", "Checkboxes");
@@ -271,7 +282,8 @@ static void build_main_panel(AppState *app) {
CLAY(CLAY_ID("Sep2"),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } },
.backgroundColor = g_theme.border) {}
.backgroundColor = g_theme.border
) {}
// Section: Radio buttons
ui_label("LblRadio", "Output Format");
@@ -280,7 +292,8 @@ static void build_main_panel(AppState *app) {
CLAY(CLAY_ID("Sep3"),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } },
.backgroundColor = g_theme.border) {}
.backgroundColor = g_theme.border
) {}
// Section: Text inputs
ui_label("LblText", "Text Inputs");
@@ -289,13 +302,15 @@ static void build_main_panel(AppState *app) {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT() },
.childGap = uip(8),
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}) {
}
) {
CLAY(CLAY_ID("TextCol1"),
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT() },
.childGap = uip(4),
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}) {
}
) {
ui_label("LblName", "Name:");
ui_text_input("TxtName", app->demo_text_a, sizeof(app->demo_text_a));
}
@@ -304,7 +319,8 @@ static void build_main_panel(AppState *app) {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT() },
.childGap = uip(4),
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}) {
}
) {
ui_label("LblPath", "Output Path:");
ui_text_input("TxtPath", app->demo_text_b, sizeof(app->demo_text_b));
}
@@ -312,21 +328,24 @@ static void build_main_panel(AppState *app) {
CLAY(CLAY_ID("Sep4"),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } },
.backgroundColor = g_theme.border) {}
.backgroundColor = g_theme.border
) {}
// Section: Dropdown
ui_label("LblDropdown", "Sample Rate");
CLAY(CLAY_ID("DropdownWrapper"),
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(uis(200)), .height = CLAY_SIZING_FIT() },
}) {
}
) {
static const char *rate_options[] = { "44100 Hz", "48000 Hz", "88200 Hz", "96000 Hz", "192000 Hz" };
ui_dropdown("DropRate", rate_options, 5, &app->demo_dropdown_sel);
}
CLAY(CLAY_ID("Sep5"),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } },
.backgroundColor = g_theme.border) {}
.backgroundColor = g_theme.border
) {}
// Section: Knobs
ui_label("LblKnobs", "Knobs");
@@ -335,14 +354,16 @@ static void build_main_panel(AppState *app) {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
.childGap = uip(16),
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}) {
}
) {
ui_knob("KnobVolume", "Volume", &app->demo_knob_unsigned, 100.0f, 0, 75.0f, 1);
ui_knob("KnobPan", "Pan", &app->demo_knob_signed, 50.0f, 1, 0.0f, 1);
}
CLAY(CLAY_ID("Sep6"),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } },
.backgroundColor = g_theme.border) {}
.backgroundColor = g_theme.border
) {}
// Section: Sliders
ui_label("LblSliders", "Sliders");
@@ -351,7 +372,8 @@ static void build_main_panel(AppState *app) {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
.childGap = uip(16),
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}) {
}
) {
ui_slider_h("SliderH", "Horizontal", &app->demo_slider_h, 100.0f, 0, 50.0f, 1);
}
CLAY(CLAY_ID("SliderVRow"),
@@ -360,14 +382,16 @@ static void build_main_panel(AppState *app) {
.childGap = uip(24),
.childAlignment = { .y = CLAY_ALIGN_Y_TOP },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}) {
}
) {
ui_slider_v("SliderV", "Vertical", &app->demo_slider_v, 100.0f, 0, 75.0f, 1);
ui_fader("Fader1", "Fader", &app->demo_fader, 50.0f, 1, 0.0f, 1);
}
CLAY(CLAY_ID("Sep7"),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } },
.backgroundColor = g_theme.border) {}
.backgroundColor = g_theme.border
) {}
// Section: Windows & Modals
ui_label("LblWindows", "Windows & Modals");
@@ -376,7 +400,8 @@ static void build_main_panel(AppState *app) {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
.childGap = uip(8),
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}) {
}
) {
if (ui_button("BtnAbout", "About")) {
app->show_about_window = 1;
}
@@ -453,19 +478,23 @@ static void build_main_panel(AppState *app) {
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(bar_w), .height = CLAY_SIZING_GROW() },
},
.backgroundColor = g_theme.scrollbar_bg) {
.backgroundColor = g_theme.scrollbar_bg
) {
CLAY(thumb_id,
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(thumb_h) },
},
.backgroundColor = thumb_color, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), .floating = {
.backgroundColor = thumb_color,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
.floating = {
.offset = { 0, thumb_y },
.attachPoints = {
.element = CLAY_ATTACH_POINT_LEFT_TOP,
.parent = CLAY_ATTACH_POINT_LEFT_TOP,
},
.attachTo = CLAY_ATTACH_TO_PARENT,
}, ) {}
},
) {}
}
} else {
app->scrollbar_dragging = false;
@@ -487,7 +516,9 @@ static void build_right_panel(AppState *app) {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
},
.backgroundColor = rp_top, .custom = { .customData = rp_grad }) {
.backgroundColor = rp_top,
.custom = { .customData = rp_grad }
) {
ui_tab_bar("RightTabs", right_tabs, 2, &app->right_panel_tab);
if (app->right_panel_tab == 0) {
@@ -498,11 +529,13 @@ static void build_right_panel(AppState *app) {
.padding = { uip(8), uip(8), uip(6), uip(6) },
.childGap = uip(4),
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}) {
}
) {
// Top highlight (beveled edge)
CLAY(CLAY_ID("PropsHighlight"),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } },
.backgroundColor = g_theme.bg_lighter) {}
.backgroundColor = g_theme.bg_lighter
) {}
CLAY_TEXT(CLAY_STRING("Details"), &g_text_config_normal);
}
} else {
@@ -514,11 +547,13 @@ static void build_right_panel(AppState *app) {
.padding = { uip(8), uip(8), uip(6), uip(6) },
.childGap = uip(6),
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}) {
}
) {
// Top highlight (beveled edge)
CLAY(CLAY_ID("MidiHighlight"),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } },
.backgroundColor = g_theme.bg_lighter) {}
.backgroundColor = g_theme.bg_lighter
) {}
// Refresh button
Clay_ElementId refresh_eid = CLAY_ID("MidiRefreshBtn");
B32 refresh_hovered = Clay_PointerOver(refresh_eid);
@@ -528,7 +563,9 @@ static void build_right_panel(AppState *app) {
.padding = { uip(12), uip(12), 0, 0 },
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = refresh_hovered ? g_theme.accent_hover : g_theme.bg_lighter, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS)) {
.backgroundColor = refresh_hovered ? g_theme.accent_hover : g_theme.bg_lighter,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS)
) {
CLAY_TEXT(CLAY_STRING("Refresh"), &g_text_config_normal);
}
if (refresh_hovered && g_wstate.mouse_clicked) {
@@ -605,14 +642,17 @@ static void build_right_panel(AppState *app) {
.childGap = uip(6),
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}) {
}
) {
// Note name box (colored by velocity)
CLAY(CLAY_IDI("MidiInNote", i),
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(uis(36)), .height = CLAY_SIZING_FIXED(uis(18)) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = box_color, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS)) {
.backgroundColor = box_color,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS)
) {
CLAY_TEXT(note_str, box_txt);
}
// Velocity number
@@ -641,7 +681,8 @@ static void build_right_panel(AppState *app) {
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT() },
.padding = { uip(4), uip(4), uip(2), uip(2) },
}) {
}
) {
CLAY_TEXT(device_str, &g_text_config_normal);
}
}
@@ -665,7 +706,9 @@ static void build_log_panel(AppState *app) {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(uis(app->log_height)) },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
},
.backgroundColor = lp_top, .custom = { .customData = lp_grad }, ) {
.backgroundColor = lp_top,
.custom = { .customData = lp_grad },
) {
static const char *bottom_tabs[] = { "Item Editor", "Sample Mapper" };
ui_tab_bar("BottomTabRow", bottom_tabs, 2, &app->bottom_panel_tab);
@@ -677,10 +720,12 @@ static void build_log_panel(AppState *app) {
.padding = { uip(8), uip(8), uip(6), uip(6) },
.childGap = uip(4),
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}) {
}
) {
CLAY(CLAY_ID("ItemEditorHighlight"),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } },
.backgroundColor = g_theme.bg_lighter) {}
.backgroundColor = g_theme.bg_lighter
) {}
CLAY_TEXT(CLAY_STRING("Item Editor"), &g_text_config_normal);
}
} else {
@@ -690,7 +735,8 @@ static void build_log_panel(AppState *app) {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
.padding = { uip(4), uip(4), uip(4), uip(4) },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}) {
}
) {
F32 piano_avail_h = uis(app->log_height) - TAB_HEIGHT - uip(8);
F32 piano_avail_w = (F32)app->last_w - uip(8);
ui_piano(&app->piano_state, app->midi, piano_avail_w, piano_avail_h);
@@ -718,7 +764,8 @@ static void settings_window_content(void *user_data) {
.padding = { 0, 0, uip(8), 0 },
.childGap = uip(6),
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}) {
}
) {
if (app->settings_tab == 0) {
// === Audio tab ===
ui_label("SettingsLblAudio", "Audio Device");
@@ -732,7 +779,8 @@ static void settings_window_content(void *user_data) {
}
CLAY(CLAY_ID("SettingsAudioWrap"),
.layout = { .sizing = { .width = CLAY_SIZING_FIXED(uis(260)), .height = CLAY_SIZING_FIT() } }) {
.layout = { .sizing = { .width = CLAY_SIZING_FIXED(uis(260)), .height = CLAY_SIZING_FIT() } }
) {
ui_dropdown("SettingsAudio", audio_options, audio_count + 1, &app->audio_device_sel);
}
@@ -750,7 +798,8 @@ static void settings_window_content(void *user_data) {
.childGap = uip(8),
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}) {
}
) {
B32 device_open = (app->audio_device_sel > 0);
B32 tone_playing = audio_is_test_tone_playing(app->audio);
@@ -766,7 +815,9 @@ static void settings_window_content(void *user_data) {
.padding = { uip(12), uip(12), 0, 0 },
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = g_theme.disabled_bg, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS)) {
.backgroundColor = g_theme.disabled_bg,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS)
) {
static Clay_TextElementConfig disabled_text = {};
disabled_text.textColor = g_theme.disabled_text;
disabled_text.fontSize = FONT_SIZE_NORMAL;
@@ -795,21 +846,24 @@ static void settings_window_content(void *user_data) {
ui_label("SettingsLblTheme", "Theme");
static const char *theme_options[] = { "Dark", "Light" };
CLAY(CLAY_ID("SettingsThemeWrap"),
.layout = { .sizing = { .width = CLAY_SIZING_FIXED(uis(220)), .height = CLAY_SIZING_FIT() } }) {
.layout = { .sizing = { .width = CLAY_SIZING_FIXED(uis(220)), .height = CLAY_SIZING_FIT() } }
) {
ui_dropdown("SettingsTheme", theme_options, 2, &app->settings_theme_sel);
}
ui_label("SettingsLblAccent", "Accent Color");
static const char *accent_options[] = { "Blue", "Turquoise", "Orange", "Purple", "Pink", "Red", "Green" };
CLAY(CLAY_ID("SettingsAccentWrap"),
.layout = { .sizing = { .width = CLAY_SIZING_FIXED(uis(220)), .height = CLAY_SIZING_FIT() } }) {
.layout = { .sizing = { .width = CLAY_SIZING_FIXED(uis(220)), .height = CLAY_SIZING_FIT() } }
) {
ui_dropdown("SettingsAccent", accent_options, 7, &app->accent_sel);
}
ui_label("SettingsLblRadius", "Corner Radius");
static const char *radius_options[] = { "None", "Small", "Medium", "Large" };
CLAY(CLAY_ID("SettingsRadiusWrap"),
.layout = { .sizing = { .width = CLAY_SIZING_FIXED(uis(220)), .height = CLAY_SIZING_FIT() } }) {
.layout = { .sizing = { .width = CLAY_SIZING_FIXED(uis(220)), .height = CLAY_SIZING_FIT() } }
) {
if (ui_dropdown("SettingsRadius", radius_options, 4, &app->radius_sel)) {
g_theme.corner_radius = radius_values[app->radius_sel];
}
@@ -831,10 +885,7 @@ static void about_window_content(void *user_data) {
// Panel splitter drag logic (called each frame before build_ui)
static void update_panel_splitters(AppState *app) {
if (app->master_layout != 0) {
platform_set_cursor(PLATFORM_CURSOR_ARROW);
return;
}
if (app->master_layout != 0) { platform_set_cursor(PLATFORM_CURSOR_ARROW); return; }
PlatformInput input = g_wstate.input;
B32 mouse_clicked = input.mouse_down && !input.was_mouse_down;
B32 mouse_released = !input.mouse_down && input.was_mouse_down;
@@ -955,7 +1006,9 @@ static void build_header_bar(AppState *app) {
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
},
.backgroundColor = bar_bg, .border = { .color = border_bot, .width = { .bottom = 2 } }, ) {
.backgroundColor = bar_bg,
.border = { .color = border_bot, .width = { .bottom = 2 } },
) {
// === LEFT: toolbar buttons ===
CLAY(CLAY_ID("ToolbarGroup"),
.layout = {
@@ -963,14 +1016,17 @@ static void build_header_bar(AppState *app) {
.childGap = uip(4),
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}) {
}
) {
// Rewind
CLAY(CLAY_ID("TbRewind"),
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(uis(32)), .height = CLAY_SIZING_FIXED(uis(32)) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = g_theme.bg_lighter, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), ) { ui_icon(UI_ICON_TRANSPORT_REWIND, uis(16), g_theme.text_dim); }
.backgroundColor = g_theme.bg_lighter,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
) { ui_icon(UI_ICON_TRANSPORT_REWIND, uis(16), g_theme.text_dim); }
// Stop
CLAY(CLAY_ID("TbStop"),
@@ -978,7 +1034,9 @@ static void build_header_bar(AppState *app) {
.sizing = { .width = CLAY_SIZING_FIXED(uis(32)), .height = CLAY_SIZING_FIXED(uis(32)) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = g_theme.bg_lighter, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), ) { ui_icon(UI_ICON_TRANSPORT_STOP, uis(14), g_theme.text_dim); }
.backgroundColor = g_theme.bg_lighter,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
) { ui_icon(UI_ICON_TRANSPORT_STOP, uis(14), g_theme.text_dim); }
// Play
CLAY(CLAY_ID("TbPlay"),
@@ -986,7 +1044,9 @@ static void build_header_bar(AppState *app) {
.sizing = { .width = CLAY_SIZING_FIXED(uis(32)), .height = CLAY_SIZING_FIXED(uis(32)) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = g_theme.bg_lighter, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), ) { ui_icon(UI_ICON_TRANSPORT_PLAY, uis(16), g_theme.text_dim); }
.backgroundColor = g_theme.bg_lighter,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
) { ui_icon(UI_ICON_TRANSPORT_PLAY, uis(16), g_theme.text_dim); }
// Record
CLAY(CLAY_ID("TbRecord"),
@@ -994,12 +1054,15 @@ static void build_header_bar(AppState *app) {
.sizing = { .width = CLAY_SIZING_FIXED(uis(32)), .height = CLAY_SIZING_FIXED(uis(32)) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = g_theme.bg_lighter, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), ) { ui_icon(UI_ICON_TRANSPORT_RECORD, uis(14), Clay_Color{ 200, 60, 60, 255 }); }
.backgroundColor = g_theme.bg_lighter,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
) { ui_icon(UI_ICON_TRANSPORT_RECORD, uis(14), Clay_Color{200, 60, 60, 255}); }
}
// Spacer
CLAY(CLAY_ID("HeaderSpacerL"),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } }) {}
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } }
) {}
// === CENTER: time display (nearly full header height) ===
CLAY(CLAY_ID("TimeDisplay"),
@@ -1007,7 +1070,10 @@ static void build_header_bar(AppState *app) {
.sizing = { .width = CLAY_SIZING_FIXED(uis(200)), .height = CLAY_SIZING_FIXED(uis(48)) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = inset_bg, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), .border = { .color = border_bot, .width = { .left = 1, .right = 1, .top = 1, .bottom = 1 } }, ) {
.backgroundColor = inset_bg,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
.border = { .color = border_bot, .width = { .left = 1, .right = 1, .top = 1, .bottom = 1 } },
) {
CLAY_TEXT(CLAY_STRING("00:00:00.000"), &header_clock_text);
}
@@ -1018,7 +1084,8 @@ static void build_header_bar(AppState *app) {
.childGap = uip(10),
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}) {
}
) {
// Tempo
CLAY(CLAY_ID("TempoBox"),
.layout = {
@@ -1028,7 +1095,10 @@ static void build_header_bar(AppState *app) {
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
},
.backgroundColor = inset_bg, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), .border = { .color = border_bot, .width = { .left = 1, .right = 1, .top = 1, .bottom = 1 } }, ) {
.backgroundColor = inset_bg,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
.border = { .color = border_bot, .width = { .left = 1, .right = 1, .top = 1, .bottom = 1 } },
) {
CLAY_TEXT(CLAY_STRING("TEMPO"), &header_indicator_label);
CLAY_TEXT(CLAY_STRING("120.00"), &header_indicator_text);
}
@@ -1042,7 +1112,10 @@ static void build_header_bar(AppState *app) {
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
},
.backgroundColor = inset_bg, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), .border = { .color = border_bot, .width = { .left = 1, .right = 1, .top = 1, .bottom = 1 } }, ) {
.backgroundColor = inset_bg,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
.border = { .color = border_bot, .width = { .left = 1, .right = 1, .top = 1, .bottom = 1 } },
) {
CLAY_TEXT(CLAY_STRING("SIGNATURE"), &header_indicator_label);
CLAY_TEXT(CLAY_STRING("4 / 4"), &header_indicator_text);
}
@@ -1050,7 +1123,8 @@ static void build_header_bar(AppState *app) {
// Spacer
CLAY(CLAY_ID("HeaderSpacerR"),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } }) {}
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } }
) {}
// === RIGHT: Edit / Mix buttons ===
// Edit button
@@ -1066,7 +1140,9 @@ static void build_header_bar(AppState *app) {
.padding = { uip(14), uip(14), 0, 0 },
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = edit_bg, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), ) {
.backgroundColor = edit_bg,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
) {
CLAY_TEXT(CLAY_STRING("Edit"), edit_active ? &header_btn_active_text : &g_text_config_normal);
}
if (edit_hovered && g_wstate.mouse_clicked) {
@@ -1087,7 +1163,9 @@ static void build_header_bar(AppState *app) {
.padding = { uip(14), uip(14), 0, 0 },
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = mix_bg, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), ) {
.backgroundColor = mix_bg,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
) {
CLAY_TEXT(CLAY_STRING("Mix"), mix_active ? &header_btn_active_text : &g_text_config_normal);
}
if (mix_hovered && g_wstate.mouse_clicked) {
@@ -1110,7 +1188,9 @@ static void build_header_bar(AppState *app) {
.sizing = { .width = CLAY_SIZING_FIXED(uis(22)), .height = CLAY_SIZING_FIXED(uis(22)) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = pop_hovered ? g_theme.accent_hover : g_theme.bg_lighter, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), ) {
.backgroundColor = pop_hovered ? g_theme.accent_hover : g_theme.bg_lighter,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
) {
ui_icon(mix_popped ? UI_ICON_POP_IN : UI_ICON_POP_OUT, uis(12), g_theme.text_dim);
}
if (pop_hovered && g_wstate.mouse_clicked) {
@@ -1138,7 +1218,9 @@ static void build_header_bar(AppState *app) {
.padding = { uip(14), uip(14), 0, 0 },
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = patch_bg, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), ) {
.backgroundColor = patch_bg,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
) {
CLAY_TEXT(CLAY_STRING("Patch"), patch_active ? &header_btn_active_text : &g_text_config_normal);
}
if (patch_hovered && g_wstate.mouse_clicked) {
@@ -1161,7 +1243,9 @@ static void build_header_bar(AppState *app) {
.sizing = { .width = CLAY_SIZING_FIXED(uis(22)), .height = CLAY_SIZING_FIXED(uis(22)) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = pop_hovered ? g_theme.accent_hover : g_theme.bg_lighter, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), ) {
.backgroundColor = pop_hovered ? g_theme.accent_hover : g_theme.bg_lighter,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
) {
ui_icon(patch_popped ? UI_ICON_POP_IN : UI_ICON_POP_OUT, uis(12), g_theme.text_dim);
}
if (pop_hovered && g_wstate.mouse_clicked) {
@@ -1193,7 +1277,9 @@ static void build_mix_view(AppState *app) {
.childGap = 0,
.layoutDirection = CLAY_LEFT_TO_RIGHT,
},
.backgroundColor = mv_top, .custom = { .customData = mv_grad }, ) {
.backgroundColor = mv_top,
.custom = { .customData = mv_grad },
) {
static char ch_label_bufs[8][8];
static char fader_id_bufs[8][16];
static char pan_id_bufs[8][16];
@@ -1213,7 +1299,9 @@ static void build_mix_view(AppState *app) {
.childAlignment = { .x = CLAY_ALIGN_X_CENTER },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
},
.backgroundColor = strip_bg, .border = { .color = g_theme.border, .width = { .right = 1 } }, ) {
.backgroundColor = strip_bg,
.border = { .color = g_theme.border, .width = { .right = 1 } },
) {
// Channel label
S32 llen = snprintf(ch_label_bufs[i], sizeof(ch_label_bufs[i]), "Ch %d", i + 1);
Clay_String ch_str = { .isStaticallyAllocated = false, .length = llen, .chars = ch_label_bufs[i] };
@@ -1227,13 +1315,16 @@ static void build_mix_view(AppState *app) {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(uis(22)) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = sr_hovered ? g_theme.accent_hover : g_theme.bg_lighter, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), ) {
.backgroundColor = sr_hovered ? g_theme.accent_hover : g_theme.bg_lighter,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
) {
CLAY_TEXT(CLAY_STRING("SEND/RECV"), &g_text_config_dim);
}
// Spacer pushes pan + fader to bottom
CLAY(CLAY_IDI("MixSpacer", i),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() } }) {}
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() } }
) {}
// Pan knob
ui_knob(pan_id_bufs[i], "Pan", &app->mix_pans[i], 50.0f, 1, 0.0f, 1);
@@ -1261,7 +1352,8 @@ static void build_mix_view(AppState *app) {
.childAlignment = { .x = CLAY_ALIGN_X_CENTER },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
},
.backgroundColor = master_bg, ) {
.backgroundColor = master_bg,
) {
CLAY_TEXT(CLAY_STRING("Master"), &g_text_config_normal);
// SEND/RECV button
@@ -1273,13 +1365,16 @@ static void build_mix_view(AppState *app) {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(uis(22)) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = msr_hovered ? g_theme.accent_hover : g_theme.bg_lighter, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), ) {
.backgroundColor = msr_hovered ? g_theme.accent_hover : g_theme.bg_lighter,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
) {
CLAY_TEXT(CLAY_STRING("SEND/RECV"), &g_text_config_dim);
}
}
CLAY(CLAY_ID("MixMasterSpacer"),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() } }) {}
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() } }
) {}
// Master pan knob
ui_knob("MixMasterPan", "Pan", &app->mix_master_pan, 50.0f, 1, 0.0f, 1);
@@ -1303,7 +1398,9 @@ static void build_patch_view(AppState *app) {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
},
.backgroundColor = pv_top, .custom = { .customData = pv_grad }, ) {
.backgroundColor = pv_top,
.custom = { .customData = pv_grad },
) {
static const char *patch_tabs[] = { "Matrix", "Graph" };
ui_tab_bar("PatchTabs", patch_tabs, 2, &app->patch_tab);
@@ -1349,7 +1446,8 @@ static void build_patch_view(AppState *app) {
.childGap = uip(32),
.layoutDirection = CLAY_LEFT_TO_RIGHT,
},
.clip = { .horizontal = true, .vertical = true, .childOffset = Clay_GetScrollOffset() }, ) {
.clip = { .horizontal = true, .vertical = true, .childOffset = Clay_GetScrollOffset() },
) {
// ============================================================
// INTERNAL ROUTING matrix (32 inputs x 33 outputs)
// ============================================================
@@ -1358,7 +1456,8 @@ static void build_patch_view(AppState *app) {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
.childGap = uip(4),
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}) {
}
) {
// Title
CLAY_TEXT(CLAY_STRING("Internal Routing"), &matrix_title_text);
@@ -1367,7 +1466,8 @@ static void build_patch_view(AppState *app) {
.layout = {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
.padding = { (U16)label_w, 0, 0, 0 },
}) {
}
) {
CLAY_TEXT(CLAY_STRING("OUTPUT >"), &matrix_axis_text);
}
@@ -1376,19 +1476,22 @@ static void build_patch_view(AppState *app) {
.layout = {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}) {
}
) {
// Column headers
CLAY(CLAY_ID("IntHeaderRow"),
.layout = {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIXED(cell_size) },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}) {
}
) {
CLAY(CLAY_ID("IntCorner"),
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(label_w), .height = CLAY_SIZING_FIXED(cell_size) },
.padding = { 0, uip(4), 0, 0 },
.childAlignment = { .x = CLAY_ALIGN_X_RIGHT, .y = CLAY_ALIGN_Y_CENTER },
}) {
}
) {
CLAY_TEXT(CLAY_STRING("INPUT v"), &matrix_axis_text);
}
@@ -1405,7 +1508,8 @@ static void build_patch_view(AppState *app) {
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(cell_size), .height = CLAY_SIZING_FIXED(cell_size) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
}, ) {
},
) {
CLAY_TEXT(dst_str, d == 0 ? &matrix_axis_text : &matrix_hdr_text);
}
}
@@ -1421,13 +1525,15 @@ static void build_patch_view(AppState *app) {
.layout = {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIXED(cell_size) },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}) {
}
) {
CLAY(CLAY_IDI("IntSrcLbl", s),
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(label_w), .height = CLAY_SIZING_FIXED(cell_size) },
.padding = { 0, uip(4), 0, 0 },
.childAlignment = { .x = CLAY_ALIGN_X_RIGHT, .y = CLAY_ALIGN_Y_CENTER },
}, ) {
},
) {
CLAY_TEXT(src_str, &matrix_hdr_text);
}
@@ -1475,7 +1581,9 @@ static void build_patch_view(AppState *app) {
.sizing = { .width = CLAY_SIZING_FIXED(cell_size), .height = CLAY_SIZING_FIXED(cell_size) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = cell_bg, .border = { .color = g_theme.border, .width = { .right = 1, .bottom = 1 } }, ) {
.backgroundColor = cell_bg,
.border = { .color = g_theme.border, .width = { .right = 1, .bottom = 1 } },
) {
if (is_feedback) {
CLAY_TEXT(CLAY_STRING("-"), &fb_text);
} else if (active) {
@@ -1500,7 +1608,8 @@ static void build_patch_view(AppState *app) {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
.childGap = uip(4),
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}) {
}
) {
// Title
CLAY_TEXT(CLAY_STRING("Hardware Routing"), &matrix_title_text);
@@ -1509,7 +1618,8 @@ static void build_patch_view(AppState *app) {
.layout = {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
.padding = { (U16)label_w, 0, 0, 0 },
}) {
}
) {
CLAY_TEXT(CLAY_STRING("HW OUTPUT >"), &matrix_axis_text);
}
@@ -1518,19 +1628,22 @@ static void build_patch_view(AppState *app) {
.layout = {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}) {
}
) {
// Column headers
CLAY(CLAY_ID("HwHeaderRow"),
.layout = {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIXED(cell_size) },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}) {
}
) {
CLAY(CLAY_ID("HwCorner"),
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(label_w), .height = CLAY_SIZING_FIXED(cell_size) },
.padding = { 0, uip(4), 0, 0 },
.childAlignment = { .x = CLAY_ALIGN_X_RIGHT, .y = CLAY_ALIGN_Y_CENTER },
}) {
}
) {
CLAY_TEXT(CLAY_STRING("CH OUT v"), &matrix_axis_text);
}
@@ -1543,7 +1656,8 @@ static void build_patch_view(AppState *app) {
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(cell_size), .height = CLAY_SIZING_FIXED(cell_size) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
}, ) {
},
) {
CLAY_TEXT(dst_str, &matrix_hdr_text);
}
}
@@ -1559,13 +1673,15 @@ static void build_patch_view(AppState *app) {
.layout = {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIXED(cell_size) },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}) {
}
) {
CLAY(CLAY_IDI("HwSrcLbl", s),
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(label_w), .height = CLAY_SIZING_FIXED(cell_size) },
.padding = { 0, uip(4), 0, 0 },
.childAlignment = { .x = CLAY_ALIGN_X_RIGHT, .y = CLAY_ALIGN_Y_CENTER },
}, ) {
},
) {
CLAY_TEXT(src_str, &matrix_hdr_text);
}
@@ -1595,7 +1711,9 @@ static void build_patch_view(AppState *app) {
.sizing = { .width = CLAY_SIZING_FIXED(cell_size), .height = CLAY_SIZING_FIXED(cell_size) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = cell_bg, .border = { .color = g_theme.border, .width = { .right = 1, .bottom = 1 } }, ) {
.backgroundColor = cell_bg,
.border = { .color = g_theme.border, .width = { .right = 1, .bottom = 1 } },
) {
if (active) {
CLAY_TEXT(CLAY_STRING("X"), &cell_x_text);
}
@@ -1618,7 +1736,8 @@ static void build_patch_view(AppState *app) {
.padding = { uip(16), uip(16), uip(12), uip(12) },
.childGap = 0,
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
}) {
}
) {
CLAY_TEXT(CLAY_STRING("Graph view coming soon"), &g_text_config_dim);
}
}
@@ -1644,7 +1763,8 @@ static void build_ui(AppState *app) {
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}) {
}
) {
build_header_bar(app);
if (app->master_layout == 0) {
@@ -1653,14 +1773,16 @@ static void build_ui(AppState *app) {
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}) {
}
) {
build_browser_panel(app);
// Browser splitter (vertical, 1px line)
if (app->show_browser) {
CLAY(CLAY_ID("SplitBrowser"),
.layout = { .sizing = { .width = CLAY_SIZING_FIXED(1), .height = CLAY_SIZING_GROW() } },
.backgroundColor = g_theme.border) {}
.backgroundColor = g_theme.border
) {}
}
build_main_panel(app);
@@ -1669,13 +1791,15 @@ static void build_ui(AppState *app) {
// Right splitter (vertical, 1px line)
CLAY(CLAY_ID("SplitRight"),
.layout = { .sizing = { .width = CLAY_SIZING_FIXED(1), .height = CLAY_SIZING_GROW() } },
.backgroundColor = g_theme.border) {}
.backgroundColor = g_theme.border
) {}
CLAY(CLAY_ID("RightColumn"),
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(uis(app->right_col_width)), .height = CLAY_SIZING_GROW() },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}, ) {
},
) {
build_right_panel(app);
}
}
@@ -1685,7 +1809,8 @@ static void build_ui(AppState *app) {
if (app->show_log) {
CLAY(CLAY_ID("SplitLog"),
.layout = { .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1) } },
.backgroundColor = g_theme.border) {}
.backgroundColor = g_theme.border
) {}
}
build_log_panel(app);
@@ -1701,6 +1826,7 @@ static void build_ui(AppState *app) {
}
}
}
}
////////////////////////////////
@@ -1891,10 +2017,7 @@ int main(int argc, char **argv) {
app.log_height = 180.0f;
app.panel_drag = 0;
app.master_layout = 0;
for (S32 i = 0; i < 8; i++) {
app.mix_faders[i] = 0.0f;
app.mix_pans[i] = 0.0f;
}
for (S32 i = 0; i < 8; i++) { app.mix_faders[i] = 0.0f; app.mix_pans[i] = 0.0f; }
app.mix_master_pan = 0.0f;
app.patch_tab = 0;
memset(app.patch_matrix, 0, sizeof(app.patch_matrix));
@@ -1902,12 +2025,7 @@ int main(int argc, char **argv) {
snprintf(app.demo_text_a, sizeof(app.demo_text_a), "My Instrument");
#ifdef __APPLE__
snprintf(app.demo_text_b, sizeof(app.demo_text_b), "~/Samples/output");
{
mach_timebase_info_data_t tbi;
mach_timebase_info(&tbi);
app.freq_numer = tbi.numer;
app.freq_denom = tbi.denom;
}
{ mach_timebase_info_data_t tbi; mach_timebase_info(&tbi); app.freq_numer = tbi.numer; app.freq_denom = tbi.denom; }
app.last_time = mach_absolute_time();
#else
snprintf(app.demo_text_b, sizeof(app.demo_text_b), "C:\\Samples\\output");

View File

@@ -1,8 +1,8 @@
#include "midi/midi.h"
#include <CoreFoundation/CoreFoundation.h>
#include <CoreMIDI/CoreMIDI.h>
#include <stdatomic.h>
#include <CoreFoundation/CoreFoundation.h>
#include <string.h>
#include <stdatomic.h>
#define MIDI_MAX_DEVICES 64
#define MIDI_RELEASE_FLASH_DURATION 0.15f
@@ -50,10 +50,7 @@ static void midi_read_callback(const MIDIPacketList *pktlist, void *readProcRefC
U8 status = packet->data[j];
// Skip non-status bytes (running status not handled for simplicity)
if (status < 0x80) {
j++;
continue;
}
if (status < 0x80) { j++; continue; }
U8 kind = status & 0xF0;
@@ -95,8 +92,7 @@ static void midi_read_callback(const MIDIPacketList *pktlist, void *readProcRefC
} else if (kind == 0xF0) {
// System messages — skip to end or next status byte
j++;
while (j < packet->length && packet->data[j] < 0x80)
j++;
while (j < packet->length && packet->data[j] < 0x80) j++;
} else {
j += 3; // Default: 3-byte message
}

View File

@@ -1,7 +1,7 @@
#include "midi/midi.h"
#include <windows.h>
#include <mmeapi.h>
#include <string.h>
#include <windows.h>
#define MIDI_MAX_DEVICES 64
#define MIDI_RELEASE_FLASH_DURATION 0.15f

View File

@@ -4,27 +4,16 @@
// macOS virtual key codes (avoids Carbon.h include)
enum {
kVK_ANSI_A = 0x00,
kVK_ANSI_C = 0x08,
kVK_ANSI_V = 0x09,
kVK_ANSI_A = 0x00, kVK_ANSI_C = 0x08, kVK_ANSI_V = 0x09,
kVK_ANSI_X = 0x07,
kVK_Return = 0x24,
kVK_Tab = 0x30,
kVK_Delete = 0x33,
kVK_Escape = 0x35,
kVK_ForwardDelete = 0x75,
kVK_LeftArrow = 0x7B,
kVK_RightArrow = 0x7C,
kVK_DownArrow = 0x7D,
kVK_UpArrow = 0x7E,
kVK_Home = 0x73,
kVK_End = 0x77,
kVK_Command = 0x37,
kVK_Shift = 0x38,
kVK_RightShift = 0x3C,
kVK_RightCommand = 0x36,
kVK_ANSI_Equal = 0x18,
kVK_ANSI_Minus = 0x1B,
kVK_Return = 0x24, kVK_Tab = 0x30, kVK_Delete = 0x33,
kVK_Escape = 0x35, kVK_ForwardDelete = 0x75,
kVK_LeftArrow = 0x7B, kVK_RightArrow = 0x7C,
kVK_DownArrow = 0x7D, kVK_UpArrow = 0x7E,
kVK_Home = 0x73, kVK_End = 0x77,
kVK_Command = 0x37, kVK_Shift = 0x38,
kVK_RightShift = 0x3C, kVK_RightCommand = 0x36,
kVK_ANSI_Equal = 0x18, kVK_ANSI_Minus = 0x1B,
kVK_ANSI_0 = 0x1D,
kVK_ANSI_KeypadEnter = 0x4C,
};
@@ -69,13 +58,8 @@ static PlatformWindow *g_main_window = nullptr;
@end
@implementation ASmplAppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
(void)notification;
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
(void)sender;
return YES;
}
- (void)applicationDidFinishLaunching:(NSNotification *)notification { (void)notification; }
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender { (void)sender; return YES; }
@end
@interface ASmplWindowDelegate : NSObject <NSWindowDelegate> {
@@ -117,10 +101,7 @@ static void platform_macos_insert_text_pw(PlatformWindow *pw, const char *utf8)
PlatformInput *ev = &pw->input;
while (*utf8 && ev->char_count < PLATFORM_MAX_CHARS_PER_FRAME) {
U8 c = (U8)*utf8;
if (c < 32) {
utf8++;
continue;
}
if (c < 32) { utf8++; continue; }
// Handle ASCII printable range (single-byte UTF-8)
if (c < 0x80) {
ev->chars[ev->char_count++] = (U16)c;
@@ -174,45 +155,25 @@ static void platform_macos_key_down_pw(PlatformWindow *pw, U16 keycode, NSEventM
@implementation ASmplView
- (BOOL)acceptsFirstResponder {
return YES;
}
- (BOOL)canBecomeKeyView {
return YES;
}
- (BOOL)acceptsFirstResponder { return YES; }
- (BOOL)canBecomeKeyView { return YES; }
// Needed for NSTextInputClient
- (BOOL)hasMarkedText {
return NO;
}
- (NSRange)markedRange {
return NSMakeRange(NSNotFound, 0);
}
- (NSRange)selectedRange {
return NSMakeRange(NSNotFound, 0);
}
- (BOOL)hasMarkedText { return NO; }
- (NSRange)markedRange { return NSMakeRange(NSNotFound, 0); }
- (NSRange)selectedRange { return NSMakeRange(NSNotFound, 0); }
- (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange {
(void)string;
(void)selectedRange;
(void)replacementRange;
}
- (void)unmarkText {
}
- (NSArray<NSAttributedStringKey> *)validAttributesForMarkedText {
return @[];
(void)string; (void)selectedRange; (void)replacementRange;
}
- (void)unmarkText {}
- (NSArray<NSAttributedStringKey> *)validAttributesForMarkedText { return @[]; }
- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range actualRange:(NSRangePointer)actualRange {
(void)range;
(void)actualRange;
(void)range; (void)actualRange;
return nil;
}
- (NSUInteger)characterIndexForPoint:(NSPoint)point {
(void)point;
return NSNotFound;
}
- (NSUInteger)characterIndexForPoint:(NSPoint)point { (void)point; return NSNotFound; }
- (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actualRange {
(void)range;
(void)actualRange;
(void)range; (void)actualRange;
return NSZeroRect;
}
@@ -249,12 +210,8 @@ static void platform_macos_key_down_pw(PlatformWindow *pw, U16 keycode, NSEventM
if (_platformWindow) _platformWindow->mouse_down_state = 0;
}
- (void)mouseMoved:(NSEvent *)event {
(void)event;
}
- (void)mouseDragged:(NSEvent *)event {
(void)event;
}
- (void)mouseMoved:(NSEvent *)event { (void)event; }
- (void)mouseDragged:(NSEvent *)event { (void)event; }
- (void)scrollWheel:(NSEvent *)event {
if (!_platformWindow) return;
@@ -264,10 +221,7 @@ static void platform_macos_key_down_pw(PlatformWindow *pw, U16 keycode, NSEventM
_platformWindow->input.scroll_delta.y += dy;
}
- (BOOL)acceptsFirstMouse:(NSEvent *)event {
(void)event;
return YES;
}
- (BOOL)acceptsFirstMouse:(NSEvent *)event { (void)event; return YES; }
@end

View File

@@ -3,8 +3,8 @@
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <malloc.h>
#include <windows.h>
#include <malloc.h>
struct PlatformWindow {
HWND hwnd;
@@ -143,7 +143,8 @@ PlatformWindow *platform_create_window(PlatformWindowDesc *desc) {
x, y,
rect.right - rect.left,
rect.bottom - rect.top,
parent_hwnd, nullptr, GetModuleHandleW(nullptr), nullptr);
parent_hwnd, nullptr, GetModuleHandleW(nullptr), nullptr
);
_freea(wtitle);

View File

@@ -30,8 +30,8 @@
#include "renderer/font_inter.gen.h"
// Embedded SPIR-V shaders (generated at build time by glslc)
#include "renderer/ui_frag.spv.h"
#include "renderer/ui_vert.spv.h"
#include "renderer/ui_frag.spv.h"
#define NUM_BACK_BUFFERS 2
#define MAX_VERTICES (64 * 1024)
@@ -172,9 +172,9 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback(
VkDebugUtilsMessageSeverityFlagBitsEXT severity,
VkDebugUtilsMessageTypeFlagsEXT type,
const VkDebugUtilsMessengerCallbackDataEXT *data,
void *user_data) {
(void)type;
(void)user_data;
void *user_data)
{
(void)type; (void)user_data;
if (severity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
OutputDebugStringA("VK: ");
OutputDebugStringA(data->pMessage);
@@ -220,7 +220,8 @@ static void end_one_shot(Renderer *r, VkCommandBuffer cb) {
static void transition_image(VkCommandBuffer cb, VkImage image,
VkImageLayout old_layout, VkImageLayout new_layout,
VkAccessFlags src_access, VkAccessFlags dst_access,
VkPipelineStageFlags src_stage, VkPipelineStageFlags dst_stage) {
VkPipelineStageFlags src_stage, VkPipelineStageFlags dst_stage)
{
VkImageMemoryBarrier barrier = {0};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = old_layout;
@@ -279,8 +280,11 @@ static B32 create_instance(Renderer *r) {
{
VkDebugUtilsMessengerCreateInfoEXT dbg = {0};
dbg.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
dbg.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
dbg.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
dbg.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
dbg.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT
| VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT
| VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
dbg.pfnUserCallback = vk_debug_callback;
PFN_vkCreateDebugUtilsMessengerEXT func =
@@ -644,42 +648,15 @@ static B32 create_pipeline(Renderer *r) {
binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
VkVertexInputAttributeDescription attrs[9] = {};
attrs[0].location = 0;
attrs[0].binding = 0;
attrs[0].format = VK_FORMAT_R32G32_SFLOAT;
attrs[0].offset = offsetof(UIVertex, pos);
attrs[1].location = 1;
attrs[1].binding = 0;
attrs[1].format = VK_FORMAT_R32G32_SFLOAT;
attrs[1].offset = offsetof(UIVertex, uv);
attrs[2].location = 2;
attrs[2].binding = 0;
attrs[2].format = VK_FORMAT_R32G32B32A32_SFLOAT;
attrs[2].offset = offsetof(UIVertex, col);
attrs[3].location = 3;
attrs[3].binding = 0;
attrs[3].format = VK_FORMAT_R32G32_SFLOAT;
attrs[3].offset = offsetof(UIVertex, rect_min);
attrs[4].location = 4;
attrs[4].binding = 0;
attrs[4].format = VK_FORMAT_R32G32_SFLOAT;
attrs[4].offset = offsetof(UIVertex, rect_max);
attrs[5].location = 5;
attrs[5].binding = 0;
attrs[5].format = VK_FORMAT_R32G32B32A32_SFLOAT;
attrs[5].offset = offsetof(UIVertex, corner_radii);
attrs[6].location = 6;
attrs[6].binding = 0;
attrs[6].format = VK_FORMAT_R32_SFLOAT;
attrs[6].offset = offsetof(UIVertex, border_thickness);
attrs[7].location = 7;
attrs[7].binding = 0;
attrs[7].format = VK_FORMAT_R32_SFLOAT;
attrs[7].offset = offsetof(UIVertex, softness);
attrs[8].location = 8;
attrs[8].binding = 0;
attrs[8].format = VK_FORMAT_R32_SFLOAT;
attrs[8].offset = offsetof(UIVertex, mode);
attrs[0].location = 0; attrs[0].binding = 0; attrs[0].format = VK_FORMAT_R32G32_SFLOAT; attrs[0].offset = offsetof(UIVertex, pos);
attrs[1].location = 1; attrs[1].binding = 0; attrs[1].format = VK_FORMAT_R32G32_SFLOAT; attrs[1].offset = offsetof(UIVertex, uv);
attrs[2].location = 2; attrs[2].binding = 0; attrs[2].format = VK_FORMAT_R32G32B32A32_SFLOAT; attrs[2].offset = offsetof(UIVertex, col);
attrs[3].location = 3; attrs[3].binding = 0; attrs[3].format = VK_FORMAT_R32G32_SFLOAT; attrs[3].offset = offsetof(UIVertex, rect_min);
attrs[4].location = 4; attrs[4].binding = 0; attrs[4].format = VK_FORMAT_R32G32_SFLOAT; attrs[4].offset = offsetof(UIVertex, rect_max);
attrs[5].location = 5; attrs[5].binding = 0; attrs[5].format = VK_FORMAT_R32G32B32A32_SFLOAT; attrs[5].offset = offsetof(UIVertex, corner_radii);
attrs[6].location = 6; attrs[6].binding = 0; attrs[6].format = VK_FORMAT_R32_SFLOAT; attrs[6].offset = offsetof(UIVertex, border_thickness);
attrs[7].location = 7; attrs[7].binding = 0; attrs[7].format = VK_FORMAT_R32_SFLOAT; attrs[7].offset = offsetof(UIVertex, softness);
attrs[8].location = 8; attrs[8].binding = 0; attrs[8].format = VK_FORMAT_R32_SFLOAT; attrs[8].offset = offsetof(UIVertex, mode);
VkPipelineVertexInputStateCreateInfo vertex_input = {0};
vertex_input.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
@@ -723,7 +700,8 @@ static B32 create_pipeline(Renderer *r) {
blend_attach.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
blend_attach.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blend_attach.alphaBlendOp = VK_BLEND_OP_ADD;
blend_attach.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
blend_attach.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
| VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
VkPipelineColorBlendStateCreateInfo blend = {0};
blend.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
@@ -999,7 +977,8 @@ static void emit_quad(DrawBatch *batch,
F32 cr, F32 cg, F32 cb, F32 ca,
F32 rmin_x, F32 rmin_y, F32 rmax_x, F32 rmax_y,
F32 cr_tl, F32 cr_tr, F32 cr_br, F32 cr_bl,
F32 border_thickness, F32 softness, F32 mode) {
F32 border_thickness, F32 softness, F32 mode)
{
if (batch->vertex_count + 4 > MAX_VERTICES || batch->index_count + 6 > MAX_INDICES)
return;
@@ -1009,54 +988,28 @@ static void emit_quad(DrawBatch *batch,
F32 px0 = x0, py0 = y0, px1 = x1, py1 = y1;
if (mode < 0.5f) {
F32 pad = softness + 1.0f;
px0 -= pad;
py0 -= pad;
px1 += pad;
py1 += pad;
px0 -= pad; py0 -= pad; px1 += pad; py1 += pad;
}
v[0].pos[0] = px0;
v[0].pos[1] = py0;
v[0].uv[0] = u0;
v[0].uv[1] = v0;
v[1].pos[0] = px1;
v[1].pos[1] = py0;
v[1].uv[0] = u1;
v[1].uv[1] = v0;
v[2].pos[0] = px1;
v[2].pos[1] = py1;
v[2].uv[0] = u1;
v[2].uv[1] = v1;
v[3].pos[0] = px0;
v[3].pos[1] = py1;
v[3].uv[0] = u0;
v[3].uv[1] = v1;
v[0].pos[0] = px0; v[0].pos[1] = py0; v[0].uv[0] = u0; v[0].uv[1] = v0;
v[1].pos[0] = px1; v[1].pos[1] = py0; v[1].uv[0] = u1; v[1].uv[1] = v0;
v[2].pos[0] = px1; v[2].pos[1] = py1; v[2].uv[0] = u1; v[2].uv[1] = v1;
v[3].pos[0] = px0; v[3].pos[1] = py1; v[3].uv[0] = u0; v[3].uv[1] = v1;
for (S32 i = 0; i < 4; i++) {
v[i].col[0] = cr;
v[i].col[1] = cg;
v[i].col[2] = cb;
v[i].col[3] = ca;
v[i].rect_min[0] = rmin_x;
v[i].rect_min[1] = rmin_y;
v[i].rect_max[0] = rmax_x;
v[i].rect_max[1] = rmax_y;
v[i].corner_radii[0] = cr_tl;
v[i].corner_radii[1] = cr_tr;
v[i].corner_radii[2] = cr_br;
v[i].corner_radii[3] = cr_bl;
v[i].col[0] = cr; v[i].col[1] = cg; v[i].col[2] = cb; v[i].col[3] = ca;
v[i].rect_min[0] = rmin_x; v[i].rect_min[1] = rmin_y;
v[i].rect_max[0] = rmax_x; v[i].rect_max[1] = rmax_y;
v[i].corner_radii[0] = cr_tl; v[i].corner_radii[1] = cr_tr;
v[i].corner_radii[2] = cr_br; v[i].corner_radii[3] = cr_bl;
v[i].border_thickness = border_thickness;
v[i].softness = softness;
v[i].mode = mode;
}
U32 *idx = &batch->indices[batch->index_count];
idx[0] = base;
idx[1] = base + 1;
idx[2] = base + 2;
idx[3] = base;
idx[4] = base + 2;
idx[5] = base + 3;
idx[0] = base; idx[1] = base + 1; idx[2] = base + 2;
idx[3] = base; idx[4] = base + 2; idx[5] = base + 3;
batch->vertex_count += 4;
batch->index_count += 6;
@@ -1066,7 +1019,8 @@ static void emit_quad_rotated(DrawBatch *batch,
F32 x0, F32 y0, F32 x1, F32 y1,
F32 u0, F32 v0, F32 u1, F32 v1,
F32 cr, F32 cg, F32 cb, F32 ca,
F32 angle_rad) {
F32 angle_rad)
{
if (batch->vertex_count + 4 > MAX_VERTICES || batch->index_count + 6 > MAX_INDICES)
return;
@@ -1083,49 +1037,34 @@ static void emit_quad_rotated(DrawBatch *batch,
v[0].pos[0] = cx + dx0 * cosA - dy0 * sinA;
v[0].pos[1] = cy + dx0 * sinA + dy0 * cosA;
v[0].uv[0] = u0;
v[0].uv[1] = v0;
v[0].uv[0] = u0; v[0].uv[1] = v0;
v[1].pos[0] = cx + dx1 * cosA - dy0 * sinA;
v[1].pos[1] = cy + dx1 * sinA + dy0 * cosA;
v[1].uv[0] = u1;
v[1].uv[1] = v0;
v[1].uv[0] = u1; v[1].uv[1] = v0;
v[2].pos[0] = cx + dx1 * cosA - dy1 * sinA;
v[2].pos[1] = cy + dx1 * sinA + dy1 * cosA;
v[2].uv[0] = u1;
v[2].uv[1] = v1;
v[2].uv[0] = u1; v[2].uv[1] = v1;
v[3].pos[0] = cx + dx0 * cosA - dy1 * sinA;
v[3].pos[1] = cy + dx0 * sinA + dy1 * cosA;
v[3].uv[0] = u0;
v[3].uv[1] = v1;
v[3].uv[0] = u0; v[3].uv[1] = v1;
for (S32 i = 0; i < 4; i++) {
v[i].col[0] = cr;
v[i].col[1] = cg;
v[i].col[2] = cb;
v[i].col[3] = ca;
v[i].rect_min[0] = 0;
v[i].rect_min[1] = 0;
v[i].rect_max[0] = 0;
v[i].rect_max[1] = 0;
v[i].corner_radii[0] = 0;
v[i].corner_radii[1] = 0;
v[i].corner_radii[2] = 0;
v[i].corner_radii[3] = 0;
v[i].col[0] = cr; v[i].col[1] = cg; v[i].col[2] = cb; v[i].col[3] = ca;
v[i].rect_min[0] = 0; v[i].rect_min[1] = 0;
v[i].rect_max[0] = 0; v[i].rect_max[1] = 0;
v[i].corner_radii[0] = 0; v[i].corner_radii[1] = 0;
v[i].corner_radii[2] = 0; v[i].corner_radii[3] = 0;
v[i].border_thickness = 0;
v[i].softness = 0;
v[i].mode = 2.0f;
}
U32 *idx = &batch->indices[batch->index_count];
idx[0] = base;
idx[1] = base + 1;
idx[2] = base + 2;
idx[3] = base;
idx[4] = base + 2;
idx[5] = base + 3;
idx[0] = base; idx[1] = base + 1; idx[2] = base + 2;
idx[3] = base; idx[4] = base + 2; idx[5] = base + 3;
batch->vertex_count += 4;
batch->index_count += 6;
@@ -1135,7 +1074,8 @@ static void emit_rect(DrawBatch *batch,
F32 x0, F32 y0, F32 x1, F32 y1,
F32 cr, F32 cg, F32 cb, F32 ca,
F32 cr_tl, F32 cr_tr, F32 cr_br, F32 cr_bl,
F32 border_thickness, F32 softness) {
F32 border_thickness, F32 softness)
{
emit_quad(batch, x0, y0, x1, y1,
0, 0, 0, 0,
cr, cg, cb, ca,
@@ -1149,7 +1089,8 @@ static void emit_rect_vgradient(DrawBatch *batch,
F32 tr, F32 tg, F32 tb, F32 ta,
F32 br, F32 bg, F32 bb_, F32 ba,
F32 cr_tl, F32 cr_tr, F32 cr_br, F32 cr_bl,
F32 softness) {
F32 softness)
{
if (batch->vertex_count + 4 > MAX_VERTICES || batch->index_count + 6 > MAX_INDICES)
return;
@@ -1159,61 +1100,29 @@ static void emit_rect_vgradient(DrawBatch *batch,
F32 pad = softness + 1.0f;
F32 px0 = x0 - pad, py0 = y0 - pad, px1 = x1 + pad, py1 = y1 + pad;
v[0].pos[0] = px0;
v[0].pos[1] = py0;
v[0].uv[0] = 0;
v[0].uv[1] = 0;
v[1].pos[0] = px1;
v[1].pos[1] = py0;
v[1].uv[0] = 0;
v[1].uv[1] = 0;
v[2].pos[0] = px1;
v[2].pos[1] = py1;
v[2].uv[0] = 0;
v[2].uv[1] = 0;
v[3].pos[0] = px0;
v[3].pos[1] = py1;
v[3].uv[0] = 0;
v[3].uv[1] = 0;
v[0].pos[0] = px0; v[0].pos[1] = py0; v[0].uv[0] = 0; v[0].uv[1] = 0;
v[1].pos[0] = px1; v[1].pos[1] = py0; v[1].uv[0] = 0; v[1].uv[1] = 0;
v[2].pos[0] = px1; v[2].pos[1] = py1; v[2].uv[0] = 0; v[2].uv[1] = 0;
v[3].pos[0] = px0; v[3].pos[1] = py1; v[3].uv[0] = 0; v[3].uv[1] = 0;
v[0].col[0] = tr;
v[0].col[1] = tg;
v[0].col[2] = tb;
v[0].col[3] = ta;
v[1].col[0] = tr;
v[1].col[1] = tg;
v[1].col[2] = tb;
v[1].col[3] = ta;
v[2].col[0] = br;
v[2].col[1] = bg;
v[2].col[2] = bb_;
v[2].col[3] = ba;
v[3].col[0] = br;
v[3].col[1] = bg;
v[3].col[2] = bb_;
v[3].col[3] = ba;
v[0].col[0] = tr; v[0].col[1] = tg; v[0].col[2] = tb; v[0].col[3] = ta;
v[1].col[0] = tr; v[1].col[1] = tg; v[1].col[2] = tb; v[1].col[3] = ta;
v[2].col[0] = br; v[2].col[1] = bg; v[2].col[2] = bb_; v[2].col[3] = ba;
v[3].col[0] = br; v[3].col[1] = bg; v[3].col[2] = bb_; v[3].col[3] = ba;
for (S32 i = 0; i < 4; i++) {
v[i].rect_min[0] = x0;
v[i].rect_min[1] = y0;
v[i].rect_max[0] = x1;
v[i].rect_max[1] = y1;
v[i].corner_radii[0] = cr_tl;
v[i].corner_radii[1] = cr_tr;
v[i].corner_radii[2] = cr_br;
v[i].corner_radii[3] = cr_bl;
v[i].rect_min[0] = x0; v[i].rect_min[1] = y0;
v[i].rect_max[0] = x1; v[i].rect_max[1] = y1;
v[i].corner_radii[0] = cr_tl; v[i].corner_radii[1] = cr_tr;
v[i].corner_radii[2] = cr_br; v[i].corner_radii[3] = cr_bl;
v[i].border_thickness = 0;
v[i].softness = softness;
v[i].mode = 0;
}
U32 *idx = &batch->indices[batch->index_count];
idx[0] = base;
idx[1] = base + 1;
idx[2] = base + 2;
idx[3] = base;
idx[4] = base + 2;
idx[5] = base + 3;
idx[0] = base; idx[1] = base + 1; idx[2] = base + 2;
idx[3] = base; idx[4] = base + 2; idx[5] = base + 3;
batch->vertex_count += 4;
batch->index_count += 6;
@@ -1221,7 +1130,8 @@ static void emit_rect_vgradient(DrawBatch *batch,
static void emit_text_glyphs(DrawBatch *batch, Renderer *r,
Clay_BoundingBox bbox, Clay_Color color, const char *text, S32 text_len,
U16 font_size) {
U16 font_size)
{
if (text_len == 0 || color.a < 0.1f) return;
F32 cr = color.r / 255.f;
@@ -1269,7 +1179,8 @@ static void emit_text_glyphs(DrawBatch *batch, Renderer *r,
// Flush helper
static void flush_batch(Renderer *r, DrawBatch *batch, U32 buf_idx,
U32 *flush_index_start, VkDescriptorSet tex_set) {
U32 *flush_index_start, VkDescriptorSet tex_set)
{
U32 draw_index_count = batch->index_count - *flush_index_start;
if (draw_index_count == 0) return;
@@ -1817,14 +1728,8 @@ void renderer_resize(Renderer *r, S32 width, S32 height) {
// Clean up old swap chain resources
for (U32 i = 0; i < NUM_BACK_BUFFERS; i++) {
if (r->framebuffers[i]) {
vkDestroyFramebuffer(r->device, r->framebuffers[i], NULL);
r->framebuffers[i] = VK_NULL_HANDLE;
}
if (r->swap_chain_views[i]) {
vkDestroyImageView(r->device, r->swap_chain_views[i], NULL);
r->swap_chain_views[i] = VK_NULL_HANDLE;
}
if (r->framebuffers[i]) { vkDestroyFramebuffer(r->device, r->framebuffers[i], NULL); r->framebuffers[i] = VK_NULL_HANDLE; }
if (r->swap_chain_views[i]) { vkDestroyImageView(r->device, r->swap_chain_views[i], NULL); r->swap_chain_views[i] = VK_NULL_HANDLE; }
}
VkSwapchainKHR old_swap = r->swap_chain;
@@ -1850,14 +1755,8 @@ void renderer_set_font_scale(Renderer *r, F32 scale) {
F32 target_size = 22.0f * scale;
if (fabsf(target_size - r->font_atlas_size) < 0.1f) return;
vkDeviceWaitIdle(r->device);
if (r->font_view) {
vkDestroyImageView(r->device, r->font_view, NULL);
r->font_view = VK_NULL_HANDLE;
}
if (r->font_image) {
vmaDestroyImage(r->allocator, r->font_image, r->font_alloc);
r->font_image = VK_NULL_HANDLE;
}
if (r->font_view) { vkDestroyImageView(r->device, r->font_view, NULL); r->font_view = VK_NULL_HANDLE; }
if (r->font_image) { vmaDestroyImage(r->allocator, r->font_image, r->font_alloc); r->font_image = VK_NULL_HANDLE; }
create_font_atlas(r, target_size);
}

View File

@@ -200,7 +200,8 @@ void ui_destroy(UI_Context *ctx) {
void ui_begin_frame(UI_Context *ctx, F32 viewport_w, F32 viewport_h,
Vec2F32 mouse_pos, B32 mouse_down,
Vec2F32 scroll_delta, F32 dt) {
Vec2F32 scroll_delta, F32 dt)
{
g_measure_ctx = ctx;
Clay_SetCurrentContext(ctx->clay_ctx);
Clay_SetLayoutDimensions(Clay_Dimensions{viewport_w, viewport_h});

View File

@@ -32,7 +32,8 @@ void ui_piano(UI_PianoState *state, MidiEngine *midi, F32 avail_w, F32 avail_h)
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}) {
}
) {
// Compute black key size proportional to white keys
F32 black_key_h = avail_h * PIANO_BLACK_H_PCT;
if (black_key_h < uis(20)) black_key_h = uis(20);
@@ -60,7 +61,9 @@ void ui_piano(UI_PianoState *state, MidiEngine *midi, F32 avail_w, F32 avail_h)
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() },
},
.backgroundColor = bg, .border = { .color = { 190, 190, 190, 255 }, .width = { .right = 1 } }, ) {}
.backgroundColor = bg,
.border = { .color = {190, 190, 190, 255}, .width = { .right = 1 } },
) {}
}
// Black keys (floating, attached to left white key)
@@ -86,7 +89,9 @@ void ui_piano(UI_PianoState *state, MidiEngine *midi, F32 avail_w, F32 avail_h)
.height = CLAY_SIZING_FIXED(black_key_h),
},
},
.backgroundColor = bg, .cornerRadius = { .topLeft = 0, .topRight = 0, .bottomLeft = uis(2), .bottomRight = uis(2) }, .floating = {
.backgroundColor = bg,
.cornerRadius = { .topLeft = 0, .topRight = 0, .bottomLeft = uis(2), .bottomRight = uis(2) },
.floating = {
.parentId = parent_wkey.id,
.zIndex = 100,
.attachPoints = {
@@ -94,7 +99,8 @@ void ui_piano(UI_PianoState *state, MidiEngine *midi, F32 avail_w, F32 avail_h)
.parent = CLAY_ATTACH_POINT_RIGHT_TOP,
},
.attachTo = CLAY_ATTACH_TO_ELEMENT_WITH_ID,
}, ) {}
},
) {}
}
}
}

View File

@@ -1,6 +1,6 @@
#pragma once
#include "midi/midi.h"
#include "ui/ui_core.h"
#include "midi/midi.h"
#define PIANO_FIRST_NOTE 21 // A0
#define PIANO_LAST_NOTE 108 // C8

View File

@@ -23,10 +23,7 @@ PopupWindow *popup_open(PlatformWindow *parent_window, Renderer *parent_renderer
// Find free slot
PopupWindow *popup = nullptr;
for (S32 i = 0; i < MAX_POPUP_WINDOWS; i++) {
if (!g_popups[i].alive) {
popup = &g_popups[i];
break;
}
if (!g_popups[i].alive) { popup = &g_popups[i]; break; }
}
if (!popup) return nullptr;
@@ -140,7 +137,8 @@ void popup_do_frame(PopupWindow *popup, F32 dt) {
.childGap = uip(8),
.layoutDirection = CLAY_TOP_TO_BOTTOM,
},
.backgroundColor = g_theme.bg_medium, ) {
.backgroundColor = g_theme.bg_medium,
) {
if (popup->content_fn) {
popup->content_fn(popup->content_user_data);
}

View File

@@ -1,8 +1,8 @@
#pragma once
#include "platform/platform.h"
#include "renderer/renderer.h"
#include "ui/ui_core.h"
#include "ui/ui_widgets.h"
#include "platform/platform.h"
#include "renderer/renderer.h"
#define MAX_POPUP_WINDOWS 4

View File

@@ -5,10 +5,10 @@
// AFTER a CLAY() block, use Clay_PointerOver(elementId).
#include "ui/ui_widgets.h"
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
UI_WidgetState g_wstate = {};
@@ -82,7 +82,9 @@ static void emit_shadow(Clay_BoundingBox bb, F32 ox, F32 oy, F32 radius,
.height = CLAY_SIZING_FIXED(bb.height + expand*2),
},
},
.backgroundColor = { 0, 0, 0, per_layer }, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS + expand), .floating = {
.backgroundColor = {0, 0, 0, per_layer},
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS + expand),
.floating = {
.offset = { bb.x - expand + ox, bb.y - expand + oy },
.zIndex = z,
.attachPoints = {
@@ -90,7 +92,8 @@ static void emit_shadow(Clay_BoundingBox bb, F32 ox, F32 oy, F32 radius,
.parent = CLAY_ATTACH_POINT_LEFT_TOP,
},
.attachTo = CLAY_ATTACH_TO_ROOT,
}) {}
}
) {}
} else {
CLAY(shadow_eid,
.layout = {
@@ -99,7 +102,9 @@ static void emit_shadow(Clay_BoundingBox bb, F32 ox, F32 oy, F32 radius,
.height = CLAY_SIZING_FIXED(bb.height + expand*2),
},
},
.backgroundColor = { 0, 0, 0, per_layer }, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS + expand), .floating = {
.backgroundColor = {0, 0, 0, per_layer},
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS + expand),
.floating = {
.offset = { -expand + ox, -expand + oy },
.parentId = parent_id,
.zIndex = z,
@@ -108,7 +113,8 @@ static void emit_shadow(Clay_BoundingBox bb, F32 ox, F32 oy, F32 radius,
.parent = parent_attach,
},
.attachTo = CLAY_ATTACH_TO_ELEMENT_WITH_ID,
}) {}
}
) {}
}
}
}
@@ -228,7 +234,8 @@ void ui_icon(UI_IconID icon, F32 size, Clay_Color color) {
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(size), .height = CLAY_SIZING_FIXED(size) },
},
.custom = { .customData = data }) {}
.custom = { .customData = data }
) {}
}
////////////////////////////////
@@ -240,7 +247,8 @@ void ui_label(const char *id, const char *text) {
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT() },
.padding = { 0, 0, uip(2), uip(2) },
}) {
}
) {
CLAY_TEXT(clay_str(text), &g_widget_text_config);
}
}
@@ -265,7 +273,10 @@ B32 ui_button(const char *id, const char *text) {
.padding = { uip(12), uip(12), uip(1), 0 },
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = base, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), .custom = { .customData = grad }, ) {
.backgroundColor = base,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
.custom = { .customData = grad },
) {
CLAY_TEXT(clay_str(text), &g_widget_text_config_btn);
}
@@ -288,7 +299,8 @@ B32 ui_checkbox(const char *id, const char *label, B32 *value) {
.childGap = uip(8),
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}) {
}
) {
// Box
Clay_Color box_bg = *value ? g_theme.accent : g_theme.bg_dark;
if (hovered) {
@@ -299,7 +311,10 @@ B32 ui_checkbox(const char *id, const char *label, B32 *value) {
.sizing = { .width = CLAY_SIZING_FIXED(WIDGET_CHECKBOX_SIZE), .height = CLAY_SIZING_FIXED(WIDGET_CHECKBOX_SIZE) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = box_bg, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), .border = { .color = g_theme.border, .width = { 1, 1, 1, 1 } }) {
.backgroundColor = box_bg,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
.border = { .color = g_theme.border, .width = { 1, 1, 1, 1 } }
) {
if (*value) {
ui_icon(UI_ICON_CHECK, WIDGET_CHECKBOX_SIZE * 0.75f, g_theme.button_text);
}
@@ -329,7 +344,8 @@ B32 ui_radio_group(const char *id, const char **options, S32 count, S32 *selecte
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
.childGap = uip(4),
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}) {
}
) {
for (S32 i = 0; i < count; i++) {
B32 is_selected = (*selected == i);
Clay_ElementId row_id = WIDI(id, i + 100);
@@ -341,7 +357,8 @@ B32 ui_radio_group(const char *id, const char **options, S32 count, S32 *selecte
.childGap = uip(8),
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
}) {
}
) {
// Radio circle
Clay_Color dot_bg = is_selected ? g_theme.accent : g_theme.bg_dark;
if (row_hovered) {
@@ -352,13 +369,18 @@ B32 ui_radio_group(const char *id, const char **options, S32 count, S32 *selecte
.sizing = { .width = CLAY_SIZING_FIXED(WIDGET_RADIO_OUTER), .height = CLAY_SIZING_FIXED(WIDGET_RADIO_OUTER) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = dot_bg, .cornerRadius = CLAY_CORNER_RADIUS(uis(8)), .border = { .color = g_theme.border, .width = { 1, 1, 1, 1 } }) {
.backgroundColor = dot_bg,
.cornerRadius = CLAY_CORNER_RADIUS(uis(8)),
.border = { .color = g_theme.border, .width = { 1, 1, 1, 1 } }
) {
if (is_selected) {
CLAY(WIDI(id, i + 300),
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(WIDGET_RADIO_INNER), .height = CLAY_SIZING_FIXED(WIDGET_RADIO_INNER) },
},
.backgroundColor = g_theme.button_text, .cornerRadius = CLAY_CORNER_RADIUS(uis(4))) {}
.backgroundColor = g_theme.button_text,
.cornerRadius = CLAY_CORNER_RADIUS(uis(4))
) {}
}
}
@@ -398,13 +420,8 @@ void ui_text_input_reset_display_bufs() {
static void text_input_get_sel(S32 *lo, S32 *hi) {
S32 a = g_wstate.sel_start;
S32 b = g_wstate.sel_end;
if (a <= b) {
*lo = a;
*hi = b;
} else {
*lo = b;
*hi = a;
}
if (a <= b) { *lo = a; *hi = b; }
else { *lo = b; *hi = a; }
}
// Helper: true if there's an active selection
@@ -543,10 +560,7 @@ B32 ui_text_input(const char *id, char *buf, S32 buf_size) {
S32 clip_len = (S32)strlen(clip);
// Filter to single line (stop at newline)
for (S32 i = 0; i < clip_len; i++) {
if (clip[i] == '\n' || clip[i] == '\r') {
clip_len = i;
break;
}
if (clip[i] == '\n' || clip[i] == '\r') { clip_len = i; break; }
}
S32 space = buf_size - 1 - len;
if (clip_len > space) clip_len = space;
@@ -594,8 +608,7 @@ B32 ui_text_input(const char *id, char *buf, S32 buf_size) {
break;
case PKEY_LEFT:
if (text_input_has_sel()) {
S32 lo, hi;
text_input_get_sel(&lo, &hi);
S32 lo, hi; text_input_get_sel(&lo, &hi);
g_wstate.cursor_pos = lo;
} else if (g_wstate.cursor_pos > 0) {
g_wstate.cursor_pos--;
@@ -606,8 +619,7 @@ B32 ui_text_input(const char *id, char *buf, S32 buf_size) {
break;
case PKEY_RIGHT:
if (text_input_has_sel()) {
S32 lo, hi;
text_input_get_sel(&lo, &hi);
S32 lo, hi; text_input_get_sel(&lo, &hi);
g_wstate.cursor_pos = hi;
} else if (g_wstate.cursor_pos < len) {
g_wstate.cursor_pos++;
@@ -666,10 +678,7 @@ B32 ui_text_input(const char *id, char *buf, S32 buf_size) {
// our ID was just added above. Find it and advance to next.
S32 my_idx = -1;
for (S32 i = 0; i < g_wstate.text_input_count; i++) {
if (g_wstate.text_input_ids[i] == eid.id) {
my_idx = i;
break;
}
if (g_wstate.text_input_ids[i] == eid.id) { my_idx = i; break; }
}
if (my_idx >= 0) {
// Focus next (wrapping). But we might not have all inputs registered
@@ -723,7 +732,11 @@ B32 ui_text_input(const char *id, char *buf, S32 buf_size) {
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
},
.backgroundColor = bg, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), .custom = { .customData = inset_grad }, .border = { .color = border_color, .width = { 1, 1, 1, 1 } }, ) {
.backgroundColor = bg,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
.custom = { .customData = inset_grad },
.border = { .color = border_color, .width = { 1, 1, 1, 1 } },
) {
if (len == 0 && !is_focused) {
// Placeholder
CLAY_TEXT(CLAY_STRING("..."), &g_widget_text_config_dim);
@@ -746,7 +759,8 @@ B32 ui_text_input(const char *id, char *buf, S32 buf_size) {
.layout = {
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
},
.backgroundColor = g_theme.accent) {
.backgroundColor = g_theme.accent
) {
CLAY_TEXT(clay_str(dbuf_sel), &g_widget_text_config_sel);
}
}
@@ -812,14 +826,11 @@ B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected)
while (lo < hi) {
S32 mid = (lo + hi + 1) / 2;
Vec2F32 seg = ui_measure_text(current_label, mid, FONT_SIZE_NORMAL);
if (seg.x <= target_w) lo = mid;
else hi = mid - 1;
if (seg.x <= target_w) lo = mid; else hi = mid - 1;
}
if (lo + 3 < (S32)sizeof(dd_trunc_buf)) {
memcpy(dd_trunc_buf, current_label, lo);
dd_trunc_buf[lo] = '.';
dd_trunc_buf[lo + 1] = '.';
dd_trunc_buf[lo + 2] = '.';
dd_trunc_buf[lo] = '.'; dd_trunc_buf[lo+1] = '.'; dd_trunc_buf[lo+2] = '.';
dd_trunc_buf[lo+3] = '\0';
display_label = dd_trunc_buf;
}
@@ -839,11 +850,16 @@ B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected)
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
},
.backgroundColor = bg, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), .custom = { .customData = dd_grad }, .border = { .color = is_open ? g_theme.accent : g_theme.border, .width = { 1, 1, 1, 1 } }, ) {
.backgroundColor = bg,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
.custom = { .customData = dd_grad },
.border = { .color = is_open ? g_theme.accent : g_theme.border, .width = { 1, 1, 1, 1 } },
) {
CLAY(text_eid,
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT() },
}) {
}
) {
CLAY_TEXT(clay_str(display_label), &g_widget_text_config);
}
@@ -851,7 +867,8 @@ B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected)
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(uis(20)), .height = CLAY_SIZING_FIXED(uis(20)) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
}) {
}
) {
ui_icon(UI_ICON_CHEVRON_DOWN, uis(12), g_theme.text_dim);
}
}
@@ -885,7 +902,9 @@ B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected)
.sizing = { .width = CLAY_SIZING_FIT(.min = header_width), .height = CLAY_SIZING_FIT() },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
},
.backgroundColor = g_theme.bg_dark, .cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS), .floating = {
.backgroundColor = g_theme.bg_dark,
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS),
.floating = {
.parentId = eid.id,
.zIndex = 2000,
.attachPoints = {
@@ -894,7 +913,8 @@ B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected)
},
.attachTo = CLAY_ATTACH_TO_ELEMENT_WITH_ID,
},
.border = { .color = g_theme.border, .width = { 1, 1, 1, 1 } }, ) {
.border = { .color = g_theme.border, .width = { 1, 1, 1, 1 } },
) {
for (S32 i = 0; i < count; i++) {
B32 is_item_selected = (*selected == i);
Clay_ElementId item_id = WIDI(id, i + 600);
@@ -904,18 +924,11 @@ B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected)
if (item_hovered) item_bg = g_theme.bg_lighter;
Clay_TextElementConfig *item_text = (is_item_selected && !item_hovered)
? &g_widget_text_config_btn
: &g_widget_text_config;
? &g_widget_text_config_btn : &g_widget_text_config;
Clay_CornerRadius item_radius = {};
if (i == 0) {
item_radius.topLeft = CORNER_RADIUS;
item_radius.topRight = CORNER_RADIUS;
}
if (i == count - 1) {
item_radius.bottomLeft = CORNER_RADIUS;
item_radius.bottomRight = CORNER_RADIUS;
}
if (i == 0) { item_radius.topLeft = CORNER_RADIUS; item_radius.topRight = CORNER_RADIUS; }
if (i == count - 1) { item_radius.bottomLeft = CORNER_RADIUS; item_radius.bottomRight = CORNER_RADIUS; }
CLAY(item_id,
.layout = {
@@ -923,7 +936,9 @@ B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected)
.padding = { uip(8), uip(8), 0, 0 },
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = item_bg, .cornerRadius = item_radius) {
.backgroundColor = item_bg,
.cornerRadius = item_radius
) {
CLAY_TEXT(clay_str(options[i]), item_text);
}
@@ -940,10 +955,7 @@ B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected)
// Check if any item was clicked (already handled above)
B32 clicked_item = 0;
for (S32 i = 0; i < count; i++) {
if (Clay_PointerOver(WIDI(id, i + 600))) {
clicked_item = 1;
break;
}
if (Clay_PointerOver(WIDI(id, i + 600))) { clicked_item = 1; break; }
}
if (!clicked_item) {
g_wstate.open_dropdown_id = 0;
@@ -973,7 +985,9 @@ S32 ui_tab_bar(const char *id, const char **labels, S32 count, S32 *selected) {
.padding = { 0, 0, 0, 0 },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
},
.backgroundColor = g_theme.bg_medium, .border = { .color = g_theme.border, .width = { .bottom = 1 } }, ) {
.backgroundColor = g_theme.bg_medium,
.border = { .color = g_theme.border, .width = { .bottom = 1 } },
) {
for (S32 i = 0; i < count; i++) {
Clay_ElementId tab_eid = Clay__HashStringWithOffset(id_str, (U32)i, 0);
B32 is_active = (i == *selected);
@@ -988,7 +1002,9 @@ S32 ui_tab_bar(const char *id, const char **labels, S32 count, S32 *selected) {
.padding = { TAB_PADDING_H, TAB_PADDING_H, 0, uip(6) },
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
},
.cornerRadius = { .topLeft = TAB_CORNER_RADIUS, .topRight = TAB_CORNER_RADIUS, .bottomLeft = 0, .bottomRight = 0 }, .custom = { .customData = &g_tab_gradient }, ) {
.cornerRadius = { .topLeft = TAB_CORNER_RADIUS, .topRight = TAB_CORNER_RADIUS, .bottomLeft = 0, .bottomRight = 0 },
.custom = { .customData = &g_tab_gradient },
) {
CLAY_TEXT(lbl_str, &g_widget_text_config_tab);
}
} else {
@@ -999,7 +1015,9 @@ S32 ui_tab_bar(const char *id, const char **labels, S32 count, S32 *selected) {
.padding = { TAB_PADDING_H, TAB_PADDING_H, 0, uip(6) },
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = bg, .cornerRadius = { .topLeft = TAB_CORNER_RADIUS, .topRight = TAB_CORNER_RADIUS, .bottomLeft = 0, .bottomRight = 0 }, ) {
.backgroundColor = bg,
.cornerRadius = { .topLeft = TAB_CORNER_RADIUS, .topRight = TAB_CORNER_RADIUS, .bottomLeft = 0, .bottomRight = 0 },
) {
CLAY_TEXT(lbl_str, &g_widget_text_config_tab_inactive);
}
}
@@ -1034,11 +1052,7 @@ static S32 value_edit_process_keys(F32 *value, F32 max_val, B32 is_signed, B32 *
#define KE_HAS_SEL() (*esel0 != *esel1)
#define KE_SEL_LO() (*esel0 < *esel1 ? *esel0 : *esel1)
#define KE_SEL_HI() (*esel0 < *esel1 ? *esel1 : *esel0)
#define KE_CLEAR_SEL() \
do { \
*esel0 = *ecur; \
*esel1 = *ecur; \
} while (0)
#define KE_CLEAR_SEL() do { *esel0 = *ecur; *esel1 = *ecur; } while(0)
auto ke_delete_sel = [&]() -> S32 {
S32 lo = KE_SEL_LO(), hi = KE_SEL_HI();
@@ -1054,19 +1068,13 @@ static S32 value_edit_process_keys(F32 *value, F32 max_val, B32 is_signed, B32 *
if (ctrl) {
if (key == PKEY_A) {
*esel0 = 0;
*esel1 = elen;
*ecur = elen;
continue;
*esel0 = 0; *esel1 = elen; *ecur = elen; continue;
}
if (key == PKEY_C) {
if (KE_HAS_SEL()) {
S32 lo = KE_SEL_LO(), hi = KE_SEL_HI();
char tmp[32];
S32 n = hi - lo;
if (n > 31) n = 31;
memcpy(tmp, &ebuf[lo], n);
tmp[n] = '\0';
char tmp[32]; S32 n = hi - lo; if (n > 31) n = 31;
memcpy(tmp, &ebuf[lo], n); tmp[n] = '\0';
platform_clipboard_set(tmp);
}
continue;
@@ -1074,11 +1082,8 @@ static S32 value_edit_process_keys(F32 *value, F32 max_val, B32 is_signed, B32 *
if (key == PKEY_X) {
if (KE_HAS_SEL()) {
S32 lo = KE_SEL_LO(), hi = KE_SEL_HI();
char tmp[32];
S32 n = hi - lo;
if (n > 31) n = 31;
memcpy(tmp, &ebuf[lo], n);
tmp[n] = '\0';
char tmp[32]; S32 n = hi - lo; if (n > 31) n = 31;
memcpy(tmp, &ebuf[lo], n); tmp[n] = '\0';
platform_clipboard_set(tmp);
elen = ke_delete_sel();
}
@@ -1089,8 +1094,7 @@ static S32 value_edit_process_keys(F32 *value, F32 max_val, B32 is_signed, B32 *
if (clip) {
if (KE_HAS_SEL()) elen = ke_delete_sel();
S32 clip_len = (S32)strlen(clip);
char filtered[32];
S32 flen = 0;
char filtered[32]; S32 flen = 0;
for (S32 i = 0; i < clip_len && flen < 30; i++) {
char c = clip[i];
if ((c >= '0' && c <= '9') || c == '.' || c == '-')
@@ -1101,8 +1105,7 @@ static S32 value_edit_process_keys(F32 *value, F32 max_val, B32 is_signed, B32 *
if (flen > 0) {
memmove(&ebuf[*ecur + flen], &ebuf[*ecur], elen - *ecur + 1);
memcpy(&ebuf[*ecur], filtered, flen);
*ecur += flen;
elen += flen;
*ecur += flen; elen += flen;
}
KE_CLEAR_SEL();
}
@@ -1111,40 +1114,29 @@ static S32 value_edit_process_keys(F32 *value, F32 max_val, B32 is_signed, B32 *
continue;
}
if (key == PKEY_RETURN) {
commit = 1;
} else if (key == PKEY_ESCAPE) {
cancel = 1;
} else if (key == PKEY_BACKSPACE) {
if (KE_HAS_SEL()) {
elen = ke_delete_sel();
} else if (*ecur > 0) {
if (key == PKEY_RETURN) { commit = 1; }
else if (key == PKEY_ESCAPE) { cancel = 1; }
else if (key == PKEY_BACKSPACE) {
if (KE_HAS_SEL()) { elen = ke_delete_sel(); }
else if (*ecur > 0) {
memmove(&ebuf[*ecur - 1], &ebuf[*ecur], elen - *ecur + 1);
(*ecur)--;
elen--;
(*ecur)--; elen--;
}
KE_CLEAR_SEL();
} else if (key == PKEY_DELETE) {
if (KE_HAS_SEL()) {
elen = ke_delete_sel();
} else if (*ecur < elen) {
if (KE_HAS_SEL()) { elen = ke_delete_sel(); }
else if (*ecur < elen) {
memmove(&ebuf[*ecur], &ebuf[*ecur + 1], elen - *ecur);
elen--;
}
KE_CLEAR_SEL();
} else if (key == PKEY_LEFT) {
if (KE_HAS_SEL()) {
*ecur = KE_SEL_LO();
} else if (*ecur > 0) {
(*ecur)--;
}
if (KE_HAS_SEL()) { *ecur = KE_SEL_LO(); }
else if (*ecur > 0) { (*ecur)--; }
KE_CLEAR_SEL();
} else if (key == PKEY_RIGHT) {
if (KE_HAS_SEL()) {
*ecur = KE_SEL_HI();
} else if (*ecur < elen) {
(*ecur)++;
}
if (KE_HAS_SEL()) { *ecur = KE_SEL_HI(); }
else if (*ecur < elen) { (*ecur)++; }
KE_CLEAR_SEL();
}
}
@@ -1157,9 +1149,7 @@ static S32 value_edit_process_keys(F32 *value, F32 max_val, B32 is_signed, B32 *
if (KE_HAS_SEL()) elen = ke_delete_sel();
if (elen < 30) {
memmove(&ebuf[*ecur + 1], &ebuf[*ecur], elen - *ecur + 1);
ebuf[*ecur] = (char)ch;
(*ecur)++;
elen++;
ebuf[*ecur] = (char)ch; (*ecur)++; elen++;
}
KE_CLEAR_SEL();
}
@@ -1178,10 +1168,7 @@ static S32 value_edit_process_keys(F32 *value, F32 max_val, B32 is_signed, B32 *
F32 lo = is_signed ? -max_val : 0.0f;
if (parsed < lo) parsed = lo;
if (parsed > max_val) parsed = max_val;
if (parsed != *value) {
*value = parsed;
*changed = 1;
}
if (parsed != *value) { *value = parsed; *changed = 1; }
}
g_wstate.knob_edit_id = 0;
return 1;
@@ -1229,30 +1216,31 @@ static void value_edit_render(U32 hash, F32 width) {
.childAlignment = { .x = CLAY_ALIGN_X_CENTER },
.layoutDirection = CLAY_LEFT_TO_RIGHT,
},
.backgroundColor = g_theme.bg_dark, .cornerRadius = CLAY_CORNER_RADIUS(uis(2)), .border = { .color = g_theme.accent, .width = { 1, 1, 1, 1 } }) {
.backgroundColor = g_theme.bg_dark,
.cornerRadius = CLAY_CORNER_RADIUS(uis(2)),
.border = { .color = g_theme.accent, .width = { 1, 1, 1, 1 } }
) {
if (has_sel) {
if (sel_lo > 0) {
S32 n = sel_lo;
memcpy(ke_dbuf_before, ebuf, n);
ke_dbuf_before[n] = '\0';
memcpy(ke_dbuf_before, ebuf, n); ke_dbuf_before[n] = '\0';
Clay_String s_before = { .length = n, .chars = ke_dbuf_before };
CLAY_TEXT(s_before, &edit_cfg);
}
{
S32 n = sel_hi - sel_lo;
memcpy(ke_dbuf_sel, &ebuf[sel_lo], n);
ke_dbuf_sel[n] = '\0';
memcpy(ke_dbuf_sel, &ebuf[sel_lo], n); ke_dbuf_sel[n] = '\0';
Clay_String s_sel = { .length = n, .chars = ke_dbuf_sel };
CLAY(CLAY_IDI("ValEditSel", (S32)hash),
.layout = { .sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() } },
.backgroundColor = g_theme.accent) {
.backgroundColor = g_theme.accent
) {
CLAY_TEXT(s_sel, &edit_sel_cfg);
}
}
if (sel_hi < elen) {
S32 n = elen - sel_hi;
memcpy(ke_dbuf_after, &ebuf[sel_hi], n);
ke_dbuf_after[n] = '\0';
memcpy(ke_dbuf_after, &ebuf[sel_hi], n); ke_dbuf_after[n] = '\0';
Clay_String s_after = { .length = n, .chars = ke_dbuf_after };
CLAY_TEXT(s_after, &edit_cfg);
}
@@ -1284,10 +1272,7 @@ static void value_edit_click_away(Clay_ElementId eid, F32 *value, F32 max_val, B
F32 lo = is_signed ? -max_val : 0.0f;
if (parsed < lo) parsed = lo;
if (parsed > max_val) parsed = max_val;
if (parsed != *value) {
*value = parsed;
*changed = 1;
}
if (parsed != *value) { *value = parsed; *changed = 1; }
}
g_wstate.knob_edit_id = 0;
}
@@ -1311,11 +1296,8 @@ static void value_edit_enter(U32 hash, F32 value, B32 is_signed) {
// Normalize a value to [0,1] range.
static F32 value_normalize(F32 value, F32 max_val, B32 is_signed) {
F32 n;
if (is_signed) {
n = (value + max_val) / (2.0f * max_val);
} else {
n = value / max_val;
}
if (is_signed) { n = (value + max_val) / (2.0f * max_val); }
else { n = value / max_val; }
if (n < 0.0f) n = 0.0f;
if (n > 1.0f) n = 1.0f;
return n;
@@ -1325,11 +1307,8 @@ static F32 value_normalize(F32 value, F32 max_val, B32 is_signed) {
static char *value_format_text(F32 value, B32 is_signed, S32 *out_len) {
if (g_knob_text_buf_count >= UI_MAX_KNOB_TEXT_BUFS) return nullptr;
char *buf = g_knob_text_bufs[g_knob_text_buf_count++];
if (is_signed) {
*out_len = snprintf(buf, 32, "%+.1f", value);
} else {
*out_len = snprintf(buf, 32, "%.1f", value);
}
if (is_signed) { *out_len = snprintf(buf, 32, "%+.1f", value); }
else { *out_len = snprintf(buf, 32, "%.1f", value); }
return buf;
}
@@ -1368,10 +1347,7 @@ B32 ui_knob(const char *id, const char *label, F32 *value, F32 max_val, B32 is_s
F32 lo = is_signed ? -max_val : 0.0f;
if (new_val < lo) new_val = lo;
if (new_val > max_val) new_val = max_val;
if (new_val != *value) {
*value = new_val;
changed = 1;
}
if (new_val != *value) { *value = new_val; changed = 1; }
normalized = value_normalize(*value, max_val, is_signed);
angle_rad = (-135.0f + normalized * 270.0f) * deg_to_rad;
}
@@ -1397,7 +1373,8 @@ B32 ui_knob(const char *id, const char *label, F32 *value, F32 max_val, B32 is_s
.childGap = WIDGET_KNOB_LABEL_GAP,
.childAlignment = { .x = CLAY_ALIGN_X_CENTER },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}) {
}
) {
Clay_ElementId knob_eid = CLAY_IDI("KnobBg", (S32)knob_hash);
B32 hovered = Clay_PointerOver(knob_eid);
@@ -1406,7 +1383,9 @@ B32 ui_knob(const char *id, const char *label, F32 *value, F32 max_val, B32 is_s
.sizing = { .width = CLAY_SIZING_FIXED(knob_size), .height = CLAY_SIZING_FIXED(knob_size) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
},
.backgroundColor = g_theme.bg_dark, .cornerRadius = CLAY_CORNER_RADIUS(knob_size / 2.0f)) {
.backgroundColor = g_theme.bg_dark,
.cornerRadius = CLAY_CORNER_RADIUS(knob_size / 2.0f)
) {
if (g_rotated_icon_pool_count < UI_MAX_ROTATED_ICONS_PER_FRAME) {
S32 ri_idx = g_rotated_icon_pool_count;
CustomRotatedIconData *rdata = &g_rotated_icon_pool[g_rotated_icon_pool_count++];
@@ -1420,7 +1399,8 @@ B32 ui_knob(const char *id, const char *label, F32 *value, F32 max_val, B32 is_s
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(icon_size), .height = CLAY_SIZING_FIXED(icon_size) },
},
.custom = { .customData = rdata }) {}
.custom = { .customData = rdata }
) {}
}
}
@@ -1432,10 +1412,7 @@ B32 ui_knob(const char *id, const char *label, F32 *value, F32 max_val, B32 is_s
kd->last_click_frame = g_frame_number;
if (is_double_click) {
if (*value != default_val) {
*value = default_val;
changed = 1;
}
if (*value != default_val) { *value = default_val; changed = 1; }
normalized = value_normalize(*value, max_val, is_signed);
angle_rad = (-135.0f + normalized * 270.0f) * deg_to_rad;
kd->last_click_id = 0;
@@ -1465,7 +1442,8 @@ B32 ui_knob(const char *id, const char *label, F32 *value, F32 max_val, B32 is_s
.sizing = { .width = CLAY_SIZING_FIXED(knob_size), .height = CLAY_SIZING_FIT() },
.padding = { uip(2), uip(2), uip(1), uip(1) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER },
}) {
}
) {
CLAY_TEXT(val_str, &knob_val_cfg);
}
@@ -1514,10 +1492,7 @@ B32 ui_slider_h(const char *id, const char *label, F32 *value, F32 max_val, B32
F32 lo = is_signed ? -max_val : 0.0f;
if (new_val < lo) new_val = lo;
if (new_val > max_val) new_val = max_val;
if (new_val != *value) {
*value = new_val;
changed = 1;
}
if (new_val != *value) { *value = new_val; changed = 1; }
normalized = value_normalize(*value, max_val, is_signed);
}
@@ -1545,7 +1520,8 @@ B32 ui_slider_h(const char *id, const char *label, F32 *value, F32 max_val, B32
.childGap = WIDGET_KNOB_LABEL_GAP,
.childAlignment = { .x = CLAY_ALIGN_X_CENTER },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}) {
}
) {
// Label
CLAY_TEXT(clay_str(label), &g_widget_text_config_dim);
@@ -1557,13 +1533,16 @@ B32 ui_slider_h(const char *id, const char *label, F32 *value, F32 max_val, B32
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(track_w), .height = CLAY_SIZING_FIXED(thumb_h) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER },
}) {
}
) {
// Visible track (centered inside hit area)
CLAY(CLAY_IDI("SlHTrack", (S32)hash),
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(track_w), .height = CLAY_SIZING_FIXED(track_h) },
},
.backgroundColor = g_theme.bg_dark, .cornerRadius = CLAY_CORNER_RADIUS(track_h / 2.0f)) {
.backgroundColor = g_theme.bg_dark,
.cornerRadius = CLAY_CORNER_RADIUS(track_h / 2.0f)
) {
// Fill bar
F32 fill_w = normalized * track_w;
if (fill_w < 1.0f) fill_w = 1.0f;
@@ -1571,7 +1550,9 @@ B32 ui_slider_h(const char *id, const char *label, F32 *value, F32 max_val, B32
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(fill_w), .height = CLAY_SIZING_GROW() },
},
.backgroundColor = fill_color, .cornerRadius = CLAY_CORNER_RADIUS(track_h / 2.0f)) {}
.backgroundColor = fill_color,
.cornerRadius = CLAY_CORNER_RADIUS(track_h / 2.0f)
) {}
}
// Floating icon thumb (attached to hit area)
@@ -1598,7 +1579,8 @@ B32 ui_slider_h(const char *id, const char *label, F32 *value, F32 max_val, B32
.attachTo = CLAY_ATTACH_TO_PARENT,
.clipTo = CLAY_CLIP_TO_ATTACHED_PARENT,
},
.custom = { .customData = idata }, ) {}
.custom = { .customData = idata },
) {}
}
}
@@ -1610,10 +1592,7 @@ B32 ui_slider_h(const char *id, const char *label, F32 *value, F32 max_val, B32
kd->last_click_frame = g_frame_number;
if (is_double_click) {
if (*value != default_val) {
*value = default_val;
changed = 1;
}
if (*value != default_val) { *value = default_val; changed = 1; }
normalized = value_normalize(*value, max_val, is_signed);
kd->last_click_id = 0;
} else {
@@ -1642,7 +1621,8 @@ B32 ui_slider_h(const char *id, const char *label, F32 *value, F32 max_val, B32
.sizing = { .width = CLAY_SIZING_FIXED(track_w), .height = CLAY_SIZING_FIT() },
.padding = { uip(2), uip(2), uip(1), uip(1) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER },
}) {
}
) {
CLAY_TEXT(val_str, &sl_val_cfg);
}
@@ -1688,10 +1668,7 @@ B32 ui_slider_v(const char *id, const char *label, F32 *value, F32 max_val, B32
F32 lo = is_signed ? -max_val : 0.0f;
if (new_val < lo) new_val = lo;
if (new_val > max_val) new_val = max_val;
if (new_val != *value) {
*value = new_val;
changed = 1;
}
if (new_val != *value) { *value = new_val; changed = 1; }
normalized = value_normalize(*value, max_val, is_signed);
}
@@ -1719,7 +1696,8 @@ B32 ui_slider_v(const char *id, const char *label, F32 *value, F32 max_val, B32
.childGap = WIDGET_KNOB_LABEL_GAP,
.childAlignment = { .x = CLAY_ALIGN_X_CENTER },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}) {
}
) {
// Label
CLAY_TEXT(clay_str(label), &g_widget_text_config_dim);
@@ -1731,14 +1709,17 @@ B32 ui_slider_v(const char *id, const char *label, F32 *value, F32 max_val, B32
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(thumb_w), .height = CLAY_SIZING_FIXED(track_h) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER },
}) {
}
) {
// Visible track (centered inside hit area)
CLAY(CLAY_IDI("SlVTrack", (S32)hash),
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(track_w), .height = CLAY_SIZING_FIXED(track_h) },
.childAlignment = { .y = CLAY_ALIGN_Y_BOTTOM },
},
.backgroundColor = g_theme.bg_dark, .cornerRadius = CLAY_CORNER_RADIUS(track_w / 2.0f)) {
.backgroundColor = g_theme.bg_dark,
.cornerRadius = CLAY_CORNER_RADIUS(track_w / 2.0f)
) {
// Fill bar (from bottom)
F32 fill_h = normalized * track_h;
if (fill_h < 1.0f) fill_h = 1.0f;
@@ -1746,7 +1727,9 @@ B32 ui_slider_v(const char *id, const char *label, F32 *value, F32 max_val, B32
.layout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(fill_h) },
},
.backgroundColor = fill_color, .cornerRadius = CLAY_CORNER_RADIUS(track_w / 2.0f)) {}
.backgroundColor = fill_color,
.cornerRadius = CLAY_CORNER_RADIUS(track_w / 2.0f)
) {}
}
// Floating icon thumb (attached to hit area)
@@ -1773,7 +1756,8 @@ B32 ui_slider_v(const char *id, const char *label, F32 *value, F32 max_val, B32
.attachTo = CLAY_ATTACH_TO_PARENT,
.clipTo = CLAY_CLIP_TO_ATTACHED_PARENT,
},
.custom = { .customData = idata }, ) {}
.custom = { .customData = idata },
) {}
}
}
@@ -1785,10 +1769,7 @@ B32 ui_slider_v(const char *id, const char *label, F32 *value, F32 max_val, B32
kd->last_click_frame = g_frame_number;
if (is_double_click) {
if (*value != default_val) {
*value = default_val;
changed = 1;
}
if (*value != default_val) { *value = default_val; changed = 1; }
normalized = value_normalize(*value, max_val, is_signed);
kd->last_click_id = 0;
} else {
@@ -1817,7 +1798,8 @@ B32 ui_slider_v(const char *id, const char *label, F32 *value, F32 max_val, B32
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
.padding = { uip(2), uip(2), uip(1), uip(1) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER },
}) {
}
) {
CLAY_TEXT(val_str, &sl_val_cfg);
}
@@ -1863,10 +1845,7 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
F32 lo = is_signed ? -max_val : 0.0f;
if (new_val < lo) new_val = lo;
if (new_val > max_val) new_val = max_val;
if (new_val != *value) {
*value = new_val;
changed = 1;
}
if (new_val != *value) { *value = new_val; changed = 1; }
normalized = value_normalize(*value, max_val, is_signed);
}
@@ -1897,7 +1876,8 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
.childGap = WIDGET_KNOB_LABEL_GAP,
.childAlignment = { .x = CLAY_ALIGN_X_CENTER },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}) {
}
) {
// Label
CLAY_TEXT(clay_str(label), &g_widget_text_config_dim);
@@ -1909,13 +1889,16 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(cap_w), .height = CLAY_SIZING_FIXED(track_h) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER },
}) {
}
) {
// Visible track (centered inside hit area, empty)
CLAY(CLAY_IDI("FdrTrack", (S32)hash),
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(track_w), .height = CLAY_SIZING_FIXED(track_h) },
},
.backgroundColor = g_theme.bg_dark, .cornerRadius = CLAY_CORNER_RADIUS(track_w / 2.0f)) {}
.backgroundColor = g_theme.bg_dark,
.cornerRadius = CLAY_CORNER_RADIUS(track_w / 2.0f)
) {}
// Tick marks on both sides of the track
for (S32 i = 0; i <= num_ticks; i++) {
@@ -1928,7 +1911,8 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(tw), .height = CLAY_SIZING_FIXED(tick_h) },
},
.backgroundColor = g_theme.text_dim, .floating = {
.backgroundColor = g_theme.text_dim,
.floating = {
.offset = {
.x = track_left - tw,
.y = tick_y,
@@ -1940,14 +1924,16 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
.pointerCaptureMode = CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH,
.attachTo = CLAY_ATTACH_TO_PARENT,
.clipTo = CLAY_CLIP_TO_ATTACHED_PARENT,
}, ) {}
},
) {}
// Right tick
CLAY(CLAY_IDI("FdrTkR", (S32)(hash * 100 + i)),
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(tw), .height = CLAY_SIZING_FIXED(tick_h) },
},
.backgroundColor = g_theme.text_dim, .floating = {
.backgroundColor = g_theme.text_dim,
.floating = {
.offset = {
.x = track_left + track_w,
.y = tick_y,
@@ -1959,7 +1945,8 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
.pointerCaptureMode = CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH,
.attachTo = CLAY_ATTACH_TO_PARENT,
.clipTo = CLAY_CLIP_TO_ATTACHED_PARENT,
}, ) {}
},
) {}
}
// Floating fader cap (RGBA icon from asset SVG)
@@ -1985,7 +1972,8 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
.attachTo = CLAY_ATTACH_TO_PARENT,
.clipTo = CLAY_CLIP_TO_ATTACHED_PARENT,
},
.custom = { .customData = idata }, ) {}
.custom = { .customData = idata },
) {}
// Color tint overlay on top of fader cap
Clay_Color tint = g_theme.accent;
@@ -1995,7 +1983,9 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
.layout = {
.sizing = { .width = CLAY_SIZING_FIXED(cap_w), .height = CLAY_SIZING_FIXED(cap_h) },
},
.backgroundColor = tint, .cornerRadius = CLAY_CORNER_RADIUS(cap_corner), .floating = {
.backgroundColor = tint,
.cornerRadius = CLAY_CORNER_RADIUS(cap_corner),
.floating = {
.offset = { .x = 0, .y = cap_y },
.attachPoints = {
.element = CLAY_ATTACH_POINT_LEFT_TOP,
@@ -2004,7 +1994,8 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
.pointerCaptureMode = CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH,
.attachTo = CLAY_ATTACH_TO_PARENT,
.clipTo = CLAY_CLIP_TO_ATTACHED_PARENT,
}, ) {}
},
) {}
}
}
@@ -2016,10 +2007,7 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
kd->last_click_frame = g_frame_number;
if (is_double_click) {
if (*value != default_val) {
*value = default_val;
changed = 1;
}
if (*value != default_val) { *value = default_val; changed = 1; }
normalized = value_normalize(*value, max_val, is_signed);
kd->last_click_id = 0;
} else {
@@ -2048,7 +2036,8 @@ B32 ui_fader(const char *id, const char *label, F32 *value, F32 max_val, B32 is_
.sizing = { .width = CLAY_SIZING_FIT(), .height = CLAY_SIZING_FIT() },
.padding = { uip(2), uip(2), uip(1), uip(1) },
.childAlignment = { .x = CLAY_ALIGN_X_CENTER },
}) {
}
) {
CLAY_TEXT(val_str, &fdr_val_cfg);
}

View File

@@ -6,9 +6,9 @@
// The caller owns all data — the widget layer only stores transient UI state
// like which text field is focused or which dropdown is open.
#include "platform/platform.h"
#include "ui/ui_core.h"
#include "ui/ui_icons.h"
#include "platform/platform.h"
////////////////////////////////
// Widget state (global, managed by widget layer)