lacci 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/lacci/scarpe_cli.rb +0 -1
- data/lib/lacci/version.rb +1 -1
- data/lib/scarpe/niente/display_service.rb +5 -1
- data/lib/scarpe/niente/drawable.rb +2 -0
- data/lib/scarpe/niente/shoes_spec.rb +7 -1
- data/lib/scarpe/niente.rb +14 -2
- data/lib/shoes/app.rb +44 -50
- data/lib/shoes/constants.rb +23 -2
- data/lib/shoes/display_service.rb +43 -4
- data/lib/shoes/drawable.rb +309 -35
- data/lib/shoes/drawables/arc.rb +2 -24
- data/lib/shoes/drawables/arrow.rb +2 -22
- data/lib/shoes/drawables/border.rb +28 -0
- data/lib/shoes/drawables/button.rb +4 -20
- data/lib/shoes/drawables/check.rb +7 -3
- data/lib/shoes/drawables/document_root.rb +4 -4
- data/lib/shoes/drawables/edit_box.rb +6 -5
- data/lib/shoes/drawables/edit_line.rb +5 -4
- data/lib/shoes/drawables/flow.rb +3 -5
- data/lib/shoes/drawables/font_helper.rb +62 -0
- data/lib/shoes/drawables/image.rb +2 -2
- data/lib/shoes/drawables/line.rb +4 -7
- data/lib/shoes/drawables/link.rb +5 -8
- data/lib/shoes/drawables/list_box.rb +8 -5
- data/lib/shoes/drawables/oval.rb +48 -0
- data/lib/shoes/drawables/para.rb +106 -18
- data/lib/shoes/drawables/progress.rb +2 -1
- data/lib/shoes/drawables/radio.rb +5 -3
- data/lib/shoes/drawables/rect.rb +5 -4
- data/lib/shoes/drawables/shape.rb +2 -1
- data/lib/shoes/drawables/slot.rb +99 -8
- data/lib/shoes/drawables/stack.rb +6 -11
- data/lib/shoes/drawables/star.rb +8 -30
- data/lib/shoes/drawables/text_drawable.rb +93 -34
- data/lib/shoes/drawables/video.rb +3 -2
- data/lib/shoes/drawables/widget.rb +8 -3
- data/lib/shoes/drawables.rb +2 -1
- data/lib/shoes/errors.rb +13 -3
- data/lib/shoes/margin_helper.rb +79 -0
- data/lib/shoes.rb +4 -3
- metadata +11 -11
- data/lib/scarpe/niente/logger.rb +0 -29
- data/lib/shoes/drawables/span.rb +0 -27
- data/lib/shoes/spacing.rb +0 -9
data/lib/shoes/drawable.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
require_relative 'margin_helper'
|
3
3
|
class Shoes
|
4
4
|
# Shoes::Drawable
|
5
5
|
#
|
@@ -15,7 +15,7 @@ class Shoes
|
|
15
15
|
include Shoes::Colors
|
16
16
|
|
17
17
|
# All Drawables have these so they go in Shoes::Drawable and are inherited
|
18
|
-
@shoes_events = ["parent", "destroy", "prop_change"]
|
18
|
+
@shoes_events = ["parent", "destroy", "prop_change", "hover", "leave", "motion"]
|
19
19
|
|
20
20
|
class << self
|
21
21
|
attr_accessor :drawable_classes
|
@@ -43,7 +43,8 @@ class Shoes
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def drawable_class_by_name(name)
|
46
|
-
|
46
|
+
name = name.to_s
|
47
|
+
drawable_classes.detect { |k| k.dsl_name == name }
|
47
48
|
end
|
48
49
|
|
49
50
|
def is_widget_class?(name)
|
@@ -53,13 +54,14 @@ class Shoes
|
|
53
54
|
def validate_as(prop_name, value)
|
54
55
|
prop_name = prop_name.to_s
|
55
56
|
hashes = shoes_style_hashes
|
56
|
-
|
57
|
+
|
57
58
|
h = hashes.detect { |hash| hash[:name] == prop_name }
|
58
59
|
raise(Shoes::Errors::NoSuchStyleError, "Can't find property #{prop_name.inspect} in #{self} property list: #{hashes.inspect}!") unless h
|
59
|
-
|
60
|
+
|
60
61
|
return value if h[:validator].nil?
|
61
|
-
|
62
|
-
|
62
|
+
|
63
|
+
# Pass both the property name and value to the validator block
|
64
|
+
h[:validator].call(value,prop_name)
|
63
65
|
end
|
64
66
|
|
65
67
|
# Return a list of Shoes events for this class.
|
@@ -67,18 +69,65 @@ class Shoes
|
|
67
69
|
# @return Array[String] the list of event names
|
68
70
|
def get_shoes_events
|
69
71
|
if @shoes_events.nil?
|
70
|
-
raise
|
72
|
+
raise Shoes::Errors::UnknownEventsForClassError, "Drawable type #{self} hasn't defined its list of Shoes events!"
|
71
73
|
end
|
72
74
|
|
73
75
|
@shoes_events
|
74
76
|
end
|
75
77
|
|
78
|
+
# Return whether Shoes events have already been registered for this class
|
79
|
+
#
|
80
|
+
# @return [Boolean] true if events have been registered, false if not
|
81
|
+
def registered_shoes_events?
|
82
|
+
!@shoes_events.nil?
|
83
|
+
end
|
84
|
+
|
76
85
|
# Set the list of Shoes event names that are allowed for this class.
|
77
86
|
#
|
78
87
|
# @param args [Array] an array of event names, which will be coerced to Strings
|
79
88
|
# @return [void]
|
80
89
|
def shoes_events(*args)
|
81
|
-
@shoes_events
|
90
|
+
if @shoes_events
|
91
|
+
raise Shoes::Errors::DoubleRegisteredShoesEventError, "Registering shoes events #{args.inspect} for class #{self} but already registered events as #{@shoes_events.inspect}!"
|
92
|
+
end
|
93
|
+
@shoes_events = args.map(&:to_s) + self.superclass.get_shoes_events
|
94
|
+
end
|
95
|
+
|
96
|
+
# Require supplying these Shoes style values as positional arguments to
|
97
|
+
# initialize. Initialize will get the arg list, then set the specified styles
|
98
|
+
# if args are given for them. @see opt_init_args for additional non-required
|
99
|
+
# init args.
|
100
|
+
#
|
101
|
+
# @param args [Array<String,Symbol>] an array of Shoes style names
|
102
|
+
# @return [void]
|
103
|
+
def init_args(*args)
|
104
|
+
raise Shoes::Errors::BadArgumentListError, "Positional init args already set for #{self}!" if @required_init_args
|
105
|
+
@required_init_args = args.map(&:to_s)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Allow supplying these Shoes style values as optional positional arguments to
|
109
|
+
# initialize after the mandatory args. @see init_args for setting required
|
110
|
+
# init args.
|
111
|
+
#
|
112
|
+
# @param args [Array<String,Symbol>] an array of Shoes style names
|
113
|
+
# @return [void]
|
114
|
+
def opt_init_args(*args)
|
115
|
+
raise Shoes::Errors::BadArgumentListError, "Positional init args already set for #{self}!" if @opt_init_args
|
116
|
+
@opt_init_args = args.map(&:to_s)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Return the list of style names for required init args for this class
|
120
|
+
#
|
121
|
+
# @return [Array<String>] the array of style names as strings
|
122
|
+
def required_init_args
|
123
|
+
@required_init_args ||= [] # TODO: eventually remove the ||= here
|
124
|
+
end
|
125
|
+
|
126
|
+
# Return the list of style names for optional init args for this class
|
127
|
+
#
|
128
|
+
# @return [Array<String>] the array of style names as strings
|
129
|
+
def optional_init_args
|
130
|
+
@opt_init_args ||= []
|
82
131
|
end
|
83
132
|
|
84
133
|
# Assign a new Shoes Drawable ID number, starting from 1.
|
@@ -125,24 +174,56 @@ class Shoes
|
|
125
174
|
# Shoes styles in Shoes Linkables are automatically sync'd with the display side objects.
|
126
175
|
# If a block is passed to shoes_style, that's the validation for the property. It should
|
127
176
|
# convert a given value to a valid value for the property or throw an exception.
|
128
|
-
|
177
|
+
#
|
178
|
+
# If feature is non-nil, it's the feature that an app must request in order to see this
|
179
|
+
# property.
|
180
|
+
#
|
181
|
+
# @param name [String,Symbol] the style name
|
182
|
+
# @param feature [Symbol,NilClass] the feature that must be defined for an app to request this style, or nil
|
183
|
+
# @block if block is given, call it to map the given style value to a valid value, or raise an exception
|
184
|
+
def shoes_style(name, feature: nil, &validator)
|
129
185
|
name = name.to_s
|
130
186
|
|
131
187
|
return if linkable_properties_hash[name]
|
132
188
|
|
133
|
-
linkable_properties << { name: name, validator: }
|
189
|
+
linkable_properties << { name: name, validator:, feature: }
|
134
190
|
linkable_properties_hash[name] = true
|
135
191
|
end
|
136
192
|
|
137
|
-
# Add these names as Shoes styles
|
138
|
-
def shoes_styles(*names)
|
139
|
-
names.each { |n| shoes_style(n) }
|
193
|
+
# Add these names as Shoes styles with the given validator and feature, if any
|
194
|
+
def shoes_styles(*names, feature: nil, &validator)
|
195
|
+
names.each { |n| shoes_style(n, feature:, &validator) }
|
140
196
|
end
|
141
197
|
|
142
|
-
|
143
|
-
|
198
|
+
# Query what feature, if any, is required to use a specific shoes_style.
|
199
|
+
# If no specific feature is needed, nil will be returned.
|
200
|
+
def feature_for_shoes_style(style_name)
|
201
|
+
style_name = style_name.to_s
|
202
|
+
lp = linkable_properties.detect { |prop| prop[:name] == style_name }
|
203
|
+
return lp[:feature] if lp
|
204
|
+
|
205
|
+
# If we get to the top of the superclass tree and we didn't find it, it's not here
|
206
|
+
if self.class == ::Shoes::Drawable
|
207
|
+
raise Shoes::Errors::NoSuchStyleError, "Can't find information for style #{style_name.inspect}!"
|
208
|
+
end
|
209
|
+
|
210
|
+
super
|
211
|
+
end
|
144
212
|
|
145
|
-
|
213
|
+
# Return a list of shoes_style names with the given features. If with_features is nil,
|
214
|
+
# return them with a list of features for the current Shoes::App. For the list of
|
215
|
+
# styles available with no features requested, pass nil to with_features.
|
216
|
+
def shoes_style_names(with_features: nil)
|
217
|
+
# No with_features given? Use the ones requested by this Shoes::App
|
218
|
+
with_features ||= Shoes::App.instance.features
|
219
|
+
parent_prop_names = self != Shoes::Drawable ? self.superclass.shoes_style_names(with_features:) : []
|
220
|
+
|
221
|
+
if with_features == :all
|
222
|
+
subclass_props = linkable_properties
|
223
|
+
else
|
224
|
+
subclass_props = linkable_properties.select { |prop| !prop[:feature] || with_features.include?(prop[:feature]) }
|
225
|
+
end
|
226
|
+
parent_prop_names | subclass_props.map { |prop| prop[:name] }
|
146
227
|
end
|
147
228
|
|
148
229
|
def shoes_style_hashes
|
@@ -157,31 +238,170 @@ class Shoes
|
|
157
238
|
end
|
158
239
|
end
|
159
240
|
|
241
|
+
# Every Shoes drawable has positioning properties
|
242
|
+
shoes_styles :top, :left, :width, :height
|
243
|
+
|
244
|
+
# Margins around drawable
|
245
|
+
shoes_styles :margin, :margin_top, :margin_bottom, :margin_left, :margin_right
|
246
|
+
|
247
|
+
# Padding around drawable
|
248
|
+
shoes_styles :padding, :padding_top, :padding_bottom, :padding_left, :padding_right
|
249
|
+
|
160
250
|
# Shoes uses a "hidden" style property for hide/show
|
161
251
|
shoes_style :hidden
|
162
252
|
|
163
253
|
attr_reader :debug_id
|
164
254
|
|
255
|
+
# These styles can be set to a current per-slot value and inherited from parent slots.
|
256
|
+
# Their value is set at drawable-create time.
|
257
|
+
DRAW_CONTEXT_STYLES = [:fill, :stroke, :strokewidth, :rotate, :transform, :translate]
|
258
|
+
|
259
|
+
include MarginHelper
|
260
|
+
|
165
261
|
def initialize(*args, **kwargs)
|
166
|
-
|
262
|
+
kwargs = margin_parse(kwargs)
|
263
|
+
log_init("Shoes::#{self.class.name}") unless @log
|
167
264
|
|
168
|
-
|
265
|
+
# First, get the list of allowed and disallowed styles for the given features
|
266
|
+
# and make sure no disallowed styles were given.
|
267
|
+
|
268
|
+
app_features = Shoes::App.instance.features
|
269
|
+
this_app_styles = self.class.shoes_style_names.map(&:to_sym)
|
270
|
+
not_this_app_styles = self.class.shoes_style_names(with_features: :all).map(&:to_sym) - this_app_styles
|
271
|
+
|
272
|
+
bad_styles = kwargs.keys & not_this_app_styles
|
273
|
+
unless bad_styles.empty?
|
274
|
+
features_needed = bad_styles.map { |s| self.class.feature_for_shoes_style(s) }.uniq
|
275
|
+
raise Shoes::Errors::UnsupportedFeatureError, "The style(s) #{bad_styles.inspect} are only defined for applications that request specific features: #{features_needed.inspect} (you requested #{app_features.inspect})!"
|
276
|
+
end
|
277
|
+
|
278
|
+
# Next, check positional arguments and make sure the correct number and type
|
279
|
+
# were passed and match positional args with style names.
|
280
|
+
|
281
|
+
supplied_args = kwargs.keys
|
282
|
+
|
283
|
+
req_args = self.class.required_init_args
|
284
|
+
opt_args = self.class.optional_init_args
|
285
|
+
pos_args = req_args + opt_args
|
286
|
+
if req_args != ["any"]
|
287
|
+
if args.size > pos_args.size
|
288
|
+
raise Shoes::Errors::BadArgumentListError, "Too many arguments given for #{self.class}#initialize! #{args.inspect}"
|
289
|
+
end
|
290
|
+
|
291
|
+
if args.size == 0
|
292
|
+
# It's fine to use keyword args instead, but we should make sure they're actually there
|
293
|
+
needed_args = req_args.map(&:to_sym) - kwargs.keys
|
294
|
+
unless needed_args.empty?
|
295
|
+
raise Shoes::Errors::BadArgumentListError, "Keyword arguments for #{self.class}#initialize should also supply #{needed_args.inspect}! #{args.inspect}"
|
296
|
+
end
|
297
|
+
elsif args.size < req_args.size
|
298
|
+
raise Shoes::Errors::BadArgumentListError, "Too few arguments given for #{self.class}#initialize! #{args.inspect}"
|
299
|
+
end
|
300
|
+
|
301
|
+
# Set each positional argument
|
302
|
+
args.each.with_index do |val, idx|
|
303
|
+
style_name = pos_args[idx]
|
304
|
+
next if style_name.nil? || style_name == "" # It's possible to have non-style positional args
|
169
305
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
val = self.class.validate_as(prop, kwargs[prop_sym])
|
174
|
-
instance_variable_set("@" + prop, val)
|
175
|
-
elsif default_styles.key?(prop_sym)
|
176
|
-
val = self.class.validate_as(prop, default_styles[prop_sym])
|
177
|
-
instance_variable_set("@" + prop, val)
|
306
|
+
val = self.class.validate_as(style_name, args[idx])
|
307
|
+
instance_variable_set("@#{style_name}", val)
|
308
|
+
supplied_args << style_name.to_sym
|
178
309
|
end
|
179
310
|
end
|
180
311
|
|
312
|
+
this_drawable_styles = self.class.shoes_style_names.map(&:to_sym)
|
313
|
+
dc = Shoes::App.instance.current_draw_context || {}
|
314
|
+
|
315
|
+
# Styles not passed as arguments can come from the draw context
|
316
|
+
|
317
|
+
# What styles are in the draw context, are used by this drawable, and weren't
|
318
|
+
# given as positional or keyword arguments?
|
319
|
+
draw_context_styles = (DRAW_CONTEXT_STYLES & this_drawable_styles) - supplied_args
|
320
|
+
unless draw_context_styles.empty?
|
321
|
+
# When we first call this, there is no parent. We don't want to set the parent
|
322
|
+
# yet because that will send a notification, and *that* should wait until after
|
323
|
+
# we've told the display service that this drawable was created. So instead
|
324
|
+
# we'll query the parent object's draw context directly.
|
325
|
+
|
326
|
+
draw_context_styles.each do |style|
|
327
|
+
dc_val = dc[style.to_s]
|
328
|
+
next if dc_val.nil?
|
329
|
+
|
330
|
+
val = self.class.validate_as(style, dc[style.to_s])
|
331
|
+
instance_variable_set("@#{style}", val)
|
332
|
+
supplied_args << style
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
# Styles that were *not* passed should be set to defaults
|
337
|
+
|
338
|
+
default_styles = Shoes::Drawable.drawable_default_styles[self.class]
|
339
|
+
|
340
|
+
# No arg specified for a property with a default value? Set it to default.
|
341
|
+
(default_styles.keys - supplied_args).each do |key|
|
342
|
+
val = self.class.validate_as(key, default_styles[key])
|
343
|
+
instance_variable_set("@#{key}", val)
|
344
|
+
end
|
345
|
+
|
346
|
+
# If we have a keyword arg for a style, set it as specified.
|
347
|
+
(this_drawable_styles & kwargs.keys).each do |key|
|
348
|
+
val = self.class.validate_as(key, kwargs[key])
|
349
|
+
instance_variable_set("@#{key}", val)
|
350
|
+
end
|
351
|
+
|
352
|
+
# We'd like to avoid unexpected keywords. But we're not disciplined enough to
|
353
|
+
# raise an error by default yet. Non-style keywords passed to Drawable#initialize
|
354
|
+
# are deprecated at this point, but I need to hunt down the last of them
|
355
|
+
# and prevent them.
|
356
|
+
unexpected = (kwargs.keys - this_drawable_styles)
|
357
|
+
unless unexpected.empty?
|
358
|
+
STDERR.puts "Unexpected non-style keyword(s) in #{self.class} initialize: #{unexpected.inspect}"
|
359
|
+
end
|
360
|
+
|
181
361
|
super(linkable_id: Shoes::Drawable.allocate_drawable_id)
|
182
362
|
Shoes::Drawable.register_drawable_id(self.linkable_id, self)
|
183
363
|
|
184
364
|
generate_debug_id
|
365
|
+
|
366
|
+
parent = ::Shoes::App.instance.current_slot
|
367
|
+
if self.class.expects_parent?
|
368
|
+
set_parent(parent, notify: false)
|
369
|
+
end
|
370
|
+
|
371
|
+
unless self.class.registered_shoes_events?
|
372
|
+
# No Shoes events declared and we're creating an instance?
|
373
|
+
# Default to no class-specific events.
|
374
|
+
self.class.shoes_events
|
375
|
+
end
|
376
|
+
|
377
|
+
# Binding the motion events here isn't perfect.
|
378
|
+
# What about drawables like SubscriptionItem that
|
379
|
+
# have no motion events? With the current Lacci
|
380
|
+
# implementation, the answer is that those events
|
381
|
+
# will never be sent. Calling .hover on one will
|
382
|
+
# be useless, harmless, and allowed. If you want
|
383
|
+
# to make it disallowed, you can do something like
|
384
|
+
# define a SubscriptionItem#hover that raises an
|
385
|
+
# exception instead.
|
386
|
+
|
387
|
+
bind_self_event("hover") do
|
388
|
+
@hover&.call
|
389
|
+
end
|
390
|
+
|
391
|
+
bind_self_event("leave") do
|
392
|
+
@leave&.call
|
393
|
+
end
|
394
|
+
|
395
|
+
bind_self_event("motion") do |x, y|
|
396
|
+
@motion&.call(x, y)
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
def self.expects_parent?
|
401
|
+
return false if [::Shoes::App, ::Shoes::DocumentRoot].include?(self)
|
402
|
+
return false if self < ::Shoes::TextDrawable
|
403
|
+
|
404
|
+
true
|
185
405
|
end
|
186
406
|
|
187
407
|
# Calling stack.app or drawable.app will execute the block
|
@@ -223,13 +443,14 @@ class Shoes
|
|
223
443
|
private
|
224
444
|
|
225
445
|
def validate_event_name(event_name)
|
226
|
-
|
227
|
-
|
446
|
+
events = self.class.get_shoes_events
|
447
|
+
unless events.include?(event_name.to_s)
|
448
|
+
raise Shoes::Errors::UnregisteredShoesEventError, "Drawable #{self.inspect} tried to bind Shoes event #{event_name}, which is not in #{events.inspect}!"
|
228
449
|
end
|
229
450
|
end
|
230
451
|
|
231
452
|
def bind_self_event(event_name, &block)
|
232
|
-
raise(Shoes::Errors::
|
453
|
+
raise(Shoes::Errors::NoSuchLinkableIdError, "Drawable has no linkable_id! #{inspect}") unless linkable_id
|
233
454
|
|
234
455
|
validate_event_name(event_name)
|
235
456
|
|
@@ -292,10 +513,11 @@ class Shoes
|
|
292
513
|
klass_name = self.class.name.delete_prefix("Scarpe::").delete_prefix("Shoes::")
|
293
514
|
|
294
515
|
is_widget = Shoes::Drawable.is_widget_class?(klass_name)
|
516
|
+
parent_id = @parent&.linkable_id
|
295
517
|
|
296
518
|
# Should we send an event so this can be discovered from someplace other than
|
297
519
|
# the DisplayService?
|
298
|
-
::Shoes::DisplayService.display_service.create_display_drawable_for(klass_name, self.linkable_id, shoes_style_values, is_widget:)
|
520
|
+
::Shoes::DisplayService.display_service.create_display_drawable_for(klass_name, self.linkable_id, shoes_style_values, parent_id:, is_widget:)
|
299
521
|
end
|
300
522
|
|
301
523
|
public
|
@@ -303,11 +525,17 @@ class Shoes
|
|
303
525
|
attr_reader :parent
|
304
526
|
attr_reader :destroyed
|
305
527
|
|
306
|
-
|
528
|
+
# Set the Drawable's parent drawable. Notify the display service
|
529
|
+
# that the parent has changed unless instructed not to.
|
530
|
+
# We don't notify when first creating the Drawable. The create
|
531
|
+
# event that is first sent will include the parent.
|
532
|
+
def set_parent(new_parent, notify: true)
|
307
533
|
@parent&.remove_child(self)
|
308
534
|
new_parent&.add_child(self)
|
309
535
|
@parent = new_parent
|
310
|
-
|
536
|
+
return unless notify
|
537
|
+
|
538
|
+
send_shoes_event(new_parent&.linkable_id, event_name: "parent", target: linkable_id)
|
311
539
|
end
|
312
540
|
|
313
541
|
# Removes the element from the Shoes::Drawable tree and removes all event subscriptions
|
@@ -336,6 +564,28 @@ class Shoes
|
|
336
564
|
self.hidden = !self.hidden
|
337
565
|
end
|
338
566
|
|
567
|
+
# Set the hover handler. Not every drawable may do something useful with this.
|
568
|
+
#
|
569
|
+
# @yield A block to be called when the cursor moves to be over the drawable.
|
570
|
+
def hover(&block)
|
571
|
+
@hover = block
|
572
|
+
end
|
573
|
+
|
574
|
+
# Set the leave handler. Not every drawable may do something useful with this.
|
575
|
+
#
|
576
|
+
# @yield A block to be called when the cursor moves to be off of the drawable.
|
577
|
+
def leave(&block)
|
578
|
+
@leave = block
|
579
|
+
end
|
580
|
+
|
581
|
+
# Set the motion handler, called with x and y coordinates as params.
|
582
|
+
# Not every drawable may do something useful with this.
|
583
|
+
#
|
584
|
+
# @yield A block to be called when the cursor moves around over the drawable.
|
585
|
+
def motion(&block)
|
586
|
+
@motion = block
|
587
|
+
end
|
588
|
+
|
339
589
|
# We use method_missing to auto-create Shoes style getters and setters.
|
340
590
|
def method_missing(name, *args, **kwargs, &block)
|
341
591
|
name_s = name.to_s
|
@@ -344,7 +594,7 @@ class Shoes
|
|
344
594
|
prop_name = name_s[0..-2]
|
345
595
|
if self.class.shoes_style_name?(prop_name)
|
346
596
|
self.class.define_method(name) do |new_value|
|
347
|
-
raise(Shoes::Errors::
|
597
|
+
raise(Shoes::Errors::NoSuchLinkableIdError, "Trying to set Shoes styles in a #{self.class} with no linkable ID!") unless linkable_id
|
348
598
|
|
349
599
|
new_value = self.class.validate_as(prop_name, new_value)
|
350
600
|
instance_variable_set("@" + prop_name, new_value)
|
@@ -357,7 +607,7 @@ class Shoes
|
|
357
607
|
|
358
608
|
if self.class.shoes_style_name?(name_s)
|
359
609
|
self.class.define_method(name) do
|
360
|
-
raise(Shoes::Errors::
|
610
|
+
raise(Shoes::Errors::NoSuchLinkableIdError, "Trying to get Shoes styles in an object with no linkable ID! #{inspect}") unless linkable_id
|
361
611
|
|
362
612
|
instance_variable_get("@" + name_s)
|
363
613
|
end
|
@@ -376,5 +626,29 @@ class Shoes
|
|
376
626
|
|
377
627
|
super
|
378
628
|
end
|
629
|
+
|
630
|
+
def self.convert_to_integer(value, attribute_name)
|
631
|
+
begin
|
632
|
+
value = Integer(value)
|
633
|
+
raise Shoes::Errors::InvalidAttributeValueError, "Negative number '#{value}' not allowed for attribute '#{attribute_name}'" if value < 0
|
634
|
+
|
635
|
+
value
|
636
|
+
rescue ArgumentError
|
637
|
+
error_message = "Invalid value '#{value}' provided for attribute '#{attribute_name}'. The value should be a number."
|
638
|
+
raise Shoes::Errors::InvalidAttributeValueError, error_message
|
639
|
+
end
|
640
|
+
end
|
641
|
+
|
642
|
+
def self.convert_to_float(value, attribute_name)
|
643
|
+
begin
|
644
|
+
value = Float(value)
|
645
|
+
raise Shoes::Errors::InvalidAttributeValueError, "Negative number '#{value}' not allowed for attribute '#{attribute_name}'" if value < 0
|
646
|
+
|
647
|
+
value
|
648
|
+
rescue ArgumentError
|
649
|
+
error_message = "Invalid value '#{value}' provided for attribute '#{attribute_name}'. The value should be a number."
|
650
|
+
raise Shoes::Errors::InvalidAttributeValueError, error_message
|
651
|
+
end
|
652
|
+
end
|
379
653
|
end
|
380
654
|
end
|
data/lib/shoes/drawables/arc.rb
CHANGED
@@ -13,37 +13,15 @@ class Shoes
|
|
13
13
|
shoes_style(prop) { |val| convert_to_float(val, prop) }
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
init_args :left, :top, :width, :height, :angle1, :angle2
|
17
|
+
def initialize(*args, **kwargs)
|
17
18
|
@draw_context = Shoes::App.instance.current_draw_context
|
18
19
|
|
19
20
|
super
|
20
|
-
self.left, self.top, self.width, self.height, self.angle1, self.angle2 = args
|
21
21
|
|
22
22
|
create_display_drawable
|
23
23
|
end
|
24
24
|
|
25
|
-
def self.convert_to_integer(value, attribute_name)
|
26
|
-
begin
|
27
|
-
value = Integer(value)
|
28
|
-
raise Shoes::Errors::InvalidAttributeValueError, "Negative number '#{value}' not allowed for attribute '#{attribute_name}'" if value < 0
|
29
25
|
|
30
|
-
value
|
31
|
-
rescue ArgumentError
|
32
|
-
error_message = "Invalid value '#{value}' provided for attribute '#{attribute_name}'. The value should be a number."
|
33
|
-
raise Shoes::Errors::InvalidAttributeValueError, error_message
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.convert_to_float(value, attribute_name)
|
38
|
-
begin
|
39
|
-
value = Float(value)
|
40
|
-
raise Shoes::Errors::InvalidAttributeValueError, "Negative number '#{value}' not allowed for attribute '#{attribute_name}'" if value < 0
|
41
|
-
|
42
|
-
value
|
43
|
-
rescue ArgumentError
|
44
|
-
error_message = "Invalid value '#{value}' provided for attribute '#{attribute_name}'. The value should be a number."
|
45
|
-
raise Shoes::Errors::InvalidAttributeValueError, error_message
|
46
|
-
end
|
47
|
-
end
|
48
26
|
end
|
49
27
|
end
|
@@ -9,33 +9,13 @@ class Shoes
|
|
9
9
|
shoes_style(prop) { |val| val.is_a?(Hash) ? val : convert_to_integer(val, prop) }
|
10
10
|
end
|
11
11
|
|
12
|
-
|
12
|
+
init_args :left, :top, :width
|
13
|
+
def initialize(*args, **kwargs)
|
13
14
|
@draw_context = Shoes::App.instance.current_draw_context
|
14
15
|
|
15
16
|
super
|
16
17
|
|
17
|
-
if args.length == 1 && args[0].is_a?(Hash)
|
18
|
-
options = args[0]
|
19
|
-
self.left = options[:left]
|
20
|
-
self.top = options[:top]
|
21
|
-
self.width = options[:width]
|
22
|
-
else
|
23
|
-
self.left, self.top, self.width = args
|
24
|
-
end
|
25
|
-
|
26
18
|
create_display_drawable
|
27
19
|
end
|
28
|
-
|
29
|
-
def self.convert_to_integer(value, attribute_name)
|
30
|
-
begin
|
31
|
-
value = Integer(value)
|
32
|
-
raise Shoes::Errors::InvalidAttributeValueError, "Negative number '#{value}' not allowed for attribute '#{attribute_name}'" if value < 0
|
33
|
-
|
34
|
-
value
|
35
|
-
rescue ArgumentError
|
36
|
-
error_message = "Invalid value '#{value}' provided for attribute '#{attribute_name}'. The value should be a number."
|
37
|
-
raise Shoes::Errors::InvalidAttributeValueError, error_message
|
38
|
-
end
|
39
|
-
end
|
40
20
|
end
|
41
21
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Shoes
|
4
|
+
class Border < Shoes::Drawable
|
5
|
+
# Shoes style with verification or value mapping:
|
6
|
+
# shoes_style(:left) { |val| convert_to_integer(val, "left") }
|
7
|
+
|
8
|
+
shoes_styles :stroke, :strokewidth # Write your shoes styles here
|
9
|
+
|
10
|
+
shoes_style(:strokewidth) { |val| convert_to_integer(val, "strokewidth") }
|
11
|
+
shoes_style(:curve) { |val| convert_to_integer(val, "curve") }
|
12
|
+
|
13
|
+
Shoes::Drawable.drawable_default_styles[Shoes::Border][:stroke] = :black
|
14
|
+
Shoes::Drawable.drawable_default_styles[Shoes::Border][:strokewidth] = 1
|
15
|
+
Shoes::Drawable.drawable_default_styles[Shoes::Border][:curve] = 0
|
16
|
+
|
17
|
+
opt_init_args :stroke, :strokewidth, :curve
|
18
|
+
def initialize(*args, **kwargs)
|
19
|
+
super
|
20
|
+
@draw_context = Shoes::App.instance.current_draw_context
|
21
|
+
|
22
|
+
create_display_drawable
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
class Shoes
|
4
4
|
class Button < Shoes::Drawable
|
5
|
-
include Shoes::Log
|
6
5
|
shoes_styles :text, :width, :height, :top, :left, :color, :padding_top, :padding_bottom, :text_color, :size, :font_size, :tooltip
|
7
|
-
shoes_events :click
|
6
|
+
shoes_events :click
|
8
7
|
|
8
|
+
init_args :text
|
9
9
|
# Creates a new Button object.
|
10
10
|
#
|
11
11
|
# @param text [String] The text displayed on the button.
|
@@ -32,27 +32,18 @@ class Shoes
|
|
32
32
|
# )
|
33
33
|
# }
|
34
34
|
# end
|
35
|
-
def initialize(
|
36
|
-
font_size: nil, tooltip: nil, &block)
|
37
|
-
|
38
|
-
log_init("Button")
|
39
|
-
|
35
|
+
def initialize(*args, **kwargs, &block)
|
40
36
|
# Properties passed as positional args, not keywords, don't get auto-set
|
41
|
-
@text = text
|
42
37
|
@block = block
|
43
38
|
|
44
39
|
super
|
45
40
|
|
46
|
-
# Bind to a handler named "click"
|
41
|
+
# Bind block to a handler named "click"
|
47
42
|
bind_self_event("click") do
|
48
43
|
@log.debug("Button clicked, calling handler") if @block
|
49
44
|
@block&.call
|
50
45
|
end
|
51
46
|
|
52
|
-
bind_self_event("hover") do
|
53
|
-
@hover&.call
|
54
|
-
end
|
55
|
-
|
56
47
|
create_display_drawable
|
57
48
|
end
|
58
49
|
|
@@ -62,12 +53,5 @@ class Shoes
|
|
62
53
|
def click(&block)
|
63
54
|
@block = block
|
64
55
|
end
|
65
|
-
|
66
|
-
# Set the hover handler
|
67
|
-
#
|
68
|
-
# @yield A block to be called when the cursor moves to be over the button.
|
69
|
-
def hover(&block)
|
70
|
-
@hover = block
|
71
|
-
end
|
72
56
|
end
|
73
57
|
end
|
@@ -5,17 +5,21 @@ class Shoes
|
|
5
5
|
shoes_styles :checked
|
6
6
|
shoes_events :click
|
7
7
|
|
8
|
-
|
8
|
+
init_args
|
9
|
+
opt_init_args :checked
|
10
|
+
def initialize(*args, **kwargs, &block)
|
9
11
|
@block = block
|
10
12
|
super
|
11
13
|
|
12
|
-
bind_self_event("click")
|
14
|
+
bind_self_event("click") do
|
15
|
+
self.checked = !checked?
|
16
|
+
@block.call(self) if @block
|
17
|
+
end
|
13
18
|
create_display_drawable
|
14
19
|
end
|
15
20
|
|
16
21
|
def click(&block)
|
17
22
|
@block = block
|
18
|
-
self.checked = !checked?
|
19
23
|
end
|
20
24
|
|
21
25
|
def checked?
|
@@ -4,11 +4,11 @@ class Shoes
|
|
4
4
|
class DocumentRoot < Shoes::Flow
|
5
5
|
shoes_events # No DocumentRoot-specific events yet
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
@width = @margin = @padding = nil
|
10
|
-
@options = {}
|
7
|
+
Shoes::Drawable.drawable_default_styles[Shoes::DocumentRoot][:height] = "100%"
|
8
|
+
Shoes::Drawable.drawable_default_styles[Shoes::DocumentRoot][:width] = "100%"
|
11
9
|
|
10
|
+
init_args
|
11
|
+
def initialize(**kwargs, &block)
|
12
12
|
super
|
13
13
|
end
|
14
14
|
|