rbcurse-core 0.0.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 (94) hide show
  1. data/README.md +69 -0
  2. data/VERSION +1 -0
  3. data/examples/abasiclist.rb +151 -0
  4. data/examples/alpmenu.rb +46 -0
  5. data/examples/app.sample +17 -0
  6. data/examples/atree.rb +100 -0
  7. data/examples/common/file.rb +45 -0
  8. data/examples/data/README.markdown +9 -0
  9. data/examples/data/brew.txt +38 -0
  10. data/examples/data/color.2 +37 -0
  11. data/examples/data/gemlist.txt +60 -0
  12. data/examples/data/lotr.txt +12 -0
  13. data/examples/data/ports.txt +136 -0
  14. data/examples/data/table.txt +37 -0
  15. data/examples/data/tasks.csv +88 -0
  16. data/examples/data/tasks.txt +27 -0
  17. data/examples/data/todo.txt +10 -0
  18. data/examples/data/todocsv.csv +28 -0
  19. data/examples/data/unix1.txt +21 -0
  20. data/examples/data/unix2.txt +11 -0
  21. data/examples/dbdemo.rb +487 -0
  22. data/examples/dirtree.rb +90 -0
  23. data/examples/newtabbedwindow.rb +100 -0
  24. data/examples/newtesttabp.rb +92 -0
  25. data/examples/tabular.rb +132 -0
  26. data/examples/tasks.rb +167 -0
  27. data/examples/term2.rb +83 -0
  28. data/examples/testkeypress.rb +72 -0
  29. data/examples/testlistbox.rb +158 -0
  30. data/examples/testmessagebox.rb +140 -0
  31. data/examples/testree.rb +106 -0
  32. data/examples/testwsshortcuts.rb +66 -0
  33. data/examples/testwsshortcuts2.rb +127 -0
  34. data/lib/rbcurse.rb +8 -0
  35. data/lib/rbcurse/core/docs/index.txt +73 -0
  36. data/lib/rbcurse/core/include/action.rb +40 -0
  37. data/lib/rbcurse/core/include/appmethods.rb +112 -0
  38. data/lib/rbcurse/core/include/bordertitle.rb +41 -0
  39. data/lib/rbcurse/core/include/chunk.rb +182 -0
  40. data/lib/rbcurse/core/include/io.rb +953 -0
  41. data/lib/rbcurse/core/include/listcellrenderer.rb +140 -0
  42. data/lib/rbcurse/core/include/listeditable.rb +317 -0
  43. data/lib/rbcurse/core/include/listscrollable.rb +590 -0
  44. data/lib/rbcurse/core/include/listselectable.rb +264 -0
  45. data/lib/rbcurse/core/include/multibuffer.rb +83 -0
  46. data/lib/rbcurse/core/include/orderedhash.rb +77 -0
  47. data/lib/rbcurse/core/include/ractionevent.rb +67 -0
  48. data/lib/rbcurse/core/include/rchangeevent.rb +27 -0
  49. data/lib/rbcurse/core/include/rhistory.rb +62 -0
  50. data/lib/rbcurse/core/include/rinputdataevent.rb +47 -0
  51. data/lib/rbcurse/core/include/vieditable.rb +170 -0
  52. data/lib/rbcurse/core/system/colormap.rb +163 -0
  53. data/lib/rbcurse/core/system/keyboard.rb +150 -0
  54. data/lib/rbcurse/core/system/keydefs.rb +30 -0
  55. data/lib/rbcurse/core/system/ncurses.rb +218 -0
  56. data/lib/rbcurse/core/system/panel.rb +162 -0
  57. data/lib/rbcurse/core/system/window.rb +901 -0
  58. data/lib/rbcurse/core/util/ansiparser.rb +117 -0
  59. data/lib/rbcurse/core/util/app.rb +1235 -0
  60. data/lib/rbcurse/core/util/basestack.rb +407 -0
  61. data/lib/rbcurse/core/util/bottomline.rb +1850 -0
  62. data/lib/rbcurse/core/util/colorparser.rb +71 -0
  63. data/lib/rbcurse/core/util/focusmanager.rb +31 -0
  64. data/lib/rbcurse/core/util/padreader.rb +189 -0
  65. data/lib/rbcurse/core/util/rcommandwindow.rb +587 -0
  66. data/lib/rbcurse/core/util/rdialogs.rb +619 -0
  67. data/lib/rbcurse/core/util/viewer.rb +149 -0
  68. data/lib/rbcurse/core/util/widgetshortcuts.rb +505 -0
  69. data/lib/rbcurse/core/widgets/applicationheader.rb +102 -0
  70. data/lib/rbcurse/core/widgets/box.rb +58 -0
  71. data/lib/rbcurse/core/widgets/divider.rb +310 -0
  72. data/lib/rbcurse/core/widgets/keylabelprinter.rb +178 -0
  73. data/lib/rbcurse/core/widgets/rcombo.rb +238 -0
  74. data/lib/rbcurse/core/widgets/rcontainer.rb +415 -0
  75. data/lib/rbcurse/core/widgets/rlink.rb +30 -0
  76. data/lib/rbcurse/core/widgets/rlist.rb +723 -0
  77. data/lib/rbcurse/core/widgets/rmenu.rb +939 -0
  78. data/lib/rbcurse/core/widgets/rmenulink.rb +22 -0
  79. data/lib/rbcurse/core/widgets/rmessagebox.rb +373 -0
  80. data/lib/rbcurse/core/widgets/rprogress.rb +118 -0
  81. data/lib/rbcurse/core/widgets/rtabbedpane.rb +615 -0
  82. data/lib/rbcurse/core/widgets/rtabbedwindow.rb +68 -0
  83. data/lib/rbcurse/core/widgets/rtextarea.rb +920 -0
  84. data/lib/rbcurse/core/widgets/rtextview.rb +780 -0
  85. data/lib/rbcurse/core/widgets/rtree.rb +787 -0
  86. data/lib/rbcurse/core/widgets/rwidget.rb +3040 -0
  87. data/lib/rbcurse/core/widgets/scrollbar.rb +143 -0
  88. data/lib/rbcurse/core/widgets/statusline.rb +94 -0
  89. data/lib/rbcurse/core/widgets/tabular.rb +264 -0
  90. data/lib/rbcurse/core/widgets/tabularwidget.rb +1211 -0
  91. data/lib/rbcurse/core/widgets/textpad.rb +516 -0
  92. data/lib/rbcurse/core/widgets/tree/treecellrenderer.rb +150 -0
  93. data/lib/rbcurse/core/widgets/tree/treemodel.rb +428 -0
  94. metadata +156 -0
@@ -0,0 +1,590 @@
1
+ # Provides the ability to scroll content, typically an array
2
+ # widget that includes may override on_enter_row and on_leave_row
3
+ # Caller should have
4
+ # row_count()
5
+ # scrollatrow() typically @height - 2 (unless a header row, then -3)
6
+ # @current_index (row of current index, starting with 0 usually)
7
+ # @toprow : set to 0 for starters, top row to be displayed
8
+ # @pcol (used for horiz scrolling, starts at 0)
9
+ #
10
+ module ListScrollable
11
+ attr_reader :search_found_ix, :find_offset, :find_offset1
12
+ attr_accessor :show_caret # 2010-01-23 23:06 our own fake insertion point
13
+ def previous_row num=(($multiplier.nil? or $multiplier == 0) ? 1 : $multiplier)
14
+ #return :UNHANDLED if @current_index == 0 # EVIL
15
+ return :NO_PREVIOUS_ROW if @current_index == 0
16
+ @oldrow = @current_index
17
+ # NOTE that putting a multiplier inside, prevents an event from being triggered for each row's
18
+ # on leave and on enter
19
+ num.times {
20
+ @current_index -= 1 if @current_index > 0
21
+ }
22
+ bounds_check
23
+ $multiplier = 0
24
+ end
25
+ alias :up :previous_row
26
+ def next_row num=(($multiplier.nil? or $multiplier == 0) ? 1 : $multiplier)
27
+ rc = row_count
28
+ # returning unhandled was clever .. when user hits down arrow on last row the focus goes to
29
+ # next field. however, in long lists when user scrolls the sudden jumping to next is very annoying.
30
+ # In combos, if focus was on last row, the combo closed which is not accceptable.
31
+ #return :UNHANDLED if @current_index == rc-1 # EVIL !!!
32
+ return :NO_NEXT_ROW if @current_index == rc-1 # changed 2011-10-5 so process can do something
33
+ @oldrow = @current_index
34
+ @current_index += 1*num if @current_index < rc
35
+ bounds_check
36
+ $multiplier = 0
37
+ end
38
+ alias :down :next_row
39
+ def goto_bottom
40
+ @oldrow = @current_index
41
+ rc = row_count
42
+ @current_index = rc -1
43
+ bounds_check
44
+ end
45
+ alias :goto_end :goto_bottom
46
+ def goto_top
47
+ @oldrow = @current_index
48
+ @current_index = 0
49
+ bounds_check
50
+ end
51
+ alias :goto_start :goto_top
52
+ def scroll_backward
53
+ @oldrow = @current_index
54
+ h = scrollatrow()
55
+ m = $multiplier == 0? 1 : $multiplier
56
+ @current_index -= h * m
57
+ bounds_check
58
+ $multiplier = 0
59
+ end
60
+ def scroll_forward
61
+ @oldrow = @current_index
62
+ h = scrollatrow()
63
+ rc = row_count
64
+ m = $multiplier == 0? 1 : $multiplier
65
+ # more rows than box
66
+ if h * m < rc
67
+ # next 2 lines were preventing widget_scrolled from being set to true,
68
+ # so i've modified it slightly as per scroll_down 2011-11-1
69
+ #@toprow += h+1 #if @current_index+h < rc
70
+ #@current_index = @toprow
71
+ @current_index += h+1
72
+ else
73
+ # fewer rows than box
74
+ @current_index = rc -1
75
+ end
76
+ #@current_index += h+1 #if @current_index+h < rc
77
+ bounds_check
78
+ end
79
+
80
+ ##
81
+ # please set oldrow before calling this. Store current_index as oldrow before changing. NOTE
82
+ def bounds_check
83
+ h = scrollatrow()
84
+ rc = row_count
85
+ @old_toprow = @toprow
86
+
87
+ @current_index = 0 if @current_index < 0 # not lt 0
88
+ @current_index = rc-1 if @current_index >= rc && rc>0 # not gt rowcount
89
+ @toprow = rc-h-1 if rc > h && @toprow > rc - h - 1 # toprow shows full page if possible
90
+ # curr has gone below table, move toprow forward
91
+ if @current_index - @toprow > h
92
+ @toprow = @current_index - h
93
+ elsif @current_index < @toprow
94
+ # curr has gone above table, move toprow up
95
+ @toprow = @current_index
96
+ end
97
+
98
+ @row_changed = false
99
+ if @oldrow != @current_index
100
+ on_leave_row @oldrow if respond_to? :on_leave_row # to be defined by widget that has included this
101
+ on_enter_row @current_index if respond_to? :on_enter_row # to be defined by widget that has included this
102
+ set_form_row
103
+ @row_changed = true
104
+ end
105
+ #set_form_row # 2011-10-13
106
+
107
+ if @old_toprow != @toprow # only if scrolling has happened should we repaint
108
+ @repaint_required = true #if @old_toprow != @toprow # only if scrolling has happened should we repaint
109
+ @widget_scrolled = true
110
+ end
111
+ end
112
+ # the cursor should be appropriately positioned
113
+ def set_form_row
114
+ r,c = rowcol
115
+ @rows_panned ||= 0
116
+
117
+ win_row = 0 # 2010-02-07 21:44 now ext offset added by widget
118
+
119
+ # when the toprow is set externally then cursor can be mispositioned since
120
+ # bounds_check has not been called
121
+ if @current_index < @toprow
122
+ # cursor is outside table
123
+ @current_index = @toprow # ??? only if toprow 2010-10-19 12:56
124
+ end
125
+
126
+ row = win_row + r + (@current_index-@toprow) + @rows_panned
127
+ #$log.debug " #{@name} set_form_row #{row} = ci #{@current_index} + r #{r} + winrow: #{win_row} - tr:#{@toprow} #{@toprow} + rowsp #{@rows_panned} "
128
+ # row should not be < r or greater than r+height TODO FIXME
129
+
130
+
131
+
132
+ setrowcol row, nil
133
+ #show_caret_func
134
+ end
135
+ ## In many situations like placing a textarea or textview inside a splitpane
136
+ ##+ or scrollpane there have been issues getting the cursor at the right point,
137
+ ##+ since there are multiple buffers. Finally in tabbedpanes, i am pretty
138
+ ##+ lost getting the correct position, and i feel we should set the cursor
139
+ ##+ internally once and for all. So here's an attempt
140
+
141
+ # paint the cursor ourselves on the widget, rather than rely on getting to the top window with
142
+ # the correct coordinates. I do need to erase cursor too. Can be dicey, but is worth the attempt.
143
+ # This works perfectly, except for when placed in a Tabbedpane since that prints the form with a row offset
144
+ #+ of 2 and the widget does not know of the offset. cursor gets it correct since the form has an add_row.
145
+ def show_caret_func
146
+ return unless @show_caret
147
+ # trying highlighting cursor 2010-01-23 19:07 TABBEDPANE TRYING
148
+ # TODO take into account rows_panned etc ? I don't think so.
149
+ @rows_panned ||= 0
150
+ r,c = rowcol
151
+ yy = r + @current_index - @toprow - @win_top
152
+ #xx = @form.col # how do we know what value has been set earlier ?
153
+ yy = r + @current_index - @toprow #- @win_top
154
+ yy = @row_offset + @current_index - @toprow #- @win_top
155
+ xx = @col_offset + @curpos || 0
156
+ #yy = @row_offset if yy < @row_offset # sometimes r is 0, we are missing something in tabbedpane+scroll
157
+ #xx = @col_offset if xx < @col_offset
158
+ #xx = 0 if xx < 0
159
+
160
+ $log.debug " #{@name} printing CARET at #{yy},#{xx}: fwt:- #{@win_top} r:#{@row} tr:-#{@toprow}+ci:#{@current_index},+r #{r} "
161
+ if !@oldcursorrow.nil?
162
+ @graphic.mvchgat(y=@oldcursorrow, x=@oldcursorcol, 1, Ncurses::A_NORMAL, $datacolor, NIL)
163
+ end
164
+ @oldcursorrow = yy
165
+ @oldcursorcol = xx
166
+ @graphic.mvchgat(y=yy, x=xx, 1, Ncurses::A_NORMAL, $reversecolor, nil)
167
+ @buffer_modified = true
168
+ end
169
+ def scroll_right
170
+ $log.debug " inside scroll_right "
171
+ hscrollcols = $multiplier > 0 ? $multiplier : @width/2
172
+ #hscrollcols = $multiplier > 0 ? $multiplier : 1 # for testing out
173
+ $log.debug " scroll_right mult:#{$multiplier} , hscrollcols #{hscrollcols}, pcol #{@pcol} w: #{@width} ll:#{@longest_line} "
174
+ #blen = @buffer.rstrip.length
175
+ blen = @longest_line
176
+ @pcol += hscrollcols if @pcol + @width < blen
177
+ @repaint_required = true
178
+ end
179
+ def scroll_left
180
+ hscrollcols = $multiplier > 0 ? $multiplier : @width/2
181
+ @pcol -= hscrollcols if @pcol > 0
182
+ @pcol = 0 if @pcol < 0
183
+ @repaint_required = true
184
+ end
185
+ ## returns cursor to last row (if moving columns in same row, won't work)
186
+ # Useful after a large move such as 12j, 20 C-n etc, Mapped to '' in textview
187
+ def goto_last_position
188
+ return unless @oldrow
189
+ @current_index = @oldrow
190
+ bounds_check
191
+ end
192
+ # not that saving content_rows is buggy since we add rows.
193
+ ##
194
+ # caution, this now uses winrow not prow
195
+ ## for user to know which row is being focussed on
196
+ def focussed_index
197
+ @current_index # 2009-01-07 14:35
198
+ end
199
+ # only to be used in single selection cases as focussed item FIXME.
200
+ # best not to use, as can be implementation dep, use current_index
201
+ def selected_item
202
+ get_content()[focussed_index()]
203
+ end
204
+ #alias :current_index :focussed_index
205
+ alias :selected_index :focussed_index
206
+
207
+ # finds the next match for the char pressed
208
+ # returning the index
209
+ # If we are only checking first char, then why chomp ?
210
+ # Please note that this is used now by tree, and list can have non-strings, so use to_s
211
+ def next_match char
212
+ data = get_content
213
+ row = focussed_index + 1
214
+ row.upto(data.length-1) do |ix|
215
+ #val = data[ix].chomp rescue return # 2010-01-05 15:28 crashed on trueclass
216
+ val = data[ix].to_s rescue return # 2010-01-05 15:28 crashed on trueclass
217
+ #if val[0,1] == char #and val != currval
218
+ if val[0,1].casecmp(char) == 0 #AND VAL != CURRval
219
+ return ix
220
+ end
221
+ end
222
+ row = focussed_index - 1
223
+ 0.upto(row) do |ix|
224
+ #val = data[ix].chomp
225
+ val = data[ix].to_s
226
+ #if val[0,1] == char #and val != currval
227
+ if val[0,1].casecmp(char) == 0 #and val != currval
228
+ return ix
229
+ end
230
+ end
231
+ return -1
232
+ end
233
+ ## 2008-12-18 18:03
234
+ # sets the selection to the next row starting with char
235
+ def set_selection_for_char char
236
+ @oldrow = @current_index
237
+ @last_regex = "^#{char}"
238
+ ix = next_match char
239
+ @current_index = ix if ix && ix != -1
240
+ @search_found_ix = @current_index
241
+ bounds_check
242
+ return ix
243
+ end
244
+
245
+ ##
246
+ # ensures that the given row is focussed
247
+ # new version of older one that was not perfect.
248
+ # 2009-01-17 13:25
249
+ def set_focus_on arow
250
+ @oldrow = @current_index
251
+ arow += @_header_adjustment if @_header_adjustment # for tables 2011-11-30
252
+ @current_index = arow
253
+ bounds_check if @oldrow != @current_index
254
+ end
255
+ ##
256
+ def install_keys
257
+ =begin
258
+ @KEY_ASK_FIND_FORWARD ||= ?\M-f.getbyte(0)
259
+ @KEY_ASK_FIND_BACKWARD ||= ?\M-F.getbyte(0)
260
+ @KEY_FIND_NEXT ||= ?\M-g.getbyte(0)
261
+ @KEY_FIND_PREV ||= ?\M-G.getbyte(0)
262
+ =end
263
+ @KEY_ASK_FIND ||= ?\M-f.getbyte(0)
264
+ @KEY_FIND_MORE ||= ?\M-g.getbyte(0)
265
+ end
266
+ def ask_search
267
+ options = ["Search backwards", "case insensitive", "Wrap around"]
268
+ defaults = [@search_direction_prev,@search_case,@search_wrap]
269
+ regex = @last_regex || ""
270
+
271
+ mb = MessageBox.new :title => "Search" , :width => 70 do
272
+ add Field.new :label => 'Enter regex to search', :name => "patt", :display_length => 30,
273
+ :bgcolor => :cyan, :text => regex
274
+ add CheckBox.new :text => options[0], :value => defaults[0], :name => "0"
275
+ add CheckBox.new :text => options[1], :value => defaults[1], :name => "1"
276
+ add CheckBox.new :text => options[2], :value => defaults[2], :name => "2"
277
+
278
+ button_type :ok_cancel
279
+ end
280
+ index = mb.run
281
+ return if index != 0
282
+ regex = mb.widget("patt").text
283
+ @search_direction_prev = mb.widget("0").value
284
+ @search_case = mb.widget("1").value
285
+ @search_wrap = mb.widget("2").value
286
+ #
287
+ #-----
288
+ #options = ["Search backwards", "case insensitive", "Wrap around"]
289
+ #sel,regex,hash = get_string_with_options("Enter regex to search", 20, @last_regex||"", "checkboxes"=>options, "checkbox_defaults"=>[@search_direction_prev,@search_case,@search_wrap])
290
+ #return if sel != 0
291
+ #@search_direction_prev = hash[options[0]]
292
+ #@search_case = hash[options[1]]
293
+ #@search_wrap = hash[options[2]]
294
+ if @search_direction_prev == true
295
+ ix = _find_prev regex, @current_index
296
+ else
297
+ ix = _find_next regex, @current_index
298
+ end
299
+ if ix.nil?
300
+ alert("No matching data for: #{regex}")
301
+ else
302
+ set_focus_on(ix)
303
+ set_form_col @find_offset1
304
+ @cell_editor.component.curpos = (@find_offset||0) if @cell_editing_allowed
305
+ end
306
+ @last_regex = regex
307
+ end
308
+ def find_more
309
+ if @search_direction_prev
310
+ find_prev
311
+ else
312
+ find_next
313
+ end
314
+ end
315
+ # find forwards
316
+ # Using this to start a search or continue search
317
+ def _find_next regex=@last_regex, start = @search_found_ix
318
+ #raise "No previous search" if regex.nil?
319
+ warn "No previous search" and return if regex.nil?
320
+ #$log.debug " _find_next #{@search_found_ix} : #{@current_index}"
321
+ fend = @list.size-1
322
+ if start != fend
323
+ start += 1 unless start == fend
324
+ @last_regex = regex
325
+ @search_start_ix = start
326
+ regex = Regexp.new(regex, Regexp::IGNORECASE) if @search_case
327
+ start.upto(fend) do |ix|
328
+ row1 = @list[ix].to_s
329
+
330
+ # 2011-09-29 crashing on a character F3 in log file
331
+ row = row1.encode("ASCII-8BIT", :invalid => :replace, :undef => :replace, :replace => "?")
332
+
333
+ m=row.match(regex)
334
+ if !m.nil?
335
+ @find_offset = m.offset(0)[0]
336
+ @find_offset1 = m.offset(0)[1]
337
+ @search_found_ix = ix
338
+ return ix
339
+ end
340
+ end
341
+ end
342
+ fend = start-1
343
+ start = 0
344
+ if @search_wrap
345
+ start.upto(fend) do |ix|
346
+ row = @list[ix].to_s
347
+ m=row.match(regex)
348
+ if !m.nil?
349
+ @find_offset = m.offset(0)[0]
350
+ @find_offset1 = m.offset(0)[1]
351
+ @search_found_ix = ix
352
+ return ix
353
+ end
354
+ end
355
+ end
356
+ return nil
357
+ end
358
+ def find_next
359
+ unless @last_regex
360
+ alert("No previous search. Search first.")
361
+ return
362
+ end
363
+ ix = _find_next
364
+ regex = @last_regex
365
+ if ix.nil?
366
+ alert("No more matching data for: #{regex}")
367
+ else
368
+ set_focus_on(ix)
369
+ set_form_col @find_offset1
370
+ @cell_editor.component.curpos = (@find_offset||0) if @cell_editing_allowed
371
+ end
372
+ end
373
+ def find_prev
374
+ unless @last_regex
375
+ alert("No previous search. Search first.")
376
+ return
377
+ end
378
+ ix = _find_prev
379
+ regex = @last_regex
380
+ if ix.nil?
381
+ alert("No previous matching data for: #{regex}")
382
+ else
383
+ set_focus_on(ix)
384
+ set_form_col @find_offset
385
+ @cell_editor.component.curpos = (@find_offset||0) if @cell_editing_allowed
386
+ end
387
+ end
388
+ ##
389
+ # find backwards
390
+ # Using this to start a search or continue search
391
+ def _find_prev regex=@last_regex, start = @search_found_ix
392
+ #raise "No previous search" if regex.nil?
393
+ warn "No previous search" and return if regex.nil?
394
+ #$log.debug " _find_prev #{@search_found_ix} : #{@current_index}"
395
+ if start != 0
396
+ start -= 1 unless start == 0
397
+ @last_regex = regex
398
+ @search_start_ix = start
399
+ regex = Regexp.new(regex, Regexp::IGNORECASE) if @search_case
400
+ start.downto(0) do |ix|
401
+ row = @list[ix].to_s
402
+ m=row.match(regex)
403
+ if !m.nil?
404
+ @find_offset = m.offset(0)[0]
405
+ @find_offset1 = m.offset(0)[1]
406
+ @search_found_ix = ix
407
+ return ix
408
+ end
409
+ end
410
+ end
411
+ fend = start-1
412
+ start = @list.size-1
413
+ if @search_wrap
414
+ start.downto(fend) do |ix|
415
+ row = @list[ix].to_s
416
+ m=row.match(regex)
417
+ if !m.nil?
418
+ @find_offset = m.offset(0)[0]
419
+ @find_offset1 = m.offset(0)[1]
420
+ @search_found_ix = ix
421
+ return ix
422
+ end
423
+ end
424
+ end
425
+ return nil
426
+ end
427
+ ##
428
+ # goes to start of next word (or n words) - vi's w
429
+ # NOTE: will not work if the list has different data from what is displayed
430
+ # Nothing i can do about it.
431
+ # Also does not work as expected if consecutive spaces FIXME
432
+ # Will not scroll list, if reaches end, jist goes on and vanshes FIXME
433
+ #
434
+ def forward_word
435
+ $multiplier = 1 if !$multiplier || $multiplier == 0
436
+ line = @current_index
437
+ buff = @list[line].to_s
438
+ return unless buff
439
+ pos = @curpos || 0 # list does not have curpos
440
+ $multiplier.times {
441
+ found = buff.index(/[[:punct:][:space:]]/, pos)
442
+ if !found
443
+ # if not found, we've lost a counter
444
+ if line+1 < @list.length
445
+ line += 1
446
+ else
447
+ return
448
+ end
449
+ buff = @list[line].to_s
450
+ pos = 0
451
+ else
452
+ pos = found + 1
453
+ end
454
+ $log.debug " forward_word: pos #{pos} line #{line} buff: #{buff}"
455
+ }
456
+ @current_index = line
457
+ @curpos = pos
458
+ @buffer = @list[@current_index].to_s
459
+ set_form_row
460
+ set_form_col pos
461
+ @repaint_required = true
462
+ end
463
+ ##
464
+ # goes to next occurence of <char> (or nth occurence)
465
+ # Actually, we can club this with forward_word so no duplication
466
+ # Or call one from the other
467
+ #
468
+ def forward_char char=nil
469
+ if char.nil?
470
+ $log.debug " XXX acceptng char"
471
+ ch = @graphic.getchar
472
+ return -1 if ch < 0 or ch > 255 # or 127 ???
473
+ char = ch.chr
474
+ end
475
+ $log.debug " forward_char char:#{char}:"
476
+ $multiplier = 1 if !$multiplier or $multiplier == 0
477
+ line = @current_index
478
+ buff = @list[line].to_s
479
+ pos = @curpos
480
+ $multiplier.times {
481
+ found = false
482
+ while !found
483
+ found = buff.index(char, pos)
484
+ if !found
485
+ line += 1 # unless eof
486
+ buff = @list[line].to_s
487
+ pos = 0
488
+ else
489
+ pos = found + 1
490
+ end
491
+ break if line >= @list.size
492
+ $log.debug " #{found} forward_word: pos #{pos} line #{line} buff: #{buff}"
493
+ end
494
+ }
495
+ @current_index = line
496
+ @curpos = pos
497
+ @buffer = @list[@current_index].to_s
498
+ set_form_row
499
+ set_form_col pos
500
+ @repaint_required = true
501
+ end
502
+ # takes a block, this way anyone extending this class can just pass a block to do his job
503
+ # This modifies the string
504
+ def sanitize content #:nodoc:
505
+ if content.is_a? String
506
+ content.chomp!
507
+ content.replace(content.encode("ASCII-8BIT", :invalid => :replace, :undef => :replace, :replace => "?"))
508
+ content.gsub!(/[\t\r\n]/, ' ') # don't display tab, newline
509
+ content.gsub!(/\n/, ' ') # don't display tab, newline
510
+ content.gsub!(/[^[:print:]]/, '') # don't display non print characters
511
+ else
512
+ content
513
+ end
514
+ end
515
+ # returns only the visible portion of string taking into account display length
516
+ # and horizontal scrolling. MODIFIES STRING
517
+ # NOTE truncate does not take into account left_margin that some widgets might use
518
+ def truncate content #:nodoc:
519
+ #maxlen = @maxlen || @width-2
520
+ _maxlen = @maxlen || @width-@internal_width
521
+ _maxlen = @width-@internal_width if _maxlen > @width-@internal_width
522
+ if !content.nil?
523
+ if content.length > _maxlen # only show maxlen
524
+ @longest_line = content.length if content.length > @longest_line
525
+ #content = content[@pcol..@pcol+_maxlen-1]
526
+ content.replace content[@pcol..@pcol+_maxlen-1]
527
+ else
528
+ # can this be avoided if pcol is 0 XXX
529
+ content.replace content[@pcol..-1] if @pcol > 0
530
+ end
531
+ end
532
+ content
533
+ end
534
+ #
535
+ # Is the given index in the visible area
536
+ # UNTESTED XXX
537
+ def is_visible? index
538
+ #(0..scrollatrow()).include? index - @toprow
539
+ j = index - @toprow
540
+ j >= 0 && j <= scrollatrow()
541
+ end
542
+ # offset in widget like 0..scrollatrow
543
+ # NOTE can return nil, if user scrolls forward or backward
544
+ # @private
545
+ def _convert_index_to_visible_row index=@current_index
546
+ pos = index - @toprow
547
+ return nil if pos < 0 || pos > scrollatrow()
548
+ return pos
549
+ end
550
+ # actual position to write on window
551
+ # NOTE can return nil, if user scrolls forward or backward
552
+ def _convert_index_to_printable_row index=@current_index
553
+ r,c = rowcol
554
+ pos = _convert_index_to_visible_row(index)
555
+ return nil unless pos
556
+ pos = r + pos
557
+ return pos
558
+ end
559
+
560
+ # highlights the focussed (current) and unfocussed (oldrow)
561
+ # NOTE: when multiselecting ... it will remove selection
562
+ # so be careful when calling.
563
+ def highlight_focussed_row type, r=nil, c=nil, acolor=nil
564
+ return unless @should_show_focus
565
+ case type
566
+ when :FOCUSSED
567
+ ix = @current_index
568
+ return if is_row_selected ix
569
+ r = _convert_index_to_printable_row() unless r
570
+ attrib = @focussed_attrib || 'bold'
571
+
572
+ when :UNFOCUSSED
573
+ return if @oldrow.nil? || @oldrow == @current_index
574
+ ix = @oldrow
575
+ return if is_row_selected ix
576
+ r = _convert_index_to_printable_row(@oldrow) unless r
577
+ return unless r # row is not longer visible
578
+ attrib = @attr
579
+ end
580
+ unless c
581
+ _r, c = rowcol
582
+ end
583
+ # this optimization now overrides any coloring that listbox may have done per row XXX
584
+ acolor ||= get_color $datacolor
585
+ att = get_attrib(attrib) #if @focussed_attrib
586
+ @graphic.mvchgat(y=r, x=c, @width-@internal_width, att , acolor , nil)
587
+ end
588
+
589
+
590
+ end