class
TUI::HSplit
- TUI::HSplit
- TUI::Widget
- Reference
- Object
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.crConstructors
-
.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.
-
.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.
- .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)
Instance Method Summary
-
#border_style : Style
Applied to the divider line drawn by #render when #bordered? is true.
-
#border_style=(border_style : Style)
Applied to the divider line drawn by #render when #bordered? is true.
-
#bordered=(bordered : Bool)
Whether to draw the vertical divider between panes — false to leave the gap column blank, e.g.
-
#bordered? : Bool
Whether to draw the vertical divider between panes — false to leave the gap column blank, e.g.
-
#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.
-
#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.
-
#handle_key(ev : KeyEvent) : Bool
Returns true if the key was consumed.
-
#left : Widget
The two hosted panes.
-
#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.
-
#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. -
#left_width : Int32
Width in columns of the left pane, excluding the divider column.
-
#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.
-
#render : Nil
Draw into @buffer using LOCAL coordinates (0, 0 = this widget's own top-left).
- #right : Widget
-
#status_hint : String
Plain text describing the actions available in the widget's current state.
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
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.
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.
Instance Method Detail
Applied to the divider line drawn by #render when #bordered? is true.
Applied to the divider line drawn by #render when #bordered? is true.
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?.
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?.
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.
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.
Returns true if the key was consumed.
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.
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.
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.
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.
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.
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.
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.