shoes-dsl 4.0.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
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