rkumar-rbcurse 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. data/CHANGELOG +1577 -0
  2. data/README.txt +310 -0
  3. data/examples/qdfilechooser.rb +68 -0
  4. data/examples/rfe.rb +853 -0
  5. data/examples/rfe_renderer.rb +69 -0
  6. data/examples/test1.rb +242 -0
  7. data/examples/test2.rb +498 -0
  8. data/examples/testcombo.rb +95 -0
  9. data/examples/testkeypress.rb +61 -0
  10. data/examples/testmenu.rb +105 -0
  11. data/examples/testtable.rb +266 -0
  12. data/examples/testtabp.rb +106 -0
  13. data/examples/testtodo.rb +532 -0
  14. data/examples/viewtodo.rb +512 -0
  15. data/lib/rbcurse.rb +7 -0
  16. data/lib/rbcurse/action.rb +31 -0
  17. data/lib/rbcurse/applicationheader.rb +57 -0
  18. data/lib/rbcurse/celleditor.rb +120 -0
  19. data/lib/rbcurse/checkboxcellrenderer.rb +69 -0
  20. data/lib/rbcurse/colormap.rb +133 -0
  21. data/lib/rbcurse/comboboxcellrenderer.rb +45 -0
  22. data/lib/rbcurse/defaultlistselectionmodel.rb +49 -0
  23. data/lib/rbcurse/keylabelprinter.rb +143 -0
  24. data/lib/rbcurse/listcellrenderer.rb +99 -0
  25. data/lib/rbcurse/listkeys.rb +33 -0
  26. data/lib/rbcurse/listscrollable.rb +216 -0
  27. data/lib/rbcurse/listselectable.rb +67 -0
  28. data/lib/rbcurse/mapper.rb +108 -0
  29. data/lib/rbcurse/orderedhash.rb +77 -0
  30. data/lib/rbcurse/rcombo.rb +243 -0
  31. data/lib/rbcurse/rdialogs.rb +183 -0
  32. data/lib/rbcurse/rform.rb +845 -0
  33. data/lib/rbcurse/rinputdataevent.rb +36 -0
  34. data/lib/rbcurse/rlistbox.rb +804 -0
  35. data/lib/rbcurse/rmenu.rb +666 -0
  36. data/lib/rbcurse/rmessagebox.rb +325 -0
  37. data/lib/rbcurse/rpopupmenu.rb +754 -0
  38. data/lib/rbcurse/rtabbedpane.rb +259 -0
  39. data/lib/rbcurse/rtable.rb +1296 -0
  40. data/lib/rbcurse/rtextarea.rb +673 -0
  41. data/lib/rbcurse/rtextview.rb +335 -0
  42. data/lib/rbcurse/rwidget.rb +1731 -0
  43. data/lib/rbcurse/scrollable.rb +301 -0
  44. data/lib/rbcurse/selectable.rb +94 -0
  45. data/lib/rbcurse/table/tablecellrenderer.rb +85 -0
  46. data/lib/rbcurse/table/tabledatecellrenderer.rb +102 -0
  47. data/lib/ver/keyboard.rb +150 -0
  48. data/lib/ver/keyboard2.rb +170 -0
  49. data/lib/ver/ncurses.rb +102 -0
  50. data/lib/ver/window.rb +369 -0
  51. data/test/test_rbcurse.rb +0 -0
  52. metadata +117 -0
@@ -0,0 +1,36 @@
1
+ =begin
2
+ * Name: InputDataEvent
3
+ * Description: Event created when data modified in Field or TextEdit
4
+ * Author: rkumar (arunachalesha)
5
+
6
+ --------
7
+ * Date: 2008-12-24 17:27
8
+ * License:
9
+ Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
10
+
11
+ =end
12
+ require 'rubygems'
13
+
14
+ # Event created when data modified in Field or TextEdit
15
+ # 2008-12-24 17:54
16
+ module RubyCurses
17
+ class InputDataEvent
18
+ attr_accessor :index0, :index1, :source, :type, :row, :text
19
+ def initialize index0, index1, source, type, row, text
20
+ @index0 = index0
21
+ @index1 = index1
22
+ @source = source
23
+ @type = type
24
+ @row = row
25
+ @text = text
26
+ end
27
+ def to_s
28
+ inspect
29
+ end
30
+ def inspect
31
+ ## now that textarea.to_s prints content we shouldn pass it here.
32
+ #"#{@type.to_s}, #{@source}, ind0:#{@index0}, ind1:#{@index1}, row:#{@row}, text:#{@text}"
33
+ "#{@type.to_s}, ind0:#{@index0}, ind1:#{@index1}, row:#{@row}, text:#{@text}"
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,804 @@
1
+ =begin
2
+ * Name: rlistbox: editable scrollable lists
3
+ * Description
4
+ * Author: rkumar (arunachalesha)
5
+ * Date: 2008-11-19 12:49
6
+ * License: Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
7
+ * This file started on 2009-01-13 22:18 (broken off rwidgets.rb)
8
+ TODO
9
+ =end
10
+ require 'rubygems'
11
+ require 'ncurses'
12
+ require 'logger'
13
+ require 'rbcurse'
14
+ require 'rbcurse/listcellrenderer'
15
+ require 'rbcurse/listkeys'
16
+
17
+
18
+ include Ncurses
19
+ module RubyCurses
20
+ extend self
21
+ ##
22
+ # When an event is fired by Listbox, contents are changed, then this object will be passed
23
+ # to trigger
24
+ # shamelessly plugged from a legacy language best unnamed
25
+ # type is CONTENTS_CHANGED, INTERVAL_ADDED, INTERVAL_REMOVED
26
+ class ListDataEvent
27
+ attr_accessor :index0, :index1, :source, :type
28
+ def initialize index0, index1, source, type
29
+ @index0 = index0
30
+ @index1 = index1
31
+ @source = source
32
+ @type = type
33
+ end
34
+ def to_s
35
+ "#{@type.to_s}, #{@source}, #{@index0}, #{@index1}"
36
+ end
37
+ def inspect
38
+ "#{@type.to_s}, #{@source}, #{@index0}, #{@index1}"
39
+ end
40
+ end
41
+ # http://www.java2s.com/Code/JavaAPI/javax.swing.event/ListDataEventCONTENTSCHANGED.htm
42
+ # should we extend array of will that open us to misuse
43
+ class ListDataModel
44
+ include Enumerable
45
+ include RubyCurses::EventHandler
46
+ attr_accessor :selected_index
47
+
48
+ def initialize anarray
49
+ @list = anarray.dup
50
+ end
51
+ # changd on 2009-01-14 12:28 based on ..
52
+ # http://www.ruby-forum.com/topic/175637#769030
53
+ def each(&blk)
54
+ @list.each(&blk)
55
+ end
56
+ #def each
57
+ # @list.each { |item| yield item }
58
+ #end
59
+ # not sure how to do this XXX removed on 2009-01-14 12:28
60
+ #def <=>(other)
61
+ # @list <=> other
62
+ #end
63
+ def index obj
64
+ @list.index(obj)
65
+ end
66
+ def length ; @list.length; end
67
+
68
+ def insert off0, *data
69
+ @list.insert off0, *data
70
+ lde = ListDataEvent.new(off0, off0+data.length-1, self, :INTERVAL_ADDED)
71
+ fire_handler :LIST_DATA_EVENT, lde
72
+ end
73
+ def append data
74
+ @list << data
75
+ lde = ListDataEvent.new(@list.length-1, @list.length-1, self, :INTERVAL_ADDED)
76
+ fire_handler :LIST_DATA_EVENT, lde
77
+ end
78
+ def update off0, data
79
+ @list[off0] = data
80
+ lde = ListDataEvent.new(off0, off0, self, :CONTENTS_CHANGED)
81
+ fire_handler :LIST_DATA_EVENT, lde
82
+ end
83
+ def []=(off0, data)
84
+ update off0, data
85
+ end
86
+ def [](off0)
87
+ @list[off0]
88
+ end
89
+ def delete_at off0
90
+ ret=@list.delete_at off0
91
+ lde = ListDataEvent.new(off0, off0, self, :INTERVAL_REMOVED)
92
+ fire_handler :LIST_DATA_EVENT, lde
93
+ return ret
94
+ end
95
+ def remove_all
96
+ lde = ListDataEvent.new(0, @list.size, self, :INTERVAL_REMOVED)
97
+ @list = []
98
+ fire_handler :LIST_DATA_EVENT, lde
99
+ end
100
+ def delete obj
101
+ off0 = @list.index obj
102
+ return nil if off0.nil?
103
+ ret=@list.delete off0
104
+ lde = ListDataEvent.new(off0, off0, self, :INTERVAL_REMOVED)
105
+ fire_handler :LIST_DATA_EVENT, lde
106
+ return ret
107
+ end
108
+ def include?(obj)
109
+ return @list.include?(obj)
110
+ end
111
+ def values
112
+ @list.dup
113
+ end
114
+ def on_enter_row object
115
+ $log.debug " XXX on_enter_row of list_data"
116
+ fire_handler :ENTER_ROW, object
117
+ end
118
+ # ##
119
+ # added 2009-01-14 01:00
120
+ # searches between given range of rows (def 0 and end)
121
+ # returns row index of first match of given regex (or nil if not found)
122
+ def find_match regex, ix0=0, ix1=length()
123
+ $log.debug " find_match got #{regex} #{ix0} #{ix1}"
124
+ @last_regex = regex
125
+ @search_start_ix = ix0
126
+ @search_end_ix = ix1
127
+ #@search_found_ix = nil
128
+ @list.each_with_index do |row, ix|
129
+ next if ix < ix0
130
+ break if ix > ix1
131
+ if !row.match(regex).nil?
132
+ @search_found_ix = ix
133
+ return ix
134
+ end
135
+ end
136
+ return nil
137
+ end
138
+ ##
139
+ # continues previous search
140
+ def find_next
141
+ raise "No previous search" if @last_regex.nil?
142
+ start = @search_found_ix && @search_found_ix+1 || 0
143
+ return find_match @last_regex, start, @search_end_ix
144
+ end
145
+ ##
146
+ # find backwards
147
+ # Using this to start a search or continue search
148
+ def find_prev regex=@last_regex, start = @search_found_ix
149
+ raise "No previous search" if @last_regex.nil?
150
+ $log.debug " find_prev #{@search_found_ix} : #{@current_index}"
151
+ start -= 1 unless start == 0
152
+ @last_regex = regex
153
+ @search_start_ix = start
154
+ start.downto(0) do |ix|
155
+ row = @list[ix]
156
+ if !row.match(regex).nil?
157
+ @search_found_ix = ix
158
+ return ix
159
+ end
160
+ end
161
+ return nil
162
+ #return find_match @last_regex, start, @search_end_ix
163
+ end
164
+
165
+ alias :to_array :values
166
+ end # class ListDataModel
167
+ ##
168
+ # scrollable, selectable list of items
169
+ # TODO Add events for item add/remove and selection change
170
+ # added event LIST_COMBO_SELECT fired whenever a select/deselect is done.
171
+ # - I do not know how this works in Tk so only the name is copied..
172
+ # - @selected contains indices of selected objects.
173
+ # - currently the first argument of event is row (the row selected/deselected). Should it
174
+ # be the object.
175
+ # - this event could change when range selection is allowed.
176
+ #
177
+
178
+ ##
179
+ # pops up a list of values for selection
180
+ # 2008-12-10
181
+ class PopupList
182
+ include DSL
183
+ include RubyCurses::EventHandler
184
+ dsl_accessor :title
185
+ dsl_accessor :row, :col, :height, :width
186
+ dsl_accessor :layout
187
+ attr_reader :config
188
+ attr_reader :selected_index # button index selected by user
189
+ attr_reader :window # required for keyboard
190
+ dsl_accessor :list_selection_mode # true or false allow multiple selection
191
+ dsl_accessor :relative_to # a widget, if given row and col are relative to widgets windows
192
+ # layout
193
+ dsl_accessor :max_visible_items # how many to display
194
+ dsl_accessor :list_config # hash with values for the list to use
195
+ dsl_accessor :valign
196
+ attr_reader :listbox
197
+
198
+ def initialize aconfig={}, &block
199
+ @config = aconfig
200
+ @selected_index = -1
201
+ @list_config ||= {}
202
+ @config.each_pair { |k,v| instance_variable_set("@#{k}",v) }
203
+ instance_eval &block if block_given?
204
+ @list_config.each_pair { |k,v| instance_variable_set("@#{k}",v) }
205
+ @height ||= [@max_visible_items || 10, @list.length].min
206
+ #$log.debug " POPUP XXX #{@max_visible_items} ll:#{@list.length} h:#{@height}"
207
+ # get widgets absolute coords
208
+ if !@relative_to.nil?
209
+ layout = @relative_to.form.window.layout
210
+ @row = @row + layout[:top]
211
+ @col = @col + layout[:left]
212
+ end
213
+ if !@valign.nil?
214
+ case @valign.to_sym
215
+ when :BELOW
216
+ @row += 1
217
+ when :ABOVE
218
+ @row -= @height+1
219
+ @row = 0 if @row < 0
220
+ when :CENTER
221
+ @row -= @height/2
222
+ @row = 0 if @row < 0
223
+ else
224
+ end
225
+ end
226
+
227
+ layout(1+height, @width+4, @row, @col) # changed 2 to 1, 2008-12-17 13:48
228
+ @window = VER::Window.new(@layout)
229
+ @form = RubyCurses::Form.new @window
230
+ @window.bkgd(Ncurses.COLOR_PAIR($reversecolor));
231
+ #@window.attron(Ncurses.COLOR_PAIR($reversecolor));
232
+ #@window.wclear
233
+ #@window.attroff(Ncurses.COLOR_PAIR($reversecolor));
234
+ @window.wrefresh
235
+ @panel = @window.panel # useless line ?
236
+ Ncurses::Panel.update_panels
237
+ # @message_row = @message_col = 2
238
+ # print_borders
239
+ # print_title
240
+ print_input # creates the listbox
241
+ @form.repaint
242
+ @window.wrefresh
243
+ handle_keys
244
+ end
245
+ def list alist=nil
246
+ return @list if alist.nil?
247
+ @list = ListDataModel.new(alist)
248
+ # will we need this ? listbox made each time so data should be fresh
249
+ #@list.bind(:LIST_DATA_EVENT) { |e| list_data_changed() }
250
+ end
251
+ def list_data_model ldm
252
+ raise "Expecting list_data_model" unless ldm.is_a? RubyCurses::ListDataModel
253
+ @list = ldm
254
+ # will we need this ? listbox made each time so data should be fresh
255
+ #@list.bind(:LIST_DATA_EVENT) { |e| list_data_changed() }
256
+ end
257
+ ##
258
+ def input_value
259
+ #return @listbox.getvalue if !@listbox.nil?
260
+ return @listbox.focussed_index if !@listbox.nil?
261
+ end
262
+ ## popuplist
263
+ def stopping?
264
+ @stop
265
+ end
266
+ ## popuplist
267
+ def handle_keys
268
+ begin
269
+ while((ch = @window.getchar()) != 999 )
270
+ case ch
271
+ when -1
272
+ next
273
+ else
274
+ press ch
275
+ break if @stop
276
+ end
277
+ end
278
+ ensure
279
+ destroy
280
+ end
281
+ return 0 #@selected_index
282
+ end
283
+ ##
284
+ # TODO get next match for key
285
+ def press ch
286
+ $log.debug "popup handle_keys : #{ch}" if ch != -1
287
+ case ch
288
+ when -1
289
+ return
290
+ when KEY_F1, 27, ?\C-q # 27/ESC does not come here since gobbled by keyboard.rb
291
+ @stop = true
292
+ return
293
+ when KEY_ENTER, 10, 13
294
+ fire_handler :PRESS, @listbox.focussed_index
295
+ # since Listbox is handling enter, COMBO_SELECT will not be fired
296
+ # $log.debug "popup ENTER : #{@selected_index} "
297
+ # $log.debug "popup ENTER : #{field.name}" if !field.nil?
298
+ @stop = true
299
+ return
300
+ when 9
301
+ @form.select_next_field
302
+ else
303
+ # fields must return unhandled else we will miss hotkeys.
304
+ # On messageboxes, often if no edit field, then O and C are hot.
305
+ field = @form.get_current_field
306
+ handled = field.handle_key ch
307
+
308
+ if handled == :UNHANDLED
309
+ @stop = true
310
+ return
311
+ end
312
+ end
313
+ @form.repaint
314
+ Ncurses::Panel.update_panels();
315
+ Ncurses.doupdate();
316
+ @window.wrefresh
317
+ end
318
+ def print_input
319
+ r = c = 0
320
+ width = @layout[:width]
321
+ height = @layout[:height]
322
+ height = @height
323
+ parent = @relative_to
324
+ defaultvalue = @default_value || ""
325
+ list = @list
326
+ selection_mode = @list_selection_mode
327
+ default_values = @default_values
328
+ @list_config['color'] ||= 'black'
329
+ @list_config['bgcolor'] ||= 'yellow'
330
+ @listbox = RubyCurses::Listbox.new @form, @list_config do
331
+ name "input"
332
+ row r
333
+ col c
334
+ # attr 'reverse'
335
+ width width
336
+ height height
337
+ list_data_model list
338
+ # ?? XXX display_length 30
339
+ # set_buffer defaultvalue
340
+ selection_mode selection_mode
341
+ default_values default_values
342
+ is_popup true
343
+ #add_observer parent
344
+
345
+ end
346
+ end
347
+ # may need to be upgraded to new one XXX FIXME
348
+ def configure(*val , &block)
349
+ case val.size
350
+ when 1
351
+ return @config[val[0]]
352
+ when 2
353
+ @config[val[0]] = val[1]
354
+ instance_variable_set("@#{val[0]}", val[1])
355
+ end
356
+ instance_eval &block if block_given?
357
+ end
358
+ def cget param
359
+ @config[param]
360
+ end
361
+
362
+ def layout(height=0, width=0, top=0, left=0)
363
+ @layout = { :height => height, :width => width, :top => top, :left => left }
364
+ end
365
+ def destroy
366
+ @window.destroy if !@window.nil?
367
+ end
368
+ end # class PopupList
369
+ ##
370
+ # this is the new LISTBOX, based on new scrollable.
371
+ #
372
+ class Listbox < Widget
373
+ require 'rbcurse/listscrollable'
374
+ require 'rbcurse/listselectable'
375
+ require 'rbcurse/defaultlistselectionmodel'
376
+ require 'rbcurse/celleditor'
377
+ include ListScrollable
378
+ include ListSelectable
379
+ include RubyCurses::ListKeys
380
+ dsl_accessor :height
381
+ dsl_accessor :title
382
+ dsl_property :title_attrib # bold, reverse, normal
383
+ # dsl_accessor :list # the array of data to be sent by user
384
+ attr_reader :toprow
385
+ # attr_reader :prow
386
+ # attr_reader :winrow
387
+ # dsl_accessor :selection_mode # allow multiple select or not
388
+ # dsl_accessor :list_variable # a variable values are shown from this
389
+ dsl_accessor :default_values # array of default values
390
+ dsl_accessor :is_popup # if it is in a popup and single select, selection closes
391
+ attr_accessor :current_index
392
+ #dsl_accessor :cell_renderer
393
+ dsl_accessor :selected_color, :selected_bgcolor, :selected_attr
394
+ dsl_accessor :max_visible_items # how many to display 2009-01-11 16:15
395
+ dsl_accessor :cell_editing_allowed
396
+ dsl_property :show_selector
397
+ dsl_property :row_selected_symbol # 2009-01-12 12:01 changed from selector to selected
398
+ dsl_property :row_unselected_symbol # added 2009-01-12 12:00
399
+ dsl_property :left_margin
400
+ # please set these in he constructor block. Settin them later will have no effect
401
+ # since i would have bound them to actions
402
+ dsl_accessor :KEY_ROW_SELECTOR
403
+ dsl_accessor :KEY_GOTO_TOP
404
+ dsl_accessor :KEY_GOTO_BOTTOM
405
+ dsl_accessor :KEY_CLEAR_SELECTION
406
+ dsl_accessor :KEY_NEXT_SELECTION
407
+ dsl_accessor :KEY_PREV_SELECTION
408
+ dsl_accessor :valign # 2009-01-17 18:32
409
+
410
+ def initialize form, config={}, &block
411
+ @focusable = true
412
+ @editable = false
413
+ @row = 0
414
+ @col = 0
415
+ # data of listbox
416
+ @list = []
417
+ # any special attribs such as status to be printed in col1, or color (selection)
418
+ @list_attribs = {}
419
+ super
420
+ @current_index ||= 0
421
+ @row_offset = @col_offset = 1
422
+ @content_rows = @list.length
423
+ @selection_mode ||= 'multiple'
424
+ @win = @form.window
425
+ print_borders unless @win.nil? # in messagebox we don;t have window as yet!
426
+ # next 2 lines carry a redundancy
427
+ select_default_values
428
+ # when the combo box has a certain row in focus, the popup should have the same row in focus
429
+
430
+ init_vars
431
+ install_list_keys
432
+
433
+ if !@list.selected_index.nil?
434
+ set_focus_on @list.selected_index # the new version
435
+ end
436
+ end
437
+ def init_vars
438
+ @to_print_borders ||= 1
439
+ @repaint_required = true
440
+ @toprow = @pcol = 0
441
+ if @show_selector
442
+ @row_selected_symbol ||= '>'
443
+ @row_unselected_symbol ||= ' '
444
+ @left_margin ||= @row_selected_symbol.length
445
+ end
446
+ @left_margin ||= 0
447
+ end
448
+ def install_bindings
449
+
450
+ end
451
+
452
+ ##
453
+ # getter and setter for selection_mode
454
+ # Must be called after creating model, so no duplicate. Since one may set in model directly.
455
+ def selection_mode(*val)
456
+ raise "ListSelectionModel not yet created!" if @list_selection_model.nil?
457
+ if val.empty?
458
+ @list_selection_model.selection_mode
459
+ else
460
+ @list_selection_model.selection_mode = val[0]
461
+ end
462
+ end
463
+ def row_count
464
+ @list.length
465
+ end
466
+ # added 2009-01-07 13:05 so new scrollable can use
467
+ def scrollatrow
468
+ @height - 2
469
+ end
470
+ def list alist=nil
471
+ return @list if alist.nil?
472
+ @list = RubyCurses::ListDataModel.new(alist)
473
+ # added on 2009-01-13 23:19 since updates are not automatic now
474
+ @list.bind(:LIST_DATA_EVENT) { |e| list_data_changed() }
475
+ create_default_list_selection_model
476
+ end
477
+ def list_variable alist=nil
478
+ return @list if alist.nil?
479
+ @list = RubyCurses::ListDataModel.new(alist.value)
480
+ # added on 2009-01-13 23:19 since updates are not automatic now
481
+ @list.bind(:LIST_DATA_EVENT) { |e| list_data_changed() }
482
+ create_default_list_selection_model
483
+ end
484
+ def list_data_model ldm=nil
485
+ return @list if ldm.nil?
486
+ raise "Expecting list_data_model" unless ldm.is_a? RubyCurses::ListDataModel
487
+ @list = ldm
488
+ # added on 2009-01-13 23:19 since updates are not automatic now
489
+ @list.bind(:LIST_DATA_EVENT) { |e| list_data_changed() }
490
+ create_default_list_selection_model
491
+ end
492
+
493
+ def select_default_values
494
+ return if @default_values.nil?
495
+ @default_values.each do |val|
496
+ row = @list.index val
497
+ #do_select(row) unless row.nil?
498
+ add_row_selection_interval row, row unless row.nil?
499
+ end
500
+ end
501
+ def print_borders
502
+ width = @width
503
+ height = @height
504
+ window = @form.window
505
+ startcol = @col
506
+ startrow = @row
507
+ @color_pair = get_color($datacolor)
508
+ window.print_border startrow, startcol, height, width, @color_pair, @attr
509
+ print_title
510
+ end
511
+ def print_title
512
+ printstring(@form.window, @row, @col+(@width-@title.length)/2, @title, @color_pair, @title_attrib) unless @title.nil?
513
+ end
514
+ ### START FOR scrollable ###
515
+ def get_content
516
+ #@list 2008-12-01 23:13
517
+ @list_variable && @list_variable.value || @list
518
+ end
519
+ def get_window
520
+ @form.window
521
+ end
522
+ ### END FOR scrollable ###
523
+ # override widgets text
524
+ def getvalue
525
+ selected_rows
526
+ end
527
+ # Listbox
528
+ def handle_key(ch)
529
+ @current_index ||= 0
530
+ @toprow ||= 0
531
+ h = scrollatrow()
532
+ rc = row_count
533
+ $log.debug " listbxo got ch #{ch}"
534
+ $log.debug " when kps #{@KEY_PREV_SELECTION} "
535
+ case ch
536
+ when KEY_UP # show previous value
537
+ previous_row
538
+ when KEY_DOWN # show previous value
539
+ next_row
540
+ when @KEY_ROW_SELECTOR # 32:
541
+ return if is_popup and @selection_mode == 'single' # not allowing select this way since there will be a difference
542
+ toggle_row_selection @current_index #, @current_index
543
+ @repaint_required = true
544
+ when @KEY_SCROLL_FORWARD # ?\C-n:
545
+ scroll_forward
546
+ when @KEY_SCROLL_BACKWARD # ?\C-p:
547
+ scroll_backward
548
+ when @KEY_GOTO_TOP # 48, ?\C-[:
549
+ # please note that C-[ gives 27, same as esc so will respond after ages
550
+ goto_top
551
+ when @KEY_GOTO_BOTTOM # ?\C-]:
552
+ goto_bottom
553
+ when @KEY_NEXT_SELECTION # ?'
554
+ $log.debug "insdie next selection"
555
+ @oldrow = @current_index
556
+ do_next_selection #if @select_mode == 'multiple'
557
+ bounds_check
558
+ when @KEY_PREV_SELECTION # ?"
559
+ @oldrow = @current_index
560
+ $log.debug "insdie prev selection"
561
+ do_prev_selection #if @select_mode == 'multiple'
562
+ bounds_check
563
+ when @KEY_CLEAR_SELECTION
564
+ clear_selection #if @select_mode == 'multiple'
565
+ @repaint_required = true
566
+ when 27, ?\C-c:
567
+ editing_canceled @current_index if @cell_editing_allowed
568
+ when @KEY_ASK_FIND_FORWARD
569
+ ask_search_forward
570
+ when @KEY_ASK_FIND_BACKWARD
571
+ ask_search_backward
572
+ when @KEY_FIND_NEXT
573
+ find_next
574
+ when @KEY_FIND_PREV
575
+ find_prev
576
+ else
577
+ # this has to be fixed, if compo does not handle key it has to continue into next part FIXME
578
+ ret = :UNHANDLED # changed on 2009-01-27 13:14 not going into unhandled, tab not released
579
+ if @cell_editing_allowed
580
+ @repaint_required = true
581
+ # hack - on_enter_row should fire when this widget gets focus. first row that is DONE
582
+ begin
583
+ ret = @cell_editor.component.handle_key(ch)
584
+ rescue
585
+ on_enter_row @current_index
586
+ ret = @cell_editor.component.handle_key(ch)
587
+ end
588
+ end
589
+ if ret == :UNHANDLED
590
+ case ch
591
+ when ?A..?Z, ?a..?z
592
+ ret = set_selection_for_char ch.chr
593
+ else
594
+ ret = process_key ch, self
595
+ return :UNHANDLED if ret == :UNHANDLED
596
+ end
597
+ end
598
+ end
599
+ end
600
+ def ask_search_forward
601
+ regex = get_string("Enter regex to search")
602
+ ix = @list.find_match regex
603
+ if ix.nil?
604
+ alert("No matching data for: #{regex}")
605
+ else
606
+ set_focus_on(ix)
607
+ end
608
+ end
609
+ def ask_search_backward
610
+ regex = get_string("Enter regex to search (backward)")
611
+ ix = @list.find_prev regex, @current_index
612
+ if ix.nil?
613
+ alert("No matching data for: #{regex}")
614
+ else
615
+ set_focus_on(ix)
616
+ end
617
+ end
618
+ def find_prev
619
+ ix = @list.find_prev
620
+ regex = @last_regex
621
+ if ix.nil?
622
+ alert("No previous matching data for: #{regex}")
623
+ else
624
+ @oldrow = @current_index
625
+ @current_index = ix
626
+ bounds_check
627
+ end
628
+ end
629
+ # table find_next
630
+ def find_next
631
+ ix = @list.find_next
632
+ regex = @last_regex
633
+ if ix.nil?
634
+ alert("No more matching data for: #{regex}")
635
+ else
636
+ set_focus_on(ix) unless ix.nil?
637
+ end
638
+ end
639
+ def on_enter
640
+ on_enter_row @current_index
641
+ set_form_row # added 2009-01-11 23:41
642
+ $log.debug " ONE ENTER LIST #{@current_index}, #{@form.row}"
643
+ @repaint_required
644
+ fire_handler :ENTER, self
645
+ end
646
+ def on_enter_row arow
647
+ $log.debug " Listbox #{self} ENTER_ROW with curr #{@current_index}. row: #{arow} H: #{@handler.keys}"
648
+ #fire_handler :ENTER_ROW, arow
649
+ fire_handler :ENTER_ROW, self
650
+ @list.on_enter_row self
651
+ edit_row_at arow
652
+ @repaint_required = true
653
+ end
654
+ def edit_row_at arow
655
+ if @cell_editing_allowed
656
+ #$log.debug " cell editor on enter #{arow} val of list[row]: #{@list[arow]}"
657
+ editor = cell_editor
658
+ prepare_editor editor, arow
659
+ end
660
+ end
661
+ ##
662
+ # private
663
+ def prepare_editor editor, row
664
+ r,c = rowcol
665
+ value = @list[row] # .chomp
666
+ value = value.dup rescue value # so we can cancel
667
+ row = r + (row - @toprow) # @form.row
668
+ col = c+@left_margin # @form.col
669
+ # unfortunately 2009-01-11 19:47 combo boxes editable allows changing value
670
+ editor.prepare_editor self, row, col, value
671
+ set_form_col @left_margin
672
+
673
+ # set original value so we can cancel
674
+ # set row and col,
675
+ # set value and other things, color and bgcolor
676
+ end
677
+ def on_leave_row arow
678
+ #$log.debug " Listbox #{self} leave with (cr: #{@current_index}) #{arow}: list[row]:#{@list[arow]}"
679
+ $log.debug " Listbox #{self} leave with (cr: #{@current_index}) #{arow}: "
680
+ #fire_handler :LEAVE_ROW, arow
681
+ fire_handler :LEAVE_ROW, self
682
+ editing_completed arow
683
+ end
684
+ def editing_completed arow
685
+ if @cell_editing_allowed
686
+ if !@cell_editor.nil?
687
+ # $log.debug " cell editor (leave) setting value row: #{arow} val: #{@cell_editor.getvalue}"
688
+ @list[arow] = @cell_editor.getvalue #.dup 2009-01-10 21:42 boolean can't duplicate
689
+ else
690
+ $log.debug "CELL EDITOR WAS NIL, #{arow} "
691
+ end
692
+ end
693
+ @repaint_required = true
694
+ end
695
+ def editing_canceled arow=@current_index
696
+ return unless @cell_editing_allowed
697
+ prepare_editor @cell_editor, arow
698
+ @repaint_required = true
699
+ end
700
+
701
+ ##
702
+ # getter and setter for cell_editor
703
+ def cell_editor(*val)
704
+ if val.empty?
705
+ @cell_editor ||= create_default_cell_editor
706
+ else
707
+ @cell_editor = val[0]
708
+ end
709
+ end
710
+ def create_default_cell_editor
711
+ return RubyCurses::CellEditor.new RubyCurses::Field.new nil, {"focusable"=>false, "visible"=>false, "display_length"=> @width-2-@left_margin}
712
+ end
713
+ ##
714
+ # getter and setter for cell_renderer
715
+ def cell_renderer(*val)
716
+ if val.empty?
717
+ @cell_renderer ||= create_default_cell_renderer
718
+ else
719
+ @cell_renderer = val[0]
720
+ end
721
+ end
722
+ def create_default_cell_renderer
723
+ return RubyCurses::ListCellRenderer.new "", {"color"=>@color, "bgcolor"=>@bgcolor, "parent" => self, "display_length"=> @width-2-@left_margin}
724
+ end
725
+ ##
726
+ # this method chops the data to length before giving it to the
727
+ # renderer, this can cause problems if the renderer does some
728
+ # processing. also, it pans the data horizontally giving the renderer
729
+ # a section of it.
730
+ def repaint
731
+ return unless @repaint_required
732
+ print_borders if @to_print_borders == 1 # do this once only, unless everything changes
733
+ rc = row_count
734
+ maxlen = @maxlen ||= @width-2
735
+ tm = list()
736
+ tr = @toprow
737
+ acolor = get_color $datacolor
738
+ h = scrollatrow()
739
+ r,c = rowcol
740
+ 0.upto(h) do |hh|
741
+ crow = tr+hh
742
+ if crow < rc
743
+ focussed = @current_index == crow ? true : false
744
+ selected = is_row_selected crow
745
+ content = tm[crow] # 2009-01-17 18:37 chomp giving error in some cases says frozen
746
+ if content.is_a? String
747
+ content = content.dup
748
+ content.chomp!
749
+ content.gsub!(/\t/, ' ') # don't display tab
750
+ content.gsub!(/[^[:print:]]/, '') # don't display non print characters
751
+ if !content.nil?
752
+ if content.length > maxlen # only show maxlen
753
+ content = content[@pcol..@pcol+maxlen-1]
754
+ else
755
+ content = content[@pcol..-1]
756
+ end
757
+ end
758
+ elsif content.is_a? TrueClass or content.is_a? FalseClass
759
+ else
760
+ content = content.to_s
761
+ end
762
+ ## set the selector symbol if requested
763
+ selection_symbol = ''
764
+ if @show_selector
765
+ if selected
766
+ selection_symbol = @row_selected_symbol
767
+ else
768
+ selection_symbol = @row_unselected_symbol
769
+ end
770
+ @form.window.printstring r+hh, c, selection_symbol, acolor,@attr
771
+ end
772
+ #renderer = get_default_cell_renderer_for_class content.class.to_s
773
+ renderer = cell_renderer()
774
+ #renderer.show_selector @show_selector
775
+ #renderer.row_selected_symbol @row_selected_symbol
776
+ #renderer.left_margin @left_margin
777
+ #renderer.repaint @form.window, r+hh, c+(colix*11), content, focussed, selected
778
+ ## added crow on 2009-02-06 23:03
779
+ # since data is being truncated and renderer may need index
780
+ renderer.repaint @form.window, r+hh, c+@left_margin, crow, content, focussed, selected
781
+ else
782
+ # clear rows
783
+ @form.window.printstring r+hh, c, " " * (@width-2), acolor,@attr
784
+ end
785
+ end
786
+ if @cell_editing_allowed
787
+ @cell_editor.component.repaint unless @cell_editor.nil? or @cell_editor.component.form.nil?
788
+ end
789
+ @table_changed = false
790
+ @repaint_required = false
791
+ end
792
+ def list_data_changed
793
+ if row_count == 0 # added on 2009-02-02 17:13 so cursor not hanging on last row which could be empty
794
+ init_vars
795
+ @current_index = 0
796
+ set_form_row
797
+ end
798
+ @repaint_required = true
799
+ end
800
+
801
+ end # class listb
802
+
803
+
804
+ end # module