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,264 @@
|
|
1
|
+
# File created: 2010-10-29 14:09
|
2
|
+
# Author : rkumar
|
3
|
+
#
|
4
|
+
# this is a new, simpler version of listselectable
|
5
|
+
# the original gets into models and has complicated operation as well
|
6
|
+
# as difficult to remember method names. This attempts to be a simple plugin.
|
7
|
+
# Currently being used by rbasiclistbox (rlist) and now tabularwidget.
|
8
|
+
# NOTE: pls define @_header_adjustment to 0 if you don't use it or know what it means.
|
9
|
+
# TODO: of course we need to fire events so user can do something.
|
10
|
+
module RubyCurses
|
11
|
+
module NewListSelectable
|
12
|
+
|
13
|
+
# @group selection related
|
14
|
+
|
15
|
+
# change selection of current row on pressing space bar
|
16
|
+
# If mode is multiple, then other selections are cleared and this is added
|
17
|
+
# @example
|
18
|
+
# bind_key(32) { toggle_row_selection }
|
19
|
+
# current_index is not account for header_adjustment
|
20
|
+
# if current row is selected in mulitple we should deselect ?? FIXME
|
21
|
+
def toggle_row_selection crow=@current_index-@_header_adjustment
|
22
|
+
@last_clicked = crow
|
23
|
+
@repaint_required = true
|
24
|
+
case @selection_mode
|
25
|
+
when :multiple
|
26
|
+
@widget_scrolled = true # FIXME we need a better name
|
27
|
+
if @selected_indices.include? crow
|
28
|
+
@selected_indices.delete crow
|
29
|
+
lse = ListSelectionEvent.new(crow, crow, self, :DELETE)
|
30
|
+
fire_handler :LIST_SELECTION_EVENT, lse
|
31
|
+
else
|
32
|
+
@selected_indices << crow
|
33
|
+
lse = ListSelectionEvent.new(crow, crow, self, :INSERT)
|
34
|
+
fire_handler :LIST_SELECTION_EVENT, lse
|
35
|
+
end
|
36
|
+
else
|
37
|
+
if @selected_index == crow
|
38
|
+
@old_selected_index = @selected_index # 2011-10-15 so we can unhighlight
|
39
|
+
@selected_index = nil
|
40
|
+
lse = ListSelectionEvent.new(crow, crow, self, :DELETE)
|
41
|
+
fire_handler :LIST_SELECTION_EVENT, lse
|
42
|
+
else
|
43
|
+
@old_selected_index = @selected_index # 2011-10-15 so we can unhighlight
|
44
|
+
@selected_index = crow
|
45
|
+
lse = ListSelectionEvent.new(crow, crow, self, :INSERT)
|
46
|
+
fire_handler :LIST_SELECTION_EVENT, lse
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
#
|
51
|
+
# Only for multiple mode.
|
52
|
+
# add an item to selection, if selection mode is multiple
|
53
|
+
# if item already selected, it is deselected, else selected
|
54
|
+
# typically bound to Ctrl-Space
|
55
|
+
# @example
|
56
|
+
# bind_key(0) { add_to_selection }
|
57
|
+
def add_to_selection crow=@current_index-@_header_adjustment
|
58
|
+
@last_clicked ||= crow
|
59
|
+
min = [@last_clicked, crow].min
|
60
|
+
max = [@last_clicked, crow].max
|
61
|
+
case @selection_mode
|
62
|
+
when :multiple
|
63
|
+
@widget_scrolled = true # FIXME we need a better name
|
64
|
+
if @selected_indices.include? crow
|
65
|
+
# delete from last_clicked until this one in any direction
|
66
|
+
min.upto(max){ |i| @selected_indices.delete i }
|
67
|
+
lse = ListSelectionEvent.new(min, max, self, :DELETE)
|
68
|
+
fire_handler :LIST_SELECTION_EVENT, lse
|
69
|
+
else
|
70
|
+
# add to selection from last_clicked until this one in any direction
|
71
|
+
min.upto(max){ |i| @selected_indices << i unless @selected_indices.include?(i) }
|
72
|
+
lse = ListSelectionEvent.new(min, max, self, :INSERT)
|
73
|
+
fire_handler :LIST_SELECTION_EVENT, lse
|
74
|
+
end
|
75
|
+
else
|
76
|
+
end
|
77
|
+
@repaint_required = true
|
78
|
+
self
|
79
|
+
end
|
80
|
+
# clears selected indices, typically called when multiple select
|
81
|
+
# Key binding is application specific
|
82
|
+
def clear_selection
|
83
|
+
return if @selected_indices.nil? || @selected_indices.empty?
|
84
|
+
@selected_indices = []
|
85
|
+
@selected_index = nil
|
86
|
+
@old_selected_index = nil
|
87
|
+
# Not sure what event type I should give, DELETE or a new one, user should
|
88
|
+
# understand that selection has been cleared, and ignore first two params
|
89
|
+
lse = ListSelectionEvent.new(0, @list.size, self, :CLEAR)
|
90
|
+
fire_handler :LIST_SELECTION_EVENT, lse
|
91
|
+
@repaint_required = true
|
92
|
+
@widget_scrolled = true # FIXME we need a better name
|
93
|
+
end
|
94
|
+
def is_row_selected crow=@current_index-@_header_adjustment
|
95
|
+
case @selection_mode
|
96
|
+
when :multiple
|
97
|
+
@selected_indices.include? crow
|
98
|
+
else
|
99
|
+
crow == @selected_index
|
100
|
+
end
|
101
|
+
end
|
102
|
+
alias :is_selected? is_row_selected
|
103
|
+
# FIXME add adjustment and test
|
104
|
+
def goto_next_selection
|
105
|
+
return if selected_rows().length == 0
|
106
|
+
row = selected_rows().sort.find { |i| i > @current_index }
|
107
|
+
row ||= @current_index
|
108
|
+
@current_index = row
|
109
|
+
@repaint_required = true # fire list_select XXX
|
110
|
+
end
|
111
|
+
# FIXME add adjustment and test
|
112
|
+
def goto_prev_selection
|
113
|
+
return if selected_rows().length == 0
|
114
|
+
row = selected_rows().sort{|a,b| b <=> a}.find { |i| i < @current_index }
|
115
|
+
row ||= @current_index
|
116
|
+
@current_index = row
|
117
|
+
@repaint_required = true # fire list_select XXX
|
118
|
+
end
|
119
|
+
# add the following range to selected items, unless already present
|
120
|
+
# should only be used if multiple selection interval
|
121
|
+
def add_selection_interval ix0, ix1
|
122
|
+
return if @selection_mode != :multiple
|
123
|
+
@widget_scrolled = true # FIXME we need a better name
|
124
|
+
@anchor_selection_index = ix0
|
125
|
+
@lead_selection_index = ix1
|
126
|
+
ix0.upto(ix1) {|i| @selected_indices << i unless @selected_indices.include? i }
|
127
|
+
lse = ListSelectionEvent.new(ix0, ix1, self, :INSERT)
|
128
|
+
fire_handler :LIST_SELECTION_EVENT, lse
|
129
|
+
#$log.debug " DLSM firing LIST_SELECTION EVENT #{lse}"
|
130
|
+
end
|
131
|
+
alias :add_row_selection_interval :add_selection_interval
|
132
|
+
def remove_selection_interval ix0, ix1
|
133
|
+
@anchor_selection_index = ix0
|
134
|
+
@lead_selection_index = ix1
|
135
|
+
@selected_indices.delete_if {|x| x >= ix0 and x <= ix1}
|
136
|
+
lse = ListSelectionEvent.new(ix0, ix1, self, :DELETE)
|
137
|
+
fire_handler :LIST_SELECTION_EVENT, lse
|
138
|
+
end
|
139
|
+
alias :remove_row_selection_interval :remove_selection_interval
|
140
|
+
# convenience method to select next len rows
|
141
|
+
def insert_index_interval ix0, len
|
142
|
+
@anchor_selection_index = ix0
|
143
|
+
@lead_selection_index = ix0+len
|
144
|
+
add_selection_interval @anchor_selection_index, @lead_selection_index
|
145
|
+
end
|
146
|
+
# select all rows, you may specify starting row.
|
147
|
+
# if header row, then 1 else should be 0. Actually we should have a way to determine
|
148
|
+
# this, and the default should be zero.
|
149
|
+
def select_all start_row=0 #+@_header_adjustment
|
150
|
+
@repaint_required = true
|
151
|
+
# don't select header row - need to make sure this works for all cases. we may
|
152
|
+
# need a variable instead of hardoded value
|
153
|
+
add_row_selection_interval start_row, row_count()
|
154
|
+
end
|
155
|
+
def invert_selection start_row=0 #+@_header_adjustment
|
156
|
+
start_row.upto(row_count()){|i| invert_row_selection i }
|
157
|
+
end
|
158
|
+
|
159
|
+
def invert_row_selection row=@current_index-@_header_adjustment
|
160
|
+
@repaint_required = true
|
161
|
+
if is_selected? row
|
162
|
+
remove_row_selection_interval(row, row)
|
163
|
+
else
|
164
|
+
add_row_selection_interval(row, row)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
# selects all rows with the values given, leaving existing selections
|
168
|
+
# intact. Typically used after accepting search criteria, and getting a list of values
|
169
|
+
# to select (such as file names). Will not work with tables (array or array)
|
170
|
+
def select_values values
|
171
|
+
return unless values
|
172
|
+
values.each do |val|
|
173
|
+
row = @list.index val
|
174
|
+
add_row_selection_interval row, row unless row.nil?
|
175
|
+
end
|
176
|
+
end
|
177
|
+
# unselects all rows with the values given, leaving all other rows intact
|
178
|
+
# You can map "-" to ask_select and call this from there.
|
179
|
+
# bind_key(?+, :ask_select) # --> calls select_values
|
180
|
+
# bind_key(?-, :ask_unselect)
|
181
|
+
def unselect_values values
|
182
|
+
return unless values
|
183
|
+
values.each do |val|
|
184
|
+
row = @list.index val
|
185
|
+
remove_row_selection_interval row, row unless row.nil?
|
186
|
+
end
|
187
|
+
end
|
188
|
+
# please override this, this is just very basic and default
|
189
|
+
# Please implement get_matching_indices(String).
|
190
|
+
def ask_select prompt="Enter selection pattern: "
|
191
|
+
ret = ask(prompt, String) {|q| yield q if block_given? }
|
192
|
+
return if ret.nil? || ret == ""
|
193
|
+
indices = get_matching_indices ret
|
194
|
+
return if indices.nil? || indices.empty?
|
195
|
+
indices.each { |e|
|
196
|
+
# will not work if single select !! FIXME
|
197
|
+
add_row_selection_interval e,e
|
198
|
+
}
|
199
|
+
@repaint_required = true
|
200
|
+
end
|
201
|
+
def get_matching_indices pattern
|
202
|
+
alert "please implement this method get_matching_indices(pattern)->[] in your class "
|
203
|
+
return []
|
204
|
+
end # mod
|
205
|
+
# Applications may call this or just copy and modify
|
206
|
+
def list_bindings
|
207
|
+
# what about users wanting 32 and ENTER to also go to next row automatically
|
208
|
+
# should make that optional, TODO
|
209
|
+
bind_key(32, 'toggle selection') { toggle_row_selection }
|
210
|
+
bind_key(0, 'range select') { add_to_selection }
|
211
|
+
bind_key(?+, :ask_select) # --> calls select_values
|
212
|
+
bind_key(?-, :ask_unselect) # please implement FIXME TODO
|
213
|
+
bind_key(?a, :select_all)
|
214
|
+
bind_key(?*, :invert_selection)
|
215
|
+
bind_key(?u, :clear_selection)
|
216
|
+
@_header_adjustment ||= 0 # incase caller does not use
|
217
|
+
@_events << :LIST_SELECTION_EVENT unless @_events.include? :LIST_SELECTION_EVENT
|
218
|
+
end
|
219
|
+
def list_init_vars
|
220
|
+
@selected_indices = []
|
221
|
+
@selected_index = nil
|
222
|
+
@old_selected_index = nil
|
223
|
+
#@row_selected_symbol = ''
|
224
|
+
if @show_selector
|
225
|
+
@row_selected_symbol ||= '*'
|
226
|
+
@row_unselected_symbol ||= ' '
|
227
|
+
@left_margin ||= @row_selected_symbol.length
|
228
|
+
end
|
229
|
+
end
|
230
|
+
# paint the selector. Called from repaint, prior to printing data row
|
231
|
+
# remember to set left_margin at top of repaint method as:
|
232
|
+
# @left_margin ||= @row_selected_symbol.length
|
233
|
+
def paint_selector crow, r, c, acolor, attrib
|
234
|
+
selected = is_row_selected crow
|
235
|
+
selection_symbol = ''
|
236
|
+
if @show_selector
|
237
|
+
if selected
|
238
|
+
selection_symbol = @row_selected_symbol
|
239
|
+
else
|
240
|
+
selection_symbol = @row_unselected_symbol
|
241
|
+
end
|
242
|
+
@graphic.printstring r, c, selection_symbol, acolor,attrib
|
243
|
+
end
|
244
|
+
end
|
245
|
+
def selected_rows
|
246
|
+
@selected_indices
|
247
|
+
end
|
248
|
+
end # mod
|
249
|
+
class ListSelectionEvent
|
250
|
+
attr_accessor :firstrow, :lastrow, :source, :type
|
251
|
+
def initialize firstrow, lastrow, source, type
|
252
|
+
@firstrow = firstrow
|
253
|
+
@lastrow = lastrow
|
254
|
+
@source = source
|
255
|
+
@type = type
|
256
|
+
end
|
257
|
+
def to_s
|
258
|
+
"#{@type.to_s}, firstrow: #{@firstrow}, lastrow: #{@lastrow}, source: #{@source}"
|
259
|
+
end
|
260
|
+
def inspect
|
261
|
+
to_s
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end # mod
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module RubyCurses
|
2
|
+
# this module makes it possible for a textview to maintain multiple buffers
|
3
|
+
# The first buffer has been placed using set_content(lines, config).
|
4
|
+
# After this, additional buffers mst be supplied with add_content text, config.
|
5
|
+
# Also, please note that after you call set_content the first time, you must call
|
6
|
+
# add_content so the buffer can be accessed while cycling. will try to fix this.
|
7
|
+
# (I don't want to touch textview, would prefer not to write a decorator).
|
8
|
+
|
9
|
+
# TODO allow setting of a limit, so in some cases where we keep adding
|
10
|
+
# programatically, the
|
11
|
+
module MultiBuffers
|
12
|
+
extend self
|
13
|
+
|
14
|
+
# add content to buffers of a textview
|
15
|
+
# @param [Array] text
|
16
|
+
# @param [Hash] options, typically :content_type => :ansi or :tmux
|
17
|
+
def add_content text, config={}
|
18
|
+
unless @_buffers
|
19
|
+
bind_key(?\M-n, :buffer_next)
|
20
|
+
bind_key(?\M-p, :buffer_prev)
|
21
|
+
bind_key(KEY_BACKSPACE, :buffer_prev) # backspace, already hardcoded in textview !
|
22
|
+
bind_key(?:, :buffer_menu)
|
23
|
+
end
|
24
|
+
@_buffers ||= []
|
25
|
+
@_buffers_conf ||= []
|
26
|
+
@_buffers << text
|
27
|
+
@_buffers_conf << config
|
28
|
+
@_buffer_ctr ||= 0
|
29
|
+
$log.debug "XXX: HELP adding text #{@_buffers.size} "
|
30
|
+
end
|
31
|
+
|
32
|
+
# display next buffer
|
33
|
+
def buffer_next
|
34
|
+
@_buffer_ctr += 1
|
35
|
+
x = @_buffer_ctr
|
36
|
+
l = @_buffers[x]
|
37
|
+
@_buffer_ctr = 0 unless l
|
38
|
+
set_content @_buffers[@_buffer_ctr], @_buffers_conf[@_buffer_ctr]
|
39
|
+
end
|
40
|
+
#
|
41
|
+
# display previous buffer if any
|
42
|
+
def buffer_prev
|
43
|
+
if @_buffer_ctr < 1
|
44
|
+
buffer_last
|
45
|
+
return
|
46
|
+
end
|
47
|
+
@_buffer_ctr -= 1 if @_buffer_ctr > 0
|
48
|
+
x = @_buffer_ctr
|
49
|
+
l = @_buffers[x]
|
50
|
+
if l
|
51
|
+
set_content l, @_buffers_conf[x]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
def buffer_last
|
55
|
+
@_buffer_ctr = @_buffers.count - 1
|
56
|
+
l = @_buffers.last
|
57
|
+
set_content l, @_buffers_conf.last
|
58
|
+
end
|
59
|
+
# close window, a bit clever
|
60
|
+
def close
|
61
|
+
@graphic.ungetch(?q.ord)
|
62
|
+
end
|
63
|
+
# display a menu so user can do buffer management
|
64
|
+
# However, how can application add to these. Or disable, such as when we
|
65
|
+
# add buffer delete or buffer insert or edit
|
66
|
+
def buffer_menu
|
67
|
+
menu = PromptMenu.new self do
|
68
|
+
item :n, :buffer_next
|
69
|
+
item :p, :buffer_prev
|
70
|
+
item :b, :scroll_backward
|
71
|
+
item :f, :scroll_forward
|
72
|
+
item :q, :close
|
73
|
+
submenu :m, "submenu..." do
|
74
|
+
item :p, :goto_last_position
|
75
|
+
item :r, :scroll_right
|
76
|
+
item :l, :scroll_left
|
77
|
+
end
|
78
|
+
end
|
79
|
+
menu.display_new :title => "Buffer Menu"
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
## Insert order preserving hash
|
2
|
+
# Thanks to Bill Kelly, posted on http://www.ruby-forum.com/topic/166075
|
3
|
+
#
|
4
|
+
class OrderedHash
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def initialize(*args, &block)
|
8
|
+
@h = Hash.new(*args, &block)
|
9
|
+
@ordered_keys = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def []=(key, val)
|
13
|
+
@ordered_keys << key unless @h.has_key? key
|
14
|
+
@h[key] = val
|
15
|
+
end
|
16
|
+
|
17
|
+
def each
|
18
|
+
@ordered_keys.each {|k| yield(k, @h[k])}
|
19
|
+
end
|
20
|
+
alias :each_pair :each
|
21
|
+
|
22
|
+
def each_value
|
23
|
+
@ordered_keys.each {|k| yield(@h[k])}
|
24
|
+
end
|
25
|
+
|
26
|
+
def each_key
|
27
|
+
@ordered_keys.each {|k| yield k}
|
28
|
+
end
|
29
|
+
|
30
|
+
def keys
|
31
|
+
@ordered_keys
|
32
|
+
end
|
33
|
+
|
34
|
+
def values
|
35
|
+
@ordered_keys.map {|k| @h[k]}
|
36
|
+
end
|
37
|
+
|
38
|
+
def clear
|
39
|
+
@ordered_keys.clear
|
40
|
+
@h.clear
|
41
|
+
end
|
42
|
+
|
43
|
+
def delete(k, &block)
|
44
|
+
@ordered_keys.delete k
|
45
|
+
@h.delete(k, &block)
|
46
|
+
end
|
47
|
+
|
48
|
+
def reject!
|
49
|
+
del = []
|
50
|
+
each_pair {|k,v| del << k if yield k,v}
|
51
|
+
del.each {|k| delete k}
|
52
|
+
del.empty? ? nil : self
|
53
|
+
end
|
54
|
+
|
55
|
+
def delete_if(&block)
|
56
|
+
reject!(&block)
|
57
|
+
self
|
58
|
+
end
|
59
|
+
## added since the normal hash will give it in unordered. so debugging sucks
|
60
|
+
def inspect
|
61
|
+
out = []
|
62
|
+
each do | k,v |
|
63
|
+
out << " #{k} => #{v} "
|
64
|
+
end
|
65
|
+
res = %Q[ { #{out.join(",\n ")} } ]
|
66
|
+
end
|
67
|
+
|
68
|
+
%w(merge!).each do |name|
|
69
|
+
define_method(name) do |*args|
|
70
|
+
raise NotImplementedError, "#{name} not implemented"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def method_missing(*args)
|
75
|
+
@h.send(*args)
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
=begin
|
2
|
+
* Name: ActionEvent
|
3
|
+
* Description: Event used to notify interested parties that an action has happened on component
|
4
|
+
Usually a button press. Nothing more.
|
5
|
+
* Author: rkumar (arunachalesha)
|
6
|
+
|
7
|
+
--------
|
8
|
+
* Date: 2010-09-12 18:53
|
9
|
+
* License:
|
10
|
+
Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
|
11
|
+
|
12
|
+
=end
|
13
|
+
|
14
|
+
# Event created when state changed (as in ViewPort)
|
15
|
+
module RubyCurses
|
16
|
+
# source - as always is the object whose event has been fired
|
17
|
+
# id - event identifier (seems redundant since we bind events often separately.
|
18
|
+
# event - is :PRESS
|
19
|
+
# action_command - command string associated with event (such as title of button that changed
|
20
|
+
ActionEvent = Struct.new(:source, :event, :action_command) do
|
21
|
+
# This should always return the most relevant text associated with this object
|
22
|
+
# so the user does not have to go through the source object's documentation.
|
23
|
+
# It should be a user-friendly string
|
24
|
+
# @return text associated with source (label of button)
|
25
|
+
def text
|
26
|
+
source.text
|
27
|
+
end
|
28
|
+
|
29
|
+
# This is similar to text and can often be just an alias.
|
30
|
+
# However, i am putting this for backward compatibility with programs
|
31
|
+
# that received the object and called it's getvalue. It is better to use text.
|
32
|
+
# @return text associated with source (label of button)
|
33
|
+
def getvalue
|
34
|
+
source.getvalue
|
35
|
+
end
|
36
|
+
end
|
37
|
+
# a derivative of Action Event for textviews
|
38
|
+
# We allow a user to press ENTER on a row and use that for processing.
|
39
|
+
# We are basically using TextView as a list in which user can scroll around
|
40
|
+
# and move cursor at will.
|
41
|
+
class TextActionEvent < ActionEvent
|
42
|
+
# current_index or line number starting 0
|
43
|
+
attr_accessor :current_index
|
44
|
+
# cursor position on the line
|
45
|
+
attr_accessor :curpos
|
46
|
+
def initialize source, event, action_command, current_index, curpos
|
47
|
+
super source, event, action_command
|
48
|
+
@current_index = current_index
|
49
|
+
@curpos = curpos
|
50
|
+
end
|
51
|
+
# the text of the line on which the user is
|
52
|
+
def text
|
53
|
+
source.current_value.to_s
|
54
|
+
end
|
55
|
+
# the word under the cursor TODO
|
56
|
+
# if its a text with pipe delim, then ??
|
57
|
+
def word_under_cursor line=text(), pos=@curpos, delim=" "
|
58
|
+
line ||= text()
|
59
|
+
pos ||= @curpos
|
60
|
+
finish = line.index(delim, pos)
|
61
|
+
start = line.rindex(delim,pos)
|
62
|
+
finish = -1 if finish.nil?
|
63
|
+
start = 0 if start.nil?
|
64
|
+
return line[start..finish]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|