class RubyCurses::StackFlow

This is a more advanced version of container which allows user to stack or flow components, including embedding stacks within flows and viceversa.

Attributes

components[R]
current_component[R]
should container stack objects ignoring users row col
this is esp needed since App sets row and col which is too early
This is now the default value, till i can redo things

dsl_accessor :stack

Public Class Methods

new(form=nil, config={}) click to toggle source
Calls superclass method
# File lib/canis/core/widgets/extras/stackflow.rb, line 60
def initialize form=nil, config={}, &block
  @row_offset = @col_offset = 1
  @focusable = false
  @editable = false
  @components = [] # all components
  @focusables = [] # focusable components, makes checks easier
  @active     = []
  super

  init_vars
end

Public Instance Methods

decrease_current() click to toggle source
# File lib/canis/core/widgets/extras/stackflow.rb, line 416
def decrease_current
  c = @current_component
  p = c.config[:parent]
  $log.debug "XXX: INC increase current #{c} , #{p} "
  p.decrease c
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/extras/stackflow.rb, line 403
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/extras/stackflow.rb, line 318
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/extras/stackflow.rb, line 337
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/extras/stackflow.rb, line 227
def handle_key ch
  $log.debug " STACKFLOW 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 "STACKFLOW GOTO NEXT TAB"
    return goto_next_component
  elsif ch == KEY_BTAB
    return goto_prev_component
  end
  comp = @current_component
  $log.debug " STACKFLOW handle_key #{ch}: #{comp}" 
  if comp
    ret = comp.handle_key(ch) 
    $log.debug " STACKFLOW 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 STACKFLOW key unhandled by comp #{comp.name} "
  else
    $log.warn "XXX STACKFLOW 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
increase_current() click to toggle source
# File lib/canis/core/widgets/extras/stackflow.rb, line 410
def increase_current
  c = @current_component
  p = c.config[:parent]
  $log.debug "XXX: INC increase current #{c} , #{p} "
  p.increase c
end
init_vars() click to toggle source
# File lib/canis/core/widgets/extras/stackflow.rb, line 71
def init_vars
  @repaint_required = true
  @ctr = 0

  @name ||= "a_stackflow"
  #raise "NO components !" if @components.empty?
  calc_weightages2(@components, self) # FIXME this needs to move to basestack

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/extras/stackflow.rb, line 379
def leave_current_component
  begin
    @current_component.on_leave
  rescue FieldValidationException => fve
    alert fve.to_s
  end
  # 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 STACKFLOW 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/extras/stackflow.rb, line 297
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
  elsif $current_key == KEY_TAB || $current_key == KEY_DOWN
    @current_component = @focusables.first
  else
    # let current component be, since an unhandled key may have resulted
    #  in on_enter being called again
  end
  return unless @current_component
  $log.debug " STACKFLOW 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/extras/stackflow.rb, line 394
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/extras/stackflow.rb, line 398
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/extras/stackflow.rb, line 314
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/extras/stackflow.rb, line 136
def repaint # stackflow
  my_win = @form ? @form.window : @target_window
  @graphic = my_win unless @graphic
  raise " #{@name} NO GRAPHIC set as yet                 STACKFLOW paint " unless @graphic
  # actually at this level we don't have margins set -- not yet.
  @margin_left   ||= 0
  @margin_right  ||= 0
  @margin_top    ||= 0
  @margin_bottom ||= 0
  r  = @row + @row_offset + @margin_top
  c  = @col + @col_offset + @margin_left
  ht = @height-2-(@margin_top + @margin_bottom)
  wd = @width -2-(@margin_left + @margin_right)
  # should this not happen only if repaint_required ?
  @components.each { |e| 
    e.parent_component = self
    e.row              = r
    e.col              = c
    # check that we are not trying to print outside bounds
    # by default we are stacking top level comps regardless of stack or flow
    #  otherwise too complicated
    if e.is_a? BaseStack 
      # using ||= allows us to use overrides given by user
      # but disallows us from calculating if size changes
        e.height           = (ht) * (e.weight * 0.01)
        e.height           = e.height.round 
        e.width            = wd 
        if e.row + e.height >= @row + @height
          #alert "is exceeding #{e.row} #{e.height} > #{@row} + #{@height} "
          e.height = @height - e.row - 1
        end
        r += e.height
        $log.debug "XXX: STACK r:#{e.row} e.h: #{e.height} w:#{e.weight} h: #{@height} "
      #if e.type == :flow
        #e.height           ||= (@height-2) * (e.weight * 0.01)
        #e.height           = e.height.round
        #e.width            ||= (@width-2)
        #r += e.height
      #elsif e.type == :stack
        #e.width            ||= (@width-2) * (e.weight * 0.01)
        #e.width            = e.width.round
        #e.height           ||= (@height-2)
        #c += e.width
      #end
    end
    check_coords e
    attach_form e unless e.form
  } # seeme one if printing out
  last = @components.last
  if last.row + last.height < @row + @height
    last.height += 1 # @row + @height - last.row + last.height
  end

  # if some major change has happened then repaint everything
  # if multiple components then last row and col needs to be stored or else overlap will happen FIXME
  if @repaint_required
    $log.debug " STACKFLOW repaint graphic #{@graphic}, size:#{@components.size} "
    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/extras/stackflow.rb, line 373
def set_form_col
  # override widget
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/extras/stackflow.rb, line 358
def set_form_row
  return :UNHANDLED if @current_component.nil?
  cc = @current_component
  $log.debug "STACKFLOW #{@name} set_form_row calling sfr for #{cc.name}, r #{cc.row} c: #{cc.col} "
  $log.debug " STACKFLOW on enter sfr #{@current_component.name}  #{@current_component} "

  @current_component.on_enter
  @current_component.set_form_row # why was this missing in vimsplit. is it
  $log.debug "STACKFLOW #{@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/extras/stackflow.rb, line 129
def widgets; @components; end

Private 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/extras/stackflow.rb, line 90
def __add *items
  items.each do |c|  
    raise ArgumentError, "Nil component passed to add" unless c
    if c.is_a? Widget
      c.set_form @form unless c.form
      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
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/extras/stackflow.rb, line 123
def attach_form c
  c.form = @form
  c.override_graphic @graphic
  c.parent_component = self
end
check_coords(e) click to toggle source
# File lib/canis/core/widgets/extras/stackflow.rb, line 203
def check_coords e  # container
  r = e.row
  c = e.col
  $log.debug "  check_coords for #{e}. r:#{e.row} , h:#{e.height} , c:#{e.col} , w:#{e.width} "
  if r >= @row + @height
    $log.warn "XXX: WARN #{e.class} is out of bounds row #{r} "
    e.visible = false
  end
  if c >= @col + @width
    $log.warn "XXX: WARN #{e.class} is out of bounds col #{c} "
    e.visible = false
  end
  if e.row + e.height >= @height
    $log.warn "XXX: WARN #{e.class} is out of bounds row #{e.row} + h #{e.height} >= #{@height} "
    #e.visible = false
  end
  if e.col + e.width >= @width
    $log.warn "XXX: WARN #{e.class} is out of bounds col #{e.col} + w #{e.width} >= #{@width} "
    #e.visible = false
  end
end