class Canis::Container

This is an attempt at having a container which can contain multiple widgets without being a form itself. Having forms within forms complicates code too much, esp cursor positioning. e.g. tabbedpane

Attributes

current_component[R]

Public Class Methods

new(form=nil, config={}) click to toggle source
Calls superclass method
# File lib/canis/core/widgets/rcontainer.rb, line 47
def initialize form=nil, config={}, &block
  @suppress_borders = false
  @row_offset = @col_offset = 1
  @_events ||= []
  @stack = true
  @positioning = :stack
  super
  @focusable = true
  @editable = false
  @components = [] # all components
  @focusables = [] # focusable components, makes checks easier

  init_vars
end

Public Instance Methods

add(*items) click to toggle source

NOTE: since we are handling the traversal, we delink the object from any form's widgets array that might have been added. Whenever a form is available, we set it (without adding widget to it) so it can print using the form's window.

@param [Widget] to add

# File lib/canis/core/widgets/rcontainer.rb, line 77
def add *items
  items.each do |c|  
    raise ArgumentError, "Nil component passed to add" unless c
    if c.is_a? Widget
      if c.form && c.form != @form
        $log.debug " removing widget VIMSPLIT #{c.class} wr:  #{c.row} row:#{@row} ht:#{@height} "
        c.form.remove_widget c
        c.form = nil
        # or should i just stack them myself and screw what you've asked for
      end
      # take it out of form's control. We will control it.
      if c.form
        c.form.remove_widget c
      end
      # shoot, what if at this point the container does not have a form
      attach_form c if @form
    end
    # most likely if you have created both container and widgets
    # inside app, it would have given row after container

    @components << c
    if c.focusable
      @focusables << c 
      @current_component ||= c # only the first else cursor falls on last on enter
    end

  end # items each
  self
end
Also aliased as: add_widget
add_widget(*items)
Alias for: add
attach_form(c) click to toggle source

When we get a form, we silently attach it to this object, without the form

knowing. We don't want form managing this object.
# File lib/canis/core/widgets/rcontainer.rb, line 109
def attach_form c
  c.form = @form
  c.override_graphic @graphic
  c.parent_component = self
end
check_component(c) click to toggle source
# File lib/canis/core/widgets/rcontainer.rb, line 163
def check_component c
  raise "row is less than container #{c.row} #{@row} " if c.row <= @row
  raise "col is less than container #{c.col} #{@col} " if c.col <= @col
end
correct_component(c) click to toggle source

correct coordinates of comp esp if App has stacked them after this container It is best to use the simple stack feature. The rest could change at any time

and is quite arbitrary. Some folks may set absolute locations if container
is directly on a form, others may set relative locations if it is inside a 
tabbed pane or other container. Thus, stacks are best
# File lib/canis/core/widgets/rcontainer.rb, line 125
def correct_component c
  raise "Form is still not set in Container" unless @form
  attach_form(c) unless c.form
  @last_row ||= @row + 1
  inset = 2
  # 2011-10-20 current default behaviour is to stack
  if @positioning == :stack
    c.row = @last_row
    c.col = @col + inset

    # do not advance row, save col for next row
    @last_row += 1
  elsif @positioning == :relative   # UNTESTED NOTE
    if (c.row || 0) <= 0
      $log.warn "c.row in CONTAINER is #{c.row} "
      c.row = @last_row
      @last_row += 1
    elsif c.row > @row + @height -1
      $log.warn "c.row in CONTAINER exceeds container.  #{c.row} "
      c.row -= @height - @row_offset
    else
      # this is where it should come
      c.row += @row + @row_offset
      @last_row = c.row + 1
    end
    if (c.col || 0) <= 0
      c.col = @col + inset + @col_offset
    elsif c.col > @col + @width -1
      c.col -= @width
    elsif c.col == @col
      c.col += @col_offset + inset
    else #f c.col < @col
      c.col += @col+@col_offset
    end
  $log.debug "XXX: CORRECT #{c.name}  r:#{c.row} c:#{c.col} "
  end
  @first_time = false
end
goto_component(comp) click to toggle source

set focus on given component Sometimes you have the handle to component, and you want to move focus to it

# File lib/canis/core/widgets/rcontainer.rb, line 385
def goto_component comp
  return if comp == @current_component
  leave_current_component
  @current_component = comp
  set_form_row
end
goto_next_component() click to toggle source
# File lib/canis/core/widgets/rcontainer.rb, line 299
def goto_next_component
  if @current_component != nil 
    leave_current_component
    if on_last_component?
      #@_entered = false
      return :UNHANDLED
    end
    @current_index = @focusables.index(@current_component)
    index = @current_index + 1
    f = @focusables[index]
    if f
      @current_index = index
      @current_component = f
      return set_form_row
    end
  end
  @_entered = false
  return :UNHANDLED
end
goto_prev_component() click to toggle source
# File lib/canis/core/widgets/rcontainer.rb, line 318
def goto_prev_component
  if @current_component != nil 
    leave_current_component
    if on_first_component?
      @_entered = false
      return :UNHANDLED
    end
    @current_index = @focusables.index(@current_component)
    index = @current_index -= 1
    f = @focusables[index]
    if f
      @current_index = index
      @current_component = f
      return set_form_row
    end
  end
  return :UNHANDLED
end
handle_key(ch) click to toggle source

called by parent or form, otherwise its private

# File lib/canis/core/widgets/rcontainer.rb, line 211
def handle_key ch
  $log.debug " CONTAINER handle_key #{ch} "
  return if @components.empty?
  _multiplier = ($multiplier == 0 ? 1 : $multiplier )

  # should this go here 2011-10-19
  unless @_entered
    $log.warn "XXX WARN: calling ON_ENTER since in this situation it was not called"
    on_enter
  end
  if ch == KEY_TAB
    $log.debug "CONTAINER GOTO NEXT TAB"
    return goto_next_component
  elsif ch == KEY_BTAB
    return goto_prev_component
  end
  comp = @current_component
  $log.debug " CONTAINER handle_key #{ch}: #{comp}" 
  if comp
    ret = comp.handle_key(ch) 
    $log.debug " CONTAINER handle_key#{ch}: #{comp} returned #{ret} " 
    if ret != :UNHANDLED
      comp.repaint # NOTE: if we don;t do this, then it won't get repainted. I will have to repaint ALL
      # in repaint of this.
      return ret 
    end
    $log.debug "XXX CONTAINER key unhandled by comp #{comp.name} "
  else
    $log.warn "XXX CONTAINER key unhandled NULL comp"
  end
  case ch
  when ?\C-c.getbyte(0)
    $multiplier = 0
    return 0
  when ?0.getbyte(0)..?9.getbyte(0)
    $log.debug " VIM coming here to set multiplier #{$multiplier} "
    $multiplier *= 10 ; $multiplier += (ch-48)
    return 0
  end
  ret = process_key ch, self
  # allow user to map left and right if he wants
  if ret == :UNHANDLED
    case ch
    when KEY_UP
      # form will pick this up and do needful
      return goto_prev_component #unless on_first_component?
    when KEY_LEFT
      # if i don't check for first component, key will go back to form,
      # but not be processes. so focussed remain here, but be false.
      # In case of returnign an unhandled TAB, on_leave will happen and cursor will move to
      # previous component outside of this.
      return goto_prev_component unless on_first_component?
    when KEY_RIGHT
      return goto_next_component #unless on_last_component?
    when KEY_DOWN
      return goto_next_component #unless on_last_component?
    else 
      @_entered = false
      return :UNHANDLED
    end
  end

  $multiplier = 0
  return 0
end
init_vars() click to toggle source
# File lib/canis/core/widgets/rcontainer.rb, line 61
def init_vars
  @repaint_required = true
  @row_offset = @col_offset = 0 if @suppress_borders # FIXME supposed to use this !!

  @internal_width = 2
  @internal_width = 1 if @suppress_borders
  @name ||= "AContainer"
  @first_time = true

end
leave_current_component() click to toggle source

leave the component we are on. This should be followed by all containers, so that the on_leave action of earlier comp can be displayed, such as dimming components selections

# File lib/canis/core/widgets/rcontainer.rb, line 365
def leave_current_component
  @current_component.on_leave
  # NOTE this is required, since repaint will just not happen otherwise
  # Some components are erroneously repainting all, after setting this to true so it is
  # working there.
  @current_component.repaint_required true
  $log.debug " after on_leave RCONT XXX #{@current_component.focussed}   #{@current_component.name}"
  @current_component.repaint
end
on_enter() click to toggle source

Actually we should only go to current component if it accepted a key stroke. if user tabbed thru it, then no point going back to it. Go to first or last depending on TAB or BACKTAB otherwise. NOTE: if user comes in using DOWN or UP, last traversed component will get the focus

# File lib/canis/core/widgets/rcontainer.rb, line 281
def on_enter
  # if BTAB, the last comp XXX they must be focusable FIXME
  if $current_key == KEY_BTAB || $current_key == KEY_UP
    @current_component = @focusables.last
  else
    @current_component = @focusables.first
  end
  return unless @current_component
  $log.debug " CONTAINER came to ON_ENTER #{@current_component} "
  set_form_row
  @_entered = true
end
on_first_component?() click to toggle source

is focus on first component FIXME check for focusable

# File lib/canis/core/widgets/rcontainer.rb, line 376
def on_first_component?
  @current_component == @focusables.first
end
on_last_component?() click to toggle source

is focus on last component FIXME check for focusable

# File lib/canis/core/widgets/rcontainer.rb, line 380
def on_last_component?
  @current_component == @focusables.last
end
on_leave() click to toggle source

we cannot be sure that this will be called especially if this is embedded inside some other component

Calls superclass method
# File lib/canis/core/widgets/rcontainer.rb, line 295
def on_leave
  @_entered = false
  super
end
repaint() click to toggle source

repaint object called by Form, and sometimes parent component (if not form).

# File lib/canis/core/widgets/rcontainer.rb, line 171
def repaint
  my_win = @form ? @form.window : @target_window
  @graphic = my_win unless @graphic
  raise " #{@name} NO GRAPHIC set as yet                 CONTAINER paint " unless @graphic
  @components.each { |e| correct_component e } if @first_time
  #@components.each { |e| check_component e } # seeme one if printing out

  #return unless @repaint_required

  # if some major change has happened then repaint everything
  if @repaint_required
    $log.debug " VIM repaint graphic #{@graphic} "
    print_borders unless @suppress_borders # do this once only, unless everything changes
    @components.each { |e| e.repaint_all(true); e.repaint }
  else
    @components.each { |e| e.repaint }
  end # if repaint_required

  @repaint_required = false
end
set_form_col() click to toggle source
# File lib/canis/core/widgets/rcontainer.rb, line 356
def set_form_col
  return if @current_component.nil?
  $log.debug " #{@name} CONTAINER EMPTY set_form_col calling sfc for #{@current_component.name} "
  # already called from above.
  #@current_component.set_form_col
end
set_form_row() click to toggle source

private XXX why are we calling 3 methods in a row, why not OE manages these 3 There's double calling going on.

# File lib/canis/core/widgets/rcontainer.rb, line 339
def set_form_row
  return :UNHANDLED if @current_component.nil?
  cc = @current_component
  $log.debug "CONT #{@name} set_form_row calling sfr for #{cc.name}, r #{cc.row} c: #{cc.col} "
  $log.debug " CONTAINER on enter sfr #{@current_component.name}  #{@current_component} "

  # bug caught here. we were printing a field before it had been set, so it printed out
  @components.each { |e| correct_component e } if @first_time
  @current_component.on_enter
  @current_component.set_form_row # why was this missing in vimsplit. is it
    $log.debug "CONT2 #{@name} set_form_row calling sfr for #{cc.name}, r #{cc.row} c: #{cc.col} "
  # that on_enter does a set_form_row
  @current_component.set_form_col # XXX
  @current_component.repaint # OMG this could happen before we've set row and col
  # XXX compo should do set_form_row and col if it has that
end
widgets() click to toggle source
# File lib/canis/core/widgets/rcontainer.rb, line 115
def widgets; @components; end

Private Instance Methods

print_borders() click to toggle source
print_title() click to toggle source