Class: Canis::Form

Inherits:
Object show all
Includes:
EventHandler, Utils
Defined in:
lib/canis/core/widgets/rwidget.rb

Overview

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.

Since:

  • 1.2.0

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Utils

#ORIG_process_key, #ORIGbind_key, #ORIGkeycode_tos, #_process_key, #bind_composite_mapping, #bind_key, #bind_keys, #check_composite_mapping, #create_logger, #define_key, #define_prefix_command, #execute_mapping, #get_attrib, #get_color, #key, #key_tos, #print_key_bindings, #repeatm, #run_command, #shell_out, #shell_output, #suspend, #view, #xxxbind_composite_mapping

Methods included from EventHandler

#bind, #event?, #event_list, #fire_handler, #fire_property_change, #register_events

Constructor Details

#initialize(win, &block) ⇒ Form

Returns a new instance of Form.

Since:

  • 1.2.0



1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
# File 'lib/canis/core/widgets/rwidget.rb', line 1572

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

Instance Attribute Details

#active_indexObject

index of active widget

Since:

  • 1.2.0



1548
1549
1550
# File 'lib/canis/core/widgets/rwidget.rb', line 1548

def active_index
  @active_index
end

#attrObject

Since:

  • 1.2.0



1542
1543
1544
# File 'lib/canis/core/widgets/rwidget.rb', line 1542

def attr
  @attr
end

#bgcolorObject

returns form’s bgcolor, or global default.

Since:

  • 1.2.0



2226
2227
2228
# File 'lib/canis/core/widgets/rwidget.rb', line 2226

def bgcolor
  @bgcolor || $def_bg_color
end

#by_nameObject (readonly)

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

lb = @form.by_name["listb"]

Since:

  • 1.2.0



1553
1554
1555
# File 'lib/canis/core/widgets/rwidget.rb', line 1553

def by_name
  @by_name
end

#colObject

cursor row and col

Since:

  • 1.2.0



1538
1539
1540
# File 'lib/canis/core/widgets/rwidget.rb', line 1538

def col
  @col
end

#colorObject

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.

Since:

  • 1.2.0



2222
2223
2224
# File 'lib/canis/core/widgets/rwidget.rb', line 2222

def color
  @color || $def_fg_color
end

#layout_managerObject

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

Since:

  • 1.2.0



1570
1571
1572
# File 'lib/canis/core/widgets/rwidget.rb', line 1570

def layout_manager
  @layout_manager
end

associated menubar

Since:

  • 1.2.0



1556
1557
1558
# File 'lib/canis/core/widgets/rwidget.rb', line 1556

def menu_bar
  @menu_bar
end

#modifiedObject

has the form been modified

Since:

  • 1.2.0



1545
1546
1547
# File 'lib/canis/core/widgets/rwidget.rb', line 1545

def modified
  @modified
end

#nameObject

name given to form for debugging

Since:

  • 1.2.0



1564
1565
1566
# File 'lib/canis/core/widgets/rwidget.rb', line 1564

def name
  @name
end

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.

Since:

  • 1.2.0



1561
1562
1563
# File 'lib/canis/core/widgets/rwidget.rb', line 1561

def navigation_policy
  @navigation_policy
end

#resize_requiredObject

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

Since:

  • 1.2.0



1568
1569
1570
# File 'lib/canis/core/widgets/rwidget.rb', line 1568

def resize_required
  @resize_required
end

#rowObject

cursor row and col

Since:

  • 1.2.0



1538
1539
1540
# File 'lib/canis/core/widgets/rwidget.rb', line 1538

def row
  @row
end

#widgetsObject (readonly)

array of widgets

Since:

  • 1.2.0



1532
1533
1534
# File 'lib/canis/core/widgets/rwidget.rb', line 1532

def widgets
  @widgets
end

#windowObject

related window used for printing

Since:

  • 1.2.0



1535
1536
1537
# File 'lib/canis/core/widgets/rwidget.rb', line 1535

def window
  @window
end

Instance Method Details

#add_widget(widget) ⇒ Object Also known as: add

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)

Since:

  • 1.2.0



1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
# File 'lib/canis/core/widgets/rwidget.rb', line 1637

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

#addcol(num) ⇒ Object

move cursor by num columns. Form

Since:

  • 1.2.0



1953
1954
1955
1956
1957
1958
1959
1960
# File 'lib/canis/core/widgets/rwidget.rb', line 1953

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) ⇒ Object

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

Since:

  • 1.2.0



1964
1965
1966
1967
1968
1969
1970
1971
# File 'lib/canis/core/widgets/rwidget.rb', line 1964

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

#digit_argument(ch) ⇒ Object

Since:

  • 1.2.0



2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
# File 'lib/canis/core/widgets/rwidget.rb', line 2032

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_fieldWidget? Also known as: current_widget

Returns current field, nil if no focusable field.

Returns:

  • (Widget, nil)

    current field, nil if no focusable field

Since:

  • 1.2.0



1723
1724
1725
1726
1727
# File 'lib/canis/core/widgets/rwidget.rb', line 1723

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

#handle_key(ch) ⇒ Object

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.

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

Since:

  • 1.2.0



2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
# File 'lib/canis/core/widgets/rwidget.rb', line 2112

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_managerObject

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.

Since:

  • 1.2.0



2215
2216
2217
2218
# File 'lib/canis/core/widgets/rwidget.rb', line 2215

def help_manager
  require 'canis/core/util/helpmanager'
  @help_manager ||= Canis::HelpManager.new self
end

#map_keysObject

These mappings will only trigger if the current field

does not use them.

Since:

  • 1.2.0



2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
# File 'lib/canis/core/widgets/rwidget.rb', line 2065

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) ⇒ Object

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

Since:

  • 1.2.0



1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
# File 'lib/canis/core/widgets/rwidget.rb', line 1785

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) ⇒ Object

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

Since:

  • 1.2.0



1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
# File 'lib/canis/core/widgets/rwidget.rb', line 1767

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) ⇒ Object

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

Since:

  • 1.2.0



1988
1989
1990
# File 'lib/canis/core/widgets/rwidget.rb', line 1988

def process_key keycode, object
  return _process_key keycode, object, @window
end

#remove_widget(widget) ⇒ Object

remove a widget (internal use)

Since:

  • 1.2.0



1652
1653
1654
1655
1656
1657
1658
# File 'lib/canis/core/widgets/rwidget.rb', line 1652

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

#repaintObject

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

Since:

  • 1.2.0



1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
# File 'lib/canis/core/widgets/rwidget.rb', line 1678

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_widgetsObject

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

Since:

  • 1.2.0



2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
# File 'lib/canis/core/widgets/rwidget.rb', line 2090

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) ⇒ Object

puts focus on the given field/widget index XXX if called externally will not run a on_leave of previous field

Parameters:

  • index

    of field in @widgets (or can be a Widget too)

Since:

  • 1.2.0



1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
# File 'lib/canis/core/widgets/rwidget.rb', line 1806

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_fieldObject

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

Since:

  • 1.2.0



1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
# File 'lib/canis/core/widgets/rwidget.rb', line 1732

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_fieldObject

take focus to last field on form

Since:

  • 1.2.0



1758
1759
1760
1761
# File 'lib/canis/core/widgets/rwidget.rb', line 1758

def select_last_field
  @active_index = nil 
  select_prev_field
end

#select_next_fieldObject

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

Since:

  • 1.2.0



1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
# File 'lib/canis/core/widgets/rwidget.rb', line 1860

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_fieldnil, :NO_PREV_FIELD

put focus on previous field will cycle by default, unless navigation policy not :CYCLICAL in which case returns :NO_PREV_FIELD.

Returns:

  • (nil, :NO_PREV_FIELD)

    nil if cyclical and it finds a field if not cyclical, and no more fields then :NO_PREV_FIELD

Since:

  • 1.2.0



1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
# File 'lib/canis/core/widgets/rwidget.rb', line 1913

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) ⇒ Object

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

Since:

  • 1.2.0



1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
# File 'lib/canis/core/widgets/rwidget.rb', line 1618

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) ⇒ Object

move cursor to where the fields row and col are private

Since:

  • 1.2.0



1715
1716
1717
1718
1719
1720
1721
# File 'lib/canis/core/widgets/rwidget.rb', line 1715

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) ⇒ Object

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

Since:

  • 1.2.0



1976
1977
1978
1979
# File 'lib/canis/core/widgets/rwidget.rb', line 1976

def setrowcol r, c
  @row = r unless r.nil?
  @col = c unless c.nil?
end

#to_sObject

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

Since:

  • 1.2.0



2210
# File 'lib/canis/core/widgets/rwidget.rb', line 2210

def to_s; @name || self; end

#universal_argumentObject

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. by system. ) implies only numeric args were obtained. This method updates $multiplier

Since:

  • 1.2.0



1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
# File 'lib/canis/core/widgets/rwidget.rb', line 1998

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_focusablesObject

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

Since:

  • 1.2.0



1662
1663
1664
1665
# File 'lib/canis/core/widgets/rwidget.rb', line 1662

def update_focusables
  $log.debug "XXX:  inside update focusables"
  @focusable_modified = true
end

#validate_field(f = ) ⇒ 0, -1

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 NOTE : catches exception and sets $error_message, check if -1

Returns:

  • (0, -1)

    for success or failure

Since:

  • 1.2.0



1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
# File 'lib/canis/core/widgets/rwidget.rb', line 1843

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