class RETerm::Window

Windows are areas rendered on screen, associated with components to be rendered in them. They specify the position to start drawing component as well as the maximum width and height. A border may be drawn around a window and a {ColorPair} associated.

If Layout is added to a Window, children may subsequently be added. This should be performed via the Layout#add_child method.

@example adding a layout to a window

init_reterm {
  win = Window.new :rows => 50, :cols => 30
  layout = Layouts::Horizontal.new
  win.component = layout

  child = layout.add_child :rows => 5, :cols => 10
  child.class # => RETerm::Window

  label = Components::Label.new :text => "Hello World!"
  child.component = label

  update_reterm
  sleep(5)
}

Attributes

children[RW]
cols[RW]
component[RW]
hborder[RW]
parent[R]
rows[RW]
vborder[RW]
win[R]
window_id[R]
x[RW]
y[RW]

Public Class Methods

adjust_proportional(parent, rows, cols) click to toggle source

Adjusts rows/cols in a context dependent manner TODO should proporational percentage be of remaining area?

# File lib/reterm/window.rb, line 193
def self.adjust_proportional(parent, rows, cols)
  nr = rows
  nc = cols

  nr = parent.rows * nr if rows < 1
  nc = parent.cols * nc if cols < 1

  return nr, nc
end
align(parent, x, y, rows, cols) click to toggle source

Adjusts x/y in context dependent manner

# File lib/reterm/window.rb, line 204
def self.align(parent, x, y, rows, cols)
  nx = x
  ny = y

  nx = 1 if x == :left
  ny = 1 if y == :top

  nx = parent.cols - cols - 1 if x == :right
  ny = parent.rows - rows - 1 if y == :bottom

  nx = parent.cols / 2 - cols / 2 if x == :center
  ny = parent.rows / 2 - rows / 2 if y == :center

  return nx, ny
end
all() click to toggle source

Static method returning all tracked windows

# File lib/reterm/window.rb, line 303
def self.all
  @@registry ||= []
  @@registry
end
fill_parent(parent, x, y, rows, cols) click to toggle source

Adjusts rows / cols so as to fill parent

# File lib/reterm/window.rb, line 221
def self.fill_parent(parent, x, y, rows, cols)
  if (y + rows) < parent.rows
    rows = parent.rows - y - 1
  end

  if (x + cols) < parent.cols
    cols = parent.cols - x - 1
  end

  return rows, cols
end
new(args={}) click to toggle source

Instantiate Window with given args. None are required, but unless :rows, :cols, :x, or :y is specified, window will be created in it's default position.

This method will generate a unique id for each window and add it to a static registry for subsequent tracking.

@param [Hash] args arguments used to instantiate window @option args [Integer] :rows number of rows to assign to window @option args [Integer] :cols number of cols to assign to window @option args [Integer] :x starting x position of window @option args [Integer] :y starting y position of window @option args [Integer] :vborder vertical border char @option args [Integer] :hborder horizontal border char @option args [Component] :component component to assign to window @option args [Window] :parent parent to assign to window, if

set window will be created a a child, else it will be
independently created & tracked.

@options args [Boolean] :expand bool indicating

if window can be expanded on request

@options args [Boolean] :must_expand bool indicating

if window must be expanded when requested. Failure
to expand will result in an error

@options args [Boolean] :fill bool indicating

if window should fill remaining space
# File lib/reterm/window.rb, line 130
def initialize(args={})
  @@registry ||= []
  @@registry  << self

  @@wid ||= 0
  @@wid  += 1
  @window_id = @@wid

  @children = []

  @x    = args[:x] || 0
  @y    = args[:y] || 0

  @vborder = args[:vborder] || 0
  @hborder = args[:hborder] || 0

  component = args[:component]

  @rows = args[:rows] ||
          (component ?
           (component.requested_rows + component.extra_padding) :
           Terminal.rows)

  @cols = args[:cols] ||
          (component ?
           (component.requested_cols + component.extra_padding) :
           Terminal.cols)

  if args[:parent]
    @parent = args[:parent]

    @rows, @cols = *Window.adjust_proportional(@parent, @rows, @cols)
    @x,    @y    = *Window.align(@parent, @x, @y, @rows, @cols)

    @win = parent.win.derwin(@rows, @cols, @y, @x)

  else
    @parent = nil

    @rows, @cols = *Window.adjust_proportional(Terminal, @rows, @cols)
    @x,    @y    = *Window.align(Terminal, @x, @y, @rows, @cols)

    @win = Ncurses::WINDOW.new(@rows, @cols, @y, @x)
  end

  raise ArgumentError, "could not create window" if !@win

  self.component = component if !!component

  Ncurses::keypad(@win, true)

  @win.timeout(SYNC_TIMEOUT) if sync_enabled? # XXX

  @expand      = !!args[:expand]
  @must_expand = !!args[:must_expand]

  @fill        = !!args[:fill]
end
top() click to toggle source

Static method returning top level windows

# File lib/reterm/window.rb, line 309
def self.top
  @@registry ||= []
  @@registry.select { |w| !w.parent? }
end

Public Instance Methods

activate!(*input) click to toggle source

Activate window component

# File lib/reterm/window.rb, line 530
def activate!(*input)
  component.activate!(*input)
end
actual_cols() click to toggle source

Return window cols

# File lib/reterm/window.rb, line 520
def actual_cols
  dimensions[1]
end
actual_rows() click to toggle source

Return window rows

# File lib/reterm/window.rb, line 515
def actual_rows
  dimensions[0]
end
bold!() { || ... } click to toggle source

Enable bold formatting

# File lib/reterm/window.rb, line 460
def bold!
  @win.attron(Ncurses::A_BOLD)
  return unless block_given?

  yield
  @win.attroff(Ncurses::A_BOLD)
end
border!() click to toggle source

Draw Border around window

# File lib/reterm/window.rb, line 423
def border!
  @win.box(@vborder, @hborder)
end
cdk?() click to toggle source

Return bool indicating if cdk is enabled for this window/component

# File lib/reterm/window.rb, line 296
def cdk?
  !!@cdk_scr
end
cdk_scr() click to toggle source

Return cdk screen (only used by CDK components)

# File lib/reterm/window.rb, line 290
def cdk_scr
  enable_cdk!
  @cdk_scr ||= CDK::SCREEN.new(@win)
end
child_containing(x, y, z) click to toggle source

Return child containing specified screen coordiantes, else nil

# File lib/reterm/window.rb, line 336
def child_containing(x, y, z)
  found = nil
  children.find { |c|
    next if found

    # recursively descend into layout children
    if c.component.kind_of?(Layout)
      found = c.child_containing(x, y, z)

    else
      found =
        c.total_x <= x && c.total_y <= y && # c.z >= z
       (c.total_x + c.cols) >= x && (c.total_y + c.rows) >= y
      found = c if found
    end
  }

  found
end
children?() click to toggle source

Return boolean indicating if this window has children

# File lib/reterm/window.rb, line 67
def children?
  !@children.empty?
end
clear!() click to toggle source

Clear window by removing all children and reinitializing window space

# File lib/reterm/window.rb, line 371
def clear!
  children.each { |c|
    del_child(c)
  }

  @children = []
  erase
end
colored?() click to toggle source

Return bool indiciating if colors are set

# File lib/reterm/window.rb, line 488
def colored?
  !!@colors
end
colors=(c) click to toggle source

Set window color

# File lib/reterm/window.rb, line 493
def colors=(c)
  @colors = c.is_a?(ColorPair) ? c : ColorPair.for(c).first
  @win.bkgd(Ncurses.COLOR_PAIR(@colors.id)) unless @win.nil?

  component.colors = @colors if component?

  children.each { |ch|
    ch.colors = c
  }
end
component=(c) click to toggle source

Assign component to window. This will autoassign local window to component as well.

# File lib/reterm/window.rb, line 53
def component=(c)
  clear!

  c.window   = self
  c.colors   = @colors if colored?
  @component = c
end
component?() click to toggle source

Return bool indicating if this window has a component associated with it

# File lib/reterm/window.rb, line 47
def component?
  !!@component
end
create_child(h={}) click to toggle source

Create child window, this method should not be invoked by end-user, rather it is is invoked the Layout#add_child is called.

# File lib/reterm/window.rb, line 319
def create_child(h={})
  c = self.class.new h.merge(:parent => self)
  c.colors = @colors if colored?
  children << c
  c
end
del_child(child) click to toggle source

Remove child window, like create_child, this is used internally and should not be invoked by the end user

# File lib/reterm/window.rb, line 328
def del_child(child)
  @children.delete(child)
  @@registry.delete(child)
  child.finalize!
  child.win.delwin if !!child.win
end
dimensions() click to toggle source

Return window dimensions as an array containing rows & cols

# File lib/reterm/window.rb, line 505
def dimensions
  rows = []
  cols = []
  @win.getmaxyx(rows, cols)
  rows = rows.first
  cols = cols.first
  [rows, cols]
end
distance_from(win) click to toggle source
# File lib/reterm/window.rb, line 98
def distance_from(win)
  # FIXME: need to expand to compare each of 4 window coords
  #        to each of 4 in other window
  Math.sqrt((x - win.x) ** 2 + (y - win.y) ** 2)
end
draw!() click to toggle source

Draw component in window

# File lib/reterm/window.rb, line 525
def draw!
  component.draw! if component?
end
erase() click to toggle source

Erase window drawing area

# File lib/reterm/window.rb, line 381
def erase
  children.each { |c|
    c.erase
  }

  @win.werase if @win

  component.component.erase if cdk? && component? && component.init?
end
erase_scr() click to toggle source

Erases window screen by overwriting it with blanks

# File lib/reterm/window.rb, line 392
def erase_scr
  0.upto(rows) { |r|
    mvaddstr(r, 1, " " * cols)
  }
end
expand?() click to toggle source
# File lib/reterm/window.rb, line 251
def expand?
  !!@expand
end
finalize!() click to toggle source

Invoke window finalization routine by destroying it and all children

# File lib/reterm/window.rb, line 237
def finalize!
  erase
  @@registry.delete(self)

  children.each { |c|
    del_child c
  }

  cdk_scr.destroy if cdk?
  component.finalize! if component?
end
first_child?() click to toggle source

Return boolean indicating if this window is the first child of its parent

# File lib/reterm/window.rb, line 73
def first_child?
  return true unless parent?
  parent.children.index(self) == 0
end
getch() click to toggle source

Blocking call to capture next character from window

# File lib/reterm/window.rb, line 428
def getch
  @win.getch
end
last_child?() click to toggle source

Return boolean indicating if this window is the last child of its parent

# File lib/reterm/window.rb, line 80
def last_child?
  return true unless parent?
  parent.children.index(self) == (parent.children.size - 1)
end
must_expand?() click to toggle source
# File lib/reterm/window.rb, line 255
def must_expand?
  !!@must_expand
end
mvaddstr(*a) click to toggle source

Write string at specified loc

# File lib/reterm/window.rb, line 455
def mvaddstr(*a)
  @win.mvaddstr(*a)
end
no_bold!() click to toggle source

Disable bold formatting

# File lib/reterm/window.rb, line 469
def no_bold!
  @win.attroff(Ncurses::A_BOLD)
end
no_border!() click to toggle source

Remove Border around window

# File lib/reterm/window.rb, line 418
def no_border!
  @win.border(' '.ord, ' '.ord, ' '.ord, ' '.ord, ' '.ord, ' '.ord, ' '.ord, ' '.ord)
end
no_reverse!() click to toggle source

Disabled reverse formatting

# File lib/reterm/window.rb, line 483
def no_reverse!
  @win.attroff(Ncurses::A_REVERSE)
end
noutrefresh() click to toggle source
# File lib/reterm/window.rb, line 408
def noutrefresh
  @win.noutrefresh
  children.each { |c|
    c.noutrefresh
  }

  component.component.screen.noutrefresh if cdk?
end
parent?() click to toggle source

Return boolean if this window is a child of another

# File lib/reterm/window.rb, line 62
def parent?
  !!@parent
end
refresh() click to toggle source

Refresh / resynchronize window and all children

# File lib/reterm/window.rb, line 399
def refresh
  @win.refresh
  children.each { |c|
    c.refresh
  }

  component.component.screen.refresh if cdk?
end
request_expansion(r, c) click to toggle source
# File lib/reterm/window.rb, line 259
def request_expansion(r, c)
  h = {:rows => r,
       :cols => c,
       :x    => x,
       :y    => y}

  if parent?
    if parent.component.exceeds_bounds_with?(h)
      if parent.component.expandable?
        parent.component.expand(h)

      else
        raise ArgumentError, "cannot expand" if must_expand?
        return false
      end
    end

  else
    unless Terminal.contains?(h)
      raise ArgumentError, "terminal too small" if must_expand?
      return false
    end
  end

  resize(r, c)
  true
end
resize(rows, cols) click to toggle source
# File lib/reterm/window.rb, line 358
def resize(rows, cols)
  r = win.resize rows, cols
  raise ArgumentError, "could not resize window" if r == -1

  @rows = rows
  @cols = cols

  self
end
reverse!() { || ... } click to toggle source

Enable reverse formatting

# File lib/reterm/window.rb, line 474
def reverse!
  @win.attron(Ncurses::A_REVERSE)
  return unless block_given?

  yield
  @win.attroff(Ncurses::A_REVERSE)
end
root() click to toggle source

Return root window (recusively), self if parent is not set

# File lib/reterm/window.rb, line 86
def root
  parent? ? parent.root : self
end
sync!() click to toggle source

Dispatch to component synchronization

# File lib/reterm/window.rb, line 447
def sync!
  component.sync! if component?
  children.each { |c|
    c.sync!
  }
end
sync_getch() click to toggle source

Normal getch unless sync enabled in which case, timeout will be checked & components synchronized

# File lib/reterm/window.rb, line 434
def sync_getch
  return self.getch unless sync_enabled?

  c = -1
  while c == -1 && !shutdown?
    c = self.getch
    run_sync!
  end

  c
end
total_x() click to toggle source
# File lib/reterm/window.rb, line 90
def total_x
  @tx ||= parent? ? (parent.total_x + x) : x
end
total_y() click to toggle source
# File lib/reterm/window.rb, line 94
def total_y
  @ty ||= parent? ? (parent.total_y + y) : y
end