Removed excon as explicit dependency, implemented menu's as (mostly) first class citizens, refactoring of gui layout, FIXME: broke Slider Handle..., probably some other stuff.

This commit is contained in:
2024-03-04 20:54:36 -06:00
parent 615d7ec3e4
commit c2330ed9a9
19 changed files with 178 additions and 137 deletions

View File

@@ -27,9 +27,7 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = %w[lib assets] spec.require_paths = %w[lib assets]
spec.add_dependency "excon", "~> 0.88"
spec.add_dependency "gosu", "~> 1.1" 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_dependency "ffi", :platforms => [:mswin, :mingw] # Required by Clipboard on Windows
spec.add_development_dependency "bundler", "~> 2.2" spec.add_development_dependency "bundler", "~> 2.2"

View File

@@ -6,7 +6,6 @@ else
require "gosu" require "gosu"
end end
require "json" require "json"
require "excon"
require_relative "cyberarm_engine/version" require_relative "cyberarm_engine/version"
require_relative "cyberarm_engine/stats" 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/radio"
require_relative "cyberarm_engine/ui/elements/progress" require_relative "cyberarm_engine/ui/elements/progress"
require_relative "cyberarm_engine/ui/elements/slider" 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/game_state"
require_relative "cyberarm_engine/ui/gui_state" require_relative "cyberarm_engine/ui/gui_state"

View File

@@ -1,3 +1,5 @@
require "excon"
module CyberarmEngine module CyberarmEngine
module Cache module Cache
class DownloadManager class DownloadManager

View File

@@ -146,10 +146,15 @@ module CyberarmEngine
slice += 1 slice += 1
end 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| nodes.each_with_index do |cluster, i|
break if cluster.empty? 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
end end
@@ -187,6 +192,8 @@ module CyberarmEngine
"<c=f80>TIMINGS:</c>\n#{frame.attempted_multitiming? ? "<c=d00>Attempted Multitiming!\nTimings may be inaccurate for:\n#{frame.multitimings.map { |m, _| m}.join("\n") }</c>\n\n" : ''}#{frame.timings.map { |t, v| "#{t}: #{v.duration}ms" }.join("\n")}" "<c=f80>TIMINGS:</c>\n#{frame.attempted_multitiming? ? "<c=d00>Attempted Multitiming!\nTimings may be inaccurate for:\n#{frame.multitimings.map { |m, _| m}.join("\n") }</c>\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) 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 @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 end
end end

View File

@@ -8,12 +8,8 @@ module CyberarmEngine
container(CyberarmEngine::Element::Stack, options, &block) container(CyberarmEngine::Element::Stack, options, &block)
end end
# TODO: Remove in version 0.16.0+ def menu(options = {}, &block)
def label(text, options = {}, &block) container(CyberarmEngine::Element::Menu, options, &block)
options[:parent] = element_parent
options[:theme] = current_theme
add_element(Element::TextBlock.new(text, options, block))
end end
[ [
@@ -27,72 +23,79 @@ module CyberarmEngine
"Link" "Link"
].each do |const| ].each do |const|
define_method(:"#{const.downcase}") do |text, options = {}, &block| define_method(:"#{const.downcase}") do |text, options = {}, &block|
options[:parent] = element_parent options[:parent] ||= element_parent
options[:theme] = current_theme options[:theme] ||= current_theme
add_element(Element.const_get(const).new(text, options, block)) add_element(Element.const_get(const).new(text, options, block))
end end
end end
def button(text, options = {}, &block) def button(text, options = {}, &block)
options[:parent] = element_parent options[:parent] ||= element_parent
options[:theme] = current_theme options[:theme] ||= current_theme
add_element(Element::Button.new(text, options, block) { block.call if block.is_a?(Proc) }) add_element(Element::Button.new(text, options, block) { block.call if block.is_a?(Proc) })
end end
def list_box(options = {}, &block) def list_box(options = {}, &block)
options[:parent] = element_parent options[:parent] ||= element_parent
options[:theme] = current_theme options[:theme] ||= current_theme
add_element(Element::ListBox.new(options, block) { block.call if block.is_a?(Proc) }) add_element(Element::ListBox.new(options, block) { block.call if block.is_a?(Proc) })
end 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) def edit_line(text, options = {}, &block)
options[:parent] = element_parent options[:parent] ||= element_parent
options[:theme] = current_theme options[:theme] ||= current_theme
add_element(Element::EditLine.new(text, options, block)) add_element(Element::EditLine.new(text, options, block))
end end
def edit_box(text, options = {}, &block) def edit_box(text, options = {}, &block)
options[:parent] = element_parent options[:parent] ||= element_parent
options[:theme] = current_theme options[:theme] ||= current_theme
add_element(Element::EditBox.new(text, options, block)) add_element(Element::EditBox.new(text, options, block))
end end
def toggle_button(options = {}, &block) def toggle_button(options = {}, &block)
options[:parent] = element_parent options[:parent] ||= element_parent
options[:theme] = current_theme options[:theme] ||= current_theme
add_element(Element::ToggleButton.new(options, block)) add_element(Element::ToggleButton.new(options, block))
end end
def check_box(text, options = {}, &block) def check_box(text, options = {}, &block)
options[:parent] = element_parent options[:parent] ||= element_parent
options[:theme] = current_theme options[:theme] ||= current_theme
add_element(Element::CheckBox.new(text, options, block)) add_element(Element::CheckBox.new(text, options, block))
end end
def image(path, options = {}, &block) def image(path, options = {}, &block)
options[:parent] = element_parent options[:parent] ||= element_parent
options[:theme] = current_theme options[:theme] ||= current_theme
add_element(Element::Image.new(path, options, block)) add_element(Element::Image.new(path, options, block))
end end
def progress(options = {}, &block) def progress(options = {}, &block)
options[:parent] = element_parent options[:parent] ||= element_parent
options[:theme] = current_theme options[:theme] ||= current_theme
add_element(Element::Progress.new(options, block)) add_element(Element::Progress.new(options, block))
end end
def slider(options = {}, &block) def slider(options = {}, &block)
options[:parent] = element_parent options[:parent] ||= element_parent
options[:theme] = current_theme options[:theme] ||= current_theme
add_element(Element::Slider.new(options, block)) add_element(Element::Slider.new(options, block))
end end
@@ -102,7 +105,7 @@ module CyberarmEngine
end end
def theme(theme) def theme(theme)
element_parent.options[:theme] = theme element_parent.options[:theme] ||= theme
end end
def current_theme def current_theme
@@ -120,8 +123,8 @@ module CyberarmEngine
end end
private def container(klass, options = {}, &block) private def container(klass, options = {}, &block)
options[:parent] = element_parent options[:parent] ||= element_parent
options[:theme] = current_theme options[:theme] ||= current_theme
_container = klass.new(options, block) _container = klass.new(options, block)
@@ -129,7 +132,7 @@ module CyberarmEngine
CyberarmEngine::Element::Container.current_container = _container CyberarmEngine::Element::Container.current_container = _container
_container.build _container.build
_container.parent.add(_container) _container.parent.add(_container) unless _container.is_a?(CyberarmEngine::Element::Menu)
CyberarmEngine::Element::Container.current_container = old_parent CyberarmEngine::Element::Container.current_container = old_parent

View File

@@ -180,9 +180,7 @@ module CyberarmEngine
return if self.is_a?(ToolTip) return if self.is_a?(ToolTip)
if old_width != width || old_height != height root.gui_state.request_recalculate if old_width != width || old_height != height
root.gui_state.request_recalculate
end
stylize stylize
end end
@@ -577,7 +575,7 @@ module CyberarmEngine
end end
def recalculate_if_size_changed 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 root.gui_state.request_recalculate
@old_width = width @old_width = width
@@ -628,7 +626,19 @@ module CyberarmEngine
end end
def recalculate 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 end
def reposition def reposition

View File

@@ -34,7 +34,7 @@ module CyberarmEngine
@text.draw @text.draw
end end
def recalculate def layout
unless @enabled unless @enabled
@style.background_canvas.background = @style.disabled[:background] @style.background_canvas.background = @style.disabled[:background]
@text.color = @style.disabled[:color] @text.color = @style.disabled[:color]

View File

@@ -49,9 +49,7 @@ module CyberarmEngine
root.gui_state.request_recalculate_for(self) if @children.delete(element) root.gui_state.request_recalculate_for(self) if @children.delete(element)
end end
def clear(&block) def append(&block)
@children.clear
old_container = CyberarmEngine::Element::Container.current_container old_container = CyberarmEngine::Element::Container.current_container
CyberarmEngine::Element::Container.current_container = self CyberarmEngine::Element::Container.current_container = self
@@ -62,7 +60,9 @@ module CyberarmEngine
root.gui_state.request_recalculate_for(self) root.gui_state.request_recalculate_for(self)
end end
def append(&block) def clear(&block)
@children.clear
old_container = CyberarmEngine::Element::Container.current_container old_container = CyberarmEngine::Element::Container.current_container
CyberarmEngine::Element::Container.current_container = self CyberarmEngine::Element::Container.current_container = self
@@ -151,20 +151,24 @@ module CyberarmEngine
end end
def recalculate 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) @current_position = Vector.new(@style.margin_left + @style.padding_left, @style.margin_top + @style.padding_top)
return unless visible? return unless visible?
Stats.frame&.increment(:gui_recalculations) Stats.frame&.increment(:gui_recalculations)
stylize
# s = Gosu.milliseconds # s = Gosu.milliseconds
stylize
layout layout
old_width = @width # Old sizes MUST be determined AFTER call to layout
old_height = @height old_width = width
old_height = height
@cached_scroll_width = nil @cached_scroll_width = nil
@cached_scroll_height = nil @cached_scroll_height = nil
@@ -207,6 +211,7 @@ module CyberarmEngine
end end
end end
# t = Gosu.milliseconds
# Move children to parent after positioning # Move children to parent after positioning
@children.each do |child| @children.each do |child|
child.x += (@x + @style.border_thickness_left) - style.margin_left child.x += (@x + @style.border_thickness_left) - style.margin_left
@@ -216,12 +221,11 @@ module CyberarmEngine
child.recalculate child.recalculate
child.reposition # TODO: Implement top,bottom,left,center, and right positioning 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) update_child_element_visibity(child)
end end
# puts "TOOK: #{Gosu.milliseconds - t}ms to recalculate #{self.class}:0x#{self.object_id.to_s(16)}'s #{@children.count} children"
# puts "TOOK: #{Gosu.milliseconds - s}ms to recalculate #{self.class}:0x#{self.object_id.to_s(16)}"
update_background update_background
@@ -236,17 +240,11 @@ module CyberarmEngine
@scroll_target_position.y = 0 @scroll_target_position.y = 0
end 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 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 end
def layout def layout

View File

@@ -278,7 +278,7 @@ module CyberarmEngine
:handled :handled
end end
def recalculate def layout
super super
@width = dimensional_size(@style.width, :width) || default(:width) @width = dimensional_size(@style.width, :width) || default(:width)

View File

@@ -27,7 +27,7 @@ module CyberarmEngine
:handled :handled
end end
def recalculate def layout
_width = dimensional_size(@style.width, :width) _width = dimensional_size(@style.width, :width)
_height = dimensional_size(@style.height, :height) _height = dimensional_size(@style.height, :height)

View File

@@ -12,21 +12,7 @@ module CyberarmEngine
@style.background_canvas.background = default(:background) @style.background_canvas.background = default(:background)
# TODO: "Clean Up" into own class? @menu = Menu.new(parent: self, theme: @options[:theme])
@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
self.choose = @choose self.choose = @choose
end end
@@ -40,7 +26,13 @@ module CyberarmEngine
def choose=(item) def choose=(item)
valid = @items.detect { |i| i == 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 @choose = item
@@ -62,39 +54,25 @@ module CyberarmEngine
end end
def show_menu def show_menu
@menu.clear @menu.clear do
@menu.style.width = width @menu.style.width = width
@items.each do |item| @items.each do |item|
next if item == self.value # prevent already selected item from appearing in list
# NOTE: Remove this? Might be kinda confusing...
next if item == self.value
btn = Button.new( root.gui_state.menu_item(item, width: 1.0, margin: 0, border_color: 0x00ffffff) do
item,
{
parent: @menu,
width: 1.0,
theme: @options[:theme],
margin: 0,
border_color: 0x00ffffff
},
proc do
self.choose = item self.choose = item
@block&.call(self.value) @block&.call(self.value)
end end
) end
@menu.add(btn)
end end
recalculate recalculate
root.gui_state.show_menu(@menu) @menu.show
end
def recalculate
super
@menu.recalculate
end end
end end
end end

View File

@@ -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

View File

@@ -0,0 +1,6 @@
module CyberarmEngine
class Element
class MenuItem < Button
end
end
end

View File

@@ -19,7 +19,7 @@ module CyberarmEngine
@fraction_background.draw @fraction_background.draw
end end
def recalculate def layout
_width = dimensional_size(@style.width, :width) _width = dimensional_size(@style.width, :width)
_height = dimensional_size(@style.height, :height) _height = dimensional_size(@style.height, :height)
@width = _width @width = _width

View File

@@ -47,7 +47,7 @@ module CyberarmEngine
add(@handle) add(@handle)
end end
def recalculate def layout
_width = dimensional_size(@style.width, :width) _width = dimensional_size(@style.width, :width)
_height = dimensional_size(@style.height, :height) _height = dimensional_size(@style.height, :height)
@@ -55,7 +55,7 @@ module CyberarmEngine
@height = _height @height = _height
position_handle position_handle
@handle.recalculate @handle.layout
@handle.update_background @handle.update_background
update_background update_background

View File

@@ -38,16 +38,13 @@ module CyberarmEngine
end end
end end
def recalculate def layout
unless @enabled unless @enabled
@text.color = @style.disabled[:color] @text.color = @style.disabled[:color]
else else
@text.color = @style.color @text.color = @style.color
end end
old_width = @width
old_height = @height
@width = 0 @width = 0
@height = 0 @height = 0
@@ -91,9 +88,6 @@ module CyberarmEngine
end end
update_background update_background
root.gui_state.request_repaint if @width != old_width || @height != old_height
recalculate_if_size_changed
end end
def handle_text_wrapping(max_width) def handle_text_wrapping(max_width)

View File

@@ -7,8 +7,6 @@ module CyberarmEngine
if options.dig(:theme, :ToggleButton, :checkmark_image) if options.dig(:theme, :ToggleButton, :checkmark_image)
options[:theme][:ToggleButton][:image_width] ||= options[:theme][:TextBlock][:text_size] options[:theme][:ToggleButton][:image_width] ||= options[:theme][:TextBlock][:text_size]
super(get_image(options.dig(:theme, :ToggleButton, :checkmark_image)), options, block) super(get_image(options.dig(:theme, :ToggleButton, :checkmark_image)), options, block)
@_image = @image
else else
super(options[:checkmark], options, block) super(options[:checkmark], options, block)
end end
@@ -16,10 +14,8 @@ module CyberarmEngine
@value = options[:checked] || false @value = options[:checked] || false
if @value if @value
@image = @_image if @_image
@raw_text = @options[:checkmark] @raw_text = @options[:checkmark]
else else
@image = nil
@raw_text = "" @raw_text = ""
end end
end end
@@ -32,6 +28,14 @@ module CyberarmEngine
:handled :handled
end end
def render
if @image
draw_image if @value
else
draw_text
end
end
def recalculate def recalculate
super super
return if @image return if @image
@@ -49,10 +53,8 @@ module CyberarmEngine
@value = boolean @value = boolean
if boolean if boolean
@image = @_image if @_image
@raw_text = @options[:checkmark] @raw_text = @options[:checkmark]
else else
@image = nil
@raw_text = "" @raw_text = ""
end end

View File

@@ -38,6 +38,10 @@ module CyberarmEngine
@tip = Element::ToolTip.new("", parent: @root_container, z: Float::INFINITY, theme: current_theme) @tip = Element::ToolTip.new("", parent: @root_container, z: Float::INFINITY, theme: current_theme)
end end
def menu
@menu
end
# throws :blur event to focused element and sets GuiState focused element # throws :blur event to focused element and sets GuiState focused element
# Does NOT throw :focus event at element or set element as focused # Does NOT throw :focus event at element or set element as focused
def focus=(element) def focus=(element)
@@ -50,6 +54,24 @@ module CyberarmEngine
end end
def draw 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 super
if @menu if @menu
@@ -78,24 +100,6 @@ module CyberarmEngine
end end
def update 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 if @pending_focus_request
@pending_focus_request = false @pending_focus_request = false

View File

@@ -208,6 +208,17 @@ module CyberarmEngine
fraction_background: [0xffc75e61, 0xffe26623], fraction_background: [0xffc75e61, 0xffe26623],
border_thickness: 1, border_thickness: 1,
border_color: [0xffd59674, 0xffff8746] 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 }.freeze
end end