TermBuf::View
Inherits TermBuf::Drawing < Reference < Object
Stability: stable — changes only in a major release.
A rectangle of another drawing surface, addressed from its own top left and cut at its own edges.
A panel drawn over other content has to stay inside its border, and the
arithmetic for that does not belong in every widget. A view is where it
goes: (0, 0) is the panel's top left corner, and anything reaching past
its edges is trimmed on the way through rather than landing on whatever is
beside it.
terminal.batch do |screen|
draw_table screen
panel = screen.view Rect.new(10, 4, 30, 8)
panel.fill panel.bounds, ' ', Style::DEFAULT.reverse
panel.write 0, 0, "a line far longer than thirty cells"
end
Views nest: view.view(inner) is another view, so a border can hand what
it surrounds a surface of exactly the space left inside it. Everything
built on Drawing works against one.
A view can also carry a #style that everything drawn through it merges
onto, which is what a highlighted row wants: fill it once, then write its
columns naming only what each one adds.
row = screen.view rect, style: Style::DEFAULT.bg(highlight)
row.clear # paints the highlight
row.write 0, 0, name, Style::DEFAULT.bold # bold, on the highlight
row.write 24, 0, rate, Style::DEFAULT.faint
A write that names a background of its own still wins. Nested views layer the same way, each filling in what the one inside it left unset.
This is clipping, not layering. Nothing here says a view is on top of anything, and dismissing a panel means the next frame does not draw it — the paint diff then sends the cells it covered and nothing else.
A Blend on a draw call passes through as it is. The view translates the
write before the buffer runs the blend, so the position such a blend is
given is the cell's in the buffer rather than in the view — the same
coordinates a blend sees when nothing was drawn through a view at all.
A view can carry a #blend of its own, which is the position-aware half of
#style: a gradient across a panel, wherever the panel ends up. That one is
asked in the view's coordinates instead. See #blend.
Two commands pass through untouched, because neither is addressed in cells
of this view: #passthrough, which is aimed at the terminal, and
#scroll_region, since a Region carries its own rectangle in the
buffer's coordinates.
Constructors
A view of rect of target. Drawing#view is the way in: it makes one
of these and hands it the surface's #policy, which a view built here
keeps at the default.
Instance methods
A Blend run for every cell drawn through the view, or nil for none.
The positions it is given are this view's own, (0, 0) at the view's
top left, so a Gradient built against #bounds paints the same ramp
wherever the view is moved to and however deeply it is nested. This is
the one place a blend is not asked in the buffer's coordinates; a blend
passed to a draw call still is, since it was written against the surface
the caller was drawing on.
A draw call carrying a blend of its own does not lose it. The view's runs
first, settling the style being written, and the call's runs on that
result — the same precedence #style has, where the innermost thing to
name a field wins:
panel = screen.view rect, blend: ramp.background
panel.clear # the ramp
panel.write 0, 0, label, Style::DEFAULT.bold,
blend: Style::KEEP_BACKGROUND # bold, over the ramp
Nesting composes the same way, outermost view first and the draw call last, each asked in its own coordinates.
A Blend run for every cell drawn through the view, or nil for none.
The positions it is given are this view's own, (0, 0) at the view's
top left, so a Gradient built against #bounds paints the same ramp
wherever the view is moved to and however deeply it is nested. This is
the one place a blend is not asked in the buffer's coordinates; a blend
passed to a draw call still is, since it was written against the surface
the caller was drawing on.
A draw call carrying a blend of its own does not lose it. The view's runs
first, settling the style being written, and the call's runs on that
result — the same precedence #style has, where the innermost thing to
name a field wins:
panel = screen.view rect, blend: ramp.background
panel.clear # the ramp
panel.write 0, 0, label, Style::DEFAULT.bold,
blend: Style::KEEP_BACKGROUND # bold, over the ramp
Nesting composes the same way, outermost view first and the draw call last, each asked in its own coordinates.
The view's own rectangle, which starts at its origin rather than at the target's. What to fill or pass on to something that wants an area.
Trims command to the view and sends it on, or drops it when nothing of it lands inside.
Where the screen cell (x, y) falls in this view, or nil when it
falls outside the view altogether.
The inverse of what a draw call goes through: the buffer's coordinates in,
the view's own out. Nesting is already accounted for, since the answer is
measured from #origin, so a cell is turned into the innermost view's
coordinates in one step rather than one per level.
if inside = panel.local(hit.x, hit.y)
column, row = inside
end
Coordinates are 0-based cells on both sides. An SGR mouse report is 1-based; converting one is the mouse decoder's job, not this method's.
Where this view's (0, 0) falls in the buffer's coordinates, which is
what #blend is translated by. Fixed at construction: a view's rectangle
and its target never change.
How clusters are measured when a write is trimmed. Set from whatever the surface it was made from uses, so a cut falls where the buffer will put the cells.
How clusters are measured when a write is trimmed. Set from whatever the surface it was made from uses, so a cut falls where the buffer will put the cells.
What everything drawn through the view merges onto: a field a write
leaves unset comes from here, and one it names wins. See Style#merge.
What everything drawn through the view merges onto: a field a write
leaves unset comes from here, and one it names wins. See Style#merge.