Class: Potty::Widgets::RadioGroup

Inherits:
Base
  • Object
show all
Defined in:
lib/potty/widgets/radio_group.rb

Overview

N mutually exclusive options, one row each. Up/down move the cursor; Space/Enter selects the option under the cursor. Renders “(u25CF) label” for the chosen option and “(u25CB) label” for the rest.

Note the two distinct positions: the cursor (highlight, moved by arrows) and the selection (the committed value). They diverge while the user is navigating and reconverge on select.

Instance Attribute Summary collapse

Attributes inherited from Base

#app, #focused, #parent, #rect

Instance Method Summary collapse

Methods inherited from Base

#activate, #blur, #deactivate, #focus, #handle_escape, #hide, #layout, #on_blur, #on_focus, #on_layout, #show, #theme, #tick, #visible=, #visible?

Methods included from Events

#emit, #listeners?, #off, #on

Constructor Details

#initialize(app, options: [], selected: nil, on_change: nil) ⇒ RadioGroup

Returns a new instance of RadioGroup.



19
20
21
22
23
24
25
# File 'lib/potty/widgets/radio_group.rb', line 19

def initialize(app, options: [], selected: nil, on_change: nil)
  super(app)
  @options = normalize(options)
  @on_change = on_change
  @selected = selected.nil? ? @options.first&.fetch(:value) : selected
  @cursor = index_of(@selected) || 0
end

Instance Attribute Details

#on_changeObject

Returns the value of attribute on_change.



17
18
19
# File 'lib/potty/widgets/radio_group.rb', line 17

def on_change
  @on_change
end

Instance Method Details

#can_focus?Boolean

Returns:

  • (Boolean)


27
28
29
# File 'lib/potty/widgets/radio_group.rb', line 27

def can_focus?
  true
end

#cursor_valueObject

The value under the cursor (the highlighted row), which may differ from the committed selection while navigating. Choosers commit this on Enter.



47
48
49
50
# File 'lib/potty/widgets/radio_group.rb', line 47

def cursor_value
  opt = @options[@cursor]
  opt && opt[:value]
end

#handle_key(ch) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/potty/widgets/radio_group.rb', line 66

def handle_key(ch)
  case ch
  when Keys::UP
    move(-1)
  when Keys::DOWN
    move(1)
  when Keys::SPACE, *Keys::ENTERS
    choose(@cursor)
  else
    return false
  end
  true
end

#optionsObject



31
32
33
# File 'lib/potty/widgets/radio_group.rb', line 31

def options
  @options
end

#options=(opts) ⇒ Object



35
36
37
38
# File 'lib/potty/widgets/radio_group.rb', line 35

def options=(opts)
  @options = normalize(opts)
  @cursor = @cursor.clamp(0, [@options.size - 1, 0].max)
end

#preferred_height(_width) ⇒ Object



62
63
64
# File 'lib/potty/widgets/radio_group.rb', line 62

def preferred_height(_width)
  @options.size
end

#render(window) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/potty/widgets/radio_group.rb', line 80

def render(window)
  return unless @visible && @rect

  @options.each_with_index do |opt, i|
    break if i >= @rect.height

    marker = opt[:value] == @selected ? "(\u25CF)" : "(\u25CB)"
    on_cursor = @focused && i == @cursor
    attr = on_cursor ? theme.style(:selected, bold: true) : theme.style(:normal)
    text = "#{marker} #{opt[:label]}"[0, @rect.width]

    window.setpos(@rect.y + i, @rect.x)
    window.attron(attr) { window.addstr(text) }
  end
end

#selectedObject



40
41
42
# File 'lib/potty/widgets/radio_group.rb', line 40

def selected
  @selected
end

#selected=(value) ⇒ Object



52
53
54
55
56
57
58
59
60
# File 'lib/potty/widgets/radio_group.rb', line 52

def selected=(value)
  idx = index_of(value)
  return unless idx

  @selected = value
  @cursor = idx
  @on_change&.call(@selected)
  emit(:change, @selected)
end