class Dedalus::ViewTraversal

Public Class Methods

new(&blk) click to toggle source
# File lib/dedalus/view_traversal.rb, line 6
def initialize(&blk)
  instance_eval(&blk)
end

Public Instance Methods

on_atom(&blk) click to toggle source
# File lib/dedalus/view_traversal.rb, line 10
def on_atom(&blk)
  @atom_callback = blk
end
on_element(&blk) click to toggle source
# File lib/dedalus/view_traversal.rb, line 18
def on_element(&blk)
  @element_callback = blk
end
on_molecule(&blk) click to toggle source
# File lib/dedalus/view_traversal.rb, line 14
def on_molecule(&blk)
  @molecule_callback = blk
end
walk!(structure, origin:, dimensions:, freeform: false, render: false, z_index: ZOrder::Background) click to toggle source
# File lib/dedalus/view_traversal.rb, line 22
def walk!(structure, origin:, dimensions:, freeform: false, render: false, z_index: ZOrder::Background)
  width, height = *dimensions

  height = structure.height if !structure.is_a?(Array) && structure.height
  width  = structure.width  if !structure.is_a?(Array) && structure.width

  x0, y0 = *origin

  if structure.is_a?(Dedalus::Atom)
    @atom_callback.call(structure, origin: origin, dimensions: dimensions, freeform: freeform, z_index: z_index) if @atom_callback

  # implicitly array is rows, nested arrays are columns, doubly-nested arrays are rows, etc
  elsif structure.is_a?(Array)
    walk_rows!(structure, origin: origin, dimensions: dimensions, render: render)

  elsif structure.is_a?(Dedalus::Element)
    offset = structure.offset || [0,0]
    ox,oy = *offset

    # an element *other than* an atom, we need to call #show on it
    margin = structure.margin || 0.0
    x,y = x0 + ox + margin, y0 + oy + margin

    margin_origin = [ x, y ]
    margin_dims = [ width - margin*2, height - margin*2 ]

    if structure.is_a?(Dedalus::Molecule) && @molecule_callback
      @molecule_callback.call(structure, origin: margin_origin, dimensions: margin_dims, z_index: z_index)
    end

    if @element_callback
      @element_callback.call(structure, origin: margin_origin, dimensions: margin_dims, z_index: z_index)
    end

    pad = structure.padding || 0.0
    pad_origin = [x+pad,y+pad]
    pad_dims = [width - pad*2 - margin*2, height - pad*2 - margin*2 ]

    if structure.is_a?(LayerStack)
      structure.layers.each do |layer|
        if layer.freeform?
          if layer.shown.is_a?(Array)
            layer.elements.each_with_index do |layer_element, z_offset|
              walk!(layer_element, origin: pad_origin, dimensions: pad_dims, freeform: true, render: render, z_index: z_index+z_offset)
            end
          else
            walk!(layer.elements, origin: pad_origin, dimensions: pad_dims, freeform: true, render: render, z_index: z_index)
          end
        else
          walk!(layer.elements, origin: pad_origin, dimensions: pad_dims, freeform: false, render: render, z_index: z_index)
        end
      end
    else
      if structure.record? && render
        recorded_image = ImageRepository.lookup_recording(structure.name, structure.width, structure.height, structure.window, force: structure.rerecord?) do
          walk!(structure.shown, origin: [0,0], dimensions: pad_dims, freeform: freeform, render: render)
        end

        ox,oy = *pad_origin
        recorded_image.draw(ox,oy,z_index)
      else
        walk!(structure.shown, origin: pad_origin, dimensions: pad_dims, freeform: freeform, render: render, z_index: z_index)
      end
    end
  end
rescue => ex
  puts "ERROR: Encountered an error with structure of type #{structure.class.name}"
  p ex.message
  p ex.backtrace
  raise ex
end

Private Instance Methods

subdivide_line(elements, distance:, attr:) { |element, current_element_distance, distance_cursor| ... } click to toggle source
# File lib/dedalus/view_traversal.rb, line 130
def subdivide_line(elements, distance:, attr:)
  percent_attr = :"#{attr}_percent"
  elements_with_relative_hints = elements.select do |element|
    if element.is_a?(Array)
      false
    else
      !element.send(percent_attr).nil?
    end
  end

  elements_with_absolute_hints = elements.select do |element|
    if element.is_a?(Array)
      false
    else
      !element.send(attr).nil?
    end
  end

  elements_with_hints = (elements_with_relative_hints + elements_with_absolute_hints).uniq
  distance_specified_by_hints =
    (elements_with_relative_hints.sum(&percent_attr) * distance) +
    (elements_with_absolute_hints.sum(&attr))

  if elements_with_hints.length < elements.length
    default_element_section_distance = (distance - distance_specified_by_hints) / (elements.length - elements_with_hints.length)
  end

  distance_cursor = 0
  elements.each_with_index do |element, index|
    current_element_distance = if element.is_a?(Array)
      default_element_section_distance
    else
      if !element.send(attr).nil?
        element.send(attr)
      elsif !element.send(percent_attr).nil?
        element.send(percent_attr) * distance
      else
        default_element_section_distance
      end
    end

    if distance_cursor > distance - current_element_distance
      return elements.slice(index,elements.size)
    end

    yield(element, current_element_distance, distance_cursor)
    distance_cursor += current_element_distance
  end

  []
end
walk_columns!(columns, origin:, dimensions:, render: false) click to toggle source
# File lib/dedalus/view_traversal.rb, line 119
def walk_columns!(columns, origin:, dimensions:, render: false)
  width, height = *dimensions
  x0, y0 = *origin

  subdivide_line(columns, distance: width, attr: :width) do |column, current_column_width, width_cursor|
    x = x0 + width_cursor
    dims = [ current_column_width, height ]
    walk!(column, origin: [x,y0], dimensions: dims, render: render)
  end
end
walk_rows!(rows, origin:, dimensions:, render: false) click to toggle source
# File lib/dedalus/view_traversal.rb, line 95
def walk_rows!(rows, origin:, dimensions:, render: false)
  width, height = *dimensions
  x0, y0 = *origin

  subdivide_line(rows, distance: height, attr: :height) do |row, current_row_height, height_cursor|
    y = y0 + height_cursor
    dims = [width, current_row_height]
    if row.is_a?(Array)
      extra_columns = true
      while extra_columns
        row = walk_columns!(row, origin: [x0, y], dimensions: dims, render: render)
        if row.empty?
          extra_columns = false
        else
          height_cursor += row.first.height
          y = y0 + height_cursor
        end
      end
    else
      walk!(row, origin: [x0,y], dimensions: dims, render: render)
    end
  end
end