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,271 @@
|
|
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
|
+
|
207
|
+
##
|
208
|
+
# bindings related to selection
|
209
|
+
#
|
210
|
+
def list_bindings
|
211
|
+
# what about users wanting 32 and ENTER to also go to next row automatically
|
212
|
+
# should make that optional, TODO
|
213
|
+
bind_key($row_selector || 32, 'toggle selection') { toggle_row_selection }
|
214
|
+
# 2013-03-24 - 14:46 added condition so single select does not get these
|
215
|
+
if @selection_mode == :multiple
|
216
|
+
bind_key(0, 'range select') { add_to_selection }
|
217
|
+
bind_key(?+, :ask_select) # --> calls select_values
|
218
|
+
bind_key(?-, :ask_unselect) # please implement FIXME TODO
|
219
|
+
bind_key(?a, :select_all)
|
220
|
+
bind_key(?*, :invert_selection)
|
221
|
+
bind_key(?u, :clear_selection)
|
222
|
+
end
|
223
|
+
@_header_adjustment ||= 0 # incase caller does not use
|
224
|
+
@_events << :LIST_SELECTION_EVENT unless @_events.include? :LIST_SELECTION_EVENT
|
225
|
+
end
|
226
|
+
def list_init_vars
|
227
|
+
@selected_indices = []
|
228
|
+
@selected_index = nil
|
229
|
+
@old_selected_index = nil
|
230
|
+
#@row_selected_symbol = ''
|
231
|
+
if @show_selector
|
232
|
+
@row_selected_symbol ||= '*'
|
233
|
+
@row_unselected_symbol ||= ' '
|
234
|
+
@left_margin ||= @row_selected_symbol.length
|
235
|
+
end
|
236
|
+
end
|
237
|
+
# paint the selector. Called from repaint, prior to printing data row
|
238
|
+
# remember to set left_margin at top of repaint method as:
|
239
|
+
# @left_margin ||= @row_selected_symbol.length
|
240
|
+
def paint_selector crow, r, c, acolor, attrib
|
241
|
+
selected = is_row_selected crow
|
242
|
+
selection_symbol = ''
|
243
|
+
if @show_selector
|
244
|
+
if selected
|
245
|
+
selection_symbol = @row_selected_symbol
|
246
|
+
else
|
247
|
+
selection_symbol = @row_unselected_symbol
|
248
|
+
end
|
249
|
+
@graphic.printstring r, c, selection_symbol, acolor,attrib
|
250
|
+
end
|
251
|
+
end
|
252
|
+
def selected_rows
|
253
|
+
@selected_indices
|
254
|
+
end
|
255
|
+
end # mod
|
256
|
+
class ListSelectionEvent
|
257
|
+
attr_accessor :firstrow, :lastrow, :source, :type
|
258
|
+
def initialize firstrow, lastrow, source, type
|
259
|
+
@firstrow = firstrow
|
260
|
+
@lastrow = lastrow
|
261
|
+
@source = source
|
262
|
+
@type = type
|
263
|
+
end
|
264
|
+
def to_s
|
265
|
+
"#{@type.to_s}, firstrow: #{@firstrow}, lastrow: #{@lastrow}, source: #{@source}"
|
266
|
+
end
|
267
|
+
def inspect
|
268
|
+
to_s
|
269
|
+
end
|
270
|
+
end
|
271
|
+
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,73 @@
|
|
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
|
+
# if pressed on a space, try to go to next word to make easier 2013-03-24
|
61
|
+
if line[pos,1] == delim
|
62
|
+
while line[pos,1] == delim
|
63
|
+
pos += 1
|
64
|
+
end
|
65
|
+
end
|
66
|
+
finish = line.index(delim, pos)
|
67
|
+
start = line.rindex(delim,pos)
|
68
|
+
finish = -1 if finish.nil?
|
69
|
+
start = 0 if start.nil?
|
70
|
+
return line[start..finish]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|