rbcurse 1.3.0 → 1.4.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.
Files changed (70) hide show
  1. data/CHANGELOG +33 -0
  2. data/README.markdown +7 -1
  3. data/TODO2.txt +21 -15
  4. data/VERSION +1 -1
  5. data/examples/abasiclist.rb +2 -2
  6. data/examples/alpmenu.rb +1 -1
  7. data/examples/app.rb +0 -1
  8. data/examples/appdirtree.rb +4 -2
  9. data/examples/appemail.rb +7 -3
  10. data/examples/appemaillb.rb +1 -1
  11. data/examples/appgcompose.rb +2 -2
  12. data/examples/appgmail.rb +1 -1
  13. data/examples/appmethods.rb +20 -2
  14. data/examples/atree.rb +9 -1
  15. data/examples/dbdemo.rb +460 -0
  16. data/examples/dirtree.rb +1 -1
  17. data/examples/menu1.rb +37 -5
  18. data/examples/multispl.rb +1 -1
  19. data/examples/rfe.rb +9 -2
  20. data/examples/splitp.rb +1 -1
  21. data/examples/sqlc.rb +6 -10
  22. data/examples/sqlm.rb +2 -20
  23. data/examples/sqlt.rb +408 -0
  24. data/examples/term2.rb +1 -1
  25. data/examples/test2.rb +169 -97
  26. data/examples/testapp.rb +1 -1
  27. data/examples/testapp2.rb +1 -1
  28. data/examples/testkeypress.rb +4 -2
  29. data/examples/testtable.rb +6 -0
  30. data/examples/testtpane.rb +35 -23
  31. data/examples/testvimsplit.rb +3 -2
  32. data/lib/rbcurse.rb +1 -1
  33. data/lib/rbcurse/action.rb +8 -0
  34. data/lib/rbcurse/app.rb +39 -23
  35. data/lib/rbcurse/extras/bottomline.rb +101 -13
  36. data/lib/rbcurse/extras/directorylist.rb +14 -5
  37. data/lib/rbcurse/extras/divider.rb +1 -1
  38. data/lib/rbcurse/extras/listselectable.rb +42 -8
  39. data/lib/rbcurse/extras/masterdetail.rb +2 -2
  40. data/lib/rbcurse/extras/scrollbar.rb +11 -2
  41. data/lib/rbcurse/extras/statusline.rb +56 -0
  42. data/lib/rbcurse/extras/stdscrwindow.rb +11 -0
  43. data/lib/rbcurse/extras/tabular.rb +2 -1
  44. data/lib/rbcurse/extras/tabularwidget.rb +60 -17
  45. data/lib/rbcurse/extras/viewer.rb +16 -4
  46. data/lib/rbcurse/keylabelprinter.rb +34 -4
  47. data/lib/rbcurse/listeditable.rb +5 -1
  48. data/lib/rbcurse/listkeys.rb +1 -1
  49. data/lib/rbcurse/listscrollable.rb +15 -8
  50. data/lib/rbcurse/rbasiclistbox.rb +44 -23
  51. data/lib/rbcurse/rcommandwindow.rb +8 -14
  52. data/lib/rbcurse/rdialogs.rb +187 -2
  53. data/lib/rbcurse/rlistbox.rb +38 -19
  54. data/lib/rbcurse/rmenu.rb +313 -93
  55. data/lib/rbcurse/rmessagebox.rb +3 -2
  56. data/lib/rbcurse/rmulticontainer.rb +5 -3
  57. data/lib/rbcurse/rmultisplit.rb +2 -11
  58. data/lib/rbcurse/rmultitextview.rb +4 -5
  59. data/lib/rbcurse/rtabbedpane.rb +223 -69
  60. data/lib/rbcurse/rtable.rb +6 -10
  61. data/lib/rbcurse/rtextarea.rb +57 -36
  62. data/lib/rbcurse/rtextview.rb +12 -15
  63. data/lib/rbcurse/rtree.rb +79 -22
  64. data/lib/rbcurse/rvimsplit.rb +16 -25
  65. data/lib/rbcurse/rwidget.rb +376 -523
  66. data/lib/rbcurse/tree/treecellrenderer.rb +24 -11
  67. data/lib/rbcurse/tree/treemodel.rb +1 -1
  68. data/lib/ver/window.rb +130 -66
  69. metadata +5 -3
  70. data/examples/term.rb +0 -48
@@ -5,6 +5,11 @@
5
5
 
6
6
  --------
7
7
  * Date: 2008-12-30 12:22
8
+ * 2011-10-1 : moving print_error and print_status methods here as alternatives
9
+ to alert and confirm. Anyone who has included those will get these.
10
+ And this file is included in the base file.
11
+
12
+ Shucks, this file has no module. It's bare !
8
13
  * License:
9
14
  Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
10
15
 
@@ -12,8 +17,6 @@ TODO:
12
17
  Add one get_string(message, len, regex ...)
13
18
  Add select_one (message, values, default)
14
19
  =end
15
- require 'rubygems'
16
- ##require 'ncurses'
17
20
  require 'logger'
18
21
  require 'rbcurse/rwidget'
19
22
  require 'rbcurse/rmessagebox'
@@ -26,6 +29,7 @@ require 'rbcurse/rmessagebox'
26
29
  # alert("You did not enter anything!", "title"=>"Wake Up")
27
30
  # alert("You did not enter anything!", {"title"=>"Wake Up", "bgcolor"=>"blue", "color"=>"white"})
28
31
  # block currently ignored. don't know what to do, can't pass it to MB since alread sending in a block
32
+ #
29
33
  def alert text, config={}, &block
30
34
  title = config['title'] || "Alert"
31
35
  #instance_eval &block if block_given?
@@ -38,6 +42,8 @@ def alert text, config={}, &block
38
42
  button_type :ok
39
43
  end
40
44
  end
45
+ # confirms from user returning :YES or :NO
46
+ # Darn, should have returned boolean, now have to live with it.
41
47
  def confirm text, config={}, &block
42
48
  title = config['title'] || "Confirm"
43
49
  #instance_eval &block if block_given?
@@ -158,6 +164,185 @@ def get_string_with_options(message, len=20, default="", config={})
158
164
  return mb.selected_index, mform.by_name['input'].getvalue, hash
159
165
  end
160
166
 
167
+ # ------------------------ We've Moved here from window class ---------------- #
168
+ # #
169
+ # Moving some methods from window. They no longer require having a window. #
170
+ # #
171
+ # ---------------------------------------------------------------------------- #
172
+ #
173
+ #
174
+
175
+ # new version with a window created on 2011-10-1 12:37 AM
176
+ # Now can be separate from window class, needing nothing, just a util class
177
+ # prints a status message and pauses for a char
178
+ def print_status_message text, aconfig={}, &block
179
+ _print_message :status, text, aconfig, &block
180
+ end
181
+ # new version with a window created on 2011-10-1 12:30 AM
182
+ # Now can be separate from window class, needing nothing, just a util class
183
+ # Why are we dealing with $error_message, that was due to old idea which failed
184
+ # scrap it and send the message.
185
+ def print_error_message text, aconfig={}, &block
186
+ _print_message :error, text, aconfig, &block
187
+ end
188
+ def _create_footer_window h = 2 , w = Ncurses.COLS, t = Ncurses.LINES-2, l = 0
189
+ ewin = VER::Window.new(h, w , t, l)
190
+ end
191
+ # @param [:symbol] :error or :status kind of message
192
+ # @private
193
+ def _print_message type, text, aconfig={}, &block
194
+ case text
195
+ when RubyCurses::Variable # added 2011-09-20 incase variable passed
196
+ text = text.get_value
197
+ when Exception
198
+ text = text.to_s
199
+ end
200
+ # NOTE we are polluting global namespace
201
+ aconfig.each_pair { |k,v| instance_variable_set("@#{k}",v) }
202
+ ewin = _create_footer_window #*@layout
203
+ r = 0; c = 1;
204
+ case type
205
+ when :error
206
+ @color ||= 'red'
207
+ @bgcolor ||= 'black'
208
+ else
209
+ @color ||= :white
210
+ @bgcolor ||= :black
211
+ end
212
+ color_pair = get_color($promptcolor, @color, @bgcolor)
213
+ ewin.bkgd(Ncurses.COLOR_PAIR(color_pair));
214
+ ewin.printstring r, c, text, color_pair
215
+ ewin.printstring r+1, c, "Press a key", color_pair
216
+ ewin.wrefresh
217
+ ewin.getchar
218
+ ewin.destroy
219
+ end
220
+ #
221
+ # Alternative to confirm dialog, if you want this look and feel, at last 2 lines of screen
222
+ # @param [String] text to prompt
223
+ # @return [true, false] 'y' is true, all else if false
224
+ def confirm_window text, aconfig={}, &block
225
+ case text
226
+ when RubyCurses::Variable # added 2011-09-20 incase variable passed
227
+ text = text.get_value
228
+ when Exception
229
+ text = text.to_s
230
+ end
231
+ ewin = _create_footer_window
232
+ r = 0; c = 1;
233
+ aconfig.each_pair { |k,v| instance_variable_set("@#{k}",v) }
234
+ @color ||= :white
235
+ @bgcolor ||= :black
236
+ color_pair = get_color($promptcolor, @color, @bgcolor)
237
+ ewin.bkgd(Ncurses.COLOR_PAIR(color_pair));
238
+ ewin.printstring r, c, text, color_pair
239
+ ewin.printstring r+1, c, "[y/n]", color_pair
240
+ ewin.wrefresh
241
+ #retval = false
242
+ retval = :NO # consistent with confirm
243
+ begin
244
+ ch = ewin.getchar
245
+ retval = :YES if ch.chr == 'y'
246
+ ensure
247
+ ewin.destroy
248
+ end
249
+ retval
250
+ end
251
+ # class created to display multiple messages without asking for user to hit a key
252
+ # returns a window to which one can keep calling printstring with 0 or 1 as row.
253
+ # destroy when finished.
254
+ # Also, one can pause if one wants, or linger.
255
+ # This is meant to be a replacement for the message_immediate and message_raw
256
+ # I was trying out in App.rb. 2011-10-1 1:27 AM
257
+ # Testing from test2.rb
258
+ # TODO: add option of putting progress_bar
259
+ class StatusWindow
260
+ attr_reader :h, :w, :top, :left # height, width, top row, left col of window
261
+ attr_reader :win
262
+ attr_accessor :color_pair
263
+ def initialize config={}, &block
264
+ @color_pair = config[:color_pair]
265
+ @row_offset = config[:row_offset] || 0
266
+ @col_offset = config[:col_offset] || 0
267
+ create_window *config[:layout]
268
+ end
269
+ def create_window h = 2 , w = Ncurses.COLS-0, t = Ncurses.LINES-2, l = 0
270
+ return @win if @win
271
+ @win = VER::Window.new(h, w , t, l)
272
+ @h = h ; @w = w; @top = t ; @left = l
273
+ @color_pair ||= get_color($promptcolor, 'white','black')
274
+ @win.bkgd(Ncurses.COLOR_PAIR(@color_pair));
275
+ @win
276
+ end
277
+ # creates a color pair based on given bg and fg colors as strings
278
+ #def set_colors bgcolor, fgcolor='white'
279
+ #@color_pair = get_color($datacolor, 'white','black')
280
+ #end
281
+ # prints a string on given row (0 or 1)
282
+ def printstring r, c, text, color_pair=@color_pair
283
+ create_window unless @win
284
+ show unless @visible
285
+ r = @h-1 if r > @h-1
286
+ #@win.printstring r, c, ' '*@w, @color_pair
287
+ # FIXME this padding overwrites the border and the offset means next line wiped
288
+ # However, now it may now totally clear a long line.
289
+ @win.printstring r+@row_offset, c+@col_offset, "%-*s" % [@w-(@col_offset*2)-c, text], color_pair
290
+ @win.wrefresh
291
+ end
292
+ # print given strings from first first column onwards
293
+ def print *textarray
294
+ create_window unless @win
295
+ show unless @visible
296
+ c = 1
297
+ textarray.each_with_index { |s, i|
298
+ @win.printstring i+@row_offset, c+@col_offset, "%-*s" % [@w-(@col_offset*2)-c, s], @color_pair
299
+ }
300
+ @win.wrefresh
301
+ end
302
+ def pause; @win.getchar; end
303
+ # pauses with the message, but doesn't ask the user to press a key.
304
+ # If he does, the key should be used by underlying window.
305
+ # Do not call destroy if you call linger, it does the destroy.
306
+ def linger caller_window=nil
307
+ begin
308
+ if caller_window
309
+ ch = @win.getchar
310
+ caller_window.ungetch(ch) # will this be available to underlying window XXX i think not !!
311
+ else
312
+ sleep 1
313
+ end
314
+ ensure
315
+ destroy
316
+ end
317
+ end
318
+ # caller must destroy after he's finished printing messages, unless
319
+ # user calls linger
320
+ def destroy; @win.destroy if @win; @win = nil; end
321
+ def hide
322
+ @win.hide
323
+ @visible = false
324
+ end
325
+ def show
326
+ @win.show unless @visible
327
+ @visible = true
328
+ end
329
+ end
330
+ # returns instance of a status_window for sending multiple
331
+ # statuses during some process
332
+ def status_window aconfig={}, &block
333
+ return StatusWindow.new aconfig
334
+ end
335
+ # this is a popup dialog box on which statuses can be printed as a process is taking place.
336
+ # I am reusing StatusWindow and so there's an issue since I've put a box, so in clearing
337
+ # the line, I might overwrite the box
338
+ def progress_dialog aconfig={}, &block
339
+ aconfig[:layout] = [10,60,10,20]
340
+ window = status_window aconfig
341
+ height = 10; width = 60
342
+ window.win.print_border_mb 1,2, height, width, $normalcolor, FFI::NCurses::A_REVERSE
343
+ return window
344
+ end
345
+ #
161
346
  =begin
162
347
  http://www.kammerl.de/ascii/AsciiSignature.php
163
348
  ___
@@ -58,9 +58,6 @@ module RubyCurses
58
58
  def each(&blk)
59
59
  @list.each(&blk)
60
60
  end
61
- #def each
62
- # @list.each { |item| yield item }
63
- #end
64
61
  # not sure how to do this XXX removed on 2009-01-14 12:28
65
62
  #def <=>(other)
66
63
  # @list <=> other
@@ -309,7 +306,13 @@ module RubyCurses
309
306
  when KEY_ENTER, 10, 13
310
307
  # if you press ENTER without selecting, it won't come here
311
308
  # it will fire button OK's fire, if that's the default button
312
- fire_handler :PRESS, @listbox.focussed_index
309
+
310
+ # returns an array of indices if multiple selection
311
+ if @listbox.selection_mode == :multiple
312
+ fire_handler :PRESS, @listbox
313
+ else
314
+ fire_handler :PRESS, @listbox.focussed_index
315
+ end
313
316
  # since Listbox is handling enter, COMBO_SELECT will not be fired
314
317
  # $log.debug "popup ENTER : #{field.name}" if !field.nil?
315
318
  @stop = true
@@ -462,8 +465,6 @@ module RubyCurses
462
465
  @win_left = 0
463
466
  @win_top = 0
464
467
 
465
- #x safe_create_buffer # 2010-01-04 12:36 BUFFERED moved here 2010-01-05 18:07
466
- #x print_borders unless @win.nil? # in messagebox we don;t have window as yet!
467
468
  # next 2 lines carry a redundancy
468
469
  select_default_values
469
470
  # when the combo box has a certain row in focus, the popup should have the same row in focus
@@ -471,6 +472,7 @@ module RubyCurses
471
472
  install_keys
472
473
  init_vars
473
474
  install_list_keys
475
+ bind(:PROPERTY_CHANGE){|e| @cell_renderer = nil } # will be recreated if anything changes 2011-09-28 V1.3.1
474
476
 
475
477
  if @list && !@list.selected_index.nil?
476
478
  set_focus_on @list.selected_index # the new version
@@ -627,7 +629,7 @@ module RubyCurses
627
629
  end
628
630
  end
629
631
  # added 2010-09-15 00:11 to make life easier
630
- def_delegators :@list, :insert, :remove_all, :delete_at, :include?
632
+ def_delegators :@list, :insert, :remove_all, :delete_at, :include?, :each, :values
631
633
  # get element at
632
634
  # @param [Fixnum] index for element
633
635
  # @return [Object] element
@@ -661,7 +663,8 @@ module RubyCurses
661
663
  startcol = @col
662
664
  startrow = @row
663
665
  @color_pair = get_color($datacolor)
664
- bordercolor = @border_color || $datacolor
666
+ # bordercolor = @border_color || $datacolor # changed 2011 dts
667
+ bordercolor = @border_color || @color_pair
665
668
  borderatt = @border_attrib || Ncurses::A_NORMAL
666
669
 
667
670
  #$log.debug "rlistb #{name}: window.print_border #{startrow}, #{startcol} , h:#{height}, w:#{width} , @color_pair, @attr "
@@ -737,7 +740,7 @@ module RubyCurses
737
740
  when @KEY_CLEAR_SELECTION
738
741
  clear_selection
739
742
  @repaint_required = true
740
- when 27, ?\C-c.getbyte(0)
743
+ when 27, ?\C-c.getbyte(0), ?\C-g.getbyte(0)
741
744
  editing_canceled @current_index if @cell_editing_allowed
742
745
  cancel_block # block
743
746
  $multiplier = 0
@@ -847,7 +850,8 @@ module RubyCurses
847
850
  # @return [Boolean] false if no data
848
851
  def on_enter
849
852
  if @list.nil? || @list.size == 0
850
- Ncurses.beep
853
+ #Ncurses.beep
854
+ get_window.ungetch($current_key) # 2011-10-4 push key back so form can go next
851
855
  return :UNHANDLED
852
856
  end
853
857
  on_enter_row @current_index
@@ -886,10 +890,10 @@ module RubyCurses
886
890
  editor.component.curpos = 0 # reset it after search, if user scrols down
887
891
  #editor.component.graphic = @graphic # 2010-01-05 00:36 TRYING OUT BUFFERED
888
892
  ## override is required if the listbox uses a buffer
889
- if @should_create_buffer
890
- $log.debug " overriding editors comp with GRAPHIC #{@graphic} "
891
- editor.component.override_graphic(@graphic) # 2010-01-05 00:36 TRYING OUT BUFFERED
892
- end
893
+ #if @should_create_buffer # removed on 2011-09-29
894
+ #$log.debug " overriding editors comp with GRAPHIC #{@graphic} "
895
+ #editor.component.override_graphic(@graphic) # 2010-01-05 00:36 TRYING OUT BUFFERED
896
+ #end
893
897
  set_form_col 0 #@left_margin
894
898
 
895
899
  # set original value so we can cancel
@@ -951,7 +955,6 @@ module RubyCurses
951
955
  # processing. also, it pans the data horizontally giving the renderer
952
956
  # a section of it.
953
957
  def repaint
954
- safe_create_buffer # 2010-01-04 12:36 BUFFERED moved here 2010-01-05 18:07
955
958
  return unless @repaint_required
956
959
  # not sure where to put this, once for all or repeat 2010-02-17 23:07 RFED16
957
960
  my_win = @form ? @form.window : @target_window
@@ -972,7 +975,7 @@ module RubyCurses
972
975
  $log.debug " rlistbox #{row_count} "
973
976
  if rc > 0 # just added in case no data passed
974
977
  tr = @toprow
975
- acolor = get_color $datacolor
978
+ acolor = get_color $datacolor # should be set once, if color or bgcolor changs TODO FIXME
976
979
  h = scrollatrow()
977
980
  r,c = rowcol
978
981
  0.upto(h) do |hh|
@@ -1015,8 +1018,6 @@ module RubyCurses
1015
1018
  end # rc == 0
1016
1019
  #@table_changed = false
1017
1020
  @repaint_required = false
1018
- @buffer_modified = true # required by form to call buffer_to_screen BUFFERED
1019
- buffer_to_window # RFED16 2010-02-17 23:16
1020
1021
  end
1021
1022
  # the idea here is to allow users who subclass Listbox to easily override parts of the cumbersome repaint
1022
1023
  # method. This assumes your List has some data, but you print a lot more. Now you don't need to
@@ -1139,7 +1140,8 @@ module RubyCurses
1139
1140
  # the earlier painted edited comp in yellow keeps showing until a key is pressed
1140
1141
 
1141
1142
  def set_buffering params
1142
- super
1143
+ $log.warn "CALLED set_buffering in LISTBOX listbox " if $log.debug?
1144
+ super # removed from widget 2011-09-29
1143
1145
  ## Ensuring that changes to top get reflect in editing comp
1144
1146
  #+ otherwise it raises an exception. Still the earlier cell_edit is being
1145
1147
  #+ printed where it was , until a key is moved
@@ -1159,6 +1161,23 @@ module RubyCurses
1159
1161
  @repaint_required = true
1160
1162
  end
1161
1163
 
1164
+ # trying to simplify usage. The Java way has made listboxes very difficult to use
1165
+ # Returns selected indices
1166
+ # Indices are often required since the renderer may modify the values displayed
1167
+ #
1168
+ def get_selected_indices
1169
+ @list_selection_model.get_selected_indices
1170
+ end
1171
+
1172
+ # Returns selected values
1173
+ #
1174
+ def get_selected_values
1175
+ selected = []
1176
+ @list_selection_model.get_selected_indices.each { |i| selected << list_data_model[i] }
1177
+ return selected
1178
+ end
1179
+ alias :selected_values :get_selected_values
1180
+ alias :selected_indices :get_selected_indices
1162
1181
 
1163
1182
  # ADD HERE
1164
1183
  end # class listb
data/lib/rbcurse/rmenu.rb CHANGED
@@ -2,46 +2,52 @@
2
2
  * Name: menu and related classes
3
3
  * Description
4
4
  * Author: rkumar
5
+ * I am redoing this totally, since this was one my first ruby programs and needs
6
+ * simplification. It was hard to maintain.
5
7
  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
8
+ -- cursor to be on current menuitem if possible ... UNABLE TO !!
9
+ -- Number and letter indexing for item_list
10
+ -- Use Box characters and hline for separator
11
+ -- MenuSeparator and MenuItem should be common to popups and menus, so we don't need
12
+ 2 separate names, there was clobbering the same namespace.
13
+
14
+ ?? Also, we should move to Action classes as against just blokcs of code. And action class would have
14
15
  a user friendly string to identifiy the action, as well as a disabled option.
15
- NOTE on 2010-09-10 11:40 : this interface is based on Java's and is not block friendy. Also, i tried to keep the same class to work for horizontal menu bar and vertical submenus as per java's classes and this makes the code very complex. I should just make 2 classes and keep it simple.
16
16
 
17
17
  --------
18
- * Date: 2008-11-14 23:43
18
+ * Date: 2011-09-23 (old 2008-11-14 23:43 )
19
+ == Major changes v1.3.1
20
+ 2011-09-24 V1.3.1 added item_list for dynamic menuitem generation, see examples/menu1.rb
21
+ 2011-09-24 V1.3.1 added multicolumn outputs
22
+ 2011-09-24 V1.3.1 left and right keys on menua, C-g to abort
23
+
19
24
  * License:
20
25
  Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
21
26
 
22
27
  =end
23
- require 'rubygems'
24
- #require 'ncurses'
25
- require 'logger'
28
+ #require 'logger'
26
29
  require 'rbcurse'
27
30
 
28
- #include Ncurses # FFI 2011-09-8
29
31
  include RubyCurses
30
32
  module RubyCurses
31
33
  extend self
32
34
 
33
35
 
36
+ # The separator that separates menuitems, helping to group them.
34
37
  class MenuSeparator
35
38
  attr_accessor :enabled
36
39
  attr_accessor :parent
37
40
  attr_accessor :row
38
41
  attr_accessor :col
42
+ attr_accessor :coffset
39
43
  attr_accessor :width
44
+ attr_accessor :color, :bgcolor # 2011-09-25 V1.3.1
40
45
  def initialize
41
46
  @enable = false
42
47
  end
43
48
  def repaint
44
- @parent.window.printstring( @row, 0, "|%s|" % ("-"*@width), $reversecolor)
49
+ acolor = get_color($reversecolor, @color, @bgcolor)
50
+ @parent.window.printstring( @row, 0, "|%s|" % ("-"*@width), acolor)
45
51
  end
46
52
  def destroy
47
53
  end
@@ -54,18 +60,31 @@ module RubyCurses
54
60
  end
55
61
  end
56
62
  ##
63
+ # Items in menus. These will usually result in an action which closes the entire
64
+ # menubar.
57
65
  class MenuItem
58
66
  attr_accessor :parent
59
67
  # attr_accessor :window
60
68
  attr_accessor :row
61
69
  attr_accessor :col
70
+ attr_accessor :coffset
62
71
  attr_accessor :width
63
72
  attr_writer :accelerator
64
73
  attr_accessor :enabled
74
+ attr_accessor :color, :bgcolor # 2011-09-25 V1.3.1
75
+ attr_accessor :color_pair # 2011-09-25 V1.3.1
76
+ attr_reader :active_index # 2011-09-24 V1.3.1 trying to do a right
65
77
  attr_accessor :text, :mnemonic # changed reader to accessor
66
78
  def initialize text, mnemonic=nil, &block
67
79
  @text = text
68
80
  @enabled = true
81
+ # check for mnem that is not one char, could be an accelerator
82
+ if mnemonic
83
+ if mnemonic.length != 1
84
+ $log.error "MenuItem #{text} mnemonic #{mnemonic} should be one character. Maybe you meant accelerator? "
85
+ mnemonic = nil
86
+ end
87
+ end
69
88
  @mnemonic = mnemonic
70
89
  instance_eval &block if block_given?
71
90
  end
@@ -75,6 +94,7 @@ module RubyCurses
75
94
  def command *args, &block
76
95
  $log.debug ">>>command : #{@text} "
77
96
  @command = block if block_given?
97
+ alert "Command nil or some error! #{text} " unless @command
78
98
  @args = args
79
99
  end
80
100
  # add accelerator for a menu item
@@ -92,15 +112,17 @@ module RubyCurses
92
112
  @accelerator = val[0]
93
113
  end
94
114
  end
95
- def on_enter
115
+ def on_enter #item
96
116
  highlight
117
+ #@parent.window.wmove @row, @col+1 # 2011-09-25 V1.3.1 NO EFFECT
97
118
  end
98
119
  def on_leave
99
120
  highlight false
100
121
  end
101
122
  ## XXX it could be a menu again
123
+ # We should not be firing a :NO_MENUITEMS
102
124
  def fire
103
- #$log.debug ">>>fire menuitem : #{@text} #{@command} "
125
+ $log.debug ">>>fire menuitem : #{@text} #{@command} "
104
126
  @command.call self, *@args if !@command.nil?
105
127
  @parent.clear_menus
106
128
  return :CLOSE # added 2009-01-02 00:09 to close only actions, not submenus
@@ -111,10 +133,14 @@ module RubyCurses
111
133
  #$log.debug "HL XXX #{self} - > #{@parent} parent nil"
112
134
  end
113
135
  if tf
114
- color = $datacolor
136
+ #color = $datacolor
115
137
  #@parent.window.mvchgat(y=@row, x=1, @width, Ncurses::A_NORMAL, color, nil)
116
138
  # above line did not work in vt100, 200 terminals, next works.
117
- @parent.window.mvchgat(y=@row, x=1, @width, Ncurses::A_REVERSE, $reversecolor, nil)
139
+ # @parent.window.mvchgat(y=@row, x=1, @width, Ncurses::A_REVERSE, $reversecolor, nil) # changed 2011 dts 2011-09-24 multicolumn, 1 skips the border
140
+ @color_pair ||= get_color($reversecolor, @color, @bgcolor)
141
+ @parent.window.mvchgat(y=@row, x=@col+1, @width, Ncurses::A_REVERSE, @color_pair, nil)
142
+ #@parent.window.mvaddch @row, @col, "*".ord
143
+ #@parent.window.wmove @row, @col # 2011-09-25 V1.3.1 NO EFFECT
118
144
  else
119
145
  repaint
120
146
  end
@@ -126,11 +152,18 @@ module RubyCurses
126
152
  # return
127
153
  end
128
154
  r = @row
129
- acolor = $reversecolor
130
- acolor = get_color($reversecolor, 'green', 'white') if !@enabled
131
- @parent.window.printstring( @row, 0, "|%-*s|" % [@width, text], acolor)
155
+ c = @col
156
+ ltext = text
157
+ ltext = "* No Items *" if text == :NO_MENUITEMS
158
+ @color_pair = get_color($reversecolor, @color, @bgcolor)
159
+ #acolor = $reversecolor
160
+ acolor = @color_pair
161
+ acolor = get_color($reversecolor, 'green', @bgcolor) if !@enabled
162
+ # @parent.window.printstring( @row, 0, "|%-*s|" % [@width, ltext], acolor) # changed 2011 2011-09-24
163
+ @parent.window.printstring( @row, c, "|%-*s|" % [@width, ltext], acolor)
132
164
  if @enabled # 2010-09-10 23:56
133
165
  if !@accelerator.nil?
166
+ # FIXME add c earlier 0 was offset
134
167
  @parent.window.printstring( r, (@width+1)-@accelerator.length, @accelerator, acolor)
135
168
  elsif !@mnemonic.nil?
136
169
  m = @mnemonic
@@ -140,17 +173,20 @@ module RubyCurses
140
173
  # prev line changed since not working in vt100 and vt200
141
174
  @parent.window.printstring( r, ix+1, charm, $reversecolor, 'reverse') if !ix.nil?
142
175
  end
176
+ #@parent.window.wmove r, c # NO EFFECT
143
177
  end
144
178
  end
145
179
  def destroy
146
180
  $log.debug "DESTROY menuitem #{@text}"
147
181
  end
148
182
  end
149
- ##class Menu
150
- class Menu < MenuItem ## NEW
183
+ ## class Menu. Contains menuitems, and can be a menuitem itself.
184
+ # Opens out another list of menuitems.
185
+ class Menu < MenuItem
151
186
  attr_accessor :parent
152
187
  attr_accessor :row
153
188
  attr_accessor :col
189
+ attr_accessor :coffset
154
190
  attr_accessor :width
155
191
  attr_accessor :enabled
156
192
  attr_reader :text
@@ -173,7 +209,9 @@ module RubyCurses
173
209
  super text, nil, &block
174
210
  @row ||=10
175
211
  @col ||=10
212
+ @coffset = 0
176
213
  @@menus ||= []
214
+ @active_index = nil # 2011-09-25 V1.3.1 otherwise crashing in select_right
177
215
  end
178
216
  ## called upon firing so when we next show menubar there are not any left overs in here.
179
217
  def clear_menus
@@ -192,7 +230,7 @@ module RubyCurses
192
230
 
193
231
  # add item method which could be used from blocks
194
232
  # add 2010-09-10 12:20 simplifying
195
- def item text, mnem, &block
233
+ def item text, mnem=nil, &block
196
234
  #$log.debug "YYYY inside M: menuitem text #{text} "
197
235
  m = MenuItem.new text, mnem, &block
198
236
  add m
@@ -227,30 +265,64 @@ module RubyCurses
227
265
  @items.delete n
228
266
  end
229
267
  end
268
+ # generate an item list at runtime for this menu
269
+ def item_list *args, &block
270
+ $log.debug ">>>item_list : #{@text} "
271
+ @item_list = block if block_given?
272
+ @item_list_args = args
273
+ end
230
274
  # menu -
231
275
  def fire
232
276
  $log.debug "menu fire called: #{text} "
233
277
  if @window.nil?
234
278
  #repaint
235
- create_window
279
+ # added 2011-09-24 adding ability to generate list of items
280
+ if @item_list
281
+ # generate a list, but we need to know what to do with that list.
282
+ @items = []
283
+ l = @item_list.call self, *@item_list_args if !@item_list.nil?
284
+ if l.nil? || l.size == 0
285
+ item(:NO_MENUITEMS)
286
+ else
287
+ # for each element returned create a menuitem, and attach the command to it.
288
+ l.each { |e| it = item(e);
289
+ if @command # there should be a command otherwise what's the point
290
+ it.command(@args) do @command.call(it, it.text) end;
291
+ else
292
+ it.command(@args) do alert("No command attached to #{it.text} ") end;
293
+ $log.warn "No command attached to item_list "
294
+ end
295
+ }
296
+ end
297
+ $log.debug "menu got items #{@items.count} "
298
+ end
299
+ if @items.empty? # user did not specify any items
300
+ item(:NO_MENUITEMS)
301
+ end
302
+ create_window
236
303
  if !@parent.is_a? RubyCurses::MenuBar
237
304
  @parent.current_menu << self
238
305
  @@menus << self # NEW
239
306
  end
240
307
  else
241
308
  ### shouod this not just show ?
242
- $log.debug "menu fire called: #{text} ELSE XXX WHEN IS THIS CALLED ? 658 "
243
- return @items[@active_index].fire # this should happen if selected. else selected()
309
+ $log.debug "menu fire called: #{text} ELSE XXX WHEN IS THIS CALLED ? 658 #{@items[@active_index].text} "
310
+ if @active_index # sometimes no menu item specified 2011-09-24 NEWMENU
311
+ return @items[@active_index].fire # this should happen if selected. else selected()
312
+ end
244
313
  end
245
314
  #@action.call if !@action.nil?
246
315
  end
247
316
  # user has clicked down, we shoud display items
248
317
  # DRAW menuitems
249
318
  def repaint # menu.repaint
250
- return if @items.nil? or @items.empty?
319
+ # OMG will not print anything if no items !
320
+ # When we do item generation this list will be empty
321
+ #return if @items.nil? or @items.empty? # commented 2011-09-24 NEWMENU
251
322
  #$log.debug "menu repaint: #{text} row #{@row} col #{@col} "
323
+ @color_pair = get_color($reversecolor, @color, @bgcolor)
252
324
  if !@parent.is_a? RubyCurses::MenuBar
253
- @parent.window.printstring( @row, 0, "|%-*s>|" % [@width-1, text], $reversecolor)
325
+ @parent.window.printstring( @row, 0, "|%-*s>|" % [@width-1, text], @color_pair)
254
326
  @parent.window.refresh
255
327
  end
256
328
  if @window.nil?
@@ -302,14 +374,55 @@ module RubyCurses
302
374
  #select_item @items.length-1
303
375
  end
304
376
  end
377
+ #
378
+ # If multi-column menuitems then try going to a left item (prev column same row)
379
+ # NOTE It should only come here if items are open, otherwise row and col will be blank.
380
+ # NOTE active_index nil means no items open
381
+ #
382
+ def select_left_item
383
+ return :UNHANDLED if @items.nil? or @items.empty? or @active_index.nil?
384
+ index = nil
385
+ crow = @items[@active_index].row
386
+ ccol = @items[@active_index].col
387
+ @items.each_with_index { |e, i| index = i if e.row == crow && e.col < ccol }
388
+ if index
389
+ select_item index
390
+ else
391
+ return :UNHANDLED
392
+ end
393
+ end
394
+ # @since 1.3.1 2011-09-24
395
+ # If multi-column menuitems then try going to a right item (next column same row)
396
+ # Only if items are open, not from a menubar menu
397
+ def select_right_item
398
+ return :UNHANDLED if @items.nil? or @items.empty? or @active_index.nil?
399
+ crow = @items[@active_index].row
400
+ ccol = @items[@active_index].col
401
+ #alert "inside select right with #{@items.size} #{@items[@active_index].text}: items. r #{crow} col #{ccol} "
402
+ index = nil
403
+ @items.each_with_index { |e, i|
404
+ $log.debug " select_right #{e.row} == #{crow} , #{e.col} > #{ccol} " if $log.debug?
405
+ if e.row == crow && e.col > ccol
406
+ index = i
407
+ $log.debug "YYY select_right #{e.row} == #{crow} , #{e.col} > #{ccol} FOUND #{i} " if $log.debug?
408
+ break
409
+ end
410
+ }
411
+ if index
412
+ select_item index
413
+ else
414
+ return :UNHANDLED
415
+ end
416
+ end
305
417
  def on_enter # menu.on_enter
306
418
  #$log.debug "menu onenter: #{text} #{@row} #{@col} "
307
419
  # call parent method. XXX
308
- if @parent.is_a? RubyCurses::MenuBar
309
- @parent.window.printstring( @row, @col, " %s " % text, $datacolor)
310
- else
420
+ #if @parent.is_a? RubyCurses::MenuBar
421
+ #acolor = get_color($datacolor, @bgcolor, @color)
422
+ #@parent.window.printstring( @row, @col, " %s " % text, acolor)
423
+ #else
311
424
  highlight
312
- end
425
+ #end
313
426
  if !@window.nil? #and @parent.selected
314
427
  #$log.debug "menu onenter: #{text} calling window,show"
315
428
  @window.show
@@ -324,8 +437,10 @@ module RubyCurses
324
437
  def on_leave # menu.on_leave
325
438
  #$log.debug "menu onleave: #{text} #{@row} #{@col} "
326
439
  # call parent method. XXX
440
+ @color_pair ||= get_color($reversecolor, @color, @bgcolor)
327
441
  if @parent.is_a? RubyCurses::MenuBar
328
- @parent.window.printstring( @row, @col, " %s " % text, $reversecolor)
442
+ # @parent.window.printstring( @row, @col, " %s " % text, $reversecolor) # changed 2011 2011-09-24
443
+ @parent.window.printstring( @row, @col, " %s " % text, @color_pair)
329
444
  @window.hide if !@window.nil?
330
445
  else
331
446
  #$log.debug "MENU SUBMEN. menu onleave: #{text} #{@row} #{@col} "
@@ -337,43 +452,87 @@ module RubyCurses
337
452
  end
338
453
  end
339
454
  def highlight tf=true # menu
340
- #$log.debug "MENU SUBMENU menu highlight: #{text} #{@row} #{@col}, PW #{@parent.width} "
341
- color = tf ? $datacolor : $reversecolor
342
- att = tf ? Ncurses::A_REVERSE : Ncurses::A_NORMAL
343
- #@parent.window.mvchgat(y=@row, x=1, @width, Ncurses::A_NORMAL, color, nil)
344
- #@parent.window.mvchgat(y=@row, x=1, @parent.width, Ncurses::A_NORMAL, color, nil)
345
- # above line did not work with vt100/vt200 next does
346
- @parent.window.mvchgat(y=@row, x=1, @parent.width, att, $reversecolor, nil)
347
- @parent.window.wrefresh
348
- end
349
- def create_window # menu
350
- margin = 3
351
- @width = array_width @items
352
- #$log.debug "create window menu #{@text}: #{@row} ,#{@col},wd #{@width} "
353
- @layout = { :height => @items.length+3, :width => @width+margin, :top => @row+1, :left => @col }
455
+ if @parent.is_a? RubyCurses::MenuBar # top level menu
456
+ #acolor = get_color($datacolor, @bgcolor, @color)
457
+ #@parent.window.printstring( @row, @col, " %s " % text, acolor)
458
+ @color_pair ||= get_color($reversecolor, @color, @bgcolor)
459
+ att = Ncurses::A_REVERSE
460
+ @parent.window.mvchgat(y=@row, x=@col+1, text.length+1, att, @color_pair, nil)
461
+ else
462
+ #$log.debug "MENU SUBMENU menu highlight: #{text} #{@row} #{@col}, PW #{@parent.width} "
463
+ acolor = tf ? $datacolor : $reversecolor
464
+ att = tf ? Ncurses::A_REVERSE : Ncurses::A_NORMAL
465
+ #@parent.window.mvchgat(y=@row, x=1, @width, Ncurses::A_NORMAL, color, nil)
466
+ #@parent.window.mvchgat(y=@row, x=1, @parent.width, Ncurses::A_NORMAL, color, nil)
467
+ # above line did not work with vt100/vt200 next does
468
+ # @parent.window.mvchgat(y=@row, x=1, @parent.width, att, $reversecolor, nil) # changed 2011 2011-09-24
469
+ @parent.window.mvchgat(y=@row, x=1, @parent.width, att, @color_pair, nil)
470
+ @parent.window.wrefresh
471
+ end
472
+ end
473
+ def create_window # menu
474
+ margin = 2 # flush against parent
475
+ @width = array_width(@items) + 1 # adding 1 since menus append a ">" 2011-09-24
476
+ $log.debug "create window menu #{@text}: r #{@row} ,col #{@col}, wd #{@width} "
477
+ t = @row+1
478
+ h = @items.length+3
479
+ ww = @width+margin
480
+ ww1 = @width
481
+ max = Ncurses.LINES-1
482
+ if t + h > max
483
+ t = 2 # one below menubar, not touching
484
+ if h > max
485
+ i = ((h*1.0)/max).ceil
486
+ h = max - 1
487
+ ww = ww * i # FIXME we need to calculate
488
+ end
489
+ end # t + 1
490
+ $log.debug "create window menu #{@text}: t #{t} ,h #{h}, w: #{ww} , col #{@col} max #{max} "
491
+
492
+ #@layout = { :height => @items.length+3, :width => ww, :top => @row+1, :left => @col }
493
+ # earlier col had the offset to start the next level, I was not using it to print
494
+ # but with mulitple cols i am using it. So, this col will overwrite existing menu.
495
+ @layout = { :height => h-1, :width => ww, :top => t, :left => @coffset }
354
496
  @win = VER::Window.new(@layout)
355
497
  @window = @win
356
- @win.bkgd(Ncurses.COLOR_PAIR($datacolor));
498
+ @color_pair ||= get_color($datacolor, @color, @bgcolor)
499
+ @rev_color_pair ||= get_color($reversecolor, @color, @bgcolor)
500
+ @win.bkgd(Ncurses.COLOR_PAIR(@color_pair));
357
501
  @panel = @win.panel
358
- @window.printstring( 0, 0, "+%s+" % ("-"*@width), $reversecolor)
502
+ #@window.printstring( 0, 0, "+%s+" % ("-"*@width), $reversecolor)
503
+ @window.printstring( 0, 0, "+%s+" % ("-"*(ww1)), @rev_color_pair)
504
+ saved_r = 1
359
505
  r = 1
506
+ #saved_c = @col+@width+margin # margins???
507
+ saved_c = 0 ; # actual program uses 0 in repain for col
508
+ c = saved_c
509
+ $log.debug "create window menu #{@text}: first col r #{r} ,c #{c}"
360
510
  @items.each do |item|
361
- #if item == :SEPARATOR
362
- # @window.printstring( r, 0, "|%s|" % ("-"*@width), $reversecolor)
363
- #else
511
+ #break if r > h # added 2011-09-24 for large number of items - causes error
512
+ if r >= h-2
513
+ @window.printstring( h-2, c, "+%s+" % ("-"*(ww1)), @rev_color_pair)
514
+ r = saved_r
515
+ c += (@width + 2)
516
+ @window.printstring( 0, c, "+%s+" % ("-"*(ww1)), @rev_color_pair)
517
+ $log.debug "create window menu #{@text}: new col r #{r} ,c #{c}, #{item.text} "
518
+ end
364
519
  item.row = r
365
- item.col = 0
366
- item.col = @col+@width+margin # margins???
367
- # $log.debug "create window menu loop passing col : #{item.col} "
520
+ item.col = c
521
+ item.coffset = @coffset+@width+margin # margins???
522
+
523
+
368
524
  item.width = @width
369
525
  #item.window = @window
370
526
  item.parent = self
527
+ item.color = @color; item.bgcolor = @bgcolor
371
528
  item.repaint
372
- #end
373
529
  r+=1
374
530
  end
375
- @window.printstring( r, 0, "+%s+" % ("-"*@width), $reversecolor)
376
- select_item 0
531
+ # @window.printstring( r, 0, "+%s+" % ("-"*@width), $reversecolor) # changed 2011 2011-09-24
532
+ @window.printstring( h-2, 0, "+%s+" % ("-"*(ww1)), @rev_color_pair)
533
+ # in case of multiple rows
534
+ @window.printstring( r, c, "+%s+" % ("-"*(ww1)), @rev_color_pair)
535
+ select_item 0
377
536
  @window.refresh
378
537
  return @window
379
538
  end
@@ -415,7 +574,7 @@ module RubyCurses
415
574
  cmenu.select_next_item
416
575
  #return cmenu.fire # XXX 2010-10-16 21:39 trying out
417
576
  if cmenu.is_a? RubyCurses::Menu
418
- #alert "is a menu"
577
+ #alert "is a menu" # this gets triggered even when we are on items
419
578
  end
420
579
  when KEY_UP
421
580
  cmenu.select_prev_item
@@ -426,27 +585,48 @@ module RubyCurses
426
585
  #$log.debug "LEFT IN MENU : #{cmenu.parent.class} len: #{cmenu.parent.current_menu.length}"
427
586
  #$log.debug "left IN MENU : #{cmenu.parent.class} len: #{cmenu.current_menu.length}"
428
587
  end
429
- if cmenu.parent.is_a? RubyCurses::Menu and !cmenu.parent.current_menu.empty?
430
- #$log.debug " ABOU TO DESTROY DUE TO LEFT"
431
- cmenu.parent.current_menu.pop
432
- @@menus.pop ## NEW
433
- cmenu.destroy
434
- else
435
- return :UNHANDLED
588
+ ret = cmenu.select_left_item # 2011-09-24 V1.3.1 attempt to goto left item if columns
589
+ if ret == :UNHANDLED
590
+ if cmenu.parent.is_a? RubyCurses::MenuBar #and !cmenu.parent.current_menu.empty?
591
+ #$log.debug " ABOU TO DESTROY DUE TO LEFT"
592
+ cmenu.current_menu.pop
593
+ @@menus.pop ## NEW
594
+ cmenu.destroy
595
+ return :UNHANDLED
596
+ end
597
+ # LEFT on a menu list allows me to close and return to higher level
598
+ if cmenu.parent.is_a? RubyCurses::Menu #and !cmenu.parent.current_menu.empty?
599
+ #$log.debug " ABOU TO DESTROY DUE TO LEFT"
600
+ cmenu.current_menu.pop
601
+ @@menus.pop ## NEW
602
+ cmenu.destroy
603
+ #return :UNHANDLED
604
+ end
436
605
  end
437
606
  when KEY_RIGHT
438
- #$log.debug "RIGHTIN MENU : "
439
- if cmenu.parent.is_a? RubyCurses::Menu
607
+ $log.debug "RIGHTIN MENU : #{text} "
608
+ if cmenu.active_index
609
+ if cmenu.items[cmenu.active_index].is_a? RubyCurses::Menu
610
+ #alert "could fire here cmenu: #{cmenu.text}, par: #{cmenu.parent.text} "
611
+ cmenu.fire
612
+ return
440
613
  #$log.debug "right IN MENU : #{cmenu.parent.class} len: #{cmenu.parent.current_menu.length}"
441
614
  #$log.debug "right IN MENU : #{cmenu.parent.class} len: #{cmenu.current_menu.length}"
442
615
  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
616
+ end
617
+ # This introduces a bug if no open items
618
+ ret = cmenu.select_right_item # 2011-09-24 V1.3.1 attempt to goto right item if columns
619
+ #alert "attempting to select right #{ret} "
620
+ if ret == :UNHANDLED
621
+ #if cmenu.parent.is_a? RubyCurses::Menu and !cmenu.parent.current_menu.empty?
622
+ if cmenu.parent.is_a? RubyCurses::MenuBar #and !cmenu.current_menu.empty?
623
+ $log.debug " ABOU TO DESTROY DUE TO RIGHT"
624
+ cmenu.current_menu.pop
625
+ @@menus.pop
626
+ cmenu.destroy
627
+ return :UNHANDLED
628
+ end
448
629
  end
449
- return :UNHANDLED
450
630
  else
451
631
  ret = check_mnemonics cmenu, ch
452
632
  return ret
@@ -472,7 +652,7 @@ module RubyCurses
472
652
  def show # menu.show
473
653
  #$log.debug "show (menu) : #{@text} "
474
654
  if @window.nil?
475
- create_window
655
+ create_window #@col+@width
476
656
  end
477
657
  @window.show
478
658
  select_item 0
@@ -487,12 +667,16 @@ module RubyCurses
487
667
  attr_reader :window
488
668
  attr_reader :panel
489
669
  attr_reader :selected
670
+ attr_reader :text # temp 2011-09-24 V1.3.1
490
671
  attr_accessor :visible
491
672
  attr_accessor :active_index
492
673
  attr_accessor :state # normal, selected, highlighted
493
674
  attr_accessor :toggle_key # key used to popup, should be set prior to attaching to form
675
+ attr_accessor :color, :bgcolor # 2011-09-25 V1.3.1
676
+ attr_accessor :_object_created # 2011-10-7 if visible then Form will call this
494
677
  def initialize &block
495
678
  @window = nil
679
+ @text = "menubar"
496
680
  @items = []
497
681
  init_vars
498
682
  @visible = false
@@ -519,6 +703,8 @@ module RubyCurses
519
703
  def menu text, &block
520
704
  #$log.debug "YYYY inside MB: menu text #{text} "
521
705
  m = Menu.new text, &block
706
+ m.color = @color
707
+ m.bgcolor = @bgcolor
522
708
  add m
523
709
  return m
524
710
  end
@@ -549,6 +735,13 @@ module RubyCurses
549
735
  # menu.show
550
736
  # menu.window.wrefresh # XXX we need this
551
737
  end
738
+
739
+ def keep_visible flag=nil
740
+ return @keep_visible unless flag
741
+ @keep_visible = flag
742
+ @visible = flag
743
+ self
744
+ end
552
745
  # menubar LEFT, RIGHT, DOWN
553
746
  def handle_keys
554
747
  @selected = false
@@ -590,6 +783,8 @@ module RubyCurses
590
783
  #$log.debug " mb insdie KEYRIGHT : #{ch}"
591
784
  ret = current_menu.handle_key ch
592
785
  next_menu if ret == :UNHANDLED
786
+ when ?\C-g.getbyte(0) # abort
787
+ throw :menubarclose
593
788
  else
594
789
  #$log.debug " mb insdie ELSE : #{ch}"
595
790
  ret = current_menu.handle_key ch
@@ -608,15 +803,24 @@ module RubyCurses
608
803
  ensure
609
804
  #ensure is required becos one can throw a :close
610
805
  $log.debug " DESTROY IN ENSURE"
611
- current_menu.clear_menus #@@menus = [] # added 2009-01-23 13:21
612
- destroy # Note that we destroy the menu bar upon exit
806
+ current_menu.clear_menus #@@menus = [] # added 2009-01-23 13:21
807
+ destroy # Note that we destroy the menu bar upon exit
613
808
  end
614
809
  end
615
810
  def current_menu
616
811
  @items[@active_index]
617
812
  end
813
+ # called by set_menu_bar in widget.rb (class Form).
618
814
  def toggle
619
- @items.each { |i| $log.debug " ITEM DDD : #{i.text}" }
815
+ # added keeping it visible, 2011-10-7 being tested in dbdemo
816
+ if @keep_visible
817
+ init_vars
818
+ show
819
+ @items[0].highlight
820
+ @window.ungetch(KEY_DOWN)
821
+ return
822
+ end
823
+ #@items.each { |i| $log.debug " ITEM DDD : #{i.text}" }
620
824
  @visible = !@visible
621
825
  if !@visible
622
826
  hide
@@ -627,7 +831,7 @@ module RubyCurses
627
831
  end
628
832
  def hide
629
833
  @visible = false
630
- @window.hide if !@window.nil?
834
+ @window.hide if !@window.nil? # seems to cause auto-firing when we resume toggle 2011-09-26
631
835
  end
632
836
  def show
633
837
  @visible = true
@@ -638,35 +842,49 @@ module RubyCurses
638
842
  end
639
843
  end
640
844
  ## menubar
845
+ # TODO: check for menu to be flush right (only for last one).
641
846
  def repaint
642
847
  return if !@visible
643
- @window ||= create_window
644
- @window.printstring( 0, 0, "%-*s" % [@cols," "], $reversecolor)
848
+ @color_pair = get_color($reversecolor, @color, @bgcolor)
849
+ @window ||= create_window_menubar
850
+ # @window.printstring( 0, 0, "%-*s" % [@cols," "], $reversecolor) # changed 2011 2011-09-24
851
+ @window.printstring( 0, 0, "%-*s" % [@cols," "], @color_pair)
645
852
  c = 1; r = 0;
646
853
  @items.each do |item|
647
- item.row = r; item.col = c; item.parent = self
648
- @window.printstring( r, c, " %s " % item.text, $reversecolor)
854
+ item.row = r; item.col = c; item.coffset = c; item.parent = self
855
+ item.color = @color
856
+ item.bgcolor = @bgcolor
857
+ @window.printstring( r, c, " %s " % item.text, @color_pair)
858
+ # 2011-09-26 V1.3.1 quick dirty highlighting of first menu on menubar
859
+ # on opening since calling highlight was giving bug in parent.width
860
+ #if c == 1
861
+ #att = Ncurses::A_REVERSE
862
+ #@window.mvchgat(y=r, x=c+1, item.text.length+1, att, @color_pair, nil)
863
+ #end
649
864
  c += (item.text.length + 2)
650
865
  end
866
+ #@items[0].on_enter # 2011-09-25 V1.3.1 caused issues when toggling, first item fired on DOWN
867
+ @items[0].highlight unless @keep_visible # 2011-09-26 V1.3.1 fixed to take both cases into account
651
868
  @window.wrefresh
652
869
  end
653
- def create_window
870
+ def create_window_menubar
654
871
  @layout = { :height => 1, :width => 0, :top => 0, :left => 0 }
655
872
  @win = VER::Window.new(@layout)
656
873
  @window = @win
657
- @win.bkgd(Ncurses.COLOR_PAIR(5));
874
+ @win.bkgd(Ncurses.COLOR_PAIR(5)); # <---- FIXME
658
875
  @panel = @win.panel
659
876
  return @window
660
877
  end
661
878
  def destroy
662
879
  $log.debug "DESTRY menubar "
880
+ @items.each do |item|
881
+ item.destroy
882
+ end
883
+ return if @keep_visible
663
884
  @visible = false
664
885
  panel = @window.panel
665
886
  Ncurses::Panel.del_panel(panel.pointer) if !panel.nil?
666
887
  @window.delwin if !@window.nil?
667
- @items.each do |item|
668
- item.destroy
669
- end
670
888
  @window = nil
671
889
  end
672
890
  end # menubar
@@ -702,8 +920,10 @@ module RubyCurses
702
920
  repaint
703
921
  highlight true
704
922
  end
705
- def repaint
706
- @parent.window.printstring( row, 0, getvalue_for_paint, $reversecolor)
923
+ def repaint # checkbox
924
+ # FIXME need @color_pair here
925
+ @color_pair ||= get_color($reversecolor, @color, @bgcolor)
926
+ @parent.window.printstring( row, 0, getvalue_for_paint, @color_pair)
707
927
  parent.window.wrefresh
708
928
  end
709
929
  def method_missing(sym, *args)
@@ -714,6 +934,6 @@ module RubyCurses
714
934
  $log.error("ERROR CHECKBOXMENU #{sym} called")
715
935
  end
716
936
  end
937
+ end # class
717
938
 
718
- end
719
939
  end # modul