From a70c1063876128666be423ba320632e482189a97 Mon Sep 17 00:00:00 2001 From: cyberarm Date: Mon, 22 Mar 2021 21:10:06 -0500 Subject: [PATCH] Added Link element which is basically a button without a border or background, WIP: Element border, margin, padding, and other styles are now easily changable; work is needed to make style changes survive a recalculation --- lib/cyberarm_engine/text.rb | 9 + lib/cyberarm_engine/ui/dsl.rb | 3 +- lib/cyberarm_engine/ui/element.rb | 115 ++++++++++++- lib/cyberarm_engine/ui/elements/button.rb | 63 ------- lib/cyberarm_engine/ui/elements/check_box.rb | 5 +- lib/cyberarm_engine/ui/elements/label.rb | 156 ------------------ lib/cyberarm_engine/ui/elements/text_block.rb | 9 +- lib/cyberarm_engine/ui/theme.rb | 13 ++ 8 files changed, 140 insertions(+), 233 deletions(-) delete mode 100644 lib/cyberarm_engine/ui/elements/label.rb diff --git a/lib/cyberarm_engine/text.rb b/lib/cyberarm_engine/text.rb index 1bfb982..c10ca01 100644 --- a/lib/cyberarm_engine/text.rb +++ b/lib/cyberarm_engine/text.rb @@ -65,6 +65,15 @@ module CyberarmEngine font end + def swap_font(size, font_name = @font) + if @size != size || @font != font_name + @size = size + @font = font_name + + @textobject = check_cache(size, font_name) + end + end + def text=(string) @rendered_shadow = nil @text = string diff --git a/lib/cyberarm_engine/ui/dsl.rb b/lib/cyberarm_engine/ui/dsl.rb index 10014f0..095dd8b 100644 --- a/lib/cyberarm_engine/ui/dsl.rb +++ b/lib/cyberarm_engine/ui/dsl.rb @@ -23,7 +23,8 @@ module CyberarmEngine "Tagline", "Caption", "Para", - "Inscription" + "Inscription", + "Link" ].each do |const| define_method(:"#{const.downcase}") do |text, options = {}, &block| options[:parent] = element_parent diff --git a/lib/cyberarm_engine/ui/element.rb b/lib/cyberarm_engine/ui/element.rb index a09ea2d..897e1e3 100644 --- a/lib/cyberarm_engine/ui/element.rb +++ b/lib/cyberarm_engine/ui/element.rb @@ -105,6 +105,55 @@ module CyberarmEngine @style.margin_bottom = default(:margin_bottom) || @style.margin end + def update_styles(event = :default) + _style = @style.send(event) + + if @text&.is_a?(CyberarmEngine::Text) + @text.color = _style&.dig(:color) || @style.color + @text.swap_font(_style&.dig(:text_size) || @style.text_size, _style&.dig(:font) || @style.font) + end + + _padding = (_style&.dig(:padding) || @style.padding) || 0 + + @style.padding_left = _style&.dig(:padding_left) || _padding + @style.padding_right = _style&.dig(:padding_right) || _padding + @style.padding_top = _style&.dig(:padding_top) || _padding + @style.padding_bottom = _style&.dig(:padding_bottom) || _padding + + _margin = (_style&.dig(:margin) || @style.margin) || 0 + + @style.margin_left = _style&.dig(:margin_left) || _margin + @style.margin_right = _style&.dig(:margin_right) || _margin + @style.margin_top = _style&.dig(:margin_top) || _margin + @style.margin_bottom = _style&.dig(:margin_bottom) || _margin + + @style.background_canvas.background = _style&.dig(:background) || @style.background + + _border_thickness = (_style&.dig(:border_thickness) || @style.border_thickness) || 0 + + @style.border_thickness_left = _style&.dig(:border_thickness_left) || _border_thickness + @style.border_thickness_right = _style&.dig(:border_thickness_right) || _border_thickness + @style.border_thickness_top = _style&.dig(:border_thickness_top) || _border_thickness + @style.border_thickness_bottom = _style&.dig(:border_thickness_bottom) || _border_thickness + + _border_color = (_style&.dig(:border_color) || @style.border_color) || Gosu::Color::NONE + + @style.border_color_left = _style&.dig(:border_color_left) || _border_color + @style.border_color_right = _style&.dig(:border_color_right) || _border_color + @style.border_color_top = _style&.dig(:border_color_top) || _border_color + @style.border_color_bottom = _style&.dig(:border_color_bottom) || _border_color + + @style.border_canvas.color = [ + @style.border_color_top, + @style.border_color_right, + @style.border_color_bottom, + @style.border_color_left + ] + + (root&.gui_state || @gui_state).request_recalculate + # recalculate + end + def default_events %i[left middle right].each do |button| event(:"#{button}_mouse_button") @@ -126,6 +175,62 @@ module CyberarmEngine event(:changed) end + def enter(_sender) + @focus = false unless window.button_down?(Gosu::MsLeft) + + if !@enabled + update_styles(:disabled) + elsif @focus + update_styles(:active) + else + update_styles(:hover) + end + + :handled + end + + def left_mouse_button(_sender, _x, _y) + @focus = true + + unless @enabled + update_styles(:disabled) + else + update_styles(:active) + end + + window.current_state.focus = self + + :handled + end + + def released_left_mouse_button(sender, _x, _y) + enter(sender) + + :handled + end + + def clicked_left_mouse_button(_sender, _x, _y) + @block&.call(self) if @enabled + + return :handled + end + + def leave(_sender) + unless @enabled + update_styles(:disabled) + else + update_styles + end + + :handled + end + + def blur(_sender) + @focus = false + + :handled + end + def enabled? @enabled end @@ -285,7 +390,7 @@ module CyberarmEngine end def background=(_background) - @style.background_canvas.background = (_background) + @style.background_canvas.background = _background update_background end @@ -308,11 +413,9 @@ module CyberarmEngine @root = parent loop do - if @root.parent.nil? - break - else - @root = @root.parent - end + break unless @root&.parent + + @root = @root.parent end end diff --git a/lib/cyberarm_engine/ui/elements/button.rb b/lib/cyberarm_engine/ui/elements/button.rb index 9629f6a..75e0a01 100644 --- a/lib/cyberarm_engine/ui/elements/button.rb +++ b/lib/cyberarm_engine/ui/elements/button.rb @@ -34,69 +34,6 @@ module CyberarmEngine @text.draw end - def enter(_sender) - @focus = false unless window.button_down?(Gosu::MsLeft) - - if !@enabled - @style.background_canvas.background = @style.disabled[:background] - @text.color = @style.disabled[:color] - elsif @focus - @style.background_canvas.background = @style.active[:background] - @text.color = @style.active[:color] - else - @style.background_canvas.background = @style.hover[:background] - @text.color = @style.hover[:color] - end - - :handled - end - - def left_mouse_button(_sender, _x, _y) - @focus = true - - unless @enabled - @style.background_canvas.background = @style.disabled[:background] - @text.color = @style.disabled[:color] - else - @style.background_canvas.background = @style.active[:background] - @text.color = @style.active[:color] - end - - window.current_state.focus = self - - :handled - end - - def released_left_mouse_button(sender, _x, _y) - enter(sender) - - :handled - end - - def clicked_left_mouse_button(_sender, _x, _y) - @block.call(self) if @enabled && @block - - :handled - end - - def leave(_sender) - unless @enabled - @style.background_canvas.background = @style.disabled[:background] - @text.color = @style.disabled[:color] - else - @style.background_canvas.background = @style.background - @text.color = @style.color - end - - :handled - end - - def blur(_sender) - @focus = false - - :handled - end - def recalculate unless @enabled @style.background_canvas.background = @style.disabled[:background] diff --git a/lib/cyberarm_engine/ui/elements/check_box.rb b/lib/cyberarm_engine/ui/elements/check_box.rb index c0b2677..b9ec560 100644 --- a/lib/cyberarm_engine/ui/elements/check_box.rb +++ b/lib/cyberarm_engine/ui/elements/check_box.rb @@ -5,8 +5,11 @@ module CyberarmEngine super(options, block) options[:toggled] = options[:checked] + options[:parent] = self @toggle_button = ToggleButton.new(options) - @label = TextBlock.new(text, options) + + options[:parent] = self + @label = TextBlock.new(text, options) @label.subscribe(:holding_left_mouse_button) do |sender, x, y| @toggle_button.left_mouse_button(sender, x, y) diff --git a/lib/cyberarm_engine/ui/elements/label.rb b/lib/cyberarm_engine/ui/elements/label.rb deleted file mode 100644 index 6b60af2..0000000 --- a/lib/cyberarm_engine/ui/elements/label.rb +++ /dev/null @@ -1,156 +0,0 @@ -module CyberarmEngine - class Element - class TextBlock < 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], - shadow_size: @options[:text_shadow_size], - shadow_color: @options[:text_shadow_color] - ) - - @raw_text = text - end - - def render - @text.draw - end - - def clicked_left_mouse_button(_sender, _x, _y) - @block&.call(self) if @enabled - - # return :handled - end - - def recalculate - @width = 0 - @height = 0 - - _width = dimensional_size(@style.width, :width) - _height = dimensional_size(@style.height, :height) - - handle_text_wrapping(_width) - - @width = _width || @text.width.round - @height = _height || @text.height.round - - @text.y = @style.border_thickness_top + @style.padding_top + @y - @text.z = @z + 3 - - if (text_alignment = @options[:text_align]) - case text_alignment - when :left - @text.x = @style.border_thickness_left + @style.padding_left + @x - when :center - @text.x = if @text.width <= outer_width - @x + outer_width / 2 - @text.width / 2 - else # Act as left aligned - @style.border_thickness_left + @style.padding_left + @x - end - when :right - @text.x = @x + outer_width - (@text.width + @style.border_thickness_right + @style.padding_right) - end - end - - update_background - end - - def handle_text_wrapping(max_width) - max_width ||= @parent&.width - max_width ||= @x - (window.width + noncontent_width) - wrap_behavior = style.text_wrap - copy = @raw_text.to_s.dup - - if max_width >= line_width(copy[0]) && line_width(copy) > max_width && wrap_behavior != :none - breaks = [] - line_start = 0 - line_end = copy.length - - while line_start != copy.length - if line_width(copy[line_start...line_end]) > max_width - line_end = ((line_end - line_start) / 2.0) - 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! - entering_line_end = line_end.floor - max_reach = line_end.floor - line_start < 63 ? line_end.floor - line_start : 63 - reach = 0 - - if wrap_behavior == :word_wrap - max_reach.times do |i| - reach = i - break if copy[line_end.floor - i].to_s.match(/[[:punct:]]| /) - 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_end = line_end.floor - reach + 1 if reach != max_reach # Add +1 to walk in front of punctuation - end - - breaks << line_end.floor - line_start = line_end.floor - line_end = copy.length - - break if entering_line_end == copy.length || reach == max_reach - end - end - - breaks.each_with_index do |pos, index| - copy.insert(pos + index, "\n") if pos + index >= 0 && pos + index < copy.length - end - end - - @text.text = copy - end - - def line_width(text) - (@x + @text.textobject.markup_width(text) + noncontent_width) - end - - def value - @raw_text - end - - def value=(value) - @raw_text = value.to_s.chomp - - old_width = width - old_height = height - recalculate - - root.gui_state.request_recalculate if old_width != width || old_height != height - - publish(:changed, self.value) - end - end - - class Banner < TextBlock - end - - class Title < TextBlock - end - - class Subtitle < TextBlock - end - - class Tagline < TextBlock - end - - class Caption < TextBlock - end - - class Para < TextBlock - end - - class Inscription < TextBlock - end - - # TODO: Remove in version 0.16.0+ - class Label < TextBlock - end - end -end diff --git a/lib/cyberarm_engine/ui/elements/text_block.rb b/lib/cyberarm_engine/ui/elements/text_block.rb index 1502713..52cca02 100644 --- a/lib/cyberarm_engine/ui/elements/text_block.rb +++ b/lib/cyberarm_engine/ui/elements/text_block.rb @@ -18,12 +18,6 @@ module CyberarmEngine @text.draw end - def clicked_left_mouse_button(_sender, _x, _y) - @block&.call(self) if @enabled - - # return :handled - end - def recalculate @width = 0 @height = 0 @@ -152,5 +146,8 @@ module CyberarmEngine class ToolTip < TextBlock end + + class Link < TextBlock + end end end diff --git a/lib/cyberarm_engine/ui/theme.rb b/lib/cyberarm_engine/ui/theme.rb index e6c6746..582a4cd 100644 --- a/lib/cyberarm_engine/ui/theme.rb +++ b/lib/cyberarm_engine/ui/theme.rb @@ -159,6 +159,19 @@ module CyberarmEngine border_color: 0xffaaaaaa, background: 0xff404040 }, + Link: { # < TextBlock + color: Gosu::Color::BLUE, + border_thickness: 1, + border_bottom_color: Gosu::Color::BLUE, + hover: { + color: 0xff_ff00ff, + border_bottom_color: 0xff_ff00ff + }, + active: { + color: 0xff_ff0000, + border_bottom_color: 0xff_ff0000 + } + }, ToggleButton: { # < Button checkmark: "√"