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
@@ -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.