shoes-dsl 4.0.0.pre2
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 +7 -0
- data/CHANGELOG +84 -0
- data/Gemfile +24 -0
- data/Guardfile +11 -0
- data/LICENSE +31 -0
- data/README.md +201 -0
- data/ext/install/Rakefile +29 -0
- data/ext/install/shoes.bat +9 -0
- data/fonts/Coolvetica.ttf +0 -0
- data/fonts/Lacuna.ttf +0 -0
- data/lib/shoes/animation.rb +56 -0
- data/lib/shoes/app.rb +131 -0
- data/lib/shoes/arc.rb +25 -0
- data/lib/shoes/background.rb +24 -0
- data/lib/shoes/border.rb +24 -0
- data/lib/shoes/builtin_methods.rb +77 -0
- data/lib/shoes/button.rb +30 -0
- data/lib/shoes/check_button.rb +44 -0
- data/lib/shoes/color.rb +385 -0
- data/lib/shoes/common/background_element.rb +9 -0
- data/lib/shoes/common/changeable.rb +34 -0
- data/lib/shoes/common/clickable.rb +24 -0
- data/lib/shoes/common/inspect.rb +14 -0
- data/lib/shoes/common/positioning.rb +30 -0
- data/lib/shoes/common/registration.rb +33 -0
- data/lib/shoes/common/remove.rb +10 -0
- data/lib/shoes/common/state.rb +18 -0
- data/lib/shoes/common/style.rb +152 -0
- data/lib/shoes/common/style_normalizer.rb +16 -0
- data/lib/shoes/common/ui_element.rb +11 -0
- data/lib/shoes/common/visibility.rb +40 -0
- data/lib/shoes/configuration.rb +96 -0
- data/lib/shoes/dialog.rb +27 -0
- data/lib/shoes/dimension.rb +239 -0
- data/lib/shoes/dimensions.rb +209 -0
- data/lib/shoes/download.rb +121 -0
- data/lib/shoes/dsl.rb +591 -0
- data/lib/shoes/font.rb +49 -0
- data/lib/shoes/gradient.rb +31 -0
- data/lib/shoes/image.rb +29 -0
- data/lib/shoes/image_pattern.rb +12 -0
- data/lib/shoes/input_box.rb +60 -0
- data/lib/shoes/internal_app.rb +219 -0
- data/lib/shoes/key_event.rb +17 -0
- data/lib/shoes/line.rb +87 -0
- data/lib/shoes/link.rb +59 -0
- data/lib/shoes/link_hover.rb +5 -0
- data/lib/shoes/list_box.rb +50 -0
- data/lib/shoes/logger.rb +66 -0
- data/lib/shoes/logger/ruby.rb +18 -0
- data/lib/shoes/mock.rb +31 -0
- data/lib/shoes/mock/animation.rb +8 -0
- data/lib/shoes/mock/app.rb +47 -0
- data/lib/shoes/mock/arc.rb +9 -0
- data/lib/shoes/mock/background.rb +10 -0
- data/lib/shoes/mock/border.rb +7 -0
- data/lib/shoes/mock/button.rb +10 -0
- data/lib/shoes/mock/check.rb +25 -0
- data/lib/shoes/mock/clickable.rb +8 -0
- data/lib/shoes/mock/common_methods.rb +12 -0
- data/lib/shoes/mock/dialog.rb +13 -0
- data/lib/shoes/mock/download.rb +18 -0
- data/lib/shoes/mock/font.rb +17 -0
- data/lib/shoes/mock/image.rb +13 -0
- data/lib/shoes/mock/image_pattern.rb +9 -0
- data/lib/shoes/mock/input_box.rb +30 -0
- data/lib/shoes/mock/keypress.rb +10 -0
- data/lib/shoes/mock/keyrelease.rb +10 -0
- data/lib/shoes/mock/line.rb +14 -0
- data/lib/shoes/mock/link.rb +12 -0
- data/lib/shoes/mock/list_box.rb +19 -0
- data/lib/shoes/mock/oval.rb +12 -0
- data/lib/shoes/mock/progress.rb +10 -0
- data/lib/shoes/mock/radio.rb +27 -0
- data/lib/shoes/mock/rect.rb +14 -0
- data/lib/shoes/mock/shape.rb +20 -0
- data/lib/shoes/mock/slot.rb +16 -0
- data/lib/shoes/mock/sound.rb +8 -0
- data/lib/shoes/mock/star.rb +14 -0
- data/lib/shoes/mock/text_block.rb +36 -0
- data/lib/shoes/mock/timer.rb +8 -0
- data/lib/shoes/not_implemented_error.rb +4 -0
- data/lib/shoes/oval.rb +20 -0
- data/lib/shoes/point.rb +54 -0
- data/lib/shoes/progress.rb +25 -0
- data/lib/shoes/radio.rb +16 -0
- data/lib/shoes/rect.rb +21 -0
- data/lib/shoes/renamed_delegate.rb +15 -0
- data/lib/shoes/shape.rb +158 -0
- data/lib/shoes/slot.rb +271 -0
- data/lib/shoes/slot_contents.rb +50 -0
- data/lib/shoes/sound.rb +18 -0
- data/lib/shoes/span.rb +16 -0
- data/lib/shoes/star.rb +45 -0
- data/lib/shoes/text.rb +24 -0
- data/lib/shoes/text_block.rb +143 -0
- data/lib/shoes/text_block_dimensions.rb +52 -0
- data/lib/shoes/timer.rb +12 -0
- data/lib/shoes/url.rb +44 -0
- data/lib/shoes/version.rb +3 -0
- data/lib/shoes/widget.rb +69 -0
- data/manifests/common.rb +34 -0
- data/manifests/shoes-dsl.rb +34 -0
- data/shoes-dsl.gemspec +19 -0
- data/spec/code_coverage.rb +14 -0
- data/spec/shoes/animation_spec.rb +65 -0
- data/spec/shoes/app_spec.rb +484 -0
- data/spec/shoes/arc_spec.rb +51 -0
- data/spec/shoes/background_spec.rb +53 -0
- data/spec/shoes/border_spec.rb +47 -0
- data/spec/shoes/builtin_methods_spec.rb +110 -0
- data/spec/shoes/button_spec.rb +44 -0
- data/spec/shoes/check_spec.rb +35 -0
- data/spec/shoes/cli_spec.rb +15 -0
- data/spec/shoes/color_spec.rb +408 -0
- data/spec/shoes/common/inspect_spec.rb +26 -0
- data/spec/shoes/common/remove_spec.rb +38 -0
- data/spec/shoes/common/style_normalizer_spec.rb +28 -0
- data/spec/shoes/common/style_spec.rb +147 -0
- data/spec/shoes/configuration_spec.rb +36 -0
- data/spec/shoes/constants_spec.rb +38 -0
- data/spec/shoes/dialog_spec.rb +163 -0
- data/spec/shoes/dimension_spec.rb +407 -0
- data/spec/shoes/dimensions_spec.rb +837 -0
- data/spec/shoes/download_spec.rb +142 -0
- data/spec/shoes/flow_spec.rb +133 -0
- data/spec/shoes/font_spec.rb +37 -0
- data/spec/shoes/framework_learning_spec.rb +30 -0
- data/spec/shoes/gradient_spec.rb +32 -0
- data/spec/shoes/helpers/fake_element.rb +17 -0
- data/spec/shoes/helpers/inspect_helpers.rb +5 -0
- data/spec/shoes/helpers/sample17_helper.rb +66 -0
- data/spec/shoes/image_spec.rb +49 -0
- data/spec/shoes/images/shoe.jpg +0 -0
- data/spec/shoes/input_box_spec.rb +80 -0
- data/spec/shoes/integration_spec.rb +20 -0
- data/spec/shoes/internal_app_spec.rb +141 -0
- data/spec/shoes/keypress_spec.rb +11 -0
- data/spec/shoes/keyrelease_spec.rb +12 -0
- data/spec/shoes/line_spec.rb +49 -0
- data/spec/shoes/link_spec.rb +105 -0
- data/spec/shoes/list_box_spec.rb +74 -0
- data/spec/shoes/logger/ruby_spec.rb +8 -0
- data/spec/shoes/logger_spec.rb +45 -0
- data/spec/shoes/oval_spec.rb +24 -0
- data/spec/shoes/point_spec.rb +71 -0
- data/spec/shoes/progress_spec.rb +54 -0
- data/spec/shoes/radio_spec.rb +32 -0
- data/spec/shoes/rect_spec.rb +39 -0
- data/spec/shoes/renamed_delegate_spec.rb +70 -0
- data/spec/shoes/shape_spec.rb +95 -0
- data/spec/shoes/shared_examples/button.rb +6 -0
- data/spec/shoes/shared_examples/changeable.rb +26 -0
- data/spec/shoes/shared_examples/clickable.rb +5 -0
- data/spec/shoes/shared_examples/common_methods.rb +35 -0
- data/spec/shoes/shared_examples/dimensions.rb +32 -0
- data/spec/shoes/shared_examples/dsl.rb +44 -0
- data/spec/shoes/shared_examples/dsl/animate.rb +29 -0
- data/spec/shoes/shared_examples/dsl/arc.rb +45 -0
- data/spec/shoes/shared_examples/dsl/background.rb +26 -0
- data/spec/shoes/shared_examples/dsl/border.rb +10 -0
- data/spec/shoes/shared_examples/dsl/button.rb +5 -0
- data/spec/shoes/shared_examples/dsl/cap.rb +6 -0
- data/spec/shoes/shared_examples/dsl/check.rb +11 -0
- data/spec/shoes/shared_examples/dsl/edit_box.rb +8 -0
- data/spec/shoes/shared_examples/dsl/edit_line.rb +8 -0
- data/spec/shoes/shared_examples/dsl/editable_element.rb +29 -0
- data/spec/shoes/shared_examples/dsl/fill.rb +27 -0
- data/spec/shoes/shared_examples/dsl/flow.rb +15 -0
- data/spec/shoes/shared_examples/dsl/gradient.rb +62 -0
- data/spec/shoes/shared_examples/dsl/image.rb +21 -0
- data/spec/shoes/shared_examples/dsl/line.rb +9 -0
- data/spec/shoes/shared_examples/dsl/nofill.rb +6 -0
- data/spec/shoes/shared_examples/dsl/nostroke.rb +6 -0
- data/spec/shoes/shared_examples/dsl/oval.rb +88 -0
- data/spec/shoes/shared_examples/dsl/pattern.rb +34 -0
- data/spec/shoes/shared_examples/dsl/progress.rb +7 -0
- data/spec/shoes/shared_examples/dsl/rect.rb +92 -0
- data/spec/shoes/shared_examples/dsl/rgb.rb +26 -0
- data/spec/shoes/shared_examples/dsl/shape.rb +21 -0
- data/spec/shoes/shared_examples/dsl/star.rb +48 -0
- data/spec/shoes/shared_examples/dsl/stroke.rb +30 -0
- data/spec/shoes/shared_examples/dsl/strokewidth.rb +19 -0
- data/spec/shoes/shared_examples/dsl/style.rb +32 -0
- data/spec/shoes/shared_examples/dsl/text_elements.rb +81 -0
- data/spec/shoes/shared_examples/dsl/video.rb +5 -0
- data/spec/shoes/shared_examples/dsl_app_context.rb +8 -0
- data/spec/shoes/shared_examples/hover_leave.rb +11 -0
- data/spec/shoes/shared_examples/parent.rb +6 -0
- data/spec/shoes/shared_examples/scroll.rb +41 -0
- data/spec/shoes/shared_examples/shared_element_method.rb +60 -0
- data/spec/shoes/shared_examples/slot.rb +331 -0
- data/spec/shoes/shared_examples/state.rb +19 -0
- data/spec/shoes/shared_examples/style.rb +82 -0
- data/spec/shoes/slot_spec.rb +130 -0
- data/spec/shoes/sound_spec.rb +15 -0
- data/spec/shoes/span_spec.rb +112 -0
- data/spec/shoes/spec_helper.rb +24 -0
- data/spec/shoes/stack_spec.rb +79 -0
- data/spec/shoes/star_spec.rb +31 -0
- data/spec/shoes/text_block_dimensions_spec.rb +75 -0
- data/spec/shoes/text_block_spec.rb +270 -0
- data/spec/shoes/url_spec.rb +68 -0
- data/spec/shoes/widget_spec.rb +70 -0
- data/spec/shoes_spec.rb +44 -0
- data/spec/spec_helper.rb +18 -0
- data/static/Shoes.icns +0 -0
- data/static/shoes-icon.png +0 -0
- metadata +354 -0
data/lib/shoes/dialog.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
class Shoes
|
2
|
+
class Dialog
|
3
|
+
def initialize
|
4
|
+
@gui = Shoes.backend::Dialog.new
|
5
|
+
end
|
6
|
+
|
7
|
+
def alert(msg = '')
|
8
|
+
@gui.alert msg
|
9
|
+
end
|
10
|
+
|
11
|
+
def confirm(msg = '')
|
12
|
+
@gui.confirm msg
|
13
|
+
end
|
14
|
+
|
15
|
+
def dialog_chooser title, folder=false
|
16
|
+
@gui.dialog_chooser title, folder
|
17
|
+
end
|
18
|
+
|
19
|
+
def ask msg, args
|
20
|
+
@gui.ask msg, args
|
21
|
+
end
|
22
|
+
|
23
|
+
def ask_color title
|
24
|
+
@gui.ask_color title
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,239 @@
|
|
1
|
+
class Shoes
|
2
|
+
class Dimension
|
3
|
+
attr_reader :parent
|
4
|
+
attr_accessor :absolute_start
|
5
|
+
protected :parent # we shall not mess with parent,see #495
|
6
|
+
|
7
|
+
# in case you wonder about the -1... it is used to adjust the right and
|
8
|
+
# bottom values. Because right is not left + width but rather left + width -1
|
9
|
+
# Let me give you an example:
|
10
|
+
# Say left is 20 and we have a width of 100 then the right must be 119,
|
11
|
+
# because you have to take pixel number 20 into account so 20..119 is 100
|
12
|
+
# while 20..120 is 101. E.g.:
|
13
|
+
# (20..119).size => 100
|
14
|
+
PIXEL_COUNTING_ADJUSTMENT = -1
|
15
|
+
|
16
|
+
def initialize(parent = nil, start_as_center = false)
|
17
|
+
@parent = parent
|
18
|
+
@start_as_center = start_as_center
|
19
|
+
end
|
20
|
+
|
21
|
+
def start
|
22
|
+
value = basic_start_value
|
23
|
+
value = adjust_start_for_center(value) if start_as_center?
|
24
|
+
value
|
25
|
+
end
|
26
|
+
|
27
|
+
def end
|
28
|
+
@end || report_relative_to_parent_end
|
29
|
+
end
|
30
|
+
|
31
|
+
def extent
|
32
|
+
result = @extent
|
33
|
+
if @parent
|
34
|
+
result = calculate_relative(result) if is_relative?(result)
|
35
|
+
result = calculate_negative(result) if is_negative?(result)
|
36
|
+
end
|
37
|
+
result
|
38
|
+
end
|
39
|
+
|
40
|
+
def extent=(value)
|
41
|
+
@extent = value
|
42
|
+
@extent = parse_from_string @extent if is_string? @extent
|
43
|
+
@extent
|
44
|
+
end
|
45
|
+
|
46
|
+
def absolute_end
|
47
|
+
return absolute_start if extent.nil? || absolute_start.nil?
|
48
|
+
absolute_start + extent + PIXEL_COUNTING_ADJUSTMENT
|
49
|
+
end
|
50
|
+
|
51
|
+
def element_extent
|
52
|
+
my_extent = extent
|
53
|
+
if my_extent.nil?
|
54
|
+
nil
|
55
|
+
else
|
56
|
+
extent - (margin_start + margin_end)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def element_extent=(value)
|
61
|
+
self.extent = if value.nil?
|
62
|
+
nil
|
63
|
+
else
|
64
|
+
margin_start + value + margin_end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def element_start
|
69
|
+
return nil if absolute_start.nil?
|
70
|
+
absolute_start + margin_start + displace_start
|
71
|
+
end
|
72
|
+
|
73
|
+
def element_end
|
74
|
+
return nil if element_start.nil? || element_extent.nil?
|
75
|
+
element_start + element_extent + PIXEL_COUNTING_ADJUSTMENT
|
76
|
+
end
|
77
|
+
|
78
|
+
def absolute_start_position?
|
79
|
+
not @start.nil?
|
80
|
+
end
|
81
|
+
|
82
|
+
def absolute_end_position?
|
83
|
+
not @end.nil?
|
84
|
+
end
|
85
|
+
|
86
|
+
def absolute_position?
|
87
|
+
absolute_start_position? || absolute_end_position?
|
88
|
+
end
|
89
|
+
|
90
|
+
def positioned?
|
91
|
+
absolute_start
|
92
|
+
end
|
93
|
+
|
94
|
+
def in_bounds?(value)
|
95
|
+
(absolute_start <= value) && (value <= absolute_end)
|
96
|
+
end
|
97
|
+
|
98
|
+
# For... reasons it is important to have the value of the instance variable
|
99
|
+
# set to nil if it's not modified and then return a default value on the
|
100
|
+
# getter... reason being that for ParentDimensions we need to be able to
|
101
|
+
# figure out if a value has been modified or if we should consult the
|
102
|
+
# parent value - see ParentDimension implementation
|
103
|
+
[:margin_start, :margin_end, :displace_start].each do |method|
|
104
|
+
define_method method do
|
105
|
+
instance_variable_name = '@' + method.to_s
|
106
|
+
value = instance_variable_get(instance_variable_name) || 0
|
107
|
+
value = calculate_relative value if is_relative? value
|
108
|
+
value
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.define_int_parsing_writer(name)
|
113
|
+
define_method "#{name}=" do |value|
|
114
|
+
instance_variable_set("@#{name}", parse_int_value(value))
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
%w(start end margin_start margin_end displace_start).each do |method|
|
119
|
+
define_int_parsing_writer method
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
def basic_start_value
|
124
|
+
value = @start
|
125
|
+
value = calculate_relative value if is_relative?(value)
|
126
|
+
value = report_relative_to_parent_start if value.nil?
|
127
|
+
value
|
128
|
+
end
|
129
|
+
|
130
|
+
def is_relative?(result)
|
131
|
+
# as the value is relative to the parent values bigger than one don't
|
132
|
+
# make much sense and are problematic. E.g. through calculations users
|
133
|
+
# might end up with values like 5.14 meaning 5 pixel which would get
|
134
|
+
# interpreted as 514% of the parent
|
135
|
+
# Also check for existance of parent because otherwise relative
|
136
|
+
# calculation makes no sense
|
137
|
+
result.is_a?(Float) && result <= 1 && @parent
|
138
|
+
end
|
139
|
+
|
140
|
+
def calculate_relative(result)
|
141
|
+
(result * @parent.element_extent).to_i
|
142
|
+
end
|
143
|
+
|
144
|
+
def is_string?(result)
|
145
|
+
result.is_a?(String)
|
146
|
+
end
|
147
|
+
|
148
|
+
def is_negative?(result)
|
149
|
+
result && result < 0
|
150
|
+
end
|
151
|
+
|
152
|
+
def calculate_negative(result)
|
153
|
+
@parent.element_extent + result
|
154
|
+
end
|
155
|
+
|
156
|
+
PERCENT_REGEX = /(-?\d+(\.\d+)*)%/
|
157
|
+
|
158
|
+
def parse_from_string(result)
|
159
|
+
match = result.gsub(/\s+/, "").match(PERCENT_REGEX)
|
160
|
+
if match
|
161
|
+
match[1].to_f / 100.0
|
162
|
+
elsif valid_integer_string?(result)
|
163
|
+
int_from_string(result)
|
164
|
+
else
|
165
|
+
nil
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def parse_int_value(input)
|
170
|
+
if input.is_a?(Integer) || input.is_a?(Float)
|
171
|
+
input
|
172
|
+
elsif valid_integer_string?(input)
|
173
|
+
int_from_string(input)
|
174
|
+
else
|
175
|
+
nil
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def int_from_string(result)
|
180
|
+
(result.gsub(' ', '')).to_i
|
181
|
+
end
|
182
|
+
|
183
|
+
NUMBER_REGEX = /^-?\s*\d+/
|
184
|
+
|
185
|
+
def valid_integer_string?(input)
|
186
|
+
input.is_a?(String) && input.match(NUMBER_REGEX)
|
187
|
+
end
|
188
|
+
|
189
|
+
def report_relative_to_parent_start
|
190
|
+
if element_start && parent && parent.element_start
|
191
|
+
element_start - parent.element_start
|
192
|
+
else
|
193
|
+
nil
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def report_relative_to_parent_end
|
198
|
+
if element_end && parent && parent.element_end
|
199
|
+
parent.element_end - element_end
|
200
|
+
else
|
201
|
+
nil
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def start_as_center?
|
206
|
+
@start_as_center
|
207
|
+
end
|
208
|
+
|
209
|
+
def adjust_start_for_center(value)
|
210
|
+
my_extent = extent
|
211
|
+
if my_extent && my_extent > 0
|
212
|
+
value - my_extent / 2
|
213
|
+
else
|
214
|
+
nil
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
class ParentDimension < Dimension
|
220
|
+
SIMPLE_DELEGATE_METHODS = [:extent, :absolute_start, :margin_start,
|
221
|
+
:margin_end, :start]
|
222
|
+
|
223
|
+
SIMPLE_DELEGATE_METHODS.each do |method|
|
224
|
+
define_method method do
|
225
|
+
if value_modified? method
|
226
|
+
super
|
227
|
+
else
|
228
|
+
parent.public_send(method)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
private
|
234
|
+
def value_modified?(method)
|
235
|
+
instance_variable = ('@' + method.to_s).to_sym
|
236
|
+
instance_variable_get(instance_variable)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
# Dimensions is a central class that most Shoes classes use to represent their
|
2
|
+
# dimensions, e.g. where they are and how much space they are taking up there.
|
3
|
+
# All the different position types might be confusing. So here is a little list:
|
4
|
+
#
|
5
|
+
# Position (left, top, right, bottom)
|
6
|
+
# plain (left, top, right, bottom)
|
7
|
+
# An offset relative to the parent (parents mostly are slots e.g.
|
8
|
+
# flows/stacks), e.g it isn't fully positioned/doesn't flow anymore when set
|
9
|
+
#
|
10
|
+
# absolute (absolute_left, absolute_top, absolute_right, absolute_bottom)
|
11
|
+
# The absolute position of an element in the app, set by positioning code (in
|
12
|
+
# slot.rb). Might not be the beginning of the element as it also takes margins
|
13
|
+
# into account, so it could be the beginning of the margin. Is also used in
|
14
|
+
# the positioning code.
|
15
|
+
#
|
16
|
+
# element_* (element_left, element_top, element_right, element_bottom)
|
17
|
+
# Derived from absolute_* but shows the real position of the object, e.g. it
|
18
|
+
# adds the margins to absolute_* (mostly used by backend drawing code).
|
19
|
+
#
|
20
|
+
# Space taken up (width/height)
|
21
|
+
# plain (width, height)
|
22
|
+
# The whole space taken up by this element with margins and everything. Used
|
23
|
+
# for positioning/by the user.
|
24
|
+
#
|
25
|
+
# element_* (element_width, element_height)
|
26
|
+
# Just the space taken up by the element itself without margins.
|
27
|
+
# Used by drawing.
|
28
|
+
#
|
29
|
+
# Note that this is NOT how margins work in the CSS box model. We diverge for
|
30
|
+
# reasons mentioned in this comment/thread:
|
31
|
+
# https://github.com/shoes/shoes4/pull/467#issuecomment-27655355
|
32
|
+
|
33
|
+
class Shoes
|
34
|
+
class Dimensions
|
35
|
+
extend RenamedDelegate
|
36
|
+
include Common::Inspect
|
37
|
+
|
38
|
+
attr_writer :width, :height, :margin_left, :margin_right, :margin_top,
|
39
|
+
:margin_bottom, :top, :left, :right, :bottom
|
40
|
+
attr_reader :parent, :x_dimension, :y_dimension
|
41
|
+
attr_accessor :absolute_left, :absolute_top,
|
42
|
+
:displace_left, :displace_top
|
43
|
+
protected :parent # we shall not mess with parent,see #495
|
44
|
+
|
45
|
+
|
46
|
+
# in case you wonder about the -1... it is used to adjust the right and
|
47
|
+
# bottom values. Because right is not left + width but rather left + width -1
|
48
|
+
# Let me give you an example:
|
49
|
+
# Say left is 20 and we have a width of 100 then the right must be 119,
|
50
|
+
# because you have to take pixel number 20 into account so 20..119 is 100
|
51
|
+
# while 20..120 is 101. E.g.:
|
52
|
+
# (20..119).size => 100
|
53
|
+
PIXEL_COUNTING_ADJUSTMENT = -1
|
54
|
+
|
55
|
+
def initialize(parent, left_or_hash = nil, top = nil, width = nil,
|
56
|
+
height = nil, opts = {})
|
57
|
+
@parent = parent
|
58
|
+
if hash_as_argument?(left_or_hash)
|
59
|
+
init_with_hash(left_or_hash)
|
60
|
+
else
|
61
|
+
init_with_arguments(left_or_hash, top, width, height, opts)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def absolute_x_position?
|
66
|
+
x_dimension.absolute_position?
|
67
|
+
end
|
68
|
+
|
69
|
+
def absolute_y_position?
|
70
|
+
y_dimension.absolute_position?
|
71
|
+
end
|
72
|
+
|
73
|
+
def absolutely_positioned?
|
74
|
+
absolute_x_position? || absolute_y_position?
|
75
|
+
end
|
76
|
+
|
77
|
+
def positioned?
|
78
|
+
x_dimension.positioned? && y_dimension.positioned?
|
79
|
+
end
|
80
|
+
|
81
|
+
def in_bounds?(x, y)
|
82
|
+
x_dimension.in_bounds?(x) && y_dimension.in_bounds?(y)
|
83
|
+
end
|
84
|
+
|
85
|
+
def margin
|
86
|
+
[margin_left, margin_top, margin_right, margin_bottom]
|
87
|
+
end
|
88
|
+
|
89
|
+
def margin=(margin)
|
90
|
+
margin = [margin, margin, margin, margin] unless margin.is_a? Array
|
91
|
+
self.margin_left, self.margin_top,
|
92
|
+
self.margin_right, self.margin_bottom = margin
|
93
|
+
end
|
94
|
+
|
95
|
+
# used by positioning code in slot and there to be overwritten if something
|
96
|
+
# does not need to be positioned like a background or so
|
97
|
+
def needs_to_be_positioned?
|
98
|
+
true
|
99
|
+
end
|
100
|
+
|
101
|
+
def takes_up_space?
|
102
|
+
true
|
103
|
+
end
|
104
|
+
|
105
|
+
def inspect
|
106
|
+
nothing = '_'
|
107
|
+
super.insert(-2,
|
108
|
+
" relative:#{Point.new left, top}->#{Point.new right, bottom}" <<
|
109
|
+
" absolute:#{Point.new absolute_left, absolute_top}->#{Point.new absolute_right, absolute_bottom}" <<
|
110
|
+
" #{width || nothing}x#{height || nothing}")
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.setup_delegations
|
114
|
+
methods_to_rename = Dimension.public_instance_methods false
|
115
|
+
renamed_delegate_to :x_dimension, methods_to_rename, 'start' => 'left',
|
116
|
+
'end' => 'right',
|
117
|
+
'extent' => 'width'
|
118
|
+
renamed_delegate_to :y_dimension, methods_to_rename, 'start' => 'top',
|
119
|
+
'end' => 'bottom',
|
120
|
+
'extent' => 'height'
|
121
|
+
end
|
122
|
+
|
123
|
+
setup_delegations
|
124
|
+
|
125
|
+
private
|
126
|
+
def hash_as_argument?(left)
|
127
|
+
left.respond_to? :fetch
|
128
|
+
end
|
129
|
+
|
130
|
+
def init_with_hash(hash)
|
131
|
+
init_with_arguments hash.fetch(:left, nil), hash.fetch(:top, nil),
|
132
|
+
hash.fetch(:width, nil), hash.fetch(:height, nil),
|
133
|
+
hash
|
134
|
+
end
|
135
|
+
|
136
|
+
def init_with_arguments(left, top, width, height, opts)
|
137
|
+
@left_top_as_center = opts.fetch(:center, false)
|
138
|
+
init_x_and_y_dimensions
|
139
|
+
general_options opts # order important for redrawing
|
140
|
+
self.displace_left = opts.fetch(:displace_left, nil)
|
141
|
+
self.displace_top = opts.fetch(:displace_top, nil)
|
142
|
+
self.left = left
|
143
|
+
self.top = top
|
144
|
+
self.width = width
|
145
|
+
self.height = height
|
146
|
+
end
|
147
|
+
|
148
|
+
def init_x_and_y_dimensions
|
149
|
+
parent_x_dimension = @parent? @parent.x_dimension : nil
|
150
|
+
parent_y_dimension = @parent? @parent.y_dimension : nil
|
151
|
+
@x_dimension = Dimension.new parent_x_dimension, @left_top_as_center
|
152
|
+
@y_dimension = Dimension.new parent_y_dimension, @left_top_as_center
|
153
|
+
end
|
154
|
+
|
155
|
+
def general_options(opts)
|
156
|
+
self.right = opts[:right]
|
157
|
+
self.bottom = opts[:bottom]
|
158
|
+
init_margins opts
|
159
|
+
end
|
160
|
+
|
161
|
+
def init_margins(opts)
|
162
|
+
new_opts = opts.reject { |k, v| v.nil? }
|
163
|
+
self.margin = new_opts[:margin]
|
164
|
+
self.margin_left = new_opts.fetch(:margin_left, margin_left)
|
165
|
+
self.margin_top = new_opts.fetch(:margin_top, margin_top)
|
166
|
+
self.margin_right = new_opts.fetch(:margin_right, margin_right)
|
167
|
+
self.margin_bottom = new_opts.fetch(:margin_bottom, margin_bottom)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# for objects that do not depend on their parent (get 1.04 as real values)
|
172
|
+
class AbsoluteDimensions < Dimensions
|
173
|
+
def initialize(*args)
|
174
|
+
super(nil, *args)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# for objects that are more defined by their parents, delegates method calls
|
179
|
+
# to crucial methods to the parent if the instance variable isn't set
|
180
|
+
class ParentDimensions < Dimensions
|
181
|
+
def init_x_and_y_dimensions
|
182
|
+
@x_dimension = ParentDimension.new @parent.x_dimension,
|
183
|
+
@left_top_as_center
|
184
|
+
@y_dimension = ParentDimension.new @parent.y_dimension,
|
185
|
+
@left_top_as_center
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# depends on a #dimensions method being present that returns a Dimensions object
|
190
|
+
module DimensionsDelegations
|
191
|
+
extend Forwardable
|
192
|
+
|
193
|
+
UNDELEGATED_METHODS = [:to_s]
|
194
|
+
DELEGATED_METHODS = Dimensions.public_instance_methods(false) - UNDELEGATED_METHODS
|
195
|
+
|
196
|
+
def_delegators :dimensions, *DELEGATED_METHODS
|
197
|
+
|
198
|
+
def adjust_current_position(*_)
|
199
|
+
# no-op by default for almost all elements
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# depends on a #dsl method to forward to (e.g. for backend objects)
|
204
|
+
module BackendDimensionsDelegations
|
205
|
+
extend Forwardable
|
206
|
+
|
207
|
+
def_delegators :dsl, *DimensionsDelegations::DELEGATED_METHODS
|
208
|
+
end
|
209
|
+
end
|