Skip to content

Commit

Permalink
Merge branch 'main' into catscradle_test_obj
Browse files Browse the repository at this point in the history
  • Loading branch information
noahgibbs authored Oct 5, 2023
2 parents 5ff35f3 + 83af65d commit 817cf24
Show file tree
Hide file tree
Showing 27 changed files with 221 additions and 62 deletions.
7 changes: 7 additions & 0 deletions examples/button_style_changed.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Shoes.app do
@p = para "This text will start red\n", stroke: :red
button "OK" do
@p.replace("... but turn green when you click it.")
@p.stroke = :green
end
end
6 changes: 6 additions & 0 deletions examples/button_styles_default.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Shoes.app do
style Shoes::Para, stroke: :red
para "This text should be red\n"
para "But this text should be green\n", stroke: :green
button "OK"
end
55 changes: 55 additions & 0 deletions examples/legacy/not_checked/speedometer_app.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Source: https://www.hanselman.com/blog/the-weekly-source-code-29-ruby-and-shoes-and-the-first-ruby-virus

class Speedometer < Widget
attr_accessor :range, :tick, :position
def initialize opts = {}
@range = opts[:range] || 200
@tick = opts[:tick] || 10
@position = opts[:position] || 0
@cx, @cy = self.left + 110, self.top + 100

nostroke
rect :top => self.top, :left => self.left,
:width => 220, :height => 200
nofill
stroke white
oval :left => @cx - 50, :top => @cy - 50, :radius => 100
(ticks + 1).times do |i|
radial_line 225 + ((270.0 / ticks) * i), 70..80
radial_line 225 + ((270.0 / ticks) * i), 45..49
end
strokewidth 2
oval :left => @cx - 70, :top => @cy - 70, :radius => 140
stroke lightgreen
oval :left => @cx - 5, :top => @cy - 5, :radius => 10
@needle = radial_line 225 + ((270.0 / @range) * @position), 0..90
end
def ticks; @range / @tick end
def radial_line deg, r
pos = ((deg / 360.0) * (2.0 * Math::PI)) - (Math::PI / 2.0)
line (Math.cos(pos) * r.begin) + @cx, (Math.sin(pos) * r.begin) + @cy,
(Math.cos(pos) * r.end) + @cx, (Math.sin(pos) * r.end) + @cy
end
def position= pos
@position = pos
@needle.remove
append do
@needle = radial_line 225 + ((270.0 / @range) * @position), 0..90
end
end
end

Shoes.app do
stack do
para "Enter a number between 0 and 100"
flow do
@p = edit_line
button "OK" do
@s.position = @p.text.to_i
end
end

@s = speedometer :range => 100, :ticks => 10
end
end

14 changes: 14 additions & 0 deletions examples/para/para_text.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Shoes.app do
stack do
@note = para " your note will appear here"

@edit_box = edit_box ""
@save_button = button "Save"

@save_button.click do
new_text = @edit_box.text
@note.text = new_text
alert("Note saved successfully!")
end
end
end
2 changes: 2 additions & 0 deletions lacci/lib/shoes/colors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

module Shoes
module Colors
extend self

COLORS = {
aliceblue: [240, 248, 255],
antiquewhite: [250, 235, 215],
Expand Down
4 changes: 4 additions & 0 deletions lacci/lib/shoes/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ module Shoes
class InvalidAttributeValueError < Shoes::Error; end

class TooManyInstancesError < Shoes::Error; end

class NoSuchStyleError < Shoes::Error; end

class NoLinkableIdError < Shoes::Error; end
end
72 changes: 64 additions & 8 deletions lacci/lib/shoes/widget.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,15 @@ class Widget < Shoes::Linkable

class << self
attr_accessor :widget_classes
attr_accessor :widget_default_styles

def inherited(subclass)
Shoes::Widget.widget_classes ||= []
Shoes::Widget.widget_classes << subclass

Shoes::Widget.widget_default_styles ||= {}
Shoes::Widget.widget_default_styles[subclass] = {}

super
end

Expand All @@ -32,6 +37,17 @@ def widget_class_by_name(name)
widget_classes.detect { |k| k.dsl_name == name.to_s }
end

def validate_as(prop_name, value)
prop_name = prop_name.to_s
hashes = display_property_hashes

h = hashes.detect { |hash| hash[:name] == prop_name }
raise(Shoes::NoSuchStyleError, "Can't find property #{prop_name.inspect} in #{self} property list: #{hashes.inspect}!") unless h

return value if h[:validator].nil?
h[:validator].call(value)
end

private

def linkable_properties
Expand All @@ -45,13 +61,14 @@ def linkable_properties_hash
public

# Display properties in Shoes Linkables are automatically sync'd with the display side objects.
# TODO: do we want types or other modifiers on specific properties?
def display_property(name)
# If a block is passed to display_property, that's the validation for the property. It should
# convert a given value to a valid value for the property or throw an exception.
def display_property(name, &validator)
name = name.to_s

return if linkable_properties_hash[name]

linkable_properties << { name: name }
linkable_properties << { name: name, validator: }
linkable_properties_hash[name] = true
end

Expand All @@ -66,6 +83,12 @@ def display_property_names
parent_prop_names | linkable_properties.map { |prop| prop[:name] }
end

def display_property_hashes
parent_hashes = self != Shoes::Widget ? self.superclass.display_property_hashes : []

parent_hashes + linkable_properties
end

def display_property_name?(name)
linkable_properties_hash[name.to_s] ||
(self != Shoes::Widget && superclass.display_property_name?(name))
Expand All @@ -78,9 +101,16 @@ def display_property_name?(name)
def initialize(*args, **kwargs)
log_init("Widget")

default_styles = Shoes::Widget.widget_default_styles[self.class]

self.class.display_property_names.each do |prop|
if kwargs[prop.to_sym]
instance_variable_set("@" + prop, kwargs[prop.to_sym])
prop_sym = prop.to_sym
if kwargs[prop_sym]
val = self.class.validate_as(prop, kwargs[prop_sym])
instance_variable_set("@" + prop, val)
elsif default_styles[prop_sym]
val = self.class.validate_as(prop, default_styles[prop_sym])
instance_variable_set("@" + prop, val)
end
end

Expand All @@ -96,7 +126,7 @@ def inspect
private

def bind_self_event(event_name, &block)
raise("Widget has no linkable_id! #{inspect}") unless linkable_id
raise(Shoes::NoLinkableIdError, "Widget has no linkable_id! #{inspect}") unless linkable_id

bind_shoes_event(event_name: event_name, target: linkable_id, &block)
end
Expand All @@ -118,6 +148,31 @@ def display_property_values
properties
end

def style(*args, **kwargs)
if args.empty? && kwargs.empty?
# Just called as .style()
display_property_values
elsif args.empty?
# This is called to set one or more Shoes styles (display properties.)
prop_names = self.class.display_property_names
unknown_styles = kwargs.keys.select { |k| !prop_names.include?(k.to_s) }
unless unknown_styles.empty?
raise Shoes::NoSuchStyleError, "Unknown styles for widget type #{self.class.name}: #{unknown_styles.join(", ")}"
end

kwargs.each do |name, val|
instance_variable_set("@#{name}", val)
end
elsif args.length == 1 && args[0] < Shoes::Widget
# Shoes supports calling .style with a Shoes class, e.g. .style(Shoes::Button, displace_left: 5)
kwargs.each do |name, val|
Shoes::Widget.widget_default_styles[args[0]][name.to_sym] = val
end
else
raise Shoes::InvalidAttributeValueError, "Unexpected arguments to style! args: #{args.inspect}, keyword args: #{kwargs.inspect}"
end
end

private

def create_display_widget
Expand Down Expand Up @@ -169,8 +224,9 @@ def method_missing(name, *args, **kwargs, &block)
prop_name = name_s[0..-2]
if self.class.display_property_name?(prop_name)
self.class.define_method(name) do |new_value|
raise "Trying to set display properties in an object with no linkable ID!" unless linkable_id
raise Shoes::NoLinkableIdError, "Trying to set display properties in an object with no linkable ID!" unless linkable_id

new_value = self.class.validate_as(prop_name, new_value)
instance_variable_set("@" + prop_name, new_value)
send_shoes_event({ prop_name => new_value }, event_name: "prop_change", target: linkable_id)
end
Expand All @@ -181,7 +237,7 @@ def method_missing(name, *args, **kwargs, &block)

if self.class.display_property_name?(name_s)
self.class.define_method(name) do
raise "Trying to get display properties in an object with no linkable ID!" unless linkable_id
raise Shoes::NoLinkableIdError, "Trying to get display properties in an object with no linkable ID!" unless linkable_id

instance_variable_get("@" + name_s)
end
Expand Down
23 changes: 11 additions & 12 deletions lacci/lib/shoes/widgets/arc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,24 @@ module Shoes
class Arc < Shoes::Widget
display_properties :left, :top, :width, :height, :angle1, :angle2, :draw_context

def initialize(*args)
@left, @top, @width, @height, @angle1, @angle2 = args
[:left, :top, :width, :height].each do |prop|
display_property(prop) { |val| convert_to_integer(val, prop) }
end

@left = convert_to_integer(@left, "left")
@top = convert_to_integer(@top, "top")
@width = convert_to_integer(@width, "width")
@height = convert_to_integer(@height, "height")
@angle1 = convert_to_float(@angle1, "angle1")
@angle2 = convert_to_float(@angle2, "angle2")
[:angle1, :angle2].each do |prop|
display_property(prop) { |val| convert_to_float(val, prop) }
end

def initialize(*args)
@draw_context = Shoes::App.instance.current_draw_context

super
self.left, self.top, self.width, self.height, self.angle1, self.angle2 = args

create_display_widget
end

private

def convert_to_integer(value, attribute_name)
def self.convert_to_integer(value, attribute_name)
begin
value = Integer(value)
raise InvalidAttributeValueError, "Negative number '#{value}' not allowed for attribute '#{attribute_name}'" if value < 0
Expand All @@ -34,7 +33,7 @@ def convert_to_integer(value, attribute_name)
end
end

def convert_to_float(value, attribute_name)
def self.convert_to_float(value, attribute_name)
begin
value = Float(value)
raise InvalidAttributeValueError, "Negative number '#{value}' not allowed for attribute '#{attribute_name}'" if value < 0
Expand Down
4 changes: 1 addition & 3 deletions lacci/lib/shoes/widgets/button.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ class Button < Shoes::Widget
display_properties :text, :width, :height, :top, :left, :color, :padding_top, :padding_bottom, :text_color, :size, :font_size

def initialize(text, width: nil, height: nil, top: nil, left: nil, color: nil, padding_top: nil, padding_bottom: nil, size: 12, text_color: nil,
font_size: nil, & block)
font_size: nil, &block)

log_init("Button")

# Properties passed as positional args, not keywords, don't get auto-set
@text = text
@color = color

@block = block

super
Expand Down
3 changes: 1 addition & 2 deletions lacci/lib/shoes/widgets/edit_box.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ class EditBox < Shoes::Widget
display_properties :text, :height, :width

def initialize(text = "", height: nil, width: nil, &block)
super
@text = text
@callback = block

super

bind_self_event("change") do |new_text|
self.text = new_text
@callback&.call(self)
Expand Down
3 changes: 1 addition & 2 deletions lacci/lib/shoes/widgets/edit_line.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ class EditLine < Shoes::Widget
display_properties :text, :width

def initialize(text = "", width: nil, &block)
super
@block = block
@text = text

super

bind_self_event("change") do |new_text|
self.text = new_text
@block&.call(new_text)
Expand Down
3 changes: 1 addition & 2 deletions lacci/lib/shoes/widgets/flow.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ class Flow < Shoes::Slot
display_properties :width, :height, :margin, :padding

def initialize(width: "100%", height: nil, margin: nil, padding: nil, **options, &block)
@options = options

super
@options = options

# Create the display-side widget *before* instance_eval, which will add child widgets with their display widgets
create_display_widget
Expand Down
2 changes: 1 addition & 1 deletion lacci/lib/shoes/widgets/font.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ class Font < Shoes::Widget
display_properties :font

def initialize(font)
@font = font
super
@font = font

create_display_widget
end
Expand Down
3 changes: 1 addition & 2 deletions lacci/lib/shoes/widgets/image.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ class Image < Shoes::Widget
display_properties :url, :width, :height, :top, :left, :click

def initialize(url, width: nil, height: nil, top: nil, left: nil, click: nil)
@url = url

super
@url = url

# Get the image dimensions
# @width, @height = size
Expand Down
3 changes: 2 additions & 1 deletion lacci/lib/shoes/widgets/line.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ class Line < Shoes::Widget
display_properties :left, :top, :x2, :y2, :draw_context

def initialize(left, top, x2, y2)
super

@left = left
@top = top
@x2 = x2
@y2 = y2
@draw_context = Shoes::App.instance.current_draw_context

super
create_display_widget
end
end
Expand Down
Loading

0 comments on commit 817cf24

Please sign in to comment.