Class: Hiiro::Tui::ListScreen

Inherits:
Object
  • Object
show all
Includes:
Terminal
Defined in:
lib/hiiro/tui.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Terminal

#center_text, #env_dimension, #read_escape_char, #read_key, #terminal_cols, #terminal_line, #terminal_rows, #truncate, #visible_text, #with_screen

Constructor Details

#initialize(items:, empty_message: 'No items.') ⇒ ListScreen

Returns a new instance of ListScreen.



100
101
102
103
104
105
106
# File 'lib/hiiro/tui.rb', line 100

def initialize(items:, empty_message: 'No items.')
  @items = items
  @empty_message = empty_message
  @cursor = 0
  @top = 0
  @horizontal_offset = 0
end

Instance Attribute Details

#cursorObject (readonly)

Returns the value of attribute cursor.



98
99
100
# File 'lib/hiiro/tui.rb', line 98

def cursor
  @cursor
end

#horizontal_offsetObject (readonly)

Returns the value of attribute horizontal_offset.



98
99
100
# File 'lib/hiiro/tui.rb', line 98

def horizontal_offset
  @horizontal_offset
end

#itemsObject (readonly)

Returns the value of attribute items.



98
99
100
# File 'lib/hiiro/tui.rb', line 98

def items
  @items
end

#topObject (readonly)

Returns the value of attribute top.



98
99
100
# File 'lib/hiiro/tui.rb', line 98

def top
  @top
end

Instance Method Details

#body_rows_budgetObject



200
201
202
# File 'lib/hiiro/tui.rb', line 200

def body_rows_budget
  [terminal_rows - header_lines.length - footer_height, 1].max
end


172
173
174
# File 'lib/hiiro/tui.rb', line 172

def footer_height
  1
end


168
169
170
# File 'lib/hiiro/tui.rb', line 168

def footer_lines
  ["Showing #{@top + 1}-#{@top + visible_items.length} of #{items.length}"]
end

#format_row(item, current, line_cols) ⇒ Object



176
177
178
179
180
181
182
# File 'lib/hiiro/tui.rb', line 176

def format_row(item, current, line_cols)
  prefix = current ? '> ' : '  '
  style = current ? "\e[7m" : "\e[0m"
  text = (prefix + visible_text(item.to_s, [line_cols - prefix.length, 1].max, horizontal_offset)).ljust(line_cols)

  "#{style}#{text}\e[0m\e[K"
end

#handle_key(key) ⇒ Object



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/hiiro/tui.rb', line 124

def handle_key(key)
  case key
  when :up, 'k'
    move(-1)
  when :down, 'j'
    move(1)
  when :left, 'h'
    scroll_horizontal(-4)
  when :right, 'l'
    scroll_horizontal(4)
  when 'q', :escape, :ctrl_c
    return false
  end

  :continue
end

#header_linesObject



164
165
166
# File 'lib/hiiro/tui.rb', line 164

def header_lines
  []
end

#max_horizontal_offset(line_cols = nil, visible = nil) ⇒ Object



204
205
206
207
208
209
210
211
212
213
# File 'lib/hiiro/tui.rb', line 204

def max_horizontal_offset(line_cols = nil, visible = nil)
  line_cols ||= [terminal_cols - 1, 1].max
  visible ||= visible_items
  return 0 if visible.empty?

  longest_visible_item = visible.map { |item| item.to_s.length }.max || 0
  min_visible_chars = [5, line_cols].min

  [longest_visible_item - min_visible_chars, 0].max
end

#move(delta) ⇒ Object



184
185
186
187
188
189
190
# File 'lib/hiiro/tui.rb', line 184

def move(delta)
  @cursor = [[cursor + delta, 0].max, items.length - 1].min
  visible_rows = body_rows_budget
  @top = cursor if cursor < top
  @top = cursor - visible_rows + 1 if cursor >= top + visible_rows
  @horizontal_offset = [horizontal_offset, max_horizontal_offset].min
end

#renderObject



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/hiiro/tui.rb', line 141

def render
  rows = terminal_rows
  cols = terminal_cols
  line_cols = [cols - 1, 1].max
  headers = header_lines
  visible_rows = [rows - headers.length - footer_height, 1].max
  visible = items[@top, visible_rows] || []
  @horizontal_offset = [horizontal_offset, max_horizontal_offset(line_cols, visible)].min

  lines = headers.map { |line| terminal_line(line, line_cols) }
  visible.each_with_index do |item, idx|
    lines << format_row(item, @top + idx == cursor, line_cols)
  end

  (visible_rows - visible.length).times { lines << terminal_line('', line_cols) }
  footer_lines.each { |line| lines << terminal_line(line, line_cols) }

  $stdout.write("\e[H\e[2J")
  $stdout.write(lines.join("\r\n"))
  $stdout.write("\r")
  $stdout.flush
end

#runObject



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/hiiro/tui.rb', line 108

def run
  if items.empty?
    puts @empty_message
    return false
  end

  with_screen do |input|
    loop do
      render

      result = handle_key(read_key(input))
      return result unless result == :continue
    end
  end
end

#scroll_horizontal(delta) ⇒ Object



192
193
194
# File 'lib/hiiro/tui.rb', line 192

def scroll_horizontal(delta)
  @horizontal_offset = [[horizontal_offset + delta, 0].max, max_horizontal_offset].min
end

#visible_itemsObject



196
197
198
# File 'lib/hiiro/tui.rb', line 196

def visible_items
  items[top, body_rows_budget] || []
end