diff --git a/app/layout/ViewDrag.zig b/app/layout/ViewDrag.zig index 664e544f1..1584869d0 100644 --- a/app/layout/ViewDrag.zig +++ b/app/layout/ViewDrag.zig @@ -2063,7 +2063,7 @@ fn drawTabFace(l: *Layout, d: ViewDrag, title: []const u8) void { // selected tab's — it is the tab in hand. The face drawn before the tab became glass is the // strip's own, so anything else here changed on the way back. const theme = dvui.themeGet(); - const icon_color = theme.color(.control, .text); + const icon_color = core.widgets.treeGlyphColor(theme); const color = theme.color(.window, .text); if (asRows(d)) return drawRows(l, &d, icon_color, color); var row = dvui.box(@src(), .{ .dir = .horizontal }, .{ .gravity_x = 0.5, .gravity_y = 0.5 }); diff --git a/core/widgets.zig b/core/widgets.zig index 7d7082579..52b4f6430 100644 --- a/core/widgets.zig +++ b/core/widgets.zig @@ -319,6 +319,16 @@ pub fn treeRowGlyphSize() dvui.Size { return .{ .w = h, .h = h }; } +/// The colour a file's glyph rests in — a file tree's rows (lit toward their accent as the pointer +/// nears), a document tab's, a row or tab carried in glass — so a file looks the same wherever it +/// is shown: the theme's control text, as the tree's labels. Not the window's fill, the theme's +/// darkest, which the tree's glyphs once rested in: that read only on the main window's own base, +/// and on a pane's card (a popped-out float's, under any window material) it was the colour +/// under them. +pub fn treeGlyphColor(theme: dvui.Theme) dvui.Color { + return theme.color(.control, .text); +} + /// A tree row's expand caret, in its own glyph slot: down when `expanded`, right when not. /// /// The two arrows are different shapes (the down one wide, the right one tall) and the icon fits diff --git a/plugins/workbench/src/Workspace.zig b/plugins/workbench/src/Workspace.zig index 254dc20f6..ca45168c7 100644 --- a/plugins/workbench/src/Workspace.zig +++ b/plugins/workbench/src/Workspace.zig @@ -329,7 +329,7 @@ fn drawTabs(self: *Workspace, region: sdk.Host.Region, tabs: []const *sdk.Surfac // Same fixed glyph slot as the file tree. const tab_doc_path = if (doc_opt) |doc| doc.owner.documentPath(doc) else loading.?.path; - const tab_icon_color = dvui.themeGet().color(.control, .text); + const tab_icon_color = core.widgets.treeGlyphColor(dvui.themeGet()); { var icon_slot = core.widgets.treeRowGlyph(@src(), .{ .gravity_y = 0.5, .margin = .{ .x = 4, .w = 2 } }); defer icon_slot.deinit(); diff --git a/plugins/workbench/src/files.zig b/plugins/workbench/src/files.zig index df4ee2784..ed5f71fd2 100644 --- a/plugins/workbench/src/files.zig +++ b/plugins/workbench/src/files.zig @@ -959,7 +959,7 @@ pub fn recurseFiles(root_directory: []const u8, root_label: []const u8, outer_tr const t = 1.0 - (distance / max_distance); - color = dvui.themeGet().color(.window, .fill).lerp(color, t); + color = core.widgets.treeGlyphColor(dvui.themeGet()).lerp(color, t); if (branch.floating()) { if (dvui.dataGetSlice(null, inner_unique_id, "removed_path", []u8) == null) diff --git a/tests/integration.zig b/tests/integration.zig index bb08a5378..8d7522537 100644 --- a/tests/integration.zig +++ b/tests/integration.zig @@ -6991,6 +6991,39 @@ test "workbench: where a tab carried over a strip goes in is read as if its open try std.testing.expectEqual(@as(usize, 3), pane.insertIndexAt(500, 3)); } +fn glyphLuma(c: dvui.Color) f32 { + return 0.2126 * @as(f32, @floatFromInt(c.r)) + 0.7152 * @as(f32, @floatFromInt(c.g)) + 0.0722 * @as(f32, @floatFromInt(c.b)); +} + +test "workbench: a file tree's glyphs stand off the main window's base and a float's pane alike" { + // Fizzy Dark's colours, as `Editor` sets them up (no themes are loaded here). + var fizzy_dark = dvui.Theme.builtin.adwaita_dark; + fizzy_dark.window = .{ .fill = .{ .r = 28, .g = 29, .b = 36 }, .text = .{ .r = 206, .g = 163, .b = 127 } }; + fizzy_dark.control = .{ .fill = .{ .r = 28, .g = 29, .b = 36 }, .text = .{ .r = 134, .g = 138, .b = 148 } }; + fizzy_dark.fill = .{ .r = 42, .g = 44, .b = 54 }; + // The report, measured in a popped-out float on Liquid Glass: its explorer's pane card, and the + // main window's sidebar beside it. The window's fill, which the glyphs rested in, was the + // sidebar's dark glyph and within a few steps of the float's card: invisible there. + const float_card: dvui.Color = .{ .r = 38, .g = 39, .b = 45 }; + const main_base: dvui.Color = .{ .r = 65, .g = 67, .b = 74 }; + try std.testing.expect(@abs(glyphLuma(fizzy_dark.color(.window, .fill)) - glyphLuma(float_card)) < 15); + const glyph = fizzy.core.widgets.treeGlyphColor(fizzy_dark); + try std.testing.expect(@abs(glyphLuma(glyph) - glyphLuma(float_card)) > 60); + try std.testing.expect(@abs(glyphLuma(glyph) - glyphLuma(main_base)) > 40); + + // And in every theme fizzy ships with dvui's: off the window's fill and the content fill (a + // pane's card), whichever a tree is drawn on, in the main window or a float. + for (dvui.Theme.builtins) |theme| { + const g = fizzy.core.widgets.treeGlyphColor(theme); + for ([_]dvui.Color{ theme.color(.window, .fill), theme.color(.content, .fill) }) |base| { + std.testing.expect(@abs(glyphLuma(g) - glyphLuma(base)) > 40) catch |err| { + std.debug.print("{s}: glyph {f} on {f}\n", .{ theme.name, g, base }); + return err; + }; + } + } +} + // An app's home page in place of the workbench's: a surface keyworded `home`, shown in the `Home` // place the sole document pane declares while it is empty (`Workspace.drawHome`). The pane here is // declared as `Workspace.draw` declares it, through the plugin's `Host`, so the place is the one