summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gui/gui.zig57
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