shoes-core 4.0.0.pre3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +31 -0
- data/README.md +8 -0
- data/Rakefile +1 -0
- data/bin/shoes +62 -0
- data/bin/shoes-guard +8 -0
- data/bin/shoes-picker +6 -0
- data/bin/shoes-stub +62 -0
- data/ext/install/Rakefile +29 -0
- data/ext/install/shoes.bat +15 -0
- data/fonts/Coolvetica.ttf +0 -0
- data/fonts/Lacuna.ttf +0 -0
- data/lib/rubygems_plugin.rb +24 -0
- data/lib/shoes.rb +1 -0
- data/lib/shoes/animation.rb +56 -0
- data/lib/shoes/app.rb +130 -0
- data/lib/shoes/arc.rb +25 -0
- data/lib/shoes/background.rb +20 -0
- data/lib/shoes/border.rb +20 -0
- data/lib/shoes/builtin_methods.rb +76 -0
- data/lib/shoes/button.rb +29 -0
- data/lib/shoes/check_button.rb +41 -0
- data/lib/shoes/color.rb +387 -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 +31 -0
- data/lib/shoes/common/remove.rb +10 -0
- data/lib/shoes/common/state.rb +16 -0
- data/lib/shoes/common/style.rb +160 -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 +41 -0
- data/lib/shoes/configuration.rb +96 -0
- data/lib/shoes/core.rb +1 -0
- data/lib/shoes/core/version.rb +5 -0
- data/lib/shoes/dialog.rb +56 -0
- data/lib/shoes/dimension.rb +269 -0
- data/lib/shoes/dimensions.rb +203 -0
- data/lib/shoes/download.rb +130 -0
- data/lib/shoes/dsl.rb +656 -0
- data/lib/shoes/file_not_found_error.rb +4 -0
- data/lib/shoes/font.rb +50 -0
- data/lib/shoes/gradient.rb +31 -0
- data/lib/shoes/image.rb +53 -0
- data/lib/shoes/image_pattern.rb +12 -0
- data/lib/shoes/input_box.rb +59 -0
- data/lib/shoes/internal_app.rb +230 -0
- data/lib/shoes/key_event.rb +17 -0
- data/lib/shoes/line.rb +84 -0
- data/lib/shoes/link.rb +57 -0
- data/lib/shoes/link_hover.rb +5 -0
- data/lib/shoes/list_box.rb +50 -0
- data/lib/shoes/logger.rb +65 -0
- data/lib/shoes/logger/ruby.rb +16 -0
- data/lib/shoes/mock.rb +33 -0
- data/lib/shoes/mock/animation.rb +8 -0
- data/lib/shoes/mock/app.rb +49 -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 +22 -0
- data/lib/shoes/mock/check.rb +24 -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 +16 -0
- data/lib/shoes/mock/font.rb +15 -0
- data/lib/shoes/mock/image.rb +13 -0
- data/lib/shoes/mock/image_pattern.rb +8 -0
- data/lib/shoes/mock/input_box.rb +30 -0
- data/lib/shoes/mock/keypress.rb +11 -0
- data/lib/shoes/mock/keyrelease.rb +11 -0
- data/lib/shoes/mock/line.rb +14 -0
- data/lib/shoes/mock/link.rb +11 -0
- data/lib/shoes/mock/list_box.rb +19 -0
- data/lib/shoes/mock/oval.rb +11 -0
- data/lib/shoes/mock/packager.rb +13 -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/packager.rb +26 -0
- data/lib/shoes/point.rb +54 -0
- data/lib/shoes/progress.rb +25 -0
- data/lib/shoes/radio.rb +15 -0
- data/lib/shoes/rect.rb +21 -0
- data/lib/shoes/renamed_delegate.rb +15 -0
- data/lib/shoes/shape.rb +159 -0
- data/lib/shoes/slot.rb +276 -0
- data/lib/shoes/slot_contents.rb +51 -0
- data/lib/shoes/sound.rb +18 -0
- data/lib/shoes/span.rb +16 -0
- data/lib/shoes/star.rb +50 -0
- data/lib/shoes/text.rb +24 -0
- data/lib/shoes/text_block.rb +142 -0
- data/lib/shoes/text_block_dimensions.rb +51 -0
- data/lib/shoes/timer.rb +14 -0
- data/lib/shoes/ui/cli.rb +67 -0
- data/lib/shoes/ui/picker.rb +47 -0
- data/lib/shoes/url.rb +44 -0
- data/lib/shoes/version.rb +3 -0
- data/lib/shoes/widget.rb +67 -0
- data/shoes-core.gemspec +22 -0
- data/spec/shoes/animation_spec.rb +71 -0
- data/spec/shoes/app_spec.rb +484 -0
- data/spec/shoes/arc_spec.rb +51 -0
- data/spec/shoes/background_spec.rb +47 -0
- data/spec/shoes/border_spec.rb +46 -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/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 +171 -0
- data/spec/shoes/dimension_spec.rb +433 -0
- data/spec/shoes/dimensions_spec.rb +837 -0
- data/spec/shoes/download_spec.rb +146 -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 +68 -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 +87 -0
- data/spec/shoes/link_spec.rb +118 -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/packager_spec.rb +25 -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 +106 -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 +57 -0
- data/spec/shoes/shared_examples/dsl/star.rb +111 -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 +394 -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 +186 -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 +48 -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 +19 -0
- data/static/downloading.png +0 -0
- data/static/shoes-icon-blue.png +0 -0
- data/static/shoes-icon-brown.png +0 -0
- data/static/shoes-icon.png +0 -0
- metadata +366 -0
data/lib/shoes/core.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'shoes/dsl'
|
data/lib/shoes/dialog.rb
ADDED
@@ -0,0 +1,56 @@
|
|
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
|
+
ask_me = Shoes.app(title: args[:title] || "Shoes asks:",
|
21
|
+
width: 300, height: 125,
|
22
|
+
modal: true) do
|
23
|
+
stack do
|
24
|
+
para msg, margin: 10
|
25
|
+
|
26
|
+
@e = edit_line margin_left: 10,
|
27
|
+
width: width - 20,
|
28
|
+
secret: args[:secret]
|
29
|
+
|
30
|
+
flow margin_top: 10 do
|
31
|
+
button "OK", margin_left: 150 do
|
32
|
+
@result = @e.text
|
33
|
+
quit
|
34
|
+
end
|
35
|
+
|
36
|
+
button "Cancel" do
|
37
|
+
@result = nil
|
38
|
+
quit
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def result
|
44
|
+
@result
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
ask_me.wait_until_closed
|
49
|
+
ask_me.result
|
50
|
+
end
|
51
|
+
|
52
|
+
def ask_color(title)
|
53
|
+
@gui.ask_color title
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,269 @@
|
|
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
|
+
!@start.nil?
|
80
|
+
end
|
81
|
+
|
82
|
+
def absolute_end_position?
|
83
|
+
!@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
|
+
|
124
|
+
def basic_start_value
|
125
|
+
value = @start
|
126
|
+
value = calculate_relative value if is_relative?(value)
|
127
|
+
value = report_relative_to_parent_start if value.nil?
|
128
|
+
value
|
129
|
+
end
|
130
|
+
|
131
|
+
def is_relative?(result)
|
132
|
+
# as the value is relative to the parent values bigger than one don't
|
133
|
+
# make much sense and are problematic. E.g. through calculations users
|
134
|
+
# might end up with values like 5.14 meaning 5 pixel which would get
|
135
|
+
# interpreted as 514% of the parent
|
136
|
+
# Also check for existance of parent because otherwise relative
|
137
|
+
# calculation makes no sense
|
138
|
+
result.is_a?(Float) && result <= 1 && @parent
|
139
|
+
end
|
140
|
+
|
141
|
+
def calculate_relative(result)
|
142
|
+
(result * @parent.element_extent).to_i
|
143
|
+
end
|
144
|
+
|
145
|
+
def is_string?(result)
|
146
|
+
result.is_a?(String)
|
147
|
+
end
|
148
|
+
|
149
|
+
def is_negative?(result)
|
150
|
+
result && result < 0
|
151
|
+
end
|
152
|
+
|
153
|
+
def calculate_negative(result)
|
154
|
+
@parent.element_extent + result
|
155
|
+
end
|
156
|
+
|
157
|
+
PERCENT_REGEX = /(-?\d+(\.\d+)*)%/
|
158
|
+
|
159
|
+
def parse_from_string(result)
|
160
|
+
match = result.gsub(/\s+/, "").match(PERCENT_REGEX)
|
161
|
+
if match
|
162
|
+
match[1].to_f / 100.0
|
163
|
+
elsif valid_integer_string?(result)
|
164
|
+
int_from_string(result)
|
165
|
+
else
|
166
|
+
nil
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def parse_int_value(input)
|
171
|
+
if input.is_a?(Integer) || input.is_a?(Float)
|
172
|
+
input
|
173
|
+
elsif valid_integer_string?(input)
|
174
|
+
int_from_string(input)
|
175
|
+
else
|
176
|
+
nil
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def int_from_string(result)
|
181
|
+
(result.gsub(' ', '')).to_i
|
182
|
+
end
|
183
|
+
|
184
|
+
NUMBER_REGEX = /^-?\s*\d+/
|
185
|
+
|
186
|
+
def valid_integer_string?(input)
|
187
|
+
input.is_a?(String) && input.match(NUMBER_REGEX)
|
188
|
+
end
|
189
|
+
|
190
|
+
def report_relative_to_parent_start
|
191
|
+
if element_start && parent && parent.element_start
|
192
|
+
element_start - parent.element_start
|
193
|
+
else
|
194
|
+
nil
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def report_relative_to_parent_end
|
199
|
+
if element_end && parent && parent.element_end
|
200
|
+
parent.element_end - element_end
|
201
|
+
else
|
202
|
+
nil
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def start_as_center?
|
207
|
+
@start_as_center
|
208
|
+
end
|
209
|
+
|
210
|
+
def adjust_start_for_center(value)
|
211
|
+
my_extent = extent
|
212
|
+
if my_extent && my_extent > 0
|
213
|
+
value - my_extent / 2
|
214
|
+
else
|
215
|
+
nil
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
class ParentDimension < Dimension
|
221
|
+
SIMPLE_DELEGATE_METHODS = [:absolute_start, :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
|
+
def extent
|
234
|
+
[extent_in_parent, raw_extent(super)].min
|
235
|
+
end
|
236
|
+
|
237
|
+
private
|
238
|
+
|
239
|
+
# Represents the extent, bounded by the parent container's sizing
|
240
|
+
def extent_in_parent
|
241
|
+
if parent.element_end
|
242
|
+
# Why subtracting an absolute from an element dimension value? A
|
243
|
+
# diagram helped me reason out what we wanted.
|
244
|
+
#
|
245
|
+
# parent. parent. self. self. parent. parent.
|
246
|
+
# abs_start elem_start abs_start abs_end elem_end abs_end
|
247
|
+
# | margin | | | | margin |
|
248
|
+
#
|
249
|
+
# To get our extent respecting the parent's margins, it's our absolute
|
250
|
+
# start, minus parent's element end (so we don't blow past the margin)
|
251
|
+
extent_in_parent = parent.element_end - self.absolute_start - PIXEL_COUNTING_ADJUSTMENT
|
252
|
+
else
|
253
|
+
# If we hit this, then the extent in parent isn't available and will be
|
254
|
+
# ignored by the min call below
|
255
|
+
extent_in_parent = Float::INFINITY
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
# Represents the raw value set for extent, either on element or on parent
|
260
|
+
def raw_extent(original_value)
|
261
|
+
original_value || parent.extent
|
262
|
+
end
|
263
|
+
|
264
|
+
def value_modified?(method)
|
265
|
+
instance_variable = ('@' + method.to_s).to_sym
|
266
|
+
instance_variable_get(instance_variable)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
@@ -0,0 +1,203 @@
|
|
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
|
+
# in case you wonder about the -1... it is used to adjust the right and
|
46
|
+
# bottom values. Because right is not left + width but rather left + width -1
|
47
|
+
# Let me give you an example:
|
48
|
+
# Say left is 20 and we have a width of 100 then the right must be 119,
|
49
|
+
# because you have to take pixel number 20 into account so 20..119 is 100
|
50
|
+
# while 20..120 is 101. E.g.:
|
51
|
+
# (20..119).size => 100
|
52
|
+
PIXEL_COUNTING_ADJUSTMENT = -1
|
53
|
+
|
54
|
+
def initialize(parent, left_or_hash = nil, top = nil, width = nil,
|
55
|
+
height = nil, opts = {})
|
56
|
+
@parent = parent
|
57
|
+
if hash_as_argument?(left_or_hash)
|
58
|
+
init_with_hash(left_or_hash)
|
59
|
+
else
|
60
|
+
init_with_arguments(left_or_hash, top, width, height, opts)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def absolute_x_position?
|
65
|
+
x_dimension.absolute_position?
|
66
|
+
end
|
67
|
+
|
68
|
+
def absolute_y_position?
|
69
|
+
y_dimension.absolute_position?
|
70
|
+
end
|
71
|
+
|
72
|
+
def absolutely_positioned?
|
73
|
+
absolute_x_position? || absolute_y_position?
|
74
|
+
end
|
75
|
+
|
76
|
+
def positioned?
|
77
|
+
x_dimension.positioned? && y_dimension.positioned?
|
78
|
+
end
|
79
|
+
|
80
|
+
def in_bounds?(x, y)
|
81
|
+
x_dimension.in_bounds?(x) && y_dimension.in_bounds?(y)
|
82
|
+
end
|
83
|
+
|
84
|
+
def margin
|
85
|
+
[margin_left, margin_top, margin_right, margin_bottom]
|
86
|
+
end
|
87
|
+
|
88
|
+
def margin=(margin)
|
89
|
+
margin = [margin, margin, margin, margin] unless margin.is_a? Array
|
90
|
+
self.margin_left, self.margin_top,
|
91
|
+
self.margin_right, self.margin_bottom = margin
|
92
|
+
end
|
93
|
+
|
94
|
+
def takes_up_space?
|
95
|
+
true
|
96
|
+
end
|
97
|
+
|
98
|
+
def inspect
|
99
|
+
nothing = '_'
|
100
|
+
super.insert(-2,
|
101
|
+
" relative:#{Point.new left, top}->#{Point.new right, bottom}" \
|
102
|
+
" absolute:#{Point.new absolute_left, absolute_top}->#{Point.new absolute_right, absolute_bottom}" \
|
103
|
+
" #{width || nothing}x#{height || nothing}")
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.setup_delegations
|
107
|
+
methods_to_rename = Dimension.public_instance_methods false
|
108
|
+
renamed_delegate_to :x_dimension, methods_to_rename, 'start' => 'left',
|
109
|
+
'end' => 'right',
|
110
|
+
'extent' => 'width'
|
111
|
+
renamed_delegate_to :y_dimension, methods_to_rename, 'start' => 'top',
|
112
|
+
'end' => 'bottom',
|
113
|
+
'extent' => 'height'
|
114
|
+
end
|
115
|
+
|
116
|
+
setup_delegations
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def hash_as_argument?(left)
|
121
|
+
left.respond_to? :fetch
|
122
|
+
end
|
123
|
+
|
124
|
+
def init_with_hash(hash)
|
125
|
+
init_with_arguments hash.fetch(:left, nil), hash.fetch(:top, nil),
|
126
|
+
hash.fetch(:width, nil), hash.fetch(:height, nil),
|
127
|
+
hash
|
128
|
+
end
|
129
|
+
|
130
|
+
def init_with_arguments(left, top, width, height, opts)
|
131
|
+
@left_top_as_center = opts.fetch(:center, false)
|
132
|
+
init_x_and_y_dimensions
|
133
|
+
general_options opts # order important for redrawing
|
134
|
+
self.displace_left = opts.fetch(:displace_left, nil)
|
135
|
+
self.displace_top = opts.fetch(:displace_top, nil)
|
136
|
+
self.left = left
|
137
|
+
self.top = top
|
138
|
+
self.width = width
|
139
|
+
self.height = height
|
140
|
+
end
|
141
|
+
|
142
|
+
def init_x_and_y_dimensions
|
143
|
+
parent_x_dimension = @parent ? @parent.x_dimension : nil
|
144
|
+
parent_y_dimension = @parent ? @parent.y_dimension : nil
|
145
|
+
@x_dimension = Dimension.new parent_x_dimension, @left_top_as_center
|
146
|
+
@y_dimension = Dimension.new parent_y_dimension, @left_top_as_center
|
147
|
+
end
|
148
|
+
|
149
|
+
def general_options(opts)
|
150
|
+
self.right = opts[:right]
|
151
|
+
self.bottom = opts[:bottom]
|
152
|
+
init_margins opts
|
153
|
+
end
|
154
|
+
|
155
|
+
def init_margins(opts)
|
156
|
+
new_opts = opts.reject { |_k, v| v.nil? }
|
157
|
+
self.margin = new_opts[:margin]
|
158
|
+
self.margin_left = new_opts.fetch(:margin_left, margin_left)
|
159
|
+
self.margin_top = new_opts.fetch(:margin_top, margin_top)
|
160
|
+
self.margin_right = new_opts.fetch(:margin_right, margin_right)
|
161
|
+
self.margin_bottom = new_opts.fetch(:margin_bottom, margin_bottom)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# for objects that do not depend on their parent (get 1.04 as real values)
|
166
|
+
class AbsoluteDimensions < Dimensions
|
167
|
+
def initialize(*args)
|
168
|
+
super(nil, *args)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# for objects that are more defined by their parents, delegates method calls
|
173
|
+
# to crucial methods to the parent if the instance variable isn't set
|
174
|
+
class ParentDimensions < Dimensions
|
175
|
+
def init_x_and_y_dimensions
|
176
|
+
@x_dimension = ParentDimension.new @parent.x_dimension,
|
177
|
+
@left_top_as_center
|
178
|
+
@y_dimension = ParentDimension.new @parent.y_dimension,
|
179
|
+
@left_top_as_center
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# depends on a #dimensions method being present that returns a Dimensions object
|
184
|
+
module DimensionsDelegations
|
185
|
+
extend Forwardable
|
186
|
+
|
187
|
+
UNDELEGATED_METHODS = [:to_s]
|
188
|
+
DELEGATED_METHODS = Dimensions.public_instance_methods(false) - UNDELEGATED_METHODS
|
189
|
+
|
190
|
+
def_delegators :dimensions, *DELEGATED_METHODS
|
191
|
+
|
192
|
+
def adjust_current_position(*_)
|
193
|
+
# no-op by default for almost all elements
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# depends on a #dsl method to forward to (e.g. for backend objects)
|
198
|
+
module BackendDimensionsDelegations
|
199
|
+
extend Forwardable
|
200
|
+
|
201
|
+
def_delegators :dsl, *DimensionsDelegations::DELEGATED_METHODS
|
202
|
+
end
|
203
|
+
end
|