Class: RubyTUI::Widgets::List

Inherits:
Object
  • Object
show all
Includes:
StatefulWidget
Defined in:
lib/rubytui/widgets/list.rb

Overview

List renders a scrollable, selectable list of items.

Examples:

state = RubyTUI::Widgets::ListState.new
list = RubyTUI::Widgets::List.new(items: ["One", "Two", "Three"])
frame.render_stateful_widget(list, area, state)
state.select_next(list.items.length)  # e.g. on a Down key press

See Also:

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(items: [], style: Style::DEFAULT, highlight_style: nil, highlight_symbol: "> ", block: nil) ⇒ List

Returns a new instance of List.

Parameters:

  • items (Array<String, Span, Line, #to_s>) (defaults to: []) —

    list items, each converted to a Line (default: [])

  • style (Style) (defaults to: Style::DEFAULT) —

    base style of every item (default: Style::DEFAULT)

  • highlight_style (Style, nil) (defaults to: nil) —

    patched onto style for the selected item (default: bold yellow foreground)

  • highlight_symbol (String) (defaults to: "> ") —

    prefix of the selected item; other items are prefixed with spaces of the same width (default: "> ")

  • block (Widgets::Block, nil) (defaults to: nil) —

    optional wrapping block



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/rubytui/widgets/list.rb', line 82

def initialize(
  items: [],
  style: Style::DEFAULT,
  highlight_style: nil,
  highlight_symbol: "> ",
  block: nil
)
  @items = items.map { |item| normalize_item(item) }
  @style = style
  @highlight_style = highlight_style || Style.new.fg(Color::YELLOW).bold
  @highlight_symbol = highlight_symbol
  @highlight_symbol_width = Buffer.string_width(@highlight_symbol)
  @normal_symbol = " " * @highlight_symbol_width
  @block = block
end

Instance Attribute Details

#items ⇒ Object (readonly)

Returns the value of attribute items.



72
73
74
# File 'lib/rubytui/widgets/list.rb', line 72

def items
  @items
end

Instance Method Details

#render(area, buf, state) ⇒ void

This method returns an undefined value.

Render the visible items, one per row, marking the selected item with highlight_symbol and highlight_style.

Clamps state.selected to the item range and adjusts state.offset in place so the selected item is visible. Item text is truncated to the area width; span styles are patched onto the item style.

Parameters:

  • area (Rect) —

    the rectangular area to render into

  • buf (Buffer) —

    the buffer to write cells into

  • state (ListState) —

    selection and scroll state, updated in place



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/rubytui/widgets/list.rb', line 109

def render(area, buf, state)
  return if area.empty?

  render_area = area
  if @block
    @block.render(area, buf)
    render_area = @block.inner(area)
  end

  return if render_area.empty? || @items.empty?

  # Adjust scroll offset to keep selected item visible
  visible_height = render_area.height
  clamp_state(state, visible_height)

  # Render visible items
  visible_items = @items[state.offset, visible_height] || []
  visible_items.each_with_index do |item, i|
    y = render_area.y + i
    actual_index = state.offset + i
    is_selected = actual_index == state.selected

    symbol = is_selected ? @highlight_symbol : @normal_symbol
    item_style = is_selected ? @style.patch(@highlight_style) : @style

    # Write selection symbol
    x = render_area.x
    buf.set_string(x, y, symbol, item_style)
    x += @highlight_symbol_width

    # Write item text
    available = render_area.width - @highlight_symbol_width
    item.spans.each do |span|
      break if available <= 0

      text = Buffer.truncate_to_width(span.content, available)
      text_width = Buffer.string_width(text)
      effective_style = item_style.patch(span.style)
      buf.set_string(x, y, text, effective_style)
      x += text_width
      available -= text_width
    end

    # Fill remaining width with style (for highlight background)
    if is_selected && x < render_area.right
      remaining = render_area.right - x
      buf.set_string(x, y, " " * remaining, item_style)
    end
  end
end