Selkie.git | xt/snapshots/ | 50-modal-scrim-styled.raku
use lib 'lib';
use Selkie::Test::Snapshot;
use Selkie::BorderStyle;
use Selkie::Container;
use Selkie::Layout::VBox;
use Selkie::Sizing;
use Selkie::Style;
use Selkie::Widget;
use Selkie::Widget::Modal;
use Selkie::Widget::Text;
# BackdropScrim, composited for real.
#
# A scrim only means anything when there is something underneath it, so
# this scenario builds the two-plane scene an App has at runtime: a
# screen root, and a modal mounted as a sibling above it. notcurses
# composites the whole pile before the harness reads cells back, so the
# styled readback below is the actual blended result, not the scrim
# plane's own colours.
#
# What to look for in the golden:
#
# * The screen text underneath the scrim SURVIVES — the scrim plane
# is primed with an empty EGC (gcluster 0), which notcurses's glyph
# search reads as "keep looking further down the pile". A space
# would have covered it.
# * Its colours are exactly halved towards black on both channels:
# 0xE0E0E0 on 0x202040 reads back as 0x707070 on 0x101020. One
# AlphaBlend layer is one 50/50 average, per channel, integer and
# truncating — there is no fractional alpha to turn up.
# * The dialog itself is untouched: the frame and the content sit on
# opaque planes above the scrim.
#
# The modal's own full-screen plane contributes nothing at all here
# (transparent channels, empty EGC), which is the S4 fix for
# `dim-background => False` showing a flat rectangle.
class Scene does Selkie::Container {
# children[0] is the screen root, children[1] the modal — both are
# real children so the role's destroy tears the whole scene down.
method render() {
my $screen = self.children[0];
my $modal = self.children[1];
for $screen, $modal -> $w {
next without $w;
unless $w.plane {
$w.init-plane(self.plane, y => 0, x => 0,
rows => self.rows, cols => self.cols);
}
$w.set-viewport(abs-y => self.abs-y, abs-x => self.abs-x,
rows => self.rows, cols => self.cols);
$w.mark-dirty;
$w.render;
}
self.clear-dirty;
}
}
my $screen = Selkie::Layout::VBox.new(sizing => Sizing.flex);
my $screen-style = Selkie::Style.new(fg => 0xE0E0E0, bg => 0x202040);
for <alpha beta gamma delta epsilon zeta eta theta> -> $word {
$screen.add: Selkie::Widget::Text.new(
text => $word x 4, style => $screen-style, sizing => Sizing.fixed(1),
);
}
my $modal = Selkie::Widget::Modal.new(
width-ratio => 0.5,
height-ratio => 0.5,
backdrop => BackdropScrim,
framed => True,
frame-style => BorderRounded,
frame-title => 'Hi',
frame-padding => 0,
);
$modal.set-content(Selkie::Widget::Text.new(
text => 'solid', sizing => Sizing.flex,
));
my $scene = Scene.new(sizing => Sizing.flex);
$scene.add($screen);
$scene.add($modal);
print render-to-string($scene, rows => 8, cols => 30, :capture-styles);