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.
- data/CHANGELOG +33 -0
- data/README.markdown +7 -1
- data/TODO2.txt +21 -15
- data/VERSION +1 -1
- data/examples/abasiclist.rb +2 -2
- data/examples/alpmenu.rb +1 -1
- data/examples/app.rb +0 -1
- data/examples/appdirtree.rb +4 -2
- data/examples/appemail.rb +7 -3
- data/examples/appemaillb.rb +1 -1
- data/examples/appgcompose.rb +2 -2
- data/examples/appgmail.rb +1 -1
- data/examples/appmethods.rb +20 -2
- data/examples/atree.rb +9 -1
- data/examples/dbdemo.rb +460 -0
- data/examples/dirtree.rb +1 -1
- data/examples/menu1.rb +37 -5
- data/examples/multispl.rb +1 -1
- data/examples/rfe.rb +9 -2
- data/examples/splitp.rb +1 -1
- data/examples/sqlc.rb +6 -10
- data/examples/sqlm.rb +2 -20
- data/examples/sqlt.rb +408 -0
- data/examples/term2.rb +1 -1
- data/examples/test2.rb +169 -97
- data/examples/testapp.rb +1 -1
- data/examples/testapp2.rb +1 -1
- data/examples/testkeypress.rb +4 -2
- data/examples/testtable.rb +6 -0
- data/examples/testtpane.rb +35 -23
- data/examples/testvimsplit.rb +3 -2
- data/lib/rbcurse.rb +1 -1
- data/lib/rbcurse/action.rb +8 -0
- data/lib/rbcurse/app.rb +39 -23
- data/lib/rbcurse/extras/bottomline.rb +101 -13
- data/lib/rbcurse/extras/directorylist.rb +14 -5
- data/lib/rbcurse/extras/divider.rb +1 -1
- data/lib/rbcurse/extras/listselectable.rb +42 -8
- data/lib/rbcurse/extras/masterdetail.rb +2 -2
- data/lib/rbcurse/extras/scrollbar.rb +11 -2
- data/lib/rbcurse/extras/statusline.rb +56 -0
- data/lib/rbcurse/extras/stdscrwindow.rb +11 -0
- data/lib/rbcurse/extras/tabular.rb +2 -1
- data/lib/rbcurse/extras/tabularwidget.rb +60 -17
- data/lib/rbcurse/extras/viewer.rb +16 -4
- data/lib/rbcurse/keylabelprinter.rb +34 -4
- data/lib/rbcurse/listeditable.rb +5 -1
- data/lib/rbcurse/listkeys.rb +1 -1
- data/lib/rbcurse/listscrollable.rb +15 -8
- data/lib/rbcurse/rbasiclistbox.rb +44 -23
- data/lib/rbcurse/rcommandwindow.rb +8 -14
- data/lib/rbcurse/rdialogs.rb +187 -2
- data/lib/rbcurse/rlistbox.rb +38 -19
- data/lib/rbcurse/rmenu.rb +313 -93
- data/lib/rbcurse/rmessagebox.rb +3 -2
- data/lib/rbcurse/rmulticontainer.rb +5 -3
- data/lib/rbcurse/rmultisplit.rb +2 -11
- data/lib/rbcurse/rmultitextview.rb +4 -5
- data/lib/rbcurse/rtabbedpane.rb +223 -69
- data/lib/rbcurse/rtable.rb +6 -10
- data/lib/rbcurse/rtextarea.rb +57 -36
- data/lib/rbcurse/rtextview.rb +12 -15
- data/lib/rbcurse/rtree.rb +79 -22
- data/lib/rbcurse/rvimsplit.rb +16 -25
- data/lib/rbcurse/rwidget.rb +376 -523
- data/lib/rbcurse/tree/treecellrenderer.rb +24 -11
- data/lib/rbcurse/tree/treemodel.rb +1 -1
- data/lib/ver/window.rb +130 -66
- metadata +5 -3
- data/examples/term.rb +0 -48
data/lib/rbcurse/rvimsplit.rb
CHANGED
@@ -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.
|
213
|
+
if source.next_component && source.next_component.row > 1 && source.parent.height > 1
|
216
214
|
source.parent.height -= 1
|
217
|
-
source.
|
218
|
-
source.
|
215
|
+
source.next_component.height +=1
|
216
|
+
source.next_component.row -= 1
|
219
217
|
source.parent.repaint_required
|
220
|
-
source.
|
218
|
+
source.next_component.repaint_required
|
221
219
|
source.parent.repaint
|
222
|
-
source.
|
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.
|
224
|
+
if source.next_component && source.next_component.height > 1
|
227
225
|
source.parent.height += 1
|
228
|
-
source.
|
229
|
-
source.
|
226
|
+
source.next_component.height -=1
|
227
|
+
source.next_component.row += 1
|
230
228
|
source.parent.repaint_required
|
231
|
-
source.
|
229
|
+
source.next_component.repaint_required
|
232
230
|
source.parent.repaint
|
233
|
-
source.
|
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
|
data/lib/rbcurse/rwidget.rb
CHANGED
@@ -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
|
-
|
14
|
-
|
15
|
-
-
|
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
|
-
|
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
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
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
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
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
|
-
|
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
|
-
|
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 "
|
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 "
|
313
|
+
$log.debug " assigning #{keycode} , A0 #{a0} , A1 #{a1} " if $log.debug?
|
272
314
|
@key_handler[a0][a1] = blk
|
273
|
-
#$log.debug "
|
315
|
+
#$log.debug " XX assigning #{keycode} to key_handler " if $log.debug?
|
274
316
|
else
|
275
|
-
#$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
|
-
|
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
|
-
|
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
|
-
|
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.
|
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
|
-
#
|
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
|
-
|
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
|
-
|
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.
|
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
|
-
#
|
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
|
802
|
+
#$log.debug " inside width() #{val}"
|
905
803
|
if val.empty?
|
906
804
|
return @width
|
907
805
|
else
|
908
|
-
#$log.debug " inside
|
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
|
-
|
920
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
1123
|
-
|
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
|
-
|
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
|
-
|
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
|
-
@
|
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
|
-
|
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 ||=
|
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
|
-
###
|
1088
|
+
### @window.wrefresh
|
1249
1089
|
if @window.window_type == :WINDOW
|
1250
|
-
|
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 "
|
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
|
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 ?
|
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 "
|
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
|
-
|
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 "
|
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
|
-
|
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 "
|
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
|
-
|
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
|
-
|
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
|
-
|
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 "
|
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
|
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
|
1812
|
-
dsl_accessor :display_length
|
1813
|
-
|
1814
|
-
|
1815
|
-
dsl_accessor :show
|
1816
|
-
dsl_accessor :null_allowed
|
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
|
1823
|
-
attr_reader :type
|
1824
|
-
#attr_reader :curpos
|
1825
|
-
attr_accessor :datatype
|
1826
|
-
attr_reader :original_value
|
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
|
-
|
1682
|
+
@_events ||= []
|
1857
1683
|
@_events.push(:CHANGE)
|
1684
|
+
super
|
1858
1685
|
end
|
1859
1686
|
def init_vars
|
1860
|
-
@pcol = 0
|
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?
|
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
|
-
#
|
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
|
-
|
1978
|
-
|
1979
|
-
|
1980
|
-
|
1981
|
-
|
1982
|
-
|
1983
|
-
|
1984
|
-
|
1985
|
-
|
1986
|
-
|
1987
|
-
|
1988
|
-
|
1989
|
-
|
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
|
-
|
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
|
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
|
-
#
|
1885
|
+
#
|
2042
1886
|
def handle_key ch
|
2043
|
-
@repaint_required = true
|
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
|
-
|
2079
|
-
|
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
|
-
|
2103
|
-
|
2104
|
-
|
2105
|
-
|
2106
|
-
|
2107
|
-
|
2108
|
-
|
2109
|
-
|
2110
|
-
|
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
|
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
|
-
|
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
|
-
|
2395
|
-
|
2396
|
-
|
2397
|
-
|
2398
|
-
|
2399
|
-
|
2400
|
-
|
2401
|
-
|
2402
|
-
|
2403
|
-
|
2404
|
-
|
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
|
-
|
2432
|
-
|
2433
|
-
|
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
|
-
|
2436
|
-
|
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 ##
|
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
|
-
|
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
|
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 "
|
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
|
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.
|