class Layouter::Parent
Constants
- DIM
Public Class Methods
distribute(value, importances, maxs)
click to toggle source
# File lib/layouter/parent.rb, line 70 def self.distribute(value, importances, maxs) raise(AssertionError) unless value.is_a?(Integer) # Avoid endless loops. raise(AssertionError) unless value <= maxs.sum # Avoid endless loops. raise(AssertionError) unless importances.length == maxs.length unless maxs.all? { |v| v.is_a?(Integer) || v == Float::INFINITY } raise(AssertionError) end data = importances.zip(maxs).map.with_index do |(importance, max), i| { index: i, value: 0, importance: importance, max: max } end while true # Distribute based on the importance, adhering to the maxs. extra = value - data.map { |h| h[:value] }.sum break if extra <= Float::EPSILON * data.length candidates = data.select { |h| h[:value] < h[:max] } denominator = candidates.map { |h| h[:importance] }.sum.to_f candidates.each do |h| share = extra * h[:importance] / denominator h[:value] = h[:value] + share > h[:max] ? h[:max] : h[:value] + share end end data.each { |h| h[:value] = h[:value].round } while true # Fill up any extra or missing value from turning to integers. extra = value - data.map { |h| h[:value] }.sum break if extra == 0 delta = extra > 0 ? 1 : -1 data = data.sort_by { |h| h[:importance] } data = data.reverse if extra > 0 data.cycle do |h| if h[:max] > h[:value] && h[:value] > 0 h[:value] += delta extra -= delta break if extra == 0 end end end raise(AssertionError) unless data.map { |h| h[:value] }.sum == value raise(AssertionError) unless data.all? { |h| h[:value] <= h[:max] } data.sort_by { |h| h[:index] }.map { |h| h[:value] } end
new(orientation, children)
click to toggle source
Calls superclass method
Layouter::Element::new
# File lib/layouter/parent.rb, line 9 def initialize(orientation, children) super() unless DIM.keys.include?(orientation) raise(ArgumentError.new("Invalid orientation")) end unless children.is_a?(Array) && children.all? { |c| c.is_a?(Element) } raise(ArgumentError.new("Invalid children")) end @orientation = orientation @children = children end
Public Instance Methods
[](index)
click to toggle source
# File lib/layouter/parent.rb, line 21 def [](index) @children[index] end
importance()
click to toggle source
# File lib/layouter/parent.rb, line 56 def importance @children.map(&:importance).max end
layout(width, height)
click to toggle source
# File lib/layouter/parent.rb, line 25 def layout(width, height) dim = DIM[@orientation] value = binding.local_variable_get(dim) min, max = send(:"min_#{dim}"), send(:"max_#{dim}") raise(AssertionError) if min > max raise(LayoutError.new(dim, :too_small)) unless value >= min raise(LayoutError.new(dim, :too_big)) unless value <= max importances = @children.map(&:importance) maxs = @children.map { |c| c.send(:"max_#{dim}") - c.send(:"min_#{dim}") } extras = self.class.distribute(value - min, importances, maxs) @children.zip(extras).each do |child, extra| child.layout( dim == :width ? child.min_width + extra : width, dim == :height ? child.min_height + extra : height, ) end @calculated_width, @calculated_height = width, height self end
render()
click to toggle source
# File lib/layouter/parent.rb, line 60 def render layout! if @orientation == :rows @children.map(&:render).join("\n") elsif @orientation == :cols tmp = @children.map { |child| child.render.split("\n") } tmp[0].zip(*tmp[1..-1]).map(&:join).join("\n") end end