show names on tabs in tabbed layout
This commit is contained in:
+51
-3
@@ -21,6 +21,7 @@ const Wm = @import("Wm.zig");
|
||||
const Window = @import("Window.zig");
|
||||
const shm = @import("shm.zig");
|
||||
const color = @import("color.zig");
|
||||
const font = @import("font.zig");
|
||||
const layout = @import("layout.zig");
|
||||
const Box = layout.Box;
|
||||
|
||||
@@ -157,9 +158,10 @@ fn onLayerEvent(_: *river.LayerShellOutputV1, event: river.LayerShellOutputV1.Ev
|
||||
}
|
||||
}
|
||||
|
||||
/// The strip of solid colour blocks drawn above the windows in the tabbed
|
||||
/// layout. One block per window, the focused one highlighted; titles are not
|
||||
/// drawn here but are published over IPC for bars that want to render them.
|
||||
/// The strip of tabs drawn above the windows in the tabbed layout. One tab per
|
||||
/// window, labelled with its title and the focused one highlighted. The same
|
||||
/// titles are published over IPC, for bars that would rather draw the tabs
|
||||
/// themselves with a real font.
|
||||
pub const TabBar = struct {
|
||||
wm: *Wm,
|
||||
|
||||
@@ -240,6 +242,7 @@ pub const TabBar = struct {
|
||||
const sep = color.toArgb8888(config.tab_separator);
|
||||
buffer.fill(local, sep);
|
||||
|
||||
const scale = textScale(box.height);
|
||||
for (self.rects.items, windows) |rect, win| {
|
||||
const is_focused = focused != null and focused.? == win;
|
||||
const argb = color.toArgb8888(if (is_focused) config.tab_focused else config.tab_normal);
|
||||
@@ -252,6 +255,9 @@ pub const TabBar = struct {
|
||||
.height = rect.height,
|
||||
};
|
||||
buffer.fill(inner, argb);
|
||||
|
||||
const ink = color.toArgb8888(if (is_focused) config.tab_text_focused else config.tab_text_normal);
|
||||
drawLabel(buffer, inner, label(win), scale, ink);
|
||||
}
|
||||
|
||||
// Translate the hit rectangles into global coordinates for click
|
||||
@@ -286,6 +292,48 @@ pub const TabBar = struct {
|
||||
self.windows.clearRetainingCapacity();
|
||||
}
|
||||
|
||||
/// What to write on a window's tab: its title, or its app id while it has
|
||||
/// not set one, so that a tab is never blank.
|
||||
fn label(win: *const Window) []const u8 {
|
||||
if (win.title) |t| {
|
||||
if (t.len > 0) return t;
|
||||
}
|
||||
if (win.app_id) |a| {
|
||||
if (a.len > 0) return a;
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
/// Whole-pixel scale for the font: the largest that leaves a little air
|
||||
/// above and below in a bar this tall. `config.tab_font_scale` overrides
|
||||
/// it for anyone wanting big letters in a thin bar, or the reverse.
|
||||
fn textScale(height: i32) i32 {
|
||||
if (config.tab_font_scale > 0) return config.tab_font_scale;
|
||||
var s: i32 = 1;
|
||||
while (s < 4 and font.cell_height * (s + 1) + 4 <= height) s += 1;
|
||||
return s;
|
||||
}
|
||||
|
||||
/// Centre a title in one tab, eliding it with an ellipsis when the tab is
|
||||
/// too narrow to hold it.
|
||||
fn drawLabel(buffer: *shm.Buffer, tab: Box, text: []const u8, scale: i32, argb: u32) void {
|
||||
const pad = 2 * scale;
|
||||
const avail = tab.width - 2 * pad;
|
||||
if (avail <= 0) return;
|
||||
|
||||
const f = font.fit(text, font.cellsForWidth(avail, scale));
|
||||
const cells = f.cells + @intFromBool(f.elided);
|
||||
if (cells == 0) return;
|
||||
|
||||
const x = tab.x + @divFloor(tab.width - font.textWidth(cells, scale), 2);
|
||||
// Centre the part above the baseline; the descender row may hang into
|
||||
// the padding, which is what it is for.
|
||||
const y = tab.y + @divFloor(tab.height - (font.cell_height - 1) * scale, 2);
|
||||
|
||||
const pen = buffer.drawText(text[0..f.end], x, y, scale, argb, tab);
|
||||
if (f.elided) buffer.drawGlyph(font.ellipsis, pen, y, scale, argb, tab);
|
||||
}
|
||||
|
||||
/// Which window's tab covers this global coordinate, if any.
|
||||
pub fn windowAt(self: *const TabBar, x: i32, y: i32) ?*Window {
|
||||
if (!self.mapped) return null;
|
||||
|
||||
Reference in New Issue
Block a user