rbcurse-core 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
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