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.
Files changed (209) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +84 -0
  3. data/Gemfile +24 -0
  4. data/Guardfile +11 -0
  5. data/LICENSE +31 -0
  6. data/README.md +201 -0
  7. data/ext/install/Rakefile +29 -0
  8. data/ext/install/shoes.bat +9 -0
  9. data/fonts/Coolvetica.ttf +0 -0
  10. data/fonts/Lacuna.ttf +0 -0
  11. data/lib/shoes/animation.rb +56 -0
  12. data/lib/shoes/app.rb +131 -0
  13. data/lib/shoes/arc.rb +25 -0
  14. data/lib/shoes/background.rb +24 -0
  15. data/lib/shoes/border.rb +24 -0
  16. data/lib/shoes/builtin_methods.rb +77 -0
  17. data/lib/shoes/button.rb +30 -0
  18. data/lib/shoes/check_button.rb +44 -0
  19. data/lib/shoes/color.rb +385 -0
  20. data/lib/shoes/common/background_element.rb +9 -0
  21. data/lib/shoes/common/changeable.rb +34 -0
  22. data/lib/shoes/common/clickable.rb +24 -0
  23. data/lib/shoes/common/inspect.rb +14 -0
  24. data/lib/shoes/common/positioning.rb +30 -0
  25. data/lib/shoes/common/registration.rb +33 -0
  26. data/lib/shoes/common/remove.rb +10 -0
  27. data/lib/shoes/common/state.rb +18 -0
  28. data/lib/shoes/common/style.rb +152 -0
  29. data/lib/shoes/common/style_normalizer.rb +16 -0
  30. data/lib/shoes/common/ui_element.rb +11 -0
  31. data/lib/shoes/common/visibility.rb +40 -0
  32. data/lib/shoes/configuration.rb +96 -0
  33. data/lib/shoes/dialog.rb +27 -0
  34. data/lib/shoes/dimension.rb +239 -0
  35. data/lib/shoes/dimensions.rb +209 -0
  36. data/lib/shoes/download.rb +121 -0
  37. data/lib/shoes/dsl.rb +591 -0
  38. data/lib/shoes/font.rb +49 -0
  39. data/lib/shoes/gradient.rb +31 -0
  40. data/lib/shoes/image.rb +29 -0
  41. data/lib/shoes/image_pattern.rb +12 -0
  42. data/lib/shoes/input_box.rb +60 -0
  43. data/lib/shoes/internal_app.rb +219 -0
  44. data/lib/shoes/key_event.rb +17 -0
  45. data/lib/shoes/line.rb +87 -0
  46. data/lib/shoes/link.rb +59 -0
  47. data/lib/shoes/link_hover.rb +5 -0
  48. data/lib/shoes/list_box.rb +50 -0
  49. data/lib/shoes/logger.rb +66 -0
  50. data/lib/shoes/logger/ruby.rb +18 -0
  51. data/lib/shoes/mock.rb +31 -0
  52. data/lib/shoes/mock/animation.rb +8 -0
  53. data/lib/shoes/mock/app.rb +47 -0
  54. data/lib/shoes/mock/arc.rb +9 -0
  55. data/lib/shoes/mock/background.rb +10 -0
  56. data/lib/shoes/mock/border.rb +7 -0
  57. data/lib/shoes/mock/button.rb +10 -0
  58. data/lib/shoes/mock/check.rb +25 -0
  59. data/lib/shoes/mock/clickable.rb +8 -0
  60. data/lib/shoes/mock/common_methods.rb +12 -0
  61. data/lib/shoes/mock/dialog.rb +13 -0
  62. data/lib/shoes/mock/download.rb +18 -0
  63. data/lib/shoes/mock/font.rb +17 -0
  64. data/lib/shoes/mock/image.rb +13 -0
  65. data/lib/shoes/mock/image_pattern.rb +9 -0
  66. data/lib/shoes/mock/input_box.rb +30 -0
  67. data/lib/shoes/mock/keypress.rb +10 -0
  68. data/lib/shoes/mock/keyrelease.rb +10 -0
  69. data/lib/shoes/mock/line.rb +14 -0
  70. data/lib/shoes/mock/link.rb +12 -0
  71. data/lib/shoes/mock/list_box.rb +19 -0
  72. data/lib/shoes/mock/oval.rb +12 -0
  73. data/lib/shoes/mock/progress.rb +10 -0
  74. data/lib/shoes/mock/radio.rb +27 -0
  75. data/lib/shoes/mock/rect.rb +14 -0
  76. data/lib/shoes/mock/shape.rb +20 -0
  77. data/lib/shoes/mock/slot.rb +16 -0
  78. data/lib/shoes/mock/sound.rb +8 -0
  79. data/lib/shoes/mock/star.rb +14 -0
  80. data/lib/shoes/mock/text_block.rb +36 -0
  81. data/lib/shoes/mock/timer.rb +8 -0
  82. data/lib/shoes/not_implemented_error.rb +4 -0
  83. data/lib/shoes/oval.rb +20 -0
  84. data/lib/shoes/point.rb +54 -0
  85. data/lib/shoes/progress.rb +25 -0
  86. data/lib/shoes/radio.rb +16 -0
  87. data/lib/shoes/rect.rb +21 -0
  88. data/lib/shoes/renamed_delegate.rb +15 -0
  89. data/lib/shoes/shape.rb +158 -0
  90. data/lib/shoes/slot.rb +271 -0
  91. data/lib/shoes/slot_contents.rb +50 -0
  92. data/lib/shoes/sound.rb +18 -0
  93. data/lib/shoes/span.rb +16 -0
  94. data/lib/shoes/star.rb +45 -0
  95. data/lib/shoes/text.rb +24 -0
  96. data/lib/shoes/text_block.rb +143 -0
  97. data/lib/shoes/text_block_dimensions.rb +52 -0
  98. data/lib/shoes/timer.rb +12 -0
  99. data/lib/shoes/url.rb +44 -0
  100. data/lib/shoes/version.rb +3 -0
  101. data/lib/shoes/widget.rb +69 -0
  102. data/manifests/common.rb +34 -0
  103. data/manifests/shoes-dsl.rb +34 -0
  104. data/shoes-dsl.gemspec +19 -0
  105. data/spec/code_coverage.rb +14 -0
  106. data/spec/shoes/animation_spec.rb +65 -0
  107. data/spec/shoes/app_spec.rb +484 -0
  108. data/spec/shoes/arc_spec.rb +51 -0
  109. data/spec/shoes/background_spec.rb +53 -0
  110. data/spec/shoes/border_spec.rb +47 -0
  111. data/spec/shoes/builtin_methods_spec.rb +110 -0
  112. data/spec/shoes/button_spec.rb +44 -0
  113. data/spec/shoes/check_spec.rb +35 -0
  114. data/spec/shoes/cli_spec.rb +15 -0
  115. data/spec/shoes/color_spec.rb +408 -0
  116. data/spec/shoes/common/inspect_spec.rb +26 -0
  117. data/spec/shoes/common/remove_spec.rb +38 -0
  118. data/spec/shoes/common/style_normalizer_spec.rb +28 -0
  119. data/spec/shoes/common/style_spec.rb +147 -0
  120. data/spec/shoes/configuration_spec.rb +36 -0
  121. data/spec/shoes/constants_spec.rb +38 -0
  122. data/spec/shoes/dialog_spec.rb +163 -0
  123. data/spec/shoes/dimension_spec.rb +407 -0
  124. data/spec/shoes/dimensions_spec.rb +837 -0
  125. data/spec/shoes/download_spec.rb +142 -0
  126. data/spec/shoes/flow_spec.rb +133 -0
  127. data/spec/shoes/font_spec.rb +37 -0
  128. data/spec/shoes/framework_learning_spec.rb +30 -0
  129. data/spec/shoes/gradient_spec.rb +32 -0
  130. data/spec/shoes/helpers/fake_element.rb +17 -0
  131. data/spec/shoes/helpers/inspect_helpers.rb +5 -0
  132. data/spec/shoes/helpers/sample17_helper.rb +66 -0
  133. data/spec/shoes/image_spec.rb +49 -0
  134. data/spec/shoes/images/shoe.jpg +0 -0
  135. data/spec/shoes/input_box_spec.rb +80 -0
  136. data/spec/shoes/integration_spec.rb +20 -0
  137. data/spec/shoes/internal_app_spec.rb +141 -0
  138. data/spec/shoes/keypress_spec.rb +11 -0
  139. data/spec/shoes/keyrelease_spec.rb +12 -0
  140. data/spec/shoes/line_spec.rb +49 -0
  141. data/spec/shoes/link_spec.rb +105 -0
  142. data/spec/shoes/list_box_spec.rb +74 -0
  143. data/spec/shoes/logger/ruby_spec.rb +8 -0
  144. data/spec/shoes/logger_spec.rb +45 -0
  145. data/spec/shoes/oval_spec.rb +24 -0
  146. data/spec/shoes/point_spec.rb +71 -0
  147. data/spec/shoes/progress_spec.rb +54 -0
  148. data/spec/shoes/radio_spec.rb +32 -0
  149. data/spec/shoes/rect_spec.rb +39 -0
  150. data/spec/shoes/renamed_delegate_spec.rb +70 -0
  151. data/spec/shoes/shape_spec.rb +95 -0
  152. data/spec/shoes/shared_examples/button.rb +6 -0
  153. data/spec/shoes/shared_examples/changeable.rb +26 -0
  154. data/spec/shoes/shared_examples/clickable.rb +5 -0
  155. data/spec/shoes/shared_examples/common_methods.rb +35 -0
  156. data/spec/shoes/shared_examples/dimensions.rb +32 -0
  157. data/spec/shoes/shared_examples/dsl.rb +44 -0
  158. data/spec/shoes/shared_examples/dsl/animate.rb +29 -0
  159. data/spec/shoes/shared_examples/dsl/arc.rb +45 -0
  160. data/spec/shoes/shared_examples/dsl/background.rb +26 -0
  161. data/spec/shoes/shared_examples/dsl/border.rb +10 -0
  162. data/spec/shoes/shared_examples/dsl/button.rb +5 -0
  163. data/spec/shoes/shared_examples/dsl/cap.rb +6 -0
  164. data/spec/shoes/shared_examples/dsl/check.rb +11 -0
  165. data/spec/shoes/shared_examples/dsl/edit_box.rb +8 -0
  166. data/spec/shoes/shared_examples/dsl/edit_line.rb +8 -0
  167. data/spec/shoes/shared_examples/dsl/editable_element.rb +29 -0
  168. data/spec/shoes/shared_examples/dsl/fill.rb +27 -0
  169. data/spec/shoes/shared_examples/dsl/flow.rb +15 -0
  170. data/spec/shoes/shared_examples/dsl/gradient.rb +62 -0
  171. data/spec/shoes/shared_examples/dsl/image.rb +21 -0
  172. data/spec/shoes/shared_examples/dsl/line.rb +9 -0
  173. data/spec/shoes/shared_examples/dsl/nofill.rb +6 -0
  174. data/spec/shoes/shared_examples/dsl/nostroke.rb +6 -0
  175. data/spec/shoes/shared_examples/dsl/oval.rb +88 -0
  176. data/spec/shoes/shared_examples/dsl/pattern.rb +34 -0
  177. data/spec/shoes/shared_examples/dsl/progress.rb +7 -0
  178. data/spec/shoes/shared_examples/dsl/rect.rb +92 -0
  179. data/spec/shoes/shared_examples/dsl/rgb.rb +26 -0
  180. data/spec/shoes/shared_examples/dsl/shape.rb +21 -0
  181. data/spec/shoes/shared_examples/dsl/star.rb +48 -0
  182. data/spec/shoes/shared_examples/dsl/stroke.rb +30 -0
  183. data/spec/shoes/shared_examples/dsl/strokewidth.rb +19 -0
  184. data/spec/shoes/shared_examples/dsl/style.rb +32 -0
  185. data/spec/shoes/shared_examples/dsl/text_elements.rb +81 -0
  186. data/spec/shoes/shared_examples/dsl/video.rb +5 -0
  187. data/spec/shoes/shared_examples/dsl_app_context.rb +8 -0
  188. data/spec/shoes/shared_examples/hover_leave.rb +11 -0
  189. data/spec/shoes/shared_examples/parent.rb +6 -0
  190. data/spec/shoes/shared_examples/scroll.rb +41 -0
  191. data/spec/shoes/shared_examples/shared_element_method.rb +60 -0
  192. data/spec/shoes/shared_examples/slot.rb +331 -0
  193. data/spec/shoes/shared_examples/state.rb +19 -0
  194. data/spec/shoes/shared_examples/style.rb +82 -0
  195. data/spec/shoes/slot_spec.rb +130 -0
  196. data/spec/shoes/sound_spec.rb +15 -0
  197. data/spec/shoes/span_spec.rb +112 -0
  198. data/spec/shoes/spec_helper.rb +24 -0
  199. data/spec/shoes/stack_spec.rb +79 -0
  200. data/spec/shoes/star_spec.rb +31 -0
  201. data/spec/shoes/text_block_dimensions_spec.rb +75 -0
  202. data/spec/shoes/text_block_spec.rb +270 -0
  203. data/spec/shoes/url_spec.rb +68 -0
  204. data/spec/shoes/widget_spec.rb +70 -0
  205. data/spec/shoes_spec.rb +44 -0
  206. data/spec/spec_helper.rb +18 -0
  207. data/static/Shoes.icns +0 -0
  208. data/static/shoes-icon.png +0 -0
  209. metadata +354 -0
@@ -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