class

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

new(target : Drawing, rect : Rect, style : Style = Style::DEFAULT, blend : Blend | Nil = nil)

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.

Source

Instance methods

blend

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.

Source
blend=(blend : Blend | Nil)

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.

Source
bounds

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.

Source
height

Rows down.

Source
issue(command : Command) : Nil

Trims command to the view and sends it on, or drops it when nothing of it lands inside.

Source
local(x : Int32, y : Int32) : Tuple(Int32, Int32) | Nil

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.

Source
origin

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.

Source
policy

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.

Source
policy=(policy : Unicode::WidthPolicy)

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.

Source
rect

The rectangle this view covers, in target's coordinates.

Source
style

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.

Source
style=(style : Style)

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.

Source
target

Where clipped commands go: a Terminal, a Batcher, a BufferSurface, or another view.

Source
width

Cells across.

Source