canis 0.0.4
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 +45 -0
- data/CHANGES +52 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +24 -0
- data/Rakefile +2 -0
- data/canis.gemspec +25 -0
- data/examples/alpmenu.rb +46 -0
- data/examples/app.sample +19 -0
- data/examples/appemail.rb +191 -0
- data/examples/atree.rb +105 -0
- data/examples/bline.rb +181 -0
- data/examples/common/devel.rb +319 -0
- data/examples/common/file.rb +93 -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 +59 -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 +16 -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 +506 -0
- data/examples/dirtree.rb +177 -0
- data/examples/newtabbedwindow.rb +100 -0
- data/examples/newtesttabp.rb +92 -0
- data/examples/tabular.rb +212 -0
- data/examples/tasks.rb +179 -0
- data/examples/term2.rb +88 -0
- data/examples/testbuttons.rb +307 -0
- data/examples/testcombo.rb +102 -0
- data/examples/testdb.rb +182 -0
- data/examples/testfields.rb +208 -0
- data/examples/testflowlayout.rb +43 -0
- data/examples/testkeypress.rb +98 -0
- data/examples/testlistbox.rb +187 -0
- data/examples/testlistbox1.rb +199 -0
- data/examples/testmessagebox.rb +144 -0
- data/examples/testprogress.rb +116 -0
- data/examples/testree.rb +107 -0
- data/examples/testsplitlayout.rb +53 -0
- data/examples/testsplitlayout1.rb +49 -0
- data/examples/teststacklayout.rb +48 -0
- data/examples/testwsshortcuts.rb +68 -0
- data/examples/testwsshortcuts2.rb +129 -0
- data/lib/canis.rb +16 -0
- data/lib/canis/core/docs/index.txt +104 -0
- data/lib/canis/core/docs/list.txt +16 -0
- data/lib/canis/core/docs/style_help.yml +34 -0
- data/lib/canis/core/docs/tabbedpane.txt +15 -0
- data/lib/canis/core/docs/table.txt +31 -0
- data/lib/canis/core/docs/textpad.txt +48 -0
- data/lib/canis/core/docs/tree.txt +23 -0
- data/lib/canis/core/include/.DS_Store +0 -0
- data/lib/canis/core/include/action.rb +83 -0
- data/lib/canis/core/include/actionmanager.rb +49 -0
- data/lib/canis/core/include/appmethods.rb +179 -0
- data/lib/canis/core/include/bordertitle.rb +49 -0
- data/lib/canis/core/include/canisparser.rb +100 -0
- data/lib/canis/core/include/colorparser.rb +437 -0
- data/lib/canis/core/include/defaultfilerenderer.rb +64 -0
- data/lib/canis/core/include/io.rb +320 -0
- data/lib/canis/core/include/layouts/SplitLayout.rb +161 -0
- data/lib/canis/core/include/layouts/abstractlayout.rb +213 -0
- data/lib/canis/core/include/layouts/flowlayout.rb +104 -0
- data/lib/canis/core/include/layouts/stacklayout.rb +109 -0
- data/lib/canis/core/include/listbindings.rb +89 -0
- data/lib/canis/core/include/listeditable.rb +319 -0
- data/lib/canis/core/include/listoperations.rb +61 -0
- data/lib/canis/core/include/listselectionmodel.rb +388 -0
- data/lib/canis/core/include/multibuffer.rb +173 -0
- data/lib/canis/core/include/ractionevent.rb +73 -0
- data/lib/canis/core/include/rchangeevent.rb +27 -0
- data/lib/canis/core/include/rhistory.rb +95 -0
- data/lib/canis/core/include/rinputdataevent.rb +47 -0
- data/lib/canis/core/include/textdocument.rb +111 -0
- data/lib/canis/core/include/vieditable.rb +175 -0
- data/lib/canis/core/include/widgetmenu.rb +66 -0
- data/lib/canis/core/system/colormap.rb +165 -0
- data/lib/canis/core/system/keydefs.rb +32 -0
- data/lib/canis/core/system/ncurses.rb +237 -0
- data/lib/canis/core/system/panel.rb +129 -0
- data/lib/canis/core/system/window.rb +1081 -0
- data/lib/canis/core/util/ansiparser.rb +119 -0
- data/lib/canis/core/util/app.rb +696 -0
- data/lib/canis/core/util/basestack.rb +412 -0
- data/lib/canis/core/util/defaultcolorparser.rb +84 -0
- data/lib/canis/core/util/extras/README +5 -0
- data/lib/canis/core/util/extras/bottomline.rb +1815 -0
- data/lib/canis/core/util/extras/padreader.rb +192 -0
- data/lib/canis/core/util/focusmanager.rb +31 -0
- data/lib/canis/core/util/helpmanager.rb +160 -0
- data/lib/canis/core/util/oldwidgetshortcuts.rb +304 -0
- data/lib/canis/core/util/promptmenu.rb +235 -0
- data/lib/canis/core/util/rcommandwindow.rb +933 -0
- data/lib/canis/core/util/rdialogs.rb +520 -0
- data/lib/canis/core/util/textutils.rb +74 -0
- data/lib/canis/core/util/viewer.rb +238 -0
- data/lib/canis/core/util/widgetshortcuts.rb +508 -0
- data/lib/canis/core/widgets/applicationheader.rb +103 -0
- data/lib/canis/core/widgets/box.rb +58 -0
- data/lib/canis/core/widgets/divider.rb +310 -0
- data/lib/canis/core/widgets/extras/README.md +12 -0
- data/lib/canis/core/widgets/extras/rtextarea.rb +960 -0
- data/lib/canis/core/widgets/extras/stackflow.rb +474 -0
- data/lib/canis/core/widgets/keylabelprinter.rb +194 -0
- data/lib/canis/core/widgets/listbox.rb +326 -0
- data/lib/canis/core/widgets/listfooter.rb +86 -0
- data/lib/canis/core/widgets/rcombo.rb +210 -0
- data/lib/canis/core/widgets/rcontainer.rb +415 -0
- data/lib/canis/core/widgets/rlink.rb +30 -0
- data/lib/canis/core/widgets/rmenu.rb +970 -0
- data/lib/canis/core/widgets/rmenulink.rb +30 -0
- data/lib/canis/core/widgets/rmessagebox.rb +400 -0
- data/lib/canis/core/widgets/rprogress.rb +118 -0
- data/lib/canis/core/widgets/rtabbedpane.rb +631 -0
- data/lib/canis/core/widgets/rtabbedwindow.rb +70 -0
- data/lib/canis/core/widgets/rwidget.rb +3634 -0
- data/lib/canis/core/widgets/scrollbar.rb +147 -0
- data/lib/canis/core/widgets/statusline.rb +113 -0
- data/lib/canis/core/widgets/table.rb +1072 -0
- data/lib/canis/core/widgets/tabular.rb +264 -0
- data/lib/canis/core/widgets/textpad.rb +1674 -0
- data/lib/canis/core/widgets/tree.rb +690 -0
- data/lib/canis/core/widgets/tree/treecellrenderer.rb +150 -0
- data/lib/canis/core/widgets/tree/treemodel.rb +432 -0
- data/lib/canis/version.rb +3 -0
- metadata +229 -0
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
# Some methods for manipulating lists
|
|
2
|
+
# Different components may bind different keys to these
|
|
3
|
+
# Currently will be called by TextArea and the editable version
|
|
4
|
+
# of TextView (vieditable).
|
|
5
|
+
#
|
|
6
|
+
require 'canis/core/include/rinputdataevent'
|
|
7
|
+
module ListEditable
|
|
8
|
+
|
|
9
|
+
def remove_all
|
|
10
|
+
# don't create a new object, other dependents like selection model may suffer 2014-04-08 - 20:00
|
|
11
|
+
#@list = []
|
|
12
|
+
@list.clear
|
|
13
|
+
set_modified # added 2009-02-13 22:28 so repaints
|
|
14
|
+
end
|
|
15
|
+
# current behav is a mix of vim's D and C-k from alpine, i don;t know how i screwed it up like this
|
|
16
|
+
# Should be:
|
|
17
|
+
# 1. do not take cursor back by 1 (this is vims D behavior)
|
|
18
|
+
# 2. retain EOL, we need to evaluate at undo
|
|
19
|
+
# 3. if nothing coming in delete buffer then join next line here
|
|
20
|
+
# 4. if line is blank, it will go to delete line (i think).
|
|
21
|
+
# Earlier, a C-k at pos 0 would blank the line and not delete it (copied from alpine).
|
|
22
|
+
# The next C-k would delete. emacs deletes if C-k at pos 0.
|
|
23
|
+
def delete_eol
|
|
24
|
+
return -1 unless @editable
|
|
25
|
+
pos = @curpos -1 # retain from 0 till prev char
|
|
26
|
+
@delete_buffer = @buffer[@curpos..-1]
|
|
27
|
+
# currently eol is there in delete_buff often. Should i maintain it ? 2010-03-08 18:29 UNDO
|
|
28
|
+
#@delete_buffer.chomp! # new 2010-03-08 18:29 UNDO - this worked but hope does not have othe impact
|
|
29
|
+
|
|
30
|
+
# if pos is 0, pos-1 becomes -1, end of line!
|
|
31
|
+
@list[@current_index] = pos == -1 ? "" : @buffer[0..pos]
|
|
32
|
+
$log.debug "delete EOL :pos=#{pos}, #{@delete_buffer}: row: #{@list[@current_index]}:"
|
|
33
|
+
@buffer = @list[@current_index]
|
|
34
|
+
if @delete_buffer == ""
|
|
35
|
+
$log.debug " TA: DELETE going to join next "
|
|
36
|
+
join_next_line # pull next line in
|
|
37
|
+
end
|
|
38
|
+
oldcur = @curpos
|
|
39
|
+
#x cursor_backward if @curpos > 0 # this was vims behavior -- knoecked off
|
|
40
|
+
#fire_handler :CHANGE, self # 2008-12-09 14:56
|
|
41
|
+
fire_handler :CHANGE, InputDataEvent.new(oldcur,oldcur+@delete_buffer.length, self, :DELETE, @current_index, @delete_buffer) # 2008-12-24 18:34
|
|
42
|
+
set_modified
|
|
43
|
+
return @delete_buffer
|
|
44
|
+
end
|
|
45
|
+
def join_next_line
|
|
46
|
+
# return if last line TODO
|
|
47
|
+
buff = @list.delete_at(@current_index + 1)
|
|
48
|
+
if buff
|
|
49
|
+
$log.debug " TA: DELETE inside to join next #{buff} "
|
|
50
|
+
fire_handler :CHANGE, InputDataEvent.new(0,0+buff.length, self, :DELETE_LINE, @current_index+1, buff)
|
|
51
|
+
@buffer << buff
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
# deletes given line or current
|
|
55
|
+
# now fires DELETE_LINE so no guessing by undo manager
|
|
56
|
+
def delete_line line=@current_index
|
|
57
|
+
return -1 unless @editable
|
|
58
|
+
if !$multiplier || $multiplier == 0
|
|
59
|
+
@delete_buffer = @list.delete_at line
|
|
60
|
+
else
|
|
61
|
+
@delete_buffer = @list.slice!(line, $multiplier)
|
|
62
|
+
end
|
|
63
|
+
@curpos ||= 0 # rlist has no such var
|
|
64
|
+
$multiplier = 0
|
|
65
|
+
add_to_kill_ring @delete_buffer
|
|
66
|
+
@buffer = @list[@current_index]
|
|
67
|
+
if @buffer.nil?
|
|
68
|
+
up
|
|
69
|
+
setrowcol @row + 1, nil # @form.col
|
|
70
|
+
end
|
|
71
|
+
# warning: delete buffer can now be an array
|
|
72
|
+
fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos+@delete_buffer.length, self, :DELETE_LINE, line, @delete_buffer) # 2008-12-24 18:34
|
|
73
|
+
set_modified
|
|
74
|
+
# next line being called from textarea which is old style and thus bombs
|
|
75
|
+
fire_dimension_changed if respond_to? :fire_dimension_changed
|
|
76
|
+
end
|
|
77
|
+
def delete_curr_char num=($multiplier == 0 ? 1 : $multiplier)
|
|
78
|
+
return -1 unless @editable
|
|
79
|
+
delete_at @curpos, num # changed so only one event, and one undo
|
|
80
|
+
set_modified
|
|
81
|
+
$multiplier = 0
|
|
82
|
+
end
|
|
83
|
+
#
|
|
84
|
+
# 2010-03-08 23:30 does not seem to be working well when backspacing at first char of line
|
|
85
|
+
# FIXME should work as a unit, so one undo and one fire_handler, at least if on one line.
|
|
86
|
+
def delete_prev_char num=($multiplier == 0 ? 1 : $multiplier)
|
|
87
|
+
return -1 if !@editable
|
|
88
|
+
num.times do
|
|
89
|
+
if @curpos <= 0
|
|
90
|
+
join_to_prev_line
|
|
91
|
+
return
|
|
92
|
+
end
|
|
93
|
+
@curpos -= 1 if @curpos > 0
|
|
94
|
+
delete_at
|
|
95
|
+
set_modified
|
|
96
|
+
addcol -1
|
|
97
|
+
end
|
|
98
|
+
$multiplier = 0
|
|
99
|
+
end
|
|
100
|
+
# open a new line and add chars to it.
|
|
101
|
+
# FIXME does not fire handler, thus won't undo
|
|
102
|
+
def append_row lineno=@current_index, chars=""
|
|
103
|
+
$log.debug "append row sapce:#{chars}."
|
|
104
|
+
@list.insert lineno+1, chars
|
|
105
|
+
end
|
|
106
|
+
##
|
|
107
|
+
# delete character/s on current line
|
|
108
|
+
def delete_at index=@curpos, howmany=1
|
|
109
|
+
return -1 if !@editable
|
|
110
|
+
$log.debug "delete_at (characters) : #{@current_index} #{@buffer} #{index}"
|
|
111
|
+
char = @buffer.slice!(@curpos,howmany) # changed added ,1 and take char for event
|
|
112
|
+
# if no newline at end of this then bring up prev character/s till maxlen
|
|
113
|
+
# NO WE DON'T DO THIS ANYLONGER 2008-12-26 21:09 lets see
|
|
114
|
+
=begin
|
|
115
|
+
if @buffer[-1,1]!="\r"
|
|
116
|
+
@buffer[-1]=" " if @buffer[-1,1]=="\n"
|
|
117
|
+
if !next_line.nil? and next_line.length > 0
|
|
118
|
+
move_chars_up
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
=end
|
|
122
|
+
set_modified true
|
|
123
|
+
fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos+howmany, self, :DELETE, @current_index, char) # 2008-12-24 18:34
|
|
124
|
+
end
|
|
125
|
+
def undo_handler(uh)
|
|
126
|
+
@undo_handler = uh
|
|
127
|
+
end
|
|
128
|
+
## THIS ONE SHOULD BE IN TEXTVIEW ALSO
|
|
129
|
+
# saves current or n lines into kill ring, appending to earlier contents
|
|
130
|
+
# Use yank (paste) or yank-pop to retrieve
|
|
131
|
+
def kill_ring_save
|
|
132
|
+
pointer = @current_index
|
|
133
|
+
list = []
|
|
134
|
+
repeatm {
|
|
135
|
+
line = @list[pointer]
|
|
136
|
+
list << line unless line.nil?
|
|
137
|
+
pointer += 1
|
|
138
|
+
}
|
|
139
|
+
add_to_kill_ring list
|
|
140
|
+
end
|
|
141
|
+
## THIS ONE SHOULD BE IN TEXTVIEW ALSO
|
|
142
|
+
# add given line or lines to kill_ring
|
|
143
|
+
def add_to_kill_ring list
|
|
144
|
+
# directly referenceing kill_ring. We need to OO it a bit, so we can change internals w'o breaking all.
|
|
145
|
+
# FIXME
|
|
146
|
+
if $append_next_kill
|
|
147
|
+
# user requested this kill to be appened to last kill, so it can be yanked as one
|
|
148
|
+
#$kill_ring.last << list
|
|
149
|
+
last = $kill_ring.pop
|
|
150
|
+
$log.debug "YANK: addto : last= #{last} , list= #{list} "
|
|
151
|
+
case list
|
|
152
|
+
when Array
|
|
153
|
+
#list.insert 0, last
|
|
154
|
+
list.insert 0, *last # 2011-10-10 changed as it was wrong in textarea
|
|
155
|
+
$kill_ring << list
|
|
156
|
+
when String
|
|
157
|
+
$kill_ring << [last, list]
|
|
158
|
+
end
|
|
159
|
+
else
|
|
160
|
+
$kill_ring << list
|
|
161
|
+
end
|
|
162
|
+
$kill_ring_pointer = $kill_ring.size
|
|
163
|
+
$append_next_kill = false
|
|
164
|
+
$log.debug "YANK: kill_ring: #{$kill_ring} "
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# pastes recent (last) entry of kill_ring.
|
|
168
|
+
# This can be one or more lines. Please note that for us vimmer's yank means copy
|
|
169
|
+
# but for emacsers it seems to mean paste. Aargh!!
|
|
170
|
+
# earlier it was not +1, it was pasting before not after
|
|
171
|
+
def yank where=@current_index+1
|
|
172
|
+
return -1 if !@editable
|
|
173
|
+
return if $kill_ring.empty?
|
|
174
|
+
row = $kill_ring.last
|
|
175
|
+
$log.debug "YANK: row #{row} "
|
|
176
|
+
index = where
|
|
177
|
+
case row
|
|
178
|
+
when Array
|
|
179
|
+
#index = @current_index
|
|
180
|
+
row.each{ |r|
|
|
181
|
+
@list.insert index, r.dup
|
|
182
|
+
index += 1
|
|
183
|
+
}
|
|
184
|
+
$kill_last_pop_size = row.size
|
|
185
|
+
when String
|
|
186
|
+
#@list[@current_index].insert row.dup
|
|
187
|
+
#@list.insert @current_index, row.dup
|
|
188
|
+
@list.insert index, row.dup
|
|
189
|
+
$kill_last_pop_size = 1
|
|
190
|
+
else
|
|
191
|
+
raise "textarea yank got uncertain datatype from kill_ring #{row.class} "
|
|
192
|
+
end
|
|
193
|
+
$kill_ring_pointer = $kill_ring.size - 1
|
|
194
|
+
$kill_ring_index = @current_index # pops will replace data in this row, never an insert
|
|
195
|
+
@repaint_required = true
|
|
196
|
+
@widget_scrolled = true
|
|
197
|
+
# XXX not firing anything here, so i can't undo. yet, i don't know whether a yank will
|
|
198
|
+
# be followed by a yank-pop, in which case it will not be undone.
|
|
199
|
+
# object row can be string or array - time to use INSERT_LINE so we are clear
|
|
200
|
+
# row.length can be array's size or string length - beware
|
|
201
|
+
fire_handler :CHANGE, InputDataEvent.new(0,row.length, self, :INSERT_LINE, @current_index, row)
|
|
202
|
+
return 0 # don't want a UNHANDLED or NO_BLOCK going back
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# paste previous entries from kill ring
|
|
206
|
+
# I am not totally clear on this, not being an emacs user. but seems you have to do C-y
|
|
207
|
+
# once (yank) before you can do a yank pop.
|
|
208
|
+
def yank_pop
|
|
209
|
+
return -1 if !@editable
|
|
210
|
+
return if $kill_ring.empty?
|
|
211
|
+
mapped_key = @current_key # we are mapped to this
|
|
212
|
+
# checking that user has done a yank on this row. We only replace on the given row, never
|
|
213
|
+
# insert. But what if user edited after yank, Sheesh ! XXX
|
|
214
|
+
if $kill_ring_index != @current_index
|
|
215
|
+
Ncurses.beep
|
|
216
|
+
return # error message required that user must yank first
|
|
217
|
+
end
|
|
218
|
+
# the real reason i put this into a loop is so that i can properly undo the
|
|
219
|
+
# action later if required. I only need to store the final selection.
|
|
220
|
+
# This also ensures the user doesn't wander off in between and come back.
|
|
221
|
+
row = nil
|
|
222
|
+
while true
|
|
223
|
+
# remove lines from last replace, then insert
|
|
224
|
+
index = @current_index
|
|
225
|
+
$kill_last_pop_size.times {
|
|
226
|
+
del = @list.delete_at index
|
|
227
|
+
}
|
|
228
|
+
row = $kill_ring[$kill_ring_pointer-$multiplier]
|
|
229
|
+
$multiplier = 0
|
|
230
|
+
index = @current_index
|
|
231
|
+
case row
|
|
232
|
+
when Array
|
|
233
|
+
row.each{ |r|
|
|
234
|
+
@list.insert index, r.dup
|
|
235
|
+
index += 1
|
|
236
|
+
}
|
|
237
|
+
$kill_last_pop_size = row.size
|
|
238
|
+
when String
|
|
239
|
+
@list.insert index, row.dup
|
|
240
|
+
$kill_last_pop_size = 1
|
|
241
|
+
else
|
|
242
|
+
raise "textarea yank_pop got uncertain datatype from kill_ring #{row.class} "
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
$kill_ring_pointer -= 1
|
|
246
|
+
if $kill_ring_pointer < 0
|
|
247
|
+
# should be size, but that'll give an error. need to find a way!
|
|
248
|
+
$kill_ring_pointer = $kill_ring.size - 1
|
|
249
|
+
end
|
|
250
|
+
@repaint_required = true
|
|
251
|
+
@widget_scrolled = true
|
|
252
|
+
my_win = @form || @parent_component.form # 2010-02-12 12:51
|
|
253
|
+
my_win.repaint
|
|
254
|
+
ch = @graphic.getchar
|
|
255
|
+
if ch != mapped_key
|
|
256
|
+
@graphic.ungetch ch # seems to work fine
|
|
257
|
+
return ch # XXX to be picked up by handle_key loop and processed
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
# object row can be string or array - time to use INSERT_LINE so we are clear
|
|
261
|
+
# row.length can be array's size or string length - beware
|
|
262
|
+
fire_handler :CHANGE, InputDataEvent.new(0,row.length, self, :INSERT_LINE, @current_index, row)
|
|
263
|
+
return 0
|
|
264
|
+
end
|
|
265
|
+
def append_next_kill
|
|
266
|
+
$append_next_kill = true
|
|
267
|
+
end
|
|
268
|
+
# deletes count words on current line
|
|
269
|
+
# Does not at this point go beyond the line
|
|
270
|
+
def delete_word
|
|
271
|
+
return -1 unless @editable
|
|
272
|
+
$multiplier = 1 if !$multiplier || $multiplier == 0
|
|
273
|
+
line = @current_index
|
|
274
|
+
pos = @curpos
|
|
275
|
+
@delete_buffer = ""
|
|
276
|
+
# currently only look in current line
|
|
277
|
+
$multiplier.times {
|
|
278
|
+
found = @buffer.index(/[[:punct:][:space:]]/, pos)
|
|
279
|
+
break if !found
|
|
280
|
+
$log.debug " delete_word: pos #{pos} found #{found} buff: #{@buffer} "
|
|
281
|
+
@delete_buffer << @buffer.slice!(pos..found)
|
|
282
|
+
}
|
|
283
|
+
return if @delete_buffer == ""
|
|
284
|
+
$log.debug " delete_word: delbuff #{@delete_buffer} "
|
|
285
|
+
add_to_kill_ring @delete_buffer
|
|
286
|
+
fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos+@delete_buffer.length, self, :DELETE, line, @delete_buffer) # 2008-12-24 18:34
|
|
287
|
+
set_modified
|
|
288
|
+
end
|
|
289
|
+
##
|
|
290
|
+
# deletes forward till the occurence of a character
|
|
291
|
+
# it gets the char from the user
|
|
292
|
+
# Should we pass in the character (and accept it as a separate func) ???
|
|
293
|
+
def delete_forward
|
|
294
|
+
return -1 unless @editable
|
|
295
|
+
ch = @graphic.getchar
|
|
296
|
+
return if ch < 0 || ch > 255
|
|
297
|
+
char = ch.chr
|
|
298
|
+
$multiplier = 1 if !$multiplier || $multiplier == 0
|
|
299
|
+
line = @current_index
|
|
300
|
+
pos = @curpos
|
|
301
|
+
tmpbuf = ""
|
|
302
|
+
# currently only look in current line
|
|
303
|
+
$multiplier.times {
|
|
304
|
+
found = @buffer.index(char, pos)
|
|
305
|
+
break if !found
|
|
306
|
+
#$log.debug " delete_forward: pos #{pos} found #{found} buff: #{@buffer} "
|
|
307
|
+
# ideally do this in one shot outside loop, but its okay here for now
|
|
308
|
+
tmpbuf << @buffer.slice!(pos..found)
|
|
309
|
+
}
|
|
310
|
+
return if tmpbuf == ""
|
|
311
|
+
@delete_buffer = tmpbuf
|
|
312
|
+
$log.debug " delete_forward: delbuff #{@delete_buffer} "
|
|
313
|
+
add_to_kill_ring @delete_buffer
|
|
314
|
+
fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos+@delete_buffer.length, self, :DELETE, line, @delete_buffer) # 2008-12-24 18:34
|
|
315
|
+
set_modified
|
|
316
|
+
$multiplier = 0
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
end # end module
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Some methods for traversing list like widgets such as tree, listbox and maybe table
|
|
2
|
+
# Different components may bind different keys to these
|
|
3
|
+
#
|
|
4
|
+
module Canis
|
|
5
|
+
module ListOperations
|
|
6
|
+
|
|
7
|
+
# get a char ensure it is a char or number
|
|
8
|
+
# In this state, it could accept control and other chars.
|
|
9
|
+
private
|
|
10
|
+
def _ask_a_char
|
|
11
|
+
ch = @graphic.getch
|
|
12
|
+
#message "achar is #{ch}"
|
|
13
|
+
if ch < 26 || ch > 255
|
|
14
|
+
@graphic.ungetch ch
|
|
15
|
+
return :UNHANDLED
|
|
16
|
+
end
|
|
17
|
+
return ch.chr
|
|
18
|
+
end
|
|
19
|
+
public
|
|
20
|
+
# sets the selection to the next row starting with char
|
|
21
|
+
# Trying to return unhandled is having no effect right now. if only we could pop it into a
|
|
22
|
+
# stack or unget it.
|
|
23
|
+
def set_selection_for_char char=nil
|
|
24
|
+
char = _ask_a_char unless char
|
|
25
|
+
#alert "got #{char} "
|
|
26
|
+
return :UNHANDLED if char == :UNHANDLED
|
|
27
|
+
@oldrow = @current_index
|
|
28
|
+
@last_regex = /^#{char}/
|
|
29
|
+
ix = next_regex @last_regex
|
|
30
|
+
#alert "next returned #{ix}"
|
|
31
|
+
return unless ix
|
|
32
|
+
@current_index = ix[0]
|
|
33
|
+
@search_found_ix = @current_index
|
|
34
|
+
@curpos = ix[1]
|
|
35
|
+
ensure_visible
|
|
36
|
+
return @current_index
|
|
37
|
+
end
|
|
38
|
+
# Find the next row that contains given string
|
|
39
|
+
# @return row and col offset of match, or nil
|
|
40
|
+
# @param String to find
|
|
41
|
+
def next_regex str
|
|
42
|
+
first = nil
|
|
43
|
+
## content can be string or Chunkline, so we had to write <tt>index</tt> for this.
|
|
44
|
+
## =~ does not give an error, but it does not work.
|
|
45
|
+
@list.each_with_index do |line, ix|
|
|
46
|
+
#col = line.index str
|
|
47
|
+
# for treemodel which will give us user_object.to_s
|
|
48
|
+
col = line.to_s.index str
|
|
49
|
+
if col
|
|
50
|
+
first ||= [ ix, col ]
|
|
51
|
+
if ix > @current_index
|
|
52
|
+
return [ix, col]
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
return first
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
end # end module
|
|
61
|
+
end # end module
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
#!/usr/bin/env ruby -w
|
|
2
|
+
# ----------------------------------------------------------------------------- #
|
|
3
|
+
# File: listselectionmodel.rb
|
|
4
|
+
# Description: Used by textpad derivates to give selection of rows
|
|
5
|
+
# Author: j kepler http://github.com/mare-imbrium/canis/
|
|
6
|
+
# Date: 2014-04-10 - 21:04
|
|
7
|
+
# License: Same as ruby license
|
|
8
|
+
# Last update: 2014-07-07 00:36
|
|
9
|
+
# ----------------------------------------------------------------------------- #
|
|
10
|
+
# listselectionmodel.rb Copyright (C) 2012-2014 j kepler
|
|
11
|
+
# ----------------------------------------------------------------------------- #
|
|
12
|
+
#
|
|
13
|
+
require 'forwardable'
|
|
14
|
+
|
|
15
|
+
# The +DefaultListSelection+ mixin provides Textpad derived classes with
|
|
16
|
+
# selection methods and bindings.
|
|
17
|
+
# == Example
|
|
18
|
+
# Inside the constructor of the multiline object use the following line, before the call to `super()`
|
|
19
|
+
#
|
|
20
|
+
# self.extend DefaultListSelection
|
|
21
|
+
#
|
|
22
|
+
# At any other portion, for example after the call to `super()` you may set the
|
|
23
|
+
# default model if the user has not done so in the calling block
|
|
24
|
+
#
|
|
25
|
+
# @list_selection_model ||= Canis::DefaultListSelectionModel.new self
|
|
26
|
+
#
|
|
27
|
+
# When clearing data, as in `clear`, +selected_indices+ should also be cleared.
|
|
28
|
+
#
|
|
29
|
+
# == Note
|
|
30
|
+
#
|
|
31
|
+
# This module does not take care of rendering a selected row. This must still be handled
|
|
32
|
+
# by the default or custom renderer using `is_row_selected?`.
|
|
33
|
+
#
|
|
34
|
+
# Note that changing the order of data, or deleting, inserting etc will not correct the selection
|
|
35
|
+
# indices. Indices are assumed to be stable, and they may be cleared using `clear` on +@selected_indices+
|
|
36
|
+
# if the data indices change.
|
|
37
|
+
#
|
|
38
|
+
module Canis
|
|
39
|
+
extend self
|
|
40
|
+
module DefaultListSelection
|
|
41
|
+
def self.extended(obj)
|
|
42
|
+
extend Forwardable
|
|
43
|
+
# selection modes may be :multiple, :single or :none
|
|
44
|
+
dsl_accessor :selection_mode
|
|
45
|
+
# color of selected rows, and attribute of selected rows
|
|
46
|
+
dsl_accessor :selected_color, :selected_bgcolor, :selected_attr
|
|
47
|
+
# indices of selected rows
|
|
48
|
+
dsl_accessor :selected_indices
|
|
49
|
+
# model that takes care of selection operations
|
|
50
|
+
dsl_accessor :list_selection_model
|
|
51
|
+
#
|
|
52
|
+
# all operations of selection are delegated to the ListSelectionModel
|
|
53
|
+
def_delegators :@list_selection_model, :is_row_selected?, :toggle_row_selection, :select, :unselect, :is_selection_empty?, :clear_selection, :selected_rows, :select_all, :selected_values, :selected_value
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
obj.instance_exec {
|
|
57
|
+
@selected_indices = []
|
|
58
|
+
@selection_mode = :multiple # default is multiple intervals
|
|
59
|
+
#@list_selection_model = DefaultListSelectionModel.new obj
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
end # mod DefaultListSelection
|
|
64
|
+
# Whenever user selects one or more rows, this object is sent via event
|
|
65
|
+
# giving start row and last row of selection, object
|
|
66
|
+
# and type which is :INSERT :DELETE :CLEAR
|
|
67
|
+
class ListSelectionEvent < Struct.new(:firstrow, :lastrow, :source, :type)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
##
|
|
71
|
+
# Object that takes care of selection of rows.
|
|
72
|
+
# This may be replace with a custom object at time of instantiation of list
|
|
73
|
+
# Note that there are only two selection modes: single and multiple.
|
|
74
|
+
# Multiple refers to multiple intervals. There is also a multiple row selection
|
|
75
|
+
# mode, single interval, which only allows one range to be selected, much like a
|
|
76
|
+
# text object, i.e. any text editor.
|
|
77
|
+
#
|
|
78
|
+
## I am copying this from listselectable. that was a module so was included and shared variables
|
|
79
|
+
# but now this is a class, and cannot access state as directly
|
|
80
|
+
|
|
81
|
+
class DefaultListSelectionModel
|
|
82
|
+
|
|
83
|
+
def initialize component
|
|
84
|
+
raise "Components passed to DefaultListSelectionModel is nil" unless component
|
|
85
|
+
@obj = component
|
|
86
|
+
|
|
87
|
+
@selected_indices = @obj.selected_indices
|
|
88
|
+
# in this case since it is called immediately upon extend, user cannot change this
|
|
89
|
+
# Need a method to let user change after extending
|
|
90
|
+
@selection_mode = @obj.selection_mode
|
|
91
|
+
list_bindings
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# change selection of current row on pressing space bar (or keybinding)
|
|
95
|
+
# If mode is multiple, then this row is added to previous selections
|
|
96
|
+
# @example
|
|
97
|
+
# bind_key(32) { toggle_row_selection }
|
|
98
|
+
#
|
|
99
|
+
#
|
|
100
|
+
def toggle_row_selection crow=@obj.current_index
|
|
101
|
+
@last_clicked = crow
|
|
102
|
+
@repaint_required = true
|
|
103
|
+
case @obj.selection_mode
|
|
104
|
+
when :multiple
|
|
105
|
+
if @selected_indices.include? crow
|
|
106
|
+
@selected_indices.delete crow
|
|
107
|
+
lse = ListSelectionEvent.new(crow, crow, @obj, :DELETE)
|
|
108
|
+
@obj.fire_handler :LIST_SELECTION_EVENT, lse
|
|
109
|
+
else
|
|
110
|
+
@selected_indices << crow
|
|
111
|
+
lse = ListSelectionEvent.new(crow, crow, @obj, :INSERT)
|
|
112
|
+
@obj.fire_handler :LIST_SELECTION_EVENT, lse
|
|
113
|
+
end
|
|
114
|
+
else
|
|
115
|
+
# single - now change to use array only
|
|
116
|
+
@selected_index = @selected_indices[0]
|
|
117
|
+
if @selected_index == crow
|
|
118
|
+
@old_selected_index = @selected_index # 2011-10-15 so we can unhighlight
|
|
119
|
+
@selected_index = nil
|
|
120
|
+
@selected_indices.clear
|
|
121
|
+
lse = ListSelectionEvent.new(crow, crow, @obj, :DELETE)
|
|
122
|
+
@obj.fire_handler :LIST_SELECTION_EVENT, lse
|
|
123
|
+
else
|
|
124
|
+
@selected_indices[0] = crow
|
|
125
|
+
@obj.fire_row_changed(@old_selected_index) if @old_selected_index
|
|
126
|
+
@old_selected_index = crow # 2011-10-15 so we can unhighlight
|
|
127
|
+
lse = ListSelectionEvent.new(crow, crow, @obj, :INSERT)
|
|
128
|
+
@obj.fire_handler :LIST_SELECTION_EVENT, lse
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
@obj.fire_row_changed crow
|
|
132
|
+
#alert "toggling #{@selected_indices.join(',')}"
|
|
133
|
+
end
|
|
134
|
+
#
|
|
135
|
+
# Range select.
|
|
136
|
+
# Only for multiple mode.
|
|
137
|
+
# Uses the last row clicked on, till the current one.
|
|
138
|
+
# If user clicks inside a selcted range, then deselect from last click till current (remove from earlier)
|
|
139
|
+
# If user clicks outside selected range, then select from last click till current (add to earlier)
|
|
140
|
+
# typically bound to Ctrl-Space (0)
|
|
141
|
+
#
|
|
142
|
+
# @example
|
|
143
|
+
#
|
|
144
|
+
# bind_key(0) { range_select }
|
|
145
|
+
#
|
|
146
|
+
def range_select crow=@obj.current_index
|
|
147
|
+
#alert "add to selection fired #{@last_clicked}"
|
|
148
|
+
@last_clicked ||= crow
|
|
149
|
+
min = [@last_clicked, crow].min
|
|
150
|
+
max = [@last_clicked, crow].max
|
|
151
|
+
case @obj.selection_mode
|
|
152
|
+
when :multiple
|
|
153
|
+
if @selected_indices.include? crow
|
|
154
|
+
# delete from last_clicked until this one in any direction
|
|
155
|
+
min.upto(max){ |i| @selected_indices.delete i
|
|
156
|
+
@obj.fire_row_changed i
|
|
157
|
+
}
|
|
158
|
+
lse = ListSelectionEvent.new(min, max, @obj, :DELETE)
|
|
159
|
+
@obj.fire_handler :LIST_SELECTION_EVENT, lse
|
|
160
|
+
else
|
|
161
|
+
# add to selection from last_clicked until this one in any direction
|
|
162
|
+
min.upto(max){ |i| @selected_indices << i unless @selected_indices.include?(i)
|
|
163
|
+
@obj.fire_row_changed i
|
|
164
|
+
}
|
|
165
|
+
lse = ListSelectionEvent.new(min, max, @obj, :INSERT)
|
|
166
|
+
@obj.fire_handler :LIST_SELECTION_EVENT, lse
|
|
167
|
+
end
|
|
168
|
+
else
|
|
169
|
+
end
|
|
170
|
+
@last_clicked = crow # 2014-04-08 - 01:21 this was missing, i think it is required
|
|
171
|
+
self
|
|
172
|
+
end
|
|
173
|
+
# clears selected indices, typically called when multiple select
|
|
174
|
+
# Key binding is application specific
|
|
175
|
+
def clear_selection
|
|
176
|
+
return if @selected_indices.nil? || @selected_indices.empty?
|
|
177
|
+
arr = @selected_indices.dup # to un highlight
|
|
178
|
+
@selected_indices.clear
|
|
179
|
+
arr.each {|i| @obj.fire_row_changed(i) }
|
|
180
|
+
@selected_index = nil
|
|
181
|
+
@old_selected_index = nil
|
|
182
|
+
# User should ignore first two params
|
|
183
|
+
lse = ListSelectionEvent.new(0, arr.size, @obj, :CLEAR)
|
|
184
|
+
@obj.fire_handler :LIST_SELECTION_EVENT, lse
|
|
185
|
+
arr = nil
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# returns +true+ if given row has been selected
|
|
189
|
+
# Now that we use only the array, the multiple check is good enough
|
|
190
|
+
def is_row_selected? crow
|
|
191
|
+
case @obj.selection_mode
|
|
192
|
+
when :multiple
|
|
193
|
+
@selected_indices.include? crow
|
|
194
|
+
else
|
|
195
|
+
@selected_index = @selected_indices[0]
|
|
196
|
+
crow == @selected_index
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
alias :is_selected? is_row_selected?
|
|
200
|
+
|
|
201
|
+
# after selecting, traverse selections forward
|
|
202
|
+
def goto_next_selection
|
|
203
|
+
return if selected_rows().length == 0
|
|
204
|
+
row = selected_rows().sort.find { |i| i > @obj.current_index }
|
|
205
|
+
row ||= @obj.current_index
|
|
206
|
+
#@obj.current_index = row
|
|
207
|
+
@obj.goto_line row
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# after selecting, traverse selections backward
|
|
211
|
+
def goto_prev_selection
|
|
212
|
+
return if selected_rows().length == 0
|
|
213
|
+
row = selected_rows().sort{|a,b| b <=> a}.find { |i| i < @obj.current_index }
|
|
214
|
+
row ||= @obj.current_index
|
|
215
|
+
#@obj.current_index = row
|
|
216
|
+
@obj.goto_line row
|
|
217
|
+
end
|
|
218
|
+
# add the following range to selected items, unless already present
|
|
219
|
+
# should only be used if multiple selection interval
|
|
220
|
+
def add_row_selection_interval ix0, ix1
|
|
221
|
+
return if @obj.selection_mode != :multiple
|
|
222
|
+
@anchor_selection_index = ix0
|
|
223
|
+
@lead_selection_index = ix1
|
|
224
|
+
ix0.upto(ix1) {|i|
|
|
225
|
+
@selected_indices << i unless @selected_indices.include? i
|
|
226
|
+
@obj.fire_row_changed i
|
|
227
|
+
}
|
|
228
|
+
lse = ListSelectionEvent.new(ix0, ix1, @obj, :INSERT)
|
|
229
|
+
@obj.fire_handler :LIST_SELECTION_EVENT, lse
|
|
230
|
+
#$log.debug " DLSM firing LIST_SELECTION EVENT #{lse}"
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# remove selected indices between given indices inclusive
|
|
234
|
+
def remove_row_selection_interval ix0, ix1
|
|
235
|
+
@anchor_selection_index = ix0
|
|
236
|
+
@lead_selection_index = ix1
|
|
237
|
+
arr = @selected_indices.dup # to un highlight
|
|
238
|
+
@selected_indices.delete_if {|x| x >= ix0 and x <= ix1 }
|
|
239
|
+
arr.each {|i| @obj.fire_row_changed(i) }
|
|
240
|
+
lse = ListSelectionEvent.new(ix0, ix1, @obj, :DELETE)
|
|
241
|
+
@obj.fire_handler :LIST_SELECTION_EVENT, lse
|
|
242
|
+
end
|
|
243
|
+
# convenience method to select next len rows
|
|
244
|
+
def insert_index_interval ix0, len
|
|
245
|
+
@anchor_selection_index = ix0
|
|
246
|
+
@lead_selection_index = ix0+len
|
|
247
|
+
add_row_selection_interval @anchor_selection_index, @lead_selection_index
|
|
248
|
+
end
|
|
249
|
+
# select all rows, you may specify starting row.
|
|
250
|
+
# if header row, then 1 else should be 0. Actually we should have a way to determine
|
|
251
|
+
# this, and the default should be zero.
|
|
252
|
+
def select_all start_row=0 #+@_header_adjustment
|
|
253
|
+
# don't select header row - need to make sure this works for all cases. we may
|
|
254
|
+
# need a variable instead of hardoded value
|
|
255
|
+
add_row_selection_interval start_row, @obj.list.count()-1
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# toggle selection of entire list
|
|
259
|
+
# Requires application specific key binding
|
|
260
|
+
def invert_selection start_row=0 #+@_header_adjustment
|
|
261
|
+
start_row.upto(@obj.list.count()-1){|i| invert_row_selection i }
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# toggles selection for given row
|
|
265
|
+
# Typically called by invert_selection
|
|
266
|
+
def invert_row_selection row=@obj.current_index
|
|
267
|
+
@repaint_required = true
|
|
268
|
+
if is_selected? row
|
|
269
|
+
remove_row_selection_interval(row, row)
|
|
270
|
+
else
|
|
271
|
+
add_row_selection_interval(row, row)
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
# selects all rows with the values given, leaving existing selections
|
|
275
|
+
# intact. Typically used after accepting search criteria, and getting a list of values
|
|
276
|
+
# to select (such as file names). Will not work with tables (array or array)
|
|
277
|
+
# TODO is this even needed, scrap
|
|
278
|
+
def select_values values
|
|
279
|
+
return unless values
|
|
280
|
+
values.each do |val|
|
|
281
|
+
row = @list.index val
|
|
282
|
+
add_row_selection_interval row, row unless row.nil?
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
# TODO is this even needed, scrap
|
|
286
|
+
# unselects all rows with the values given, leaving all other rows intact
|
|
287
|
+
# You can map "-" to ask_select and call this from there.
|
|
288
|
+
# bind_key(?+, :ask_select) # --> calls select_values
|
|
289
|
+
# bind_key(?-, :ask_unselect)
|
|
290
|
+
def unselect_values values
|
|
291
|
+
return unless values
|
|
292
|
+
values.each do |val|
|
|
293
|
+
row = @list.index val
|
|
294
|
+
remove_row_selection_interval row, row unless row.nil?
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
#
|
|
298
|
+
# Asks user to enter a string or pattern for selecting rows
|
|
299
|
+
# Selects rows based on pattern, leaving other selections as-is
|
|
300
|
+
def ask_select prompt="Enter selection pattern: "
|
|
301
|
+
ret = get_string prompt
|
|
302
|
+
return if ret.nil? || ret == ""
|
|
303
|
+
indices = get_matching_indices ret
|
|
304
|
+
#$log.debug "listselectionmodel: ask_select got matches#{@indices} "
|
|
305
|
+
return if indices.nil? || indices.empty?
|
|
306
|
+
indices.each { |e|
|
|
307
|
+
# will not work if single select !! FIXME
|
|
308
|
+
add_row_selection_interval e,e
|
|
309
|
+
}
|
|
310
|
+
end
|
|
311
|
+
# returns a list of matching indices using a simple regex match on given pattern
|
|
312
|
+
# returns an empty list if no match
|
|
313
|
+
def get_matching_indices pattern
|
|
314
|
+
matches = []
|
|
315
|
+
@obj.content.each_with_index { |e,i|
|
|
316
|
+
# convert to string for tables
|
|
317
|
+
e = e.to_s unless e.is_a? String
|
|
318
|
+
if e =~ /#{pattern}/
|
|
319
|
+
matches << i
|
|
320
|
+
end
|
|
321
|
+
}
|
|
322
|
+
return matches
|
|
323
|
+
end
|
|
324
|
+
# Asks user to enter a string or pattern for UNselecting rows
|
|
325
|
+
# UNSelects rows based on pattern, leaving other selections as-is
|
|
326
|
+
def ask_unselect prompt="Enter selection pattern: "
|
|
327
|
+
ret = get_string prompt
|
|
328
|
+
return if ret.nil? || ret == ""
|
|
329
|
+
indices = get_matching_indices ret
|
|
330
|
+
return if indices.nil? || indices.empty?
|
|
331
|
+
indices.each { |e|
|
|
332
|
+
# will not work if single select !! FIXME
|
|
333
|
+
remove_row_selection_interval e,e
|
|
334
|
+
}
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
##
|
|
338
|
+
# bindings related to selection
|
|
339
|
+
#
|
|
340
|
+
def list_bindings
|
|
341
|
+
# freeing space for paging, now trying out 'v' as selector. 2014-04-14 - 18:57
|
|
342
|
+
@obj.bind_key($row_selector || 'v'.ord, 'toggle selection') { toggle_row_selection }
|
|
343
|
+
|
|
344
|
+
# the mode may be set to single after the constructor, so this would have taken effect.
|
|
345
|
+
if @obj.selection_mode == :multiple
|
|
346
|
+
# freeing ctrl_space for back paging, now trying out 'V' as selector. 2014-04-14 - 18:57
|
|
347
|
+
@obj.bind_key($range_selector || 'V'.ord, 'range select') { range_select }
|
|
348
|
+
@obj.bind_key(?+, 'ask_select') { ask_select }
|
|
349
|
+
@obj.bind_key(?-, 'ask_unselect') { ask_unselect }
|
|
350
|
+
@obj.bind_key(?a, 'select_all') {select_all}
|
|
351
|
+
@obj.bind_key(?*, 'invert_selection') { invert_selection }
|
|
352
|
+
@obj.bind_key(?u, 'clear_selection') { clear_selection }
|
|
353
|
+
@obj.bind_key([?g,?n], 'goto next selection'){ goto_next_selection } # mapping double keys like vim
|
|
354
|
+
@obj.bind_key([?g,?p], 'goto prev selection'){ goto_prev_selection } # mapping double keys like vim
|
|
355
|
+
end
|
|
356
|
+
@_header_adjustment ||= 0 # incase caller does not use
|
|
357
|
+
#@obj._events << :LIST_SELECTION_EVENT unless @obj._events.include? :LIST_SELECTION_EVENT
|
|
358
|
+
end
|
|
359
|
+
def list_init_vars
|
|
360
|
+
# uncommenting since link with obj will be broken
|
|
361
|
+
#@selected_indices = []
|
|
362
|
+
@selected_index = nil
|
|
363
|
+
@old_selected_index = nil
|
|
364
|
+
#@row_selected_symbol = ''
|
|
365
|
+
## FIXME we are not doing selectors at present. should we, else remove this
|
|
366
|
+
if @show_selector
|
|
367
|
+
@row_selected_symbol ||= '*'
|
|
368
|
+
@row_unselected_symbol ||= ' '
|
|
369
|
+
@left_margin ||= @row_selected_symbol.length
|
|
370
|
+
end
|
|
371
|
+
end
|
|
372
|
+
# return the indices selected
|
|
373
|
+
def selected_rows
|
|
374
|
+
@selected_indices
|
|
375
|
+
end
|
|
376
|
+
# return the values selected
|
|
377
|
+
def selected_values
|
|
378
|
+
@obj.values_at(*@selected_indices)
|
|
379
|
+
end
|
|
380
|
+
# returns first selection, meant for convenience of single select listboxes
|
|
381
|
+
# earlier called selected_item
|
|
382
|
+
def selected_value
|
|
383
|
+
return nil if @selected_indices.empty?
|
|
384
|
+
@obj[@selected_indices.first]
|
|
385
|
+
#selected_values.first
|
|
386
|
+
end
|
|
387
|
+
end # class
|
|
388
|
+
end # mod Canis
|