diff --git a/cyberarm_engine.gemspec b/cyberarm_engine.gemspec index cf96af7..cfef862 100644 --- a/cyberarm_engine.gemspec +++ b/cyberarm_engine.gemspec @@ -29,6 +29,7 @@ Gem::Specification.new do |spec| spec.require_paths = ["lib"] spec.add_dependency "gosu", "~> 0.15.0" + spec.add_dependency "gosu_more_drawables", "~> 0.3" spec.add_development_dependency "bundler", "~> 1.16" spec.add_development_dependency "rake", "~> 13.0" diff --git a/lib/cyberarm_engine.rb b/lib/cyberarm_engine.rb index d534894..bd97a17 100644 --- a/lib/cyberarm_engine.rb +++ b/lib/cyberarm_engine.rb @@ -5,6 +5,7 @@ rescue LoadError => e require "gosu" end require "json" +require "gosu_more_drawables" require_relative "cyberarm_engine/version" @@ -35,15 +36,19 @@ require_relative "cyberarm_engine/ui/style" require_relative "cyberarm_engine/ui/border_canvas" require_relative "cyberarm_engine/ui/element" require_relative "cyberarm_engine/ui/elements/label" +require_relative "cyberarm_engine/ui/elements/list_box" require_relative "cyberarm_engine/ui/elements/button" require_relative "cyberarm_engine/ui/elements/toggle_button" require_relative "cyberarm_engine/ui/elements/edit_line" +require_relative "cyberarm_engine/ui/elements/edit_box" require_relative "cyberarm_engine/ui/elements/image" require_relative "cyberarm_engine/ui/elements/container" require_relative "cyberarm_engine/ui/elements/flow" require_relative "cyberarm_engine/ui/elements/stack" 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/game_state" require_relative "cyberarm_engine/ui/gui_state" diff --git a/lib/cyberarm_engine/ui/dsl.rb b/lib/cyberarm_engine/ui/dsl.rb index 0b53ea7..0628cb3 100644 --- a/lib/cyberarm_engine/ui/dsl.rb +++ b/lib/cyberarm_engine/ui/dsl.rb @@ -57,6 +57,13 @@ module CyberarmEngine add_element( Element::Progress.new(options, block) ) end + def slider(options = {}, &block) + options[:parent] = element_parent + options[:theme] = current_theme + + add_element( Element::Slider.new(options, block) ) + end + def background(color = Gosu::Color::NONE) element_parent.style.background = color end diff --git a/lib/cyberarm_engine/ui/element.rb b/lib/cyberarm_engine/ui/element.rb index a7b9afb..3729cf1 100644 --- a/lib/cyberarm_engine/ui/element.rb +++ b/lib/cyberarm_engine/ui/element.rb @@ -4,7 +4,7 @@ module CyberarmEngine include Event include Common - attr_accessor :x, :y, :z, :enabled + attr_accessor :x, :y, :z, :enabled, :tip attr_reader :parent, :options, :style, :event_handler, :background_canvas, :border_canvas def initialize(options = {}, block = nil) @@ -16,6 +16,7 @@ module CyberarmEngine @focus = false @enabled = true @visible = true + @tip = @options[:tip] ? @options[:tip] : "" @style = Style.new(options) @@ -152,6 +153,10 @@ module CyberarmEngine def button_up(id) end + def draggable?(button) + false + end + def render end diff --git a/lib/cyberarm_engine/ui/elements/container.rb b/lib/cyberarm_engine/ui/elements/container.rb index f4cb8c0..c067270 100644 --- a/lib/cyberarm_engine/ui/elements/container.rb +++ b/lib/cyberarm_engine/ui/elements/container.rb @@ -93,8 +93,8 @@ module CyberarmEngine # Move child to parent after positioning @children.each do |child| - child.x += @x - style.margin_left - child.y += @y - style.margin_top + child.x += (@x + @style.border_thickness_left) - style.margin_left + child.y += (@y + @style.border_thickness_top) - style.margin_top child.stylize child.recalculate diff --git a/lib/cyberarm_engine/ui/elements/edit_box.rb b/lib/cyberarm_engine/ui/elements/edit_box.rb new file mode 100644 index 0000000..1a68fde --- /dev/null +++ b/lib/cyberarm_engine/ui/elements/edit_box.rb @@ -0,0 +1,6 @@ +module CyberarmEngine + class Element + class EditBox < Element + end + end +end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/elements/list_box.rb b/lib/cyberarm_engine/ui/elements/list_box.rb new file mode 100644 index 0000000..076ddfa --- /dev/null +++ b/lib/cyberarm_engine/ui/elements/list_box.rb @@ -0,0 +1,6 @@ +module CyberarmEngine + class Element + class ListBox < Element + end + end +end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/elements/radio.rb b/lib/cyberarm_engine/ui/elements/radio.rb new file mode 100644 index 0000000..b847ca7 --- /dev/null +++ b/lib/cyberarm_engine/ui/elements/radio.rb @@ -0,0 +1,6 @@ +module CyberarmEngine + class Element + class Radio < Element + end + end +end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/elements/slider.rb b/lib/cyberarm_engine/ui/elements/slider.rb new file mode 100644 index 0000000..599fa42 --- /dev/null +++ b/lib/cyberarm_engine/ui/elements/slider.rb @@ -0,0 +1,101 @@ +module CyberarmEngine + class Element + class Slider < Container + class Handle < Button + def initialize(*args) + super(*args) + + event(:begin_drag) + event(:drag_update) + event(:end_drag) + end + + def draggable?(button) + button == :left + end + + def begin_drag(sender, x, y, button) + @drag_start_pos = Vector.new(x, y) + + :handled + end + + def drag_update(sender, x, y, button) + # ratio = (@parent.x - (x - @drag_start_pos.x) / (@parent.width - width) * -1).clamp(0.0, 1.0) + # @x = @parent.x + width + ((@parent.width * ratio) - width * 2) + @parent.handle_dragged_to(x, y) + + :handled + end + + def end_drag(sender, x, y, button) + @drag_start_pos = nil + + :handled + end + end + + attr_reader :range, :step_size + def initialize(options = {}, block = nil) + super(options, block) + + @range = @options[:range] ? @options[:range] : 0.0..1.0 + @step_size = @options[:step] ? @options[:step] : 0.1 + @value = @options[:value] ? @options[:value] : 0.5 + + @handle = Handle.new("", parent: self, width: 8) { close } + self.add(@handle) + end + + def recalculate + _width = dimensional_size(@style.width, :width) + _height= dimensional_size(@style.height,:height) + + @width = _width + @height = _height + + @handle.x = @x + @style.border_thickness_left + @style.padding_left + @handle.y = @y + @style.border_thickness_top + @style.padding_left + @handle.recalculate + + update_background + end + + def draw + super + + @handle.draw + end + + def update + super + + @tip = value.to_s + @handle.tip = @tip + end + + def holding_left_mouse_button(sender, x, y) + handle_dragged_to(x, y) + end + + def handle_dragged_to(x, y) + @ratio = ((x - @handle.width) - @x) / content_width + + # p [@ratio, @value] + self.value = @ratio.clamp(0.0, 1.0) * (@range.max - @range.min) + @range.min + + end + + def value + @value + end + + def value=(n) + @value = n + @handle.x = @x + @style.padding_left + @style.border_thickness_left + + (content_width * (@value - @range.min) / (@range.max - @range.min).to_f) + @handle.recalculate + end + end + end +end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/elements/toggle_button.rb b/lib/cyberarm_engine/ui/elements/toggle_button.rb index c6c9170..9139e80 100644 --- a/lib/cyberarm_engine/ui/elements/toggle_button.rb +++ b/lib/cyberarm_engine/ui/elements/toggle_button.rb @@ -43,8 +43,10 @@ module CyberarmEngine _width = dimensional_size(@style.width, :width) _height= dimensional_size(@style.height,:height) + @width = _width ? _width : @text.textobject.text_width(@options[:checkmark]) @height = _height ? _height : @text.height + update_background end diff --git a/lib/cyberarm_engine/ui/gui_state.rb b/lib/cyberarm_engine/ui/gui_state.rb index 6098f23..9f3e82d 100644 --- a/lib/cyberarm_engine/ui/gui_state.rb +++ b/lib/cyberarm_engine/ui/gui_state.rb @@ -22,6 +22,11 @@ module CyberarmEngine @mouse_down_on = {} @mouse_down_position = {} @pending_recalculate_request = false + + @tip = CyberarmEngine::Text.new("", size: 22, z: Float::INFINITY) + @menu = nil + @min_drag_distance = 0 + @mouse_pos = Vector.new end # throws :blur event to focused element and sets GuiState focused element @@ -35,6 +40,15 @@ module CyberarmEngine @focus end + def draw + super + + if @tip.text.length > 0 + Gosu.draw_rect(@tip.x - 2, @tip.y - 2, @tip.width + 4, @tip.height + 4, 0xff020202, Float::INFINITY) + @tip.draw + end + end + def update if @pending_recalculate_request @root_container.recalculate @@ -56,12 +70,30 @@ module CyberarmEngine redirect_holding_mouse_button(:middle) if @mouse_over && Gosu.button_down?(Gosu::MsMiddle) redirect_holding_mouse_button(:right) if @mouse_over && Gosu.button_down?(Gosu::MsRight) + if Vector.new(window.mouse_x, window.mouse_y) == @last_mouse_pos + if @mouse_over && (Gosu.milliseconds - @mouse_moved_at) > tool_tip_delay + @tip.text = @mouse_over.tip if @mouse_over + @tip.x, @tip.y = window.mouse_x - @tip.width / 2, window.mouse_y - @tip.height - 4 + else + @tip.text = "" + end + else + @mouse_moved_at = Gosu.milliseconds + end + + @last_mouse_pos = Vector.new(window.mouse_x, window.mouse_y) + @mouse_pos = @last_mouse_pos.clone + request_recalculate if @active_width != window.width || @active_height != window.height @active_width = window.width @active_height = window.height end + def tool_tip_delay + 500 # ms + end + def button_down(id) super @@ -115,12 +147,26 @@ module CyberarmEngine @mouse_over.publish(:"clicked_#{button}_mouse_button", window.mouse_x, window.mouse_y) if @mouse_over == @mouse_down_on[button] end + if @dragging_element + @dragging_element.publish(:end_drag, window.mouse_x, window.mouse_y, button) + @dragging_element = nil + end + @mouse_down_position[button] = nil @mouse_down_on[button] = nil end def redirect_holding_mouse_button(button) - @mouse_over.publish(:"holding_#{button}_mouse_button", window.mouse_x, window.mouse_y) if @mouse_over + if !@dragging_element && @mouse_down_on[button] && @mouse_down_on[button].draggable?(button) && @mouse_pos.distance(@mouse_down_position[button]) > @min_drag_distance + @dragging_element = @mouse_down_on[button] + @dragging_element.publish(:"begin_drag", window.mouse_x, window.mouse_y, button) + end + + if @dragging_element + @dragging_element.publish(:"drag_update", window.mouse_x, window.mouse_y, button) if @dragging_element + else + @mouse_over.publish(:"holding_#{button}_mouse_button", window.mouse_x, window.mouse_y) if @mouse_over + end end def redirect_mouse_wheel(button) diff --git a/lib/cyberarm_engine/ui/theme.rb b/lib/cyberarm_engine/ui/theme.rb index 1a3ad73..ed5f1e9 100644 --- a/lib/cyberarm_engine/ui/theme.rb +++ b/lib/cyberarm_engine/ui/theme.rb @@ -114,6 +114,15 @@ module CyberarmEngine fraction_background: [0xffc75e61, 0xffe26623], border_thickness: 1, border_color: [0xffd59674, 0xffff8746] + }, + + Slider: { # < Element + width: 250, + height: 36, + background: 0xff111111, + fraction_background: [0xffc75e61, 0xffe26623], + border_thickness: 1, + border_color: [0xffd59674, 0xffff8746] } }.freeze end