Class: RubyCurses::Form

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

Overview

TODO: we don’t have an event for when form is entered and exited. Current ENTER and LEAVE are for when any widgt is entered, so a common event can be put for all widgets in one place.

Since:

  • 1.2.0

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Utils

#OLDdefine_key, #_process_key, #bind_key, #bind_keys, #clean_string!, #define_key, #define_prefix_command, #display_app_help, #get_attrib, #get_color, #keycode_tos, #last_line, #one_line_window, #parse_formatted_text, #print_key_bindings, #repeatm, #run_command, #shell_out, #shell_output, #suspend, #view, #wrap_text

Methods included from EventHandler

#bind, #fire_handler, #fire_property_change

Constructor Details

#initialize(win, &block) ⇒ Form

Returns a new instance of Form.

Since:

  • 1.2.0



1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1289

def initialize win, &block
  @window = win
  @widgets = []
  @by_name = {}
  @active_index = -1
  @row = @col = -1
  @add_cols = @add_rows = 0 # 2010-01-26 20:28  CLEANUP
  @handler = {}
  @modified = false
  @focusable = true
  @navigation_policy ||= :CYCLICAL
  @_events = [:ENTER, :LEAVE, :RESIZE]
  instance_eval &block if block_given?
  ## I need some counter so a widget knows it has been panned and can send a correct
  ##+ cursor coordinate to system.
  @rows_panned = @cols_panned = 0 # how many rows were panned, typically at a higher level
  @_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 ||= :vim ## :emacs or :vim, keys to be defined accordingly. TODO

  bind_key(KEY_F1, 'help') { hm = help_manager(); hm.display_help }
end

Instance Attribute Details

#active_indexObject

index of active widget

Since:

  • 1.2.0



1262
1263
1264
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1262

def active_index
  @active_index
end

#add_colsObject

next 2 added since tabbedpanes offset needs to be accounted by form inside it. NOTE: if you set a form inside another set parent_form in addition to these 2.

Since:

  • 1.2.0



1283
1284
1285
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1283

def add_cols
  @add_cols
end

#add_rowsObject

2010-01-26 20:23 additional columns due to being placed in some container

Since:

  • 1.2.0



1284
1285
1286
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1284

def add_rows
  @add_rows
end

#by_nameObject (readonly)

hash containing widgets by name for retrieval

Useful if one widget refers to second before second created.

Since:

  • 1.2.0



1266
1267
1268
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1266

def by_name
  @by_name
end

#colObject

cursor row and col

Since:

  • 1.2.0



1254
1255
1256
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1254

def col
  @col
end

#cols_pannedObject

how many cols the component is panning embedded widget by

Since:

  • 1.2.0



1279
1280
1281
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1279

def cols_panned
  @cols_panned
end

associated menubar

Since:

  • 1.2.0



1269
1270
1271
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1269

def menu_bar
  @menu_bar
end

#modifiedObject

has the form been modified

Since:

  • 1.2.0



1259
1260
1261
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1259

def modified
  @modified
end

#nameObject

name given to form for debugging

Since:

  • 1.2.0



1287
1288
1289
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1287

def name
  @name
end

:CYCLICAL will cycle around. Needed to move to other tabs

Since:

  • 1.2.0



1271
1272
1273
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1271

def navigation_policy
  @navigation_policy
end

#parent_formObject

i need some way to move the cursor by telling the main form what the coords are + perhaps this will work

Since:

  • 1.2.0



1274
1275
1276
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1274

def parent_form
  @parent_form
end

#rowObject

cursor row and col

Since:

  • 1.2.0



1254
1255
1256
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1254

def row
  @row
end

#rows_pannedObject

how many rows the component is panning embedded widget by

Since:

  • 1.2.0



1277
1278
1279
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1277

def rows_panned
  @rows_panned
end

#valueObject (readonly)

???

Since:

  • 1.2.0



1245
1246
1247
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1245

def value
  @value
end

#widgetsObject (readonly)

array of widgets

Since:

  • 1.2.0



1248
1249
1250
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1248

def widgets
  @widgets
end

#windowObject

related window used for printing

Since:

  • 1.2.0



1251
1252
1253
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1251

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.

Since:

  • 1.2.0



1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1350

def add_widget widget
  # this help to access widget by a name
  if widget.respond_to? :name and !widget.name.nil?
    ##$log.debug "NAME #{self} adding a widget #{@widgets.length} .. #{widget.name} "
    @by_name[widget.name] = widget
  end


  #$log.debug " #{self} adding a widget #{@widgets.length} .. #{widget} "
  @widgets << widget
  return @widgets.length-1
end

#addcol(num) ⇒ Object

move cursor by num columns. Form

Since:

  • 1.2.0



1662
1663
1664
1665
1666
1667
1668
1669
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1662

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



1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1673

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
  # added on 2010-01-05 22:26 so component widgets like scrollpane can get the cursor
  if !@parent_form.nil? and @parent_form != @form
    $log.debug " #{@name} addrowcol calling parents setrowcol #{row}, #{col}  "
    @parent_form.setrowcol row, col
  end
end

#DEPRECATED_dump_dataObject

test program to dump data onto log The problem I face is that since widget array contains everything that should be displayed I do not know what all the user wants - what are his data entry fields. A user could have disabled entry on some field after modification, so i can’t use focusable or editable as filters. I just dump everything? What’s more, currently getvalue has been used by paint to return what needs to be displayed - at least by label and button.

Since:

  • 1.2.0



1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1896

def DEPRECATED_dump_data # CLEAN
  $log.debug "DEPRECATED DUMPING DATA "
  @widgets.each do |w|
    # we need checkbox and radio button values
    #next if w.is_a? RubyCurses::Button or w.is_a? RubyCurses::Label 
    next if w.is_a? RubyCurses::Label 
    next if !w.is_a? RubyCurses::Widget
    if w.respond_to? :getvalue
      $log.debug " #{w.name} #{w.getvalue}"
    else
      $log.debug " #{w.name} DOES NOT RESPOND TO getvalue"
    end
  end
  $log.debug " END DUMPING DATA "
end

#digit_argument(ch) ⇒ Object

Since:

  • 1.2.0



1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1754

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

#focusable?(f) ⇒ Boolean

is a field focusable Added a method here, so forms can extend this to avoid focussing on off-screen components

Returns:

  • (Boolean)

Since:

  • 1.2.0



1504
1505
1506
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1504

def focusable?(f)
  return f.focusable
end

#get_current_fieldWidget?

Returns current field, nil if no focusable field.

Returns:

  • (Widget, nil)

    current field, nil if no focusable field

Since:

  • 1.2.0



1414
1415
1416
1417
1418
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1414

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



1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
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
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1813

def handle_key(ch)
  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 Ncurses::KEY_RESIZE # SIGWINCH
      when FFI::NCurses::KEY_RESIZE # SIGWINCH #  FFI
        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}  "
        #alert "SIGWINCH WE NEED TO RECALC AND REPAINT resize #{lines}, #{cols}: #{x}, #{y} "
        Ncurses.endwin
        @window.wrefresh
        @widgets.each { |e| e.repaint_all(true) } # trying out
        ## 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
            $log.debug "FORM process_key #{ch} got ret #{ret} in #{self} "
            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



1957
1958
1959
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1957

def help_manager
  @help_manager ||= HelpManager.new self
end

#index_of_first_focusable_fieldObject

return the offset of first field that takes focus

Since:

  • 1.2.0



1449
1450
1451
1452
1453
1454
1455
1456
1457
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1449

def index_of_first_focusable_field
  @widgets.each_with_index do |f, i| 
    if focusable?(f)
      #select_field i
      return i
    end
  end
  nil
end

#map_keysObject

These mappings will only trigger if the current field

does not use them.

Since:

  • 1.2.0



1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1787

def map_keys
  return if @keys_mapped
  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

#next_positionObject

NOTE: very experimental, use at risk, can change location or be deprec return location to place next widget (below) Does not check for availability or overlap

Since:

  • 1.2.0



1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1942

def next_position
  $log.warn "WARN  deprecated form next_position"
  w = widgets.last
  if w.height.nil? || w.height == 0
    h = 1
  else
    h = w.height
  end
  row = w.row + h
  col = w.col
  return row, col
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



1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1487

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_background || f.highlight_foreground
    f.repaint_required true
  end

  f.modified false
  #f.set_modified false
  f.on_enter if f.respond_to? :on_enter
  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



1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1470

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
  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

#place_below(me, other = nil) ⇒ Object

NOTE: very experimental, use at risk, can change location or be deprec place given widget below given one, or last added one Does not check for availability or overlap

Since:

  • 1.2.0



1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1922

def place_below me, other=nil
  $log.warn "WARN deprecated form place_below"
  w = widgets
  if other.nil?
    other = w[-1]
    # if user calls this after placing this field
    other = w[-2] if other == me
  end
  if other.height.nil? || other.height == 0
    h = 1
  else
    h = other.height
  end
  me.row = other.row + h
  me.col = other.col
  me
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



1710
1711
1712
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1710

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

#remove_widget(widget) ⇒ Object

remove a widget

added 2008-12-09 12:18

Since:

  • 1.2.0



1366
1367
1368
1369
1370
1371
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1366

def remove_widget widget
  if widget.respond_to? :name and !widget.name.nil?
    @by_name.delete(widget.name)
  end
  @widgets.delete widget
end

#repaintObject

form repaint to be called at some interval, such as after each keypress.

Since:

  • 1.2.0



1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1374

def repaint
  $log.debug " form repaint:#{self}, #{@name} , r #{@row} c #{@col} " if $log.debug? 
  @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
  #  this can bomb if someone sets row. We need a better way!
  if @row == -1 and @_firsttime == true
    #set_field_cursor 0
    #  this part caused an endless loop on 2010-01-02 19:20 when scrollpane scrolled up
    #$log.debug "form repaint calling select field 0 SHOULD HAPPEN FIRST TIME ONLY"
    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

#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

Since:

  • 1.2.0



1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1510

def select_field ix0
  return if @widgets.nil? or @widgets.empty? or !focusable?(@widgets[ix0])
 #$log.debug "inside select_field :  #{ix0} ai #{@active_index}" 
  f = @widgets[ix0]
  if focusable?(f)
    @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 Also known as: req_first_field

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



1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1422

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 =  index_of_first_focusable_field()
  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 req_first_field on_leave #{err}"
     Ncurses.beep
     #$error_message = "#{err}"
     $error_message.value = "#{err}"
     return
    end
  end
  select_field ix
end

#select_last_fieldObject Also known as: req_last_field

take focus to last field on form

Since:

  • 1.2.0



1459
1460
1461
1462
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1459

def select_last_field
  @active_index = nil 
  select_prev_field
end

#select_next_fieldObject Also known as: req_next_field

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



1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
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
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1560

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
    @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
  index = @active_index + 1
  index.upto(@widgets.length-1) do |i|
    f = @widgets[i]
    #$log.debug "insdie sele nxt field :  i #{i}  #{index} WL:#{@widgets.length}, field #{f}" 
    if focusable?(f)
      select_field i
      return 0
    end
  end
  #req_first_field
  #$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
    @active_index = nil
    # recursive call worked, but bombed if no focusable field!
    #select_next_field
    0.upto(index-1) do |i|
      f = @widgets[i]
      if focusable?(f)
        select_field i
        return 0
      end
    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 Also known as: req_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



1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1615

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

  index = @active_index - 1
  (index).downto(0) do |i|
    f = @widgets[i]
    if focusable?(f)
      select_field i
      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
    @active_index = nil # HACK !!!
    #select_prev_field
    total = @widgets.length-1
    total.downto(index-1) do |i|
      f = @widgets[i]
      if focusable?(f)
        select_field i
        return
      end
    end
  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



1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1331

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

#set_parent_buffer(b) ⇒ Object

trying out for splitpane and others who have a sub-form. TabbedPane uses

Since:

  • 1.2.0



1913
1914
1915
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1913

def set_parent_buffer b
  @parent_buffer = b
end

#setpos(r = @row, c = @col) ⇒ Object

move cursor to where the fields row and col are private

Since:

  • 1.2.0



1406
1407
1408
1409
1410
1411
1412
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1406

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



1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1689

def setrowcol r, c
  @row = r unless r.nil?
  @col = c unless c.nil?
  r +=  @add_rows unless r.nil? # 2010-01-26 20:31 
  c +=  @add_cols unless c.nil? # 2010-01-26 20:31 
  $log.debug " addcols #{@add_cols} addrow #{@add_rows} : #{self} r = #{r} , c = #{c}, parent: #{@parent_form}  "
  if !@parent_form.nil? and @parent_form != self
    $log.debug " (#{@name}) addrow calling parents setrowcol #{r}, #{c} : pare: #{@parent_form}; self:  #{self}, #{self.class}  "
    #r += @parent_form.window.top unless  r.nil?
    #c += @parent_form.window.left unless c.nil?
    @parent_form.setrowcol r, c
  end
end

#to_sObject

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

Since:

  • 1.2.0



1917
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1917

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



1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1720

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

#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



1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1543

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