mirror of
https://github.com/cyberarm/cyberarm_engine.git
synced 2025-12-17 05:22:35 +00:00
Compare commits
26 Commits
v0.19.0
...
31e909eb30
| Author | SHA1 | Date | |
|---|---|---|---|
| 31e909eb30 | |||
| 300e7c4e59 | |||
| be98fe47ad | |||
| a75afaf47a | |||
| d81df5f4e2 | |||
| f2ea0d9942 | |||
| 08d068f156 | |||
| a4d02038c3 | |||
| 37bdd6ef23 | |||
| 24bd769a32 | |||
| 2be5733bc1 | |||
| c8734ae98b | |||
| c35d587419 | |||
| 153871e7f3 | |||
| cf91d4a083 | |||
| 35ad687d4c | |||
| 54802e1254 | |||
| 6cf4cd73dd | |||
| 5e5f8ba7ea | |||
| 63a51d9d2f | |||
| 6af384536a | |||
| c1b25d2045 | |||
| a915a25699 | |||
| 0aa9b59316 | |||
| d2bf406d29 | |||
| f82c101728 |
@@ -27,8 +27,8 @@ 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 "clipboard", "~> 1.3.5"
|
spec.add_dependency "clipboard", "~> 1.3"
|
||||||
spec.add_dependency "excon", "~> 0.78.0"
|
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 "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
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ require_relative "cyberarm_engine/transform"
|
|||||||
require_relative "cyberarm_engine/ray"
|
require_relative "cyberarm_engine/ray"
|
||||||
require_relative "cyberarm_engine/background"
|
require_relative "cyberarm_engine/background"
|
||||||
require_relative "cyberarm_engine/background_nine_slice"
|
require_relative "cyberarm_engine/background_nine_slice"
|
||||||
|
require_relative "cyberarm_engine/background_image"
|
||||||
require_relative "cyberarm_engine/animator"
|
require_relative "cyberarm_engine/animator"
|
||||||
|
|
||||||
require_relative "cyberarm_engine/text"
|
require_relative "cyberarm_engine/text"
|
||||||
|
|||||||
93
lib/cyberarm_engine/background_image.rb
Normal file
93
lib/cyberarm_engine/background_image.rb
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
module CyberarmEngine
|
||||||
|
class BackgroundImage
|
||||||
|
include CyberarmEngine::Common
|
||||||
|
attr_accessor :x, :y, :z, :mode
|
||||||
|
attr_reader :image, :width, :height, :color
|
||||||
|
|
||||||
|
def initialize(image_path: nil, x: 0, y: 0, z: 0, width: 0, height: 0, mode: :fill, color: Gosu::Color::WHITE)
|
||||||
|
@image_path = image_path
|
||||||
|
@image = get_image(image_path) if image_path
|
||||||
|
|
||||||
|
@x = x
|
||||||
|
@y = y
|
||||||
|
@z = z
|
||||||
|
@width = width
|
||||||
|
@height = height
|
||||||
|
|
||||||
|
@mode = mode
|
||||||
|
|
||||||
|
@color = color
|
||||||
|
|
||||||
|
@cached_tiling = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def image=(image_path)
|
||||||
|
@cached_tiling = nil if image_path != @image_path
|
||||||
|
@image_path = image_path
|
||||||
|
@image = image_path ? get_image(image_path) : image_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def width=(n)
|
||||||
|
@cached_tiling = nil if @width != n
|
||||||
|
@width = n
|
||||||
|
end
|
||||||
|
|
||||||
|
def height=(n)
|
||||||
|
@cached_tiling = nil if @height != n
|
||||||
|
@height = n
|
||||||
|
end
|
||||||
|
|
||||||
|
def color=(c)
|
||||||
|
@cached_tiling = nil if @color != c
|
||||||
|
@color = c
|
||||||
|
end
|
||||||
|
|
||||||
|
def width_scale
|
||||||
|
(@width.to_f / @image.width).abs
|
||||||
|
end
|
||||||
|
|
||||||
|
def height_scale
|
||||||
|
(@height.to_f / @image.height).abs
|
||||||
|
end
|
||||||
|
|
||||||
|
def draw
|
||||||
|
return unless @image
|
||||||
|
|
||||||
|
Gosu.clip_to(@x, @y, @width, @height) do
|
||||||
|
send(:"draw_#{mode}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def draw_stretch
|
||||||
|
@image.draw(@x, @y, @z, width_scale, height_scale, @color)
|
||||||
|
end
|
||||||
|
|
||||||
|
def draw_tiled
|
||||||
|
@cached_tiling ||= Gosu.record(@width, @height) do
|
||||||
|
height_scale.ceil.times do |y|
|
||||||
|
width_scale.ceil.times do |x|
|
||||||
|
@image.draw(x * @image.width, y * @image.height, @z, 1, 1, @color)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@cached_tiling.draw(@x, @y, @z)
|
||||||
|
end
|
||||||
|
|
||||||
|
def draw_fill
|
||||||
|
if @width * width_scale > height * height_scale
|
||||||
|
draw_fill_width
|
||||||
|
else
|
||||||
|
draw_fill_height
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def draw_fill_width
|
||||||
|
@image.draw(@x, @y, @z, width_scale, width_scale, @color)
|
||||||
|
end
|
||||||
|
|
||||||
|
def draw_fill_height
|
||||||
|
@image.draw(@x, @y, @z, height_scale, height_scale, @color)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -4,7 +4,7 @@ module CyberarmEngine
|
|||||||
include Event
|
include Event
|
||||||
include Common
|
include Common
|
||||||
|
|
||||||
attr_accessor :x, :y, :z, :enabled, :tip
|
attr_accessor :x, :y, :z, :tip, :element_visible
|
||||||
attr_reader :parent, :options, :style, :event_handler, :background_canvas, :border_canvas
|
attr_reader :parent, :options, :style, :event_handler, :background_canvas, :border_canvas
|
||||||
|
|
||||||
def initialize(options = {}, block = nil)
|
def initialize(options = {}, block = nil)
|
||||||
@@ -13,9 +13,9 @@ module CyberarmEngine
|
|||||||
@options = options
|
@options = options
|
||||||
@block = block
|
@block = block
|
||||||
|
|
||||||
@focus = @options[:focus].nil? ? false : @options[:focus]
|
@focus = !@options.key?(:focus) ? false : @options[:focus]
|
||||||
@enabled = @options[:enabled].nil? ? true : @options[:enabled]
|
@enabled = !@options.key?(:enabled) ? true : @options[:enabled]
|
||||||
@visible = @options[:visible].nil? ? true : @options[:visible]
|
@visible = !@options.key?(:visible) ? true : @options[:visible]
|
||||||
@tip = @options[:tip] || ""
|
@tip = @options[:tip] || ""
|
||||||
|
|
||||||
@debug_color = @options[:debug_color].nil? ? Gosu::Color::RED : @options[:debug_color]
|
@debug_color = @options[:debug_color].nil? ? Gosu::Color::RED : @options[:debug_color]
|
||||||
@@ -24,6 +24,7 @@ module CyberarmEngine
|
|||||||
|
|
||||||
@root ||= nil
|
@root ||= nil
|
||||||
@gui_state ||= nil
|
@gui_state ||= nil
|
||||||
|
@element_visible = true
|
||||||
|
|
||||||
@x = @style.x
|
@x = @style.x
|
||||||
@y = @style.y
|
@y = @style.y
|
||||||
@@ -37,6 +38,7 @@ module CyberarmEngine
|
|||||||
|
|
||||||
@style.background_canvas = Background.new
|
@style.background_canvas = Background.new
|
||||||
@style.background_nine_slice_canvas = BackgroundNineSlice.new
|
@style.background_nine_slice_canvas = BackgroundNineSlice.new
|
||||||
|
@style.background_image_canvas = BackgroundImage.new
|
||||||
@style.border_canvas = BorderCanvas.new(element: self)
|
@style.border_canvas = BorderCanvas.new(element: self)
|
||||||
|
|
||||||
@style_event = :default
|
@style_event = :default
|
||||||
@@ -51,11 +53,15 @@ module CyberarmEngine
|
|||||||
def stylize
|
def stylize
|
||||||
set_static_position
|
set_static_position
|
||||||
|
|
||||||
|
set_color
|
||||||
|
set_font
|
||||||
|
|
||||||
set_padding
|
set_padding
|
||||||
set_margin
|
set_margin
|
||||||
|
|
||||||
set_background
|
set_background
|
||||||
set_background_nine_slice
|
set_background_nine_slice
|
||||||
|
set_background_image
|
||||||
|
|
||||||
set_border_thickness
|
set_border_thickness
|
||||||
set_border_color
|
set_border_color
|
||||||
@@ -70,6 +76,15 @@ module CyberarmEngine
|
|||||||
@y = @style.y if @style.y != 0
|
@y = @style.y if @style.y != 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_color
|
||||||
|
@style.color = safe_style_fetch(:color)
|
||||||
|
@text&.color = @style.color
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_font
|
||||||
|
@text&.swap_font(safe_style_fetch(:text_size), safe_style_fetch(:font))
|
||||||
|
end
|
||||||
|
|
||||||
def set_background
|
def set_background
|
||||||
@style.background = safe_style_fetch(:background)
|
@style.background = safe_style_fetch(:background)
|
||||||
|
|
||||||
@@ -91,6 +106,14 @@ module CyberarmEngine
|
|||||||
@style.background_nine_slice_bottom = safe_style_fetch(:background_nine_slice_bottom) || @style.background_nine_slice_from_edge
|
@style.background_nine_slice_bottom = safe_style_fetch(:background_nine_slice_bottom) || @style.background_nine_slice_from_edge
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_background_image
|
||||||
|
@style.background_image = safe_style_fetch(:background_image)
|
||||||
|
@style.background_image_mode = safe_style_fetch(:background_image_mode) || :stretch
|
||||||
|
@style.background_image_color = safe_style_fetch(:background_image_color) || Gosu::Color::WHITE
|
||||||
|
@style.background_image_canvas.mode = @style.background_image_mode
|
||||||
|
@style.background_image_canvas.color = @style.background_image_color
|
||||||
|
end
|
||||||
|
|
||||||
def set_border_thickness
|
def set_border_thickness
|
||||||
@style.border_thickness = safe_style_fetch(:border_thickness)
|
@style.border_thickness = safe_style_fetch(:border_thickness)
|
||||||
|
|
||||||
@@ -138,14 +161,8 @@ module CyberarmEngine
|
|||||||
old_width = width
|
old_width = width
|
||||||
old_height = height
|
old_height = height
|
||||||
|
|
||||||
_style = @style.send(event)
|
|
||||||
@style_event = event
|
@style_event = event
|
||||||
|
|
||||||
if @text.is_a?(CyberarmEngine::Text)
|
|
||||||
@text.color = _style&.dig(:color) || @style.default[:color]
|
|
||||||
@text.swap_font(_style&.dig(:text_size) || @style.default[:text_size], _style&.dig(:font) || @style.default[:font])
|
|
||||||
end
|
|
||||||
|
|
||||||
return if self.is_a?(ToolTip)
|
return if self.is_a?(ToolTip)
|
||||||
|
|
||||||
if old_width != width || old_height != height
|
if old_width != width || old_height != height
|
||||||
@@ -238,6 +255,14 @@ module CyberarmEngine
|
|||||||
:handled
|
:handled
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def enabled=(boolean)
|
||||||
|
@enabled = boolean
|
||||||
|
|
||||||
|
recalculate
|
||||||
|
|
||||||
|
@enabled
|
||||||
|
end
|
||||||
|
|
||||||
def enabled?
|
def enabled?
|
||||||
@enabled
|
@enabled
|
||||||
end
|
end
|
||||||
@@ -246,6 +271,10 @@ module CyberarmEngine
|
|||||||
@visible
|
@visible
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def element_visible?
|
||||||
|
@element_visible
|
||||||
|
end
|
||||||
|
|
||||||
def toggle
|
def toggle
|
||||||
@visible = !@visible
|
@visible = !@visible
|
||||||
root.gui_state.request_recalculate
|
root.gui_state.request_recalculate
|
||||||
@@ -265,15 +294,15 @@ module CyberarmEngine
|
|||||||
|
|
||||||
def draw
|
def draw
|
||||||
return unless visible?
|
return unless visible?
|
||||||
|
return unless element_visible?
|
||||||
|
|
||||||
@style.background_canvas.draw
|
@style.background_canvas.draw
|
||||||
@style.background_nine_slice_canvas.draw
|
@style.background_nine_slice_canvas.draw
|
||||||
|
@style.background_image_canvas.draw
|
||||||
@style.border_canvas.draw
|
@style.border_canvas.draw
|
||||||
|
|
||||||
Gosu.clip_to(@x, @y, width, height) do
|
|
||||||
render
|
render
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def debug_draw
|
def debug_draw
|
||||||
return if defined?(GUI_DEBUG_ONLY_ELEMENT) && self.class == GUI_DEBUG_ONLY_ELEMENT
|
return if defined?(GUI_DEBUG_ONLY_ELEMENT) && self.class == GUI_DEBUG_ONLY_ELEMENT
|
||||||
@@ -370,29 +399,75 @@ module CyberarmEngine
|
|||||||
end
|
end
|
||||||
|
|
||||||
def scroll_width
|
def scroll_width
|
||||||
@children.sum(&:width) + noncontent_width
|
@children.sum(&:outer_width)
|
||||||
end
|
end
|
||||||
|
|
||||||
def scroll_height
|
def scroll_height
|
||||||
@children.sum(&:height) + noncontent_height
|
if is_a?(CyberarmEngine::Element::Flow)
|
||||||
|
return 0 if @children.size.zero?
|
||||||
|
|
||||||
|
pairs_ = []
|
||||||
|
sorted_children_ = @children.sort_by(&:y)
|
||||||
|
a_ = []
|
||||||
|
y_position_ = sorted_children_.first.y
|
||||||
|
|
||||||
|
sorted_children_.each do |child|
|
||||||
|
unless child.y == y_position_
|
||||||
|
y_position_ = child.y
|
||||||
|
pairs_ << a_
|
||||||
|
a_ = []
|
||||||
|
end
|
||||||
|
|
||||||
|
a_ << child
|
||||||
|
end
|
||||||
|
|
||||||
|
pairs_ << a_ unless pairs_.last == a_
|
||||||
|
|
||||||
|
pairs_.sum { |pair| pair.map(&:outer_height).max } + @style.padding_bottom + @style.border_thickness_bottom
|
||||||
|
else
|
||||||
|
@children.sum(&:outer_height) + @style.padding_bottom + @style.border_thickness_bottom
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def max_scroll_width
|
def max_scroll_width
|
||||||
scroll_width - width
|
scroll_width - outer_width
|
||||||
end
|
end
|
||||||
|
|
||||||
def max_scroll_height
|
def max_scroll_height
|
||||||
scroll_height - height
|
scroll_height - outer_height
|
||||||
end
|
end
|
||||||
|
|
||||||
def dimensional_size(size, dimension)
|
def dimensional_size(size, dimension)
|
||||||
raise "dimension must be either :width or :height" unless %i[width height].include?(dimension)
|
raise "dimension must be either :width or :height" unless %i[width height].include?(dimension)
|
||||||
|
|
||||||
if size.is_a?(Numeric) && size.between?(0.0, 1.0)
|
new_size = if size.is_a?(Numeric) && size.between?(0.0, 1.0)
|
||||||
(@parent.send(:"content_#{dimension}") * size).round - send(:"noncontent_#{dimension}").round
|
(@parent.send(:"content_#{dimension}") * size).floor - send(:"noncontent_#{dimension}").floor
|
||||||
else
|
else
|
||||||
size
|
size
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if @parent && @style.fill # Handle fill behavior
|
||||||
|
fill_siblings = @parent.children.select { |c| c.style.fill }.count.to_f # include self since we're dividing
|
||||||
|
|
||||||
|
if dimension == :width && @parent.is_a?(Flow)
|
||||||
|
space_available_width = ((@parent.content_width - (@parent.children.reject { |c| c.style.fill }).map(&:outer_width).sum) / fill_siblings)
|
||||||
|
space_available_width = space_available_width.nan? ? 0 : space_available_width.floor # The parent element might not have its dimensions, yet.
|
||||||
|
|
||||||
|
return space_available_width - noncontent_width
|
||||||
|
|
||||||
|
elsif dimension == :height && @parent.is_a?(Stack)
|
||||||
|
space_available_height = ((@parent.content_height - (@parent.children.reject { |c| c.style.fill }).map(&:outer_height).sum) / fill_siblings)
|
||||||
|
space_available_height = space_available_height.nan? ? 0 : space_available_height.floor # The parent element might not have its dimensions, yet.
|
||||||
|
|
||||||
|
return space_available_height - noncontent_height
|
||||||
|
end
|
||||||
|
|
||||||
|
else # Handle min_width/height and max_width/height
|
||||||
|
return @style.send(:"min_#{dimension}") if @style.send(:"min_#{dimension}") && new_size < @style.send(:"min_#{dimension}")
|
||||||
|
return @style.send(:"max_#{dimension}") if @style.send(:"max_#{dimension}") && new_size > @style.send(:"max_#{dimension}")
|
||||||
|
end
|
||||||
|
|
||||||
|
new_size
|
||||||
end
|
end
|
||||||
|
|
||||||
def background=(_background)
|
def background=(_background)
|
||||||
@@ -409,6 +484,7 @@ module CyberarmEngine
|
|||||||
|
|
||||||
@style.background_canvas.update
|
@style.background_canvas.update
|
||||||
update_background_nine_slice
|
update_background_nine_slice
|
||||||
|
update_background_image
|
||||||
@style.border_canvas.update
|
@style.border_canvas.update
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -436,6 +512,24 @@ module CyberarmEngine
|
|||||||
@style.background_nine_slice_canvas.image = @style.background_nine_slice
|
@style.background_nine_slice_canvas.image = @style.background_nine_slice
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def background_image=(image_path)
|
||||||
|
@style.background_image = image_path.is_a?(Gosu::Image) ? image_path : get_image(image_path)
|
||||||
|
update_background_image
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_background_image
|
||||||
|
@style.background_image_canvas.x = @x
|
||||||
|
@style.background_image_canvas.y = @y
|
||||||
|
@style.background_image_canvas.z = @z
|
||||||
|
@style.background_image_canvas.width = width
|
||||||
|
@style.background_image_canvas.height = height
|
||||||
|
|
||||||
|
@style.background_image_canvas.mode = @style.background_image_mode
|
||||||
|
@style.background_image_canvas.color = @style.background_image_color
|
||||||
|
|
||||||
|
@style.background_image_canvas.image = @style.background_image
|
||||||
|
end
|
||||||
|
|
||||||
def root
|
def root
|
||||||
return self if is_root?
|
return self if is_root?
|
||||||
|
|
||||||
|
|||||||
@@ -64,8 +64,8 @@ module CyberarmEngine
|
|||||||
@scale_y = 1
|
@scale_y = 1
|
||||||
end
|
end
|
||||||
|
|
||||||
@width = _width || @image.width.round * @scale_x
|
@width = _width || @image.width.floor * @scale_x
|
||||||
@height = _height || @image.height.round * @scale_y
|
@height = _height || @image.height.floor * @scale_y
|
||||||
|
|
||||||
update_background
|
update_background
|
||||||
else
|
else
|
||||||
@@ -86,9 +86,12 @@ module CyberarmEngine
|
|||||||
|
|
||||||
old_width = width
|
old_width = width
|
||||||
old_height = height
|
old_height = height
|
||||||
recalculate
|
|
||||||
|
|
||||||
root.gui_state.request_recalculate if old_width != width || old_height != height
|
if old_width != width || old_height != height
|
||||||
|
root.gui_state.request_recalculate
|
||||||
|
else
|
||||||
|
recalculate
|
||||||
|
end
|
||||||
|
|
||||||
publish(:changed, self.value)
|
publish(:changed, self.value)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ module CyberarmEngine
|
|||||||
root.gui_state.request_recalculate
|
root.gui_state.request_recalculate
|
||||||
end
|
end
|
||||||
|
|
||||||
def apend(&block)
|
def append(&block)
|
||||||
old_container = $__current_container__
|
old_container = $__current_container__
|
||||||
|
|
||||||
$__current_container__ = self
|
$__current_container__ = self
|
||||||
@@ -57,7 +57,12 @@ module CyberarmEngine
|
|||||||
end
|
end
|
||||||
|
|
||||||
def render
|
def render
|
||||||
Gosu.clip_to(@x, @y, width, height) do
|
Gosu.clip_to(
|
||||||
|
@x + @style.border_thickness_left + @style.padding_left,
|
||||||
|
@y + @style.border_thickness_top + @style.padding_top,
|
||||||
|
content_width + 1,
|
||||||
|
content_height + 1
|
||||||
|
) do
|
||||||
@children.each(&:draw)
|
@children.each(&:draw)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -103,6 +108,8 @@ module CyberarmEngine
|
|||||||
|
|
||||||
stylize
|
stylize
|
||||||
|
|
||||||
|
# s = Gosu.milliseconds
|
||||||
|
|
||||||
layout
|
layout
|
||||||
|
|
||||||
if is_root?
|
if is_root?
|
||||||
@@ -115,8 +122,8 @@ module CyberarmEngine
|
|||||||
_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 || (@children.map { |c| c.x + c.outer_width }.max || 0).round
|
@width = _width || (@children.map { |c| c.x + c.outer_width }.max || 0).floor
|
||||||
@height = _height || (@children.map { |c| c.y + c.outer_height }.max || 0).round
|
@height = _height || (@children.map { |c| c.y + c.outer_height }.max || 0).floor
|
||||||
end
|
end
|
||||||
|
|
||||||
# Move child to parent after positioning
|
# Move child to parent after positioning
|
||||||
@@ -129,8 +136,13 @@ module CyberarmEngine
|
|||||||
child.reposition # TODO: Implement top,bottom,left,center, and right positioning
|
child.reposition # TODO: Implement top,bottom,left,center, and right positioning
|
||||||
|
|
||||||
Stats.increment(:gui_recalculations_last_frame, 1)
|
Stats.increment(:gui_recalculations_last_frame, 1)
|
||||||
|
|
||||||
|
child.element_visible = child.x >= @x - child.width && child.x <= @x + width &&
|
||||||
|
child.y >= @y - child.height && child.y <= @y + height
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# puts "TOOK: #{Gosu.milliseconds - s}ms to recalculate #{self.class}:0x#{self.object_id.to_s(16)}"
|
||||||
|
|
||||||
update_background
|
update_background
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -139,12 +151,14 @@ module CyberarmEngine
|
|||||||
end
|
end
|
||||||
|
|
||||||
def max_width
|
def max_width
|
||||||
_width = dimensional_size(@style.width, :width)
|
# _width = dimensional_size(@style.width, :width)
|
||||||
if _width
|
# if _width
|
||||||
|
# outer_width
|
||||||
|
# else
|
||||||
|
# window.width - (@parent ? @parent.style.margin_right + @style.margin_right : @style.margin_right)
|
||||||
|
# end
|
||||||
|
|
||||||
outer_width
|
outer_width
|
||||||
else
|
|
||||||
window.width - (@parent ? @parent.style.margin_right + @style.margin_right : @style.margin_right)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def fits_on_line?(element) # Flow
|
def fits_on_line?(element) # Flow
|
||||||
@@ -194,7 +208,8 @@ module CyberarmEngine
|
|||||||
if @scroll_position.y < 0
|
if @scroll_position.y < 0
|
||||||
@scroll_position.y += @scroll_speed
|
@scroll_position.y += @scroll_speed
|
||||||
@scroll_position.y = 0 if @scroll_position.y > 0
|
@scroll_position.y = 0 if @scroll_position.y > 0
|
||||||
recalculate
|
|
||||||
|
root.gui_state.request_recalculate_for(self)
|
||||||
|
|
||||||
return :handled
|
return :handled
|
||||||
end
|
end
|
||||||
@@ -208,7 +223,8 @@ module CyberarmEngine
|
|||||||
if @scroll_position.y.abs < max_scroll_height
|
if @scroll_position.y.abs < max_scroll_height
|
||||||
@scroll_position.y -= @scroll_speed
|
@scroll_position.y -= @scroll_speed
|
||||||
@scroll_position.y = -max_scroll_height if @scroll_position.y.abs > max_scroll_height
|
@scroll_position.y = -max_scroll_height if @scroll_position.y.abs > max_scroll_height
|
||||||
recalculate
|
|
||||||
|
root.gui_state.request_recalculate_for(self)
|
||||||
|
|
||||||
return :handled
|
return :handled
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ module CyberarmEngine
|
|||||||
end
|
end
|
||||||
|
|
||||||
def row_at(y)
|
def row_at(y)
|
||||||
((y - @text.y) / @text.textobject.height).round
|
((y - @text.y) / @text.textobject.height).floor
|
||||||
end
|
end
|
||||||
|
|
||||||
def column_at(x, y)
|
def column_at(x, y)
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ module CyberarmEngine
|
|||||||
@scale_y = 1
|
@scale_y = 1
|
||||||
end
|
end
|
||||||
|
|
||||||
@width = _width || @image.width.round * @scale_x
|
@width = _width || @image.width.floor * @scale_x
|
||||||
@height = _height || @image.height.round * @scale_y
|
@height = _height || @image.height.floor * @scale_y
|
||||||
|
|
||||||
update_background
|
update_background
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ module CyberarmEngine
|
|||||||
@menu.define_singleton_method(:recalculate_menu) do
|
@menu.define_singleton_method(:recalculate_menu) do
|
||||||
@x = @__list_box.x
|
@x = @__list_box.x
|
||||||
@y = @__list_box.y + @__list_box.height
|
@y = @__list_box.y + @__list_box.height
|
||||||
|
|
||||||
|
@y = @__list_box.y - height if @y + height > window.height
|
||||||
end
|
end
|
||||||
@menu.instance_variable_set(:"@__list_box", self)
|
@menu.instance_variable_set(:"@__list_box", self)
|
||||||
|
|
||||||
@@ -46,10 +48,18 @@ module CyberarmEngine
|
|||||||
:handled
|
:handled
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def clicked_left_mouse_button(_sender, _x, _y)
|
||||||
|
# @block&.call(self.value) if @enabled
|
||||||
|
|
||||||
|
:handled
|
||||||
|
end
|
||||||
|
|
||||||
def show_menu
|
def show_menu
|
||||||
@menu.clear
|
@menu.clear
|
||||||
|
|
||||||
@items.each do |item|
|
@items.each do |item|
|
||||||
|
next if item == self.value
|
||||||
|
|
||||||
btn = Button.new(
|
btn = Button.new(
|
||||||
item,
|
item,
|
||||||
{
|
{
|
||||||
@@ -61,7 +71,7 @@ module CyberarmEngine
|
|||||||
},
|
},
|
||||||
proc do
|
proc do
|
||||||
self.choose = item
|
self.choose = item
|
||||||
@block&.call(item)
|
@block&.call(self.value)
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,16 @@
|
|||||||
module CyberarmEngine
|
module CyberarmEngine
|
||||||
class Element
|
class Element
|
||||||
class Progress < Element
|
class Progress < Element
|
||||||
|
attr_reader :type
|
||||||
|
|
||||||
def initialize(options = {}, block = nil)
|
def initialize(options = {}, block = nil)
|
||||||
super(options, block)
|
super(options, block)
|
||||||
|
|
||||||
|
@animation_speed = options[:animation_speed] || 3_000
|
||||||
|
@marquee_width = options[:marquee_width] || 0.25
|
||||||
|
@marquee_offset = 0
|
||||||
|
@marquee_animation_time = Gosu.milliseconds
|
||||||
|
@type = options[:type] || :linear
|
||||||
@fraction_background = Background.new(background: @style.fraction_background)
|
@fraction_background = Background.new(background: @style.fraction_background)
|
||||||
self.value = options[:fraction] || 0.0
|
self.value = options[:fraction] || 0.0
|
||||||
end
|
end
|
||||||
@@ -24,15 +31,45 @@ module CyberarmEngine
|
|||||||
def update_background
|
def update_background
|
||||||
super
|
super
|
||||||
|
|
||||||
@fraction_background.x = @style.border_thickness_left + @style.padding_left + @x
|
@fraction_background.x = (@style.border_thickness_left + @style.padding_left + @x) + @marquee_offset
|
||||||
@fraction_background.y = @style.border_thickness_top + @style.padding_top + @y
|
@fraction_background.y = @style.border_thickness_top + @style.padding_top + @y
|
||||||
@fraction_background.z = @z
|
@fraction_background.z = @z
|
||||||
@fraction_background.width = @width * @fraction
|
@fraction_background.width = @width * (@type == :marquee ? @marquee_width : @fraction)
|
||||||
@fraction_background.height = @height
|
@fraction_background.height = @height
|
||||||
|
|
||||||
@fraction_background.background = @style.fraction_background
|
@fraction_background.background = @style.fraction_background
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
super
|
||||||
|
|
||||||
|
return unless @type == :marquee
|
||||||
|
|
||||||
|
marquee_width = @width * @marquee_width
|
||||||
|
range = @width + marquee_width
|
||||||
|
|
||||||
|
@marquee_offset = (@width * (Gosu.milliseconds - @marquee_animation_time) / @animation_speed) - marquee_width
|
||||||
|
@marquee_animation_time = Gosu.milliseconds if @marquee_offset > range
|
||||||
|
|
||||||
|
update_background
|
||||||
|
end
|
||||||
|
|
||||||
|
def type=(type)
|
||||||
|
@type = type
|
||||||
|
|
||||||
|
case type
|
||||||
|
when :linear
|
||||||
|
@marquee_offset = 0
|
||||||
|
when :marquee
|
||||||
|
@marquee_offset = 0
|
||||||
|
@marquee_animation_time = Gosu.milliseconds
|
||||||
|
else
|
||||||
|
raise ArgumentError, "Only types :linear and :marquee are supported"
|
||||||
|
end
|
||||||
|
|
||||||
|
update_background
|
||||||
|
end
|
||||||
|
|
||||||
def value
|
def value
|
||||||
@fraction
|
@fraction
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -18,8 +18,15 @@ module CyberarmEngine
|
|||||||
end
|
end
|
||||||
|
|
||||||
def render
|
def render
|
||||||
|
# Gosu.clip_to is too expensive to always use so check if we actually need it.
|
||||||
|
if @text.width > width || @text.height > height
|
||||||
|
Gosu.clip_to(@x, @y, width, height) do
|
||||||
@text.draw
|
@text.draw
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
@text.draw
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def recalculate
|
def recalculate
|
||||||
unless @enabled
|
unless @enabled
|
||||||
@@ -36,8 +43,8 @@ module CyberarmEngine
|
|||||||
|
|
||||||
handle_text_wrapping(_width)
|
handle_text_wrapping(_width)
|
||||||
|
|
||||||
@width = _width || @text.width.round
|
@width = _width || @text.width.floor
|
||||||
@height = _height || @text.height.round
|
@height = _height || @text.height.floor
|
||||||
|
|
||||||
@text.y = @style.border_thickness_top + @style.padding_top + @y
|
@text.y = @style.border_thickness_top + @style.padding_top + @y
|
||||||
@text.z = @z + 3
|
@text.z = @z + 3
|
||||||
@@ -47,8 +54,8 @@ module CyberarmEngine
|
|||||||
when :left
|
when :left
|
||||||
@text.x = @style.border_thickness_left + @style.padding_left + @x
|
@text.x = @style.border_thickness_left + @style.padding_left + @x
|
||||||
when :center
|
when :center
|
||||||
@text.x = if @text.width <= outer_width
|
@text.x = if @text.width <= width
|
||||||
@x + outer_width / 2 - @text.width / 2
|
@x + width / 2 - @text.width / 2
|
||||||
else # Act as left aligned
|
else # Act as left aligned
|
||||||
@style.border_thickness_left + @style.padding_left + @x
|
@style.border_thickness_left + @style.padding_left + @x
|
||||||
end
|
end
|
||||||
@@ -61,46 +68,64 @@ module CyberarmEngine
|
|||||||
end
|
end
|
||||||
|
|
||||||
def handle_text_wrapping(max_width)
|
def handle_text_wrapping(max_width)
|
||||||
max_width ||= @parent&.width
|
max_width ||= @parent&.content_width
|
||||||
max_width ||= @x - (window.width + noncontent_width)
|
max_width ||= @x - (window.width + noncontent_width)
|
||||||
wrap_behavior = style.text_wrap
|
wrap_behavior = style.text_wrap
|
||||||
copy = @raw_text.to_s.dup
|
copy = @raw_text.to_s.dup
|
||||||
|
|
||||||
if line_width(copy[0]) <= max_width && line_width(copy) > max_width && wrap_behavior != :none
|
# Only perform text wrapping: if it is enabled, is possible to wrap, and text is too long to fit on one line
|
||||||
breaks = []
|
if wrap_behavior != :none && line_width(copy[0]) <= max_width && line_width(copy) > max_width
|
||||||
|
breaks = [] # list of indexes to insert a line break
|
||||||
line_start = 0
|
line_start = 0
|
||||||
line_end = copy.length
|
line_end = copy.length
|
||||||
|
|
||||||
while line_start != copy.length
|
stalled = false
|
||||||
if line_width(copy[line_start...line_end]) > max_width
|
stalled_interations = 0
|
||||||
line_end = ((line_end - line_start) / 2.0)
|
max_stalled_iterations = 10
|
||||||
line_end = 1.0 if line_end <= 1
|
checked_copy_length = line_width(copy[line_start..line_end])
|
||||||
elsif line_end < copy.length && line_width(copy[line_start...line_end + 1]) < max_width
|
|
||||||
# To small, grow!
|
|
||||||
# TODO: find a more efficient way
|
|
||||||
line_end += 1
|
|
||||||
|
|
||||||
else # FOUND IT!
|
# find length of lines
|
||||||
entering_line_end = line_end.floor
|
while line_width(copy[line_start..line_end]) > max_width && stalled_interations < max_stalled_iterations
|
||||||
max_reach = line_end.floor - line_start < 63 ? line_end.floor - line_start : 63
|
search_start = line_start
|
||||||
reach = 0
|
search_end = line_end
|
||||||
|
|
||||||
|
# Perform a binary search to find length of line
|
||||||
|
while search_start < search_end
|
||||||
|
midpoint = ((search_start.to_f + search_end) / 2.0).floor
|
||||||
|
|
||||||
|
if line_width(copy[line_start..midpoint]) > max_width
|
||||||
|
search_end = midpoint
|
||||||
|
else
|
||||||
|
search_start = midpoint + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if wrap_behavior == :word_wrap
|
if wrap_behavior == :word_wrap
|
||||||
max_reach.times do |i|
|
word_search_end = search_end
|
||||||
reach = i
|
failed = false
|
||||||
break if copy[line_end.floor - i].to_s.match(/[[:punct:]]| /)
|
|
||||||
|
until(copy[word_search_end].to_s.match(/[[:punct:]]| /))
|
||||||
|
word_search_end -= 1
|
||||||
|
|
||||||
|
if word_search_end <= 1 || word_search_end < line_start
|
||||||
|
failed = true
|
||||||
|
break
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# puts "Max width: #{max_width}/#{line_width(@raw_text)} Reach: {#{reach}/#{max_reach}} Line Start: #{line_start}/#{line_end.floor} (#{copy.length}|#{@raw_text.length}) [#{entering_line_end}] '#{copy}' {#{copy[line_start...line_end]}}"
|
line_start = failed ? search_end : word_search_end + 1 # walk in front of punctuation
|
||||||
line_end = line_end.floor - reach + 1 if reach != max_reach # Add +1 to walk in front of punctuation
|
else
|
||||||
|
line_start = search_end
|
||||||
end
|
end
|
||||||
|
|
||||||
breaks << line_end.floor
|
breaks << line_start
|
||||||
line_start = line_end.floor
|
|
||||||
line_end = copy.length
|
|
||||||
|
|
||||||
break if entering_line_end == copy.length || reach == max_reach
|
# Prevent locking up due to outer while loop text width < max_width check not being satisfied.
|
||||||
end
|
stalled = checked_copy_length == line_width(copy[line_start..line_end])
|
||||||
|
checked_copy_length = line_width(copy[line_start..line_end])
|
||||||
|
|
||||||
|
stalled_interations += 1 if stalled
|
||||||
|
stalled_interations = 0 unless stalled
|
||||||
end
|
end
|
||||||
|
|
||||||
breaks.each_with_index do |pos, index|
|
breaks.each_with_index do |pos, index|
|
||||||
@@ -124,9 +149,12 @@ module CyberarmEngine
|
|||||||
|
|
||||||
old_width = width
|
old_width = width
|
||||||
old_height = height
|
old_height = height
|
||||||
recalculate
|
|
||||||
|
|
||||||
root.gui_state.request_recalculate if old_width != width || old_height != height
|
if old_width != width || old_height != height
|
||||||
|
root.gui_state.request_recalculate
|
||||||
|
else
|
||||||
|
recalculate
|
||||||
|
end
|
||||||
|
|
||||||
publish(:changed, self.value)
|
publish(:changed, self.value)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ module CyberarmEngine
|
|||||||
@last_mouse_pos = nil
|
@last_mouse_pos = nil
|
||||||
@dragging_element = nil
|
@dragging_element = nil
|
||||||
@pending_recalculate_request = false
|
@pending_recalculate_request = false
|
||||||
|
@pending_element_recalculate_requests = []
|
||||||
|
|
||||||
@menu = nil
|
@menu = nil
|
||||||
@min_drag_distance = 0
|
@min_drag_distance = 0
|
||||||
@@ -56,6 +57,7 @@ module CyberarmEngine
|
|||||||
|
|
||||||
if @tip.value.length.positive?
|
if @tip.value.length.positive?
|
||||||
Gosu.flush
|
Gosu.flush
|
||||||
|
|
||||||
@tip.draw
|
@tip.draw
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -75,6 +77,9 @@ module CyberarmEngine
|
|||||||
@pending_recalculate_request = false
|
@pending_recalculate_request = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@pending_element_recalculate_requests.each(&:recalculate)
|
||||||
|
@pending_element_recalculate_requests.clear
|
||||||
|
|
||||||
if @pending_focus_request
|
if @pending_focus_request
|
||||||
@pending_focus_request = false
|
@pending_focus_request = false
|
||||||
|
|
||||||
@@ -231,6 +236,13 @@ module CyberarmEngine
|
|||||||
@pending_recalculate_request = true
|
@pending_recalculate_request = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def request_recalculate_for(element)
|
||||||
|
# element is already queued
|
||||||
|
return if @pending_element_recalculate_requests.detect { |e| e == element }
|
||||||
|
|
||||||
|
@pending_element_recalculate_requests << element
|
||||||
|
end
|
||||||
|
|
||||||
def request_focus(element)
|
def request_focus(element)
|
||||||
@pending_focus_request = true
|
@pending_focus_request = true
|
||||||
@pending_focus_element = element
|
@pending_focus_element = element
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
module CyberarmEngine
|
module CyberarmEngine
|
||||||
NAME = "InDev".freeze
|
NAME = "InDev".freeze
|
||||||
VERSION = "0.19.0".freeze
|
VERSION = "0.20.0".freeze
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user