diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/gui/gui.zig | 57 |
1 files changed, 52 insertions, 5 deletions
diff --git a/src/gui/gui.zig b/src/gui/gui.zig index c737450b..be961477 100644 --- a/src/gui/gui.zig +++ b/src/gui/gui.zig @@ -9330,12 +9330,15 @@ fn tagPlaques(g: *Gui, gpa: std.mem.Allocator, regions: []const pardes.Region, g const b = plaque.border; const sh = plaque.shadow; const fill = if (tag.active) chrome.tag_focus_bg else chrome.tag_bg; - // The band's own ground, then the shadow, the frame and the fill. - try addDecor(g, gpa, plaque.band[0], plaque.band[1], plaque.band[2], plaque.band[3], page, 1, track, win_w, win_h); - const shadow_rgb = chrome.decor_box_shadow orelse border_rgb; - try addDecor(g, gpa, plaque.box[0] + sh[0], plaque.box[1] + sh[1], plaque.box[2] + sh[0], plaque.box[3] + sh[1], if (pane) shadow_rgb else mixRgb(shadow_rgb, page), 1, track, win_w, win_h); - try addDecor(g, gpa, plaque.box[0], plaque.box[1], plaque.box[2], plaque.box[3], border_rgb, 1, track, win_w, win_h); + // The band's own ground, then the shadow, the frame and the fill, + // each only where the ones over it leave it showing: all four are + // opaque, so that is the same picture drawn once, not four times. + const shadow: [4]f32 = .{ plaque.box[0] + sh[0], plaque.box[1] + sh[1], plaque.box[2] + sh[0], plaque.box[3] + sh[1] }; const inner: [4]f32 = .{ plaque.box[0] + b, plaque.box[1] + b, plaque.box[2] - b, plaque.box[3] - b }; + try addDecorExcept(g, gpa, plaque.band, &.{ plaque.box, shadow }, page, track, win_w, win_h); + const shadow_rgb = chrome.decor_box_shadow orelse border_rgb; + try addDecorExcept(g, gpa, shadow, &.{plaque.box}, if (pane) shadow_rgb else mixRgb(shadow_rgb, page), track, win_w, win_h); + try addDecorExcept(g, gpa, plaque.box, &.{inner}, border_rgb, track, win_w, win_h); if (pane and tag.active and chrome.decor_box_stripe != null) try addPattern(g, gpa, inner[0], inner[1], inner[2], inner[3], chrome.decor_box_stripe.?, fill, dp(@floatFromInt(@max(1, chrome.decor_box_stripe_px))), true, track, win_w, win_h) else @@ -9343,6 +9346,50 @@ fn tagPlaques(g: *Gui, gpa: std.mem.Allocator, regions: []const pardes.Region, g }; } +/// Flat decor over `rect` (window pixels) less each of `holes`: up to four +/// strips round the first hole's part of it, each less the rest. +fn addDecorExcept(g: *Gui, gpa: std.mem.Allocator, rect: [4]f32, holes: []const [4]f32, rgb: [3]u8, track: ?pardes.animation.Track, win_w: f32, win_h: f32) std.mem.Allocator.Error!void { + if (rect[0] >= rect[2] or rect[1] >= rect[3]) return; + if (holes.len == 0) return addDecor(g, gpa, rect[0], rect[1], rect[2], rect[3], rgb, 1, track, win_w, win_h); + const hole = holes[0]; + const x0 = @max(rect[0], hole[0]); + const y0 = @max(rect[1], hole[1]); + const x1 = @min(rect[2], hole[2]); + const y1 = @min(rect[3], hole[3]); + if (x0 >= x1 or y0 >= y1) return addDecorExcept(g, gpa, rect, holes[1..], rgb, track, win_w, win_h); + for ([_][4]f32{ + .{ rect[0], rect[1], rect[2], y0 }, + .{ rect[0], y1, rect[2], rect[3] }, + .{ rect[0], y0, x0, y1 }, + .{ x1, y0, rect[2], y1 }, + }) |strip| try addDecorExcept(g, gpa, strip, holes[1..], rgb, track, win_w, win_h); +} + +test "decor less its holes covers each pixel of the rest once and none of the holes" { + const gpa = std.testing.allocator; + var g: Gui = undefined; + g.cell_w = 1; + g.cell_h = 1; + g.decor = .empty; + defer g.decor.deinit(gpa); + const holes = [_][4]f32{ .{ 3, 2, 9, 6 }, .{ 5, 4, 12, 8 }, .{ 30, 30, 40, 40 } }; + try addDecorExcept(&g, gpa, .{ 1, 1, 11, 10 }, &holes, .{ 1, 2, 3 }, null, 16, 12); + for (0..12) |y| for (0..16) |x| { + const px: f32 = @as(f32, @floatFromInt(x)) + 0.5; + const py: f32 = @as(f32, @floatFromInt(y)) + 0.5; + var hits: usize = 0; + for (g.decor.items) |item| { + const r: [4]f32 = .{ (item.x0 + 1) / 2 * 16, (1 - item.y0) / 2 * 12, (item.x1 + 1) / 2 * 16, (1 - item.y1) / 2 * 12 }; + hits += @intFromBool(px > r[0] and px < r[2] and py > r[1] and py < r[3]); + } + const in_rect = px > 1 and px < 11 and py > 1 and py < 10; + const in_hole = for (holes) |h| { + if (px > h[0] and px < h[2] and py > h[1] and py < h[3]) break true; + } else false; + try std.testing.expectEqual(@as(usize, @intFromBool(in_rect and !in_hole)), hits); + }; +} + const Plaque = struct { band: [4]f32, box: [4]f32, border: f32, shadow: [2]f32 }; /// A tag's plaque in window pixels: its band (the rows, from after the |
