class WhirledPeas::Graphics::ContainerPainter

Abstract Painter for containers. Containers (as the name implies) contain other child elements and must delegate painting of the children to the children themselves.

Constants

PADDING

Attributes

children[R]

Public Class Methods

new(name, settings) click to toggle source
Calls superclass method
# File lib/whirled_peas/graphics/container_painter.rb, line 14
def initialize(name, settings)
  super
  @children = []
end

Public Instance Methods

add_child(child) click to toggle source

Tightly manage access to the children (rather than simply exposing the underlying array). This allows subclasses to easily modify behavior based on that element's specific settings.

# File lib/whirled_peas/graphics/container_painter.rb, line 85
def add_child(child)
  children << child
end
children?() click to toggle source
# File lib/whirled_peas/graphics/container_painter.rb, line 93
def children?
  num_children > 0
end
each_child(&block) click to toggle source
# File lib/whirled_peas/graphics/container_painter.rb, line 97
def each_child(&block)
  children.each(&block)
end
num_children() click to toggle source
# File lib/whirled_peas/graphics/container_painter.rb, line 89
def num_children
  children.length
end
paint(canvas, left, top, &block) click to toggle source

Paint the common attributes of containers (e.g. border and background color). Any class that inherits from this one should call `super` at the start of its paint method, before painting its children.

# File lib/whirled_peas/graphics/container_painter.rb, line 22
def paint(canvas, left, top, &block)
  return unless canvas.writable?
  return unless needs_printing?
  canvas_coords = coords(left, top)

  # Paint the border, background color, and scrollbar starting from the top left
  # border position, moving down row by row until we reach the bottom border
  # position
  stroke_left = canvas_coords.border_left
  stroke_top = canvas_coords.border_top

  # All strokes will have the same formatting options
  formatting = [*settings.border.color, *settings.bg_color]

  # Paint the top border if the settings call for it
  if settings.border.top?
    canvas.stroke(stroke_left, stroke_top, top_border_stroke, formatting, &block)
    stroke_top += 1
  end
  # Precalculate the middle border container grids with more than 1 row
  middle_border = dimensions.num_rows > 1 ? middle_border_stroke : ''

  vert_scrollbar = settings.scrollbar.vert? ? ScrollbarHelper.vert(
    dimensions.children_height + dimensions.padding_height,
    dimensions.inner_grid_height,
    canvas_coords.content_top - canvas_coords.offset_content_top,
  ) : []

  # Paint each grid row by row
  dimensions.num_rows.times do |row_num|
    # In a grid with N rows, we will need to paint N - 1 inner horizontal borders.
    # This code treats the inner horizontal border as the top of each row except for
    # the first one.
    if row_num > 0 && settings.border.inner_horiz?
      canvas.stroke(stroke_left, stroke_top, middle_border, formatting, &block)
      stroke_top += 1
    end

    # Paint the interior of each row (horizontal borders, veritical scroll bar and
    # background color for the padding and content area)
    dimensions.inner_grid_height.times do |row_within_cell|
      content_line = content_line_stroke(row_within_cell, vert_scrollbar)
      canvas.stroke(stroke_left, stroke_top, content_line, formatting, &block)
      stroke_top += 1
    end

    # Paint the horizontal scroll bar is the settings call for it
    if settings.scrollbar.horiz?
      canvas.stroke(stroke_left, stroke_top, bottom_scroll_stroke(canvas_coords), formatting, &block)
      stroke_top += 1
    end
  end

  # Paint the bottom border if the settings call for it
  if settings.border.bottom?
    canvas.stroke(stroke_left, stroke_top, bottom_border_stroke, formatting, &block)
    stroke_top += 1
  end
end

Private Instance Methods

bottom_border_stroke() click to toggle source

Return the stroke for the bottom border

# File lib/whirled_peas/graphics/container_painter.rb, line 209
def bottom_border_stroke
  line_stroke(
    settings.border.style.bottom_left,
    settings.border.style.bottom_junc,
    settings.border.style.bottom_right
  ) do
    settings.border.style.bottom_horiz * (dimensions.inner_grid_width + (settings.scrollbar.vert? ? 1 : 0))
  end
end
bottom_scroll_stroke(canvas_coords) click to toggle source

Return the stroke for the horizontal scroll bar

# File lib/whirled_peas/graphics/container_painter.rb, line 235
def bottom_scroll_stroke(canvas_coords)
  line_stroke(
    settings.border.style.left_vert,
    settings.border.style.middle_vert,
    settings.border.style.right_vert,
  ) do
    ScrollbarHelper.horiz(
      dimensions.children_width + dimensions.padding_width,
      dimensions.inner_grid_width,
      canvas_coords.content_left - canvas_coords.offset_content_left
    ).join
  end
end
content_line_stroke(row_within_cell, vert_scrollbar) click to toggle source

Return the stroke for a grid row between any borders

# File lib/whirled_peas/graphics/container_painter.rb, line 220
def content_line_stroke(row_within_cell, vert_scrollbar)
  line_stroke(
    settings.border.style.left_vert,
    settings.border.style.middle_vert,
    settings.border.style.right_vert,
  ) do
    if settings.scrollbar.vert?
      PADDING * dimensions.inner_grid_width + vert_scrollbar[row_within_cell]
    else
      PADDING * dimensions.inner_grid_width
    end
  end
end
coords(left, top) click to toggle source

Return an object that allows easy access to important coordinates within the container, e.g. the left position where the left border is printed

# File lib/whirled_peas/graphics/container_painter.rb, line 117
def coords(left, top)
  ContainerCoords.new(dimensions, settings, left, top)
end
horiz_justify_offset(containing_width) click to toggle source

@return [Array<Integer>] a two-item array, the first being the amount of horizontal

spacing to paint *before the first* child and the second being the amount of spacing
to paint *between each* child
# File lib/whirled_peas/graphics/container_painter.rb, line 124
def horiz_justify_offset(containing_width)
  if settings.align_center?
    [(dimensions.content_width - containing_width) / 2, 0]
  elsif settings.align_right?
    [dimensions.content_width - containing_width, 0]
  elsif settings.align_between?
    return [0, 0] if num_children == 1
    [0, (dimensions.content_width - containing_width) / (num_children - 1)]
  elsif settings.align_around?
    full_spacing = (dimensions.content_width - containing_width) / num_children
    [full_spacing / 2, full_spacing]
  elsif settings.align_evenly?
    spacing = (dimensions.content_width - containing_width) / (num_children + 1)
    [spacing, spacing]
  else
    [0, 0]
  end
end
line_stroke(left_border, junc_border, right_border) { || ... } click to toggle source

Return a stroke for one line of the container

@param left_border [String] the character to print as the first character if there

is a left border

@param junc_border [String] the character to print as the junction between two grid

columns if there is an inner vertical border

@param right_border [String] the character to print as the last character if there

is a right border

@block [String] the block should yield a string that represents the interior

(including padding) of a grid cell
# File lib/whirled_peas/graphics/container_painter.rb, line 175
def line_stroke(left_border, junc_border, right_border, &block)
  stroke = ''
  stroke += left_border if settings.border.left?
  dimensions.num_cols.times do |col_num|
    stroke += junc_border if col_num > 0 && settings.border.inner_vert?
    stroke += yield
  end
  stroke += right_border if settings.border.right?
  stroke
end
middle_border_stroke() click to toggle source

Return the stroke for an inner horizontal border

# File lib/whirled_peas/graphics/container_painter.rb, line 198
def middle_border_stroke
  line_stroke(
    settings.border.style.left_junc,
    settings.border.style.cross_junc,
    settings.border.style.right_junc
  ) do
    settings.border.style.middle_horiz * (dimensions.inner_grid_width + (settings.scrollbar.vert? ? 1 : 0))
  end
end
needs_printing?() click to toggle source

Determine if there is anything to print for the container (this does not accont for children, just the border, scrollbar, and background color)

# File lib/whirled_peas/graphics/container_painter.rb, line 107
def needs_printing?
  return true if settings.bg_color
  return true if settings.border.outer?
  return true if dimensions.num_cols > 1 && settings.border.inner_vert?
  return true if dimensions.num_rows > 1 && settings.border.inner_horiz?
  settings.scrollbar.horiz? || settings.scrollbar.vert?
end
top_border_stroke() click to toggle source

Return the stroke for the top border

# File lib/whirled_peas/graphics/container_painter.rb, line 187
def top_border_stroke
  line_stroke(
    settings.border.style.top_left,
    settings.border.style.top_junc,
    settings.border.style.top_right
  ) do
    settings.border.style.top_horiz * (dimensions.inner_grid_width + (settings.scrollbar.vert? ? 1 : 0))
  end
end
vert_justify_offset(containing_height) click to toggle source

@return [Array<Integer>] a two-item array, the first being the amount of vertical

spacing to paint *above the first* child and the second being the amount of spacing
to paint *between each* child
# File lib/whirled_peas/graphics/container_painter.rb, line 146
def vert_justify_offset(containing_height)
  if settings.valign_middle?
    [(dimensions.content_height - containing_height) / 2, 0]
  elsif settings.valign_bottom?
    [dimensions.content_height - containing_height, 0]
  elsif settings.valign_between?
    return [0, 0] if num_children == 1
    [0, (dimensions.content_height - containing_height) / (num_children - 1)]
  elsif settings.valign_around?
    full_spacing = (dimensions.content_height - containing_height) / num_children
    [full_spacing / 2, full_spacing]
  elsif settings.valign_evenly?
    spacing = (dimensions.content_height - containing_height) / (num_children + 1)
    [spacing, spacing]
  else
    [0, 0]
  end
end