diff --git a/lib/cyberarm_engine.rb b/lib/cyberarm_engine.rb index 58ec23d..a7f2b0e 100644 --- a/lib/cyberarm_engine.rb +++ b/lib/cyberarm_engine.rb @@ -19,16 +19,17 @@ require_relative "cyberarm_engine/ui/event" require_relative "cyberarm_engine/ui/style" require_relative "cyberarm_engine/ui/border_canvas" require_relative "cyberarm_engine/ui/element" -require_relative "cyberarm_engine/ui/label" -require_relative "cyberarm_engine/ui/button" -require_relative "cyberarm_engine/ui/toggle_button" -require_relative "cyberarm_engine/ui/edit_line" -require_relative "cyberarm_engine/ui/image" -require_relative "cyberarm_engine/ui/container" +require_relative "cyberarm_engine/ui/elements/label" +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/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/progress" -require_relative "cyberarm_engine/ui/flow" -require_relative "cyberarm_engine/ui/stack" -require_relative "cyberarm_engine/ui/check_box" require_relative "cyberarm_engine/ui/dsl" require_relative "cyberarm_engine/game_state" diff --git a/lib/cyberarm_engine/engine.rb b/lib/cyberarm_engine/engine.rb index 1ce9f35..a1e1c0b 100644 --- a/lib/cyberarm_engine/engine.rb +++ b/lib/cyberarm_engine/engine.rb @@ -62,7 +62,7 @@ module CyberarmEngine @states << klass else @states << klass.new(options) if child_of?(klass, GameState) - @states << klass.new if child_of?(klass, Container) + @states << klass.new if child_of?(klass, Element::Container) end end diff --git a/lib/cyberarm_engine/ui/button.rb b/lib/cyberarm_engine/ui/button.rb deleted file mode 100644 index 00d1fff..0000000 --- a/lib/cyberarm_engine/ui/button.rb +++ /dev/null @@ -1,53 +0,0 @@ -module CyberarmEngine - class Button < Label - def initialize(text, options = {}, block = nil) - super(text, options, block) - - @style.background_canvas.background = default(:background) - end - - def render - draw_text - end - - def draw_text - @text.draw - end - - def enter(sender) - @focus = false unless window.button_down?(Gosu::MsLeft) - - if @focus - @style.background_canvas.background = default(:active, :background) - @text.color = default(:active, :color) - else - @style.background_canvas.background = default(:hover, :background) - @text.color = default(:hover, :color) - end - end - - def left_mouse_button(sender, x, y) - @focus = true - @style.background_canvas.background = default(:active, :background) - window.current_state.focus = self - @text.color = default(:active, :color) - end - - def released_left_mouse_button(sender,x, y) - enter(sender) - end - - def clicked_left_mouse_button(sender, x, y) - @block.call(self) if @block - end - - def leave(sender) - @style.background_canvas.background = default(:background) - @text.color = default(:color) - end - - def blur(sender) - @focus = false - end - end -end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/check_box.rb b/lib/cyberarm_engine/ui/check_box.rb deleted file mode 100644 index a4a8695..0000000 --- a/lib/cyberarm_engine/ui/check_box.rb +++ /dev/null @@ -1,57 +0,0 @@ -module CyberarmEngine - class CheckBox < Flow - def initialize(text, options, block = nil) - super({}, block = nil) - options[:toggled] = options[:checked] - - @toggle_button = ToggleButton.new(options) - @label = Label.new(text, options) - - define_label_singletons - - add(@toggle_button) - add(@label) - end - - def text=(text) - @label.text = text - recalculate - end - - def value - @toggle_button.value - end - - def value=(bool) - @toggle_button.vlaue = bool - end - - def define_label_singletons - @label.define_singleton_method(:_toggle_button) do |button| - @_toggle_button = button - end - - @label._toggle_button(@toggle_button) - - @label.define_singleton_method(:holding_left_mouse_button) do |sender, x, y| - @_toggle_button.left_mouse_button(sender, x, y) - end - - @label.define_singleton_method(:released_left_mouse_button) do |sender, x, y| - @_toggle_button.released_left_mouse_button(sender, x, y) - end - - @label.define_singleton_method(:clicked_left_mouse_button) do |sender, x, y| - @_toggle_button.clicked_left_mouse_button(sender, x, y) - end - - @label.define_singleton_method(:enter) do |sender| - @_toggle_button.enter(sender) - end - - @label.define_singleton_method(:leave) do |sender| - @_toggle_button.leave(sender) - end - end - end -end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/container.rb b/lib/cyberarm_engine/ui/container.rb deleted file mode 100644 index 611959f..0000000 --- a/lib/cyberarm_engine/ui/container.rb +++ /dev/null @@ -1,157 +0,0 @@ -module CyberarmEngine - class Container < Element - include Common - - attr_accessor :stroke_color, :fill_color - attr_reader :children, :gui_state - attr_reader :scroll_x, :scroll_y - - def initialize(options = {}, block = nil) - @gui_state = options.delete(:gui_state) - super - - @scroll_x, @scroll_y = 0, 0 - @scroll_speed = 10 - - @text_color = options[:color] - - @children = [] - end - - def build - @block.call(self) if @block - - recalculate - end - - def add(element) - @children << element - - recalculate - end - - def render - Gosu.clip_to(@x, @y, width, height) do - @children.each(&:draw) - end - end - - def update - @children.each(&:update) - end - - def hit_element?(x, y) - @children.reverse_each do |child| - case child - when Container - if element = child.hit_element?(x, y) - return element - end - else - return child if child.hit?(x, y) - end - end - - self if hit?(x, y) - end - - def recalculate - @current_position = Vector.new(@style.margin_left + @style.padding_left, @style.margin_top + @style.padding_top) - return unless visible? - stylize - - layout - - if is_root? - @width = @style.width = window.width - @height = @style.height = window.height - else - _width = dimensional_size(@style.width, :width) - _height= dimensional_size(@style.height,:height) - @width = _width ? _width : (@children.map {|c| c.x + c.outer_width }.max || 0).round - @height = _height ? _height : (@children.map {|c| c.y + c.outer_height}.max || 0).round - end - - - # Move child to parent after positioning - @children.each do |child| - child.x += @x - child.y += @y - - child.stylize - child.recalculate - child.reposition # TODO: Implement top,bottom,left,center, and right positioning - end - - update_background - end - - def layout - raise "Not overridden" - end - - def max_width - @max_width ? @max_width : window.width - (@parent ? @parent.style.margin_right + @style.margin_right : @style.margin_right) - end - - def fits_on_line?(element) # Flow - @current_position.x + element.outer_width <= max_width && - @current_position.x + element.outer_width <= window.width - end - - def position_on_current_line(element) # Flow - element.x = element.style.margin_left + @current_position.x - element.y = element.style.margin_top + @current_position.y - - element.recalculate - - @current_position.x += element.outer_width - @current_position.x = @style.margin_left if @current_position.x >= max_width - end - - def tallest_neighbor(querier, y_position) # Flow - response = querier - @children.each do |child| - response = child if child.outer_height > response.outer_height - break if child == querier - end - - return response - end - - def position_on_next_line(child) # Flow - @current_position.x = @style.margin_left - @current_position.y += tallest_neighbor(child, @current_position.y).outer_height - - child.x = child.style.margin_left + @current_position.x - child.y = child.style.margin_top + @current_position.y - - child.recalculate - - @current_position.x += child.outer_width - end - - def move_to_next_line(element) # Stack - element.x = element.style.margin_left + @current_position.x - element.y = element.style.margin_top + @current_position.y - - element.recalculate - - @current_position.y += element.outer_height - end - - # def mouse_wheel_up(sender, x, y) - # @children.each {|c| c.y -= @scroll_speed} - # @children.each {|c| c.recalculate} - # end - - # def mouse_wheel_down(sender, x, y) - # @children.each {|c| c.y += @scroll_speed} - # @children.each {|c| c.recalculate} - # end - - def value - @children.map {|c| c.class}.join(", ") - end - end -end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/dsl.rb b/lib/cyberarm_engine/ui/dsl.rb index d6492ec..f68dc04 100644 --- a/lib/cyberarm_engine/ui/dsl.rb +++ b/lib/cyberarm_engine/ui/dsl.rb @@ -3,7 +3,7 @@ module CyberarmEngine def flow(options = {}, &block) options[:parent] = @containers.last options[:theme] = current_theme - _container = Flow.new(options, block) + _container = Element::Flow.new(options, block) @containers << _container _container.build _container.parent.add(_container) @@ -15,7 +15,7 @@ module CyberarmEngine def stack(options = {}, &block) options[:parent] = @containers.last options[:theme] = current_theme - _container = Stack.new(options, block) + _container = Element::Stack.new(options, block) @containers << _container _container.build _container.parent.add(_container) @@ -27,7 +27,7 @@ module CyberarmEngine def label(text, options = {}, &block) options[:parent] = @containers.last options[:theme] = current_theme - _element = Label.new(text, options, block) + _element = Element::Label.new(text, options, block) @containers.last.add(_element) return _element @@ -36,7 +36,7 @@ module CyberarmEngine def button(text, options = {}, &block) options[:parent] = @containers.last options[:theme] = current_theme - _element = Button.new(text, options, block) { if block.is_a?(Proc); block.call; end } + _element = Element::Button.new(text, options, block) { if block.is_a?(Proc); block.call; end } @containers.last.add(_element) return _element @@ -45,7 +45,7 @@ module CyberarmEngine def edit_line(text, options = {}, &block) options[:parent] = @containers.last options[:theme] = current_theme - _element = EditLine.new(text, options, block) + _element = Element::EditLine.new(text, options, block) @containers.last.add(_element) return _element @@ -54,7 +54,7 @@ module CyberarmEngine def toggle_button(options = {}, &block) options[:parent] = @containers.last options[:theme] = current_theme - _element = ToggleButton.new(options, block) + _element = Element::ToggleButton.new(options, block) @containers.last.add(_element) return _element @@ -63,7 +63,7 @@ module CyberarmEngine def check_box(text, options = {}, &block) options[:parent] = @containers.last options[:theme] = current_theme - _element = CheckBox.new(text, options, block) + _element = Element::CheckBox.new(text, options, block) @containers.last.add(_element) return _element @@ -72,7 +72,16 @@ module CyberarmEngine def image(path, options = {}, &block) options[:parent] = @containers.last options[:theme] = current_theme - _element = Image.new(path, options, block) + _element = Element::Image.new(path, options, block) + @containers.last.add(_element) + + return _element + end + + def progress(options = {}, &block) + options[:parent] = @containers.last + options[:theme] = current_theme + _element = Element::Progress.new(options, block) @containers.last.add(_element) return _element diff --git a/lib/cyberarm_engine/ui/edit_line.rb b/lib/cyberarm_engine/ui/edit_line.rb deleted file mode 100644 index fce8b4a..0000000 --- a/lib/cyberarm_engine/ui/edit_line.rb +++ /dev/null @@ -1,90 +0,0 @@ -module CyberarmEngine - class EditLine < Button - def initialize(text, options = {}, block = nil) - super(text, options, block) - - @type = default(:type) - - @caret_width = default(:caret_width) - @caret_height= @text.height - @caret_color = default(:caret_color) - @caret_interval = default(:caret_interval) - @caret_last_interval = Gosu.milliseconds - @show_caret = true - - @text_input = Gosu::TextInput.new - @text_input.text = text - - return self - end - - def render - Gosu.clip_to(@text.x, @text.y, @style.width, @text.height) do - draw_text - Gosu.draw_rect(caret_position, @text.y, @caret_width, @caret_height, @caret_color, @z + 40) if @focus && @show_caret - end - end - - def update - if @type == :password - @text.text = default(:password_character) * @text_input.text.length - else - @text.text = @text_input.text - end - - if Gosu.milliseconds >= @caret_last_interval + @caret_interval - @caret_last_interval = Gosu.milliseconds - - @show_caret = !@show_caret - end - end - - def left_mouse_button(sender, x, y) - super - window.text_input = @text_input - end - - def enter(sender) - if @focus - @style.background_canvas.background = default(:active, :background) - @text.color = default(:active, :color) - else - @style.background_canvas.background = default(:hover, :background) - @text.color = default(:hover, :color) - end - end - - def leave(sender) - unless @focus - super - end - end - - def blur(sender) - @focus = false - @style.background_canvas.background = default(:background) - @text.color = default(:color) - window.text_input = nil - end - - # TODO: Fix caret rendering in wrong position unless caret_pos is at end of text - def caret_position - if @type == :password - @text.x + @text.textobject.text_width(default(:password_character) * @text_input.text[0..@text_input.caret_pos-1].length) - else - @text.x + @text.textobject.text_width(@text_input.text[0..@text_input.caret_pos-1]) - end - end - - def recalculate - super - - @width = dimensional_size(@style.width, :width) || default(:width) - update_background - end - - def value - @text_input.text - end - end -end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/elements/button.rb b/lib/cyberarm_engine/ui/elements/button.rb new file mode 100644 index 0000000..dd6f1bc --- /dev/null +++ b/lib/cyberarm_engine/ui/elements/button.rb @@ -0,0 +1,55 @@ +module CyberarmEngine + class Element + class Button < Label + def initialize(text, options = {}, block = nil) + super(text, options, block) + + @style.background_canvas.background = default(:background) + end + + def render + draw_text + end + + def draw_text + @text.draw + end + + def enter(sender) + @focus = false unless window.button_down?(Gosu::MsLeft) + + if @focus + @style.background_canvas.background = default(:active, :background) + @text.color = default(:active, :color) + else + @style.background_canvas.background = default(:hover, :background) + @text.color = default(:hover, :color) + end + end + + def left_mouse_button(sender, x, y) + @focus = true + @style.background_canvas.background = default(:active, :background) + window.current_state.focus = self + @text.color = default(:active, :color) + end + + def released_left_mouse_button(sender,x, y) + enter(sender) + end + + def clicked_left_mouse_button(sender, x, y) + @block.call(self) if @block + end + + def leave(sender) + @style.background_canvas.background = default(:background) + @text.color = default(:color) + end + + def blur(sender) + @focus = false + end + end + end +end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/elements/check_box.rb b/lib/cyberarm_engine/ui/elements/check_box.rb new file mode 100644 index 0000000..8b2563f --- /dev/null +++ b/lib/cyberarm_engine/ui/elements/check_box.rb @@ -0,0 +1,59 @@ +module CyberarmEngine + class Element + class CheckBox < Flow + def initialize(text, options, block = nil) + super({}, block = nil) + options[:toggled] = options[:checked] + + @toggle_button = ToggleButton.new(options) + @label = Label.new(text, options) + + define_label_singletons + + add(@toggle_button) + add(@label) + end + + def text=(text) + @label.text = text + recalculate + end + + def value + @toggle_button.value + end + + def value=(bool) + @toggle_button.vlaue = bool + end + + def define_label_singletons + @label.define_singleton_method(:_toggle_button) do |button| + @_toggle_button = button + end + + @label._toggle_button(@toggle_button) + + @label.define_singleton_method(:holding_left_mouse_button) do |sender, x, y| + @_toggle_button.left_mouse_button(sender, x, y) + end + + @label.define_singleton_method(:released_left_mouse_button) do |sender, x, y| + @_toggle_button.released_left_mouse_button(sender, x, y) + end + + @label.define_singleton_method(:clicked_left_mouse_button) do |sender, x, y| + @_toggle_button.clicked_left_mouse_button(sender, x, y) + end + + @label.define_singleton_method(:enter) do |sender| + @_toggle_button.enter(sender) + end + + @label.define_singleton_method(:leave) do |sender| + @_toggle_button.leave(sender) + end + end + end + end +end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/elements/container.rb b/lib/cyberarm_engine/ui/elements/container.rb new file mode 100644 index 0000000..3a3557f --- /dev/null +++ b/lib/cyberarm_engine/ui/elements/container.rb @@ -0,0 +1,159 @@ +module CyberarmEngine + class Element + class Container < Element + include Common + + attr_accessor :stroke_color, :fill_color + attr_reader :children, :gui_state + attr_reader :scroll_x, :scroll_y + + def initialize(options = {}, block = nil) + @gui_state = options.delete(:gui_state) + super + + @scroll_x, @scroll_y = 0, 0 + @scroll_speed = 10 + + @text_color = options[:color] + + @children = [] + end + + def build + @block.call(self) if @block + + recalculate + end + + def add(element) + @children << element + + recalculate + end + + def render + Gosu.clip_to(@x, @y, width, height) do + @children.each(&:draw) + end + end + + def update + @children.each(&:update) + end + + def hit_element?(x, y) + @children.reverse_each do |child| + case child + when Container + if element = child.hit_element?(x, y) + return element + end + else + return child if child.hit?(x, y) + end + end + + self if hit?(x, y) + end + + def recalculate + @current_position = Vector.new(@style.margin_left + @style.padding_left, @style.margin_top + @style.padding_top) + return unless visible? + stylize + + layout + + if is_root? + @width = @style.width = window.width + @height = @style.height = window.height + else + _width = dimensional_size(@style.width, :width) + _height= dimensional_size(@style.height,:height) + @width = _width ? _width : (@children.map {|c| c.x + c.outer_width }.max || 0).round + @height = _height ? _height : (@children.map {|c| c.y + c.outer_height}.max || 0).round + end + + + # Move child to parent after positioning + @children.each do |child| + child.x += @x + child.y += @y + + child.stylize + child.recalculate + child.reposition # TODO: Implement top,bottom,left,center, and right positioning + end + + update_background + end + + def layout + raise "Not overridden" + end + + def max_width + @max_width ? @max_width : window.width - (@parent ? @parent.style.margin_right + @style.margin_right : @style.margin_right) + end + + def fits_on_line?(element) # Flow + @current_position.x + element.outer_width <= max_width && + @current_position.x + element.outer_width <= window.width + end + + def position_on_current_line(element) # Flow + element.x = element.style.margin_left + @current_position.x + element.y = element.style.margin_top + @current_position.y + + element.recalculate + + @current_position.x += element.outer_width + @current_position.x = @style.margin_left if @current_position.x >= max_width + end + + def tallest_neighbor(querier, y_position) # Flow + response = querier + @children.each do |child| + response = child if child.outer_height > response.outer_height + break if child == querier + end + + return response + end + + def position_on_next_line(child) # Flow + @current_position.x = @style.margin_left + @current_position.y += tallest_neighbor(child, @current_position.y).outer_height + + child.x = child.style.margin_left + @current_position.x + child.y = child.style.margin_top + @current_position.y + + child.recalculate + + @current_position.x += child.outer_width + end + + def move_to_next_line(element) # Stack + element.x = element.style.margin_left + @current_position.x + element.y = element.style.margin_top + @current_position.y + + element.recalculate + + @current_position.y += element.outer_height + end + + # def mouse_wheel_up(sender, x, y) + # @children.each {|c| c.y -= @scroll_speed} + # @children.each {|c| c.recalculate} + # end + + # def mouse_wheel_down(sender, x, y) + # @children.each {|c| c.y += @scroll_speed} + # @children.each {|c| c.recalculate} + # end + + def value + @children.map {|c| c.class}.join(", ") + end + end + end +end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/elements/edit_line.rb b/lib/cyberarm_engine/ui/elements/edit_line.rb new file mode 100644 index 0000000..1146e8d --- /dev/null +++ b/lib/cyberarm_engine/ui/elements/edit_line.rb @@ -0,0 +1,92 @@ +module CyberarmEngine + class Element + class EditLine < Button + def initialize(text, options = {}, block = nil) + super(text, options, block) + + @type = default(:type) + + @caret_width = default(:caret_width) + @caret_height= @text.height + @caret_color = default(:caret_color) + @caret_interval = default(:caret_interval) + @caret_last_interval = Gosu.milliseconds + @show_caret = true + + @text_input = Gosu::TextInput.new + @text_input.text = text + + return self + end + + def render + Gosu.clip_to(@text.x, @text.y, @style.width, @text.height) do + draw_text + Gosu.draw_rect(caret_position, @text.y, @caret_width, @caret_height, @caret_color, @z + 40) if @focus && @show_caret + end + end + + def update + if @type == :password + @text.text = default(:password_character) * @text_input.text.length + else + @text.text = @text_input.text + end + + if Gosu.milliseconds >= @caret_last_interval + @caret_interval + @caret_last_interval = Gosu.milliseconds + + @show_caret = !@show_caret + end + end + + def left_mouse_button(sender, x, y) + super + window.text_input = @text_input + end + + def enter(sender) + if @focus + @style.background_canvas.background = default(:active, :background) + @text.color = default(:active, :color) + else + @style.background_canvas.background = default(:hover, :background) + @text.color = default(:hover, :color) + end + end + + def leave(sender) + unless @focus + super + end + end + + def blur(sender) + @focus = false + @style.background_canvas.background = default(:background) + @text.color = default(:color) + window.text_input = nil + end + + # TODO: Fix caret rendering in wrong position unless caret_pos is at end of text + def caret_position + if @type == :password + @text.x + @text.textobject.text_width(default(:password_character) * @text_input.text[0..@text_input.caret_pos-1].length) + else + @text.x + @text.textobject.text_width(@text_input.text[0..@text_input.caret_pos-1]) + end + end + + def recalculate + super + + @width = dimensional_size(@style.width, :width) || default(:width) + update_background + end + + def value + @text_input.text + end + end + end +end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/elements/flow.rb b/lib/cyberarm_engine/ui/elements/flow.rb new file mode 100644 index 0000000..76ce972 --- /dev/null +++ b/lib/cyberarm_engine/ui/elements/flow.rb @@ -0,0 +1,17 @@ +module CyberarmEngine + class Element + class Flow < Container + include Common + + def layout + @children.each do |child| + if fits_on_line?(child) + position_on_current_line(child) + else + position_on_next_line(child) + end + end + end + end + end +end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/elements/image.rb b/lib/cyberarm_engine/ui/elements/image.rb new file mode 100644 index 0000000..43d2378 --- /dev/null +++ b/lib/cyberarm_engine/ui/elements/image.rb @@ -0,0 +1,50 @@ +module CyberarmEngine + class Element + class Image < Element + def initialize(path, options = {}, block = nil) + super(options, block) + @path = path + + @image = Gosu::Image.new(path, retro: @options[:image_retro]) + @scale_x, @scale_y = 1, 1 + end + + def render + @image.draw( + @style.border_thickness_left + @style.padding_left + @x, + @style.border_thickness_top + @style.padding_top + @y, + @z + 2, + @scale_x, @scale_y) # TODO: Add color support? + end + + def clicked_left_mouse_button(sender, x, y) + @block.call(self) if @block + end + + def recalculate + _width = dimensional_size(@style.width, :width) + _height= dimensional_size(@style.height,:height) + + if _width && _height + @scale_x = _width.to_f / @image.width + @scale_y = _height.to_f / @image.height + elsif _width + @scale_x = _width.to_f / @image.width + @scale_y = @scale_x + elsif _height + @scale_y = _height.to_f / @image.height + @scale_x = @scale_y + else + @scale_x, @scale_y = 1, 1 + end + + @width = _width ? _width : @image.width.round * @scale_x + @height= _height ? _height : @image.height.round * @scale_y + end + + def value + @path + end + end + end +end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/elements/label.rb b/lib/cyberarm_engine/ui/elements/label.rb new file mode 100644 index 0000000..2f43202 --- /dev/null +++ b/lib/cyberarm_engine/ui/elements/label.rb @@ -0,0 +1,45 @@ +module CyberarmEngine + class Element + class Label < Element + def initialize(text, options = {}, block = nil) + super(options, block) + + @text = Text.new(text, font: @options[:font], z: @z, color: @options[:color], size: @options[:text_size], shadow: @options[:text_shadow]) + end + + def render + @text.draw + end + + def clicked_left_mouse_button(sender, x, y) + @block.call(self) if @block + end + + def recalculate + _width = dimensional_size(@style.width, :width) + _height= dimensional_size(@style.height,:height) + @width = _width ? _width : @text.width.round + @height= _height ? _height : @text.height.round + + @text.x = @style.border_thickness_left + @style.padding_left + @x + @text.y = @style.border_thickness_top + @style.padding_top + @y + @text.z = @z + 3 + + update_background + end + + def value + @text.text + end + + def value=(value) + @text.text = value + + old_width, old_height = width, height + recalculate + + root.gui_state.request_recalculate if old_width != width || old_height != height + end + end + end +end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/elements/progress.rb b/lib/cyberarm_engine/ui/elements/progress.rb new file mode 100644 index 0000000..4827ce6 --- /dev/null +++ b/lib/cyberarm_engine/ui/elements/progress.rb @@ -0,0 +1,50 @@ +module CyberarmEngine + class Element + class Progress < Element + def initialize(options = {}, block = nil) + super(options, block) + + @fraction_background = Background.new(background: @style.fraction_background) + self.value = options[:fraction] ? options[:fraction] : 0.0 + end + + def render + @fraction_background.draw + end + + def recalculate + _width = dimensional_size(@style.width, :width) + _height= dimensional_size(@style.height,:height) + @width = _width + @height= _height + + update_background + end + + def update_background + super + + @fraction_background.x = @style.border_thickness_left + @style.padding_left + @x + @fraction_background.y = @style.border_thickness_top + @style.padding_top + @y + @fraction_background.z = @z + @fraction_background.width = @width * @fraction + @fraction_background.height = @height + + @fraction_background.background = @style.fraction_background + end + + def value + @fraction + end + + def value=(decimal) + raise "value must be number" unless decimal.is_a?(Numeric) + + @fraction = decimal.clamp(0.0, 1.0) + update_background + + return @fraction + end + end + end +end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/elements/stack.rb b/lib/cyberarm_engine/ui/elements/stack.rb new file mode 100644 index 0000000..3d01c0c --- /dev/null +++ b/lib/cyberarm_engine/ui/elements/stack.rb @@ -0,0 +1,13 @@ +module CyberarmEngine + class Element + class Stack < Container + include Common + + def layout + @children.each do |child| + move_to_next_line(child) + end + 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 new file mode 100644 index 0000000..e9e3cde --- /dev/null +++ b/lib/cyberarm_engine/ui/elements/toggle_button.rb @@ -0,0 +1,54 @@ +module CyberarmEngine + class Element + class ToggleButton < Button + attr_reader :toggled + + def initialize(options, block = nil) + super(options[:checkmark], options, block) + @toggled = options[:toggled] || false + if @toggled + @text.text = @options[:checkmark] + else + @text.text = "" + end + + return self + end + + def toggled=(boolean) + @toggled = !boolean + toggle + end + + def clicked_left_mouse_button(sender, x, y) + toggle + + @block.call(self) if @block + end + + def toggle + if @toggled + @toggled = false + @text.text = "" + else + @toggled = true + @text.text = @options[:checkmark] + end + end + + def recalculate + super + + _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 + + def value + @toggled + end + end + end +end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/flow.rb b/lib/cyberarm_engine/ui/flow.rb deleted file mode 100644 index 732c77c..0000000 --- a/lib/cyberarm_engine/ui/flow.rb +++ /dev/null @@ -1,15 +0,0 @@ -module CyberarmEngine - class Flow < Container - include Common - - def layout - @children.each do |child| - if fits_on_line?(child) - position_on_current_line(child) - else - position_on_next_line(child) - end - end - end - end -end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/gui_state.rb b/lib/cyberarm_engine/ui/gui_state.rb index 4bc16ba..f98d608 100644 --- a/lib/cyberarm_engine/ui/gui_state.rb +++ b/lib/cyberarm_engine/ui/gui_state.rb @@ -10,7 +10,7 @@ module CyberarmEngine @down_keys = {} - @root_container = Stack.new(gui_state: self) + @root_container = Element::Stack.new(gui_state: self) @game_objects << @root_container @containers = [@root_container] diff --git a/lib/cyberarm_engine/ui/image.rb b/lib/cyberarm_engine/ui/image.rb deleted file mode 100644 index 734d772..0000000 --- a/lib/cyberarm_engine/ui/image.rb +++ /dev/null @@ -1,48 +0,0 @@ -module CyberarmEngine - class Image < Element - def initialize(path, options = {}, block = nil) - super(options, block) - @path = path - - @image = Gosu::Image.new(path, retro: @options[:image_retro]) - @scale_x, @scale_y = 1, 1 - end - - def render - @image.draw( - @style.border_thickness_left + @style.padding_left + @x, - @style.border_thickness_top + @style.padding_top + @y, - @z + 2, - @scale_x, @scale_y) # TODO: Add color support? - end - - def clicked_left_mouse_button(sender, x, y) - @block.call(self) if @block - end - - def recalculate - _width = dimensional_size(@style.width, :width) - _height= dimensional_size(@style.height,:height) - - if _width && _height - @scale_x = _width.to_f / @image.width - @scale_y = _height.to_f / @image.height - elsif _width - @scale_x = _width.to_f / @image.width - @scale_y = @scale_x - elsif _height - @scale_y = _height.to_f / @image.height - @scale_x = @scale_y - else - @scale_x, @scale_y = 1, 1 - end - - @width = _width ? _width : @image.width.round * @scale_x - @height= _height ? _height : @image.height.round * @scale_y - end - - def value - @path - end - end -end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/label.rb b/lib/cyberarm_engine/ui/label.rb deleted file mode 100644 index 6fefc56..0000000 --- a/lib/cyberarm_engine/ui/label.rb +++ /dev/null @@ -1,45 +0,0 @@ -module CyberarmEngine - class Label < Element - def initialize(text, options = {}, block = nil) - super(options, block) - - @text = Text.new(text, font: @options[:font], z: @z, color: @options[:color], size: @options[:text_size], shadow: @options[:text_shadow]) - - return self - end - - def render - @text.draw - end - - def clicked_left_mouse_button(sender, x, y) - @block.call(self) if @block - end - - def recalculate - _width = dimensional_size(@style.width, :width) - _height= dimensional_size(@style.height,:height) - @width = _width ? _width : @text.width.round - @height= _height ? _height : @text.height.round - - @text.x = @style.border_thickness_left + @style.padding_left + @x - @text.y = @style.border_thickness_top + @style.padding_top + @y - @text.z = @z + 3 - - update_background - end - - def value - @text.text - end - - def value=(value) - @text.text = value - - old_width, old_height = width, height - recalculate - - root.gui_state.request_recalculate if old_width != width || old_height != height - end - end -end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/stack.rb b/lib/cyberarm_engine/ui/stack.rb deleted file mode 100644 index 0d0b9f7..0000000 --- a/lib/cyberarm_engine/ui/stack.rb +++ /dev/null @@ -1,11 +0,0 @@ -module CyberarmEngine - class Stack < Container - include Common - - def layout - @children.each do |child| - move_to_next_line(child) - end - end - end -end \ No newline at end of file diff --git a/lib/cyberarm_engine/ui/theme.rb b/lib/cyberarm_engine/ui/theme.rb index d25d708..eba3b1a 100644 --- a/lib/cyberarm_engine/ui/theme.rb +++ b/lib/cyberarm_engine/ui/theme.rb @@ -90,7 +90,7 @@ module CyberarmEngine caret_interval: 500, }, - Image: { + Image: { # < Element retro: false }, @@ -104,6 +104,15 @@ module CyberarmEngine ToggleButton: { # < Button checkmark: "√" + }, + + Progress: { # < Element + width: 250, + height: 36, + background: 0xff111111, + fraction_background: [0xffc75e61, 0xffe26623], + border_thickness: 4, + border_color: [0xffd59674, 0xffff8746] } }.freeze end diff --git a/lib/cyberarm_engine/ui/toggle_button.rb b/lib/cyberarm_engine/ui/toggle_button.rb deleted file mode 100644 index fc2db6a..0000000 --- a/lib/cyberarm_engine/ui/toggle_button.rb +++ /dev/null @@ -1,52 +0,0 @@ -module CyberarmEngine - class ToggleButton < Button - attr_reader :toggled - - def initialize(options, block = nil) - super(options[:checkmark], options, block) - @toggled = options[:toggled] || false - if @toggled - @text.text = @options[:checkmark] - else - @text.text = "" - end - - return self - end - - def toggled=(boolean) - @toggled = !boolean - toggle - end - - def clicked_left_mouse_button(sender, x, y) - toggle - - @block.call(self) if @block - end - - def toggle - if @toggled - @toggled = false - @text.text = "" - else - @toggled = true - @text.text = @options[:checkmark] - end - end - - def recalculate - super - - _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 - - def value - @toggled - end - end -end \ No newline at end of file