rbcurse 0.1.0

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