class Canis::Field
Text edit field NOTE: width
is the length of the display whereas maxlen
is the maximum size that the value can take. Thus, maxlen
can exceed width
. Currently, maxlen
defaults to width
which defaults to 20. NOTE: Use +text(val)+ to set value, and +text()+ to retrieve value
Example¶ ↑
f = Field.new @form, text: "Some value", row: 10, col: 2
Field
introduces an event :CHANGE which is fired for each character deleted or inserted TODO: some methods should return self, so chaining can be done. Not sure if the return value of the
fire_handler is being checked. NOTE: i have just added repain_required check in Field before repaint this may mean in some places field does not paint. repaint_require will have to be set to true in those cases. this was since field was overriding a popup window that was not modal.
Attributes
for numeric fields, specify lower or upper limit of entered value
for numeric fields, specify lower or upper limit of entered value
this accesses the field created or passed with set_label
attr_reader :label
this is the class of the field set in +text()+, so value is returned in same class @example : Integer, Integer, Float
column on which field printed, usually the same as col
unless label
used. Required by History
to popup field history.
Public Class Methods
required due to labels. Is updated after printing
# so can be nil if accessed early 2011-12-8
Canis::Widget::new
# File lib/canis/core/widgets/rwidget.rb, line 2307 def initialize form=nil, config={}, &block @form = form @buffer = String.new #@type=config.fetch("type", :varchar) @row = 0 @col = 0 @editable = true @focusable = true #@event_args = {} # arguments passed at time of binding, to use when firing event map_keys init_vars register_events(:CHANGE) super @width ||= 20 @maxlen ||= @width end
Public Instance Methods
add a column to cursor position. Field
# File lib/canis/core/widgets/rwidget.rb, line 2704 def addcol num if num < 0 if @form.col <= @col + @col_offset # $log.debug " error trying to cursor back #{@form.col}" return -1 end elsif num > 0 if @form.col >= @col + @col_offset + @width # $log.debug " error trying to cursor forward #{@form.col}" return -1 end end @form.addcol num end
# File lib/canis/core/widgets/rwidget.rb, line 2664 def cursor_backward if @curpos > 0 @curpos -= 1 if @pcol > 0 and @form.col == @col + @col_offset @pcol -= 1 end addcol -1 elsif @pcol > 0 # added 2008-11-26 23:05 @pcol -= 1 end # $log.debug " crusor back cp:#{@curpos} pcol:#{@pcol} b.l:#{@buffer.length} d_l:#{@display_length} fc:#{@form.col}" =begin # this is perfect if not scrolling, but now needs changes if @curpos > 0 @curpos -= 1 addcol -1 end =end end
goto end of field, “end” is a keyword so could not use it.
# File lib/canis/core/widgets/rwidget.rb, line 2618 def cursor_end blen = @buffer.rstrip.length if blen < @width set_form_col blen else # there is a problem here FIXME. @pcol = blen-@width #set_form_col @width-1 set_form_col blen end @curpos = blen # this is position in array where editing or motion is to happen regardless of what you see # regardless of pcol (panning) # $log.debug " crusor END cp:#{@curpos} pcol:#{@pcol} b.l:#{@buffer.length} d_l:#{@width} fc:#{@form.col}" #set_form_col @buffer.length end
# File lib/canis/core/widgets/rwidget.rb, line 2655 def cursor_forward if @curpos < @buffer.length if addcol(1)==-1 # go forward if you can, else scroll @pcol += 1 if @pcol < @width end @curpos += 1 end # $log.debug " crusor FORWARD cp:#{@curpos} pcol:#{@pcol} b.l:#{@buffer.length} d_l:#{@display_length} fc:#{@form.col}" end
position cursor at start of field
# File lib/canis/core/widgets/rwidget.rb, line 2611 def cursor_home @curpos = 0 @pcol = 0 set_form_col 0 end
# File lib/canis/core/widgets/rwidget.rb, line 2417 def delete_at index=@curpos return -1 if !@editable char = @buffer.slice!(index,1) #$log.debug " delete at #{index}: #{@buffer.length}: #{@buffer}" @modified = true #fire_handler :CHANGE, self # 2008-12-09 14:51 fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos, self, :DELETE, 0, char) # 2010-09-11 13:01 end
# File lib/canis/core/widgets/rwidget.rb, line 2683 def delete_curr_char return -1 unless @editable delete_at set_modified end
# File lib/canis/core/widgets/rwidget.rb, line 2646 def delete_eol return -1 unless @editable pos = @curpos-1 @delete_buffer = @buffer[@curpos..-1] # if pos is 0, pos-1 becomes -1, end of line! @buffer = pos == -1 ? "" : @buffer[0..pos] fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos+@delete_buffer.length, self, :DELETE, 0, @delete_buffer) return @delete_buffer end
# File lib/canis/core/widgets/rwidget.rb, line 2688 def delete_prev_char return -1 if !@editable return if @curpos <= 0 # if we've panned, then unpan, and don't move cursor back # Otherwise, adjust cursor (move cursor back as we delete) adjust = true if @pcol > 0 @pcol -= 1 adjust = false end @curpos -= 1 if @curpos > 0 delete_at addcol -1 if adjust # move visual cursor back set_modified end
converts back into original type
changed to convert on 2009-01-06 23:39
# File lib/canis/core/widgets/rwidget.rb, line 2456 def getvalue dt = @datatype || String case dt.to_s when "String" return @buffer when "Integer" return @buffer.to_i when "Float" return @buffer.to_f else return @buffer.to_s end end
field
Canis::Widget#handle_key
# File lib/canis/core/widgets/rwidget.rb, line 2586 def handle_key ch @repaint_required = true case ch when 32..126 #$log.debug("FIELD: ch #{ch} ,at #{@curpos}, buffer:[#{@buffer}] bl: #{@buffer.to_s.length}") putc ch when 27 # cannot bind it #text @original_value # commented above and changed 2014-05-12 - 20:05 I think above creates positioning issues. TEST XXX restore_original_value else ret = super return ret end 0 # 2008-12-16 23:05 without this -1 was going back so no repaint end
checks field against valid_range
, above
and below
, returning true
if it passes set attributes, false
if it fails any one.
# File lib/canis/core/widgets/rwidget.rb, line 2752 def in_range?( val ) val = val.to_i (@above.nil? or val > @above) and (@below.nil? or val < @below) and (@valid_range.nil? or @valid_range.include?(val)) end
# File lib/canis/core/widgets/rwidget.rb, line 2323 def init_vars @pcol = 0 # needed for horiz scrolling @curpos = 0 # current cursor position in buffer # this is the index where characters are put or deleted # # when user edits @modified = false @repaint_required = true end
# File lib/canis/core/widgets/rwidget.rb, line 2500 def label *val return @label if val.empty? raise "Field does not allow setting of label. Please use LabeledField instead with lcol for label column" end
# File lib/canis/core/widgets/rwidget.rb, line 2568 def map_keys return if @keys_mapped bind_key(FFI::NCurses::KEY_LEFT, :cursor_backward ) bind_key(FFI::NCurses::KEY_RIGHT, :cursor_forward ) bind_key(FFI::NCurses::KEY_BACKSPACE, :delete_prev_char ) bind_key(127, :delete_prev_char ) bind_key(330, :delete_curr_char ) bind_key(?\C-a, :cursor_home ) bind_key(?\C-e, :cursor_end ) bind_key(?\C-k, :delete_eol ) bind_key(?\C-_, :undo_delete_eol ) #bind_key(27){ text @original_value } bind_key(?\C-g, 'revert'){ text @original_value } # 2011-09-29 V1.3.1 ESC did not work @keys_mapped = true end
overriding widget, check for value change
2009-01-18 12:25
# File lib/canis/core/widgets/rwidget.rb, line 2770 def modified? getvalue() != @original_value end
save original value on enter, so we can check for modified. 2009-01-18 12:25
2011-10-9 I have changed to take @buffer since getvalue returns a datatype and this causes a crash in set_original on cursor forward.
Canis::Widget#on_enter
# File lib/canis/core/widgets/rwidget.rb, line 2762 def on_enter #@original_value = getvalue.dup rescue getvalue @original_value = @buffer.dup # getvalue.dup rescue getvalue super end
upon leaving a field returns false if value not valid as per values or valid_regex 2008-12-22 12:40 if null_allowed, don't validate, but do fire_handlers
Canis::Widget#on_leave
# File lib/canis/core/widgets/rwidget.rb, line 2721 def on_leave val = getvalue #$log.debug " FIELD ON LEAVE:#{val}. #{@values.inspect}" valid = true if val.to_s.empty? && @null_allowed #$log.debug " empty and null allowed" else if !@values.nil? valid = @values.include? val raise FieldValidationException, "Field value (#{val}) not in values: #{@values.join(',')}" unless valid end if !@valid_regex.nil? valid = @valid_regex.match(val.to_s) raise FieldValidationException, "Field not matching regex #{@valid_regex}" unless valid end # added valid_range for numerics 2011-09-29 if !in_range?(val) raise FieldValidationException, "Field not matching range #{@valid_range}, above #{@above} or below #{@below} " end end # here is where we should set the forms modified to true - 2009-01 if modified? set_modified true end # if super fails we would have still set modified to true super #return valid end
FIXME this may not work since i have disabled -1, now i do not set row and col
# File lib/canis/core/widgets/rwidget.rb, line 2505 def position_label $log.debug "XXX: LABEL row #{@label.row}, #{@label.col} " @label.row @row unless @label.row #if @label.row == -1 @label.col @col-(@label.name.length+1) unless @label.col #if @label.col == -1 @label.label_for(self) # this line got deleted when we redid stuff ! $log.debug " XXX: LABEL row #{@label.row}, #{@label.col} " end
TODO : sending c>=0 allows control chars to go. Should be >= ?A i think.
# File lib/canis/core/widgets/rwidget.rb, line 2401 def putc c if c >= 0 and c <= 127 ret = putch c.chr if ret == 0 if addcol(1) == -1 # if can't go forward, try scrolling # scroll if exceeding display len but less than max len if @curpos > @width && @curpos <= @maxlen @pcol += 1 if @pcol < @width end end set_modified return 0 # 2010-09-11 12:59 else would always return -1 end end return -1 end
add a char to field, and validate NOTE: this should return self for chaining operations and throw an exception if disabled or exceeding size @param [char] a character to add @return [Integer] 0 if okay, -1 if not editable or exceeding length
# File lib/canis/core/widgets/rwidget.rb, line 2370 def putch char return -1 if !@editable return -1 if !@overwrite_mode && (@buffer.length >= @maxlen) blen = @buffer.length if @chars_allowed != nil return if char.match(@chars_allowed).nil? end # added insert or overwrite mode 2010-03-17 20:11 oldchar = nil if @overwrite_mode oldchar = @buffer[@curpos] @buffer[@curpos] = char else @buffer.insert(@curpos, char) end oldcurpos = @curpos #$log.warn "XXX: FIELD CURPOS #{@curpos} blen #{@buffer.length} " #if @curpos > blen @curpos += 1 if @curpos < @maxlen @modified = true #$log.debug " FIELD FIRING CHANGE: #{char} at new #{@curpos}: bl:#{@buffer.length} buff:[#{@buffer}]" # i have no way of knowing what change happened and what char was added deleted or changed #fire_handler :CHANGE, self # 2008-12-09 14:51 if @overwrite_mode fire_handler :CHANGE, InputDataEvent.new(oldcurpos,@curpos, self, :DELETE, 0, oldchar) # 2010-09-11 12:43 end fire_handler :CHANGE, InputDataEvent.new(oldcurpos,@curpos, self, :INSERT, 0, char) # 2010-09-11 12:43 0 end
Note that some older widgets like Field repaint every time the form.repaint
+ is called, whether updated or not. I can't remember why this is, but + currently I've not implemented events with these widgets. 2010-01-03 15:00
# File lib/canis/core/widgets/rwidget.rb, line 2517 def repaint return unless @repaint_required # 2010-11-20 13:13 its writing over a window i think TESTING if @label_unattached alert "came here unattachd" @label.set_form(@form) @label_unattached = nil end if @label_unplaced alert "came here unplaced" position_label @label_unplaced = nil end #@bgcolor ||= $def_bg_color #@color ||= $def_fg_color _color = color() _bgcolor = bgcolor() $log.debug("repaint FIELD: #{id}, #{name}, #{row} #{col},pcol:#{@pcol}, #{focusable} st: #{@state} ") @width = 1 if width == 0 printval = getvalue_for_paint().to_s # added 2009-01-06 23:27 printval = mask()*printval.length unless @mask.nil? if !printval.nil? if printval.length > width # only show maxlen printval = printval[@pcol..@pcol+width-1] else printval = printval[@pcol..-1] end end acolor = @color_pair || get_color($datacolor, _color, _bgcolor) if @state == :HIGHLIGHTED _bgcolor = @highlight_bgcolor || _bgcolor _color = @highlight_color || _color acolor = get_color(acolor, _color, _bgcolor) end @graphic = @form.window if @graphic.nil? ## cell editor listbox hack #$log.debug " Field g:#{@graphic}. r,c,displen:#{@row}, #{@col}, #{@width} c:#{@color} bg:#{@bgcolor} a:#{@attr} :#{@name} " r = row c = col @graphic.printstring r, c, sprintf("%-*s", width, printval), acolor, attr() @field_col = c @repaint_required = false end
silently restores value without firing handlers, use if exception and you want old value @since 1.4.0 2011-10-2
# File lib/canis/core/widgets/rwidget.rb, line 2428 def restore_original_value @buffer = @original_value.dup # earlier commented but trying again, since i am getting IndexError in insert 2188 # Added next 3 lines to fix issue, now it comes back to beginning. cursor_home @repaint_required = true end
deprecated set or unset focusable
# File lib/canis/core/widgets/rwidget.rb, line 2562 def set_focusable(tf) $log.warn "pls don't use, deprecated. use focusable(boolean)" focusable tf end
sets the visual cursor on the window at correct place added here since we need to account for pcol. 2011-12-7 NOTE be careful of curpos - pcol being less than 0
# File lib/canis/core/widgets/rwidget.rb, line 2636 def set_form_col col1=@curpos @curpos = col1 || 0 # NOTE we set the index of cursor here c = @col + @col_offset + @curpos - @pcol min = @col + @col_offset max = min + @width c = min if c < min c = max if c > max #$log.debug " #{@name} FIELD set_form_col #{c}, curpos #{@curpos} , #{@col} + #{@col_offset} pcol:#{@pcol} " setrowcol nil, c end
create a label linked to this field Typically one passes a Label
, but now we can pass just a String
, a label is created. This differs from label
in positioning. The Field
is printed on row
and col
and the label before it. Thus, all fields are aligned on column, however you must leave adequate columns for the label to be printed to the left of the field.
NOTE: 2011-10-20 when field attached to some container, label won't be attached In such cases, use just +label()+ not +set_label()+. @param [Label, String] label object to be associated with this field @return label created which can be further customized. FIXME this may not work since i have disabled -1, now i do not set row and col 2011-11-5
# File lib/canis/core/widgets/rwidget.rb, line 2481 def set_label label # added case for user just using a string case label when String # what if no form at this point @label_unattached = true unless @form label = Label.new @form, {:text => label} end @label = label # in the case of app it won't be set yet FIXME # So app sets label to 0 and t his won't trigger # can this be delayed to when paint happens XXX if @row position_label else @label_unplaced = true end label end
Set the value in the field. @param if none given, returns value existing @param value (can be int, float, String
)
@return self
# File lib/canis/core/widgets/rwidget.rb, line 2779 def text(*val) if val.empty? return getvalue() else return unless val # added 2010-11-17 20:11, dup will fail on nil return unless val[0] # 2013-04-20 - 19:02 dup failing on fixnum, set_buffer does a dup # so maybe i can do without it here #s = val[0].dup s = val[0] _set_buffer(s) end end
# File lib/canis/core/widgets/rwidget.rb, line 2793 def text=(val) return unless val # added 2010-11-17 20:11, dup will fail on nil # will bomb on integer or float etc !! #_set_buffer(val.dup) _set_buffer(val) end
NOTE: earlier there was some confusion over type, chars_allowed
and datatype Now type and chars_allowed
are merged into one. If you pass a symbol such as :integer, :float or Float Integer
then some
standard chars_allowed will be used. Otherwise you may pass a regexp.
@param symbol :integer, :float, :alpha, :alnum, Float, Integer
, Numeric, Regexp
# File lib/canis/core/widgets/rwidget.rb, line 2338 def type *val return @chars_allowed if val.empty? dtype = val[0] #return self if @chars_allowed # disallow changing if dtype.is_a? Regexp @chars_allowed = dtype return self end dtype = dtype.to_s.downcase.to_sym if dtype.is_a? String case dtype # missing to_sym would have always failed due to to_s 2011-09-30 1.3.1 when :integer, Integer @chars_allowed = /\d/ when :numeric, :float, Numeric, Float @chars_allowed = /[\d\.]/ when :alpha @chars_allowed = /[a-zA-Z]/ when :alnum @chars_allowed = /[a-zA-Z0-9]/ else raise ArgumentError, "Field type: invalid datatype specified. Use :integer, :numeric, :float, :alpha, :alnum " end self end
does an undo on delete_eol
, not a real undo
# File lib/canis/core/widgets/rwidget.rb, line 2603 def undo_delete_eol return if @delete_buffer.nil? #oldvalue = @buffer @buffer.insert @curpos, @delete_buffer fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos+@delete_buffer.length, self, :INSERT, 0, @delete_buffer) # 2010-09-11 13:01 end