motion-kit 0.12.0 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +28 -8
  3. data/lib/{motion-kit → motion-kit-cocoa}/calculator/view_calculator.rb +0 -0
  4. data/lib/motion-kit-cocoa/constraints/constraint.rb +3 -1
  5. data/lib/motion-kit-cocoa/{layouts → helpers}/accessibility_compat.rb +0 -0
  6. data/lib/motion-kit-cocoa/{layouts → helpers}/cagradientlayer_helpers.rb +0 -0
  7. data/lib/motion-kit-cocoa/{layouts → helpers}/calayer_helpers.rb +0 -0
  8. data/lib/motion-kit-cocoa/{layouts → helpers}/sugarcube_compat.rb +0 -0
  9. data/lib/motion-kit-ios/{layouts → helpers}/constraints_helpers.rb +0 -0
  10. data/lib/motion-kit-ios/{layouts → helpers}/layout_device.rb +0 -0
  11. data/lib/motion-kit-ios/{layouts → helpers}/layout_orientation.rb +0 -0
  12. data/lib/motion-kit-ios/{layouts → helpers}/uibutton_helpers.rb +0 -0
  13. data/lib/motion-kit-ios/{layouts/uiview_layout_autoresizing.rb → helpers/uiview_autoresizing_helpers.rb} +0 -0
  14. data/lib/motion-kit-ios/{layouts/uiview_layout_constraints.rb → helpers/uiview_constraints_helpers.rb} +0 -0
  15. data/lib/motion-kit-ios/{layouts/uiview_layout_frame.rb → helpers/uiview_frame_helpers.rb} +0 -0
  16. data/lib/motion-kit-ios/{layouts/uiview_layout_gradient.rb → helpers/uiview_gradient_helpers.rb} +0 -0
  17. data/lib/motion-kit-ios/{layouts → helpers}/uiview_helpers.rb +0 -0
  18. data/lib/motion-kit-osx/{layouts → helpers}/constraints_helpers.rb +0 -0
  19. data/lib/motion-kit-osx/{layouts → helpers}/nsmenu_extensions.rb +0 -0
  20. data/lib/motion-kit-osx/{layouts → helpers}/nsmenu_helpers.rb +0 -0
  21. data/lib/motion-kit-osx/{layouts → helpers}/nsmenuitem_extensions.rb +0 -0
  22. data/lib/motion-kit-osx/{layouts → helpers}/nstablecolumn_helpers.rb +0 -0
  23. data/lib/motion-kit-osx/{layouts → helpers}/nstableview_helpers.rb +0 -0
  24. data/lib/motion-kit-osx/{layouts/nsview_layout_autoresizing.rb → helpers/nsview_autoresizing_helpers.rb} +0 -0
  25. data/lib/motion-kit-osx/{layouts/nsview_layout_constraints.rb → helpers/nsview_constraints_helpers.rb} +0 -0
  26. data/lib/motion-kit-osx/{layouts/nsview_layout_frame.rb → helpers/nsview_frame_helpers.rb} +0 -0
  27. data/lib/motion-kit-osx/{layouts → helpers}/nsview_helpers.rb +0 -0
  28. data/lib/motion-kit-osx/helpers/nswindow_frame_helpers.rb +361 -0
  29. data/lib/motion-kit-osx/{layouts → helpers}/nswindow_helpers.rb +0 -0
  30. data/lib/motion-kit/{layouts → helpers}/base_layout.rb +0 -0
  31. data/lib/motion-kit/{layouts → helpers}/base_layout_class_methods.rb +0 -0
  32. data/lib/motion-kit/{layouts → helpers}/parent.rb +0 -0
  33. data/lib/motion-kit/{layouts → helpers}/tree_layout.rb +21 -4
  34. data/lib/motion-kit/object.rb +11 -0
  35. data/lib/motion-kit/version.rb +1 -1
  36. data/spec/ios/layout_spec.rb +6 -6
  37. data/spec/ios/motion_kit_id_spec.rb +15 -0
  38. data/spec/ios/remove_layout_spec.rb +9 -5
  39. data/spec/osx/{frame_helper_spec.rb → nsview_frame_helper_spec.rb} +69 -69
  40. data/spec/osx/nswindow_frame_helper_spec.rb +1288 -0
  41. metadata +38 -34
  42. data/lib/motion-kit-osx/layouts/nswindow_frame.rb +0 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1027d089bb3ce6aafe9f4f55d152a6e3c22a4511
4
- data.tar.gz: 7e6b2b1bca51e2d3e0aae3d71a2adb76cf31c768
3
+ metadata.gz: 2b2b7891f4a764ec64a5a015e75cb609f161d744
4
+ data.tar.gz: ca6b9958b22c9dbc6d78efe6eaf9281878e1db98
5
5
  SHA512:
6
- metadata.gz: f45d382fbffb1edea0cf1f4f53ca14344d997de32441319a4978d428fecf5721fe32f51e67c37437e28f335b932ab3ee3747059e6c269ec1f96df15f5bf032c2
7
- data.tar.gz: 02332a86a6625fa6175423524e4bc94865a34c2d7da9a39318699edd144dea3e54893276c38331680e736ba64c67280a68284aa4852fdb31baaf99f2f8edf3b5
6
+ metadata.gz: 904f76837a3321502bccc36587931301d48d500ab597482df30d5541b218cb4de7cd7d21df78b3e4fa7d7e98b6d7e876e2926439ca4e761fa2345db9c258f419
7
+ data.tar.gz: c905dcff79b15598662c7cd2055ae8121cb763db31df07bca51d32002643b92ca942455242f514ddbdb14872a59c5326d73bb935fb11bea481a711bd392291bc
data/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  2. Simple, easy to learn DSL
10
10
  3. Crossframework compatibility:
11
11
  - [UIKit][readmore-uikit]
12
- - [ApplicationKit][readmore-applicationkit]
12
+ - [AppKit][readmore-appkit]
13
13
  - [AutoLayout][readmore-autolayout]
14
14
  - [Frame geometry][readmore-frames]
15
15
  - [CoreAnimation][readmore-coreanimation]
@@ -29,8 +29,9 @@
29
29
  [SweetKit]: https://github.com/rubymotion/sweet-kit
30
30
 
31
31
  [READMORE]: https://github.com/rubymotion/motion-kit/blob/master/READMORE.md
32
+ [readmore-migrating]: https://github.com/rubymotion/motion-kit/blob/master/READMORE.md#migrating-from-teacup
32
33
  [readmore-uikit]: https://github.com/rubymotion/motion-kit/blob/master/READMORE.md#uikit
33
- [readmore-applicationkit]: https://github.com/rubymotion/motion-kit/blob/master/READMORE.md#applicationkit
34
+ [readmore-appkit]: https://github.com/rubymotion/motion-kit/blob/master/READMORE.md#appkit
34
35
  [readmore-coreanimation]: https://github.com/rubymotion/motion-kit/blob/master/READMORE.md#coreanimation
35
36
  [readmore-frames]: https://github.com/rubymotion/motion-kit/blob/master/READMORE.md#frames
36
37
  [readmore-autolayout]: https://github.com/rubymotion/motion-kit/blob/master/READMORE.md#autolayout
@@ -42,6 +43,10 @@
42
43
  You can [read all about](#goodbye-teacup) why Colin decided that Teacup needed to
43
44
  be replaced with a new project, rather than upgraded or refactored.
44
45
 
46
+ If you need to update your app to use MotionKit, see
47
+ [READMORE.md][readmore-migrating] for an example of migrating stylesheets,
48
+ styles, and constraints.
49
+
45
50
 
46
51
  ## Usage
47
52
 
@@ -188,7 +193,7 @@ class LoginLayout < MotionKit::Layout
188
193
  frame [[10, 10], ['100% - 10', :auto]]
189
194
  end
190
195
  add UITextField, :password_input do
191
- frame below(:username_input, margin: 8)
196
+ frame below(:username_input, down: 8)
192
197
  end
193
198
  end
194
199
  end
@@ -241,10 +246,11 @@ include multiple stylesheets this way, just be careful around name collisions.
241
246
  module LoginStyles
242
247
 
243
248
  def login_button_style
249
+ # this example uses SugarCube to create UIColor and CGColor objects.
244
250
  background_color '#51A8E7'.uicolor
245
251
  title 'Log In'
246
252
  # `layer` returns a CALayer, which in turn becomes the new context inside
247
- # this block!
253
+ # this block
248
254
  layer do
249
255
  corner_radius 7.0
250
256
  shadow_color '#000000'.cgcolor
@@ -342,8 +348,11 @@ root view, so retain one yourself to prevent it from being deallocated.
342
348
  If you've used RMQ's Stylers, you'll recognize a very similar pattern here. In
343
349
  RMQ the 'style' methods are handed a 'Styler' instance, which wraps access to
344
350
  the view. In MotionKit we make use of `method_missing` to call these methods
345
- indirectly. That takes care of most methods related to styling, except those
346
- that take multiple arguments. Those can get "helper" methods.
351
+ indirectly. That takes care of most methods related to styling, but you might
352
+ want to write some "helper" methods so that your styling code is more concise.
353
+ Some examples are included in the MotionKit core, but the [SweetKit][] gem has
354
+ many more. If you are writing helpers for UIKit or AppKit, please consider
355
+ adding them to SweetKit, so we can all share in the productivity boost! :smiley:
347
356
 
348
357
  ```ruby
349
358
  def login_label_style
@@ -356,6 +365,7 @@ that take multiple arguments. Those can get "helper" methods.
356
365
  title 'Press me'
357
366
  # this gets delegated to UIButtonHelpers#title(title), which in turn calls
358
367
  # button.setTitle(title, forState: UIControlStateNormal)
368
+ # See uibutton_helpers.rb for implementation.
359
369
  end
360
370
  ```
361
371
 
@@ -384,8 +394,8 @@ benchmarking it is insignificant and undetectable. Let us know if you find any
384
394
  performance issues.
385
395
 
386
396
  You can easily add your own helpers to MotionKit. They
387
- are all named consistenly, e.g. `MotionKit::UIViewHelpers`, e.g.
388
- `MotionKit::UILabelHelpers`. You just need to specify the "target class" that
397
+ should all be named consistenly, e.g. `MotionKit::UIViewHelpers`,
398
+ `MotionKit::UILabelHelpers`, etc. You just need to specify the "target class" that
389
399
  your helper class is meant to work with. Each class can only have *one helper
390
400
  class*.
391
401
 
@@ -926,6 +936,16 @@ annoying subtletees of the NSCell/NSControl dichotomy.
926
936
  gem install sweet-kit
927
937
 
928
938
 
939
+ # Gotchas
940
+
941
+ ### A Note on `add` and `remove`
942
+
943
+ When you use the `add` method to add a subview, that view will be retained by
944
+ the Layout *even if you remove it from the view hierarchy*. If you want the
945
+ Layout to forget all about the view, call `remove(view)` (which also calls
946
+ `removeFromSuperview`) or `forget(element_id)` (which only removes it from the
947
+ Layout) on the Layout.
948
+
929
949
  # Contributing
930
950
 
931
951
  We welcome your contributions! Please be sure to run the specs before you do,
@@ -730,7 +730,9 @@ module MotionKit
730
730
 
731
731
  def update_constraint
732
732
  if @resolved
733
- @resolved.each do
733
+ [0, 1].each do |index|
734
+ constraint = @resolved[index]
735
+ constraint.constant = self.constant[index]
734
736
  end
735
737
  end
736
738
  end
@@ -0,0 +1,361 @@
1
+ # @requires MotionKit::NSWindowHelpers
2
+ module MotionKit
3
+ class NSWindowHelpers
4
+
5
+ def _fix_frame_value(value)
6
+ if value.is_a?(Hash) && value[:relative]
7
+ return value.merge(flipped: true)
8
+ end
9
+ return value
10
+ end
11
+
12
+ def frame(value, autosave_name=nil)
13
+ value = _fix_frame_value(value)
14
+ screen = target.screen || NSScreen.mainScreen
15
+ value = MotionKit.calculate(target, :frame, value, screen)
16
+ target.setFrame(value, display: true)
17
+ if autosave_name
18
+ target.setFrameAutosaveName(autosave_name)
19
+ end
20
+ return target.frame
21
+ end
22
+
23
+ def x(value)
24
+ value = _fix_frame_value(value)
25
+ f = target.frame
26
+ screen = target.screen || NSScreen.mainScreen
27
+ f.origin.x = MotionKit.calculate(target, :width, value, screen)
28
+ target.setFrame(f, display: true)
29
+ return CGRectGetMinX(f)
30
+ end
31
+ alias left x
32
+
33
+ def right(value)
34
+ value = _fix_frame_value(value)
35
+ f = target.frame
36
+ screen = target.screen || NSScreen.mainScreen
37
+ f.origin.x = MotionKit.calculate(target, :width, value, screen) - f.size.width
38
+ target.setFrame(f, display: true)
39
+ return CGRectGetMaxX(f)
40
+ end
41
+
42
+ def center_x(value)
43
+ value = _fix_frame_value(value)
44
+ f = target.frame
45
+ screen = target.screen || NSScreen.mainScreen
46
+ f.origin.x = MotionKit.calculate(target, :width, value, screen)
47
+ f.origin.x -= f.size.width / 2
48
+ target.setFrame(f, display: true)
49
+ return CGRectGetMidX(target.frame)
50
+ end
51
+ alias middle_x center_x
52
+
53
+ def y(value)
54
+ value = _fix_frame_value(value)
55
+ f = target.frame
56
+ screen = target.screen || NSScreen.mainScreen
57
+ f.origin.y = MotionKit.calculate(target, :height, value, screen)
58
+ target.setFrame(f, display: true)
59
+ return CGRectGetMinY(f)
60
+ end
61
+
62
+ def bottom(value)
63
+ value = _fix_frame_value(value)
64
+ f = target.frame
65
+ screen = target.screen || NSScreen.mainScreen
66
+ f.origin.y = MotionKit.calculate(target, :height, value, screen)
67
+ target.setFrame(f, display: true)
68
+
69
+ return CGRectGetMinY(target.frame)
70
+ end
71
+
72
+ def top(value)
73
+ value = _fix_frame_value(value)
74
+ f = target.frame
75
+ screen = target.screen || NSScreen.mainScreen
76
+ f.origin.y = MotionKit.calculate(target, :height, value, screen)
77
+ f.origin.y -= f.size.height
78
+ target.setFrame(f, display: true)
79
+
80
+ return CGRectGetMaxY(f)
81
+ end
82
+
83
+ def center_y(value)
84
+ value = _fix_frame_value(value)
85
+ f = target.frame
86
+ screen = target.screen || NSScreen.mainScreen
87
+ f.origin.y = MotionKit.calculate(target, :height, value, screen)
88
+ f.origin.y -= f.size.height / 2
89
+ target.setFrame(f, display: true)
90
+ return CGRectGetMidY(target.frame)
91
+ end
92
+ alias middle_y center_y
93
+
94
+ def width(value)
95
+ value = _fix_frame_value(value)
96
+ f = target.frame
97
+ screen = target.screen || NSScreen.mainScreen
98
+ f.size.width = MotionKit.calculate(target, :width, value, screen)
99
+ target.setFrame(f, display: true)
100
+ return CGRectGetWidth(f)
101
+ end
102
+ alias w width
103
+
104
+ def height(value)
105
+ value = _fix_frame_value(value)
106
+ f = target.frame
107
+ screen = target.screen || NSScreen.mainScreen
108
+ f.size.height = MotionKit.calculate(target, :height, value, screen)
109
+ target.setFrame(f, display: true)
110
+ return CGRectGetHeight(f)
111
+ end
112
+ alias h height
113
+
114
+ def origin(value)
115
+ value = _fix_frame_value(value)
116
+ f = target.frame
117
+ screen = target.screen || NSScreen.mainScreen
118
+ f.origin = MotionKit.calculate(target, :origin, value, screen)
119
+ target.setFrame(f, display: true)
120
+ return target.frame.origin
121
+ end
122
+
123
+ def center(value)
124
+ value = _fix_frame_value(value)
125
+ f = target.frame
126
+ screen = target.screen || NSScreen.mainScreen
127
+ center = MotionKit.calculate(target, :center, value, screen)
128
+ origin = CGPoint.new(center.x, center.y)
129
+ origin.x -= f.size.width / 2
130
+ origin.y -= f.size.height / 2
131
+ f.origin = origin
132
+ target.setFrame(f, display: true)
133
+ return center
134
+ end
135
+ alias middle center
136
+
137
+ def size(value)
138
+ value = _fix_frame_value(value)
139
+ f = target.frame
140
+ screen = target.screen || NSScreen.mainScreen
141
+ f.size = MotionKit.calculate(target, :size, value, screen)
142
+ target.setFrame(f, display: true)
143
+ return target.frame.size
144
+ end
145
+
146
+ def _calculate_frame(f, from: from_window, relative_to: point)
147
+ if from_window.is_a?(Symbol)
148
+ from_window = self.get_view(from_window)
149
+ end
150
+
151
+ from_window_size = from_window.frame.size
152
+
153
+ calculate_window = target
154
+
155
+ if point[:x] == :reset || point[:y] == :reset
156
+ calculate_window = NSWindow.alloc.init
157
+ calculate_window.setFrame([[0, 0], target.frame.size], display: false)
158
+ end
159
+
160
+ if f.is_a?(Hash)
161
+ f = f.merge(relative: true, flipped: true)
162
+ end
163
+ f = MotionKit.calculate(calculate_window, :frame, f, from_window)
164
+ if from_window.is_a?(NSWindow)
165
+ f.origin.x += from_window.frame.origin.x
166
+ f.origin.y += from_window.frame.origin.y
167
+ end
168
+
169
+ case point[:x]
170
+ when :min, :reset
171
+ # pass
172
+ when :mid
173
+ f.origin.x += (from_window_size.width - f.size.width) / 2.0
174
+ when :max
175
+ f.origin.x += from_window_size.width - f.size.width
176
+ when :before
177
+ f.origin.x -= f.size.width
178
+ when :after
179
+ f.origin.x += from_window_size.width
180
+ else
181
+ f.origin.x += point[:x]
182
+ end
183
+
184
+ case point[:y]
185
+ when :reset, :min
186
+ # pass
187
+ when :mid
188
+ f.origin.y += (from_window_size.height - f.size.height) / 2.0
189
+ when :max
190
+ f.origin.y += from_window_size.height - f.size.height
191
+ when :above
192
+ f.origin.y += from_window_size.height
193
+ when :below
194
+ f.origin.y -= f.size.height
195
+ else
196
+ f.origin.y += point[:y]
197
+ end
198
+
199
+ return f
200
+ end
201
+
202
+ # The first arg can be a window or a frame
203
+ # @example
204
+ # frame from_top_left(width: 80, height: 22)
205
+ # frame from_top_left(another_view, width: 80, height: 22)
206
+ def from_top_left(from_window=nil, f=nil)
207
+ if from_window.is_a?(Hash)
208
+ f = from_window
209
+ from_window = nil
210
+ end
211
+ f ||= {}
212
+ from_window ||= target.screen || NSScreen.mainScreen
213
+ _calculate_frame(f, from: from_window, relative_to: { x: :min, y: :max })
214
+ end
215
+
216
+ # The first arg can be a window or a frame
217
+ # @example
218
+ # frame from_top(width: 80, height: 22)
219
+ # frame from_top(another_view, width: 80, height: 22)
220
+ def from_top(from_window=nil, f=nil)
221
+ if from_window.is_a?(Hash)
222
+ f = from_window
223
+ from_window = nil
224
+ end
225
+ f ||= {}
226
+ from_window ||= target.screen || NSScreen.mainScreen
227
+ _calculate_frame(f, from: from_window, relative_to: { x: :mid, y: :max })
228
+ end
229
+
230
+ # The first arg can be a window or a frame
231
+ # @example
232
+ # frame from_top_right(width: 80, height: 22)
233
+ # frame from_top_right(another_view, width: 80, height: 22)
234
+ def from_top_right(from_window=nil, f=nil)
235
+ if from_window.is_a?(Hash)
236
+ f = from_window
237
+ from_window = nil
238
+ end
239
+ f ||= {}
240
+ from_window ||= target.screen || NSScreen.mainScreen
241
+ _calculate_frame(f, from: from_window, relative_to: { x: :max, y: :max })
242
+ end
243
+
244
+ # The first arg can be a window or a frame
245
+ # @example
246
+ # frame from_left(width: 80, height: 22)
247
+ # frame from_left(another_view, width: 80, height: 22)
248
+ def from_left(from_window=nil, f=nil)
249
+ if from_window.is_a?(Hash)
250
+ f = from_window
251
+ from_window = nil
252
+ end
253
+ f ||= {}
254
+ from_window ||= target.screen || NSScreen.mainScreen
255
+ _calculate_frame(f, from: from_window, relative_to: { x: :min, y: :mid })
256
+ end
257
+
258
+ # The first arg can be a window or a frame
259
+ # @example
260
+ # frame from_center(width: 80, height: 22)
261
+ # frame from_center(another_view, width: 80, height: 22)
262
+ def from_center(from_window=nil, f=nil)
263
+ if from_window.is_a?(Hash)
264
+ f = from_window
265
+ from_window = nil
266
+ end
267
+ f ||= {}
268
+ from_window ||= target.screen || NSScreen.mainScreen
269
+ _calculate_frame(f, from: from_window, relative_to: { x: :mid, y: :mid })
270
+ end
271
+
272
+ # The first arg can be a window or a frame
273
+ # @example
274
+ # frame from_right(width: 80, height: 22)
275
+ # frame from_right(another_view, width: 80, height: 22)
276
+ def from_right(from_window=nil, f=nil)
277
+ if from_window.is_a?(Hash)
278
+ f = from_window
279
+ from_window = nil
280
+ end
281
+ f ||= {}
282
+ from_window ||= target.screen || NSScreen.mainScreen
283
+ _calculate_frame(f, from: from_window, relative_to: { x: :max, y: :mid })
284
+ end
285
+
286
+ # The first arg can be a window or a frame
287
+ # @example
288
+ # frame from_bottom_left(width: 80, height: 22)
289
+ # frame from_bottom_left(another_view, width: 80, height: 22)
290
+ def from_bottom_left(from_window=nil, f=nil)
291
+ if from_window.is_a?(Hash)
292
+ f = from_window
293
+ from_window = nil
294
+ end
295
+ f ||= {}
296
+ from_window ||= target.screen || NSScreen.mainScreen
297
+ _calculate_frame(f, from: from_window, relative_to: { x: :min, y: :min })
298
+ end
299
+
300
+ # The first arg can be a window or a frame
301
+ # @example
302
+ # frame from_bottom(width: 80, height: 22)
303
+ # frame from_bottom(another_view, width: 80, height: 22)
304
+ def from_bottom(from_window=nil, f=nil)
305
+ if from_window.is_a?(Hash)
306
+ f = from_window
307
+ from_window = nil
308
+ end
309
+ f ||= {}
310
+ from_window ||= target.screen || NSScreen.mainScreen
311
+ _calculate_frame(f, from: from_window, relative_to: { x: :mid, y: :min })
312
+ end
313
+
314
+ # The first arg can be a window or a frame
315
+ # @example
316
+ # frame from_bottom_right(width: 80, height: 22)
317
+ # frame from_bottom_right(another_view, width: 80, height: 22)
318
+ def from_bottom_right(from_window=nil, f=nil)
319
+ if from_window.is_a?(Hash)
320
+ f = from_window
321
+ from_window = nil
322
+ end
323
+ f ||= {}
324
+ from_window ||= target.screen || NSScreen.mainScreen
325
+ _calculate_frame(f, from: from_window, relative_to: { x: :max, y: :min })
326
+ end
327
+
328
+ # The first arg can be a window or a frame
329
+ # @example
330
+ def above(from_window, f={})
331
+ _calculate_frame(f, from: from_window, relative_to: { x: :reset, y: :above })
332
+ end
333
+
334
+ # The first arg can be a window or a frame
335
+ # @example
336
+ def below(from_window, f={})
337
+ _calculate_frame(f, from: from_window, relative_to: { x: :reset, y: :below })
338
+ end
339
+
340
+ # The first arg can be a window or a frame
341
+ # @example
342
+ def before(from_window, f={})
343
+ _calculate_frame(f, from: from_window, relative_to: { x: :before, y: :reset })
344
+ end
345
+ alias left_of before
346
+
347
+ # The first arg can be a window or a frame
348
+ # @example
349
+ def after(from_window, f={})
350
+ _calculate_frame(f, from: from_window, relative_to: { x: :after, y: :reset })
351
+ end
352
+ alias right_of after
353
+
354
+ # The first arg must be a view
355
+ # @example
356
+ def relative_to(from_window, f)
357
+ _calculate_frame(f, from: from_window, relative_to: { x: :reset, y: :reset })
358
+ end
359
+
360
+ end
361
+ end