Class: UI::ListWidget

Inherits:
Window show all
Defined in:
lib/ektoplayer/ui/widgets/listwidget.rb

Instance Attribute Summary collapse

Attributes inherited from Window

#win

Attributes inherited from Widget

#pos, #size

Instance Method Summary collapse

Methods inherited from Window

#noutrefresh, #refresh

Methods inherited from Widget

#display, #events, #invisible!, #invisible?, #key_press, #keys, #lock, #mouse, #mouse_click, #mouse_event_transform, #mouse_section, #on_key_press, #on_widget_raise, #raise_widget, #refresh, #sub, #unlock, #visible!, #visible=, #visible?, #want_layout, #want_redraw, #want_refresh, #with_lock

Constructor Details

#initialize(list: [], item_renderer: nil, **opts) ⇒ ListWidget

Returns a new instance of ListWidget.



89
90
91
92
93
94
95
96
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 89

def initialize(list: [], item_renderer: nil, **opts)
   super(**opts)
   self.list=(list)
   @item_renderer = (item_renderer or ListItemRenderer.new)
   @cursor = @selected = 0
   @search = ListSearch.new
   @selection = ListSelector.new
end

Instance Attribute Details

#cursorObject (readonly)

Returns the value of attribute cursor.



86
87
88
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 86

def cursor
  @cursor
end

#item_rendererObject

Returns the value of attribute item_renderer.



87
88
89
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 87

def item_renderer
  @item_renderer
end

#listObject

Returns the value of attribute list.



86
87
88
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 86

def list
  @list
end

#selectedObject

Returns the value of attribute selected.



86
87
88
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 86

def selected
  @selected
end

#selectionObject (readonly)

Returns the value of attribute selection.



86
87
88
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 86

def selection
  @selection
end

Instance Method Details

#bottomObject



154
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 154

def bottom;      self.selected=(index_last)                 end

#centerObject



159
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 159

def center;      self.force_cursorpos(@size.height / 2)     end

#down(n = 1) ⇒ Object



158
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 158

def down(n=1)    self.selected=(selected + n)               end

#drawObject



341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 341

def draw
   @win.erase
   return if @list.empty?
   @selected = @selected.clamp(0, index_last)
   #_check

   @cursor.times do |i|
      unless row = @list[@selected - (@cursor - i)]
         @cursor = i
         break
      end

      write_at(i); render(@selected - (@cursor - i))
   end

   #_check
   write_at(@cursor); render(@selected, selected: true)

   (@cursor + 1).upto(@size.height - 1).each_with_index do |c, i|
      break unless row = @list[@selected + i + 1]
      write_at(c); render(@selected + i + 1)
   end

   #_check
end

#force_cursorpos(new_cursor) ⇒ Object



257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 257

def force_cursorpos(new_cursor)
   self.lock
   if @selected <= cursor_max
      @cursor = @selected
   elsif (diff = (index_last - @selected)) < cursor_max
      @cursor = @size.height - diff - 1  #cursor_max.clamp(0, index_last - @selected)
   else
      @cursor = new_cursor.clamp(0, cursor_max)
   end
   want_redraw
   self.unlock
end

#get_selectionObject



123
124
125
126
127
128
129
130
131
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 123

def get_selection
   self.lock
   r = @selection.stop(@selected)
   r << @selected if r.empty?
   r
ensure
   want_redraw
   self.unlock
end

#layoutObject



148
149
150
151
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 148

def layout
   @item_renderer.width = @size.width if @item_renderer
   super
end

#on_mouse_click(mevent, mevent_transformed) ⇒ Object



367
368
369
370
371
372
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 367

def on_mouse_click(mevent, mevent_transformed)
   if new_mouse = mouse_event_transform(mevent)
      select_from_cursorpos(new_mouse.y)
   end
   super(mevent)
end

#page_downObject



156
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 156

def page_down;   self.scroll_down(size.height)              end

#page_upObject



155
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 155

def page_up;     self.scroll_up(size.height)                end

#render(index, **opts) ⇒ Object



133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 133

def render(index, **opts)
   return unless @item_renderer
   return Ektoplayer::Application.log(self, 'render todo') unless @list[index]

   opts[:selection] = (@selection.started? and (
         opts[:selected] or index.between?(
            [@selection.start_pos, @selected].min,
            [@selection.start_pos, @selected].max
         )
      )
   )

   @item_renderer.render(@win, @list[index], index, **opts)
end

#scroll_down(n = 1) ⇒ Object



305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 305

def scroll_down(n=1)
   fail ArgumentError unless n
   n = n.clamp(0, items_after_cursor)
   return if n == 0 or @list.empty?
   self.lock

   if index_bottom == index_last
      select_from_cursorpos((@cursor + n).clamp(0, cursor_max))
      #_check
   elsif n < @size.height
      old_index_bottom = index_bottom
      old_selected, @selected = @selected, @selected + n

      if lines_before_cursor > n
         write_at(@cursor); render(old_selected)
      end

      (old_index_bottom + 1).upto(old_index_bottom + n).each do |index|
         @win.append_bottom; render(index)
      end

      write_at(@cursor); render(@selected, selected: true)

      #_check
      want_refresh
   else
      @selected += n
      force_cursorpos(@cursor)
      #_check
      want_redraw
   end

   self.unlock
   #_check
end

#scroll_up(n = 1) ⇒ Object



270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 270

def scroll_up(n=1)
   fail ArgumentError unless n
   n = n.clamp(0, items_before_cursor)
   return if n == 0 or @list.empty?
   self.lock

   if index_top == 0
      # list is already on top
      select_from_cursorpos((@cursor - n).clamp(0, cursor_max))
   elsif n < @size.height
      old_index_top = index_top
      old_selected, @selected = @selected, @selected - n

      if lines_after_cursor > n
         write_at(@cursor); render(old_selected) 
      end

      (old_index_top - 1).downto(old_index_top - n).each do |index|
         @win.insert_top; render(index)
      end

      write_at(@cursor); render(@selected, selected: true)

      #_check
      want_refresh
   else
      @selected -= n # TODO: move up?
      force_cursorpos(@cursor)
      #_check # todo: move up
      want_redraw
   end

   self.unlock
end

#search_downObject



101
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 101

def search_down;  self.search_start(:down)                        end

#search_nextObject



98
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 98

def search_next;  self.selected=(@search.next(@selected, @list))  end

#search_prevObject



99
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 99

def search_prev;  self.selected=(@search.prev(@selected, @list))  end

#search_start(direction) ⇒ Object



102
103
104
105
106
107
108
109
110
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 102

def search_start(direction)
   UI::Input.readline(@pos, @size.update(height: 1), prompt: '> ', add_hist: true) do |result|
      if result
         @search.direction=(direction)
         @search.search=(result)
         search_next
      end
   end
end

#search_upObject



100
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 100

def search_up;    self.search_start(:up)                          end

#select_from_cursorpos(new_cursor) ⇒ Object

select an item by its current cursor pos



237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 237

def select_from_cursorpos(new_cursor)
   fail unless new_cursor.between?(0, cursor_max)
   # FIXME: clamp with @list.size ????
   return if (new_cursor == @cursor) or @list.empty?

   with_lock do
      old_cursor, @cursor = @cursor, new_cursor
      old_selected, @selected = @selected, (@selected - (old_cursor - @cursor)).clamp(0, index_last)
      #_check

      if @selection.started?
         want_redraw
      else
         write_at(old_cursor); render(old_selected)
         write_at(new_cursor); render(@selected, selected: true)
         want_refresh
      end
   end
end

#toggle_selectionObject



112
113
114
115
116
117
118
119
120
121
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 112

def toggle_selection
   with_lock do
      if @selection.started?
         @selection.stop(@selected)
         want_redraw
      else
         @selection.start(@selected)
      end
   end
end

#topObject



153
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 153

def top;         self.selected=(0)                          end

#up(n = 1) ⇒ Object



157
# File 'lib/ektoplayer/ui/widgets/listwidget.rb', line 157

def up(n=1)      self.selected=(selected - n)               end