ncumbra 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +25 -0
- data/Gemfile +6 -0
- data/LICENSE +21 -0
- data/README.md +48 -0
- data/README.md.bak +15 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/ex1.rb +85 -0
- data/examples/ex2.rb +128 -0
- data/examples/ex21.rb +136 -0
- data/examples/ex3.rb +163 -0
- data/examples/ex4.rb +142 -0
- data/examples/ex5.rb +103 -0
- data/examples/exbox.rb +141 -0
- data/examples/exm1.rb +137 -0
- data/examples/keys.rb +67 -0
- data/examples/tt.rb +462 -0
- data/lib/umbra/box.rb +137 -0
- data/lib/umbra/button.rb +130 -0
- data/lib/umbra/buttongroup.rb +96 -0
- data/lib/umbra/checkbox.rb +42 -0
- data/lib/umbra/dialog.rb +214 -0
- data/lib/umbra/eventhandler.rb +134 -0
- data/lib/umbra/field.rb +503 -0
- data/lib/umbra/form.rb +473 -0
- data/lib/umbra/keymappinghandler.rb +96 -0
- data/lib/umbra/label.rb +95 -0
- data/lib/umbra/labeledfield.rb +97 -0
- data/lib/umbra/listbox.rb +384 -0
- data/lib/umbra/menu.rb +93 -0
- data/lib/umbra/messagebox.rb +348 -0
- data/lib/umbra/pad.rb +340 -0
- data/lib/umbra/radiobutton.rb +71 -0
- data/lib/umbra/textbox.rb +417 -0
- data/lib/umbra/togglebutton.rb +140 -0
- data/lib/umbra/version.rb +3 -0
- data/lib/umbra/widget.rb +220 -0
- data/lib/umbra/window.rb +270 -0
- data/lib/umbra.rb +47 -0
- data/umbra.gemspec +27 -0
- metadata +127 -0
data/lib/umbra/field.rb
ADDED
@@ -0,0 +1,503 @@
|
|
1
|
+
# ----------------------------------------------------------------------------- #
|
2
|
+
# File: field.rb
|
3
|
+
# Description: text input field or widget
|
4
|
+
# Author: j kepler http://github.com/mare-imbrium/canis/
|
5
|
+
# Date: 2018-03
|
6
|
+
# License: MIT
|
7
|
+
# Last update: 2018-04-14 08:55
|
8
|
+
# ----------------------------------------------------------------------------- #
|
9
|
+
# field.rb Copyright (C) 2012-2018 j kepler
|
10
|
+
#
|
11
|
+
|
12
|
+
class InputDataEvent # {{{
|
13
|
+
attr_accessor :index0, :index1, :source, :type, :row, :text
|
14
|
+
def initialize index0, index1, source, type, row, text
|
15
|
+
@index0 = index0
|
16
|
+
@index1 = index1
|
17
|
+
@source = source
|
18
|
+
@type = type
|
19
|
+
@row = row
|
20
|
+
@text = text
|
21
|
+
end
|
22
|
+
# until now to_s was returning inspect, but to make it easy for users let us return the value
|
23
|
+
# they most expect which is the text that was changed
|
24
|
+
def to_s
|
25
|
+
inspect
|
26
|
+
end
|
27
|
+
def inspect
|
28
|
+
## now that textarea.to_s prints content we shouldn pass it here.
|
29
|
+
#"#{@type.to_s}, #{@source}, ind0:#{@index0}, ind1:#{@index1}, row:#{@row}, text:#{@text}"
|
30
|
+
"#{@type.to_s}, ind0:#{@index0}, ind1:#{@index1}, row:#{@row}, text:#{@text}"
|
31
|
+
end
|
32
|
+
# this is so that earlier applications were getting source in the block, not an event. they
|
33
|
+
# were doing a fld.getvalue, so we must keep those apps running
|
34
|
+
# @since 1.2.0 added 2010-09-11 12:25
|
35
|
+
def getvalue
|
36
|
+
@source.getvalue
|
37
|
+
end
|
38
|
+
end # }}}
|
39
|
+
# Text edit field
|
40
|
+
# TODO :
|
41
|
+
# ? remove datatype, just use strings.
|
42
|
+
# NOTE: +width+ is the length of the display whereas +maxlen+ is the maximum size that the value
|
43
|
+
# can take. Thus, +maxlen+ can exceed +width+. Currently, +maxlen+ defaults to +width+ which
|
44
|
+
# defaults to 20.
|
45
|
+
# NOTE: Use +text=(val)+ to set value of field, and +text()+ to retrieve value.
|
46
|
+
# == Example
|
47
|
+
# f = Field.new text: "Some value", row: 10, col: 2
|
48
|
+
#
|
49
|
+
# Field introduces an event :CHANGE which is fired for each character deleted or inserted
|
50
|
+
#
|
51
|
+
module Umbra
|
52
|
+
class Field < Widget
|
53
|
+
attr_accessor :maxlen # maximum length allowed into field
|
54
|
+
attr_reader :buffer # actual buffer being used for storage
|
55
|
+
|
56
|
+
|
57
|
+
attr_accessor :values # validate against provided list, (+include?+)
|
58
|
+
attr_accessor :valid_regex # validate against regular expression (+match()+)
|
59
|
+
attr_accessor :valid_range # validate against numeric range, should respond to +include?+
|
60
|
+
# for numeric fields, specify lower or upper limit of entered value
|
61
|
+
attr_accessor :below, :above
|
62
|
+
|
63
|
+
# aliased to type
|
64
|
+
#attr_accessor :chars_allowed # regex, what characters to allow entry, will ignore all else
|
65
|
+
# character to show, earlier called +show+ which clashed with Widget method +show+
|
66
|
+
attr_accessor :mask # what charactr to show for each char entered (password field)
|
67
|
+
attr_accessor :null_allowed # allow nulls, don't validate if null # added , boolean
|
68
|
+
|
69
|
+
# any new widget that has +editable+ should have +modified+ also
|
70
|
+
attr_accessor :editable # allow editing
|
71
|
+
|
72
|
+
# +type+ is just a convenience over +chars_allowed+ and sets some basic filters
|
73
|
+
# @example: :integer, :float, :alpha, :alnum
|
74
|
+
# NOTE: we do not store type, only chars_allowed, so this won't return any value
|
75
|
+
#attr_reader :type # datatype of field, currently only sets chars_allowed
|
76
|
+
|
77
|
+
# this accesses the field created or passed with set_label
|
78
|
+
#attr_reader :label
|
79
|
+
# this is the class of the field set in +text()+, so value is returned in same class
|
80
|
+
# @example : Integer, Integer, Float
|
81
|
+
attr_accessor :datatype # currently set during set_buffer
|
82
|
+
attr_reader :original_value # value on entering field
|
83
|
+
attr_accessor :overwrite_mode # true or false INSERT OVERWRITE MODE
|
84
|
+
|
85
|
+
# column on which field printed, usually the same as +col+ unless +label+ used.
|
86
|
+
# Required by +History+ to popup field history.
|
87
|
+
attr_reader :field_col # column on which field is printed
|
88
|
+
# required due to labels. Is updated after printing
|
89
|
+
# # so can be nil if accessed early 2011-12-8
|
90
|
+
|
91
|
+
def initialize config={}, &block
|
92
|
+
@buffer = String.new
|
93
|
+
@row = 0
|
94
|
+
@col = 0
|
95
|
+
@editable = true
|
96
|
+
@focusable = true
|
97
|
+
|
98
|
+
map_keys
|
99
|
+
init_vars
|
100
|
+
register_events(:CHANGE)
|
101
|
+
super
|
102
|
+
@width ||= 20
|
103
|
+
@maxlen ||= @width
|
104
|
+
end
|
105
|
+
def init_vars
|
106
|
+
@pcol = 0 # needed for horiz scrolling
|
107
|
+
@curpos = 0 # current cursor position in buffer (NOT screen/window/field)
|
108
|
+
# this is the index where characters are put or deleted
|
109
|
+
# # when user edits
|
110
|
+
@modified = false
|
111
|
+
end
|
112
|
+
|
113
|
+
# NOTE: earlier there was some confusion over type, chars_allowed and datatype
|
114
|
+
# Now type and chars_allowed are merged into one.
|
115
|
+
# If you pass a symbol such as :integer, :float or Float Integer then some
|
116
|
+
# standard chars_allowed will be used. Otherwise you may pass a regexp.
|
117
|
+
#
|
118
|
+
# @param [symbol] :integer, :float, :alpha, :alnum, Float, Integer, Numeric, Regexp
|
119
|
+
def type=(val)
|
120
|
+
|
121
|
+
dtype = val
|
122
|
+
#return self if @chars_allowed # disallow changing
|
123
|
+
# send in a regexp, we just save it.
|
124
|
+
if dtype.is_a? Regexp
|
125
|
+
@chars_allowed = dtype
|
126
|
+
return self
|
127
|
+
end
|
128
|
+
dtype = dtype.to_s.downcase.to_sym if dtype.is_a? String
|
129
|
+
case dtype # missing to_sym would have always failed due to to_s 2011-09-30 1.3.1
|
130
|
+
when :integer, Integer
|
131
|
+
@chars_allowed = /\d/
|
132
|
+
when :numeric, :float, Numeric, Float
|
133
|
+
@chars_allowed = /[\d\.]/
|
134
|
+
when :alpha
|
135
|
+
@chars_allowed = /[a-zA-Z]/
|
136
|
+
when :alnum
|
137
|
+
@chars_allowed = /[a-zA-Z0-9]/
|
138
|
+
else
|
139
|
+
raise ArgumentError, "Field type: invalid datatype specified. Use :integer, :numeric, :float, :alpha, :alnum "
|
140
|
+
end
|
141
|
+
self
|
142
|
+
end
|
143
|
+
alias :chars_allowed= :type=
|
144
|
+
|
145
|
+
#
|
146
|
+
# add a char to field, and validate
|
147
|
+
# if disabled or exceeding size
|
148
|
+
# @param [char] a character to add
|
149
|
+
# @return [Integer] 0 if okay, -1 if not editable or exceeding length
|
150
|
+
def putch char
|
151
|
+
return -1 if !@editable
|
152
|
+
return -1 if !@overwrite_mode && (@buffer.length >= @maxlen)
|
153
|
+
blen = @buffer.length
|
154
|
+
if @chars_allowed != nil
|
155
|
+
return if char.match(@chars_allowed).nil?
|
156
|
+
end
|
157
|
+
# added insert or overwrite mode 2010-03-17 20:11
|
158
|
+
oldchar = nil
|
159
|
+
if @overwrite_mode
|
160
|
+
oldchar = @buffer[@curpos]
|
161
|
+
@buffer[@curpos] = char
|
162
|
+
else
|
163
|
+
@buffer.insert(@curpos, char)
|
164
|
+
end
|
165
|
+
oldcurpos = @curpos
|
166
|
+
#$log.warn "XXX: FIELD CURPOS #{@curpos} blen #{@buffer.length} " #if @curpos > blen
|
167
|
+
@curpos += 1 if @curpos < @maxlen
|
168
|
+
@modified = true
|
169
|
+
#$log.debug " FIELD FIRING CHANGE: #{char} at new #{@curpos}: bl:#{@buffer.length} buff:[#{@buffer}]"
|
170
|
+
if @overwrite_mode
|
171
|
+
fire_handler :CHANGE, InputDataEvent.new(oldcurpos,@curpos, self, :DELETE, 0, oldchar) # 2010-09-11 12:43
|
172
|
+
end
|
173
|
+
fire_handler :CHANGE, InputDataEvent.new(oldcurpos,@curpos, self, :INSERT, 0, char) # 2010-09-11 12:43
|
174
|
+
0
|
175
|
+
end
|
176
|
+
|
177
|
+
##
|
178
|
+
# add character to field, adjust scrolling.
|
179
|
+
# NOTE: handlekey only calls this if between 32 and 126.
|
180
|
+
def putc c
|
181
|
+
if c >= 0 and c <= 127
|
182
|
+
ret = putch c.chr
|
183
|
+
if ret == 0
|
184
|
+
# character is valid
|
185
|
+
if addcol(1) == -1 # if can't go forward, try scrolling
|
186
|
+
# scroll if exceeding display len but less than max len
|
187
|
+
if @curpos > @width && @curpos <= @maxlen
|
188
|
+
@pcol += 1 if @pcol < @width
|
189
|
+
end
|
190
|
+
end
|
191
|
+
@modified = true
|
192
|
+
return 0
|
193
|
+
end
|
194
|
+
end
|
195
|
+
return -1
|
196
|
+
end
|
197
|
+
# delete a character from the buffer at given position
|
198
|
+
# Called by +delete_curr_char+ and +delete_prev_char+.
|
199
|
+
def delete_at index=@curpos
|
200
|
+
return -1 if !@editable
|
201
|
+
char = @buffer.slice!(index,1)
|
202
|
+
#$log.debug " delete at #{index}: #{@buffer.length}: #{@buffer}"
|
203
|
+
@modified = true
|
204
|
+
fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos, self, :DELETE, 0, char) # 2010-09-11 13:01
|
205
|
+
end
|
206
|
+
#
|
207
|
+
# silently restores earlier value without firing handlers, use if exception and you want old value
|
208
|
+
# Called when pressing <ESC> or <c-g>.
|
209
|
+
def restore_original_value
|
210
|
+
@buffer = @original_value.dup
|
211
|
+
# earlier commented but trying again, since i am getting IndexError in insert 2188
|
212
|
+
# Added next 3 lines to fix issue, now it comes back to beginning.
|
213
|
+
cursor_home
|
214
|
+
|
215
|
+
@repaint_required = true
|
216
|
+
end
|
217
|
+
##
|
218
|
+
# set value of Field
|
219
|
+
# fires CHANGE handler
|
220
|
+
# Please don't use this directly, use +text+
|
221
|
+
# This name is from ncurses field, added underscore to emphasize not to use
|
222
|
+
private def _set_buffer value #:nodoc:
|
223
|
+
@repaint_required = true
|
224
|
+
@datatype = value.class
|
225
|
+
@delete_buffer = @buffer.dup
|
226
|
+
@buffer = value.to_s.dup
|
227
|
+
# don't allow setting of value greater than maxlen
|
228
|
+
@buffer = @buffer[0,@maxlen] if @maxlen && @buffer.length > @maxlen
|
229
|
+
@curpos = 0
|
230
|
+
# hope @delete_buffer is not overwritten
|
231
|
+
fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos, self, :DELETE, 0, @delete_buffer) # 2010-09-11 13:01
|
232
|
+
fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos, self, :INSERT, 0, @buffer) # 2010-09-11 13:01
|
233
|
+
self # 2011-10-2
|
234
|
+
end
|
235
|
+
## add a column to cursor position. Field
|
236
|
+
private def addcol num
|
237
|
+
x = @col_offset + num
|
238
|
+
return -1 if x < 0
|
239
|
+
return -1 if x > @width
|
240
|
+
@col_offset += num
|
241
|
+
end
|
242
|
+
|
243
|
+
# converts back into original type
|
244
|
+
# changed to convert on 2009-01-06 23:39
|
245
|
+
# 2018-04-13 - Changed from private to public since I got an error on on_leave
|
246
|
+
# when this was called from LabeledField.
|
247
|
+
def getvalue
|
248
|
+
dt = @datatype || String
|
249
|
+
case dt.to_s
|
250
|
+
when "String"
|
251
|
+
return @buffer
|
252
|
+
when "Integer"
|
253
|
+
return @buffer.to_i
|
254
|
+
when "Float"
|
255
|
+
return @buffer.to_f
|
256
|
+
else
|
257
|
+
return @buffer.to_s
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
|
262
|
+
public
|
263
|
+
## Note that some older widgets like Field repaint every time the form.repaint
|
264
|
+
##+ is called, whether updated or not. I can't remember why this is, but
|
265
|
+
##+ currently I've not implemented events with these widgets. 2010-01-03 15:00
|
266
|
+
|
267
|
+
def repaint
|
268
|
+
return unless @repaint_required # 2010-11-20 13:13 its writing over a window i think TESTING
|
269
|
+
$log.debug("repaint FIELD: #{name}, r:#{row} c:#{col},wid:#{width},pcol:#{@pcol}, #{focusable} st: #{@state} ")
|
270
|
+
@width = 1 if width == 0
|
271
|
+
printval = getvalue_for_paint().to_s # added 2009-01-06 23:27
|
272
|
+
printval = mask()*printval.length unless @mask.nil?
|
273
|
+
if !printval.nil?
|
274
|
+
if printval.length > width # only show maxlen
|
275
|
+
printval = printval[@pcol..@pcol+width-1]
|
276
|
+
else
|
277
|
+
printval = printval[@pcol..-1]
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
acolor = @color_pair || CP_WHITE
|
282
|
+
if @state == :HIGHLIGHTED
|
283
|
+
acolor = @highlight_color_pair || CP_RED
|
284
|
+
end
|
285
|
+
#$log.debug " Field g:#{@graphic}. r,c,displen:#{@row}, #{@col}, #{@width} c:#{@color} bg:#{@bgcolor} a:#{@attr} :#{@name} "
|
286
|
+
r = row
|
287
|
+
c = col
|
288
|
+
@graphic.printstring r, c, sprintf("%-*s", width, printval), acolor, attr()
|
289
|
+
@field_col = c
|
290
|
+
@repaint_required = false
|
291
|
+
end
|
292
|
+
|
293
|
+
def map_keys
|
294
|
+
return if @keys_mapped
|
295
|
+
bind_key(FFI::NCurses::KEY_LEFT, :cursor_backward )
|
296
|
+
bind_key(FFI::NCurses::KEY_RIGHT, :cursor_forward )
|
297
|
+
bind_key(FFI::NCurses::KEY_BACKSPACE, :delete_prev_char )
|
298
|
+
bind_key(127, :delete_prev_char )
|
299
|
+
bind_key(330, :delete_curr_char )
|
300
|
+
bind_key(?\C-a, :cursor_home )
|
301
|
+
bind_key(?\C-e, :cursor_end )
|
302
|
+
bind_key(?\C-k, :delete_eol )
|
303
|
+
bind_key(?\C-_, :undo_delete_eol )
|
304
|
+
#bind_key(27){ text @original_value }
|
305
|
+
bind_key(?\C-g, 'revert'){ restore_original_value }
|
306
|
+
@keys_mapped = true
|
307
|
+
end
|
308
|
+
|
309
|
+
# field - handle a key sent for form
|
310
|
+
#
|
311
|
+
def handle_key ch
|
312
|
+
$log.debug "inside handle key of field with #{ch}"
|
313
|
+
@repaint_required = true
|
314
|
+
case ch
|
315
|
+
when 32..126
|
316
|
+
putc ch
|
317
|
+
when 27 # cannot bind it, so hardcoding it here
|
318
|
+
restore_original_value
|
319
|
+
else
|
320
|
+
ret = super
|
321
|
+
return ret
|
322
|
+
end
|
323
|
+
0 # 2008-12-16 23:05 without this -1 was going back so no repaint
|
324
|
+
end
|
325
|
+
# does an undo on delete_eol, not a real undo
|
326
|
+
def undo_delete_eol
|
327
|
+
return if @delete_buffer.nil?
|
328
|
+
#oldvalue = @buffer
|
329
|
+
@buffer.insert @curpos, @delete_buffer
|
330
|
+
fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos+@delete_buffer.length, self, :INSERT, 0, @delete_buffer) # 2010-09-11 13:01
|
331
|
+
end
|
332
|
+
##
|
333
|
+
# position cursor at start of field
|
334
|
+
def cursor_home
|
335
|
+
@curpos = 0
|
336
|
+
@pcol = 0
|
337
|
+
set_col_offset 0
|
338
|
+
end
|
339
|
+
##
|
340
|
+
# goto end of field, "end" is a keyword so could not use it.
|
341
|
+
def cursor_end
|
342
|
+
blen = @buffer.rstrip.length
|
343
|
+
if blen < @width
|
344
|
+
set_col_offset blen
|
345
|
+
else
|
346
|
+
@pcol = blen-@width
|
347
|
+
#set_form_col @width-1
|
348
|
+
set_col_offset blen
|
349
|
+
end
|
350
|
+
@curpos = blen # this is position in array where editing or motion is to happen regardless of what you see
|
351
|
+
# regardless of pcol (panning)
|
352
|
+
end
|
353
|
+
# sets the visual cursor on the window at correct place
|
354
|
+
# NOTE be careful of curpos - pcol being less than 0
|
355
|
+
private def set_col_offset x=@curpos
|
356
|
+
@curpos = x || 0 # NOTE we set the index of cursor here
|
357
|
+
#return -1 if x < 0
|
358
|
+
#return -1 if x > @width
|
359
|
+
if x > @width
|
360
|
+
x = @width
|
361
|
+
end
|
362
|
+
@col_offset = x
|
363
|
+
return
|
364
|
+
=begin
|
365
|
+
c = @col + @col_offset + @curpos - @pcol
|
366
|
+
min = @col + @col_offset
|
367
|
+
max = min + @width
|
368
|
+
c = min if c < min
|
369
|
+
c = max if c > max
|
370
|
+
#$log.debug " #{@name} FIELD set_form_col #{c}, curpos #{@curpos} , #{@col} + #{@col_offset} pcol:#{@pcol} "
|
371
|
+
#setrowcol nil, c # this does not exist since it called form
|
372
|
+
=end
|
373
|
+
end
|
374
|
+
def delete_eol
|
375
|
+
return -1 unless @editable
|
376
|
+
pos = @curpos-1
|
377
|
+
@delete_buffer = @buffer[@curpos..-1]
|
378
|
+
# if pos is 0, pos-1 becomes -1, end of line!
|
379
|
+
@buffer = pos == -1 ? "" : @buffer[0..pos]
|
380
|
+
fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos+@delete_buffer.length, self, :DELETE, 0, @delete_buffer)
|
381
|
+
return @delete_buffer
|
382
|
+
end
|
383
|
+
# move cursor forward one character, called with KEY_RIGHT action.
|
384
|
+
def cursor_forward
|
385
|
+
if @curpos < @buffer.length
|
386
|
+
if addcol(1)==-1 # go forward if you can, else scroll
|
387
|
+
@pcol += 1 if @pcol < @width
|
388
|
+
end
|
389
|
+
@curpos += 1
|
390
|
+
end
|
391
|
+
# $log.debug " crusor FORWARD cp:#{@curpos} pcol:#{@pcol} b.l:#{@buffer.length} d_l:#{@display_length} fc:#{@form.col}"
|
392
|
+
end
|
393
|
+
# move cursor back one character, called with KEY_LEFT action.
|
394
|
+
def cursor_backward
|
395
|
+
if @curpos > 0
|
396
|
+
@curpos -= 1
|
397
|
+
#if @pcol > 0 #and @form.col == @col + @col_offset
|
398
|
+
#@pcol -= 1
|
399
|
+
#end
|
400
|
+
addcol -1
|
401
|
+
elsif @pcol > 0
|
402
|
+
# pan left only when cursor pos is 0
|
403
|
+
@pcol -= 1
|
404
|
+
end
|
405
|
+
# $log.debug " crusor back cp:#{@curpos} pcol:#{@pcol} b.l:#{@buffer.length} d_l:#{@display_length} fc:#{@form.col}"
|
406
|
+
=begin
|
407
|
+
# this is perfect if not scrolling, but now needs changes
|
408
|
+
if @curpos > 0
|
409
|
+
@curpos -= 1
|
410
|
+
addcol -1
|
411
|
+
end
|
412
|
+
=end
|
413
|
+
end
|
414
|
+
def delete_curr_char
|
415
|
+
return -1 unless @editable
|
416
|
+
delete_at
|
417
|
+
@modified = true
|
418
|
+
end
|
419
|
+
# called when user presses backspace.
|
420
|
+
# Delete character on left of cursor
|
421
|
+
def delete_prev_char
|
422
|
+
return -1 if !@editable
|
423
|
+
return if @curpos <= 0
|
424
|
+
# if we've panned, then unpan, and don't move cursor back
|
425
|
+
# Otherwise, adjust cursor (move cursor back as we delete)
|
426
|
+
adjust = true
|
427
|
+
if @pcol > 0
|
428
|
+
@pcol -= 1
|
429
|
+
adjust = false
|
430
|
+
end
|
431
|
+
@curpos -= 1 if @curpos > 0
|
432
|
+
delete_at
|
433
|
+
addcol -1 if adjust # move visual cursor back
|
434
|
+
@modified = true
|
435
|
+
end
|
436
|
+
# upon leaving a field
|
437
|
+
# returns false if value not valid as per values or valid_regex
|
438
|
+
# 2008-12-22 12:40 if null_allowed, don't validate, but do fire_handlers
|
439
|
+
def on_leave
|
440
|
+
val = getvalue
|
441
|
+
#$log.debug " FIELD ON LEAVE:#{val}. #{@values.inspect}"
|
442
|
+
valid = true
|
443
|
+
if val.to_s.empty? && @null_allowed
|
444
|
+
#$log.debug " empty and null allowed"
|
445
|
+
else
|
446
|
+
if !@values.nil?
|
447
|
+
valid = @values.include? val
|
448
|
+
raise FieldValidationException, "Field value (#{val}) not in values: #{@values.join(',')}" unless valid
|
449
|
+
end
|
450
|
+
if !@valid_regex.nil?
|
451
|
+
valid = @valid_regex.match(val.to_s)
|
452
|
+
raise FieldValidationException, "Field not matching regex #{@valid_regex}" unless valid
|
453
|
+
end
|
454
|
+
# added valid_range for numerics 2011-09-29
|
455
|
+
if !in_range?(val)
|
456
|
+
raise FieldValidationException, "Field not matching range #{@valid_range}, above #{@above} or below #{@below} "
|
457
|
+
end
|
458
|
+
end
|
459
|
+
# here is where we should set the forms modified to true - 2009-01
|
460
|
+
if modified?
|
461
|
+
@modified = true
|
462
|
+
end
|
463
|
+
# if super fails we would have still set modified to true
|
464
|
+
super
|
465
|
+
#return valid
|
466
|
+
end
|
467
|
+
|
468
|
+
# checks field against +valid_range+, +above+ and +below+ , returning +true+ if it passes
|
469
|
+
# set attributes, +false+ if it fails any one.
|
470
|
+
def in_range?( val )
|
471
|
+
val = val.to_i
|
472
|
+
(@above.nil? or val > @above) and
|
473
|
+
(@below.nil? or val < @below) and
|
474
|
+
(@valid_range.nil? or @valid_range.include?(val))
|
475
|
+
end
|
476
|
+
## save original value on enter, so we can check for modified.
|
477
|
+
# 2009-01-18 12:25
|
478
|
+
# 2011-10-9 I have changed to take @buffer since getvalue returns a datatype
|
479
|
+
# and this causes a crash in set_original on cursor forward.
|
480
|
+
def on_enter
|
481
|
+
#@original_value = getvalue.dup rescue getvalue
|
482
|
+
@original_value = @buffer.dup # getvalue.dup rescue getvalue
|
483
|
+
super
|
484
|
+
end
|
485
|
+
##
|
486
|
+
# overriding widget, check for value change
|
487
|
+
def modified?
|
488
|
+
getvalue() != @original_value
|
489
|
+
end
|
490
|
+
# 2018-03-22 - replaced the old style text(val) with attr style
|
491
|
+
def text
|
492
|
+
getvalue
|
493
|
+
end
|
494
|
+
def text=(val)
|
495
|
+
return unless val # added 2010-11-17 20:11, dup will fail on nil
|
496
|
+
# will bomb on integer or float etc !!
|
497
|
+
#_set_buffer(val.dup)
|
498
|
+
_set_buffer(val)
|
499
|
+
end
|
500
|
+
alias :default= :text=
|
501
|
+
# ADD HERE FIELD
|
502
|
+
end # }}}
|
503
|
+
end # module
|