From fdf586305b611eb06d884268d1dcd834c158ce0f Mon Sep 17 00:00:00 2001 From: Daniel Hammer Date: Mon, 6 Jul 2026 21:01:51 +0200 Subject: [PATCH] feat: use the shared mtk tab bar for charmap's top tabs Replace charmap's bespoke tab drawing/hit-testing with mtk::draw_tab_bar / mtk::hit_tab_bar so the top tabs match the canonical MontaukOS style used by the Desktop Settings panel: a surface-colored bar with a bottom border, the active tab cut out in window_bg with a 3px accent underline, active label in accent and inactive labels in text_subtle. Tab height is now 36 (theme.tab_h). Drops the custom hover tint (the canonical style has none). Co-Authored-By: Claude Opus 4.8 --- programs/src/charmap/main.cpp | 44 +++++++---------------------------- 1 file changed, 9 insertions(+), 35 deletions(-) diff --git a/programs/src/charmap/main.cpp b/programs/src/charmap/main.cpp index 3b2505e..a8f3e11 100644 --- a/programs/src/charmap/main.cpp +++ b/programs/src/charmap/main.cpp @@ -26,6 +26,7 @@ #include #include #include +#include extern "C" { #include @@ -198,7 +199,7 @@ static constexpr int SET_COUNT = (int)(sizeof(SETS) / sizeof(SETS[0])); static constexpr int INIT_W = 680; static constexpr int INIT_H = 448; -static constexpr int TAB_H = 40; +static constexpr int TAB_H = 36; // matches mtk theme.tab_h / Settings TAB_BAR_H static constexpr int FOOTER_H = 84; static constexpr int GRID_PAD = 12; static constexpr int CELL_GAP = 6; @@ -219,7 +220,6 @@ static constexpr uint64_t TOAST_MS = 1400; static int g_set = 0; // active character set index static int g_sel = 0; // selected glyph index within active set static int g_hover = -1; // hovered glyph index, or -1 -static int g_tab_hover = -1; // hovered tab index, or -1 static bool g_copy_hover = false; static bool g_copy_pressed = false; static int g_scroll = 0; // vertical scroll offset in px @@ -227,6 +227,7 @@ static uint64_t g_toast_until = 0; static char g_toast[48] = {}; static mtk::Theme g_theme; +static const char* g_tab_labels[SET_COUNT] = {}; // populated from SETS in _start // ==== Derived layout ==== @@ -293,15 +294,6 @@ static int hit_tile(const Layout& L, int mx, int my) { return -1; } -static int hit_tab(const Layout& L, int mx, int my) { - if (my < L.tabs.y || my >= L.tabs.y + L.tabs.h) return -1; - int tab_w = L.tabs.w / SET_COUNT; - if (tab_w <= 0) return -1; - int idx = mx / tab_w; - if (idx < 0 || idx >= SET_COUNT) return -1; - return idx; -} - static void clamp_scroll(const Layout& L) { if (g_scroll > L.max_scroll) g_scroll = L.max_scroll; if (g_scroll < 0) g_scroll = 0; @@ -399,27 +391,10 @@ static void render(Canvas& c) { (SCROLLBAR_W - 4) / 2, g_theme.border); } - // ---- Tab bar (opaque) ---- - c.fill_rect(L.tabs.x, L.tabs.y, L.tabs.w, L.tabs.h, g_theme.window_bg); - int tab_w = L.tabs.w / SET_COUNT; - for (int t = 0; t < SET_COUNT; t++) { - int tx = t * tab_w; - bool active = (t == g_set); - if (t == g_tab_hover && !active) - c.fill_rect(tx, L.tabs.y, tab_w, L.tabs.h, g_theme.surface_hover); - Color tc = active ? g_theme.accent - : (t == g_tab_hover ? g_theme.text : g_theme.text_muted); - int lw = text_width(fonts::system_font, SETS[t].label, TAB_SIZE); - int lh = text_height(fonts::system_font, TAB_SIZE); - draw_text(c, fonts::system_font, tx + (tab_w - lw) / 2, - L.tabs.y + (L.tabs.h - lh) / 2 - 1, SETS[t].label, tc, TAB_SIZE); - if (active) { - int uw = lw + 16; - c.fill_rounded_rect(tx + (tab_w - uw) / 2, L.tabs.y + L.tabs.h - 3, - uw, 3, 1, g_theme.accent); - } - } - c.fill_rect(L.tabs.x, L.tabs.y + L.tabs.h - 1, L.tabs.w, 1, g_theme.border); + // ---- Tab bar (opaque) — canonical MontaukOS top-tab style, matching the + // Desktop Settings panel (surface bar, window_bg active tab, accent + // underline). Covers any grid spill above the grid top. ---- + mtk::draw_tab_bar(c, L.tabs, g_tab_labels, SET_COUNT, g_set, g_theme); // Bold font for the footer name and Copy button. TrueTypeFont* title_font = @@ -492,8 +467,7 @@ static bool handle_mouse(const montauk::abi::WinEvent& ev, int w, int h) { int tile = hit_tile(L, mx, my); if (tile != g_hover) { g_hover = tile; redraw = true; } - int tab = hit_tab(L, mx, my); - if (tab != g_tab_hover) { g_tab_hover = tab; redraw = true; } + int tab = mtk::hit_tab_bar(L.tabs, SET_COUNT, mx, my); bool copy_hov = L.copy_btn.contains(mx, my); if (copy_hov != g_copy_hover) { g_copy_hover = copy_hov; redraw = true; } @@ -564,6 +538,7 @@ static bool handle_key(const montauk::abi::KeyEvent& key, int w, int h) { extern "C" void _start() { fonts::init(); g_theme = mtk::make_theme(); + for (int i = 0; i < SET_COUNT; i++) g_tab_labels[i] = SETS[i].label; WsWindow win; if (!win.create("Character Map", INIT_W, INIT_H)) @@ -598,7 +573,6 @@ extern "C" void _start() { if (ev.type == 3) break; // close if (ev.type == 2 || ev.type == 4) { // resize / scale g_hover = -1; - g_tab_hover = -1; redraw = true; } else if (ev.type == 1) { redraw = handle_mouse(ev, win.width, win.height);