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