rbcurse-core 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +69 -0
- data/VERSION +1 -0
- data/examples/abasiclist.rb +151 -0
- data/examples/alpmenu.rb +46 -0
- data/examples/app.sample +17 -0
- data/examples/atree.rb +100 -0
- data/examples/common/file.rb +45 -0
- data/examples/data/README.markdown +9 -0
- data/examples/data/brew.txt +38 -0
- data/examples/data/color.2 +37 -0
- data/examples/data/gemlist.txt +60 -0
- data/examples/data/lotr.txt +12 -0
- data/examples/data/ports.txt +136 -0
- data/examples/data/table.txt +37 -0
- data/examples/data/tasks.csv +88 -0
- data/examples/data/tasks.txt +27 -0
- data/examples/data/todo.txt +10 -0
- data/examples/data/todocsv.csv +28 -0
- data/examples/data/unix1.txt +21 -0
- data/examples/data/unix2.txt +11 -0
- data/examples/dbdemo.rb +487 -0
- data/examples/dirtree.rb +90 -0
- data/examples/newtabbedwindow.rb +100 -0
- data/examples/newtesttabp.rb +92 -0
- data/examples/tabular.rb +132 -0
- data/examples/tasks.rb +167 -0
- data/examples/term2.rb +83 -0
- data/examples/testkeypress.rb +72 -0
- data/examples/testlistbox.rb +158 -0
- data/examples/testmessagebox.rb +140 -0
- data/examples/testree.rb +106 -0
- data/examples/testwsshortcuts.rb +66 -0
- data/examples/testwsshortcuts2.rb +127 -0
- data/lib/rbcurse.rb +8 -0
- data/lib/rbcurse/core/docs/index.txt +73 -0
- data/lib/rbcurse/core/include/action.rb +40 -0
- data/lib/rbcurse/core/include/appmethods.rb +112 -0
- data/lib/rbcurse/core/include/bordertitle.rb +41 -0
- data/lib/rbcurse/core/include/chunk.rb +182 -0
- data/lib/rbcurse/core/include/io.rb +953 -0
- data/lib/rbcurse/core/include/listcellrenderer.rb +140 -0
- data/lib/rbcurse/core/include/listeditable.rb +317 -0
- data/lib/rbcurse/core/include/listscrollable.rb +590 -0
- data/lib/rbcurse/core/include/listselectable.rb +264 -0
- data/lib/rbcurse/core/include/multibuffer.rb +83 -0
- data/lib/rbcurse/core/include/orderedhash.rb +77 -0
- data/lib/rbcurse/core/include/ractionevent.rb +67 -0
- data/lib/rbcurse/core/include/rchangeevent.rb +27 -0
- data/lib/rbcurse/core/include/rhistory.rb +62 -0
- data/lib/rbcurse/core/include/rinputdataevent.rb +47 -0
- data/lib/rbcurse/core/include/vieditable.rb +170 -0
- data/lib/rbcurse/core/system/colormap.rb +163 -0
- data/lib/rbcurse/core/system/keyboard.rb +150 -0
- data/lib/rbcurse/core/system/keydefs.rb +30 -0
- data/lib/rbcurse/core/system/ncurses.rb +218 -0
- data/lib/rbcurse/core/system/panel.rb +162 -0
- data/lib/rbcurse/core/system/window.rb +901 -0
- data/lib/rbcurse/core/util/ansiparser.rb +117 -0
- data/lib/rbcurse/core/util/app.rb +1235 -0
- data/lib/rbcurse/core/util/basestack.rb +407 -0
- data/lib/rbcurse/core/util/bottomline.rb +1850 -0
- data/lib/rbcurse/core/util/colorparser.rb +71 -0
- data/lib/rbcurse/core/util/focusmanager.rb +31 -0
- data/lib/rbcurse/core/util/padreader.rb +189 -0
- data/lib/rbcurse/core/util/rcommandwindow.rb +587 -0
- data/lib/rbcurse/core/util/rdialogs.rb +619 -0
- data/lib/rbcurse/core/util/viewer.rb +149 -0
- data/lib/rbcurse/core/util/widgetshortcuts.rb +505 -0
- data/lib/rbcurse/core/widgets/applicationheader.rb +102 -0
- data/lib/rbcurse/core/widgets/box.rb +58 -0
- data/lib/rbcurse/core/widgets/divider.rb +310 -0
- data/lib/rbcurse/core/widgets/keylabelprinter.rb +178 -0
- data/lib/rbcurse/core/widgets/rcombo.rb +238 -0
- data/lib/rbcurse/core/widgets/rcontainer.rb +415 -0
- data/lib/rbcurse/core/widgets/rlink.rb +30 -0
- data/lib/rbcurse/core/widgets/rlist.rb +723 -0
- data/lib/rbcurse/core/widgets/rmenu.rb +939 -0
- data/lib/rbcurse/core/widgets/rmenulink.rb +22 -0
- data/lib/rbcurse/core/widgets/rmessagebox.rb +373 -0
- data/lib/rbcurse/core/widgets/rprogress.rb +118 -0
- data/lib/rbcurse/core/widgets/rtabbedpane.rb +615 -0
- data/lib/rbcurse/core/widgets/rtabbedwindow.rb +68 -0
- data/lib/rbcurse/core/widgets/rtextarea.rb +920 -0
- data/lib/rbcurse/core/widgets/rtextview.rb +780 -0
- data/lib/rbcurse/core/widgets/rtree.rb +787 -0
- data/lib/rbcurse/core/widgets/rwidget.rb +3040 -0
- data/lib/rbcurse/core/widgets/scrollbar.rb +143 -0
- data/lib/rbcurse/core/widgets/statusline.rb +94 -0
- data/lib/rbcurse/core/widgets/tabular.rb +264 -0
- data/lib/rbcurse/core/widgets/tabularwidget.rb +1211 -0
- data/lib/rbcurse/core/widgets/textpad.rb +516 -0
- data/lib/rbcurse/core/widgets/tree/treecellrenderer.rb +150 -0
- data/lib/rbcurse/core/widgets/tree/treemodel.rb +428 -0
- 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
|