mirror of
https://github.com/cyberarm/cyberarm_engine.git
synced 2025-12-16 13:12:34 +00:00
195 lines
5.3 KiB
Ruby
195 lines
5.3 KiB
Ruby
module CyberarmEngine
|
|
class Container
|
|
include Common
|
|
|
|
attr_accessor :stroke_color, :fill_color, :background_color, :x, :y, :z, :width, :height
|
|
attr_reader :elements, :children, :options
|
|
attr_reader :scroll_x, :scroll_y, :internal_width, :internal_height
|
|
attr_reader :origin_x, :origin_y, :origin_width, :origin_height
|
|
|
|
def initialize(options = {}, block = nil)
|
|
@parent = options[:parent] || nil
|
|
|
|
options = {
|
|
x: 0, y: 0, z: 0,
|
|
width: 0, height: 0
|
|
}.merge(options)
|
|
|
|
x = options.dig(:x)
|
|
y = options.dig(:y)
|
|
z = options.dig(:z)
|
|
|
|
width = options.dig(:width)
|
|
height = options.dig(:height)
|
|
|
|
raise "#{self.class} 'x' must be a number" unless x.is_a?(Numeric)
|
|
raise "#{self.class} 'y' must be a number" unless y.is_a?(Numeric)
|
|
raise "#{self.class} 'z' must be a number" unless z.is_a?(Numeric)
|
|
raise "#{self.class} 'width' must be a number" unless width.is_a?(Numeric)
|
|
raise "#{self.class} 'height' must be a number" unless height.is_a?(Numeric)
|
|
raise "#{self.class} 'options' must be a Hash" unless options.is_a?(Hash)
|
|
|
|
@x, @y, @z, @width, @height, @internal_width, @internal_height = x, y, z, width-x, height-y, width-x, height-y
|
|
@origin_x, @origin_x = @x, @x
|
|
@origin_width, @origin_height = @width, @height
|
|
@scroll_x, @scroll_y = 0, 0
|
|
@scroll_speed = 10
|
|
|
|
@block = block
|
|
@options = options
|
|
|
|
@text_color = options[:text_color] || Element::THEME[:stroke]
|
|
@background_color = Element::THEME[:background]
|
|
|
|
@elements = []
|
|
@children = []
|
|
|
|
@theme = {}
|
|
|
|
return self
|
|
end
|
|
|
|
def build
|
|
@block.call(self) if @block
|
|
|
|
recalculate
|
|
end
|
|
|
|
def add_child(container)
|
|
@children << container
|
|
@elements << container
|
|
|
|
recalculate
|
|
end
|
|
|
|
def add(element)
|
|
@elements << element
|
|
|
|
recalculate
|
|
end
|
|
|
|
def draw
|
|
Gosu.clip_to(@x, @y, @width, @height) do
|
|
background
|
|
|
|
Gosu.translate(@scroll_x, @scroll_y) do
|
|
@elements.each(&:draw)
|
|
end
|
|
end
|
|
end
|
|
|
|
def update
|
|
@elements.each(&:update)
|
|
end
|
|
|
|
def button_up(id)
|
|
if $window.mouse_x.between?(@x, @x + @width)
|
|
if $window.mouse_y.between?(@y, @y + @height)
|
|
case id
|
|
when Gosu::MsWheelUp
|
|
@scroll_y += @scroll_speed
|
|
@scroll_y = 0 if @scroll_y > 0
|
|
when Gosu::MsWheelDown
|
|
@scroll_y -= @scroll_speed
|
|
if $window.height - @internal_height - @y > 0
|
|
@scroll_y = 0
|
|
else
|
|
@scroll_y = @height - @internal_height if @scroll_y <= @height - @internal_height
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
@elements.each {|e| if defined?(e.button_up); e.button_up(id); end}
|
|
end
|
|
|
|
def theme
|
|
@theme
|
|
end
|
|
|
|
def stroke(color)
|
|
@theme[:stroke] = color
|
|
end
|
|
|
|
def fill(color)
|
|
@theme[:fill] = color
|
|
end
|
|
|
|
def background
|
|
Gosu.draw_rect(@x, @y, @width, @height, @background_color, @z)
|
|
end
|
|
|
|
def recalculate
|
|
raise "mode was not defined!" unless @mode
|
|
# puts "<#{self.class}:#{self.object_id}> X: #{@x}, Y: #{@y}, width: #{@width}, height: #{@height} (children: #{@children.count}, parents: #{@parent&.children&.count})"
|
|
|
|
@packing_x = 0
|
|
@packing_y = 0
|
|
|
|
@width = @origin_width
|
|
@height= @origin_height
|
|
|
|
if @parent
|
|
neighbors = @parent.children.size > 0 ? @parent.children.size : 1
|
|
@width = @parent.width / neighbors
|
|
@height = @parent.height / neighbors
|
|
end
|
|
|
|
widest_element = nil
|
|
last_element = nil
|
|
|
|
@elements.each do |element|
|
|
flow(element) if @mode == :flow
|
|
stack(element) if @mode == :stack
|
|
|
|
if element.is_a?(Element)
|
|
widest_element ||= element
|
|
highest_element ||= element
|
|
|
|
widest_element = element if element.width > widest_element.width
|
|
last_element = element
|
|
end
|
|
|
|
margin = 0
|
|
margin = element.margin if defined?(element.margin)
|
|
case @mode
|
|
when :flow
|
|
@internal_width += element.width + margin unless @origin_width.nonzero?
|
|
@internal_height = element.height + margin if element.height + margin > @internal_height + margin unless @origin_height.nonzero?
|
|
when :stack
|
|
@internal_width = element.width + margin if element.width + margin > @internal_width + margin unless @origin_width.nonzero?
|
|
@internal_height += element.height + margin unless @origin_height.nonzero?
|
|
end
|
|
end
|
|
|
|
@internal_width += widest_element.margin if widest_element && !@origin_width.nonzero?
|
|
@internal_height += last_element.margin if last_element && !@origin_height.nonzero?
|
|
end
|
|
|
|
def flow(element)
|
|
element.x = @packing_x
|
|
if element.is_a?(Container)
|
|
element.y = @y
|
|
else
|
|
element.y = 0
|
|
end
|
|
element.recalculate
|
|
|
|
@packing_x += element.margin if defined?(element.margin)
|
|
@packing_x += element.width
|
|
end
|
|
|
|
def stack(element)
|
|
if element.is_a?(Container)
|
|
element.x = @x
|
|
else
|
|
element.x = 0
|
|
end
|
|
element.y = @packing_y
|
|
element.recalculate
|
|
|
|
@packing_y += element.margin if defined?(element.margin)
|
|
@packing_y += element.height
|
|
end
|
|
end
|
|
end |