fix: sync template sysroot, add script
This commit is contained in:
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* graph.hpp
|
||||
* Montauk Toolkit graph helpers
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gui/mtk/widgets.hpp"
|
||||
|
||||
namespace gui::mtk {
|
||||
|
||||
struct GraphHistory {
|
||||
uint64_t* samples;
|
||||
int capacity;
|
||||
int count;
|
||||
int head;
|
||||
};
|
||||
|
||||
struct GraphStyle {
|
||||
Color background;
|
||||
Color border;
|
||||
Color plot_bg;
|
||||
Color grid;
|
||||
Color label;
|
||||
Color value;
|
||||
Color line;
|
||||
Color fill;
|
||||
int radius;
|
||||
int padding;
|
||||
int grid_x;
|
||||
int grid_y;
|
||||
int line_thickness;
|
||||
bool fill_area;
|
||||
};
|
||||
|
||||
inline GraphStyle make_graph_style(const Theme& theme, Color line) {
|
||||
return {
|
||||
theme.window_bg,
|
||||
theme.border,
|
||||
theme.surface_alt,
|
||||
mix(theme.surface_alt, line, 18),
|
||||
theme.text_subtle,
|
||||
theme.text,
|
||||
line,
|
||||
lighten(line, 218),
|
||||
theme.radius_md,
|
||||
8,
|
||||
4,
|
||||
4,
|
||||
2,
|
||||
true,
|
||||
};
|
||||
}
|
||||
|
||||
inline void graph_history_init(GraphHistory* history, uint64_t* samples, int capacity) {
|
||||
if (!history) return;
|
||||
history->samples = samples;
|
||||
history->capacity = capacity;
|
||||
history->count = 0;
|
||||
history->head = 0;
|
||||
}
|
||||
|
||||
inline void graph_history_clear(GraphHistory* history) {
|
||||
if (!history) return;
|
||||
history->count = 0;
|
||||
history->head = 0;
|
||||
}
|
||||
|
||||
inline void graph_history_push(GraphHistory* history, uint64_t value) {
|
||||
if (!history || !history->samples || history->capacity <= 0) return;
|
||||
history->samples[history->head] = value;
|
||||
history->head = (history->head + 1) % history->capacity;
|
||||
if (history->count < history->capacity)
|
||||
history->count++;
|
||||
}
|
||||
|
||||
inline uint64_t graph_history_at(const GraphHistory& history, int index) {
|
||||
if (!history.samples || history.capacity <= 0 ||
|
||||
index < 0 || index >= history.count) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int start = history.head - history.count;
|
||||
while (start < 0) start += history.capacity;
|
||||
return history.samples[(start + index) % history.capacity];
|
||||
}
|
||||
|
||||
inline uint64_t graph_history_max(const GraphHistory& history) {
|
||||
uint64_t max_value = 0;
|
||||
for (int i = 0; i < history.count; i++) {
|
||||
uint64_t value = graph_history_at(history, i);
|
||||
if (value > max_value) max_value = value;
|
||||
}
|
||||
return max_value;
|
||||
}
|
||||
|
||||
inline int graph_sample_x(const Rect& plot, int index, int count) {
|
||||
if (count <= 1) return plot.x + plot.w - 1;
|
||||
return plot.x + (int)(((int64_t)index * (plot.w - 1)) / (count - 1));
|
||||
}
|
||||
|
||||
inline int graph_sample_y(const Rect& plot, uint64_t sample, uint64_t max_value) {
|
||||
if (plot.h <= 1) return plot.y;
|
||||
if (max_value == 0) max_value = 1;
|
||||
if (sample > max_value) sample = max_value;
|
||||
uint64_t scaled = (sample * (uint64_t)(plot.h - 1)) / max_value;
|
||||
return plot.y + plot.h - 1 - (int)scaled;
|
||||
}
|
||||
|
||||
inline void graph_draw_point(Canvas& c,
|
||||
const Rect& clip,
|
||||
int x,
|
||||
int y,
|
||||
Color color,
|
||||
int thickness) {
|
||||
thickness = gui_max(thickness, 1);
|
||||
int radius = thickness / 2;
|
||||
for (int py = y - radius; py <= y - radius + thickness - 1; py++) {
|
||||
for (int px = x - radius; px <= x - radius + thickness - 1; px++) {
|
||||
if (clip.contains(px, py))
|
||||
c.put_pixel(px, py, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void graph_draw_line(Canvas& c,
|
||||
const Rect& clip,
|
||||
int x0,
|
||||
int y0,
|
||||
int x1,
|
||||
int y1,
|
||||
Color color,
|
||||
int thickness) {
|
||||
int dx = gui_abs(x1 - x0);
|
||||
int sx = x0 < x1 ? 1 : -1;
|
||||
int dy = -gui_abs(y1 - y0);
|
||||
int sy = y0 < y1 ? 1 : -1;
|
||||
int err = dx + dy;
|
||||
|
||||
for (;;) {
|
||||
graph_draw_point(c, clip, x0, y0, color, thickness);
|
||||
if (x0 == x1 && y0 == y1) break;
|
||||
int e2 = 2 * err;
|
||||
if (e2 >= dy) {
|
||||
err += dy;
|
||||
x0 += sx;
|
||||
}
|
||||
if (e2 <= dx) {
|
||||
err += dx;
|
||||
y0 += sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void graph_fill_segment(Canvas& c,
|
||||
const Rect& clip,
|
||||
int x0,
|
||||
int y0,
|
||||
int x1,
|
||||
int y1,
|
||||
Color color) {
|
||||
int bottom = clip.y + clip.h - 1;
|
||||
if (x0 == x1) {
|
||||
int y = gui_min(y0, y1);
|
||||
if (clip.contains(x0, y))
|
||||
c.vline(x0, y, bottom - y + 1, color);
|
||||
return;
|
||||
}
|
||||
|
||||
if (x1 < x0) {
|
||||
int tx = x0; x0 = x1; x1 = tx;
|
||||
int ty = y0; y0 = y1; y1 = ty;
|
||||
}
|
||||
|
||||
for (int x = x0; x <= x1; x++) {
|
||||
if (x < clip.x || x >= clip.x + clip.w) continue;
|
||||
int y = y0 + (int)(((int64_t)(y1 - y0) * (x - x0)) / (x1 - x0));
|
||||
if (y < clip.y) y = clip.y;
|
||||
if (y > bottom) y = bottom;
|
||||
c.vline(x, y, bottom - y + 1, color);
|
||||
}
|
||||
}
|
||||
|
||||
inline void draw_line_graph(Canvas& c,
|
||||
const Rect& bounds,
|
||||
const GraphHistory& history,
|
||||
uint64_t max_value,
|
||||
const char* title,
|
||||
const char* value_label,
|
||||
const Theme& theme,
|
||||
const GraphStyle& style) {
|
||||
if (bounds.empty()) return;
|
||||
|
||||
draw_rounded_frame(c, bounds, style.radius, style.background, style.border);
|
||||
|
||||
int fh = system_font_height();
|
||||
int pad = gui_max(style.padding, 4);
|
||||
int title_y = bounds.y + pad;
|
||||
int title_x = bounds.x + pad;
|
||||
|
||||
if (title && title[0])
|
||||
c.text(title_x, title_y, title, style.label);
|
||||
|
||||
if (value_label && value_label[0]) {
|
||||
int value_w = text_width(value_label);
|
||||
int value_x = bounds.x + bounds.w - pad - value_w;
|
||||
if (value_x > title_x)
|
||||
c.text(value_x, title_y, value_label, style.value);
|
||||
}
|
||||
|
||||
Rect plot = {
|
||||
bounds.x + pad,
|
||||
bounds.y + pad + fh + 7,
|
||||
bounds.w - pad * 2,
|
||||
bounds.h - pad * 2 - fh - 7
|
||||
};
|
||||
if (plot.empty()) return;
|
||||
|
||||
c.fill_rect(plot.x, plot.y, plot.w, plot.h, style.plot_bg);
|
||||
|
||||
int sample_count = history.count;
|
||||
if (sample_count > 0) {
|
||||
if (max_value == 0)
|
||||
max_value = graph_history_max(history);
|
||||
if (max_value == 0)
|
||||
max_value = 1;
|
||||
|
||||
if (style.fill_area && sample_count > 1) {
|
||||
int prev_x = graph_sample_x(plot, 0, sample_count);
|
||||
int prev_y = graph_sample_y(plot, graph_history_at(history, 0), max_value);
|
||||
for (int i = 1; i < sample_count; i++) {
|
||||
int x = graph_sample_x(plot, i, sample_count);
|
||||
int y = graph_sample_y(plot, graph_history_at(history, i), max_value);
|
||||
graph_fill_segment(c, plot, prev_x, prev_y, x, y, style.fill);
|
||||
prev_x = x;
|
||||
prev_y = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (style.grid_y > 0) {
|
||||
for (int i = 1; i < style.grid_y; i++) {
|
||||
int y = plot.y + (plot.h * i) / style.grid_y;
|
||||
c.hline(plot.x, y, plot.w, style.grid);
|
||||
}
|
||||
}
|
||||
|
||||
if (style.grid_x > 0) {
|
||||
for (int i = 1; i < style.grid_x; i++) {
|
||||
int x = plot.x + (plot.w * i) / style.grid_x;
|
||||
c.vline(x, plot.y, plot.h, style.grid);
|
||||
}
|
||||
}
|
||||
|
||||
c.rect(plot.x, plot.y, plot.w, plot.h, style.border);
|
||||
|
||||
if (sample_count == 1) {
|
||||
int x = graph_sample_x(plot, 0, sample_count);
|
||||
int y = graph_sample_y(plot, graph_history_at(history, 0), max_value);
|
||||
graph_draw_point(c, plot, x, y, style.line, style.line_thickness + 1);
|
||||
} else if (sample_count > 1) {
|
||||
int prev_x = graph_sample_x(plot, 0, sample_count);
|
||||
int prev_y = graph_sample_y(plot, graph_history_at(history, 0), max_value);
|
||||
for (int i = 1; i < sample_count; i++) {
|
||||
int x = graph_sample_x(plot, i, sample_count);
|
||||
int y = graph_sample_y(plot, graph_history_at(history, i), max_value);
|
||||
graph_draw_line(c, plot, prev_x, prev_y, x, y,
|
||||
style.line, style.line_thickness);
|
||||
prev_x = x;
|
||||
prev_y = y;
|
||||
}
|
||||
}
|
||||
|
||||
(void)theme;
|
||||
}
|
||||
|
||||
inline void draw_line_graph(Canvas& c,
|
||||
const Rect& bounds,
|
||||
const GraphHistory& history,
|
||||
uint64_t max_value,
|
||||
const char* title,
|
||||
const char* value_label,
|
||||
const Theme& theme,
|
||||
Color line) {
|
||||
GraphStyle style = make_graph_style(theme, line);
|
||||
draw_line_graph(c, bounds, history, max_value, title, value_label, theme, style);
|
||||
}
|
||||
|
||||
} // namespace gui::mtk
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* hosts.hpp
|
||||
* Montauk Toolkit host adapters for desktop and standalone apps
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gui/canvas.hpp"
|
||||
#include "gui/standalone.hpp"
|
||||
#include "gui/window.hpp"
|
||||
|
||||
namespace gui::mtk {
|
||||
|
||||
struct DesktopHost {
|
||||
Window* window;
|
||||
|
||||
explicit DesktopHost(Window* win) : window(win) {}
|
||||
|
||||
Canvas canvas() const {
|
||||
return window ? Canvas(window) : Canvas(nullptr, 0, 0);
|
||||
}
|
||||
|
||||
Rect bounds() const {
|
||||
return {0, 0, window ? window->content_w : 0, window ? window->content_h : 0};
|
||||
}
|
||||
|
||||
bool map_mouse(const MouseEvent& ev, int* out_x, int* out_y) const {
|
||||
if (!window || !out_x || !out_y) return false;
|
||||
Rect cr = window->content_rect();
|
||||
*out_x = ev.x - cr.x;
|
||||
*out_y = ev.y - cr.y;
|
||||
return true;
|
||||
}
|
||||
|
||||
void invalidate() const {
|
||||
if (window) window->dirty = true;
|
||||
}
|
||||
};
|
||||
|
||||
struct StandaloneHost {
|
||||
WsWindow* window;
|
||||
|
||||
explicit StandaloneHost(WsWindow* win) : window(win) {}
|
||||
|
||||
Canvas canvas() const {
|
||||
return window ? window->canvas() : Canvas(nullptr, 0, 0);
|
||||
}
|
||||
|
||||
Rect bounds() const {
|
||||
return {0, 0, window ? window->width : 0, window ? window->height : 0};
|
||||
}
|
||||
|
||||
void present() const {
|
||||
if (window) window->present();
|
||||
}
|
||||
|
||||
void set_cursor(int cursor) const {
|
||||
if (window) window->set_cursor(cursor);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gui::mtk
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* settings.hpp
|
||||
* Montauk Toolkit helpers for loading desktop appearance settings
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <montauk/config.h>
|
||||
#include <montauk/syscall.h>
|
||||
#include "gui/gui.hpp"
|
||||
|
||||
namespace gui::mtk {
|
||||
|
||||
inline Color color_from_rgb_int(int64_t rgb, Color fallback = colors::ACCENT) {
|
||||
if (rgb < 0) return fallback;
|
||||
return Color::from_rgb((uint8_t)((rgb >> 16) & 0xFF),
|
||||
(uint8_t)((rgb >> 8) & 0xFF),
|
||||
(uint8_t)(rgb & 0xFF));
|
||||
}
|
||||
|
||||
inline Color load_system_accent(Color fallback = colors::ACCENT) {
|
||||
char user[64] = {};
|
||||
if (montauk::getuser(user, sizeof(user)) > 0 && user[0]) {
|
||||
auto doc = montauk::config::load_user(user, "desktop");
|
||||
int64_t accent = doc.get_int("appearance.accent_color", -1);
|
||||
if (accent >= 0) {
|
||||
Color color = color_from_rgb_int(accent, fallback);
|
||||
doc.destroy();
|
||||
return color;
|
||||
}
|
||||
doc.destroy();
|
||||
}
|
||||
|
||||
auto doc = montauk::config::load("desktop");
|
||||
int64_t accent = doc.get_int("appearance.accent_color", -1);
|
||||
Color color = color_from_rgb_int(accent, fallback);
|
||||
doc.destroy();
|
||||
return color;
|
||||
}
|
||||
|
||||
} // namespace gui::mtk
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* table.hpp
|
||||
* Montauk Toolkit table/list helpers
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gui/canvas.hpp"
|
||||
#include "gui/mtk/theme.hpp"
|
||||
|
||||
namespace gui::mtk {
|
||||
|
||||
struct TableColumn {
|
||||
const char* label;
|
||||
int x;
|
||||
int w;
|
||||
};
|
||||
|
||||
struct TableLayout {
|
||||
Rect header;
|
||||
Rect body;
|
||||
int row_h;
|
||||
};
|
||||
|
||||
struct TableStyle {
|
||||
Color header_bg;
|
||||
Color header_border;
|
||||
Color header_text;
|
||||
Color row_selected_bg;
|
||||
Color row_hover_bg;
|
||||
};
|
||||
|
||||
inline TableStyle make_table_style(const Theme& theme) {
|
||||
return {
|
||||
theme.surface_alt,
|
||||
theme.border,
|
||||
theme.text_subtle,
|
||||
theme.accent_soft,
|
||||
colors::TRANSPARENT,
|
||||
};
|
||||
}
|
||||
|
||||
inline int table_visible_rows(const TableLayout& layout) {
|
||||
if (layout.row_h <= 0 || layout.body.h <= 0) return 0;
|
||||
return layout.body.h / layout.row_h;
|
||||
}
|
||||
|
||||
inline int table_max_scroll(const TableLayout& layout, int row_count) {
|
||||
int visible = table_visible_rows(layout);
|
||||
if (row_count > visible && visible > 0) return row_count - visible;
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void clamp_table_scroll(int* scroll, const TableLayout& layout, int row_count) {
|
||||
if (!scroll) return;
|
||||
*scroll = gui_clamp(*scroll, 0, table_max_scroll(layout, row_count));
|
||||
}
|
||||
|
||||
inline void ensure_table_row_visible(int* scroll,
|
||||
const TableLayout& layout,
|
||||
int row_count,
|
||||
int selected) {
|
||||
if (!scroll || selected < 0) return;
|
||||
int visible = table_visible_rows(layout);
|
||||
if (visible <= 0) return;
|
||||
if (selected < *scroll) {
|
||||
*scroll = selected;
|
||||
} else if (selected >= *scroll + visible) {
|
||||
*scroll = selected - visible + 1;
|
||||
}
|
||||
clamp_table_scroll(scroll, layout, row_count);
|
||||
}
|
||||
|
||||
inline Rect table_row_rect(const TableLayout& layout, int scroll, int row_index) {
|
||||
return {
|
||||
layout.body.x,
|
||||
layout.body.y + (row_index - scroll) * layout.row_h,
|
||||
layout.body.w,
|
||||
layout.row_h
|
||||
};
|
||||
}
|
||||
|
||||
inline Rect table_cell_rect(const Rect& row_rect, const TableColumn& col) {
|
||||
return {row_rect.x + col.x, row_rect.y, col.w, row_rect.h};
|
||||
}
|
||||
|
||||
inline int table_hit_row(const TableLayout& layout,
|
||||
int scroll,
|
||||
int row_count,
|
||||
int mx,
|
||||
int my) {
|
||||
if (!layout.body.contains(mx, my) || layout.row_h <= 0) return -1;
|
||||
int row = (my - layout.body.y) / layout.row_h;
|
||||
int index = scroll + row;
|
||||
if (index < 0 || index >= row_count) return -1;
|
||||
return index;
|
||||
}
|
||||
|
||||
using TableRowRenderer = void (*)(Canvas& c,
|
||||
void* userdata,
|
||||
int row_index,
|
||||
const Rect& row_rect,
|
||||
int text_y,
|
||||
const TableColumn* cols,
|
||||
int col_count,
|
||||
const Theme& theme,
|
||||
const TableStyle& style);
|
||||
|
||||
inline void draw_table(Canvas& c,
|
||||
const TableLayout& layout,
|
||||
const TableColumn* cols,
|
||||
int col_count,
|
||||
int row_count,
|
||||
int scroll,
|
||||
int selected,
|
||||
int hovered,
|
||||
const Theme& theme,
|
||||
const TableStyle& style,
|
||||
TableRowRenderer draw_row,
|
||||
void* userdata) {
|
||||
c.fill_rect(layout.header.x, layout.header.y, layout.header.w, layout.header.h, style.header_bg);
|
||||
c.hline(layout.header.x, layout.header.y + layout.header.h - 1, layout.header.w, style.header_border);
|
||||
|
||||
int fh = system_font_height();
|
||||
int header_text_y = layout.header.y + (layout.header.h - fh) / 2;
|
||||
for (int i = 0; i < col_count; i++) {
|
||||
c.text(layout.header.x + cols[i].x, header_text_y, cols[i].label, style.header_text);
|
||||
}
|
||||
|
||||
int visible = table_visible_rows(layout);
|
||||
for (int row = 0; row < visible; row++) {
|
||||
int index = scroll + row;
|
||||
if (index >= row_count) break;
|
||||
|
||||
Rect row_rect = table_row_rect(layout, scroll, index);
|
||||
if (index == selected) {
|
||||
c.fill_rect(row_rect.x, row_rect.y, row_rect.w, row_rect.h, style.row_selected_bg);
|
||||
} else if (index == hovered && style.row_hover_bg.a > 0) {
|
||||
c.fill_rect(row_rect.x, row_rect.y, row_rect.w, row_rect.h, style.row_hover_bg);
|
||||
}
|
||||
|
||||
if (draw_row) {
|
||||
int text_y = row_rect.y + (layout.row_h - fh) / 2;
|
||||
draw_row(c, userdata, index, row_rect, text_y, cols, col_count, theme, style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gui::mtk
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* theme.hpp
|
||||
* Montauk Toolkit theme tokens and color helpers
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gui/gui.hpp"
|
||||
#include "gui/mtk/settings.hpp"
|
||||
|
||||
namespace gui::mtk {
|
||||
|
||||
inline Color mix(Color base, Color tint, uint8_t tint_alpha) {
|
||||
auto blend = [tint_alpha](uint8_t a, uint8_t b) -> uint8_t {
|
||||
return (uint8_t)((((uint16_t)a * (255 - tint_alpha)) +
|
||||
((uint16_t)b * tint_alpha) + 127) / 255);
|
||||
};
|
||||
return Color::from_rgb(blend(base.r, tint.r),
|
||||
blend(base.g, tint.g),
|
||||
blend(base.b, tint.b));
|
||||
}
|
||||
|
||||
inline Color lighten(Color c, uint8_t amount) {
|
||||
return mix(c, colors::WHITE, amount);
|
||||
}
|
||||
|
||||
inline Color darken(Color c, uint8_t amount) {
|
||||
return mix(c, colors::BLACK, amount);
|
||||
}
|
||||
|
||||
// Light selection/hover tint derived from the desktop accent. Returns the
|
||||
// canonical MENU_HOVER for the default blue accent so existing visuals are
|
||||
// preserved exactly; otherwise tints white with ~11% of the accent.
|
||||
inline Color accent_hover_tint(Color accent) {
|
||||
if (accent.r == colors::ACCENT.r && accent.g == colors::ACCENT.g
|
||||
&& accent.b == colors::ACCENT.b)
|
||||
return colors::MENU_HOVER;
|
||||
return mix(colors::WHITE, accent, 28);
|
||||
}
|
||||
|
||||
struct Theme {
|
||||
Color window_bg;
|
||||
Color surface;
|
||||
Color surface_alt;
|
||||
Color surface_hover;
|
||||
Color border;
|
||||
Color text;
|
||||
Color text_muted;
|
||||
Color text_subtle;
|
||||
Color text_inverse;
|
||||
|
||||
Color accent;
|
||||
Color accent_hover;
|
||||
Color accent_soft;
|
||||
Color accent_fg;
|
||||
Color selection;
|
||||
Color text_selection;
|
||||
|
||||
Color danger;
|
||||
Color danger_hover;
|
||||
Color danger_soft;
|
||||
Color danger_fg;
|
||||
|
||||
Color disabled_bg;
|
||||
Color disabled_fg;
|
||||
|
||||
Color badge_admin_bg;
|
||||
Color badge_admin_fg;
|
||||
Color badge_user_bg;
|
||||
Color badge_user_fg;
|
||||
|
||||
int radius_sm;
|
||||
int radius_md;
|
||||
int control_h;
|
||||
int tab_h;
|
||||
int gap_xs;
|
||||
int gap_sm;
|
||||
int gap_md;
|
||||
int gap_lg;
|
||||
};
|
||||
|
||||
inline Theme make_theme(Color accent) {
|
||||
Theme theme {};
|
||||
theme.window_bg = colors::WINDOW_BG;
|
||||
theme.surface = Color::from_rgb(0xF5, 0xF5, 0xF5);
|
||||
theme.surface_alt = Color::from_rgb(0xF8, 0xF8, 0xF8);
|
||||
theme.surface_hover = mix(theme.surface, accent, 18);
|
||||
theme.border = colors::BORDER;
|
||||
theme.text = colors::TEXT_COLOR;
|
||||
theme.text_muted = Color::from_rgb(0x88, 0x88, 0x88);
|
||||
theme.text_subtle = Color::from_rgb(0x66, 0x66, 0x66);
|
||||
theme.text_inverse = colors::WHITE;
|
||||
|
||||
theme.accent = accent;
|
||||
theme.accent_hover = darken(accent, 32);
|
||||
theme.accent_soft = lighten(accent, 214);
|
||||
theme.accent_fg = colors::WHITE;
|
||||
theme.selection = accent;
|
||||
theme.text_selection = Color::from_rgb(0xB0, 0xD0, 0xF0);
|
||||
|
||||
theme.danger = Color::from_rgb(0xD0, 0x3E, 0x3E);
|
||||
theme.danger_hover = Color::from_rgb(0xDD, 0x44, 0x44);
|
||||
theme.danger_soft = Color::from_rgb(0xF7, 0xDF, 0xDF);
|
||||
theme.danger_fg = colors::WHITE;
|
||||
|
||||
theme.disabled_bg = Color::from_rgb(0xCC, 0xCC, 0xCC);
|
||||
theme.disabled_fg = colors::WHITE;
|
||||
|
||||
theme.badge_admin_bg = Color::from_rgb(0xE8, 0xD8, 0xF0);
|
||||
theme.badge_admin_fg = Color::from_rgb(0x7B, 0x3E, 0xB8);
|
||||
theme.badge_user_bg = Color::from_rgb(0xE0, 0xE8, 0xF0);
|
||||
theme.badge_user_fg = Color::from_rgb(0x36, 0x7B, 0xF0);
|
||||
|
||||
theme.radius_sm = 3;
|
||||
theme.radius_md = 4;
|
||||
theme.control_h = 30;
|
||||
theme.tab_h = 36;
|
||||
theme.gap_xs = 2;
|
||||
theme.gap_sm = 6;
|
||||
theme.gap_md = 10;
|
||||
theme.gap_lg = 16;
|
||||
return theme;
|
||||
}
|
||||
|
||||
// Zero-arg overload pulls the accent from the desktop appearance settings, so
|
||||
// MTK widgets (buttons, menus, etc.) automatically pick up the user's chosen
|
||||
// accent without each caller having to plumb it through.
|
||||
inline Theme make_theme() {
|
||||
return make_theme(load_system_accent());
|
||||
}
|
||||
|
||||
} // namespace gui::mtk
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user