rbcurse 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -64,6 +64,10 @@ module RubyCurses
64
64
  @suppress_borders = false
65
65
  @_use_preferred_sizes = true
66
66
  @row_offset = @col_offset = 1
67
+ # type can be :INCREASE, :DECREASE, :EXPAND, :UNEXPAND :EQUAL
68
+ @_events ||= []
69
+ @_events.push :COMPONENT_RESIZE_EVENT
70
+ @_events.push :DRAG_EVENT
67
71
  super
68
72
  @focusable = true
69
73
  @editable = false
@@ -77,9 +81,6 @@ module RubyCurses
77
81
  # hash, keyed on component, contains Split (which side, flow or stack, weight)
78
82
  @ch = {}
79
83
  @weight ||= 0.50
80
- # type can be :INCREASE, :DECREASE, :EXPAND, :UNEXPAND :EQUAL
81
- @_events.push :COMPONENT_RESIZE_EVENT
82
- @_events.push :DRAG_EVENT
83
84
 
84
85
  init_vars
85
86
  bind_key([?\C-w,?o], :expand)
@@ -100,9 +101,6 @@ module RubyCurses
100
101
  def init_vars
101
102
  @repaint_required = true
102
103
  @recalculate_splits = true # convert weight to size
103
- # seems it works with false also, so do we really need it to be true ?
104
- # whe true was giving a seg fault on increasing child window by 0.05
105
- @_child_buffering = false # private, internal. not to be changed by callers.
106
104
  @row_offset = @col_offset = 0 if @suppress_borders # FIXME supposed to use this !!
107
105
 
108
106
  @internal_width = 2
@@ -212,25 +210,25 @@ module RubyCurses
212
210
  when KEY_UP
213
211
  # CHECK BOUNDS TODO
214
212
  # TODO what about KEY_LEFT and RIGHT ?
215
- if source.next && source.next.row > 1 && source.parent.height > 1
213
+ if source.next_component && source.next_component.row > 1 && source.parent.height > 1
216
214
  source.parent.height -= 1
217
- source.next.height +=1
218
- source.next.row -= 1
215
+ source.next_component.height +=1
216
+ source.next_component.row -= 1
219
217
  source.parent.repaint_required
220
- source.next.repaint_required
218
+ source.next_component.repaint_required
221
219
  source.parent.repaint
222
- source.next.repaint
220
+ source.next_component.repaint
223
221
  end
224
222
  when KEY_DOWN
225
223
  # CHECK BOUNDS TODO check with appemail.rb
226
- if source.next && source.next.height > 1
224
+ if source.next_component && source.next_component.height > 1
227
225
  source.parent.height += 1
228
- source.next.height -=1
229
- source.next.row += 1
226
+ source.next_component.height -=1
227
+ source.next_component.row += 1
230
228
  source.parent.repaint_required
231
- source.next.repaint_required
229
+ source.next_component.repaint_required
232
230
  source.parent.repaint
233
- source.next.repaint
231
+ source.next_component.repaint
234
232
  end
235
233
  end
236
234
  end
@@ -238,9 +236,6 @@ module RubyCurses
238
236
  end
239
237
  end
240
238
  c.parent_component = self
241
- c.should_create_buffer = @_child_buffering
242
- c.ext_row_offset += @ext_row_offset + @row #- @subform1.window.top #0# screen_row
243
- c.ext_col_offset += @ext_col_offset + @col #-@subform1.window.left # 0# screen_col
244
239
 
245
240
  @components << c
246
241
  if which == :FIRST
@@ -276,7 +271,6 @@ module RubyCurses
276
271
  # repaint object
277
272
  # called by Form, and sometimes parent component (if not form).
278
273
  def repaint
279
- safe_create_buffer # 2010-01-04 12:36 BUFFERED moved here 2010-01-05 18:07
280
274
  my_win = @form ? @form.window : @target_window
281
275
  @graphic = my_win unless @graphic
282
276
  raise " #{@name} neither form, nor target window given TV paint " unless my_win
@@ -368,8 +362,6 @@ module RubyCurses
368
362
  # NOTE: at present one cannot change from flow to stack inside a pane
369
363
 
370
364
  @repaint_required = false
371
- @buffer_modified = true # required by form to call buffer_to_screen BUFFERED
372
- buffer_to_window #
373
365
  end
374
366
  def v?
375
367
  @orientation == :VERTICAL_SPLIT
@@ -451,8 +443,7 @@ module RubyCurses
451
443
  rca.col += e.width
452
444
  totalwd += wt if wt
453
445
  end
454
- e.set_buffering(:target_window => @target_window || @form.window, :bottom => e.height-1, :right => e.width-1, :form => @form )
455
- e.set_buffering(:screen_top => e.row, :screen_left => e.col)
446
+ e.set_buffering(:target_window => @target_window || @form.window, :bottom => e.height-1, :right => e.width-1, :form => @form ) # removed on 2011-09-29
456
447
  $log.debug " XXXXX VIMS R #{e.row} C #{e.col} H #{e.height} W #{e.width} "
457
448
  e.repaint
458
449
  e._object_created = true # added 2010-09-16 13:02 now prop handlers can be fired
@@ -726,7 +717,7 @@ module RubyCurses
726
717
  RubyCurses::FocusManager.add @vb
727
718
  @vb.parent_component = self
728
719
  @components << @vb
729
- @vb.set_buffering(:target_window => @target_window || @form.window, :form => @form )
720
+ @vb.set_buffering(:target_window => @target_window || @form.window, :form => @form ) # removed on 2011-09-29
730
721
  @vb.bind :DRAG_EVENT do |ev|
731
722
  if v?
732
723
  case ev.type
@@ -10,9 +10,12 @@
10
10
  * Author: rkumar (arunachalesha)
11
11
  * Date: 2008-11-19 12:49
12
12
  * License: Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
13
- TODO
14
- - repaint only what is modified
15
- - save data in a hash when called for.
13
+
14
+ == CHANGES
15
+ * 2011-10-2 Added PropertyVetoException to rollback changes to property
16
+ * 2011-10-2 Returning self from dsl_accessor and dsl_property for chaining
17
+ * 2011-10-2 removing clutter of buffering, a lot of junk code removed too.
18
+ == TODO
16
19
  - make some methods private/protected
17
20
  - Add bottom bar also, perhaps allow it to be displayed on a key so it does not take
18
21
  - Can key bindings be abstracted so they can be inherited /reused.
@@ -20,8 +23,6 @@ TODO
20
23
 
21
24
 
22
25
  =end
23
- require 'rubygems'
24
- ##require 'ncurses'
25
26
  require 'logger'
26
27
  #require 'rbcurse/mapper'
27
28
  require 'rbcurse/colormap'
@@ -60,24 +61,39 @@ end
60
61
  class Module
61
62
  ## others may not want this, sets config, so there's a duplicate hash
62
63
  # also creates a attr_writer so you can use =.
64
+ # 2011-10-2 V1.3.1 Now returning self, so i can chain calls
63
65
  def dsl_accessor(*symbols)
64
66
  symbols.each { |sym|
67
+ #open('myfile.out', 'a') { |f|
68
+ #f.puts "dsl_access #{sym} "
69
+ #}
65
70
  class_eval %{
66
71
  def #{sym}(*val)
67
72
  if val.empty?
68
73
  @#{sym}
69
74
  else
75
+ #if @frozen # 2011-10-1 prevent object from being changed # changed 2011 dts
76
+ #return if @frozen && (@frozen_list.nil? || @frozen_list.include?(:#{sym}) )
77
+ #end
70
78
  @#{sym} = val.size == 1 ? val[0] : val
71
79
  # i am itching to deprecate next line XXX
72
80
  @config["#{sym}"]=@#{sym}
81
+ self # 2011-10-2
73
82
  end
74
83
  end
75
- attr_writer sym
84
+ # can the next bypass validations
85
+ # I don't think anyone will expect self to be returned if using = to assign
86
+ attr_writer sym #2011-10-2
87
+ #def #{sym}=(val)
88
+ ##{sym}(val)
89
+ # self
90
+ #end
76
91
  }
77
92
  }
78
93
  end
79
94
  # Besides creating getters and setters, this also fires property change handler
80
95
  # if the value changes, and after the object has been painted once.
96
+ # 2011-10-2 V1.3.1 Now returning self, so i can chain calls
81
97
  def dsl_property(*symbols)
82
98
  symbols.each { |sym|
83
99
  class_eval %{
@@ -85,21 +101,34 @@ class Module
85
101
  if val.empty?
86
102
  @#{sym}
87
103
  else
104
+ #return(self) if @frozen && (@frozen_list.nil? || @frozen_list.include?(:#{sym}) )
88
105
  oldvalue = @#{sym}
89
- @#{sym} = val.size == 1 ? val[0] : val
90
- newvalue = @#{sym}
91
- # i am itching to deprecate next line XXX
92
- @config["#{sym}"]=@#{sym}
93
- return if oldvalue.nil? || @_object_created.nil?
106
+ # @#{sym} = val.size == 1 ? val[0] : val
107
+ tmp = val.size == 1 ? val[0] : val
108
+ newvalue = tmp
109
+ # i am itching to deprecate config setting
110
+ if oldvalue.nil? || @_object_created.nil?
111
+ @#{sym} = tmp
112
+ @config["#{sym}"]=@#{sym}
113
+ end
114
+ return(self) if oldvalue.nil? || @_object_created.nil?
115
+
94
116
  if oldvalue != newvalue
95
117
  # trying to reduce calls to fire, when object is being created
96
- fire_property_change("#{sym}", oldvalue, newvalue) if !oldvalue.nil?
97
- end
98
- end
99
- end
118
+ begin
119
+ fire_property_change("#{sym}", oldvalue, newvalue) if !oldvalue.nil?
120
+ @#{sym} = tmp
121
+ @config["#{sym}"]=@#{sym}
122
+ rescue PropertyVetoException
123
+ $log.warn "PropertyVetoException for #{sym}:" + oldvalue + "-> "+newvalue
124
+ end
125
+ end # if old
126
+ self
127
+ end # if val
128
+ end # def
100
129
  #attr_writer sym
101
130
  def #{sym}=val
102
- # TODO if Variable, take .value NEXT VERSION
131
+ # TODO if Variable, take .value NEXT VERSION
103
132
  #{sym}(val)
104
133
  end
105
134
  }
@@ -120,12 +149,25 @@ class Fixnum
120
149
  end
121
150
  end unless "a"[0] == "a"
122
151
 
123
- #include Ncurses XXX 2011-09-8 testing FFI
124
152
  module RubyCurses
125
153
  extend self
126
154
  include ColorMap
127
155
  class FieldValidationException < RuntimeError
128
156
  end
157
+
158
+ # The property change is not acceptable, undo it. e.g. test2.rb
159
+ # @param [String] text message
160
+ # @param [Event] PropertyChangeEvent object
161
+ # @since 1.4.0
162
+ class PropertyVetoException < RuntimeError
163
+ def initialize(string, event)
164
+ @string = string
165
+ @event = event
166
+ super(string)
167
+ end
168
+ attr_reader :string, :event
169
+ end
170
+
129
171
  module Utils
130
172
  ## this is the numeric argument used to repeat and action by repeatm()
131
173
  $multiplier = 0
@@ -247,7 +289,7 @@ module RubyCurses
247
289
  # 2010-02-24 12:43 trying to take in multiple key bindings, TODO unbind
248
290
  # TODO add symbol so easy to map from config file or mapping file
249
291
  def bind_key keycode, *args, &blk
250
- $log.debug " #{@name} bind_key received #{keycode} "
292
+ $log.debug " #{@name} bind_key received #{keycode} "
251
293
  @key_handler ||= {}
252
294
  if !block_given?
253
295
  blk = args.pop
@@ -258,7 +300,7 @@ module RubyCurses
258
300
  when String
259
301
  keycode = keycode.getbyte(0) #if keycode.class==String ## 1.9 2009-10-05 19:40
260
302
  #$log.debug " #{name} Widg String called bind_key BIND #{keycode}, #{keycode_tos(keycode)} "
261
- $log.debug "XXX XX assigning #{keycode} " if $log.debug?
303
+ $log.debug " assigning #{keycode} " if $log.debug?
262
304
  @key_handler[keycode] = blk
263
305
  when Array
264
306
  # for starters lets try with 2 keys only
@@ -268,11 +310,11 @@ module RubyCurses
268
310
  a1 = keycode[1]
269
311
  a1 = keycode[1].getbyte(0) if keycode[1].class == String
270
312
  @key_handler[a0] ||= OrderedHash.new
271
- $log.debug "XXX XX assigning #{keycode} , A0 #{a0} , A1 #{a1} " if $log.debug?
313
+ $log.debug " assigning #{keycode} , A0 #{a0} , A1 #{a1} " if $log.debug?
272
314
  @key_handler[a0][a1] = blk
273
- #$log.debug "XXX XX assigning #{keycode} to key_handler " if $log.debug?
315
+ #$log.debug " XX assigning #{keycode} to key_handler " if $log.debug?
274
316
  else
275
- #$log.debug "XXX assigning #{keycode} to key_handler " if $log.debug?
317
+ #$log.debug " assigning #{keycode} to key_handler " if $log.debug?
276
318
  @key_handler[keycode] = blk
277
319
  end
278
320
  @key_args ||= {}
@@ -312,7 +354,7 @@ module RubyCurses
312
354
  if respond_to? blk
313
355
  return send(blk, *@key_args[keycode])
314
356
  else
315
- alert "This does not respond to #{blk.to_s} "
357
+ alert "This ( #{self.class} ) does not respond to #{blk.to_s} "
316
358
  end
317
359
  else
318
360
  $log.debug "rwidget BLOCK called _process_key " if $log.debug?
@@ -325,7 +367,7 @@ module RubyCurses
325
367
  require 'rbcurse/extras/viewer'
326
368
  RubyCurses::Viewer.view what, config
327
369
  end
328
- end
370
+ end # module
329
371
 
330
372
  module EventHandler
331
373
  ##
@@ -333,9 +375,12 @@ module RubyCurses
333
375
  def bind event, *xargs, &blk
334
376
  #$log.debug "#{self} called EventHandler BIND #{event}, args:#{xargs} "
335
377
  if @_events
336
- raise ArgumentError, "#{self.class} does not support this event: #{event}. #{@_events} " if !@_events.include? event
378
+ $log.warn "#{self.class} does not support this event: #{event}. #{@_events} " if !@_events.include? event
379
+ #raise ArgumentError, "#{self.class} does not support this event: #{event}. #{@_events} " if !@_events.include? event
337
380
  else
338
- $log.debug "BIND #{self.class} XXXXX no events defined in @_events. Please do so to avoid bugs and debugging. This will become a fatal error soon."
381
+ # it can come here if bind in initial block, since widgets add to @_event after calling super
382
+ # maybe we can change that.
383
+ $log.warn "BIND #{self.class} (#{event}) XXXXX no events defined in @_events. Please do so to avoid bugs and debugging. This will become a fatal error soon."
339
384
  end
340
385
  @handler ||= {}
341
386
  @event_args ||= {}
@@ -378,6 +423,10 @@ module RubyCurses
378
423
  # added 2011-09-26 1.3.0 so a user raised exception on LEAVE
379
424
  # keeps cursor in same field.
380
425
  raise fve
426
+ rescue PropertyVetoException => pve
427
+ # added 2011-09-26 1.3.0 so a user raised exception on LEAVE
428
+ # keeps cursor in same field.
429
+ raise pve
381
430
  rescue => ex
382
431
  ## some don't have name
383
432
  #$log.error "======= Error ERROR in block event #{self}: #{name}, #{event}"
@@ -395,8 +444,8 @@ module RubyCurses
395
444
  ## added on 2009-01-08 00:33
396
445
  # goes with dsl_property
397
446
  # Need to inform listeners - done 2010-02-25 23:09
447
+ # Can throw a FieldValidationException or PropertyVetoException
398
448
  def fire_property_change text, oldvalue, newvalue
399
- # should i return if oldvalue is nil ??? TODO XXX
400
449
  #$log.debug " FPC #{self}: #{text} #{oldvalue}, #{newvalue}"
401
450
  return if oldvalue.nil? || @_object_created.nil? # added 2010-09-16 so if called by methods it is still effective
402
451
  if @pce.nil?
@@ -406,6 +455,7 @@ module RubyCurses
406
455
  end
407
456
  fire_handler :PROPERTY_CHANGE, @pce
408
457
  @repaint_required = true # this was a hack and shoudl go, someone wanted to set this so it would repaint (viewport line 99 fire_prop
458
+ repaint_all(true) # for repainting borders, headers etc 2011-09-28 V1.3.1
409
459
  end
410
460
 
411
461
  end # module eventh
@@ -443,6 +493,14 @@ module RubyCurses
443
493
  end
444
494
  end
445
495
  end # module config
496
+
497
+ #
498
+ # prints a status line at bottom where mode's statuses et can be reflected
499
+ def status_line config={}, &block
500
+ require 'rbcurse/extras/statusline'
501
+ sl = RubyCurses::StatusLine.new @form, config, &block
502
+ end
503
+
446
504
  ##
447
505
  # Basic widget class.
448
506
  # NOTE: I may soon remove the config hash. I don't use it and its just making things heavy.
@@ -481,34 +539,40 @@ module RubyCurses
481
539
  dsl_property :min_width # added 2009-10-28 13:40 for splitpanes and better resizing
482
540
  dsl_property :min_height # added 2009-10-28 13:40 for splitpanes and better resizing
483
541
 
484
- ## 2010-01-05 13:27 create buffer conditionally, if enclosing component asks. Needs to be passed down
485
- ##+ to further children or editor components. Default false.
486
- attr_accessor :should_create_buffer # added 2010-01-05 13:16 BUFFERED, trying to create buffersonly where required.
487
542
  attr_accessor :_object_created # 2010-09-16 12:12 to prevent needless property change firing when object being set
488
543
 
544
+ #attr_accessor :frozen # true false
545
+ #attr_accessor :frozen_list # list of attribs that cannot be changed
489
546
  ## I think parent_form was not a good idea since i can't add parent widget offsets
490
547
  ##+ thus we should use parent_comp and push up.
491
548
  attr_accessor :parent_component # added 2010-01-12 23:28 BUFFERED - to bubble up
492
549
  # tired of getting the cursor wrong and guessing, i am now going to try to get absolute
493
550
  # coordinates - 2010-02-07 20:17 this should be updated by parent.
494
- attr_accessor :ext_col_offset, :ext_row_offset # 2010-02-07 20:16 to get abs position for cursor
551
+ #attr_accessor :ext_col_offset, :ext_row_offset # 2010-02-07 20:16 to get abs position for cursor rem 2011-09-29
495
552
  attr_accessor :rows_panned # moved from form, how many rows scrolled.panned 2010-02-11 15:26
496
553
  attr_accessor :cols_panned # moved from form, how many cols scrolled.panned 2010-02-11 15:26
497
554
 
498
555
  # sometimes inside a container there's no way of knowing if an individual comp is in focus
499
556
  # other than the explicitly set it and inquire . 2010-09-02 14:47 @since 1.1.5
557
+ # NOTE state takes care of this and is set by form
500
558
  attr_accessor :focussed # is this widget in focus, so they may paint differently
501
559
 
502
560
  def initialize form, aconfig={}, &block
503
561
  @form = form
504
562
  @row_offset ||= 0
505
563
  @col_offset ||= 0
506
- @ext_row_offset = @ext_col_offset = 0 # 2010-02-07 20:18
564
+ #@ext_row_offset = @ext_col_offset = 0 # 2010-02-07 20:18 # removed on 2011-09-29
507
565
  @state = :NORMAL
508
566
  @attr = nil
509
567
 
510
568
  @handler = nil # we can avoid firing if nil
511
569
  @event_args = {}
570
+ # These are standard events for most widgets which will be fired by
571
+ # Form. In the case of CHANGED, form fires if it's editable property is set, so
572
+ # it does not apply to all widgets.
573
+ @_events ||= []
574
+ @_events.push( *[:ENTER, :LEAVE, :CHANGED, :PROPERTY_CHANGE])
575
+
512
576
  config_setup aconfig # @config.each_pair { |k,v| variable_set(k,v) }
513
577
  #instance_eval &block if block_given?
514
578
  if block_given?
@@ -522,10 +586,6 @@ module RubyCurses
522
586
  # own default
523
587
  @bgcolor ||= "black" # 0
524
588
  @color ||= "white" # $datacolor
525
- # These are standard events for most widgets which will be fired by
526
- # Form. In the case of CHANGED, form fires if it's editable property is set, so
527
- # it does not apply to all widgets.
528
- @_events = [:ENTER, :LEAVE, :CHANGED, :PROPERTY_CHANGE]
529
589
  # @id = form.add_widget(self) if !form.nil? and form.respond_to? :add_widget
530
590
  set_form(form) unless form.nil?
531
591
  end
@@ -533,7 +593,7 @@ module RubyCurses
533
593
  # just in case anyone does a super. Not putting anything here
534
594
  # since i don't want anyone accidentally overriding
535
595
  @buffer_modified = false
536
- #@manages_cursor = false # form should manage it, I will pass row and col to it. XXX ?
596
+ #@manages_cursor = false # form should manage it, I will pass row and col to it.
537
597
  end
538
598
 
539
599
  # modified
@@ -594,22 +654,17 @@ module RubyCurses
594
654
  end
595
655
  ##
596
656
  # default repaint method. Called by form for all widgets.
597
- # XXX widget does not have display_length.
657
+ # widget does not have display_length.
598
658
  def repaint
599
659
  r,c = rowcol
600
660
  $log.debug("widget repaint : r:#{r} c:#{c} col:#{@color}" )
601
661
  value = getvalue_for_paint
602
662
  len = @display_length || value.length
603
663
  acolor = @color_pair || get_color($datacolor, @color, @bgcolor)
604
- #if @bgcolor.is_a? String and @color.is_a? String
605
- #acolor = ColorMap.get_color(@color, @bgcolor)
606
- #else
607
- #acolor = $datacolor
608
- #end
609
664
  @graphic.printstring r, c, "%-*s" % [len, value], acolor, @attr
610
665
  # next line should be in same color but only have @att so we can change att is nec
611
666
  #@form.window.mvchgat(y=r, x=c, max=len, Ncurses::A_NORMAL, @bgcolor, nil)
612
- @buffer_modified = true # required for form to call buffer_to_screen
667
+ #@buffer_modified = true # required for form to call buffer_to_screen CLEANUP
613
668
  end
614
669
 
615
670
  def destroy
@@ -661,9 +716,11 @@ module RubyCurses
661
716
  end
662
717
  # puts cursor on correct row.
663
718
  def set_form_row
664
- raise "empty todo widget"
665
719
  # @form.row = @row + 1 + @winrow
666
- @form.row = @row + 1
720
+ #@form.row = @row + 1
721
+ r, c = rowcol
722
+ $log.warn " empty set_form_row in widget #{self} r = #{r} , c = #{c} "
723
+ setrowcol row, nil
667
724
  end
668
725
  # set cursor on correct column, widget
669
726
  # Ideally, this should be overriden, as it is not likely to be correct.
@@ -671,7 +728,7 @@ module RubyCurses
671
728
  @curpos = col1 || 0 # 2010-01-14 21:02
672
729
  #@form.col = @col + @col_offset + @curpos
673
730
  c = @col + @col_offset + @curpos
674
- $log.debug " #{@name} widget WARNING super set_form_col #{c}, #{@form} "
731
+ $log.warn " #{@name} empty set_form_col #{c}, #{@form} "
675
732
  setrowcol nil, c
676
733
  end
677
734
  def hide
@@ -690,7 +747,7 @@ module RubyCurses
690
747
  end
691
748
  ##
692
749
  # moves focus to this field
693
- # XXX we must look into running on_leave of previous field
750
+ # we must look into running on_leave of previous field
694
751
  def focus
695
752
  return if !@focusable
696
753
  if @form.validate_field != -1
@@ -698,39 +755,6 @@ module RubyCurses
698
755
  end
699
756
  end
700
757
  ##
701
- # bind an action to a key, required if you create a button which has a hotkey
702
- # or a field to be focussed on a key, or any other user defined action based on key
703
- # e.g. bind_key ?\C-x, object, block
704
- # added 2009-01-06 19:13 since widgets need to handle keys properly
705
- # 2010-02-24 12:43 trying to take in multiple key bindings, TODO unbind
706
- # TODO add symbol so easy to map from config file or mapping file
707
- def OLDbind_key keycode, *args, &blk
708
- @key_handler ||= {}
709
- if !block_given?
710
- blk = args.pop
711
- raise "If block not passed, last arg should be a method symbol" if !blk.is_a? Symbol
712
- $log.debug " #{@name} bind_key received a symbol #{blk} "
713
- end
714
- case keycode
715
- when String
716
- $log.debug "Widg String called bind_key BIND #{keycode} #{keycode_tos(keycode)} "
717
- keycode = keycode.getbyte(0) #if keycode.class==String ## 1.9 2009-10-05 19:40
718
- @key_handler[keycode] = blk
719
- when Array
720
- # for starters lets try with 2 keys only
721
- a0 = keycode[0]
722
- a0 = keycode[0].getbyte(0) if keycode[0].class == String
723
- a1 = keycode[1]
724
- a1 = keycode[1].getbyte(0) if keycode[1].class == String
725
- @key_handler[a0] ||= OrderedHash.new
726
- @key_handler[a0][a1] = blk
727
- else
728
- @key_handler[keycode] = blk
729
- end
730
- @key_args ||= {}
731
- @key_args[keycode] = args
732
- end
733
- ##
734
758
  # remove a binding that you don't want
735
759
  def unbind_key keycode
736
760
  @key_args.delete keycode unless @key_args.nil?
@@ -741,12 +765,6 @@ module RubyCurses
741
765
  # returns UNHANDLED if no block for it
742
766
  # after form handles basic keys, it gives unhandled key to current field, if current field returns
743
767
  # unhandled, then it checks this map.
744
- # added 2009-01-06 19:13 since widgets need to handle keys properly
745
- # added 2009-01-18 12:58 returns ret val of blk.call
746
- # so that if block does not handle, the key can still be handled
747
- # e.g. table last row, last col does not handle, so it will auto go to next field
748
- # 2010-02-24 13:45 handles 2 key combinations, copied from Form, must be identical in logic
749
- # except maybe for window pointer. TODO not tested
750
768
  def process_key keycode, object
751
769
  return _process_key keycode, object, @graphic
752
770
  end
@@ -761,62 +779,8 @@ module RubyCurses
761
779
  def get_preferred_size
762
780
  return @preferred_height, @preferred_width
763
781
  end
764
- ##
765
- # creates a buffer for the widget to write to.
766
- # This is typically called in the constructor. Sometimes, the constructor
767
- # does not have a height or width, since the object will be resized based on parents
768
- # size, as in splitpane
769
- # Please use this only if embedding this object in another object/s that would wish
770
- # to crop this. Otherwise, you could have many pads in your app.
771
- # Sets @graphic which can be used in place of @form.window
772
- #
773
- # @return [buffer] returns pad created
774
- # @since 0.1.3
775
- # NOTE: 2010-01-12 11:14 there are some parent widgets that may want this w to have a larger top and left.
776
- # Setting it later, means that the first repaint can be off.
777
-
778
- def create_buffer()
779
- $log.debug " #{self.class} CB called with #{@should_create_buffer} H: #{@height} W #{@width} "
780
- if @should_create_buffer
781
- @height or $log.warn " CB height is nil, setting to 1. This may not be what you want"
782
- mheight = @height || 1 # some widgets don't have height XXX
783
- mwidth = @width || 30 # some widgets don't have width as yet
784
- mrow = @row || 0
785
- mcol = @col || 0
786
- layout = { :height => mheight, :width => mwidth, :top => mrow, :left => mcol }
787
- $log.debug " cb .. #{@name} create_buffer #{mrow} #{mcol} #{mheight} #{mwidth}"
788
- @screen_buffer = VER::Pad.create_with_layout(layout)
789
- @is_double_buffered = true # will be checked prior to blitting
790
- @buffer_modified = true # set this in repaint
791
- @repaint_all = true # added 2010-01-08 19:02
792
- else
793
- ## NOTE: if form has not been set, you could run into problems
794
- ## Typically a form MUST be set by now, unless you are buffering, in which
795
- ##+ case it should go in above block.
796
- @screen_buffer = @form.window if @form
797
- end
798
782
 
799
- @graphic = @screen_buffer # use buffer for writing, not screen window
800
- return @screen_buffer
801
- end # create_buffer
802
783
 
803
- ##
804
- # checks if buffer not created already, and figures
805
- # out dimensions.
806
- # Preferable to use this instead of directly using create_buffer.
807
- #
808
- def safe_create_buffer
809
- if @screen_buffer == nil
810
- if @height == nil
811
- @height = @preferred_height || @min_height
812
- end
813
- if @width == nil
814
- @width = @preferred_width || @min_width
815
- end
816
- create_buffer
817
- end
818
- return @screen_buffer
819
- end
820
784
  ##
821
785
  # Inform the system that the buffer has been modified
822
786
  # and should be blitted over the screen or copied to parent.
@@ -825,72 +789,6 @@ module RubyCurses
825
789
  end
826
790
 
827
791
 
828
- ##
829
- # copy the buffer to the screen, or given window/pad.
830
- # Relevant only in double_buffered case since pad has to be written
831
- # to screen. Should be called only by outer form, not by widgets as a widget
832
- # could be inside another widget.
833
- # Somewhere we need to clear screen if scrolling.???
834
- # aka b2s
835
- # @param [Window, #get_window, nil] screen to write to, if nil then write to phys screen
836
- # @return 0 - copy success, -1 copy failure, 1 - did nothing, usually since buffer_modified false
837
-
838
- def buffer_to_screen(screen=nil, pminrow=0, pmincol=0)
839
- raise "deprecated b2s "
840
- return 1 unless @is_double_buffered and @buffer_modified
841
- # screen is nil when form calls this to write to physical screen
842
- $log.debug " screen inside buffer_to_screen b2s :#{screen} "
843
- $log.error "ERROR !I have moved away fomr this method. Your program is broken and will not be working"
844
- ## 2010-01-03 19:38 i think its wrong to put the pad onto the screen
845
- ##+ since wrefreshing the window will cause this to be overwriting
846
- ##+ so i put current window here.
847
- if screen == nil
848
- #$log.debug " XXX calling graphic.wrefresh 2010-01-03 12:27 (parent_buffer was nil) "
849
- #$log.debug " XXX 2010-01-03 20:47 now copying pad #{@graphic} onto form.window"
850
- ret = @graphic.wrefresh
851
- ## 2010-01-03 20:45 rather than writing to phys screen, i write to forms window
852
- ##+ so later updates to that window do not overwrite this widget.
853
- ## We need to check this out with scrollpane and splitpane.
854
- #ret = @graphic.copywin(@form.window.get_window, 0, 0, @row, @col, @row+@height-1, @col+@width-1,0)
855
- else
856
- # screen is passed when a parent object calls this to copy child buffer to itself
857
- @graphic.set_backing_window(screen)
858
- $log.debug " #{@name} #{@graphic} calling copy pad to win COPY"
859
- ret = @graphic.copy_pad_to_win
860
- end
861
- @buffer_modified = false
862
- return ret
863
- end # buffer_to_screen
864
- ##
865
- # returns screen_buffer or nil
866
- #
867
- # @return [screen_buffer, nil] screen_buffer earlier created
868
- # @since 0.1.3
869
-
870
- def get_buffer()
871
- @screen_buffer
872
- end # get_buffer
873
-
874
- ##
875
- # destroys screen_buffer if present
876
- #
877
- # @return
878
- # @since 0.1.3
879
-
880
- def destroy_buffer()
881
- if @screen_buffer != nil
882
- @screen_buffer.destroy # ???
883
- end
884
- end # destroy_buffer
885
-
886
- ##
887
- # Does the widget buffer its output in a pad
888
- #
889
- # @return [true, false] comment
890
-
891
- def is_double_buffered?()
892
- @is_double_buffered
893
- end # is_double_buffered
894
792
 
895
793
  ##
896
794
  # getter and setter for width - 2009-10-29 22:45
@@ -901,11 +799,11 @@ module RubyCurses
901
799
  # @since 0.1.3
902
800
  #
903
801
  def width(*val)
904
- #$log.debug " inside XXX width() #{val}"
802
+ #$log.debug " inside width() #{val}"
905
803
  if val.empty?
906
804
  return @width
907
805
  else
908
- #$log.debug " inside XXX width()"
806
+ #$log.debug " inside width()"
909
807
  oldvalue = @width || 0 # is this default okay, else later nil cries
910
808
  #@width = val.size == 1 ? val[0] : val
911
809
  @width = val[0]
@@ -915,10 +813,10 @@ module RubyCurses
915
813
  fire_property_change(:width, oldvalue, newvalue)
916
814
  repaint_all(true) # added 2010-01-08 18:51 so widgets can redraw everything.
917
815
  end
918
- if is_double_buffered? and newvalue != oldvalue
919
- $log.debug " #{@name} w calling resize of screen buffer with #{newvalue}. WARNING: does not change buffering_params"
920
- @screen_buffer.resize(0, newvalue)
921
- end
816
+ #if is_double_buffered? and newvalue != oldvalue # removed on 2011-09-29
817
+ #$log.debug " #{@name} w calling resize of screen buffer with #{newvalue}. WARNING: does not change buffering_params"
818
+ #@screen_buffer.resize(0, newvalue)
819
+ #end
922
820
  end
923
821
  end
924
822
  def width=val
@@ -933,7 +831,7 @@ module RubyCurses
933
831
  # @since 0.1.3
934
832
  #
935
833
  def height(*val)
936
- #$log.debug " inside XXX height() #{val[0]}"
834
+ #$log.debug " inside height() #{val[0]}"
937
835
  if val.empty?
938
836
  return @height
939
837
  else
@@ -947,12 +845,6 @@ module RubyCurses
947
845
  $log.debug " widget #{@name} setting repaint_all to true"
948
846
  @repaint_all=true
949
847
  end
950
- # XXX this troubles me a lot. gets fired more than we would like
951
- # XXX When both h and w change then happens 2 times.
952
- if is_double_buffered? and newvalue != oldvalue
953
- $log.debug " #{@name} h calling resize of screen buffer with #{newvalue}"
954
- @screen_buffer.resize(newvalue, 0)
955
- end
956
848
  end
957
849
  end
958
850
  def height=val
@@ -1018,85 +910,21 @@ module RubyCurses
1018
910
  #setformrowcol r,c
1019
911
  end
1020
912
 
913
+ # I was removing this altogether but vimsplit needs this, or masterdetail gives form and window
914
+ # to vimsplit. So i 've removed everything but the form and window setting. 2011-09-29 SETBUFF
1021
915
  # move from TextView
1022
916
  # parameters relating to buffering - new 2010-02-12 12:09 RFED16
1023
917
  # I am merging so i can call multiple times
1024
918
  # WARNING NOTE : this does not set Pad's top and left since Pad may not be created yet, or at all
1025
919
  def set_buffering params
1026
- @buffer_params ||= {}
1027
- #@should_create_buffer = params[:should_create_buffer] || true
920
+
1028
921
  @target_window ||= params[:target_window]
1029
- # trying out, 2010-02-12 19:40 sometimes no form even with parent.
1030
922
  @form = params[:form] unless @form
1031
- ## XXX trying this out.
1032
- # what if container does not ask child to buffer, as in splitpane
1033
- # then graphic could be nil
1034
- if @graphic.nil? # and should_create_buffer not set or false XXX
923
+ if @graphic.nil?
1035
924
  @graphic = @target_window
1036
925
  end
1037
- $log.debug " set_buffering #{@name} got target window #{@target_window}, #{@graphic} - THIS DOES NOT UPDATE PAD ... sr:#{params[:screen_top]} sc:#{params[:screen_left]} top:#{params[:top]} left:#{params[:left]} bot:#{params[:bottom]} rt:#{params[:right]} "
1038
- # @top = params[:top]
1039
- # @left = params[:left]
1040
- # @bottom = params[:bottom]
1041
- # @right = params[:right]
1042
- # offsets ?
1043
- # warning, this does not touch @top and left of Pad, often pad will bot yet be created
1044
- @buffer_params.merge!(params)
1045
- if !@screen_buffer.nil?
1046
- # update Pad since some folks take from there such as print_border
1047
- @screen_buffer.top = params[:screen_top] if !params[:screen_top].nil?
1048
- @screen_buffer.left = params[:screen_left] if !params[:screen_left].nil?
1049
- end
1050
926
  end
1051
927
 
1052
- # copy buffer onto window
1053
- # RFED16 added 2010-02-12 14:42 0 simpler buffer management
1054
- def buffer_to_window
1055
- if @is_double_buffered and @buffer_modified
1056
- raise " #{@name} @buffer_params not passed. Use set_buffering()" unless @buffer_params
1057
- # we are notchecking for TV's width exceedingg, could get -1 if TV exceeds parent/
1058
- $log.debug "RFED16 paint #{@name} calling b2s #{@graphic} "
1059
- # TODO need to call set_screen_row_col (top, left), set_pad_top_left (pminrow, pmaxrow), set_screen_max_row_col
1060
- if false
1061
- # boh these print the pad behind 0,0, later scroll etc cover it and show bars.
1062
- # adding window was giving error
1063
- ret = buffer_to_screen #@target_window.get_window
1064
- #ret = @graphic.wrefresh
1065
- else
1066
- # ext gives me parents offset. often the row would be zero, so we still need one extra
1067
- r1 = @ext_row_offset # XXX NO, i should use top and left
1068
- c1 = @ext_col_offset
1069
- r = @graphic.top # 2010-02-12 21:12 TRYING THIS.
1070
- c = @graphic.left
1071
- maxr = @buffer_params[:bottom]
1072
- maxc = @buffer_params[:right]
1073
- r = @buffer_params[:screen_top] || 0
1074
- c = @buffer_params[:screen_left] || 0
1075
- $log.debug " b2w #{r1} #{c1} , #{r} #{c} "
1076
- ## sadly this is bypassing the method that does this stuff in Pad. We need to assimilate it back, so not so much work here
1077
- pminr = @graphic.pminrow
1078
- pminc = @graphic.pmincol
1079
- border_width = 0 # 2 #XXX 2010-02-15 23:40 2 to 0
1080
- $log.debug " #{@name} ret = @graphic.copywin(@target_window.get_window, #{pminr}, #{pminc}, #{r}, #{c}, #{r}+#{maxr} - #{border_width}, #{c} + #{maxc} - #{border_width} ,0)"
1081
- # this print the view at 0,0, byt covers the scrllare, bars not shown.
1082
- # this can crash if textview is smaller than container dimension
1083
- # can crash/give -1 when panning, giong beyond pad size XXX
1084
- ret = @graphic.copywin(@target_window.get_window, pminr, pminc, r, c, r+maxr-border_width, c+maxc-border_width,0)
1085
- if ret == -1
1086
- $log.debug " copywin #{@name} h #{@height} w #{@width} "
1087
- if @height <= maxr-border_width
1088
- $log.warn " h #{@height} is <= :bottom #{maxr} "
1089
- end
1090
- if @width <= maxc-border_width
1091
- $log.warn " h #{@width} is <= :right #{maxc} "
1092
- end
1093
- $log.warn "ERROR !!! copywin returns -1 check Target: #{@target_window}, #{@target_window.get_window} " if ret == -1
1094
- end
1095
- end
1096
- $log.debug " copywin ret --> #{ret} "
1097
- #
1098
- end
1099
- end
1100
928
  def event_list
1101
929
  return @@events if defined? @@events
1102
930
  nil
@@ -1113,64 +941,84 @@ module RubyCurses
1113
941
  class Form
1114
942
  include EventHandler
1115
943
  include RubyCurses::Utils
1116
- attr_reader :value
944
+ attr_reader :value # ???
945
+
946
+ # array of widgets
1117
947
  attr_reader :widgets
948
+
949
+ # related window used for printing
1118
950
  attr_accessor :window
951
+
952
+ # cursor row and col
1119
953
  attr_accessor :row, :col
1120
954
  # attr_accessor :color
1121
955
  # attr_accessor :bgcolor
1122
- attr_accessor :padx
1123
- attr_accessor :pady
956
+
957
+ # has the form been modified
1124
958
  attr_accessor :modified
959
+
960
+ # index of active widget
1125
961
  attr_accessor :active_index
1126
- attr_reader :by_name # hash containing widgets by name for retrieval
962
+
963
+ # hash containing widgets by name for retrieval
964
+ # Useful if one widget refers to second before second created.
965
+ attr_reader :by_name
966
+
967
+ # associated menubar
1127
968
  attr_reader :menu_bar
969
+
1128
970
  attr_accessor :navigation_policy # :CYCLICAL will cycle around. Needed to move to other tabs
1129
971
  ## i need some way to move the cursor by telling the main form what the coords are
1130
972
  ##+ perhaps this will work
1131
- attr_accessor :parent_form # added 2009-12-28 23:01 BUFFERED - to bubble up row col changes
973
+ attr_accessor :parent_form # added 2009-12-28 23:01 BUFFERED - to bubble up row col changes
974
+
1132
975
  # how many rows the component is panning embedded widget by
1133
- attr_accessor :rows_panned # HACK added 2009-12-30 16:01 BUFFERED
976
+ attr_accessor :rows_panned # HACK added 2009-12-30 16:01 BUFFERED USED ??? CLEANUP XXX
1134
977
  # how many cols the component is panning embedded widget by
1135
- attr_accessor :cols_panned # HACK added 2009-12-30 16:01 BUFFERED
978
+ attr_accessor :cols_panned # HACK added 2009-12-30 16:01 BUFFERED USED ??? CLEANUP XXX
979
+
1136
980
  ## next 2 added since tabbedpanes offset needs to be accounted by form inside it.
1137
981
  attr_accessor :add_cols # 2010-01-26 20:23 additional columns due to being placed in some container
1138
982
  attr_accessor :add_rows # 2010-01-26 20:23 additional columns due to being placed in some container
983
+
984
+ # name given to form for debugging
1139
985
  attr_accessor :name # for debugging 2010-02-02 20:12
1140
- attr_accessor :ext_col_offset, :ext_row_offset # 2010-02-07 20:16 to get abs position for cursor
1141
- # attr_accessor :allow_alt_digits # catch Alt-1-9 as digit_argument
986
+
1142
987
  def initialize win, &block
1143
988
  @window = win
1144
989
  @widgets = []
1145
990
  @by_name = {}
1146
991
  @active_index = -1
1147
- @padx = @pady = 0
1148
992
  @row = @col = -1
1149
- @ext_row_offset = @ext_col_offset = 0 # 2010-02-07 20:18
1150
- @add_cols = @add_rows = 0 # 2010-01-26 20:28
993
+ @add_cols = @add_rows = 0 # 2010-01-26 20:28 CLEANUP
1151
994
  @handler = {}
1152
995
  @modified = false
1153
996
  @focusable = true
1154
997
  @navigation_policy ||= :CYCLICAL
998
+ @_events = [:ENTER, :LEAVE]
1155
999
  instance_eval &block if block_given?
1156
- @_firsttime = true # internal, don't touch
1157
1000
  ## I need some counter so a widget knows it has been panned and can send a correct
1158
1001
  ##+ cursor coordinate to system.
1159
1002
  @rows_panned = @cols_panned = 0 # how many rows were panned, typically at a higher level
1160
1003
  @_firsttime = true; # added on 2010-01-02 19:21 to prevent scrolling crash !
1161
1004
  @name ||= ""
1005
+
1006
+ # related to emacs kill ring concept for copy-paste
1007
+
1162
1008
  $kill_ring ||= [] # 2010-03-09 22:42 so textarea and others can copy and paste emacs EMACS
1163
1009
  $kill_ring_pointer = 0 # needs to be incremented with each append, moved with yank-pop
1164
1010
  $append_next_kill = false
1165
1011
  $kill_last_pop_size = 0 # size of last pop which has to be cleared
1166
1012
 
1167
- #@allow_alt_digits = true ; # capture Alt-1-9 as digit_args. Set to false if you wish to map
1168
- # Alt-1-9 to buttons of tabs
1169
1013
  $last_key = 0 # last key pressed @since 1.1.5 (not used yet)
1170
1014
  $current_key = 0 # curr key pressed @since 1.1.5 (so some containers can behave based on whether
1171
1015
  # user tabbed in, or backtabbed in (rmultisplit)
1016
+
1017
+ # for storing error message
1172
1018
  $error_message ||= Variable.new ""
1173
- $key_map ||= :vim ## should this come here or in App or ??? 2010-09-20 23:50
1019
+
1020
+ # what kind of key-bindings do you want, :vim or :emacs
1021
+ $key_map ||= :vim ## :emacs or :vim, keys to be defined accordingly. TODO
1174
1022
  end
1175
1023
  ##
1176
1024
  # set this menubar as the form's menu bar.
@@ -1179,7 +1027,7 @@ module RubyCurses
1179
1027
  def set_menu_bar mb
1180
1028
  @menu_bar = mb
1181
1029
  add_widget mb
1182
- mb.toggle_key ||= 27 # ESC
1030
+ mb.toggle_key ||= Ncurses.KEY_F2
1183
1031
  if !mb.toggle_key.nil?
1184
1032
  ch = mb.toggle_key
1185
1033
  bind_key(ch) do |_form|
@@ -1198,20 +1046,13 @@ module RubyCurses
1198
1046
  def add_widget widget
1199
1047
  # this help to access widget by a name
1200
1048
  if widget.respond_to? :name and !widget.name.nil?
1049
+ $log.debug "NAME #{self} adding a widget #{@widgets.length} .. #{widget.name} "
1201
1050
  @by_name[widget.name] = widget
1202
1051
  end
1203
1052
 
1204
1053
 
1205
1054
  $log.debug " #{self} adding a widget #{@widgets.length} .. #{widget} "
1206
1055
  @widgets << widget
1207
- # add form offsets to widget's external offsets - 2010-02-07 20:22
1208
- if widget.is_a? RubyCurses::Widget
1209
- if @window # ext seems redundant
1210
- widget.ext_col_offset += @window.left # just hope window aint undef!! XXX
1211
- $log.debug " #{@name} add widget ( #{widget.name} ) ext_row #{widget.ext_row_offset} += #{@window.top} "
1212
- widget.ext_row_offset += @window.top
1213
- end
1214
- end
1215
1056
  return @widgets.length-1
1216
1057
  end
1217
1058
  alias :add :add_widget
@@ -1220,7 +1061,6 @@ module RubyCurses
1220
1061
  # added 2008-12-09 12:18
1221
1062
  def remove_widget widget
1222
1063
  if widget.respond_to? :name and !widget.name.nil?
1223
- $log.debug "removing from byname: #{widget.name} "
1224
1064
  @by_name.delete(widget.name)
1225
1065
  end
1226
1066
  @widgets.delete widget
@@ -1228,7 +1068,7 @@ module RubyCurses
1228
1068
  # form repaint
1229
1069
  # to be called at some interval, such as after each keypress.
1230
1070
  def repaint
1231
- $log.debug " form repaint:#{self}, #{@name} , r #{@row} c #{@col} "
1071
+ $log.debug " form repaint:#{self}, #{@name} , r #{@row} c #{@col} " if $log.debug?
1232
1072
  @widgets.each do |f|
1233
1073
  next if f.visible == false # added 2008-12-09 12:17
1234
1074
  f.repaint
@@ -1245,23 +1085,19 @@ module RubyCurses
1245
1085
  setpos
1246
1086
  # XXX this creates a problem if window is a pad
1247
1087
  # although this does show cursor movement etc.
1248
- ### XXX@window.wrefresh
1088
+ ### @window.wrefresh
1249
1089
  if @window.window_type == :WINDOW
1250
- $log.debug " formrepaint #{@name} calling window.wrefresh #{@window} "
1090
+ #$log.debug " formrepaint #{@name} calling window.wrefresh #{@window} "
1251
1091
  @window.wrefresh
1252
1092
  Ncurses::Panel.update_panels ## added 2010-11-05 00:30 to see if clears the stdscr problems
1253
1093
  else
1254
1094
  $log.warn " XXX formrepaint #{@name} no refresh called 2011-09-19 #{@window} "
1255
- #@window.wrefresh # trying FFI 2011-09-19
1256
1095
  end
1257
1096
  end
1258
1097
  ##
1259
1098
  # move cursor to where the fields row and col are
1260
1099
  # private
1261
1100
  def setpos r=@row, c=@col
1262
- # next 2 lines added, only do cursor if current field doesn't manage it.
1263
- #curr = get_current_field
1264
- #return if curr.manages_cursor
1265
1101
  $log.debug "setpos : (#{self}) #{r} #{c}"
1266
1102
  ## adding just in case things are going out of bounds of a parent and no cursor to be shown
1267
1103
  return if r.nil? or c.nil? # added 2009-12-29 23:28 BUFFERED
@@ -1289,7 +1125,7 @@ module RubyCurses
1289
1125
  elsif @active_index != ix
1290
1126
  f = @widgets[@active_index]
1291
1127
  begin
1292
- #$log.debug " XXX select first field, calling on_leave of #{f} #{@active_index} "
1128
+ #$log.debug " select first field, calling on_leave of #{f} #{@active_index} "
1293
1129
  on_leave f
1294
1130
  rescue => err
1295
1131
  $log.error " Caught EXCEPTION req_first_field on_leave #{err}"
@@ -1318,16 +1154,18 @@ module RubyCurses
1318
1154
  @active_index = nil
1319
1155
  select_prev_field
1320
1156
  end
1157
+
1321
1158
  # please do not use req_ i will deprecate it soon.
1322
1159
  alias :req_last_field :select_last_field
1160
+
1323
1161
  ## do not override
1324
1162
  # form's trigger, fired when any widget loses focus
1325
- # This wont get called in editor components in tables, since they are formless XXX
1163
+ # This wont get called in editor components in tables, since they are formless
1326
1164
  def on_leave f
1327
1165
  return if f.nil? || !f.focusable # added focusable, else label was firing
1328
1166
  f.state = :NORMAL
1329
1167
  # on leaving update text_variable if defined. Should happen on modified only
1330
- # should this not be f.text_var ... f.buffer ? XXX 2008-11-25 18:58
1168
+ # should this not be f.text_var ... f.buffer ? 2008-11-25 18:58
1331
1169
  #f.text_variable.value = f.buffer if !f.text_variable.nil? # 2008-12-20 23:36
1332
1170
  f.on_leave if f.respond_to? :on_leave
1333
1171
  fire_handler :LEAVE, f
@@ -1337,6 +1175,9 @@ module RubyCurses
1337
1175
  f.fire_handler(:CHANGED, f)
1338
1176
  end
1339
1177
  end
1178
+ # form calls on_enter of each object.
1179
+ # However, if a multicomponent calls on_enter of a widget, this code will
1180
+ # not be triggered. The highlighted part
1340
1181
  def on_enter f
1341
1182
  return if f.nil? || !f.focusable # added focusable, else label was firing 2010-09
1342
1183
  f.state = :HIGHLIGHTED
@@ -1354,27 +1195,33 @@ module RubyCurses
1354
1195
  # puts focus on the given field/widget index
1355
1196
  # XXX if called externally will not run a on_leave of previous field
1356
1197
  def select_field ix0
1357
- #return if @widgets.nil? or @widgets.empty? or !@widgets[ix0].focusable
1358
1198
  return if @widgets.nil? or @widgets.empty? or !focusable?(@widgets[ix0])
1359
- #$log.debug "insdie select field : #{ix0} ai #{@active_index}"
1199
+ #$log.debug "inside select_field : #{ix0} ai #{@active_index}"
1360
1200
  f = @widgets[ix0]
1361
1201
  if focusable?(f)
1362
1202
  @active_index = ix0
1363
1203
  @row, @col = f.rowcol
1364
- #$log.debug " WMOVE insdie sele nxt field : ROW #{@row} COL #{@col} "
1365
- @window.wmove @row, @col # added RK FFI 2011-09-7
1204
+ #$log.debug " WMOVE insdie sele nxt field : ROW #{@row} COL #{@col} "
1366
1205
  on_enter f
1206
+ @window.wmove @row, @col # added RK FFI 2011-09-7 = setpos
1207
+
1208
+ f.set_form_row # added 2011-10-5 so when embedded in another form it can get the cursor
1209
+ f.set_form_col
1210
+
1367
1211
  f.curpos = 0
1368
1212
  repaint
1369
1213
  @window.refresh
1370
1214
  else
1371
- $log.debug "insdie sele nxt field ENABLED FALSE : act #{@active_index} ix0 #{ix0}"
1215
+ $log.debug "inside select field ENABLED FALSE : act #{@active_index} ix0 #{ix0}"
1372
1216
  end
1373
1217
  end
1374
1218
  ##
1375
1219
  # run validate_field on a field, usually whatevers current
1376
1220
  # before transferring control
1377
1221
  # We should try to automate this so developer does not have to remember to call it.
1222
+ # # @param field object
1223
+ # @return [0, -1] for success or failure
1224
+ # NOTE : catches exception and sets $error_message, check if -1
1378
1225
  def validate_field f=@widgets[@active_index]
1379
1226
  begin
1380
1227
  on_leave f
@@ -1393,21 +1240,25 @@ module RubyCurses
1393
1240
  # in which case returns :NO_NEXT_FIELD.
1394
1241
  # FIXME: in the beginning it comes in as -1 and does an on_leave of last field
1395
1242
  def select_next_field
1396
- return if @widgets.nil? or @widgets.empty?
1397
- $log.debug "insdie sele nxt field : #{@active_index} WL:#{@widgets.length}"
1243
+ return :UNHANDLED if @widgets.nil? or @widgets.empty?
1244
+ #$log.debug "insdie sele nxt field : #{@active_index} WL:#{@widgets.length}"
1398
1245
  if @active_index.nil? || @active_index == -1 # needs to be tested out A LOT
1399
1246
  @active_index = -1
1400
1247
  else
1401
1248
  f = @widgets[@active_index]
1402
1249
  begin
1403
1250
  on_leave f
1251
+ rescue FieldValidationException => err # added 2011-10-2 v1.3.1 so we can rollback
1252
+ $log.error "select_next_field: caught EXCEPTION #{err}"
1253
+ $error_message.value = "#{err}"
1254
+ raise err
1404
1255
  rescue => err
1405
1256
  $log.error "select_next_field: caught EXCEPTION #{err}"
1406
1257
  $log.error(err.backtrace.join("\n"))
1407
1258
  # $error_message = "#{err}" # changed 2010
1408
1259
  $error_message.value = "#{err}"
1409
1260
  Ncurses.beep
1410
- return
1261
+ return 0
1411
1262
  end
1412
1263
  end
1413
1264
  index = @active_index + 1
@@ -1416,7 +1267,7 @@ module RubyCurses
1416
1267
  #$log.debug "insdie sele nxt field : i #{i} #{index} WL:#{@widgets.length}, field #{f}"
1417
1268
  if focusable?(f)
1418
1269
  select_field i
1419
- return
1270
+ return 0
1420
1271
  end
1421
1272
  end
1422
1273
  #req_first_field
@@ -1430,11 +1281,11 @@ module RubyCurses
1430
1281
  f = @widgets[i]
1431
1282
  if focusable?(f)
1432
1283
  select_field i
1433
- return
1284
+ return 0
1434
1285
  end
1435
1286
  end
1436
1287
  end
1437
- $log.debug "insdie sele nxt field : NO NEXT #{@active_index} WL:#{@widgets.length}"
1288
+ $log.debug "inside sele nxt field : NO NEXT #{@active_index} WL:#{@widgets.length}"
1438
1289
  return :NO_NEXT_FIELD
1439
1290
  end
1440
1291
  ##
@@ -1444,7 +1295,7 @@ module RubyCurses
1444
1295
  # @return [nil, :NO_PREV_FIELD] nil if cyclical and it finds a field
1445
1296
  # if not cyclical, and no more fields then :NO_PREV_FIELD
1446
1297
  def select_prev_field
1447
- return if @widgets.nil? or @widgets.empty?
1298
+ return :UNHANDLED if @widgets.nil? or @widgets.empty?
1448
1299
  #$log.debug "insdie sele prev field : #{@active_index} WL:#{@widgets.length}"
1449
1300
  if @active_index.nil?
1450
1301
  @active_index = @widgets.length
@@ -1469,7 +1320,7 @@ module RubyCurses
1469
1320
  return
1470
1321
  end
1471
1322
  end
1472
- # $log.debug "insdie sele prev field FAILED: #{@active_index} WL:#{@widgets.length}"
1323
+
1473
1324
  ## added on 2008-12-14 18:27 so we can skip to another form/tab
1474
1325
  # 2009-01-08 12:24 no recursion, can be stack overflows if no focusable field
1475
1326
  if @navigation_policy == :CYCLICAL
@@ -1496,12 +1347,7 @@ module RubyCurses
1496
1347
  @window.wmove @row, @col
1497
1348
  ## 2010-01-30 23:45 exchange calling parent with calling this forms setrow
1498
1349
  # since in tabbedpane with table i am not gietting this forms offset.
1499
- setrowcol nil, col
1500
- # added on 2010-01-05 22:26 so component widgets like scrollpane can get the cursor
1501
- #if !@parent_form.nil? and @parent_form != self #@form
1502
- #$log.debug " #{@name} addcol calling parents setrowcol #{row}, #{col}: #{@parent_form} "
1503
- #@parent_form.setrowcol nil, col
1504
- #end
1350
+ setrowcol nil, col
1505
1351
  end
1506
1352
  ##
1507
1353
  # move cursor by given rows and columns, can be negative.
@@ -1527,9 +1373,9 @@ module RubyCurses
1527
1373
  @col = c unless c.nil?
1528
1374
  r += @add_rows unless r.nil? # 2010-01-26 20:31
1529
1375
  c += @add_cols unless c.nil? # 2010-01-26 20:31
1530
- $log.debug " addcols #{@add_cols} addrow #{@add_rows} : #{self} "
1376
+ $log.debug " addcols #{@add_cols} addrow #{@add_rows} : #{self} r = #{r} , c = #{c} "
1531
1377
  if !@parent_form.nil? and @parent_form != self
1532
- $log.debug " (#{@name}) calling parents setrowcol #{r}, #{c} : pare: #{@parent_form}; self: #{self}, #{self.class} "
1378
+ $log.debug " (#{@name}) addrow calling parents setrowcol #{r}, #{c} : pare: #{@parent_form}; self: #{self}, #{self.class} "
1533
1379
  #r += @parent_form.window.top unless r.nil?
1534
1380
  #c += @parent_form.window.left unless c.nil?
1535
1381
  @parent_form.setrowcol r, c
@@ -1542,14 +1388,17 @@ module RubyCurses
1542
1388
  # after form handles basic keys, it gives unhandled key to current field, if current field returns
1543
1389
  # unhandled, then it checks this map.
1544
1390
  # Please update widget with any changes here. TODO: match regexes as in mapper
1391
+
1545
1392
  def process_key keycode, object
1546
1393
  return _process_key keycode, object, @window
1547
1394
  end
1395
+
1548
1396
  # Defines how user can give numeric args to a command even in edit mode
1549
1397
  # User either presses universal_argument (C-u) which generates a series of 4 16 64.
1550
1398
  # Or he presses C-u and then types some numbers. Followed by the action.
1551
1399
  # @returns [0, :UNHANDLED] :UNHANDLED implies that last keystroke is still to evaluated
1552
1400
  # by system. ) implies only numeric args were obtained. This method updates $multiplier
1401
+
1553
1402
  def universal_argument
1554
1403
  $multiplier = ( ($multiplier.nil? || $multiplier == 0) ? 4 : $multiplier *= 4)
1555
1404
  $log.debug " inside UNIV MULT0: #{$multiplier} "
@@ -1583,6 +1432,7 @@ module RubyCurses
1583
1432
  end
1584
1433
  return 0
1585
1434
  end
1435
+
1586
1436
  def digit_argument ch
1587
1437
  $multiplier = ch - ?\M-0.getbyte(0)
1588
1438
  $log.debug " inside UNIV MULT 0 #{$multiplier} "
@@ -1612,11 +1462,16 @@ module RubyCurses
1612
1462
  end
1613
1463
  return 0
1614
1464
  end
1465
+
1615
1466
  ## forms handle keys
1616
1467
  # mainly traps tab and backtab to navigate between widgets.
1617
1468
  # I know some widgets will want to use tab, e.g edit boxes for entering a tab
1618
1469
  # or for completion.
1470
+ # @throws FieldValidationException
1471
+ # NOTE : please rescue exceptions when you use this in your main loop and alert() user
1472
+ #
1619
1473
  def handle_key(ch)
1474
+ handled = :UNHANDLED # 2011-10-4
1620
1475
  if ch == ?\C-u.getbyte(0)
1621
1476
  ret = universal_argument
1622
1477
  $log.debug "C-u FORM set MULT to #{$multiplier}, ret = #{ret} "
@@ -1646,11 +1501,14 @@ module RubyCurses
1646
1501
  Ncurses.endwin
1647
1502
  @window.wrefresh
1648
1503
  else
1649
- keycode = keycode_tos(ch)
1650
- $log.debug " form HK #{ch} #{self}, #{@name}, #{keycode} "
1651
1504
  field = get_current_field
1505
+ if $log.debug?
1506
+ keycode = keycode_tos(ch)
1507
+ $log.debug " form HK #{ch} #{self}, #{@name}, #{keycode}, field: giving to: #{field}, #{field.name} "
1508
+ end
1652
1509
  handled = :UNHANDLED
1653
1510
  handled = field.handle_key ch unless field.nil? # no field focussable
1511
+ $log.debug "handled inside Form #{ch} from #{field} got #{handled} "
1654
1512
  # some widgets like textarea and list handle up and down
1655
1513
  if handled == :UNHANDLED or handled == -1 or field.nil?
1656
1514
  case ch
@@ -1662,36 +1520,24 @@ module RubyCurses
1662
1520
  ret = select_prev_field
1663
1521
  return ret if ret == :NO_PREV_FIELD
1664
1522
  when FFI::NCurses::KEY_UP
1665
- select_prev_field
1523
+ ret = select_prev_field
1524
+ return ret if ret == :NO_PREV_FIELD
1666
1525
  when FFI::NCurses::KEY_DOWN
1667
- select_next_field
1668
- #when ?\M-L.getbyte(0)
1669
- ### trying out these for fuun and testing splitpane 2010-01-10 20:32
1670
- #$log.debug " field #{field.name} was #{field.width} "
1671
- #field.width += 1
1672
- #$log.debug " field #{field.name} now #{field.width} "
1673
- #field.repaint_all
1674
- #when ?\M-H.getbyte(0), ?\M-<.getbyte(0)
1675
- #field.width -= 1
1676
- #$log.debug " field #{field.name} now #{field.width} "
1677
- #field.repaint_all
1678
- #when ?\M-J.getbyte(0)
1679
- #field.height += 1
1680
- #when ?\M-K.getbyte(0)
1681
- #field.height -= 1
1526
+ ret = select_next_field
1527
+ return ret if ret == :NO_NEXT_FIELD
1682
1528
  else
1683
- #$log.debug "XXX before calling process_key in form #{ch} " if $log.debug?
1529
+ #$log.debug " before calling process_key in form #{ch} " if $log.debug?
1684
1530
  ret = process_key ch, self
1685
1531
  $log.debug "FORM process_key #{ch} got ret #{ret} in #{self} "
1686
1532
  return :UNHANDLED if ret == :UNHANDLED
1687
1533
  end
1534
+ elsif handled == :NO_NEXT_FIELD || handled == :NO_PREV_FIELD # 2011-10-4
1535
+ return handled
1688
1536
  end
1689
1537
  end
1690
1538
  $log.debug " form before repaint #{self} , #{@name}, ret #{ret}"
1691
1539
  repaint
1692
1540
  $last_key = ch
1693
- #return handled # TRYNG 2010-03-01 23:30 since TP returns NO_NEXT_FIELD sometimes
1694
- #$multiplier = 0
1695
1541
  end
1696
1542
  ##
1697
1543
  # test program to dump data onto log
@@ -1701,8 +1547,8 @@ module RubyCurses
1701
1547
  # or editable as filters. I just dump everything?
1702
1548
  # What's more, currently getvalue has been used by paint to return what needs to be displayed -
1703
1549
  # at least by label and button.
1704
- def dump_data
1705
- $log.debug " DUMPING DATA "
1550
+ def DEPRECATED_dump_data # CLEAN
1551
+ $log.debug "DEPRECATED DUMPING DATA "
1706
1552
  @widgets.each do |w|
1707
1553
  # we need checkbox and radio button values
1708
1554
  #next if w.is_a? RubyCurses::Button or w.is_a? RubyCurses::Label
@@ -1717,7 +1563,7 @@ module RubyCurses
1717
1563
  $log.debug " END DUMPING DATA "
1718
1564
  end
1719
1565
  ##
1720
- # trying out for splitpane and others who have a sub-form
1566
+ # trying out for splitpane and others who have a sub-form. TabbedPane uses
1721
1567
  def set_parent_buffer b
1722
1568
  @parent_buffer = b
1723
1569
  end
@@ -1757,15 +1603,6 @@ module RubyCurses
1757
1603
  col = w.col
1758
1604
  return row, col
1759
1605
  end
1760
- ## so if we come back from ncurses cooked mode we can repaint.
1761
- # not required, we have to stop and restart ncurses.
1762
- #def reset_all
1763
- #$log.debug " form reset:#{self}, #{@name} , r #{@row} c #{@col} "
1764
- #@widgets.each do |f|
1765
- #next if f.visible == false # added 2008-12-09 12:17
1766
- #f.repaint_all()
1767
- #end
1768
- #end
1769
1606
 
1770
1607
  ## ADD HERE FORM
1771
1608
  end
@@ -1807,72 +1644,68 @@ module RubyCurses
1807
1644
  dsl_accessor :default # TODO use set_buffer for now
1808
1645
  dsl_accessor :values # validate against provided list
1809
1646
  dsl_accessor :valid_regex # validate against regular expression
1647
+ dsl_accessor :valid_range # validate against numeric range # 2011-09-29 V1.3.1
1810
1648
 
1811
- dsl_accessor :chars_allowed # regex, what characters to allow, will ignore all else
1812
- dsl_accessor :display_length # how much to display
1813
- dsl_accessor :bgcolor # background color 'red' 'black' 'cyan' etc
1814
- dsl_accessor :color # foreground colors from Ncurses COLOR_xxxx
1815
- dsl_accessor :show # what charactr to show for each char entered (password field)
1816
- dsl_accessor :null_allowed # allow nulls, don't validate if null # added 2008-12-22 12:38
1649
+ dsl_accessor :chars_allowed # regex, what characters to allow, will ignore all else
1650
+ dsl_accessor :display_length # how much to display
1651
+ #dsl_property :bgcolor # background color 'red' 'black' 'cyan' etc # 2011-09-29 IN WIDGET
1652
+ #dsl_property :color # foreground colors from Ncurses COLOR_xxxx
1653
+ dsl_accessor :show # what charactr to show for each char entered (password field)
1654
+ dsl_accessor :null_allowed # allow nulls, don't validate if null # added 2008-12-22 12:38
1817
1655
 
1818
1656
  # any new widget that has editable should have modified also
1819
1657
  dsl_accessor :editable # allow editing
1820
1658
 
1821
1659
  attr_reader :form
1822
- attr_reader :handler # event handler
1823
- attr_reader :type # datatype of field, currently only sets chars_allowed
1824
- #attr_reader :curpos # cursor position in buffer current, in WIDGET
1825
- attr_accessor :datatype # crrently set during set_buffer
1826
- attr_reader :original_value # value on entering field
1660
+ attr_reader :handler # event handler
1661
+ attr_reader :type # datatype of field, currently only sets chars_allowed
1662
+ #attr_reader :curpos # cursor position in buffer current, in WIDGET
1663
+ attr_accessor :datatype # crrently set during set_buffer
1664
+ attr_reader :original_value # value on entering field
1827
1665
  attr_accessor :overwrite_mode # true or false INSERT OVERWRITE MODE
1828
1666
 
1829
1667
  def initialize form, config={}, &block
1830
1668
  @form = form
1831
1669
  @buffer = String.new
1832
1670
  #@type=config.fetch("type", :varchar)
1833
- # 2010-10-19 12:26 slight change, hopefully won't bomb
1834
1671
  @display_length = 20
1835
1672
  @maxlen = @display_length
1836
1673
  @row = 0
1837
1674
  @col = 0
1838
1675
  @bgcolor = $def_bg_color
1839
1676
  @color = $def_fg_color
1840
- #@name = config.fetch("name", nil)
1841
1677
  @editable = true
1842
1678
  @focusable = true
1843
- # are these redundant ?
1844
- #@display_length = config.fetch("display_length", 20)
1845
- #@maxlen=config.fetch("maxlen", @display_length)
1846
- #@row = config.fetch("row", 0)
1847
- #@col = config.fetch("col", 0)
1848
- #@bgcolor = config.fetch("bgcolor", $def_bg_color)
1849
- #@color = config.fetch("color", $def_fg_color)
1850
- #@name = config.fetch("name", nil)
1851
- #@editable = config.fetch("editable", true)
1852
- #@focusable = config.fetch("focusable", true)
1853
1679
  @event_args = {} # arguments passed at time of binding, to use when firing event
1854
1680
  map_keys
1855
1681
  init_vars
1856
- super
1682
+ @_events ||= []
1857
1683
  @_events.push(:CHANGE)
1684
+ super
1858
1685
  end
1859
1686
  def init_vars
1860
- @pcol = 0 # needed for horiz scrolling
1687
+ @pcol = 0 # needed for horiz scrolling
1861
1688
  @curpos = 0 # current cursor position in buffer
1862
1689
  @modified = false
1863
1690
  @repaint_required = true
1864
1691
  end
1692
+
1693
+ #
1694
+ # Set Variable as value.
1695
+ # This allows using Field as a proxy
1696
+ # @param [Variable] variable containing text value
1697
+ #
1865
1698
  def text_variable tv
1866
1699
  @text_variable = tv
1867
1700
  set_buffer tv.value
1868
1701
  end
1869
1702
  ##
1870
1703
  # define a datatype, currently only influences chars allowed
1871
- # integer and float. what about allowing a minus sign? XXX
1704
+ # integer and float. what about allowing a minus sign?
1872
1705
  # 2010-09-10 20:59 changed string to symbol
1873
1706
  def type dtype
1874
1707
  return if !@chars_allowed.nil?
1875
- case dtype.to_s.downcase
1708
+ case dtype.to_s.downcase.to_sym # missing to_sym would have always failed due to to_s 2011-09-30 1.3.1
1876
1709
  when :integer
1877
1710
  @chars_allowed = /\d/
1878
1711
  when :numeric, :float
@@ -1881,8 +1714,12 @@ module RubyCurses
1881
1714
  @chars_allowed = /[a-zA-Z]/
1882
1715
  when :alnum
1883
1716
  @chars_allowed = /[a-zA-Z0-9]/
1717
+ else
1718
+ raise "type: invalid datatype specified. Use :integer, :numeric, :float, :alpha, :alnum "
1884
1719
  end
1885
1720
  end
1721
+
1722
+ #
1886
1723
  # add a char to field, and validate
1887
1724
  # NOTE: this should return self for chaining operations and throw an exception
1888
1725
  # if disabled or exceeding size
@@ -1941,8 +1778,18 @@ module RubyCurses
1941
1778
  #fire_handler :CHANGE, self # 2008-12-09 14:51
1942
1779
  fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos, self, :DELETE, 0, char) # 2010-09-11 13:01
1943
1780
  end
1781
+ #
1782
+ # silently restores value without firing handlers, use if exception and you want old value
1783
+ # @since 1.4.0 2011-10-2
1784
+ def restore_original_value
1785
+ @buffer = @original_value.dup
1786
+ #@curpos = 0 # this would require restting setformcol
1787
+ @repaint_required = true
1788
+ end
1944
1789
  ##
1945
1790
  # should this do a dup ?? YES
1791
+ # set value of Field
1792
+ # fires CHANGE handler
1946
1793
  def set_buffer value
1947
1794
  @repaint_required = true
1948
1795
  @datatype = value.class
@@ -1950,9 +1797,10 @@ module RubyCurses
1950
1797
  @delete_buffer = @buffer.dup
1951
1798
  @buffer = value.to_s.dup
1952
1799
  @curpos = 0
1953
- # XXX hope @delete_buffer is not overwritten
1800
+ # hope @delete_buffer is not overwritten
1954
1801
  fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos, self, :DELETE, 0, @delete_buffer) # 2010-09-11 13:01
1955
1802
  fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos, self, :INSERT, 0, @buffer) # 2010-09-11 13:01
1803
+ self # 2011-10-2
1956
1804
  end
1957
1805
  # converts back into original type
1958
1806
  # changed to convert on 2009-01-06 23:39
@@ -1974,19 +1822,19 @@ module RubyCurses
1974
1822
  # Typically one passes a Label, but now we can pass just a String, a label
1975
1823
  # is created
1976
1824
  # @param [Label, String] label object to be associated with this field
1977
- def set_label label
1978
- # added case for user just using a string
1979
- case label
1980
- when String
1981
- # what if no form at this point
1982
- label = Label.new @form, {:text => label}
1983
- end
1984
- @label = label
1985
- label.row @row if label.row == -1
1986
- label.col @col-(label.name.length+1) if label.col == -1
1987
- label.label_for(self)
1988
- label
1989
- end
1825
+ def set_label label
1826
+ # added case for user just using a string
1827
+ case label
1828
+ when String
1829
+ # what if no form at this point
1830
+ label = Label.new @form, {:text => label}
1831
+ end
1832
+ @label = label
1833
+ label.row @row if label.row == -1
1834
+ label.col @col-(label.name.length+1) if label.col == -1
1835
+ label.label_for(self)
1836
+ label
1837
+ end
1990
1838
 
1991
1839
  ## Note that some older widgets like Field repaint every time the form.repaint
1992
1840
  ##+ is called, whether updated or not. I can't remember why this is, but
@@ -2009,15 +1857,10 @@ module RubyCurses
2009
1857
  end
2010
1858
  #printval = printval[0..display_length-1] if printval.length > display_length
2011
1859
  acolor = @color_pair || get_color($datacolor, @color, @bgcolor)
2012
- #if @bgcolor.is_a? String and @color.is_a? String
2013
- #acolor = ColorMap.get_color(@color, @bgcolor)
2014
- #else
2015
- #acolor = $datacolor
2016
- #end
2017
- @graphic = @form.window if @graphic.nil? ## cell editor listbox hack XXX fix in correct place
1860
+ @graphic = @form.window if @graphic.nil? ## cell editor listbox hack
2018
1861
  #$log.debug " Field g:#{@graphic}. r,c,displen:#{@row}, #{@col}, #{@display_length} "
2019
1862
  @graphic.printstring row, col, sprintf("%-*s", display_length, printval), acolor, @attr
2020
- @repaint_required = false # 2010-11-20 13:13
1863
+ @repaint_required = false
2021
1864
  end
2022
1865
  def set_focusable(tf)
2023
1866
  @focusable = tf
@@ -2033,50 +1876,22 @@ module RubyCurses
2033
1876
  bind_key(?\C-e){ cursor_end }
2034
1877
  bind_key(?\C-k){ delete_eol }
2035
1878
  bind_key(?\C-_){ undo_delete_eol }
2036
- bind_key(27){ set_buffer @original_value }
1879
+ #bind_key(27){ set_buffer @original_value }
1880
+ bind_key(?\C-g){ set_buffer @original_value } # 2011-09-29 V1.3.1 ESC did not work
2037
1881
  @keys_mapped = true
2038
1882
  end
2039
1883
 
2040
1884
  # field
2041
- # # TODO bind these keys so they can be overridden
1885
+ #
2042
1886
  def handle_key ch
2043
- @repaint_required = true # added 2010-11-20 13:21
1887
+ @repaint_required = true
2044
1888
  #map_keys unless @keys_mapped # moved to init
2045
1889
  case ch
2046
- #when KEY_LEFT
2047
- #cursor_backward
2048
- #when KEY_RIGHT
2049
- #cursor_forward
2050
- #when KEY_BACKSPACE, 127
2051
- #delete_prev_char if @editable
2052
- #when KEY_UP
2053
- # $log.debug " FIELD GOT KEY_UP, NOW IGNORING 2009-01-16 17:52 "
2054
- #@form.select_prev_field # in a table this should not happen 2009-01-16 17:47
2055
- # return :UNHANDLED
2056
- #when KEY_DOWN
2057
- # $log.debug " FIELD GOT KEY_DOWN, NOW IGNORING 2009-01-16 17:52 "
2058
- #@form.select_next_field # in a table this should not happen 2009-01-16 17:47
2059
- # return :UNHANDLED
2060
- # user cannot bind here or on form if i eat up
2061
- #when KEY_ENTER, 10, 13
2062
- #if respond_to? :fire
2063
- #fire
2064
- #end
2065
- #when 330
2066
- #delete_curr_char if @editable
2067
- #when ?\C-a.getbyte(0)
2068
- #cursor_home
2069
- #when ?\C-e.getbyte(0)
2070
- #cursor_end
2071
- #when ?\C-k.getbyte(0)
2072
- #delete_eol if @editable
2073
- #when ?\C-_.getbyte(0) # changed on 2010-02-26 14:44 so C-u can be used as numeric arg
2074
- #undo_delete_eol
2075
1890
  when 32..126
2076
1891
  #$log.debug("FIELD: ch #{ch} ,at #{@curpos}, buffer:[#{@buffer}] bl: #{@buffer.to_s.length}")
2077
1892
  putc ch
2078
- #when 27 # escape
2079
- #set_buffer @original_value
1893
+ when 27 # cannot bind it
1894
+ set_buffer @original_value
2080
1895
  else
2081
1896
  ret = super
2082
1897
  return ret
@@ -2099,15 +1914,15 @@ module RubyCurses
2099
1914
  ##
2100
1915
  # goto end of field, "end" is a keyword so could not use it.
2101
1916
  def cursor_end
2102
- blen = @buffer.rstrip.length
2103
- if blen < @display_length
2104
- set_form_col blen
2105
- else
2106
- @pcol = blen-@display_length
2107
- set_form_col @display_length-1
2108
- end
2109
- @curpos = blen # HACK XXX
2110
- # $log.debug " crusor END cp:#{@curpos} pcol:#{@pcol} b.l:#{@buffer.length} d_l:#{@display_length} fc:#{@form.col}"
1917
+ blen = @buffer.rstrip.length
1918
+ if blen < @display_length
1919
+ set_form_col blen
1920
+ else
1921
+ @pcol = blen-@display_length
1922
+ set_form_col @display_length-1
1923
+ end
1924
+ @curpos = blen # HACK
1925
+ # $log.debug " crusor END cp:#{@curpos} pcol:#{@pcol} b.l:#{@buffer.length} d_l:#{@display_length} fc:#{@form.col}"
2111
1926
  #set_form_col @buffer.length
2112
1927
  end
2113
1928
  def delete_eol
@@ -2194,8 +2009,13 @@ module RubyCurses
2194
2009
  valid = @valid_regex.match(val.to_s)
2195
2010
  raise FieldValidationException, "Field not matching regex #{@valid_regex}" unless valid
2196
2011
  end
2012
+ # added valid_range for numerics 2011-09-29
2013
+ if !@valid_range.nil?
2014
+ valid = @valid_range.include?(val.to_i)
2015
+ raise FieldValidationException, "Field not matching range #{@valid_range}" unless valid
2016
+ end
2197
2017
  end
2198
- # here is where we should set the forms modified to true - 2009-01-18 12:36 XXX
2018
+ # here is where we should set the forms modified to true - 2009-01
2199
2019
  if modified?
2200
2020
  set_modified true
2201
2021
  end
@@ -2205,8 +2025,11 @@ module RubyCurses
2205
2025
  end
2206
2026
  ## save original value on enter, so we can check for modified.
2207
2027
  # 2009-01-18 12:25
2028
+ # 2011-10-9 I have changed to take @buffer since getvalue returns a datatype
2029
+ # and this causes a crash in set_original on cursor forward.
2208
2030
  def on_enter
2209
- @original_value = getvalue.dup rescue getvalue
2031
+ #@original_value = getvalue.dup rescue getvalue
2032
+ @original_value = @buffer.dup # getvalue.dup rescue getvalue
2210
2033
  super
2211
2034
  end
2212
2035
  ##
@@ -2238,6 +2061,7 @@ module RubyCurses
2238
2061
  # will update the Variable. A variable can be used to link a field with a label or
2239
2062
  # some other widget.
2240
2063
  # This is the new version of Variable. Deleting old version on 2009-01-17 12:04
2064
+
2241
2065
  class Variable
2242
2066
 
2243
2067
  def initialize value=""
@@ -2246,6 +2070,7 @@ module RubyCurses
2246
2070
  @value = value
2247
2071
  @klass = value.class.to_s
2248
2072
  end
2073
+
2249
2074
  ##
2250
2075
  # This is to ensure that change handlers for all dependent objects are called
2251
2076
  # so they are updated. This is called from text_variable property of some widgets. If you
@@ -2361,6 +2186,8 @@ module RubyCurses
2361
2186
  @name ||= @text
2362
2187
  @repaint_required = true
2363
2188
  end
2189
+ #
2190
+ # get the value for the label
2364
2191
  def getvalue
2365
2192
  @text_variable && @text_variable.value || @text
2366
2193
  end
@@ -2391,49 +2218,49 @@ module RubyCurses
2391
2218
  # XXX need to move wrapping etc up and done once.
2392
2219
  def repaint
2393
2220
  return unless @repaint_required
2394
- r,c = rowcol
2395
- # value often nil so putting blank, but usually some application error
2396
- value = getvalue_for_paint || ""
2397
- lablist = []
2398
- if @height && @height > 1
2399
- lablist = wrap_text(value, @display_length).split("\n")
2400
- else
2401
- # ensure we do not exceed
2402
- if !@display_length.nil?
2403
- if value.length > @display_length
2404
- value = value[0..@display_length-1]
2405
- end
2406
- end
2407
- lablist << value
2408
- end
2409
- len = @display_length || value.length
2410
- acolor = get_color $datacolor
2411
- #$log.debug "label :#{@text}, #{value}, #{r}, #{c} col= #{@color}, #{@bgcolor} acolor #{acolor} j:#{@justify} dlL: #{@display_length} "
2412
- firstrow = r
2413
- _height = @height || 1
2414
- str = @justify.to_sym == :right ? "%*s" : "%-*s" # added 2008-12-22 19:05
2415
- # loop added for labels that are wrapped.
2416
- # TODO clear separately since value can change in status like labels
2417
- #$log.debug " RWID 1595 #{self.class} value: #{value} form: #{form} "
2418
- @graphic = @form.window if @graphic.nil? ## HACK messagebox givig this in repaint, 423 not working ??
2419
- 0.upto(_height-1) { |i|
2420
- @graphic.printstring r+i, c, " " * len , acolor,@attr
2421
- }
2422
- lablist.each_with_index do |_value, ix|
2423
- break if ix >= _height
2424
- if @justify.to_sym == :center
2425
- padding = (@display_length - _value.length)/2
2426
- _value = " "*padding + _value + " "*padding # so its cleared if we change it midway
2221
+ r,c = rowcol
2222
+ # value often nil so putting blank, but usually some application error
2223
+ value = getvalue_for_paint || ""
2224
+ lablist = []
2225
+ if @height && @height > 1
2226
+ lablist = wrap_text(value, @display_length).split("\n")
2227
+ else
2228
+ # ensure we do not exceed
2229
+ if !@display_length.nil?
2230
+ if value.length > @display_length
2231
+ value = value[0..@display_length-1]
2427
2232
  end
2428
- @graphic.printstring r, c, str % [len, _value], acolor,@attr
2429
- r += 1
2430
2233
  end
2431
- if !@mnemonic.nil?
2432
- ulindex = value.index(@mnemonic) || value.index(@mnemonic.swapcase)
2433
- @graphic.mvchgat(y=firstrow, x=c+ulindex, max=1, Ncurses::A_BOLD|Ncurses::A_UNDERLINE, acolor, nil)
2234
+ lablist << value
2235
+ end
2236
+ len = @display_length || value.length
2237
+ acolor = get_color $datacolor
2238
+ #$log.debug "label :#{@text}, #{value}, #{r}, #{c} col= #{@color}, #{@bgcolor} acolor #{acolor} j:#{@justify} dlL: #{@display_length} "
2239
+ firstrow = r
2240
+ _height = @height || 1
2241
+ str = @justify.to_sym == :right ? "%*s" : "%-*s" # added 2008-12-22 19:05
2242
+ # loop added for labels that are wrapped.
2243
+ # TODO clear separately since value can change in status like labels
2244
+
2245
+ @graphic = @form.window if @graphic.nil? ## HACK messagebox givig this in repaint, 423 not working ??
2246
+ 0.upto(_height-1) { |i|
2247
+ @graphic.printstring r+i, c, " " * len , acolor,@attr
2248
+ }
2249
+ lablist.each_with_index do |_value, ix|
2250
+ break if ix >= _height
2251
+ if @justify.to_sym == :center
2252
+ padding = (@display_length - _value.length)/2
2253
+ _value = " "*padding + _value + " "*padding # so its cleared if we change it midway
2434
2254
  end
2435
- #@form.window.mvchgat(y=r, x=c, max=len, Ncurses::A_NORMAL, color, nil)
2436
- @repaint_required = false
2255
+ @graphic.printstring r, c, str % [len, _value], acolor,@attr
2256
+ r += 1
2257
+ end
2258
+ if !@mnemonic.nil?
2259
+ ulindex = value.index(@mnemonic) || value.index(@mnemonic.swapcase)
2260
+ @graphic.mvchgat(y=firstrow, x=c+ulindex, max=1, Ncurses::A_BOLD|Ncurses::A_UNDERLINE, acolor, nil)
2261
+ end
2262
+ #@form.window.mvchgat(y=r, x=c, max=len, Ncurses::A_NORMAL, color, nil)
2263
+ @repaint_required = false
2437
2264
  end
2438
2265
  # ADD HERE LABEL
2439
2266
  end
@@ -2452,12 +2279,13 @@ module RubyCurses
2452
2279
  @editable = false
2453
2280
  @handler={} # event handler
2454
2281
  @event_args ||= {}
2282
+ @_events ||= []
2283
+ @_events.push :PRESS
2455
2284
  super
2456
2285
  @bgcolor ||= $datacolor
2457
2286
  @color ||= $datacolor
2458
2287
  @surround_chars ||= ['[ ', ' ]']
2459
2288
  @col_offset = @surround_chars[0].length
2460
- @_events.push :PRESS
2461
2289
  end
2462
2290
  ##
2463
2291
  # set button based on Action
@@ -2483,6 +2311,7 @@ module RubyCurses
2483
2311
  @text = s
2484
2312
  end
2485
2313
  end
2314
+
2486
2315
  ##
2487
2316
  # FIXME this will not work in messageboxes since no form available
2488
2317
  # if already set mnemonic, then unbind_key, ??
@@ -2491,12 +2320,13 @@ module RubyCurses
2491
2320
  $log.error " #{self} COULD NOT SET MNEMONIC since form NIL" if @form.nil?
2492
2321
  return if @form.nil?
2493
2322
  @mnemonic = char
2494
- ch = char.downcase()[0].ord ## XXX 1.9
2323
+ ch = char.downcase()[0].ord ## 1.9
2495
2324
  # meta key
2496
2325
  mch = ?\M-a.getbyte(0) + (ch - ?a.getbyte(0))
2497
2326
  $log.debug " #{self} setting MNEMO to #{char} #{mch}"
2498
2327
  @form.bind_key(mch, self) { |_form, _butt| _butt.fire }
2499
2328
  end
2329
+
2500
2330
  ##
2501
2331
  # bind hotkey to form keys. added 2008-12-15 20:19
2502
2332
  # use ampersand in name or underline
@@ -2511,13 +2341,7 @@ module RubyCurses
2511
2341
  mch = ?\M-a.getbyte(0) + (ch - ?a.getbyte(0))
2512
2342
  @form.bind_key(mch, self) { |_form, _butt| _butt.fire }
2513
2343
  end
2514
- # 2009-01-17 01:48 removed so widgets can be called
2515
- # def on_enter
2516
- # $log.debug "ONENTER : #{@bgcolor} "
2517
- # end
2518
- # def on_leave
2519
- # $log.debug "ONLEAVE : #{@bgcolor} "
2520
- # end
2344
+
2521
2345
  def getvalue
2522
2346
  @text_variable.nil? ? @text : @text_variable.get_value(@name)
2523
2347
  end
@@ -2542,14 +2366,14 @@ module RubyCurses
2542
2366
  value = getvalue_for_paint
2543
2367
  #$log.debug("button repaint :#{self} r:#{r} c:#{c} col:#{color} bg #{bgcolor} v: #{value} ul #{@underline} mnem #{@mnemonic}")
2544
2368
  len = @display_length || value.length
2545
- @graphic = @form.window if @graphic.nil? ## cell editor listbox hack XXX fix in correct place
2369
+ @graphic = @form.window if @graphic.nil? ## cell editor listbox hack
2546
2370
  @graphic.printstring r, c, "%-*s" % [len, value], color, @attr
2547
2371
  # @form.window.mvchgat(y=r, x=c, max=len, Ncurses::A_NORMAL, bgcolor, nil)
2548
2372
  # in toggle buttons the underline can change as the text toggles
2549
2373
  if @underline || @mnemonic
2550
2374
  uline = @underline && (@underline + @text_offset) || value.index(@mnemonic) || value.index(@mnemonic.swapcase)
2551
2375
  #$log.debug " mvchgat UNDERLI r= #{r} - #{@graphic.top} c #{c} c+x #{c+uline}- #{@graphic.left} #{@graphic} "
2552
- #$log.debug " XXX HACK in next line related to UNDERLINES -graphic.top"
2376
+ #$log.debug " HACK in next line related to UNDERLINES -graphic.top"
2553
2377
  # if the char is not found don't print it
2554
2378
  if uline
2555
2379
  y=r #-@graphic.top
@@ -2563,6 +2387,7 @@ module RubyCurses
2563
2387
  end
2564
2388
  end
2565
2389
  end
2390
+
2566
2391
  ## command of button (invoked on press, hotkey, space)
2567
2392
  # added args 2008-12-20 19:22
2568
2393
  def command *args, &block
@@ -2573,9 +2398,10 @@ module RubyCurses
2573
2398
  def fire
2574
2399
  $log.debug "firing PRESS #{text}"
2575
2400
  # why the .... am i passing form ? Pass a ActionEvent with source, text() and getvalue()
2576
- #fire_handler :PRESS, @form XXX changed on 2010-09-12 19:22
2401
+ #fire_handler :PRESS, @form changed on 2010-09-12 19:22
2577
2402
  fire_handler :PRESS, ActionEvent.new(self, :PRESS, text)
2578
2403
  end
2404
+
2579
2405
  # Button
2580
2406
  def handle_key ch
2581
2407
  case ch
@@ -2590,9 +2416,21 @@ module RubyCurses
2590
2416
  fire
2591
2417
  end
2592
2418
  else
2419
+ if $key_map == :vim
2420
+ case ch
2421
+ when ?j.getbyte(0)
2422
+ @form.window.ungetch(KEY_DOWN)
2423
+ return 0
2424
+ when ?k.getbyte(0)
2425
+ @form.window.ungetch(KEY_UP)
2426
+ return 0
2427
+ end
2428
+
2429
+ end
2593
2430
  return :UNHANDLED
2594
2431
  end
2595
2432
  end
2433
+
2596
2434
  # temporary method, shoud be a proper class
2597
2435
  def self.button_layout buttons, row, startcol=0, cols=Ncurses.COLS-1, gap=5
2598
2436
  col = startcol
@@ -2676,6 +2514,10 @@ module RubyCurses
2676
2514
  @text_offset = @surround_chars[0].length
2677
2515
  @surround_chars[0] + buttontext + @surround_chars[1]
2678
2516
  end
2517
+
2518
+ # toggle button handle key
2519
+ # @param [int] key received
2520
+ #
2679
2521
  def handle_key ch
2680
2522
  if ch == 32
2681
2523
  toggle
@@ -2683,11 +2525,13 @@ module RubyCurses
2683
2525
  super
2684
2526
  end
2685
2527
  end
2528
+
2686
2529
  ##
2687
2530
  # toggle the button value
2688
2531
  def toggle
2689
2532
  fire
2690
2533
  end
2534
+
2691
2535
  # called on :PRESS event
2692
2536
  # caller should check state of itemevent passed to block
2693
2537
  def fire
@@ -2714,9 +2558,11 @@ module RubyCurses
2714
2558
  # call fire of button class 2008-12-09 17:49
2715
2559
  end
2716
2560
  end # class
2561
+
2717
2562
  ##
2718
2563
  # A checkbox, may be selected or unselected
2719
2564
  # TODO hotkey should work here too.
2565
+ #
2720
2566
  class CheckBox < ToggleButton
2721
2567
  dsl_accessor :align_right # the button will be on the right 2008-12-09 23:41
2722
2568
  # if a variable has been defined, off and on value will be set in it (default 0,1)
@@ -2745,10 +2591,12 @@ module RubyCurses
2745
2591
  end
2746
2592
  end
2747
2593
  end # class
2594
+
2748
2595
  ##
2749
2596
  # A selectable button that has a text value. It is based on a Variable that
2750
2597
  # is shared by other radio buttons. Only one is selected at a time, unlike checkbox
2751
2598
  # 2008-11-27 18:45 just made this inherited from Checkbox
2599
+
2752
2600
  class RadioButton < ToggleButton
2753
2601
  dsl_accessor :align_right # the button will be on the right 2008-12-09 23:41
2754
2602
  # if a variable has been defined, off and on value will be set in it (default 0,1)
@@ -2756,11 +2604,13 @@ module RubyCurses
2756
2604
  @surround_chars = ['(', ')'] if @surround_chars.nil?
2757
2605
  super
2758
2606
  end
2607
+
2759
2608
  # all radio buttons will return the value of the selected value, not the offered value
2760
2609
  def getvalue
2761
2610
  #@text_variable.value
2762
2611
  @variable.get_value @name
2763
2612
  end
2613
+
2764
2614
  def getvalue_for_paint
2765
2615
  buttontext = getvalue() == @value ? "o" : " "
2766
2616
  dtext = @display_length.nil? ? text : "%-*s" % [@display_length, text]
@@ -2775,16 +2625,19 @@ module RubyCurses
2775
2625
  return pretext + " #{dtext}"
2776
2626
  end
2777
2627
  end
2628
+
2778
2629
  def toggle
2779
2630
  @variable.set_value @value, @name
2780
2631
  # call fire of button class 2008-12-09 17:49
2781
2632
  fire
2782
2633
  end
2634
+
2783
2635
  # added for bindkeys since that calls fire, not toggle - XXX i don't like this
2784
2636
  def fire
2785
2637
  @variable.set_value @value,@name
2786
2638
  super
2787
2639
  end
2640
+
2788
2641
  ##
2789
2642
  # ideally this should not be used. But implemented for completeness.
2790
2643
  # it is recommended to toggle some other radio button than to uncheck this.