class TUI::HSplit

Overview

Positions two widgets side by side with a vertical divider between them, replacing the pattern of hand-computing a split width and drawing the divider with manual absolute-coordinate calls. Owns only the children's geometry and the divider — each child still renders itself.

The split is either a fixed column count (#left_width) or a proportion of the total width (#left_ratio) — the latter keeps both panes expanding or shrinking together, relative to each other, across resizes, since #layout re-derives #left_width from #left_ratio on every #composite. Only one is active at a time; setting one clears the other.

Tab toggles which pane is active and routes keys to it — the same convention SplitWindow uses for its two Scrollables, generalized here to two full Widgets. Each child's focus_if is driven from the active pane each render, so a widget like TableView can style its own cursor row accordingly, exactly as it would hosted standalone or in SplitWindow.

Defined in:

tui/layout/hsplit.cr

Constructors

Instance Method Summary

Instance methods inherited from class TUI::Widget

absolute(row : Int32, col : Int32) : NamedTuple(row: Int32, col: Int32) absolute, composite(screen : Screen) : Nil composite, focus_if(condition : Bool) : Nil focus_if, focused=(focused : Bool) focused=, focused? : Bool focused?, handle_key(ev : KeyEvent) : Bool handle_key, height : Int32 height, height=(height : Int32) height=, local(row : Int32, col : Int32) : NamedTuple(row: Int32, col: Int32) local, render : Nil render, render_to(buffer : Buffer) : Nil render_to, status_hint : String status_hint, width : Int32 width, width=(width : Int32) width=, x : Int32 x, x=(x : Int32) x=, y : Int32 y, y=(y : Int32) y=

Constructor methods inherited from class TUI::Widget

new(x : Int32, y : Int32, width : Int32, height : Int32) new

Constructor Detail

def self.full_screen(screen : Screen, left : Widget, right : Widget, left_width : Int32 | Nil = nil, left_ratio : Float64 | Nil = nil, bordered : Bool = true) : HSplit #

Sizes and positions an HSplit to fill the screen below the status bar row — see Window.full_screen for the same reasoning. #left_width defaults to an even split when neither it nor #left_ratio is given.


[View source]
def self.full_screen_scrollables(screen : Screen, left : Scrollable, right : Scrollable, left_width : Int32 | Nil = nil, left_ratio : Float64 | Nil = nil) : HSplit #

Convenience wrapper for the common case of two Scrollables placed side by side without a shared border — HSplit itself only accepts full Widgets (see full_screen above), since each pane may be an arbitrary composite widget, not just a bare Scrollable. Wraps each Scrollable in its own borderless Window before delegating to full_screen, replacing the pattern of hand-computing left_width and building two matching Window.new calls.


[View source]
def self.new(x : Int32, y : Int32, width : Int32, height : Int32, left : Widget, right : Widget, left_width : Int32 | Nil = nil, left_ratio : Float64 | Nil = nil, bordered : Bool = true) #

[View source]

Instance Method Detail

def border_style : Style #

Applied to the divider line drawn by #render when #bordered? is true.


[View source]
def border_style=(border_style : Style) #

Applied to the divider line drawn by #render when #bordered? is true.


[View source]
def bordered=(bordered : Bool) #

Whether to draw the vertical divider between panes — false to leave the gap column blank, e.g. when each pane supplies its own visual separation. Mirrors Window#bordered?.


[View source]
def bordered? : Bool #

Whether to draw the vertical divider between panes — false to leave the gap column blank, e.g. when each pane supplies its own visual separation. Mirrors Window#bordered?.


[View source]
def composite(screen : Screen) : Nil #

Children are separate widgets with their own buffers — composite them directly onto the screen rather than drawing them into HSplit's own buffer, then draw just the divider into HSplit's buffer as usual.

Order matters: super (Widget#composite) blits HSplit's OWN buffer — blank except for the divider column — over its entire bounding box. If that ran after the children, it would wipe out everything they just drew except the one divider column. Draw the divider first, so each child's later blit wins for its own region and only the actual divider column (never touched by either child) is left showing it.


[View source]
def focus_left : Nil #

Resets which pane is active back to the left one — for a host app that reuses the same HSplit instance across appearances and wants a consistent starting focus each time it reappears, rather than carrying over whatever pane was last active before it was hidden. Mirrors SplitWindow#focus_left.


[View source]
def handle_key(ev : KeyEvent) : Bool #
Description copied from class TUI::Widget

Returns true if the key was consumed.


[View source]
def left : Widget #

The two hosted panes. Read-only from outside — HSplit itself owns their geometry (see #layout, driven from HSplit's own x/y/width/ height/#left_width or #left_ratio); mutate #left_width/#left_ratio rather than these directly.


[View source]
def left_ratio : Float64 | Nil #

Fraction (0.0-1.0) of total width the left pane occupies, re-derived every #layout so both panes expand/shrink together, proportionally to each other, across resizes — nil when in fixed-#left_width mode.


[View source]
def left_ratio=(r : Float64) : Nil #

Switches to ratio mode: the left pane's width becomes r * width, recomputed on every #layout (including resizes) instead of staying pinned to an absolute column count. Re-runs #layout immediately.


[View source]
def left_width : Int32 #

Width in columns of the left pane, excluding the divider column. When #left_ratio is set, this reflects the ratio's current column count as of the last #layout, but is a derived value, not the source of truth.


[View source]
def left_width=(w : Int32) : Nil #

Sets a fixed column width for the left pane and switches out of ratio mode (clears #left_ratio) — the two are mutually exclusive. Re-runs #layout immediately so both panes' geometry stays consistent with the new split.


[View source]
def render : Nil #
Description copied from class TUI::Widget

Draw into @buffer using LOCAL coordinates (0, 0 = this widget's own top-left). Widgets never need to know their own x/y offset to draw themselves — that arithmetic is handled entirely by #composite.


[View source]
def right : Widget #

[View source]
def status_hint : String #
Description copied from class TUI::Widget

Plain text describing the actions available in the widget's current state. Rendered by the App in the global status bar at the bottom of the screen — widgets must NOT draw their own hint lines.


[View source]