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.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"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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
end
def recalculate
def layout
_width = dimensional_size(@style.width, :width)
_height = dimensional_size(@style.height, :height)
@width = _width

View File

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

View File

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

View File

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

View File

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

View File

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