rkumar-rbcurse 0.1.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.
- data/CHANGELOG +1577 -0
- data/README.txt +310 -0
- data/examples/qdfilechooser.rb +68 -0
- data/examples/rfe.rb +853 -0
- data/examples/rfe_renderer.rb +69 -0
- data/examples/test1.rb +242 -0
- data/examples/test2.rb +498 -0
- data/examples/testcombo.rb +95 -0
- data/examples/testkeypress.rb +61 -0
- data/examples/testmenu.rb +105 -0
- data/examples/testtable.rb +266 -0
- data/examples/testtabp.rb +106 -0
- data/examples/testtodo.rb +532 -0
- data/examples/viewtodo.rb +512 -0
- data/lib/rbcurse.rb +7 -0
- data/lib/rbcurse/action.rb +31 -0
- data/lib/rbcurse/applicationheader.rb +57 -0
- data/lib/rbcurse/celleditor.rb +120 -0
- data/lib/rbcurse/checkboxcellrenderer.rb +69 -0
- data/lib/rbcurse/colormap.rb +133 -0
- data/lib/rbcurse/comboboxcellrenderer.rb +45 -0
- data/lib/rbcurse/defaultlistselectionmodel.rb +49 -0
- data/lib/rbcurse/keylabelprinter.rb +143 -0
- data/lib/rbcurse/listcellrenderer.rb +99 -0
- data/lib/rbcurse/listkeys.rb +33 -0
- data/lib/rbcurse/listscrollable.rb +216 -0
- data/lib/rbcurse/listselectable.rb +67 -0
- data/lib/rbcurse/mapper.rb +108 -0
- data/lib/rbcurse/orderedhash.rb +77 -0
- data/lib/rbcurse/rcombo.rb +243 -0
- data/lib/rbcurse/rdialogs.rb +183 -0
- data/lib/rbcurse/rform.rb +845 -0
- data/lib/rbcurse/rinputdataevent.rb +36 -0
- data/lib/rbcurse/rlistbox.rb +804 -0
- data/lib/rbcurse/rmenu.rb +666 -0
- data/lib/rbcurse/rmessagebox.rb +325 -0
- data/lib/rbcurse/rpopupmenu.rb +754 -0
- data/lib/rbcurse/rtabbedpane.rb +259 -0
- data/lib/rbcurse/rtable.rb +1296 -0
- data/lib/rbcurse/rtextarea.rb +673 -0
- data/lib/rbcurse/rtextview.rb +335 -0
- data/lib/rbcurse/rwidget.rb +1731 -0
- data/lib/rbcurse/scrollable.rb +301 -0
- data/lib/rbcurse/selectable.rb +94 -0
- data/lib/rbcurse/table/tablecellrenderer.rb +85 -0
- data/lib/rbcurse/table/tabledatecellrenderer.rb +102 -0
- data/lib/ver/keyboard.rb +150 -0
- data/lib/ver/keyboard2.rb +170 -0
- data/lib/ver/ncurses.rb +102 -0
- data/lib/ver/window.rb +369 -0
- data/test/test_rbcurse.rb +0 -0
- metadata +117 -0
@@ -0,0 +1,666 @@
|
|
1
|
+
=begin
|
2
|
+
* Name: menu and related classes
|
3
|
+
* Description
|
4
|
+
* Author: rkumar
|
5
|
+
TODO
|
6
|
+
FIXME : works with 2 levels, but focus does not go into third level. This has been fixed in rpopupmenu
|
7
|
+
and needs to be fixed here. DONE 2009-01-21 12:50
|
8
|
+
- menu bar : what to do if adding a menu, or option later.
|
9
|
+
we dnt show disabld options in a way that user can know its disabled
|
10
|
+
- separate file created on 2008-12-24 17:58
|
11
|
+
NOTE : this program works but is one of the first programs and is untouched. It needs to be rewritten
|
12
|
+
since its quite crappy.
|
13
|
+
Also, we should move to Action classes as against just blokcs of code. And action class would have
|
14
|
+
a user friendly string to identifiy the action, as well as a disabled option.
|
15
|
+
|
16
|
+
--------
|
17
|
+
* Date: 2008-11-14 23:43
|
18
|
+
* License:
|
19
|
+
Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
|
20
|
+
|
21
|
+
=end
|
22
|
+
require 'rubygems'
|
23
|
+
require 'ncurses'
|
24
|
+
require 'logger'
|
25
|
+
require 'rbcurse'
|
26
|
+
|
27
|
+
include Ncurses
|
28
|
+
include RubyCurses
|
29
|
+
module RubyCurses
|
30
|
+
extend self
|
31
|
+
|
32
|
+
|
33
|
+
class MenuSeparator
|
34
|
+
attr_accessor :enabled
|
35
|
+
attr_accessor :parent
|
36
|
+
attr_accessor :row
|
37
|
+
attr_accessor :col
|
38
|
+
attr_accessor :width
|
39
|
+
def initialize
|
40
|
+
@enable = false
|
41
|
+
end
|
42
|
+
def repaint
|
43
|
+
@parent.window.printstring( @row, 0, "|%s|" % ("-"*@width), $reversecolor)
|
44
|
+
end
|
45
|
+
def destroy
|
46
|
+
end
|
47
|
+
def on_enter
|
48
|
+
end
|
49
|
+
def on_leave
|
50
|
+
end
|
51
|
+
def to_s
|
52
|
+
""
|
53
|
+
end
|
54
|
+
end
|
55
|
+
##
|
56
|
+
class MenuItem
|
57
|
+
attr_accessor :parent
|
58
|
+
# attr_accessor :window
|
59
|
+
attr_accessor :row
|
60
|
+
attr_accessor :col
|
61
|
+
attr_accessor :width
|
62
|
+
attr_accessor :accelerator
|
63
|
+
attr_accessor :enabled
|
64
|
+
attr_accessor :text, :mnemonic # changed reader to accessor
|
65
|
+
def initialize text, mnemonic=nil, &block
|
66
|
+
@text = text
|
67
|
+
@enabled = true
|
68
|
+
@mnemonic = mnemonic
|
69
|
+
instance_eval &block if block_given?
|
70
|
+
end
|
71
|
+
def to_s
|
72
|
+
"#{@text} #{@accelerator}"
|
73
|
+
end
|
74
|
+
def command *args, &block
|
75
|
+
$log.debug ">>>command : #{@text} "
|
76
|
+
@command = block if block_given?
|
77
|
+
@args = args
|
78
|
+
end
|
79
|
+
def on_enter
|
80
|
+
$log.debug ">>>on enter menuitem : #{@text} #{@row} #{@width} "
|
81
|
+
highlight
|
82
|
+
end
|
83
|
+
def on_leave
|
84
|
+
$log.debug ">>>on leave menuitem : #{@text} "
|
85
|
+
highlight false
|
86
|
+
end
|
87
|
+
## XXX it could be a menu again
|
88
|
+
def fire
|
89
|
+
$log.debug ">>>fire menuitem : #{@text} #{@command} "
|
90
|
+
@command.call self, *@args if !@command.nil?
|
91
|
+
@parent.clear_menus
|
92
|
+
return :CLOSE # added 2009-01-02 00:09 to close only actions, not submenus
|
93
|
+
end
|
94
|
+
def highlight tf=true
|
95
|
+
if @parent.nil? or @parent.window.nil?
|
96
|
+
$log.debug "HL XXX #{self} parent nil"
|
97
|
+
$log.debug "HL XXX #{self} - > #{@parent} parent nil"
|
98
|
+
end
|
99
|
+
if tf
|
100
|
+
color = $datacolor
|
101
|
+
#@parent.window.mvchgat(y=@row, x=1, @width, Ncurses::A_NORMAL, color, nil)
|
102
|
+
# above line did not work in vt100, 200 terminals, next works.
|
103
|
+
@parent.window.mvchgat(y=@row, x=1, @width, Ncurses::A_REVERSE, $reversecolor, nil)
|
104
|
+
else
|
105
|
+
repaint
|
106
|
+
end
|
107
|
+
@parent.window.wrefresh unless @parent.window.nil? ## XXX 2009-01-21 22:00
|
108
|
+
end
|
109
|
+
def repaint # menuitem.repaint
|
110
|
+
if @parent.nil? or @parent.window.nil?
|
111
|
+
$log.debug "repaint #{self} parent nil"
|
112
|
+
# return
|
113
|
+
end
|
114
|
+
r = @row
|
115
|
+
acolor = $reversecolor
|
116
|
+
acolor = get_color($reversecolor, 'green', 'white') if !@enabled
|
117
|
+
@parent.window.printstring( @row, 0, "|%-*s|" % [@width, text], acolor)
|
118
|
+
if !@accelerator.nil?
|
119
|
+
@parent.window.printstring( r, (@width+1)-@accelerator.length, @accelerator, acolor)
|
120
|
+
elsif !@mnemonic.nil?
|
121
|
+
m = @mnemonic
|
122
|
+
ix = text.index(m) || text.index(m.swapcase)
|
123
|
+
charm = text[ix,1]
|
124
|
+
#@parent.window.printstring( r, ix+1, charm, $datacolor) if !ix.nil?
|
125
|
+
# prev line changed since not working in vt100 and vt200
|
126
|
+
@parent.window.printstring( r, ix+1, charm, $reversecolor, 'reverse') if !ix.nil?
|
127
|
+
end
|
128
|
+
end
|
129
|
+
def destroy
|
130
|
+
$log.debug "DESTRY menuitem #{@text}"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
##class Menu
|
134
|
+
class Menu < MenuItem ## NEW
|
135
|
+
attr_accessor :parent
|
136
|
+
attr_accessor :row
|
137
|
+
attr_accessor :col
|
138
|
+
attr_accessor :width
|
139
|
+
attr_accessor :enabled
|
140
|
+
attr_reader :text
|
141
|
+
attr_reader :items
|
142
|
+
attr_reader :window
|
143
|
+
attr_reader :panel
|
144
|
+
attr_reader :current_menu
|
145
|
+
attr_reader :row_margin ## 2009-01-21 12:06 NEW
|
146
|
+
## this keeps a stack of menus. if we coud somehow put this in
|
147
|
+
# menubar would be great.
|
148
|
+
@@menus = []
|
149
|
+
@@row = 0
|
150
|
+
@@col = 0
|
151
|
+
|
152
|
+
def initialize text, &block
|
153
|
+
super text, nil, &block
|
154
|
+
@text = text
|
155
|
+
@items = []
|
156
|
+
@enabled = true
|
157
|
+
@current_menu = []
|
158
|
+
instance_eval &block if block_given?
|
159
|
+
@row ||=10
|
160
|
+
@col ||=10
|
161
|
+
@@menus ||= []
|
162
|
+
end
|
163
|
+
## called upon firing so when we next show menubar there are not any left overs in here.
|
164
|
+
def clear_menus
|
165
|
+
@@menus = []
|
166
|
+
end
|
167
|
+
def to_s
|
168
|
+
@text
|
169
|
+
end
|
170
|
+
# item could be menuitem or another menu
|
171
|
+
def add menuitem
|
172
|
+
@items << menuitem
|
173
|
+
return self
|
174
|
+
end
|
175
|
+
def insert_separator ix
|
176
|
+
@items.insert ix, MenuSeparator.new
|
177
|
+
end
|
178
|
+
def add_separator
|
179
|
+
@items << MenuSeparator.new
|
180
|
+
end
|
181
|
+
## added 2009-01-21 12:09 NEW
|
182
|
+
def get_item i
|
183
|
+
@items[i]
|
184
|
+
end
|
185
|
+
## added 2009-01-21 12:09 NEW
|
186
|
+
def remove n
|
187
|
+
if n.is_a? Fixnum
|
188
|
+
@items.delete_at n
|
189
|
+
else
|
190
|
+
@items.delete n
|
191
|
+
end
|
192
|
+
end
|
193
|
+
# menu -
|
194
|
+
def fire
|
195
|
+
$log.debug "menu fire called: #{text} "
|
196
|
+
if @window.nil?
|
197
|
+
#repaint
|
198
|
+
create_window
|
199
|
+
if !@parent.is_a? RubyCurses::MenuBar
|
200
|
+
@parent.current_menu << self
|
201
|
+
@@menus << self # NEW
|
202
|
+
end
|
203
|
+
else
|
204
|
+
### shouod this not just show ?
|
205
|
+
$log.debug "menu fire called: #{text} ELSE XXX WHEN IS THIS CALLED ? 658 "
|
206
|
+
return @items[@active_index].fire # this should happen if selected. else selected()
|
207
|
+
end
|
208
|
+
#@action.call if !@action.nil?
|
209
|
+
end
|
210
|
+
# user has clicked down, we shoud display items
|
211
|
+
# DRAW menuitems
|
212
|
+
def repaint # menu.repaint
|
213
|
+
return if @items.nil? or @items.empty?
|
214
|
+
$log.debug "menu repaint: #{text} row #{@row} col #{@col} "
|
215
|
+
if !@parent.is_a? RubyCurses::MenuBar
|
216
|
+
@parent.window.printstring( @row, 0, "|%-*s>|" % [@width-1, text], $reversecolor)
|
217
|
+
@parent.window.refresh
|
218
|
+
end
|
219
|
+
if @window.nil?
|
220
|
+
#create_window
|
221
|
+
else
|
222
|
+
@window.show
|
223
|
+
select_item 0
|
224
|
+
@window.refresh
|
225
|
+
end
|
226
|
+
end
|
227
|
+
##
|
228
|
+
# recursive if given one not enabled goes to next enabled
|
229
|
+
def select_item ix0
|
230
|
+
return if @items.nil? or @items.empty?
|
231
|
+
$log.debug "insdie select item : #{ix0} active: #{@active_index}"
|
232
|
+
if !@active_index.nil?
|
233
|
+
@items[@active_index].on_leave
|
234
|
+
end
|
235
|
+
previtem = @active_index
|
236
|
+
@active_index = ix0
|
237
|
+
if @items[ix0].enabled
|
238
|
+
@items[ix0].on_enter
|
239
|
+
else
|
240
|
+
$log.debug "insdie sele nxt item ENABLED FALSE : #{ix0}"
|
241
|
+
if @active_index > previtem
|
242
|
+
select_next_item
|
243
|
+
else
|
244
|
+
select_prev_item
|
245
|
+
end
|
246
|
+
end
|
247
|
+
@window.refresh
|
248
|
+
end
|
249
|
+
def select_next_item
|
250
|
+
return if @items.nil? or @items.empty?
|
251
|
+
$log.debug "insdie sele nxt item : #{@active_index}"
|
252
|
+
@active_index = -1 if @active_index.nil?
|
253
|
+
if @active_index < @items.length-1
|
254
|
+
select_item @active_index + 1
|
255
|
+
else
|
256
|
+
# select_item 0
|
257
|
+
end
|
258
|
+
end
|
259
|
+
def select_prev_item
|
260
|
+
return if @items.nil? or @items.empty?
|
261
|
+
$log.debug "insdie sele prv item : #{@active_index}"
|
262
|
+
if @active_index > 0
|
263
|
+
select_item @active_index - 1
|
264
|
+
else
|
265
|
+
#select_item @items.length-1
|
266
|
+
end
|
267
|
+
end
|
268
|
+
def on_enter # menu.on_enter
|
269
|
+
$log.debug "menu onenter: #{text} #{@row} #{@col} "
|
270
|
+
# call parent method. XXX
|
271
|
+
if @parent.is_a? RubyCurses::MenuBar
|
272
|
+
@parent.window.printstring( @row, @col, " %s " % text, $datacolor)
|
273
|
+
else
|
274
|
+
highlight
|
275
|
+
end
|
276
|
+
if !@window.nil? #and @parent.selected
|
277
|
+
$log.debug "menu onenter: #{text} calling window,show"
|
278
|
+
@window.show
|
279
|
+
select_item 0
|
280
|
+
elsif @parent.is_a? RubyCurses::MenuBar and @parent.selected
|
281
|
+
# only on the top level do we open a window if a previous one was opened
|
282
|
+
$log.debug "menu onenter: #{text} calling repaint CLASS: #{@parent.class}"
|
283
|
+
# repaint
|
284
|
+
create_window
|
285
|
+
end
|
286
|
+
end
|
287
|
+
def on_leave # menu.on_leave
|
288
|
+
$log.debug "menu onleave: #{text} #{@row} #{@col} "
|
289
|
+
# call parent method. XXX
|
290
|
+
if @parent.is_a? RubyCurses::MenuBar
|
291
|
+
@parent.window.printstring( @row, @col, " %s " % text, $reversecolor)
|
292
|
+
@window.hide if !@window.nil?
|
293
|
+
else
|
294
|
+
$log.debug "MENU SUBMEN. menu onleave: #{text} #{@row} #{@col} "
|
295
|
+
# parent is a menu
|
296
|
+
highlight false
|
297
|
+
#@parent.current_menu.pop
|
298
|
+
#@@menus.pop
|
299
|
+
#destroy
|
300
|
+
end
|
301
|
+
end
|
302
|
+
def highlight tf=true # menu
|
303
|
+
$log.debug "MENU SUBMENU menu highlight: #{text} #{@row} #{@col}, PW #{@parent.width} "
|
304
|
+
color = tf ? $datacolor : $reversecolor
|
305
|
+
att = tf ? Ncurses::A_REVERSE : Ncurses::A_NORMAL
|
306
|
+
#@parent.window.mvchgat(y=@row, x=1, @width, Ncurses::A_NORMAL, color, nil)
|
307
|
+
#@parent.window.mvchgat(y=@row, x=1, @parent.width, Ncurses::A_NORMAL, color, nil)
|
308
|
+
# above line did not work with vt100/vt200 next does
|
309
|
+
@parent.window.mvchgat(y=@row, x=1, @parent.width, att, $reversecolor, nil)
|
310
|
+
@parent.window.wrefresh
|
311
|
+
end
|
312
|
+
def create_window # menu
|
313
|
+
margin = 3
|
314
|
+
@width = array_width @items
|
315
|
+
$log.debug "create window menu #{@text}: #{@row} ,#{@col},wd #{@width} "
|
316
|
+
@layout = { :height => @items.length+3, :width => @width+margin, :top => @row+1, :left => @col }
|
317
|
+
@win = VER::Window.new(@layout)
|
318
|
+
@window = @win
|
319
|
+
@win.bkgd(Ncurses.COLOR_PAIR($datacolor));
|
320
|
+
@panel = @win.panel
|
321
|
+
@window.printstring( 0, 0, "+%s+" % ("-"*@width), $reversecolor)
|
322
|
+
r = 1
|
323
|
+
@items.each do |item|
|
324
|
+
#if item == :SEPARATOR
|
325
|
+
# @window.printstring( r, 0, "|%s|" % ("-"*@width), $reversecolor)
|
326
|
+
#else
|
327
|
+
item.row = r
|
328
|
+
item.col = 0
|
329
|
+
item.col = @col+@width+margin # margins???
|
330
|
+
# $log.debug "create window menu loop passing col : #{item.col} "
|
331
|
+
item.width = @width
|
332
|
+
#item.window = @window
|
333
|
+
item.parent = self
|
334
|
+
item.repaint
|
335
|
+
#end
|
336
|
+
r+=1
|
337
|
+
end
|
338
|
+
@window.printstring( r, 0, "+%s+" % ("-"*@width), $reversecolor)
|
339
|
+
select_item 0
|
340
|
+
@window.refresh
|
341
|
+
return @window
|
342
|
+
end
|
343
|
+
# private
|
344
|
+
def array_width a
|
345
|
+
longest = a.max {|a,b| a.to_s.length <=> b.to_s.length }
|
346
|
+
$log.debug "array width #{longest}"
|
347
|
+
longest.to_s.length
|
348
|
+
end
|
349
|
+
def destroy
|
350
|
+
$log.debug "DESTRY menu #{@text}"
|
351
|
+
return if @window.nil?
|
352
|
+
@visible = false
|
353
|
+
panel = @window.panel
|
354
|
+
Ncurses::Panel.del_panel(panel) if !panel.nil?
|
355
|
+
@window.delwin if !@window.nil?
|
356
|
+
@items.each do |item|
|
357
|
+
#next if item == :SEPARATOR
|
358
|
+
item.destroy
|
359
|
+
end
|
360
|
+
@window = nil
|
361
|
+
end
|
362
|
+
# menu LEFT, RIGHT, DOWN, UP, ENTER
|
363
|
+
# item could be menuitem or another menu
|
364
|
+
#
|
365
|
+
def handle_key ch
|
366
|
+
if !@current_menu.empty?
|
367
|
+
cmenu = @current_menu.last
|
368
|
+
else
|
369
|
+
cmenu = self
|
370
|
+
end
|
371
|
+
if !@@menus.empty?
|
372
|
+
cmenu = @@menus.last
|
373
|
+
else
|
374
|
+
cmenu = self
|
375
|
+
end
|
376
|
+
case ch
|
377
|
+
when KEY_DOWN
|
378
|
+
cmenu.select_next_item
|
379
|
+
when KEY_UP
|
380
|
+
cmenu.select_prev_item
|
381
|
+
when KEY_ENTER, 10, 13, 32 # added 32 2008-11-27 23:50
|
382
|
+
return cmenu.fire
|
383
|
+
when KEY_LEFT
|
384
|
+
if cmenu.parent.is_a? RubyCurses::Menu
|
385
|
+
$log.debug "LEFT IN MENU : #{cmenu.parent.class} len: #{cmenu.parent.current_menu.length}"
|
386
|
+
$log.debug "left IN MENU : #{cmenu.parent.class} len: #{cmenu.current_menu.length}"
|
387
|
+
end
|
388
|
+
if cmenu.parent.is_a? RubyCurses::Menu and !cmenu.parent.current_menu.empty?
|
389
|
+
$log.debug " ABOU TO DESTROY DUE TO LEFT"
|
390
|
+
cmenu.parent.current_menu.pop
|
391
|
+
@@menus.pop ## NEW
|
392
|
+
cmenu.destroy
|
393
|
+
else
|
394
|
+
return :UNHANDLED
|
395
|
+
end
|
396
|
+
when KEY_RIGHT
|
397
|
+
$log.debug "RIGHTIN MENU : "
|
398
|
+
if cmenu.parent.is_a? RubyCurses::Menu
|
399
|
+
$log.debug "right IN MENU : #{cmenu.parent.class} len: #{cmenu.parent.current_menu.length}"
|
400
|
+
$log.debug "right IN MENU : #{cmenu.parent.class} len: #{cmenu.current_menu.length}"
|
401
|
+
end
|
402
|
+
if cmenu.parent.is_a? RubyCurses::Menu and !cmenu.parent.current_menu.empty?
|
403
|
+
$log.debug " ABOU TO DESTROY DUE TO RIGHT"
|
404
|
+
cmenu.parent.current_menu.pop
|
405
|
+
@@menus.pop
|
406
|
+
cmenu.destroy
|
407
|
+
end
|
408
|
+
return :UNHANDLED
|
409
|
+
else
|
410
|
+
ret = check_mnemonics cmenu, ch
|
411
|
+
return ret
|
412
|
+
end
|
413
|
+
end
|
414
|
+
##
|
415
|
+
# checks given key against current menu's items and fires key if
|
416
|
+
# added on 2008-11-27 12:07
|
417
|
+
def check_mnemonics cmenu, ch
|
418
|
+
# $log.debug "inside check_mnemonics #{ch}"
|
419
|
+
key = ch.chr.downcase rescue ""
|
420
|
+
cmenu.items.each do |item|
|
421
|
+
next if !item.respond_to? :mnemonic or item.mnemonic.nil?
|
422
|
+
# $log.debug "inside check_mnemonics #{item.mnemonic}"
|
423
|
+
if key == item.mnemonic.downcase
|
424
|
+
ret = item.fire
|
425
|
+
return ret #0 2009-01-23 00:45
|
426
|
+
end
|
427
|
+
end
|
428
|
+
return :UNHANDLED
|
429
|
+
end
|
430
|
+
## menu
|
431
|
+
def show # menu.show
|
432
|
+
$log.debug "show (menu) : #{@text} "
|
433
|
+
if @window.nil?
|
434
|
+
create_window
|
435
|
+
end
|
436
|
+
@window.show
|
437
|
+
select_item 0
|
438
|
+
end
|
439
|
+
end
|
440
|
+
##
|
441
|
+
# An application related menubar.
|
442
|
+
# Currently, I am adding this to a form. But should this not be application specific ?
|
443
|
+
# It should popup no matter which window you are on ?? XXX
|
444
|
+
class MenuBar
|
445
|
+
attr_reader :items
|
446
|
+
attr_reader :window
|
447
|
+
attr_reader :panel
|
448
|
+
attr_reader :selected
|
449
|
+
attr_accessor :visible
|
450
|
+
attr_accessor :active_index
|
451
|
+
attr_accessor :state # normal, selected, highlighted
|
452
|
+
attr_accessor :toggle_key # key used to popup, should be set prior to attaching to form
|
453
|
+
def initialize &block
|
454
|
+
@window = nil
|
455
|
+
@items = []
|
456
|
+
init_vars
|
457
|
+
@visible = false
|
458
|
+
@cols = Ncurses.COLS-1
|
459
|
+
instance_eval &block if block_given?
|
460
|
+
end
|
461
|
+
def init_vars
|
462
|
+
@active_index = 0
|
463
|
+
end
|
464
|
+
def focusable
|
465
|
+
false
|
466
|
+
end
|
467
|
+
def add menu
|
468
|
+
@items << menu
|
469
|
+
return self
|
470
|
+
end
|
471
|
+
def next_menu
|
472
|
+
$log.debug "next meu: #{@active_index} "
|
473
|
+
if @active_index < @items.length-1
|
474
|
+
set_menu @active_index + 1
|
475
|
+
else
|
476
|
+
set_menu 0
|
477
|
+
end
|
478
|
+
end
|
479
|
+
def prev_menu
|
480
|
+
$log.debug "prev meu: #{@active_index} "
|
481
|
+
if @active_index > 0
|
482
|
+
set_menu @active_index-1
|
483
|
+
else
|
484
|
+
set_menu @items.length-1
|
485
|
+
end
|
486
|
+
end
|
487
|
+
def set_menu index
|
488
|
+
$log.debug "set meu: #{@active_index} #{index}"
|
489
|
+
menu = @items[@active_index]
|
490
|
+
menu.on_leave # hide its window, if open
|
491
|
+
@active_index = index
|
492
|
+
menu = @items[@active_index]
|
493
|
+
menu.on_enter #display window, if previous was displayed
|
494
|
+
@window.wmove menu.row, menu.col
|
495
|
+
# menu.show
|
496
|
+
# menu.window.wrefresh # XXX we need this
|
497
|
+
end
|
498
|
+
# menubar LEFT, RIGHT, DOWN
|
499
|
+
def handle_keys
|
500
|
+
@selected = false
|
501
|
+
@toggle_key ||= 27 # default switch off with ESC, if nothing else defined
|
502
|
+
set_menu 0
|
503
|
+
begin
|
504
|
+
catch(:menubarclose) do
|
505
|
+
while((ch = @window.getchar()) != @toggle_key )
|
506
|
+
$log.debug "menuubar inside handle_keys : #{ch}" if ch != -1
|
507
|
+
case ch
|
508
|
+
when -1
|
509
|
+
next
|
510
|
+
when KEY_DOWN
|
511
|
+
$log.debug "insdie keyDOWN : #{ch}"
|
512
|
+
if !@selected
|
513
|
+
current_menu.fire
|
514
|
+
else
|
515
|
+
current_menu.handle_key ch
|
516
|
+
end
|
517
|
+
|
518
|
+
@selected = true
|
519
|
+
when KEY_ENTER, 10, 13, 32
|
520
|
+
@selected = true
|
521
|
+
$log.debug " mb insdie ENTER : #{current_menu}"
|
522
|
+
ret = current_menu.handle_key ch
|
523
|
+
$log.debug "ret = #{ret} mb insdie ENTER : #{current_menu}"
|
524
|
+
#break; ## 2008-12-29 18:00 This will close after firing
|
525
|
+
#anything
|
526
|
+
break if ret == :CLOSE
|
527
|
+
when KEY_UP
|
528
|
+
$log.debug " mb insdie keyUPP : #{ch}"
|
529
|
+
current_menu.handle_key ch
|
530
|
+
when KEY_LEFT
|
531
|
+
$log.debug " mb insdie KEYLEFT : #{ch}"
|
532
|
+
ret = current_menu.handle_key ch
|
533
|
+
prev_menu if ret == :UNHANDLED
|
534
|
+
#display_items if @selected
|
535
|
+
when KEY_RIGHT
|
536
|
+
$log.debug " mb insdie KEYRIGHT : #{ch}"
|
537
|
+
ret = current_menu.handle_key ch
|
538
|
+
next_menu if ret == :UNHANDLED
|
539
|
+
else
|
540
|
+
$log.debug " mb insdie ELSE : #{ch}"
|
541
|
+
ret = current_menu.handle_key ch
|
542
|
+
if ret == :UNHANDLED
|
543
|
+
Ncurses.beep
|
544
|
+
else
|
545
|
+
break # we handled a menu action, close menubar (THIS WORKS FOR MNEMONICS ONLY and always)
|
546
|
+
end
|
547
|
+
end
|
548
|
+
Ncurses::Panel.update_panels();
|
549
|
+
Ncurses.doupdate();
|
550
|
+
|
551
|
+
@window.wrefresh
|
552
|
+
end
|
553
|
+
end # catch
|
554
|
+
ensure
|
555
|
+
#ensure is required becos one can throw a :close
|
556
|
+
$log.debug " DESTROY IN ENSURE"
|
557
|
+
current_menu.clear_menus #@@menus = [] # added 2009-01-23 13:21
|
558
|
+
destroy # Note that we destroy the menu bar upon exit
|
559
|
+
end
|
560
|
+
end
|
561
|
+
def current_menu
|
562
|
+
@items[@active_index]
|
563
|
+
end
|
564
|
+
def toggle
|
565
|
+
@items.each { |i| $log.debug " ITEM DDD : #{i.text}" }
|
566
|
+
@visible = !@visible
|
567
|
+
if !@visible
|
568
|
+
hide
|
569
|
+
else
|
570
|
+
init_vars
|
571
|
+
show
|
572
|
+
end
|
573
|
+
end
|
574
|
+
def hide
|
575
|
+
@visible = false
|
576
|
+
@window.hide if !@window.nil?
|
577
|
+
end
|
578
|
+
def show
|
579
|
+
@visible = true
|
580
|
+
if @window.nil?
|
581
|
+
repaint # XXX FIXME
|
582
|
+
else
|
583
|
+
@window.show
|
584
|
+
end
|
585
|
+
end
|
586
|
+
## menubar
|
587
|
+
def repaint
|
588
|
+
return if !@visible
|
589
|
+
@window ||= create_window
|
590
|
+
@window.printstring( 0, 0, "%-*s" % [@cols," "], $reversecolor)
|
591
|
+
c = 1; r = 0;
|
592
|
+
@items.each do |item|
|
593
|
+
item.row = r; item.col = c; item.parent = self
|
594
|
+
@window.printstring( r, c, " %s " % item.text, $reversecolor)
|
595
|
+
c += (item.text.length + 2)
|
596
|
+
end
|
597
|
+
@window.wrefresh
|
598
|
+
end
|
599
|
+
def create_window
|
600
|
+
@layout = { :height => 1, :width => 0, :top => 0, :left => 0 }
|
601
|
+
@win = VER::Window.new(@layout)
|
602
|
+
@window = @win
|
603
|
+
@win.bkgd(Ncurses.COLOR_PAIR(5));
|
604
|
+
@panel = @win.panel
|
605
|
+
return @window
|
606
|
+
end
|
607
|
+
def destroy
|
608
|
+
$log.debug "DESTRY menubar "
|
609
|
+
@visible = false
|
610
|
+
panel = @window.panel
|
611
|
+
Ncurses::Panel.del_panel(panel) if !panel.nil?
|
612
|
+
@window.delwin if !@window.nil?
|
613
|
+
@items.each do |item|
|
614
|
+
item.destroy
|
615
|
+
end
|
616
|
+
@window = nil
|
617
|
+
end
|
618
|
+
end # menubar
|
619
|
+
|
620
|
+
class CheckBoxMenuItem < MenuItem
|
621
|
+
include DSL
|
622
|
+
attr_reader :checkbox
|
623
|
+
def initialize text, mnemonic=nil, &block
|
624
|
+
@checkbox = CheckBox.new nil
|
625
|
+
@checkbox.text text
|
626
|
+
super
|
627
|
+
end
|
628
|
+
def onvalue
|
629
|
+
@checkbox.onvalue onvalue
|
630
|
+
end
|
631
|
+
def offvalue
|
632
|
+
@checkbox.onvalue offvalue
|
633
|
+
end
|
634
|
+
def text=(t) # stack level too deep if no = .????
|
635
|
+
@checkbox.text t
|
636
|
+
end
|
637
|
+
def to_s
|
638
|
+
" #{text} "
|
639
|
+
end
|
640
|
+
def getvalue
|
641
|
+
checkbox.getvalue
|
642
|
+
end
|
643
|
+
def getvalue_for_paint
|
644
|
+
"|%-*s|" % [@width, checkbox.getvalue_for_paint]
|
645
|
+
end
|
646
|
+
def fire
|
647
|
+
checkbox.toggle
|
648
|
+
super
|
649
|
+
repaint
|
650
|
+
highlight true
|
651
|
+
end
|
652
|
+
def repaint
|
653
|
+
@parent.window.printstring( row, 0, getvalue_for_paint, $reversecolor)
|
654
|
+
parent.window.wrefresh
|
655
|
+
end
|
656
|
+
def method_missing(sym, *args)
|
657
|
+
if checkbox.respond_to? sym
|
658
|
+
$log.debug("calling CHECKBOXMENU #{sym} called #{args[0]}")
|
659
|
+
checkbox.send(sym, args)
|
660
|
+
else
|
661
|
+
$log.error("ERROR CHECKBOXMENU #{sym} called")
|
662
|
+
end
|
663
|
+
end
|
664
|
+
|
665
|
+
end
|
666
|
+
end # modul
|