add themes and colors :D
This commit is contained in:
52
src/main.cpp
52
src/main.cpp
@@ -10,7 +10,6 @@
|
||||
#include "midi/midi.h"
|
||||
#include "audio/audio.h"
|
||||
#include "ui/ui_core.h"
|
||||
#include "ui/ui_theme.h"
|
||||
#include "ui/ui_widgets.h"
|
||||
|
||||
// [cpp]
|
||||
@@ -94,9 +93,14 @@ struct AppState {
|
||||
B32 show_about_window;
|
||||
B32 show_confirm_dialog;
|
||||
S32 settings_theme_sel;
|
||||
S32 settings_theme_prev;
|
||||
B32 settings_vsync;
|
||||
B32 settings_autosave;
|
||||
|
||||
// Accent color selection
|
||||
S32 accent_sel;
|
||||
S32 accent_prev;
|
||||
|
||||
// Audio device selection
|
||||
S32 audio_device_sel; // dropdown index: 0 = None, 1+ = device
|
||||
S32 audio_device_prev; // previous selection for change detection
|
||||
@@ -507,11 +511,19 @@ static void settings_window_content(void *user_data) {
|
||||
AppState *app = (AppState *)user_data;
|
||||
|
||||
ui_label("SettingsLblTheme", "Theme");
|
||||
static const char *theme_options[] = { "Dark", "Light", "Solarized" };
|
||||
static const char *theme_options[] = { "Dark", "Light" };
|
||||
CLAY(CLAY_ID("SettingsThemeWrap"),
|
||||
.layout = { .sizing = { .width = CLAY_SIZING_FIXED(uis(180)), .height = CLAY_SIZING_FIT() } }
|
||||
) {
|
||||
ui_dropdown("SettingsTheme", theme_options, 3, &app->settings_theme_sel);
|
||||
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(180)), .height = CLAY_SIZING_FIT() } }
|
||||
) {
|
||||
ui_dropdown("SettingsAccent", accent_options, 7, &app->accent_sel);
|
||||
}
|
||||
|
||||
ui_checkbox("SettingsVsync", "V-Sync", &app->settings_vsync);
|
||||
@@ -575,11 +587,11 @@ static void settings_window_content(void *user_data) {
|
||||
.padding = { uip(12), uip(12), 0, 0 },
|
||||
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER },
|
||||
},
|
||||
.backgroundColor = Clay_Color{50, 50, 50, 255},
|
||||
.backgroundColor = g_theme.disabled_bg,
|
||||
.cornerRadius = CLAY_CORNER_RADIUS(uis(3))
|
||||
) {
|
||||
static Clay_TextElementConfig disabled_text = {};
|
||||
disabled_text.textColor = Clay_Color{100, 100, 100, 255};
|
||||
disabled_text.textColor = g_theme.disabled_text;
|
||||
disabled_text.fontSize = FONT_SIZE_NORMAL;
|
||||
disabled_text.wrapMode = CLAY_TEXT_WRAP_NONE;
|
||||
CLAY_TEXT(CLAY_STRING("Play Test Tone"), &disabled_text);
|
||||
@@ -705,6 +717,34 @@ static void do_frame(AppState *app) {
|
||||
g_ui_scale = app->ui_scale;
|
||||
renderer_set_font_scale(app->renderer, app->ui_scale);
|
||||
|
||||
// Handle theme change
|
||||
if (app->settings_theme_sel != app->settings_theme_prev) {
|
||||
ui_set_theme(app->settings_theme_sel);
|
||||
ui_set_accent(app->accent_sel); // reapply accent on new base theme
|
||||
app->settings_theme_prev = app->settings_theme_sel;
|
||||
|
||||
// Refresh all text configs with new theme colors
|
||||
g_text_config_normal.textColor = g_theme.text;
|
||||
g_text_config_title.textColor = g_theme.text;
|
||||
g_text_config_dim.textColor = g_theme.text_dim;
|
||||
ui_widgets_theme_changed();
|
||||
|
||||
// Update renderer clear color to match theme
|
||||
renderer_set_clear_color(app->renderer,
|
||||
g_theme.bg_dark.r / 255.f, g_theme.bg_dark.g / 255.f, g_theme.bg_dark.b / 255.f);
|
||||
}
|
||||
|
||||
// Handle accent change
|
||||
if (app->accent_sel != app->accent_prev) {
|
||||
ui_set_accent(app->accent_sel);
|
||||
app->accent_prev = app->accent_sel;
|
||||
|
||||
g_text_config_normal.textColor = g_theme.text;
|
||||
g_text_config_title.textColor = g_theme.text;
|
||||
g_text_config_dim.textColor = g_theme.text_dim;
|
||||
ui_widgets_theme_changed();
|
||||
}
|
||||
|
||||
// Update text configs when scale changes
|
||||
if (g_text_config_normal.fontSize != FONT_SIZE_NORMAL) {
|
||||
g_text_config_normal.fontSize = FONT_SIZE_NORMAL;
|
||||
@@ -760,7 +800,7 @@ int main(int argc, char **argv) {
|
||||
AudioEngine *audio = audio_create(platform_get_native_handle(window));
|
||||
|
||||
// Initialize UI (Clay)
|
||||
ui_init_theme();
|
||||
ui_set_theme(0);
|
||||
UI_Context *ui = ui_create((F32)w, (F32)h);
|
||||
ui_set_measure_text_fn(ui, renderer_measure_text, renderer);
|
||||
init_text_configs();
|
||||
|
||||
@@ -19,6 +19,7 @@ bool renderer_begin_frame(Renderer *renderer);
|
||||
void renderer_end_frame(Renderer *renderer, Clay_RenderCommandArray render_commands);
|
||||
void renderer_resize(Renderer *renderer, int32_t width, int32_t height);
|
||||
void renderer_set_font_scale(Renderer *renderer, float scale);
|
||||
void renderer_set_clear_color(Renderer *renderer, float r, float g, float b);
|
||||
|
||||
// Text measurement callback compatible with UI_MeasureTextFn
|
||||
// Measures text of given length (NOT necessarily null-terminated) at font_size pixels.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "renderer/renderer.h"
|
||||
#include "ui/ui_core.h"
|
||||
#include "ui/ui_theme.h"
|
||||
|
||||
#include <d3d12.h>
|
||||
#include <dxgi1_5.h>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "renderer/renderer.h"
|
||||
#include "ui/ui_core.h"
|
||||
#include "ui/ui_theme.h"
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
@@ -166,6 +165,9 @@ struct Renderer {
|
||||
// Text measurement (Core Text)
|
||||
CTFontRef measure_font;
|
||||
F32 measure_font_size;
|
||||
|
||||
// Clear color
|
||||
F32 clear_r, clear_g, clear_b;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
@@ -617,6 +619,11 @@ Renderer *renderer_create(RendererDesc *desc) {
|
||||
r->measure_font = nullptr;
|
||||
r->measure_font_size = 0;
|
||||
|
||||
// Default clear color (dark theme bg_dark)
|
||||
r->clear_r = 0.12f;
|
||||
r->clear_g = 0.12f;
|
||||
r->clear_b = 0.13f;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -647,7 +654,7 @@ void renderer_end_frame(Renderer *r, Clay_RenderCommandArray render_commands) {
|
||||
pass.colorAttachments[0].texture = drawable.texture;
|
||||
pass.colorAttachments[0].loadAction = MTLLoadActionClear;
|
||||
pass.colorAttachments[0].storeAction = MTLStoreActionStore;
|
||||
pass.colorAttachments[0].clearColor = MTLClearColorMake(0.12, 0.12, 0.13, 1.0);
|
||||
pass.colorAttachments[0].clearColor = MTLClearColorMake(r->clear_r, r->clear_g, r->clear_b, 1.0);
|
||||
|
||||
id<MTLCommandBuffer> cmd_buf = [r->command_queue commandBuffer];
|
||||
id<MTLRenderCommandEncoder> encoder = [cmd_buf renderCommandEncoderWithDescriptor:pass];
|
||||
@@ -801,6 +808,12 @@ void renderer_end_frame(Renderer *r, Clay_RenderCommandArray render_commands) {
|
||||
r->frame_index++;
|
||||
}
|
||||
|
||||
void renderer_set_clear_color(Renderer *r, float cr, float cg, float cb) {
|
||||
r->clear_r = cr;
|
||||
r->clear_g = cg;
|
||||
r->clear_b = cb;
|
||||
}
|
||||
|
||||
void renderer_set_font_scale(Renderer *r, float scale) {
|
||||
float target_size = 15.0f * scale;
|
||||
if (fabsf(target_size - r->font_atlas_size) < 0.1f) return;
|
||||
|
||||
@@ -19,20 +19,122 @@ F32 g_ui_scale = 1.0f;
|
||||
// Theme global
|
||||
|
||||
UI_Theme g_theme = {};
|
||||
S32 g_theme_id = 0;
|
||||
|
||||
void ui_init_theme() {
|
||||
g_theme.bg_dark = Clay_Color{ 30, 30, 33, 255};
|
||||
g_theme.bg_medium = Clay_Color{ 41, 41, 43, 255};
|
||||
g_theme.bg_light = Clay_Color{ 51, 51, 56, 255};
|
||||
g_theme.bg_lighter = Clay_Color{ 56, 56, 61, 255};
|
||||
g_theme.border = Clay_Color{ 56, 56, 61, 255};
|
||||
g_theme.text = Clay_Color{224, 224, 224, 255};
|
||||
g_theme.text_dim = Clay_Color{112, 112, 112, 255};
|
||||
g_theme.accent = Clay_Color{ 87, 138, 176, 255};
|
||||
g_theme.accent_hover = Clay_Color{102, 153, 191, 255};
|
||||
g_theme.title_bar = Clay_Color{ 26, 26, 28, 255};
|
||||
g_theme.scrollbar_bg = Clay_Color{ 26, 26, 28, 255};
|
||||
g_theme.scrollbar_grab= Clay_Color{ 61, 61, 66, 255};
|
||||
void ui_set_theme(S32 theme_id) {
|
||||
g_theme_id = theme_id;
|
||||
|
||||
switch (theme_id) {
|
||||
default:
|
||||
case 0: // Dark
|
||||
g_theme.bg_dark = Clay_Color{ 30, 30, 33, 255};
|
||||
g_theme.bg_medium = Clay_Color{ 41, 41, 43, 255};
|
||||
g_theme.bg_light = Clay_Color{ 51, 51, 56, 255};
|
||||
g_theme.bg_lighter = Clay_Color{ 56, 56, 61, 255};
|
||||
g_theme.border = Clay_Color{ 56, 56, 61, 255};
|
||||
g_theme.text = Clay_Color{224, 224, 224, 255};
|
||||
g_theme.text_dim = Clay_Color{112, 112, 112, 255};
|
||||
g_theme.accent = Clay_Color{ 87, 138, 176, 255};
|
||||
g_theme.accent_hover = Clay_Color{102, 153, 191, 255};
|
||||
g_theme.button_text = Clay_Color{224, 224, 224, 255};
|
||||
g_theme.disabled_bg = Clay_Color{ 50, 50, 50, 255};
|
||||
g_theme.disabled_text = Clay_Color{100, 100, 100, 255};
|
||||
g_theme.title_bar = Clay_Color{ 26, 26, 28, 255};
|
||||
g_theme.scrollbar_bg = Clay_Color{ 26, 26, 28, 255};
|
||||
g_theme.scrollbar_grab = Clay_Color{ 61, 61, 66, 255};
|
||||
g_theme.tab_active_top = Clay_Color{ 70, 120, 160, 255};
|
||||
g_theme.tab_active_bottom= Clay_Color{ 30, 55, 80, 255};
|
||||
g_theme.tab_inactive = Clay_Color{ 45, 45, 48, 255};
|
||||
g_theme.tab_inactive_hover= Clay_Color{ 55, 55, 60, 255};
|
||||
g_theme.tab_text = Clay_Color{240, 240, 240, 255};
|
||||
break;
|
||||
|
||||
case 1: // Light
|
||||
g_theme.bg_dark = Clay_Color{210, 210, 215, 255};
|
||||
g_theme.bg_medium = Clay_Color{230, 230, 233, 255};
|
||||
g_theme.bg_light = Clay_Color{242, 242, 245, 255};
|
||||
g_theme.bg_lighter = Clay_Color{248, 248, 250, 255};
|
||||
g_theme.border = Clay_Color{190, 190, 195, 255};
|
||||
g_theme.text = Clay_Color{ 30, 30, 35, 255};
|
||||
g_theme.text_dim = Clay_Color{120, 120, 130, 255};
|
||||
g_theme.accent = Clay_Color{ 50, 110, 170, 255};
|
||||
g_theme.accent_hover = Clay_Color{ 65, 125, 185, 255};
|
||||
g_theme.button_text = Clay_Color{255, 255, 255, 255};
|
||||
g_theme.disabled_bg = Clay_Color{195, 195, 200, 255};
|
||||
g_theme.disabled_text = Clay_Color{150, 150, 155, 255};
|
||||
g_theme.title_bar = Clay_Color{220, 220, 225, 255};
|
||||
g_theme.scrollbar_bg = Clay_Color{220, 220, 225, 255};
|
||||
g_theme.scrollbar_grab = Clay_Color{180, 180, 185, 255};
|
||||
g_theme.tab_active_top = Clay_Color{ 70, 130, 180, 255};
|
||||
g_theme.tab_active_bottom= Clay_Color{ 50, 100, 150, 255};
|
||||
g_theme.tab_inactive = Clay_Color{218, 218, 222, 255};
|
||||
g_theme.tab_inactive_hover= Clay_Color{205, 205, 210, 255};
|
||||
g_theme.tab_text = Clay_Color{255, 255, 255, 255};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// Accent palette
|
||||
|
||||
S32 g_accent_id = 0;
|
||||
|
||||
void ui_set_accent(S32 accent_id) {
|
||||
g_accent_id = accent_id;
|
||||
B32 dark = (g_theme_id == 0);
|
||||
|
||||
// Each palette: accent, accent_hover, tab_top, tab_bottom, button_text, tab_text
|
||||
struct AccentColors {
|
||||
Clay_Color accent, accent_hover, tab_top, tab_bottom, button_text, tab_text;
|
||||
};
|
||||
|
||||
// Dark-mode palettes
|
||||
static const AccentColors dark_palettes[] = {
|
||||
// 0: Blue
|
||||
{ {87,138,176,255}, {102,153,191,255}, {70,120,160,255}, {30,55,80,255}, {224,224,224,255}, {240,240,240,255} },
|
||||
// 1: Turquoise
|
||||
{ {60,160,155,255}, {75,175,170,255}, {50,140,135,255}, {25,70,68,255}, {224,224,224,255}, {240,240,240,255} },
|
||||
// 2: Orange
|
||||
{ {200,130,50,255}, {215,145,65,255}, {190,120,40,255}, {100,60,20,255}, {240,240,240,255}, {240,240,240,255} },
|
||||
// 3: Purple
|
||||
{ {130,100,180,255}, {145,115,195,255}, {120,90,170,255}, {60,45,85,255}, {224,224,224,255}, {240,240,240,255} },
|
||||
// 4: Pink
|
||||
{ {185,95,140,255}, {200,110,155,255}, {175,85,130,255}, {88,42,65,255}, {240,240,240,255}, {240,240,240,255} },
|
||||
// 5: Red
|
||||
{ {190,75,75,255}, {205,90,90,255}, {180,65,65,255}, {90,32,32,255}, {240,240,240,255}, {240,240,240,255} },
|
||||
// 6: Green
|
||||
{ {80,155,80,255}, {95,170,95,255}, {70,140,70,255}, {35,70,35,255}, {240,240,240,255}, {240,240,240,255} },
|
||||
};
|
||||
|
||||
// Light-mode palettes (slightly more saturated for contrast on light bg)
|
||||
static const AccentColors light_palettes[] = {
|
||||
// 0: Blue
|
||||
{ {50,110,170,255}, {65,125,185,255}, {70,130,180,255}, {50,100,150,255}, {255,255,255,255}, {255,255,255,255} },
|
||||
// 1: Turquoise
|
||||
{ {30,140,135,255}, {45,155,150,255}, {40,150,145,255}, {25,115,110,255}, {255,255,255,255}, {255,255,255,255} },
|
||||
// 2: Orange
|
||||
{ {190,115,25,255}, {205,130,40,255}, {195,120,30,255}, {155,90,15,255}, {255,255,255,255}, {255,255,255,255} },
|
||||
// 3: Purple
|
||||
{ {110,75,170,255}, {125,90,185,255}, {115,80,175,255}, {85,55,140,255}, {255,255,255,255}, {255,255,255,255} },
|
||||
// 4: Pink
|
||||
{ {175,70,125,255}, {190,85,140,255}, {180,75,130,255}, {140,50,100,255}, {255,255,255,255}, {255,255,255,255} },
|
||||
// 5: Red
|
||||
{ {185,55,55,255}, {200,70,70,255}, {190,60,60,255}, {150,40,40,255}, {255,255,255,255}, {255,255,255,255} },
|
||||
// 6: Green
|
||||
{ {55,140,55,255}, {70,155,70,255}, {60,145,60,255}, {40,110,40,255}, {255,255,255,255}, {255,255,255,255} },
|
||||
};
|
||||
|
||||
S32 idx = accent_id;
|
||||
if (idx < 0) idx = 0;
|
||||
if (idx > 6) idx = 6;
|
||||
|
||||
const AccentColors &c = dark ? dark_palettes[idx] : light_palettes[idx];
|
||||
g_theme.accent = c.accent;
|
||||
g_theme.accent_hover = c.accent_hover;
|
||||
g_theme.tab_active_top = c.tab_top;
|
||||
g_theme.tab_active_bottom = c.tab_bottom;
|
||||
g_theme.button_text = c.button_text;
|
||||
g_theme.tab_text = c.tab_text;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -58,11 +58,107 @@ struct UI_Theme {
|
||||
Clay_Color text_dim;
|
||||
Clay_Color accent;
|
||||
Clay_Color accent_hover;
|
||||
Clay_Color button_text;
|
||||
Clay_Color disabled_bg;
|
||||
Clay_Color disabled_text;
|
||||
Clay_Color title_bar;
|
||||
Clay_Color scrollbar_bg;
|
||||
Clay_Color scrollbar_grab;
|
||||
|
||||
// Tab bar colors
|
||||
Clay_Color tab_active_top;
|
||||
Clay_Color tab_active_bottom;
|
||||
Clay_Color tab_inactive;
|
||||
Clay_Color tab_inactive_hover;
|
||||
Clay_Color tab_text; // Always light — readable on colored tab gradient
|
||||
};
|
||||
|
||||
extern UI_Theme g_theme;
|
||||
extern S32 g_theme_id;
|
||||
|
||||
void ui_init_theme();
|
||||
// Set theme by index: 0 = Dark, 1 = Light
|
||||
void ui_set_theme(S32 theme_id);
|
||||
|
||||
// Accent color palette: 0=Blue, 1=Turquoise, 2=Orange, 3=Purple, 4=Pink, 5=Red, 6=Green
|
||||
extern S32 g_accent_id;
|
||||
void ui_set_accent(S32 accent_id);
|
||||
|
||||
////////////////////////////////
|
||||
// UI scale (Cmd+/Cmd- zoom)
|
||||
|
||||
extern F32 g_ui_scale;
|
||||
|
||||
// Scale a float value (for CLAY_SIZING_FIXED, corner radii, etc.)
|
||||
static inline float uis(float x) { return x * g_ui_scale; }
|
||||
|
||||
// Scale to uint16_t (for Clay_Padding, childGap, etc.)
|
||||
static inline uint16_t uip(float x) { return (uint16_t)(x * g_ui_scale + 0.5f); }
|
||||
|
||||
// Scale to uint16_t font size
|
||||
static inline uint16_t uifs(float x) { return (uint16_t)(x * g_ui_scale + 0.5f); }
|
||||
|
||||
////////////////////////////////
|
||||
// Tab styling
|
||||
|
||||
#define TAB_ACTIVE_TOP g_theme.tab_active_top
|
||||
#define TAB_ACTIVE_BOTTOM g_theme.tab_active_bottom
|
||||
#define TAB_INACTIVE_BG g_theme.tab_inactive
|
||||
#define TAB_INACTIVE_HOVER g_theme.tab_inactive_hover
|
||||
#define TAB_HEIGHT uis(26)
|
||||
#define TAB_CORNER_RADIUS uis(5)
|
||||
#define TAB_PADDING_H uip(10)
|
||||
|
||||
////////////////////////////////
|
||||
// Custom render types (for gradient rects via CLAY_RENDER_COMMAND_TYPE_CUSTOM)
|
||||
|
||||
enum CustomRenderType {
|
||||
CUSTOM_RENDER_VGRADIENT = 1,
|
||||
};
|
||||
|
||||
struct CustomGradientData {
|
||||
CustomRenderType type;
|
||||
Clay_Color top_color;
|
||||
Clay_Color bottom_color;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
// Font sizes
|
||||
|
||||
#define FONT_SIZE_NORMAL uifs(15)
|
||||
#define FONT_SIZE_SMALL uifs(12)
|
||||
|
||||
////////////////////////////////
|
||||
// Widget sizing
|
||||
|
||||
#define WIDGET_BUTTON_HEIGHT uis(30)
|
||||
#define WIDGET_CHECKBOX_HEIGHT uis(28)
|
||||
#define WIDGET_CHECKBOX_SIZE uis(18)
|
||||
#define WIDGET_RADIO_OUTER uis(16)
|
||||
#define WIDGET_RADIO_INNER uis(8)
|
||||
#define WIDGET_INPUT_HEIGHT uis(30)
|
||||
#define WIDGET_DROPDOWN_HEIGHT uis(30)
|
||||
#define WIDGET_DROPDOWN_ITEM_H uis(28)
|
||||
|
||||
////////////////////////////////
|
||||
// Corner radii
|
||||
|
||||
#define CORNER_RADIUS_SM uis(3)
|
||||
#define CORNER_RADIUS_MD uis(6)
|
||||
#define CORNER_RADIUS_ROUND uis(8)
|
||||
|
||||
////////////////////////////////
|
||||
// Modal / window styling
|
||||
|
||||
#define MODAL_OVERLAY_COLOR Clay_Color{ 0, 0, 0, 120}
|
||||
#define MODAL_WIDTH uis(400)
|
||||
#define MODAL_CORNER_RADIUS CORNER_RADIUS_MD
|
||||
|
||||
#define WINDOW_CORNER_RADIUS CORNER_RADIUS_MD
|
||||
#define WINDOW_TITLE_HEIGHT uis(32)
|
||||
|
||||
////////////////////////////////
|
||||
// Panel sizing
|
||||
|
||||
#define PANEL_BROWSER_WIDTH uis(200)
|
||||
#define PANEL_RIGHT_COL_WIDTH uis(250)
|
||||
#define PANEL_LOG_HEIGHT uis(180)
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
#pragma once
|
||||
// ui_theme.h - Theme constants and defines for the UI layer.
|
||||
// Centralizes colors, sizing, padding, and radius values used across the app.
|
||||
|
||||
#include "clay.h"
|
||||
|
||||
////////////////////////////////
|
||||
// UI scale (Cmd+/Cmd- zoom)
|
||||
|
||||
extern F32 g_ui_scale;
|
||||
|
||||
// Scale a float value (for CLAY_SIZING_FIXED, corner radii, etc.)
|
||||
static inline float uis(float x) { return x * g_ui_scale; }
|
||||
|
||||
// Scale to uint16_t (for Clay_Padding, childGap, etc.)
|
||||
static inline uint16_t uip(float x) { return (uint16_t)(x * g_ui_scale + 0.5f); }
|
||||
|
||||
// Scale to uint16_t font size
|
||||
static inline uint16_t uifs(float x) { return (uint16_t)(x * g_ui_scale + 0.5f); }
|
||||
|
||||
////////////////////////////////
|
||||
// Tab styling
|
||||
|
||||
#define TAB_ACTIVE_TOP Clay_Color{ 70, 120, 160, 255}
|
||||
#define TAB_ACTIVE_BOTTOM Clay_Color{ 30, 55, 80, 255}
|
||||
#define TAB_INACTIVE_BG Clay_Color{ 45, 45, 48, 255}
|
||||
#define TAB_INACTIVE_HOVER Clay_Color{ 55, 55, 60, 255}
|
||||
#define TAB_HEIGHT uis(26)
|
||||
#define TAB_CORNER_RADIUS uis(5)
|
||||
#define TAB_PADDING_H uip(10)
|
||||
|
||||
////////////////////////////////
|
||||
// Custom render types (for gradient rects via CLAY_RENDER_COMMAND_TYPE_CUSTOM)
|
||||
|
||||
enum CustomRenderType {
|
||||
CUSTOM_RENDER_VGRADIENT = 1,
|
||||
};
|
||||
|
||||
struct CustomGradientData {
|
||||
CustomRenderType type;
|
||||
Clay_Color top_color;
|
||||
Clay_Color bottom_color;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
// Font sizes
|
||||
|
||||
#define FONT_SIZE_NORMAL uifs(15)
|
||||
#define FONT_SIZE_SMALL uifs(12)
|
||||
|
||||
////////////////////////////////
|
||||
// Widget sizing
|
||||
|
||||
#define WIDGET_BUTTON_HEIGHT uis(30)
|
||||
#define WIDGET_CHECKBOX_HEIGHT uis(28)
|
||||
#define WIDGET_CHECKBOX_SIZE uis(18)
|
||||
#define WIDGET_RADIO_OUTER uis(16)
|
||||
#define WIDGET_RADIO_INNER uis(8)
|
||||
#define WIDGET_INPUT_HEIGHT uis(30)
|
||||
#define WIDGET_DROPDOWN_HEIGHT uis(30)
|
||||
#define WIDGET_DROPDOWN_ITEM_H uis(28)
|
||||
|
||||
////////////////////////////////
|
||||
// Corner radii
|
||||
|
||||
#define CORNER_RADIUS_SM uis(3)
|
||||
#define CORNER_RADIUS_MD uis(6)
|
||||
#define CORNER_RADIUS_ROUND uis(8)
|
||||
|
||||
////////////////////////////////
|
||||
// Modal / window styling
|
||||
|
||||
#define MODAL_OVERLAY_COLOR Clay_Color{ 0, 0, 0, 120}
|
||||
#define MODAL_WIDTH uis(400)
|
||||
#define MODAL_CORNER_RADIUS CORNER_RADIUS_MD
|
||||
|
||||
#define WINDOW_CORNER_RADIUS CORNER_RADIUS_MD
|
||||
#define WINDOW_TITLE_HEIGHT uis(32)
|
||||
|
||||
////////////////////////////////
|
||||
// Panel sizing
|
||||
|
||||
#define PANEL_BROWSER_WIDTH uis(200)
|
||||
#define PANEL_RIGHT_COL_WIDTH uis(250)
|
||||
#define PANEL_LOG_HEIGHT uis(180)
|
||||
@@ -43,8 +43,14 @@ void ui_widgets_begin_frame(PlatformInput input) {
|
||||
static Clay_TextElementConfig g_widget_text_config;
|
||||
static Clay_TextElementConfig g_widget_text_config_dim;
|
||||
static Clay_TextElementConfig g_widget_text_config_sel;
|
||||
static Clay_TextElementConfig g_widget_text_config_btn;
|
||||
static Clay_TextElementConfig g_widget_text_config_tab;
|
||||
static F32 g_widget_text_configs_scale = 0;
|
||||
|
||||
void ui_widgets_theme_changed() {
|
||||
g_widget_text_configs_scale = 0;
|
||||
}
|
||||
|
||||
static void ensure_widget_text_configs() {
|
||||
if (g_widget_text_configs_scale == g_ui_scale) return;
|
||||
g_widget_text_configs_scale = g_ui_scale;
|
||||
@@ -64,6 +70,18 @@ static void ensure_widget_text_configs() {
|
||||
g_widget_text_config_sel.textColor = Clay_Color{255, 255, 255, 255};
|
||||
g_widget_text_config_sel.fontSize = FONT_SIZE_NORMAL;
|
||||
g_widget_text_config_sel.wrapMode = CLAY_TEXT_WRAP_NONE;
|
||||
|
||||
// Button text (always readable on accent background)
|
||||
g_widget_text_config_btn = {};
|
||||
g_widget_text_config_btn.textColor = g_theme.button_text;
|
||||
g_widget_text_config_btn.fontSize = FONT_SIZE_NORMAL;
|
||||
g_widget_text_config_btn.wrapMode = CLAY_TEXT_WRAP_NONE;
|
||||
|
||||
// Tab text (always light — readable on colored tab gradient)
|
||||
g_widget_text_config_tab = {};
|
||||
g_widget_text_config_tab.textColor = g_theme.tab_text;
|
||||
g_widget_text_config_tab.fontSize = FONT_SIZE_NORMAL;
|
||||
g_widget_text_config_tab.wrapMode = CLAY_TEXT_WRAP_NONE;
|
||||
}
|
||||
|
||||
static Clay_String clay_str(const char *s) {
|
||||
@@ -111,7 +129,7 @@ B32 ui_button(const char *id, const char *text) {
|
||||
.backgroundColor = hovered ? g_theme.accent_hover : g_theme.accent,
|
||||
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS_SM)
|
||||
) {
|
||||
CLAY_TEXT(clay_str(text), &g_widget_text_config);
|
||||
CLAY_TEXT(clay_str(text), &g_widget_text_config_btn);
|
||||
}
|
||||
|
||||
return (hovered && g_wstate.mouse_clicked) ? 1 : 0;
|
||||
@@ -737,6 +755,9 @@ B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected)
|
||||
Clay_Color item_bg = is_item_selected ? g_theme.accent : g_theme.bg_dark;
|
||||
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;
|
||||
|
||||
CLAY(item_id,
|
||||
.layout = {
|
||||
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(WIDGET_DROPDOWN_ITEM_H) },
|
||||
@@ -745,7 +766,7 @@ B32 ui_dropdown(const char *id, const char **options, S32 count, S32 *selected)
|
||||
},
|
||||
.backgroundColor = item_bg
|
||||
) {
|
||||
CLAY_TEXT(clay_str(options[i]), &g_widget_text_config);
|
||||
CLAY_TEXT(clay_str(options[i]), item_text);
|
||||
}
|
||||
|
||||
if (item_hovered && g_wstate.mouse_clicked) {
|
||||
@@ -892,7 +913,7 @@ S32 ui_modal(const char *id, const char *title, const char *message,
|
||||
.backgroundColor = btn_hovered ? g_theme.accent_hover : g_theme.accent,
|
||||
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS_SM)
|
||||
) {
|
||||
CLAY_TEXT(clay_str(buttons[i]), &g_widget_text_config);
|
||||
CLAY_TEXT(clay_str(buttons[i]), &g_widget_text_config_btn);
|
||||
}
|
||||
|
||||
if (btn_hovered && g_wstate.mouse_clicked) {
|
||||
@@ -1057,7 +1078,7 @@ B32 ui_window(const char *id, const char *title, B32 *open,
|
||||
.backgroundColor = close_bg,
|
||||
.cornerRadius = CLAY_CORNER_RADIUS(CORNER_RADIUS_SM)
|
||||
) {
|
||||
CLAY_TEXT(CLAY_STRING("x"), &g_widget_text_config);
|
||||
CLAY_TEXT(CLAY_STRING("x"), &g_widget_text_config_btn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1088,11 +1109,13 @@ B32 ui_window(const char *id, const char *title, B32 *open,
|
||||
////////////////////////////////
|
||||
// Tab bar
|
||||
|
||||
static CustomGradientData g_tab_gradient = {
|
||||
CUSTOM_RENDER_VGRADIENT, TAB_ACTIVE_TOP, TAB_ACTIVE_BOTTOM
|
||||
};
|
||||
static CustomGradientData g_tab_gradient;
|
||||
|
||||
S32 ui_tab_bar(const char *id, const char **labels, S32 count, S32 *selected) {
|
||||
g_tab_gradient.type = CUSTOM_RENDER_VGRADIENT;
|
||||
g_tab_gradient.top_color = TAB_ACTIVE_TOP;
|
||||
g_tab_gradient.bottom_color = TAB_ACTIVE_BOTTOM;
|
||||
|
||||
Clay_String id_str = clay_str(id);
|
||||
Clay_ElementId row_eid = Clay__HashString(id_str, 0);
|
||||
|
||||
@@ -1122,7 +1145,7 @@ S32 ui_tab_bar(const char *id, const char **labels, S32 count, S32 *selected) {
|
||||
.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);
|
||||
CLAY_TEXT(lbl_str, &g_widget_text_config_tab);
|
||||
}
|
||||
} else {
|
||||
Clay_Color bg = hovered ? (Clay_Color)TAB_INACTIVE_HOVER : (Clay_Color)TAB_INACTIVE_BG;
|
||||
|
||||
@@ -78,6 +78,9 @@ void ui_widgets_init();
|
||||
// Call each frame before building widgets. Pass in the frame's input.
|
||||
void ui_widgets_begin_frame(PlatformInput input);
|
||||
|
||||
// Call after changing theme to force text config refresh
|
||||
void ui_widgets_theme_changed();
|
||||
|
||||
// Reset per-frame text input display buffer allocator (called by begin_frame, but
|
||||
// can also be called manually if needed)
|
||||
void ui_text_input_reset_display_bufs();
|
||||
|
||||
Reference in New Issue
Block a user