Mercurial
diff infinite_canvas/theme.c @ 276:b55c22cff335
Add interactive infinite canvas prototype
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 17 Aug 2026 16:57:56 -0700 |
| parents | |
| children | 8d560f50ed4c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/infinite_canvas/theme.c Mon Aug 17 16:57:56 2026 -0700 @@ -0,0 +1,139 @@ +#include "infinite_canvas/theme.h" + +#include <stdlib.h> +#include <string.h> + +#if defined(PLATFORM_WEB) || defined(__EMSCRIPTEN__) +#include <emscripten/emscripten.h> + +EM_JS(int, Canvas_Web_Prefers_Dark, (), { + return window.matchMedia && + window.matchMedia("(prefers-color-scheme: dark)").matches ? 1 : 0; +}); +#elif defined(_WIN32) +#include <windows.h> +#else +#include <stdio.h> +#endif + +Canvas_Theme_Mode Canvas_Theme_Mode_From_String(const char *p_value) +{ + if (!p_value || strcmp(p_value, "auto") == 0) return CANVAS_THEME_AUTO; + if (strcmp(p_value, "light") == 0) return CANVAS_THEME_LIGHT; + if (strcmp(p_value, "dark") == 0) return CANVAS_THEME_DARK; + return CANVAS_THEME_AUTO; +} + +boolean Canvas_System_Prefers_Dark(void) +{ +#if defined(PLATFORM_WEB) || defined(__EMSCRIPTEN__) + return Canvas_Web_Prefers_Dark() ? TRUE : FALSE; +#elif defined(_WIN32) + DWORD light_theme = 1; + DWORD size = sizeof(light_theme); + LSTATUS status = RegGetValueA( + HKEY_CURRENT_USER, + "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", + "AppsUseLightTheme", + RRF_RT_REG_DWORD, + NULL, + &light_theme, + &size); + return status == ERROR_SUCCESS && light_theme == 0 ? TRUE : FALSE; +#elif defined(__APPLE__) + FILE *p_pipe = popen("defaults read -g AppleInterfaceStyle 2>/dev/null", "r"); + if (!p_pipe) return FALSE; + char value[32] = {0}; + boolean dark = fgets(value, sizeof(value), p_pipe) && + strstr(value, "Dark") ? TRUE : FALSE; + pclose(p_pipe); + return dark; +#else + const char *p_gtk_theme = getenv("GTK_THEME"); + if (p_gtk_theme && + (strstr(p_gtk_theme, "dark") || strstr(p_gtk_theme, "Dark"))) { + return TRUE; + } + + FILE *p_pipe = popen( + "gsettings get org.gnome.desktop.interface color-scheme 2>/dev/null", + "r"); + if (!p_pipe) return FALSE; + char value[64] = {0}; + boolean dark = fgets(value, sizeof(value), p_pipe) && + strstr(value, "prefer-dark") ? TRUE : FALSE; + pclose(p_pipe); + return dark; +#endif +} + +void Canvas_Theme_Resolve(Canvas_Theme *p_theme, Canvas_Theme_Mode mode) +{ + Canvas_Theme_Mode resolved = mode; + if (resolved == CANVAS_THEME_AUTO) { + resolved = Canvas_System_Prefers_Dark() ? + CANVAS_THEME_DARK : + CANVAS_THEME_LIGHT; + } + + *p_theme = (Canvas_Theme){ + .requested_mode = mode, + .resolved_mode = resolved, + }; + if (resolved == CANVAS_THEME_DARK) { + p_theme->background = (Color){15, 15, 17, 255}; + p_theme->surface = (Color){24, 24, 27, 255}; + p_theme->surface_muted = (Color){39, 39, 42, 255}; + p_theme->border = (Color){63, 63, 70, 255}; + p_theme->text = (Color){244, 244, 245, 255}; + p_theme->text_muted = (Color){161, 161, 170, 255}; + p_theme->accent = (Color){96, 165, 250, 255}; + p_theme->accent_soft = (Color){30, 58, 95, 255}; + p_theme->shadow = (Color){0, 0, 0, 110}; + p_theme->toast_surface = (Color){24, 24, 27, 255}; + p_theme->toast_border = (Color){63, 63, 70, 255}; + } else { + p_theme->background = (Color){255, 255, 255, 255}; + p_theme->surface = (Color){255, 255, 255, 252}; + p_theme->surface_muted = (Color){244, 247, 251, 255}; + p_theme->border = (Color){205, 211, 221, 255}; + p_theme->text = (Color){24, 24, 27, 255}; + p_theme->text_muted = (Color){113, 113, 122, 255}; + p_theme->accent = (Color){37, 99, 235, 255}; + p_theme->accent_soft = (Color){239, 246, 255, 255}; + p_theme->shadow = (Color){15, 23, 42, 36}; + p_theme->toast_surface = (Color){255, 255, 255, 255}; + p_theme->toast_border = (Color){212, 216, 223, 255}; + } +} + +void Canvas_Theme_Toggle(Canvas_Theme *p_theme) +{ + Canvas_Theme_Resolve( + p_theme, + p_theme->resolved_mode == CANVAS_THEME_DARK ? + CANVAS_THEME_LIGHT : + CANVAS_THEME_DARK); +} + +void Canvas_Theme_Draw_Shadow( + const Canvas_Theme *p_theme, + Rectangle bounds, + float roundness, + int32 segments, + float zoom, + float opacity) +{ + float offset = 6.0f / zoom; + float shadow_alpha = ((float)p_theme->shadow.a / 255.0f) * opacity; + DrawRectangleRounded( + (Rectangle){ + bounds.x + offset, + bounds.y + offset, + bounds.width, + bounds.height, + }, + roundness, + segments, + Fade(p_theme->shadow, shadow_alpha)); +}