Chrome shaders
A frame is a rect too, so it is a pass too. where="chrome" on any entry in
shaders or in a states block runs that pass over a pane's frame (border,
padding, title, buttons) instead of its contents.
states {
// a bell nobody has answered: a quarter-second flash, then gone
bell { tint where="chrome" channel="fg" color="#ffcc00" amount="(since < 250) * 255" }
}
Nothing else changes: same shaders, same amount, same
expressions, same chain order. One new
word.
Positions are the whole frame's
x/y are counted from the frame's top-left corner, with cols/rows the size
of the pane's rect, not of one side. One pass over the whole ring, so an effect
can travel round a border instead of restarting at every corner.
For anything that travels, though, the coordinate you want is distance along the ring, which the language can work out. Clockwise from the top-left:
(y == 0 ? x : x == cols-1 ? cols - 1 + y
: y == rows-1 ? 2 * cols + rows - 3 - x : 2 * cols + 2 * rows - 4 - y)
There is no way to name a subexpression, so the formula is written out in full, which is why a small effect is a long line.
Thirteen of them are ready to paste in
contrib/chrome:
a shine running round the border, a sine comet with softer shoulders, marching
ants, a standing wave, drifting sparkles, ripples leaving a corner in both
directions, etc.
A border that says something
Depending on a pane's state, we can visually communicate through it's chrome:
states {
// a dead pane's frame breathes red until you deal with it
dead { tint where="chrome" channel="fg" color="#ff0033" amount="abs(t/8%510-255)" }
// one that has not started yet is outlined, not filled
suspended { tint where="chrome" channel="fg" color="#8a8a95" amount=160 }
// and the panes you are not in recede, frame and contents together
unfocused { dim amount=60; dim where="chrome" channel="fg" amount=90 }
}
since is what makes a flash possible: it is how long the pane has been in
this state, where t only knows what time it is. The bell state ends when you
look at the pane, because that is what answering a bell is. :-)
Animation costs a clock
Anything that reads t or since asks the session to keep painting, at
anim_ms (50ms, so 20fps) and only while such a pass is actually on screen.
anim_ms 0 turns the clock off, which leaves an animated shader advancing only
when something else causes a frame.
