class Canis::Form

Manages the controls/widgets on a screen. Manages traversal, rendering and events of all widgets that are associated with it via the add_widget method.

Passes keys pressed by user to the current field. Any keys that are not handled by the current field, are handled by the form if the application has bound the key via bind_key.

TODO: we don't have an event for when form is entered and exited.

Attributes

active_index[RW]

index of active widget

attr[RW]
bgcolor[W]

color and bgcolor for all widget, widgets that don't have color specified will inherit from form If not mentioned, then global defaults will be taken

by_name[R]

hash containing widgets by name for retrieval Useful if one widget refers to second before second created.

lb = @form.by_name["listb"]
col[RW]

cursor row and col

color[W]

color and bgcolor for all widget, widgets that don't have color specified will inherit from form If not mentioned, then global defaults will be taken

layout_manager[RW]

class that lays out objects (calculates row, col, width and height)

menu_bar[R]

associated menubar

modified[RW]

has the form been modified

name[RW]

name given to form for debugging

navigation_policy[RW]

this influences whether navigation will return to first component after last or not Default is :CYCLICAL which cycles between first and last. In some cases, where a form or container exists inside a form with buttons or tabs, you may not want cyclical traversal.

resize_required[RW]

signify that the layout manager must calculate each widgets dimensions again since typically the window has been resized.

row[RW]

cursor row and col

widgets[R]

array of widgets

window[RW]

related window used for printing

Public Class Methods

new(win, &block) click to toggle source
# File lib/canis/core/widgets/rwidget.rb, line 1570
def initialize win, &block
  @window = win
  # added 2014-05-01 - 20:43 so that a window can update its form, during overlapping forms.
  @window.form = self if win
  @widgets = []
  @by_name = {}
  @active_index = -1
  @row = @col = -1
  @modified = false
  @resize_required = true
  @focusable = true
  # when widgets are added, add them here if focusable so traversal is easier. However,
  #  if user changes this during the app, we need to update this somehow. FIXME
  @focusables = [] # added 2014-04-24 - 12:28 to make traversal easier
  @navigation_policy ||= :CYCLICAL
  # 2014-04-24 - 17:42 NO MORE ENTER LEAVE at FORM LEVEL
  #register_events([:ENTER, :LEAVE, :RESIZE])
  register_events(:RESIZE)
  instance_eval &block if block_given?
  @_firsttime = true; # added on 2010-01-02 19:21 to prevent scrolling crash !
  @name ||= ""

  # related to emacs kill ring concept for copy-paste

  $kill_ring ||= [] # 2010-03-09 22:42 so textarea and others can copy and paste emacs EMACS
  $kill_ring_pointer = 0 # needs to be incremented with each append, moved with yank-pop
  $append_next_kill = false
  $kill_last_pop_size = 0 # size of last pop which has to be cleared

  $last_key = 0 # last key pressed @since 1.1.5 (not used yet)
  $current_key = 0 # curr key pressed @since 1.1.5 (so some containers can behave based on whether
                # user tabbed in, or backtabbed in (rmultisplit)

  # for storing error message
  $error_message ||= Variable.new ""

  # what kind of key-bindings do you want, :vim or :emacs
  $key_map_type ||= :vim ## :emacs or :vim, keys to be defined accordingly. TODO

  #bind_key(KEY_F1, 'help') { hm = help_manager(); hm.display_help }
  map_keys unless @keys_mapped
end

Public Instance Methods

add(widget)
Alias for: add_widget
add_widget(widget) click to toggle source

Add given widget to widget list and returns an incremental id. Adding to widgets, results in it being painted, and focussed. removing a widget and adding can give the same ID's, however at this point we are not really using ID. But need to use an incremental int in future. (internal use)

# File lib/canis/core/widgets/rwidget.rb, line 1635
def add_widget widget
  # this help to access widget by a name
  if widget.respond_to? :name and !widget.name.nil?
    @by_name[widget.name] = widget
  end

  @widgets << widget
  @focusable_modified = true

  return @widgets.length-1
end
Also aliased as: add
addcol(num) click to toggle source

move cursor by num columns. Form

# File lib/canis/core/widgets/rwidget.rb, line 1951
def addcol num
  return if @col.nil? || @col == -1
  @col += num
  @window.wmove @row, @col
  ## 2010-01-30 23:45 exchange calling parent with calling this forms setrow
  # since in tabbedpane with table i am not gietting this forms offset.
  setrowcol nil, col
end
addrowcol(row,col) click to toggle source

move cursor by given rows and columns, can be negative. 2010-01-30 23:47 FIXME, if this is called we should call setrowcol like in addcol

# File lib/canis/core/widgets/rwidget.rb, line 1962
def addrowcol row,col
  return if @col.nil? or @col == -1   # contradicts comment on top
  return if @row.nil? or @row == -1
  @col += col
  @row += row
  @window.wmove @row, @col

end
bgcolor() click to toggle source

returns form's bgcolor, or global default.

# File lib/canis/core/widgets/rwidget.rb, line 2224
def bgcolor
  @bgcolor || $def_bg_color
end
color() click to toggle source

returns forms color, or if not set then app default This is used by widget's as the color to fallback on when no color is specified for them. This way all widgets in a form can have one color.

# File lib/canis/core/widgets/rwidget.rb, line 2220
def color
  @color || $def_fg_color
end
current_widget()
Alias for: get_current_field
digit_argument(ch) click to toggle source
# File lib/canis/core/widgets/rwidget.rb, line 2030
def digit_argument ch
  $multiplier = ch - ?\M-0.getbyte(0)
  $log.debug " inside UNIV MULT 0 #{$multiplier} "
  # See if user enters numerics. If so discard existing varaible and take only
  #+ entered values
  _m = $multiplier
  while true
    ch = @window.getchar()
    case ch
    when -1
      next 
    when ?0.getbyte(0)..?9.getbyte(0)
      _m *= 10 ; _m += (ch-48)
      $multiplier = _m
      $log.debug " inside UNIV MULT 1 #{$multiplier} "
    when ?\M-0.getbyte(0)..?\M-9.getbyte(0)
      _m *= 10 ; _m += (ch-?\M-0.getbyte(0))
      $multiplier = _m
      $log.debug " inside UNIV MULT 2 #{$multiplier} "
    else
      $log.debug " inside UNIV MULT else got #{ch} "
      # here is some other key that is the function key to be repeated. we must honor this
      # and ensure it goes to the right widget
      return ch
      #return :UNHANDLED
    end
  end
  return 0
end
get_current_field() click to toggle source

@return [Widget, nil] current field, nil if no focusable field

# File lib/canis/core/widgets/rwidget.rb, line 1721
def get_current_field
  select_next_field if @active_index == -1
  return nil if @active_index.nil?   # for forms that have no focusable field 2009-01-08 12:22
  @widgets[@active_index]
end
Also aliased as: current_widget
handle_key(ch) click to toggle source
forms handle keys

mainly traps tab and backtab to navigate between widgets. I know some widgets will want to use tab, e.g edit boxes for entering a tab

or for completion.

@throws FieldValidationException NOTE : please rescue exceptions when you use this in your main loop and alert() user

# File lib/canis/core/widgets/rwidget.rb, line 2110
def handle_key(ch)
  # 2014-08-19 - 21:10 moving to init, so that user may override or remove
  #map_keys unless @keys_mapped
  handled = :UNHANDLED # 2011-10-4
      if ch ==  ?\C-u.getbyte(0)
        ret = universal_argument
        $log.debug "C-u FORM set MULT to #{$multiplier}, ret = #{ret}  "
        return 0 if ret == 0
        ch = ret # unhandled char
      elsif ch >= ?\M-1.getbyte(0) && ch <= ?\M-9.getbyte(0)
        if $catch_alt_digits # emacs EMACS
          ret = digit_argument ch
          $log.debug " FORM set MULT DA to #{$multiplier}, ret = #{ret}  "
          return 0 if ret == 0 # don't see this happening
          ch = ret # unhandled char
        end
      end

      $current_key = ch
      case ch
      when -1
        return
      when 1000, 12
        # NOTE this works if widgets cover entire screen like text areas and lists but not in
        #  dialogs where there is blank space. only widgets are painted.
        # testing out 12 is C-l
        $log.debug " form REFRESH_ALL repaint_all HK #{ch} #{self}, #{@name} "
        repaint_all_widgets
        return
      when FFI::NCurses::KEY_RESIZE  # SIGWINCH
        # note that in windows that have dialogs or text painted on window such as title or
        #  box, the clear call will clear it out. these are not redrawn.
        lines = Ncurses.LINES
        cols = Ncurses.COLS
        x = Ncurses.stdscr.getmaxy
        y = Ncurses.stdscr.getmaxx
        $log.debug " form RESIZE HK #{ch} #{self}, #{@name}, #{ch}, x #{x} y #{y}  lines #{lines} , cols: #{cols} "
        #alert "SIGWINCH WE NEED TO RECALC AND REPAINT resize #{lines}, #{cols}: #{x}, #{y} "

        # next line may be causing flicker, can we do without.
        Ncurses.endwin
        @window.wrefresh
        @window.wclear
        if @layout_manager
          @layout_manager.do_layout
          # we need to redo statusline and others that layout ignores
        else
          @widgets.each { |e| e.repaint_all(true) } # trying out
        end
        ## added RESIZE on 2012-01-5
        ## stuff that relies on last line such as statusline dock etc will need to be redrawn.
        fire_handler :RESIZE, self 
      else
        field =  get_current_field
        if $log.debug?
          keycode = keycode_tos(ch)
          $log.debug " form HK #{ch} #{self}, #{@name}, #{keycode}, field: giving to: #{field}, #{field.name}  " if field
        end
        handled = :UNHANDLED 
        handled = field.handle_key ch unless field.nil? # no field focussable
        $log.debug "handled inside Form #{ch} from #{field} got #{handled}  "
        # some widgets like textarea and list handle up and down
        if handled == :UNHANDLED or handled == -1 or field.nil?
          case ch
          when KEY_TAB, ?\M-\C-i.getbyte(0)  # tab and M-tab in case widget eats tab (such as Table)
            ret = select_next_field
            return ret if ret == :NO_NEXT_FIELD
            # alt-shift-tab  or backtab (in case Table eats backtab)
          when FFI::NCurses::KEY_BTAB, 481 ## backtab added 2008-12-14 18:41
            ret = select_prev_field
            return ret if ret == :NO_PREV_FIELD
          when FFI::NCurses::KEY_UP
            ret = select_prev_field
            return ret if ret == :NO_PREV_FIELD
          when FFI::NCurses::KEY_DOWN
            ret = select_next_field
            return ret if ret == :NO_NEXT_FIELD
          else
            #$log.debug " before calling process_key in form #{ch}  " if $log.debug?
            ret = process_key ch, self
            # seems we need to flushinp in case composite has pushed key
            $log.debug "FORM process_key #{ch} got ret #{ret} in #{self}, flushing input "
            # 2014-06-01 - 17:01 added flush, maybe at some point we could do it only if unhandled
            #   in case some method wishes to actually push some keys
            Ncurses.flushinp
            return :UNHANDLED if ret == :UNHANDLED
          end
        elsif handled == :NO_NEXT_FIELD || handled == :NO_PREV_FIELD # 2011-10-4
          return handled
        end
      end
     $log.debug " form before repaint #{self} , #{@name}, ret #{ret}"
     repaint
     $last_key = ch
     ret || 0  # 2011-10-17
end
help_manager() click to toggle source

returns in instance of help_manager with which one may install help_text and call help. user apps will only supply help_text, form would already have mapped F1 to help.

# File lib/canis/core/widgets/rwidget.rb, line 2213
def help_manager
  require 'canis/core/util/helpmanager'
  @help_manager ||= Canis::HelpManager.new self
end
map_keys() click to toggle source

These mappings will only trigger if the current field

does not use them.
# File lib/canis/core/widgets/rwidget.rb, line 2063
def map_keys
  return if @keys_mapped
  bind_key(KEY_F1, 'help') { hm = help_manager(); hm.display_help }
  bind_keys([?\M-?,?\?], 'show field help') { 
    #if get_current_field.help_text
      #textdialog(get_current_field.help_text, 'title' => 'Help Text', :bgcolor => 'green', :color => :white)
    #else
      print_key_bindings
    #end
  }
  bind_key(FFI::NCurses::KEY_F9, "Print keys", :print_key_bindings) # show bindings, tentative on F9
  bind_key(?\M-:, 'show menu') {
    fld = get_current_field
    am = fld.action_manager()
    #fld.init_menu
    am.show_actions
  }
  @keys_mapped = true
end
on_enter(f) click to toggle source

form calls on_enter of each object. However, if a multicomponent calls on_enter of a widget, this code will not be triggered. The highlighted part

# File lib/canis/core/widgets/rwidget.rb, line 1783
def on_enter f
  return if f.nil? || !f.focusable # added focusable, else label was firing 2010-09

  f.state = :HIGHLIGHTED
  # If the widget has a color defined for focussed, set repaint
  #  otherwise it will not be repainted unless user edits !
  if f.highlight_bgcolor || f.highlight_color
    f.repaint_required true
  end

  f.modified false
  #f.set_modified false
  f.on_enter if f.respond_to? :on_enter
  # 2014-04-24 - 17:42 NO MORE ENTER LEAVE at FORM LEVEL
  #fire_handler :ENTER, f
end
on_leave(f) click to toggle source
do not override

form's trigger, fired when any widget loses focus

This wont get called in editor components in tables, since  they are formless
# File lib/canis/core/widgets/rwidget.rb, line 1765
def on_leave f
  return if f.nil? || !f.focusable # added focusable, else label was firing
  f.state = :NORMAL
  # on leaving update text_variable if defined. Should happen on modified only
  # should this not be f.text_var ... f.buffer ?  2008-11-25 18:58
  #f.text_variable.value = f.buffer if !f.text_variable.nil? # 2008-12-20 23:36
  f.on_leave if f.respond_to? :on_leave
  # 2014-04-24 - 17:42 NO MORE ENTER LEAVE at FORM LEVEL
  #fire_handler :LEAVE, f
  ## to test XXX in combo boxes the box may not be editable by be modified by selection.
  if f.respond_to? :editable and f.modified?
    $log.debug " Form about to fire CHANGED for #{f} "
    f.fire_handler(:CHANGED, f) 
  end
end
process_key(keycode, object) click to toggle source

e.g. process_key ch, self returns UNHANDLED if no block for it after form handles basic keys, it gives unhandled key to current field, if current field returns unhandled, then it checks this map. Please update widget with any changes here. TODO: match regexes as in mapper

# File lib/canis/core/widgets/rwidget.rb, line 1986
def process_key keycode, object
  return _process_key keycode, object, @window
end
remove_widget(widget) click to toggle source

remove a widget (internal use)

# File lib/canis/core/widgets/rwidget.rb, line 1650
def remove_widget widget
  if widget.respond_to? :name and !widget.name.nil?
    @by_name.delete(widget.name)
  end
  @focusable_modified = true
  @widgets.delete widget
end
repaint() click to toggle source

form repaint,calls repaint on each widget which will repaint it only if it has been modified since last call. called after each keypress.

# File lib/canis/core/widgets/rwidget.rb, line 1676
def repaint
  $log.debug " form repaint:#{self}, #{@name} , r #{@row} c #{@col} " if $log.debug? 
  if @resize_required && @layout_manager
    @layout_manager.form = self unless @layout_manager.form
    @layout_manager.do_layout
    @resize_required = false
  end
  @widgets.each do |f|
    next if f.visible == false # added 2008-12-09 12:17
    #$log.debug "XXX: FORM CALLING REPAINT OF WIDGET #{f} IN LOOP"
    #raise "Row or col nil #{f.row} #{f.col} for #{f}, #{f.name} " if f.row.nil? || f.col.nil?
    f.repaint
    f._object_created = true # added 2010-09-16 13:02 now prop handlers can be fired
  end
  
  _update_focusables if @focusable_modified
  #  this can bomb if someone sets row. We need a better way!
  if @row == -1 and @_firsttime == true
   
    select_first_field
    @_firsttime = false
  end
   setpos 
   # XXX this creates a problem if window is a pad
   # although this does show cursor movement etc.
   ### @window.wrefresh
   #if @window.window_type == :WINDOW
     #$log.debug " formrepaint #{@name} calling window.wrefresh #{@window} "
     @window.wrefresh
     Ncurses::Panel.update_panels ## added 2010-11-05 00:30 to see if clears the stdscr problems
   #else
     #$log.warn " XXX formrepaint #{@name} no refresh called  2011-09-19  #{@window} "
   #end
end
repaint_all_widgets() click to toggle source

this forces a repaint of all visible widgets and has been added for the case of overlapping windows, since a black rectangle is often left when a window is destroyed. This is internally triggered whenever a window is destroyed, and currently only for root window. NOTE: often the window itself or spaces between widgets also gets cleared, so basically the window itself may need recreating ? 2014-08-18 - 21:03

# File lib/canis/core/widgets/rwidget.rb, line 2088
def repaint_all_widgets
  $log.debug "  REPAINT ALL in FORM called "
  @widgets.each do |w|
    next if w.visible == false
    next if w.class.to_s == "Canis::MenuBar"
    $log.debug "   ---- REPAINT ALL #{w.name} "
    #w.repaint_required true
    w.repaint_all true
    w.repaint
  end
  $log.debug "  REPAINT ALL in FORM complete "
  #  place cursor on current_widget
  setpos
end
select_field(ix0) click to toggle source

puts focus on the given field/widget index @param index of field in @widgets (or can be a Widget too) XXX if called externally will not run a on_leave of previous field

# File lib/canis/core/widgets/rwidget.rb, line 1804
def select_field ix0
  if ix0.is_a? Widget
    ix0 = @widgets.index(ix0)
  end
  return if @widgets.nil? or @widgets.empty?
 #$log.debug "inside select_field :  #{ix0} ai #{@active_index}"
  f = @widgets[ix0]
  return if !f.focusable?
  if f.focusable?
    @active_index = ix0
    @row, @col = f.rowcol
    #$log.debug " WMOVE insdie sele nxt field : ROW #{@row} COL #{@col} "
    on_enter f
    @window.wmove @row, @col # added RK FFI 2011-09-7 = setpos

    f.set_form_row # added 2011-10-5 so when embedded in another form it can get the cursor
    f.set_form_col # this can wreak havoc in containers, unless overridden

    # next line in field changes cursor position after setting form_col
    # resulting in a bug.  2011-11-25
    # maybe it is in containers or tabbed panes and multi-containers
    # where previous objects col is still shown. we cannot do this after
    # setformcol
    #f.curpos = 0 # why was this, okay is it because of prev obj's cursor ?
    repaint
    @window.refresh
  else
    $log.debug "inside select field ENABLED FALSE :   act #{@active_index} ix0 #{ix0}" 
  end
end
select_first_field() click to toggle source

take focus to first focussable field we shoud not send to select_next. have a separate method to avoid bugs. but check current_field, in case called from anotehr field TODO FIXME

# File lib/canis/core/widgets/rwidget.rb, line 1730
def select_first_field
  # this results in on_leave of last field being executed when form starts.
  #@active_index = -1 # FIXME HACK
  #select_next_field
  ix =  @focusables.first
  return unless ix # no focussable field

  # if the user is on a field other than current then fire on_leave
  if @active_index.nil? || @active_index < 0
  elsif @active_index != ix
    f = @widgets[@active_index]
    begin
      #$log.debug " select first field, calling on_leave of #{f} #{@active_index} "
      on_leave f
    rescue => err
     $log.error " Caught EXCEPTION select_first_field on_leave #{err}"
     Ncurses.beep
     #$error_message = "#{err}"
     $error_message.value = "#{err}"
     return
    end
  end
  select_field ix
end
select_last_field() click to toggle source

take focus to last field on form

# File lib/canis/core/widgets/rwidget.rb, line 1756
def select_last_field
  @active_index = nil 
  select_prev_field
end
select_next_field() click to toggle source

put focus on next field will cycle by default, unless navigation policy not :CYCLICAL in which case returns :NO_NEXT_FIELD. FIXME: in the beginning it comes in as -1 and does an on_leave of last field

# File lib/canis/core/widgets/rwidget.rb, line 1858
    def select_next_field
      return :UNHANDLED if @widgets.nil? || @widgets.empty?
      #$log.debug "insdie sele nxt field :  #{@active_index} WL:#{@widgets.length}"
      if @active_index.nil?  || @active_index == -1 # needs to be tested out A LOT
        # what is this silly hack for still here 2014-04-24 - 13:04  DELETE FIXME
        @active_index = -1 
      else
        f = @widgets[@active_index]
        begin
          on_leave f
        rescue FieldValidationException => err # added 2011-10-2 v1.3.1 so we can rollback
          $log.error "select_next_field: caught EXCEPTION #{err}"
          $error_message.value = "#{err}"
          raise err
        rescue => err
         $log.error "select_next_field: caught EXCEPTION #{err}"
         $log.error(err.backtrace.join("\n")) 
#         $error_message = "#{err}" # changed 2010
         $error_message.value = "#{err}"
         Ncurses.beep
         return 0
        end
      end
      f = @widgets[@active_index]
      index = @focusables.index(f)
      # 2014-08-09 - 13:09 f may be status_line esp if ai is -1, so it is not found in focusables
      # why are we first checking widgets and then focusables.
      #index += 1
      index = index ? index+1 : 0
      f = @focusables[index]
      if f
        select_field f 
        return 0
      end
      #
      #$log.debug "insdie sele nxt field FAILED:  #{@active_index} WL:#{@widgets.length}"
      ## added on 2008-12-14 18:27 so we can skip to another form/tab
      if @navigation_policy == :CYCLICAL
        f = @focusables.first
        if f
          select_field f
          return 0
        end
      end
      $log.debug "inside sele nxt field : NO NEXT  #{@active_index} WL:#{@widgets.length}" 
      return :NO_NEXT_FIELD
    end
select_prev_field() click to toggle source

put focus on previous field will cycle by default, unless navigation policy not :CYCLICAL in which case returns :NO_PREV_FIELD. @return [nil, :NO_PREV_FIELD] nil if cyclical and it finds a field

if not cyclical, and no more fields then :NO_PREV_FIELD
# File lib/canis/core/widgets/rwidget.rb, line 1911
    def select_prev_field
      return :UNHANDLED if @widgets.nil? or @widgets.empty?
      #$log.debug "insdie sele prev field :  #{@active_index} WL:#{@widgets.length}"
      if @active_index.nil?
        @active_index = @widgets.length 
      else
        f = @widgets[@active_index]
        begin
          on_leave f
        rescue => err
         $log.error " Caught EXCEPTION #{err}"
         Ncurses.beep
#         $error_message = "#{err}" # changed 2010
         $error_message.value = "#{err}"
         return
        end
      end

      f = @widgets[@active_index]
      index = @focusables.index(f)
      if index > 0
        index -= 1
        f = @focusables[index]
        if f
          select_field f
          return
        end
      end
      
      ## added on 2008-12-14 18:27 so we can skip to another form/tab
      # 2009-01-08 12:24 no recursion, can be stack overflows if no focusable field
      if @navigation_policy == :CYCLICAL
        f = @focusables.last
        select_field @widgets.index(f) if f
      end

      return :NO_PREV_FIELD
    end
set_menu_bar(mb) click to toggle source

set this menubar as the form's menu bar. also bind the toggle_key for popping up. Should this not be at application level ?

# File lib/canis/core/widgets/rwidget.rb, line 1616
def set_menu_bar mb
  @menu_bar = mb
  add_widget mb
  mb.toggle_key ||= Ncurses.KEY_F2
  if !mb.toggle_key.nil?
    ch = mb.toggle_key
    bind_key(ch, 'Menu Bar') do |_form| 
      if !@menu_bar.nil?
        @menu_bar.toggle
        @menu_bar.handle_keys
      end
    end
  end
end
setpos(r=@row, c=@col) click to toggle source

move cursor to where the fields row and col are private

# File lib/canis/core/widgets/rwidget.rb, line 1713
def setpos r=@row, c=@col
  #$log.debug "setpos : (#{self.name}) #{r} #{c} XXX"
  ## adding just in case things are going out of bounds of a parent and no cursor to be shown
  return if r.nil? or c.nil?  # added 2009-12-29 23:28 BUFFERED
  return if r<0 or c<0  # added 2010-01-02 18:49 stack too deep coming if goes above screen
  @window.wmove r,c
end
setrowcol(r, c) click to toggle source
Form

New attempt at setting cursor using absolute coordinates Also, trying NOT to go up. let this pad or window print cursor.

# File lib/canis/core/widgets/rwidget.rb, line 1974
def setrowcol r, c
  @row = r unless r.nil?
  @col = c unless c.nil?
end
to_s() click to toggle source

2010-02-07 14:50 to aid in debugging and comparing log files.

# File lib/canis/core/widgets/rwidget.rb, line 2208
def to_s; @name || self; end
universal_argument() click to toggle source

Defines how user can give numeric args to a command even in edit mode User either presses universal_argument (C-u) which generates a series of 4 16 64. Or he presses C-u and then types some numbers. Followed by the action. @returns [0, :UNHANDLED] :UNHANDLED implies that last keystroke is still to evaluated by system. ) implies only numeric args were obtained. This method updates $multiplier

# File lib/canis/core/widgets/rwidget.rb, line 1996
def universal_argument
  $multiplier = ( ($multiplier.nil? || $multiplier == 0) ? 4 : $multiplier *= 4)
      $log.debug " inside UNIV MULT0: #{$multiplier} "
  # See if user enters numerics. If so discard existing varaible and take only
  #+ entered values
  _m = 0
  while true
    ch = @window.getchar()
    case ch
    when -1
      next 
    when ?0.getbyte(0)..?9.getbyte(0)
      _m *= 10 ; _m += (ch-48)
      $multiplier = _m
      $log.debug " inside UNIV MULT #{$multiplier} "
    when ?\C-u.getbyte(0)
      if _m == 0
        # user is incrementally hitting C-u
        $multiplier *= 4
      else
        # user is terminating some numbers so he can enter a numeric command next
        return 0
      end
    else
      $log.debug " inside UNIV MULT else got #{ch} "
      # here is some other key that is the function key to be repeated. we must honor this
      # and ensure it goes to the right widget
      return ch
      #return :UNHANDLED
    end
  end
  return 0
end
update_focusables() click to toggle source

sets a flag that focusables should be updated called whenever a widgets changes its focusable property

# File lib/canis/core/widgets/rwidget.rb, line 1660
def update_focusables
  $log.debug "XXX:  inside update focusables"
  @focusable_modified = true
end
validate_field(f=@widgets[@active_index]) click to toggle source

run validate_field on a field, usually whatevers current before transferring control We should try to automate this so developer does not have to remember to call it. # @param field object @return [0, -1] for success or failure NOTE : catches exception and sets $error_message, check if -1

# File lib/canis/core/widgets/rwidget.rb, line 1841
    def validate_field f=@widgets[@active_index]
      begin
        on_leave f
      rescue => err
        $log.error "form: validate_field caught EXCEPTION #{err}"
        $log.error(err.backtrace.join("\n")) 
#        $error_message = "#{err}" # changed 2010
        $error_message.value = "#{err}"
        Ncurses.beep
        return -1
      end
      return 0
    end