Class: RubyCurses::Form

Inherits:
Object show all
Includes:
EventHandler, Utils
Defined in:
lib/rbcurse/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.

Direct Known Subclasses

ScrollForm

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Utils

#_process_key, #bind_key, #clean_string!, #get_color, #keycode_tos, #repeatm, #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.



987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
# File 'lib/rbcurse/rwidget.rb', line 987

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

Instance Attribute Details

#active_indexObject

index of active widget



961
962
963
# File 'lib/rbcurse/rwidget.rb', line 961

def active_index
  @active_index
end

#add_colsObject

next 2 added since tabbedpanes offset needs to be accounted by form inside it.



981
982
983
# File 'lib/rbcurse/rwidget.rb', line 981

def add_cols
  @add_cols
end

#add_rowsObject

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



982
983
984
# File 'lib/rbcurse/rwidget.rb', line 982

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.


965
966
967
# File 'lib/rbcurse/rwidget.rb', line 965

def by_name
  @by_name
end

#colObject

cursor row and col



953
954
955
# File 'lib/rbcurse/rwidget.rb', line 953

def col
  @col
end

#cols_pannedObject

how many cols the component is panning embedded widget by



978
979
980
# File 'lib/rbcurse/rwidget.rb', line 978

def cols_panned
  @cols_panned
end

associated menubar



968
969
970
# File 'lib/rbcurse/rwidget.rb', line 968

def menu_bar
  @menu_bar
end

#modifiedObject

has the form been modified



958
959
960
# File 'lib/rbcurse/rwidget.rb', line 958

def modified
  @modified
end

#nameObject

name given to form for debugging



985
986
987
# File 'lib/rbcurse/rwidget.rb', line 985

def name
  @name
end

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



970
971
972
# File 'lib/rbcurse/rwidget.rb', line 970

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



973
974
975
# File 'lib/rbcurse/rwidget.rb', line 973

def parent_form
  @parent_form
end

#rowObject

cursor row and col



953
954
955
# File 'lib/rbcurse/rwidget.rb', line 953

def row
  @row
end

#rows_pannedObject

how many rows the component is panning embedded widget by



976
977
978
# File 'lib/rbcurse/rwidget.rb', line 976

def rows_panned
  @rows_panned
end

#valueObject (readonly)

???



944
945
946
# File 'lib/rbcurse/rwidget.rb', line 944

def value
  @value
end

#widgetsObject (readonly)

array of widgets



947
948
949
# File 'lib/rbcurse/rwidget.rb', line 947

def widgets
  @widgets
end

#windowObject

related window used for printing



950
951
952
# File 'lib/rbcurse/rwidget.rb', line 950

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.



1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
# File 'lib/rbcurse/rwidget.rb', line 1046

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



1344
1345
1346
1347
1348
1349
1350
1351
# File 'lib/rbcurse/rwidget.rb', line 1344

def addcol num
  return if @col.nil? or @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



1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
# File 'lib/rbcurse/rwidget.rb', line 1355

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.



1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
# File 'lib/rbcurse/rwidget.rb', line 1550

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



1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
# File 'lib/rbcurse/rwidget.rb', line 1436

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)


1191
1192
1193
# File 'lib/rbcurse/rwidget.rb', line 1191

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



1108
1109
1110
1111
1112
# File 'lib/rbcurse/rwidget.rb', line 1108

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



1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
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
1536
1537
1538
1539
1540
1541
# File 'lib/rbcurse/rwidget.rb', line 1473

def handle_key(ch)
  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}  "
        alert "SIGWINCH WE NEED TO RECALC AND REPAINT resize #{lines}, #{cols}: #{x}, #{y} "
        Ncurses.endwin
        @window.wrefresh
      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}  "
        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
end

#index_of_first_focusable_fieldObject

return the offset of first field that takes focus



1143
1144
1145
1146
1147
1148
1149
1150
1151
# File 'lib/rbcurse/rwidget.rb', line 1143

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

#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



1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
# File 'lib/rbcurse/rwidget.rb', line 1595

def 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



1181
1182
1183
1184
1185
1186
1187
1188
# File 'lib/rbcurse/rwidget.rb', line 1181

def on_enter f
  return if f.nil? || !f.focusable # added focusable, else label was firing 2010-09
  f.state = :HIGHLIGHTED
  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


1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
# File 'lib/rbcurse/rwidget.rb', line 1164

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



1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
# File 'lib/rbcurse/rwidget.rb', line 1576

def place_below me, other=nil
  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



1392
1393
1394
# File 'lib/rbcurse/rwidget.rb', line 1392

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


1062
1063
1064
1065
1066
1067
# File 'lib/rbcurse/rwidget.rb', line 1062

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.



1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
# File 'lib/rbcurse/rwidget.rb', line 1070

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



1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
# File 'lib/rbcurse/rwidget.rb', line 1197

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

    f.curpos = 0
    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



1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
# File 'lib/rbcurse/rwidget.rb', line 1116

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



1153
1154
1155
1156
# File 'lib/rbcurse/rwidget.rb', line 1153

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



1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
# File 'lib/rbcurse/rwidget.rb', line 1242

def select_next_field
  return :UNHANDLED if @widgets.nil? or @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



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

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 ?



1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
# File 'lib/rbcurse/rwidget.rb', line 1027

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



1567
1568
1569
# File 'lib/rbcurse/rwidget.rb', line 1567

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



1100
1101
1102
1103
1104
1105
1106
# File 'lib/rbcurse/rwidget.rb', line 1100

def setpos r=@row, c=@col
  $log.debug "setpos : (#{self}) #{r} #{c}"
  ## 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.



1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
# File 'lib/rbcurse/rwidget.rb', line 1371

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}  "
  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.



1571
# File 'lib/rbcurse/rwidget.rb', line 1571

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



1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
# File 'lib/rbcurse/rwidget.rb', line 1402

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



1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
# File 'lib/rbcurse/rwidget.rb', line 1225

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