Renamed Label to TextBlock, added Shoes text dsl methods; needs mroe refinements, made tooltip styleable.

This commit is contained in:
2021-01-05 17:31:31 -06:00
parent 0268a8a5fb
commit 886680ab31
8 changed files with 255 additions and 13 deletions

View File

@@ -37,7 +37,7 @@ require_relative "cyberarm_engine/ui/event"
require_relative "cyberarm_engine/ui/style" require_relative "cyberarm_engine/ui/style"
require_relative "cyberarm_engine/ui/border_canvas" require_relative "cyberarm_engine/ui/border_canvas"
require_relative "cyberarm_engine/ui/element" require_relative "cyberarm_engine/ui/element"
require_relative "cyberarm_engine/ui/elements/label" require_relative "cyberarm_engine/ui/elements/text_block"
require_relative "cyberarm_engine/ui/elements/button" require_relative "cyberarm_engine/ui/elements/button"
require_relative "cyberarm_engine/ui/elements/toggle_button" require_relative "cyberarm_engine/ui/elements/toggle_button"
require_relative "cyberarm_engine/ui/elements/list_box" require_relative "cyberarm_engine/ui/elements/list_box"

View File

@@ -8,11 +8,29 @@ module CyberarmEngine
container(CyberarmEngine::Element::Stack, options, &block) container(CyberarmEngine::Element::Stack, options, &block)
end end
# TODO: Remove in version 0.16.0+
def label(text, options = {}, &block) def label(text, options = {}, &block)
options[:parent] = element_parent options[:parent] = element_parent
options[:theme] = current_theme options[:theme] = current_theme
add_element(Element::Label.new(text, options, block)) add_element(Element::TextBlock.new(text, options, block))
end
[
"Banner",
"Title",
"Subtitle",
"Tagline",
"Caption",
"Para",
"Inscription"
].each do |const|
define_method(:"#{const.downcase}") do |text, options, &block|
options[:parent] = element_parent
options[:theme] = current_theme
add_element(Element.const_get(const).new(text, options, block))
end
end end
def button(text, options = {}, &block) def button(text, options = {}, &block)

View File

@@ -1,6 +1,6 @@
module CyberarmEngine module CyberarmEngine
class Element class Element
class Button < Label class Button < TextBlock
def initialize(text_or_image, options = {}, block = nil) def initialize(text_or_image, options = {}, block = nil)
@image = nil @image = nil
@scale_x = 1 @scale_x = 1

View File

@@ -6,7 +6,7 @@ module CyberarmEngine
options[:toggled] = options[:checked] options[:toggled] = options[:checked]
@toggle_button = ToggleButton.new(options) @toggle_button = ToggleButton.new(options)
@label = Label.new(text, options) @label = TextBlock.new(text, options)
@label.subscribe(:holding_left_mouse_button) do |sender, x, y| @label.subscribe(:holding_left_mouse_button) do |sender, x, y|
@toggle_button.left_mouse_button(sender, x, y) @toggle_button.left_mouse_button(sender, x, y)

View File

@@ -1,6 +1,6 @@
module CyberarmEngine module CyberarmEngine
class Element class Element
class Label < Element class TextBlock < Element
def initialize(text, options = {}, block = nil) def initialize(text, options = {}, block = nil)
super(options, block) super(options, block)
@@ -127,5 +127,30 @@ module CyberarmEngine
publish(:changed, self.value) publish(:changed, self.value)
end end
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
end end

View File

@@ -0,0 +1,155 @@
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
class ToolTip < TextBlock
end
end
end

View File

@@ -26,7 +26,7 @@ module CyberarmEngine
@dragging_element = nil @dragging_element = nil
@pending_recalculate_request = false @pending_recalculate_request = false
@tip = CyberarmEngine::Text.new("", size: 22, z: Float::INFINITY) @tip = Element::ToolTip.new("", parent: @root_container, z: Float::INFINITY)
@menu = nil @menu = nil
@min_drag_distance = 0 @min_drag_distance = 0
@mouse_pos = Vector.new @mouse_pos = Vector.new
@@ -51,9 +51,8 @@ module CyberarmEngine
@menu.draw @menu.draw
end end
if @tip.text.length.positive? if @tip.value.length.positive?
Gosu.flush Gosu.flush
Gosu.draw_rect(@tip.x - 2, @tip.y - 2, @tip.width + 4, @tip.height + 4, 0xff020202, Float::INFINITY)
@tip.draw @tip.draw
end end
end end
@@ -87,11 +86,17 @@ module CyberarmEngine
if Vector.new(window.mouse_x, window.mouse_y) == @last_mouse_pos if Vector.new(window.mouse_x, window.mouse_y) == @last_mouse_pos
if @mouse_over && (Gosu.milliseconds - @mouse_moved_at) > tool_tip_delay if @mouse_over && (Gosu.milliseconds - @mouse_moved_at) > tool_tip_delay
@tip.text = @mouse_over.tip if @mouse_over @tip.value = @mouse_over.tip if @mouse_over
@tip.x = window.mouse_x - @tip.width / 2 @tip.x = window.mouse_x - @tip.width / 2
@tip.y = window.mouse_y - @tip.height - 4 @tip.x = 0 if @tip.x < 0
@tip.x = window.width - @tip.width if @tip.x + @tip.width > window.width
@tip.y = window.mouse_y - @tip.height
@tip.y = 0 if @tip.y < 0
@tip.y = window.height - @tip.height if @tip.y + @tip.height > window.height
@tip.update
@tip.recalculate
else else
@tip.text = "" @tip.value = ""
end end
else else
@mouse_moved_at = Gosu.milliseconds @mouse_moved_at = Gosu.milliseconds
@@ -107,7 +112,7 @@ module CyberarmEngine
end end
def tool_tip_delay def tool_tip_delay
500 # ms 250 # ms
end end
def button_down(id) def button_down(id)

View File

@@ -106,7 +106,7 @@ module CyberarmEngine
retro: false retro: false
}, },
Label: { # < Element TextBlock: { # < Element
text_size: 28, text_size: 28,
text_wrap: :none, # :word_wrap, :break_word, :none text_wrap: :none, # :word_wrap, :break_word, :none
text_shadow: false, text_shadow: false,
@@ -116,6 +116,45 @@ module CyberarmEngine
padding: 2 padding: 2
}, },
Banner: { # < TextBlock
text_size: 48
},
Title: { # < TextBlock
text_size: 34
},
Subtitle: { # < TextBlock
text_size: 26
},
Tagline: { # < TextBlock
text_size: 24
},
Caption: { # < TextBlock
text_size: 22
},
Para: { # < TextBlock
text_size: 18
},
Inscription: { # < TextBlock
text_size: 16
},
ToolTip: { # < TextBlock
color: Gosu::Color::WHITE,
padding_top: 4,
padding_bottom: 4,
padding_left: 8,
padding_right: 8,
border_thickness: 1,
border_color: 0xffaaaaaa,
background: 0xff404040
},
ToggleButton: { # < Button ToggleButton: { # < Button
checkmark: "" checkmark: ""
}, },