diff --git a/cyberarm_engine.gemspec b/cyberarm_engine.gemspec
index 1ff25fc..2170558 100644
--- a/cyberarm_engine.gemspec
+++ b/cyberarm_engine.gemspec
@@ -27,9 +27,7 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = %w[lib assets]
- spec.add_dependency "excon", "~> 0.88"
spec.add_dependency "gosu", "~> 1.1"
- spec.add_dependency "gosu_more_drawables", "~> 0.3"
# spec.add_dependency "ffi", :platforms => [:mswin, :mingw] # Required by Clipboard on Windows
spec.add_development_dependency "bundler", "~> 2.2"
diff --git a/lib/cyberarm_engine.rb b/lib/cyberarm_engine.rb
index 6522519..b5e63d6 100644
--- a/lib/cyberarm_engine.rb
+++ b/lib/cyberarm_engine.rb
@@ -6,7 +6,6 @@ else
require "gosu"
end
require "json"
-require "excon"
require_relative "cyberarm_engine/version"
require_relative "cyberarm_engine/stats"
@@ -62,6 +61,8 @@ require_relative "cyberarm_engine/ui/elements/check_box"
require_relative "cyberarm_engine/ui/elements/radio"
require_relative "cyberarm_engine/ui/elements/progress"
require_relative "cyberarm_engine/ui/elements/slider"
+require_relative "cyberarm_engine/ui/elements/menu"
+require_relative "cyberarm_engine/ui/elements/menu_item"
require_relative "cyberarm_engine/game_state"
require_relative "cyberarm_engine/ui/gui_state"
diff --git a/lib/cyberarm_engine/cache/download_manager.rb b/lib/cyberarm_engine/cache/download_manager.rb
index 031d3bf..2cd680f 100644
--- a/lib/cyberarm_engine/cache/download_manager.rb
+++ b/lib/cyberarm_engine/cache/download_manager.rb
@@ -1,3 +1,5 @@
+require "excon"
+
module CyberarmEngine
module Cache
class DownloadManager
diff --git a/lib/cyberarm_engine/stats.rb b/lib/cyberarm_engine/stats.rb
index 6c3091b..52a3504 100644
--- a/lib/cyberarm_engine/stats.rb
+++ b/lib/cyberarm_engine/stats.rb
@@ -146,10 +146,15 @@ module CyberarmEngine
slice += 1
end
+ max_node = CyberarmEngine::Stats.frames.select(&:complete?).map { |f| f.frame_timing.duration }.max
+ scale = 1
+ scale = (@height - @padding).to_f / max_node
+ scale = 1 if scale > 1
+
nodes.each_with_index do |cluster, i|
break if cluster.empty?
- @graphs[:frame_timings] << CyberarmEngine::Vector.new(@position.x + @padding + 1 * i, (@position.y + @height - @padding) - cluster.max)
+ @graphs[:frame_timings] << CyberarmEngine::Vector.new(@position.x + @padding + 1 * i, (@position.y + @height - @padding) - cluster.max * scale)
end
end
@@ -187,6 +192,8 @@ module CyberarmEngine
"TIMINGS:\n#{frame.attempted_multitiming? ? "Attempted Multitiming!\nTimings may be inaccurate for:\n#{frame.multitimings.map { |m, _| m}.join("\n") }\n\n" : ''}#{frame.timings.map { |t, v| "#{t}: #{v.duration}ms" }.join("\n")}"
Gosu.draw_rect(@data_label.x - @padding, @data_label.y - @padding, @data_label.width + @padding * 2, @data_label.height + @padding * 2, 0xdd_222222, @position.z)
@data_label.draw
+
+ # puts "Recalcs this frame: #{frame.counters[:gui_recalculations]} [dt: #{(CyberarmEngine::Window.dt * 1000).round} ms]" if frame.counters[:gui_recalculations] && frame.counters[:gui_recalculations].positive?
end
end
end
diff --git a/lib/cyberarm_engine/ui/dsl.rb b/lib/cyberarm_engine/ui/dsl.rb
index 8e3a5ca..8d2b1ba 100644
--- a/lib/cyberarm_engine/ui/dsl.rb
+++ b/lib/cyberarm_engine/ui/dsl.rb
@@ -8,12 +8,8 @@ module CyberarmEngine
container(CyberarmEngine::Element::Stack, options, &block)
end
- # TODO: Remove in version 0.16.0+
- def label(text, options = {}, &block)
- options[:parent] = element_parent
- options[:theme] = current_theme
-
- add_element(Element::TextBlock.new(text, options, block))
+ def menu(options = {}, &block)
+ container(CyberarmEngine::Element::Menu, options, &block)
end
[
@@ -27,72 +23,79 @@ module CyberarmEngine
"Link"
].each do |const|
define_method(:"#{const.downcase}") do |text, options = {}, &block|
- options[:parent] = element_parent
- options[:theme] = current_theme
+ options[:parent] ||= element_parent
+ options[:theme] ||= current_theme
add_element(Element.const_get(const).new(text, options, block))
end
end
def button(text, options = {}, &block)
- options[:parent] = element_parent
- options[:theme] = current_theme
+ options[:parent] ||= element_parent
+ options[:theme] ||= current_theme
add_element(Element::Button.new(text, options, block) { block.call if block.is_a?(Proc) })
end
def list_box(options = {}, &block)
- options[:parent] = element_parent
- options[:theme] = current_theme
+ options[:parent] ||= element_parent
+ options[:theme] ||= current_theme
add_element(Element::ListBox.new(options, block) { block.call if block.is_a?(Proc) })
end
+ def menu_item(text, options = {}, &block)
+ options[:parent] ||= element_parent
+ options[:theme] ||= current_theme
+
+ add_element(Element::MenuItem.new(text, options, block) { block.call if block.is_a?(Proc) })
+ end
+
def edit_line(text, options = {}, &block)
- options[:parent] = element_parent
- options[:theme] = current_theme
+ options[:parent] ||= element_parent
+ options[:theme] ||= current_theme
add_element(Element::EditLine.new(text, options, block))
end
def edit_box(text, options = {}, &block)
- options[:parent] = element_parent
- options[:theme] = current_theme
+ options[:parent] ||= element_parent
+ options[:theme] ||= current_theme
add_element(Element::EditBox.new(text, options, block))
end
def toggle_button(options = {}, &block)
- options[:parent] = element_parent
- options[:theme] = current_theme
+ options[:parent] ||= element_parent
+ options[:theme] ||= current_theme
add_element(Element::ToggleButton.new(options, block))
end
def check_box(text, options = {}, &block)
- options[:parent] = element_parent
- options[:theme] = current_theme
+ options[:parent] ||= element_parent
+ options[:theme] ||= current_theme
add_element(Element::CheckBox.new(text, options, block))
end
def image(path, options = {}, &block)
- options[:parent] = element_parent
- options[:theme] = current_theme
+ options[:parent] ||= element_parent
+ options[:theme] ||= current_theme
add_element(Element::Image.new(path, options, block))
end
def progress(options = {}, &block)
- options[:parent] = element_parent
- options[:theme] = current_theme
+ options[:parent] ||= element_parent
+ options[:theme] ||= current_theme
add_element(Element::Progress.new(options, block))
end
def slider(options = {}, &block)
- options[:parent] = element_parent
- options[:theme] = current_theme
+ options[:parent] ||= element_parent
+ options[:theme] ||= current_theme
add_element(Element::Slider.new(options, block))
end
@@ -102,7 +105,7 @@ module CyberarmEngine
end
def theme(theme)
- element_parent.options[:theme] = theme
+ element_parent.options[:theme] ||= theme
end
def current_theme
@@ -120,8 +123,8 @@ module CyberarmEngine
end
private def container(klass, options = {}, &block)
- options[:parent] = element_parent
- options[:theme] = current_theme
+ options[:parent] ||= element_parent
+ options[:theme] ||= current_theme
_container = klass.new(options, block)
@@ -129,7 +132,7 @@ module CyberarmEngine
CyberarmEngine::Element::Container.current_container = _container
_container.build
- _container.parent.add(_container)
+ _container.parent.add(_container) unless _container.is_a?(CyberarmEngine::Element::Menu)
CyberarmEngine::Element::Container.current_container = old_parent
diff --git a/lib/cyberarm_engine/ui/element.rb b/lib/cyberarm_engine/ui/element.rb
index 29aaf74..0bc11c4 100644
--- a/lib/cyberarm_engine/ui/element.rb
+++ b/lib/cyberarm_engine/ui/element.rb
@@ -180,9 +180,7 @@ module CyberarmEngine
return if self.is_a?(ToolTip)
- if old_width != width || old_height != height
- root.gui_state.request_recalculate
- end
+ root.gui_state.request_recalculate if old_width != width || old_height != height
stylize
end
@@ -577,7 +575,7 @@ module CyberarmEngine
end
def recalculate_if_size_changed
- if !is_a?(ToolTip) && (@old_width != width || @old_height != height)
+ if @parent && !is_a?(ToolTip) && (@old_width != width || @old_height != height)
root.gui_state.request_recalculate
@old_width = width
@@ -628,7 +626,19 @@ module CyberarmEngine
end
def recalculate
- raise "#{self.class}#recalculate was not overridden!"
+ old_width = width
+ old_height = height
+
+ stylize
+ layout
+
+ root.gui_state.request_recalculate if @parent && !is_a?(ToolTip) && (width != old_width || height != old_height)
+ root.gui_state.request_repaint if width != old_width || height != old_height
+
+ root.gui_state.menu.recalculate if root.gui_state.menu && root.gui_state.menu.parent == self
+ end
+
+ def layout
end
def reposition
diff --git a/lib/cyberarm_engine/ui/elements/button.rb b/lib/cyberarm_engine/ui/elements/button.rb
index a6334b3..66c9255 100644
--- a/lib/cyberarm_engine/ui/elements/button.rb
+++ b/lib/cyberarm_engine/ui/elements/button.rb
@@ -34,7 +34,7 @@ module CyberarmEngine
@text.draw
end
- def recalculate
+ def layout
unless @enabled
@style.background_canvas.background = @style.disabled[:background]
@text.color = @style.disabled[:color]
diff --git a/lib/cyberarm_engine/ui/elements/container.rb b/lib/cyberarm_engine/ui/elements/container.rb
index 7e8093a..ad903da 100644
--- a/lib/cyberarm_engine/ui/elements/container.rb
+++ b/lib/cyberarm_engine/ui/elements/container.rb
@@ -49,9 +49,7 @@ module CyberarmEngine
root.gui_state.request_recalculate_for(self) if @children.delete(element)
end
- def clear(&block)
- @children.clear
-
+ def append(&block)
old_container = CyberarmEngine::Element::Container.current_container
CyberarmEngine::Element::Container.current_container = self
@@ -62,7 +60,9 @@ module CyberarmEngine
root.gui_state.request_recalculate_for(self)
end
- def append(&block)
+ def clear(&block)
+ @children.clear
+
old_container = CyberarmEngine::Element::Container.current_container
CyberarmEngine::Element::Container.current_container = self
@@ -151,20 +151,24 @@ module CyberarmEngine
end
def recalculate
+ return if @in_recalculate
+
+ @in_recalculate = true
+
@current_position = Vector.new(@style.margin_left + @style.padding_left, @style.margin_top + @style.padding_top)
return unless visible?
Stats.frame&.increment(:gui_recalculations)
- stylize
-
# s = Gosu.milliseconds
+ stylize
layout
- old_width = @width
- old_height = @height
+ # Old sizes MUST be determined AFTER call to layout
+ old_width = width
+ old_height = height
@cached_scroll_width = nil
@cached_scroll_height = nil
@@ -207,6 +211,7 @@ module CyberarmEngine
end
end
+ # t = Gosu.milliseconds
# Move children to parent after positioning
@children.each do |child|
child.x += (@x + @style.border_thickness_left) - style.margin_left
@@ -216,12 +221,11 @@ module CyberarmEngine
child.recalculate
child.reposition # TODO: Implement top,bottom,left,center, and right positioning
- Stats.frame.increment(:gui_recalculations)
+ Stats.frame&.increment(:gui_recalculations)
update_child_element_visibity(child)
end
-
- # puts "TOOK: #{Gosu.milliseconds - s}ms to recalculate #{self.class}:0x#{self.object_id.to_s(16)}"
+ # puts "TOOK: #{Gosu.milliseconds - t}ms to recalculate #{self.class}:0x#{self.object_id.to_s(16)}'s #{@children.count} children"
update_background
@@ -236,17 +240,11 @@ module CyberarmEngine
@scroll_target_position.y = 0
end
- # NOTE: Experiment for removing need to explicitly call gui_state#recalculate at least 3 times for layout to layout...
- if old_width != @width || old_height != @height
- if @parent
- root.gui_state.request_recalculate_for(@parent)
- else
- root.gui_state.request_recalculate
- end
- end
-
- root.gui_state.request_repaint if @width != old_width || @height != old_height
recalculate_if_size_changed
+
+ # puts "TOOK: #{Gosu.milliseconds - s}ms to recalculate #{self.class}:0x#{self.object_id.to_s(16)}"
+
+ @in_recalculate = false
end
def layout
diff --git a/lib/cyberarm_engine/ui/elements/edit_line.rb b/lib/cyberarm_engine/ui/elements/edit_line.rb
index 15bc1ea..cdcb0e3 100644
--- a/lib/cyberarm_engine/ui/elements/edit_line.rb
+++ b/lib/cyberarm_engine/ui/elements/edit_line.rb
@@ -278,7 +278,7 @@ module CyberarmEngine
:handled
end
- def recalculate
+ def layout
super
@width = dimensional_size(@style.width, :width) || default(:width)
diff --git a/lib/cyberarm_engine/ui/elements/image.rb b/lib/cyberarm_engine/ui/elements/image.rb
index 66137de..a8d06f0 100644
--- a/lib/cyberarm_engine/ui/elements/image.rb
+++ b/lib/cyberarm_engine/ui/elements/image.rb
@@ -27,7 +27,7 @@ module CyberarmEngine
:handled
end
- def recalculate
+ def layout
_width = dimensional_size(@style.width, :width)
_height = dimensional_size(@style.height, :height)
diff --git a/lib/cyberarm_engine/ui/elements/list_box.rb b/lib/cyberarm_engine/ui/elements/list_box.rb
index c763509..973a358 100644
--- a/lib/cyberarm_engine/ui/elements/list_box.rb
+++ b/lib/cyberarm_engine/ui/elements/list_box.rb
@@ -12,21 +12,7 @@ module CyberarmEngine
@style.background_canvas.background = default(:background)
- # TODO: "Clean Up" into own class?
- @menu = Stack.new(parent: self, theme: @options[:theme])
- @menu.define_singleton_method(:recalculate_menu) do
- @x = @__list_box.x
- @y = parent.parent.scroll_top + @__list_box.y + @__list_box.height
-
- @y = (parent.parent.scroll_top + @__list_box.y) - height if @y + height > window.height
- end
- @menu.instance_variable_set(:"@__list_box", self)
-
- def @menu.recalculate
- super
-
- recalculate_menu
- end
+ @menu = Menu.new(parent: self, theme: @options[:theme])
self.choose = @choose
end
@@ -40,7 +26,13 @@ module CyberarmEngine
def choose=(item)
valid = @items.detect { |i| i == item }
- raise "Invalid value '#{item}' for choose, valid options were: #{@items.map { |i| "#{i.inspect}" }.join(", ")}" unless valid
+
+ unless valid
+ warn "Invalid value '#{item}' for choose, valid options were: #{@items.map { |i| "#{i.inspect}" }.join(", ")}"
+ item = @items.first
+
+ raise "No items list" unless item
+ end
@choose = item
@@ -62,39 +54,25 @@ module CyberarmEngine
end
def show_menu
- @menu.clear
+ @menu.clear do
- @menu.style.width = width
+ @menu.style.width = width
- @items.each do |item|
- next if item == self.value
+ @items.each do |item|
+ # prevent already selected item from appearing in list
+ # NOTE: Remove this? Might be kinda confusing...
+ next if item == self.value
- btn = Button.new(
- item,
- {
- parent: @menu,
- width: 1.0,
- theme: @options[:theme],
- margin: 0,
- border_color: 0x00ffffff
- },
- proc do
+ root.gui_state.menu_item(item, width: 1.0, margin: 0, border_color: 0x00ffffff) do
self.choose = item
@block&.call(self.value)
end
- )
-
- @menu.add(btn)
+ end
end
+
recalculate
- root.gui_state.show_menu(@menu)
- end
-
- def recalculate
- super
-
- @menu.recalculate
+ @menu.show
end
end
end
diff --git a/lib/cyberarm_engine/ui/elements/menu.rb b/lib/cyberarm_engine/ui/elements/menu.rb
new file mode 100644
index 0000000..09d0d83
--- /dev/null
+++ b/lib/cyberarm_engine/ui/elements/menu.rb
@@ -0,0 +1,27 @@
+module CyberarmEngine
+ class Element
+ class Menu < Stack
+ def recalculate
+ super
+
+ recalculate_menu
+ end
+
+ def recalculate_menu
+ # FIXME: properly find scrollable parent, if any.
+ parent_scroll_top = parent&.parent ? parent.parent.scroll_top : 0
+
+ @x = @parent.x
+ @y = parent_scroll_top + @parent.y + @parent.height
+
+ @y = (parent_scroll_top + @parent.y) - height if @y + height > window.height
+ end
+
+ def show
+ recalculate
+
+ root.gui_state.show_menu(self)
+ end
+ end
+ end
+end
diff --git a/lib/cyberarm_engine/ui/elements/menu_item.rb b/lib/cyberarm_engine/ui/elements/menu_item.rb
new file mode 100644
index 0000000..164df1d
--- /dev/null
+++ b/lib/cyberarm_engine/ui/elements/menu_item.rb
@@ -0,0 +1,6 @@
+module CyberarmEngine
+ class Element
+ class MenuItem < Button
+ end
+ end
+end
diff --git a/lib/cyberarm_engine/ui/elements/progress.rb b/lib/cyberarm_engine/ui/elements/progress.rb
index f478224..86a540b 100644
--- a/lib/cyberarm_engine/ui/elements/progress.rb
+++ b/lib/cyberarm_engine/ui/elements/progress.rb
@@ -19,7 +19,7 @@ module CyberarmEngine
@fraction_background.draw
end
- def recalculate
+ def layout
_width = dimensional_size(@style.width, :width)
_height = dimensional_size(@style.height, :height)
@width = _width
diff --git a/lib/cyberarm_engine/ui/elements/slider.rb b/lib/cyberarm_engine/ui/elements/slider.rb
index 1df4669..b2b9f6c 100644
--- a/lib/cyberarm_engine/ui/elements/slider.rb
+++ b/lib/cyberarm_engine/ui/elements/slider.rb
@@ -47,7 +47,7 @@ module CyberarmEngine
add(@handle)
end
- def recalculate
+ def layout
_width = dimensional_size(@style.width, :width)
_height = dimensional_size(@style.height, :height)
@@ -55,7 +55,7 @@ module CyberarmEngine
@height = _height
position_handle
- @handle.recalculate
+ @handle.layout
@handle.update_background
update_background
diff --git a/lib/cyberarm_engine/ui/elements/text_block.rb b/lib/cyberarm_engine/ui/elements/text_block.rb
index da9cd3f..07e61ca 100644
--- a/lib/cyberarm_engine/ui/elements/text_block.rb
+++ b/lib/cyberarm_engine/ui/elements/text_block.rb
@@ -38,16 +38,13 @@ module CyberarmEngine
end
end
- def recalculate
+ def layout
unless @enabled
@text.color = @style.disabled[:color]
else
@text.color = @style.color
end
- old_width = @width
- old_height = @height
-
@width = 0
@height = 0
@@ -91,9 +88,6 @@ module CyberarmEngine
end
update_background
-
- root.gui_state.request_repaint if @width != old_width || @height != old_height
- recalculate_if_size_changed
end
def handle_text_wrapping(max_width)
diff --git a/lib/cyberarm_engine/ui/elements/toggle_button.rb b/lib/cyberarm_engine/ui/elements/toggle_button.rb
index 4e7220d..4efb3c2 100644
--- a/lib/cyberarm_engine/ui/elements/toggle_button.rb
+++ b/lib/cyberarm_engine/ui/elements/toggle_button.rb
@@ -7,8 +7,6 @@ module CyberarmEngine
if options.dig(:theme, :ToggleButton, :checkmark_image)
options[:theme][:ToggleButton][:image_width] ||= options[:theme][:TextBlock][:text_size]
super(get_image(options.dig(:theme, :ToggleButton, :checkmark_image)), options, block)
-
- @_image = @image
else
super(options[:checkmark], options, block)
end
@@ -16,10 +14,8 @@ module CyberarmEngine
@value = options[:checked] || false
if @value
- @image = @_image if @_image
@raw_text = @options[:checkmark]
else
- @image = nil
@raw_text = ""
end
end
@@ -32,6 +28,14 @@ module CyberarmEngine
:handled
end
+ def render
+ if @image
+ draw_image if @value
+ else
+ draw_text
+ end
+ end
+
def recalculate
super
return if @image
@@ -49,10 +53,8 @@ module CyberarmEngine
@value = boolean
if boolean
- @image = @_image if @_image
@raw_text = @options[:checkmark]
else
- @image = nil
@raw_text = ""
end
diff --git a/lib/cyberarm_engine/ui/gui_state.rb b/lib/cyberarm_engine/ui/gui_state.rb
index 1e037fe..45c842a 100644
--- a/lib/cyberarm_engine/ui/gui_state.rb
+++ b/lib/cyberarm_engine/ui/gui_state.rb
@@ -38,6 +38,10 @@ module CyberarmEngine
@tip = Element::ToolTip.new("", parent: @root_container, z: Float::INFINITY, theme: current_theme)
end
+ def menu
+ @menu
+ end
+
# throws :blur event to focused element and sets GuiState focused element
# Does NOT throw :focus event at element or set element as focused
def focus=(element)
@@ -50,6 +54,24 @@ module CyberarmEngine
end
def draw
+ Stats.frame.start_timing(:gui_element_recalculate_requests)
+
+ # puts "PENDING REQUESTS: #{@pending_element_recalculate_requests.size}" if @pending_element_recalculate_requests.size.positive?
+ @pending_element_recalculate_requests.each(&:recalculate)
+ @pending_element_recalculate_requests.clear
+
+ Stats.frame.end_timing(:gui_element_recalculate_requests)
+
+ if @pending_recalculate_request
+ Stats.frame.start_timing(:gui_recalculate)
+
+ @root_container.recalculate
+
+ @pending_recalculate_request = false
+
+ Stats.frame.end_timing(:gui_recalculate)
+ end
+
super
if @menu
@@ -78,24 +100,6 @@ module CyberarmEngine
end
def update
- Stats.frame.start_timing(:gui_element_recalculate_requests)
-
- # puts "PENDING REQUESTS: #{@pending_element_recalculate_requests.size}" if @pending_element_recalculate_requests.size.positive?
- @pending_element_recalculate_requests.each(&:recalculate)
- @pending_element_recalculate_requests.clear
-
- Stats.frame.end_timing(:gui_element_recalculate_requests)
-
- if @pending_recalculate_request
- Stats.frame.start_timing(:gui_recalculate)
-
- @root_container.recalculate
-
- @pending_recalculate_request = false
-
- Stats.frame.end_timing(:gui_recalculate)
- end
-
if @pending_focus_request
@pending_focus_request = false
diff --git a/lib/cyberarm_engine/ui/theme.rb b/lib/cyberarm_engine/ui/theme.rb
index e959ce3..13b52d3 100644
--- a/lib/cyberarm_engine/ui/theme.rb
+++ b/lib/cyberarm_engine/ui/theme.rb
@@ -208,6 +208,17 @@ module CyberarmEngine
fraction_background: [0xffc75e61, 0xffe26623],
border_thickness: 1,
border_color: [0xffd59674, 0xffff8746]
+ },
+ Menu: { # < Stack
+ width: 200,
+ border_color: 0xaa_efefef,
+ border_thickness: 1
+ },
+
+ MenuItem: { # < Button
+ width: 1.0,
+ text_left: :left,
+ margin: 0
}
}.freeze
end