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



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
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1301

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



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

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



1295
1296
1297
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1295

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



1296
1297
1298
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1296

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



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

def by_name
  @by_name
end

#colObject

cursor row and col

Since:

  • 1.2.0



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

def col
  @col
end

#cols_pannedObject

how many cols the component is panning embedded widget by

Since:

  • 1.2.0



1291
1292
1293
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1291

def cols_panned
  @cols_panned
end

associated menubar

Since:

  • 1.2.0



1281
1282
1283
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1281

def menu_bar
  @menu_bar
end

#modifiedObject

has the form been modified

Since:

  • 1.2.0



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

def modified
  @modified
end

#nameObject

name given to form for debugging

Since:

  • 1.2.0



1299
1300
1301
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1299

def name
  @name
end

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

Since:

  • 1.2.0



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

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



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

def parent_form
  @parent_form
end

#rowObject

cursor row and col

Since:

  • 1.2.0



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

def row
  @row
end

#rows_pannedObject

how many rows the component is panning embedded widget by

Since:

  • 1.2.0



1289
1290
1291
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1289

def rows_panned
  @rows_panned
end

#valueObject (readonly)

???

Since:

  • 1.2.0



1257
1258
1259
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1257

def value
  @value
end

#widgetsObject (readonly)

array of widgets

Since:

  • 1.2.0



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

def widgets
  @widgets
end

#windowObject

related window used for printing

Since:

  • 1.2.0



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

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



1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1362

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



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

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



1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1685

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



1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1908

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



1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1766

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



1516
1517
1518
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1516

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



1426
1427
1428
1429
1430
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1426

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



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
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1825

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



1969
1970
1971
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1969

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



1461
1462
1463
1464
1465
1466
1467
1468
1469
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1461

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



1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1799

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



1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1954

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



1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1499

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



1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1482

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



1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1934

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



1722
1723
1724
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1722

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



1378
1379
1380
1381
1382
1383
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1378

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



1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1386

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



1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1522

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



1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1434

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



1471
1472
1473
1474
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1471

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



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
1614
1615
1616
1617
1618
1619
1620
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1572

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



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
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1627

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



1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1343

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



1925
1926
1927
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1925

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



1418
1419
1420
1421
1422
1423
1424
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1418

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



1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1701

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



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

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



1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1732

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



1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
# File 'lib/rbcurse/core/widgets/rwidget.rb', line 1555

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