ruby_motion_query 0.5.8 → 0.6.0

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.
@@ -0,0 +1,557 @@
1
+ module RubyMotionQuery
2
+
3
+ class RMQ
4
+ # @return RubyMotionQuery::Rect or array of RubyMotionQuery::Rect
5
+ #
6
+ # @example
7
+ # left = rmq(my_view).frame.left
8
+ def frame(params = nil)
9
+ if params
10
+ frame = params
11
+ self
12
+ else
13
+ if selected.length == 1
14
+ Rect.frame_for_view(selected.first)
15
+ else
16
+ selected.map{|s| Rect.frame_for_view(s)}
17
+ end
18
+ end
19
+ end
20
+
21
+ # Same as layout:
22
+ # rmq(my_view).layout(l: 10, t: 20, w: 100, h: 150)
23
+ #
24
+ # Always applied in this order, regardless of the hash order:
25
+ # grid
26
+ # l, t, w, h
27
+ # previous
28
+ # from_right, from_bottom
29
+ # right, bottom
30
+ # left and right applied together (will change width)
31
+ # top and bottom applied together (will change height)
32
+ # centered
33
+ # padding
34
+ #
35
+ # @example
36
+ # rmq(my_view).frame = :full
37
+ # rmq(my_view).frame = {l: 10, t: 20, w: 100, h: 150}
38
+ # rmq(my_view).frame = {t: 20, h: 150, l: 10, w: 100}
39
+ # rmq(my_view).frame = {l: 10, t: 20}
40
+ # rmq(my_view).frame = {h: 20}
41
+ # rmq(my_view).frame = {l: :prev, t: 20, w: 100, h: 150}
42
+ # rmq(my_view).frame = {l: 10, below_prev: 10, w: prev, h: 150}
43
+ # rmq(my_view).frame = {left: 10, top: 20, width: 100, height: 150}
44
+ # rmq(my_view).frame = {l: 10, t: 10, fr: 10, fb: 10}
45
+ # rmq(my_view).frame = {width: 50, height: 20, centered: :both}
46
+ # rmq(my_view).frame = "a1:b5"
47
+ # rmq(my_view, my_other_view).frame = {grid: "b2", w: 100, h: 200}
48
+ # rmq(my_view, my_other_view).frame = {g: "b2", w: 100, h: 200}
49
+ #
50
+ # @example with padding
51
+ # rmq(my_view).frame = {grid: "b2:d14", padding: 5}
52
+ # rmq(my_view).frame = {grid: "b2:d14", padding: {l: 5, t: 0, r: 5, b:0}}
53
+ def frame=(value)
54
+ selected.each do |view|
55
+ RubyMotionQuery::Rect.update_view_frame(view, value)
56
+ end
57
+ end
58
+
59
+ def bounds
60
+ if selected.length == 1
61
+ RubyMotionQuery::Rect.bounds_for_view(selected.first)
62
+ else
63
+ selected.map{|s| Rect.bounds_for_view(s)}
64
+ end
65
+ end
66
+
67
+ def bounds=(value)
68
+ selected.each do |view|
69
+ RubyMotionQuery::Rect.bounds_for_view(view).update(value, self.grid).apply_to_bounds
70
+ end
71
+ end
72
+
73
+ end
74
+
75
+
76
+ # RMQ Rect
77
+ #
78
+ # *******************---*******---*************************** value options
79
+ # * | | * -------------
80
+ # * | | * Integer
81
+ # * | | * signed Integer
82
+ # * top | * Float
83
+ # * | | * String
84
+ # * | | *
85
+ # * --- | * also
86
+ # * ***************|***** --- * -----------------------
87
+ # * * view | * | * :full
88
+ # * * | * | * :right_of_prev (:rop)
89
+ # * * bottom * | * :left_of_prev (:lop)
90
+ # * * | * | * :below_prev (:bp)
91
+ # *|--- left ---|* | * | * :above_prev (:ap)
92
+ # * * | * height * :grid (:g)
93
+ # * * | * | * :padding (:p)
94
+ # * * | * | * int or hash: l,t,b,r
95
+ # *|-------------------- right -+---|* | *
96
+ # * * | * | * abbreviations
97
+ # * * | * |--+--from_right----|* -----------------------
98
+ # * * --- * | * :l, :t, :w, :h
99
+ # * ***************---*** --- * :r, :b
100
+ # * | * :fr, fb
101
+ # * |------ width - + -| *
102
+ # * | * :centered options
103
+ # * | * -----------------------
104
+ # * from_bottom * :horizontal
105
+ # * | * :vertical
106
+ # * | * :both
107
+ # * --- *
108
+ # ***********************************************************
109
+ #
110
+ class Rect
111
+ attr_reader :view
112
+
113
+ class << self
114
+
115
+ def update_view_frame(view, params)
116
+ view.frame = object_to_cg_rect(params, view, view.frame, view.rmq.grid)
117
+ @_previous_view = RubyMotionQuery::RMQ.weak_ref(view)
118
+ end
119
+
120
+ def update_view_bounds(view, params)
121
+ view.frame = object_to_cg_rect(params, view, view.bounds, view.rmq.grid)
122
+ @_previous_view = RubyMotionQuery::RMQ.weak_ref(view)
123
+ end
124
+
125
+ # The previous view is literally the last view that was layed out, not
126
+ # the sibling view, the last view layed out in this screen, etc, just
127
+ # the last view.
128
+ # As styles and layouts are always applied in order, and there is only
129
+ # 1 UI thread, this should work just fine
130
+ def previous_view
131
+ # TODO, verify that there is actually a problem with circular reference here
132
+ # if not, we can just store the view and not create a weakref
133
+ RubyMotionQuery::RMQ.weak_ref_value(@_previous_view)
134
+ end
135
+
136
+ def frame_for_view(view)
137
+ new(view.frame, view)
138
+ end
139
+
140
+ def bounds_for_view(view)
141
+ new(view.bounds, view)
142
+ end
143
+
144
+ # Used internally, don't use this
145
+ #
146
+ # In singleton for performance # TODO, test if this is necessary
147
+ def object_to_cg_rect(o, view = nil, existing_rect = nil, grid = nil)
148
+ if o.is_a?(Hash)
149
+ a = rect_hash_to_rect_array(view, existing_rect, o, grid)
150
+ CGRectMake(a[0], a[1], a[2], a[3])
151
+ elsif o == :full
152
+ if view
153
+ view.superview.bounds
154
+ else
155
+ rmq.rootview.bounds
156
+ end
157
+ elsif o.is_a?(RubyMotionQuery::Rect)
158
+ o.to_cgrect
159
+ elsif grid && o.is_a?(String)
160
+ a = rect_hash_to_rect_array(view, existing_rect, {grid: o}, grid)
161
+ CGRectMake(a[0], a[1], a[2], a[3])
162
+ elsif o.is_a?(Array)
163
+ case o.length
164
+ when 4
165
+ CGRectMake(o[0], o[1], o[2], o[3])
166
+ when 2
167
+ o
168
+ end
169
+ else
170
+ o # CGRect, etc
171
+ end
172
+ end
173
+
174
+ # Used internally, don't use this
175
+ #
176
+ # In singleton for performance # TODO, test if this is necessary
177
+ def rect_hash_to_rect_array(view, existing_rect, params, grid = nil)
178
+ # TODO check if this is performant, it should be
179
+ if (sv = view.superview) && (vc = view.rmq_data.view_controller)
180
+ not_in_root_view = !(vc.view == sv)
181
+ end
182
+
183
+ # Grid
184
+ if grid
185
+ if params_g = params[:grid] || params[:g]
186
+ params.delete(:grid)
187
+ params.delete(:g)
188
+
189
+ grid_h = grid[params_g]
190
+ params = grid_h.merge(params)
191
+ end
192
+ end
193
+
194
+ params_l = params[:l] || params[:left] || params[:x]
195
+ params_t = params[:t] || params[:top] || params[:y]
196
+ params_w = params[:w] || params[:width]
197
+ params_h = params[:h] || params[:height]
198
+
199
+ below_prev = params[:below_prev] || params[:bp] || params[:below_previous]
200
+ above_prev = params[:above_prev] || params[:ap] || params[:above_previous]
201
+ right_of_prev = params[:right_of_prev] || params[:rop] || params[:right_of_previous]
202
+ left_of_prev = params[:left_of_prev] || params[:lop] || params[:left_of_previous]
203
+
204
+ l = params_l || existing_rect.origin.x
205
+ t = params_t || existing_rect.origin.y
206
+ w = params_w || existing_rect.size.width
207
+ h = params_h || existing_rect.size.height
208
+
209
+ r = params[:r] || params[:right]
210
+ b = params[:b] || params[:bottom]
211
+
212
+ fr = params[:from_right] || params[:fr]
213
+ fb = params[:from_bottom] || params[:fb]
214
+
215
+ centered = params[:centered]
216
+
217
+ # Previous
218
+ if prev_view = previous_view
219
+ if params_g && (prev_sv = prev_view.superview)
220
+
221
+ previous_root_view_point = vc.view.convertPoint(prev_view.origin, fromView: prev_sv)
222
+
223
+ if below_prev
224
+ t = params_t = previous_root_view_point.y + prev_view.frame.size.height + below_prev
225
+ elsif above_prev
226
+ t = params_t = previous_root_view_point.y - above_prev - h
227
+ end
228
+
229
+ if right_of_prev
230
+ l = params_l = previous_root_view_point.x + prev_view.frame.size.width + right_of_prev
231
+ elsif left_of_prev
232
+ l = params_l = previous_root_view_point.x - left_of_prev - w
233
+ end
234
+
235
+ else
236
+ if below_prev
237
+ t = prev_view.frame.origin.y + prev_view.frame.size.height + below_prev
238
+ elsif above_prev
239
+ t = prev_view.frame.origin.y - above_prev - h
240
+ end
241
+
242
+ if right_of_prev
243
+ l = prev_view.frame.origin.x + prev_view.frame.size.width + right_of_prev
244
+ elsif left_of_prev
245
+ l = prev_view.frame.origin.x - left_of_prev - w
246
+ end
247
+ end
248
+ end
249
+
250
+ if sv
251
+ if (fr || fb || centered) # Needs size
252
+
253
+ # Horrible horrible hack, TODO fix. This is here because
254
+ # the root_view's height isn't changed until after viewDidLoad when
255
+ # vc.edgesForExtendedLayout = UIRectEdgeNone.
256
+ # Not sure how often people use UIRectEdgeNone as I never do,
257
+ # perhaps an edge case that should be isolated in some wayo
258
+ # I hate to have to check and calc this every time
259
+ if vc && !not_in_root_view && (vc.edgesForExtendedLayout == UIRectEdgeNone)
260
+ sv_size = CGSizeMake(sv.size.width, rmq.device.screen_height - 64)
261
+ else
262
+ sv_size = sv.size
263
+ end
264
+ end
265
+ end
266
+
267
+ # From right, from_bottom
268
+ if (fr || fb) && sv
269
+ if fr
270
+ if params_l || left_of_prev || right_of_prev
271
+ w = sv_size.width - l - fr
272
+ else
273
+ l = sv_size.width - w - fr
274
+ end
275
+ end
276
+
277
+ if fb
278
+ if params_t || below_prev || above_prev
279
+ h = sv_size.height - t - fb
280
+ else
281
+ t = sv_size.height - h - fb
282
+ end
283
+ end
284
+ end
285
+
286
+ # Right and bottom
287
+ if r && !fr && !params_l
288
+ l = r - w
289
+ end
290
+ if b && !fb && !params_t
291
+ t = b - h
292
+ end
293
+
294
+ # Left and right applied together
295
+ if params_l && r && !params_w
296
+ w = r - l
297
+ end
298
+ # Top and bottom applied together
299
+ if params_t && b && !params_h
300
+ h = b - t
301
+ end
302
+
303
+ # Centered, :horizontal, :vertical, :both
304
+ if sv && centered
305
+ case centered
306
+ when :horizontal
307
+ l = (sv_size.width / 2) - (w / 2)
308
+ when :vertical
309
+ t = (sv_size.height / 2) - (h / 2)
310
+ when :both
311
+ l = (sv_size.width / 2) - (w / 2)
312
+ t = (sv_size.height / 2) - (h / 2)
313
+ end
314
+ end
315
+
316
+ if padding = params[:padding] || params[:p]
317
+ if padding.is_a?(Hash)
318
+ padding_l = padding[:l] || padding[:left] || 0
319
+ padding_t = padding[:t] || padding[:top] || 0
320
+ padding_r = padding[:r] || padding[:right] || 0
321
+ padding_b = padding[:b] || padding[:bottom] || 0
322
+ l += padding_l
323
+ t += padding_t
324
+ w -= (padding_l + padding_r)
325
+ h -= (padding_t + padding_b)
326
+ else
327
+ l += padding
328
+ t += padding
329
+ w -= (padding * 2)
330
+ h -= (padding * 2)
331
+ end
332
+ end
333
+
334
+ if params_g && not_in_root_view # Change to root_view_space
335
+ point = CGPointMake(l,t)
336
+ root_view_point = vc.view.convertPoint(point, toView: sv)
337
+ l = root_view_point.x
338
+ t = root_view_point.y
339
+ end
340
+
341
+ [l,t,w,h]
342
+ end
343
+
344
+ end # << self
345
+
346
+ def initialize(params, view = nil, grid = nil)
347
+ @left = @top = @width = @height = 0
348
+ @view = view
349
+ update params, grid
350
+ end
351
+
352
+ def update(params, grid = nil)
353
+ # Doing all of the updates to the Rect in singleton for performance.
354
+ # It would be better to be done inside an actual Rect instance, but that
355
+ # would require creating a lot of temporary objects.
356
+ # TODO performance and see if there is any real loss bringing
357
+ # object_to_cg_rect into Rect instance
358
+ #
359
+ # If we did it that way, then we'd create a new instance, then appy the
360
+ # rect instance to the frame or bounds, like so:
361
+ # Rect.new(params, view, grid).apply_to_frame
362
+ cg_rect = RubyMotionQuery::Rect.object_to_cg_rect(params, @view, self.to_cgrect, grid)
363
+
364
+ @left = cg_rect.origin.x
365
+ @top = cg_rect.origin.y
366
+ @width = cg_rect.size.width
367
+ @height = cg_rect.size.height
368
+ end
369
+
370
+ def apply_to_frame
371
+ @view.frame = to_cgrect if @view
372
+ end
373
+ def apply_to_bounds
374
+ @view.bounds = to_cgrect if @view
375
+ end
376
+
377
+ def left
378
+ @left
379
+ end
380
+ alias :l :left
381
+ alias :x :left
382
+
383
+ def right
384
+ @left + @width
385
+ end
386
+ alias :r :right
387
+
388
+ def from_right
389
+ if @view && (sv = @view.superview)
390
+ sv.size.width - right
391
+ end
392
+ end
393
+ alias :fr :from_right
394
+
395
+ def top
396
+ @top
397
+ end
398
+ alias :t :top
399
+ alias :y :top
400
+
401
+ def bottom
402
+ @top + @height
403
+ end
404
+ alias :b :bottom
405
+
406
+ def from_bottom
407
+ if @view && (sv = @view.superview)
408
+ sv.size.height - bottom
409
+ end
410
+ end
411
+ alias :fb :from_bottom
412
+
413
+ def width
414
+ @width
415
+ end
416
+ alias :w :width
417
+
418
+ def height
419
+ @height
420
+ end
421
+ alias :h :height
422
+
423
+ def z_order
424
+ if @view
425
+ @view.superview.subviews.to_a.index(@view) # is there a better way??
426
+ end
427
+ end
428
+
429
+ def origin
430
+ to_cgpoint
431
+ end
432
+
433
+ def size
434
+ to_cgsize
435
+ end
436
+
437
+ def point_in_root_view
438
+ if @view && (sv = @view.superview) && (vc = view.rmq.view_controller)
439
+ vc.view.convertPoint(CGPointMake(@left,@top), fromView: sv)
440
+ end
441
+ end
442
+
443
+ def rect_in_root_view
444
+ if @view && (sv = @view.superview) && (vc = view.rmq.view_controller)
445
+ point = vc.view.convertPoint(CGPointMake(@left,@top), fromView: sv)
446
+ RubyMotionQuery::Rect.new({l: point.x, t: point.y, w: @view.size.width, h: @view.size.height}, @view)
447
+ end
448
+ end
449
+
450
+ def left_in_root_view
451
+ if point = point_in_root_view
452
+ point.x
453
+ end
454
+ end
455
+
456
+ def top_in_root_view
457
+ if point = point_in_root_view
458
+ point.y
459
+ end
460
+ end
461
+
462
+ # TODO add center
463
+
464
+ def z_position
465
+ if @view
466
+ @view.layer.zPosition
467
+ end
468
+ end
469
+
470
+ def to_cgpoint
471
+ CGPointMake(@left, @top)
472
+ end
473
+
474
+ def to_cgsize
475
+ CGSizeMake(@width, @height)
476
+ end
477
+
478
+ def to_cgrect
479
+ CGRectMake(@left, @top, @width, @height)
480
+ end
481
+ def to_a
482
+ [@left, @top, @width, @height]
483
+ end
484
+ def to_h
485
+ {left: @left, top: @top, width: @width, height: @height}
486
+ end
487
+
488
+ def inspect
489
+ format = '#0.#'
490
+ s = "Rect {l: #{RMQ.format.numeric(left, format)}"
491
+ s << ", t: #{RMQ.format.numeric(top, format)}"
492
+ s << ", w: #{RMQ.format.numeric(width, format)}"
493
+ s << ", h: #{RMQ.format.numeric(height, format)}}"
494
+ s
495
+ end
496
+
497
+ def log
498
+ def i_f_to_s(int_or_float)
499
+ if int_or_float % 1 == 0
500
+ int_or_float.to_i.to_s
501
+ else
502
+ int_or_float.to_s
503
+ end
504
+ end
505
+
506
+ l = i_f_to_s(left.round(2)).ljust(5)
507
+ t = i_f_to_s(top.round(2)).rjust(5)
508
+ w = i_f_to_s(width.round(2)).ljust(5)
509
+ h = i_f_to_s(height.round(2)).ljust(5)
510
+ b = i_f_to_s(bottom.round(2)).rjust(5)
511
+ r = i_f_to_s(right.round(2)).ljust(5)
512
+ fr = i_f_to_s(from_right.round(2)).ljust(5)
513
+ fb = i_f_to_s(from_bottom.round(2)).rjust(5)
514
+
515
+ ww = i_f_to_s(rmq.app.window.size.width.round(2))
516
+ wh = i_f_to_s(rmq.app.window.size.height.round(2))
517
+
518
+ if @view && (sv = @view.superview)
519
+ sw = i_f_to_s(sv.size.width.round(2))
520
+ sh = i_f_to_s(sv.size.height.round(2))
521
+ end
522
+
523
+ out = %(
524
+ *****************---*******---**************************
525
+ * | | * window
526
+ * #{ t} top | * {w: #{ww}, h: #{wh}}
527
+ * | | *
528
+ * --- | * superview
529
+ * ***************|***** --- * {w: #{sw}, h: #{sh}}
530
+ * * | * | *
531
+ * * | * | *
532
+ * * #{ b} bottom * | * view
533
+ * #{ l} * | * | * {l: #{l.strip}, t: #{t.strip},
534
+ *|-- left --|* | * | * w: #{w.strip}, h: #{h.strip}}
535
+ * * | * height #{ h} *
536
+ * * | * | * z_order: #{z_order}
537
+ * * #{ r} | * | * z_position: #{z_position}
538
+ *|------------------ right -+---|* | *
539
+ * * | * | #{fr} * Location in root view
540
+ * * | * |--+--from_right---|* {l: #{i_f_to_s(left_in_root_view)}, t: #{i_f_to_s(top_in_root_view)},
541
+ * * --- * | * w: #{w.strip}, h: #{h.strip}}
542
+ * ***************---*** --- *
543
+ * | *
544
+ * |------ width - + --| *
545
+ * #{ w} | *
546
+ * | *
547
+ * | *
548
+ * #{fb} from_bottom *
549
+ * | *
550
+ * --- *
551
+ ********************************************************
552
+ )
553
+ puts out
554
+ end
555
+
556
+ end
557
+ end
@@ -45,19 +45,32 @@ module RubyMotionQuery
45
45
  @view.setBackgroundImage value, forState: UIControlStateHighlighted
46
46
  end
47
47
 
48
- # Accepts UIEdgeInsetMake OR and array of values to be the inset.
48
+ # Accepts UIEdgeInsetsMake OR and array of values to be the inset.
49
49
  # st.title_edge_insets = UIEdgeInsetsMake(0, 10.0, 0, 0)
50
50
  # OR
51
51
  # st.title_edge_insets = [0, 10.0, 0, 0]
52
52
  def title_edge_insets=(value)
53
- inset = UIEdgeInsetsMake(value[0], value[1], value[2], value[3]) if value.is_a? Array
54
- @view.setTitleEdgeInsets(inset)
53
+ value = UIEdgeInsetsMake(value[0], value[1], value[2], value[3]) if value.is_a? Array
54
+ @view.setTitleEdgeInsets(value)
55
55
  end
56
56
 
57
57
  def title_edge_insets
58
58
  @view.titleEdgeInsets
59
59
  end
60
60
 
61
+ # Accepts UIEdgeInsetsMake OR and array of values to be the inset.
62
+ # st.image_edge_insets = UIEdgeInsetsMake(0, 10.0, 0, 0)
63
+ # OR
64
+ # st.image_edge_insets = [0, 10.0, 0, 0]
65
+ def image_edge_insets=(value)
66
+ value = UIEdgeInsetsMake(value[0], value[1], value[2], value[3]) if value.is_a? Array
67
+ @view.setImageEdgeInsets(value)
68
+ end
69
+
70
+ def image_edge_insets
71
+ @view.imageEdgeInsets
72
+ end
73
+
61
74
  end
62
75
  end
63
76
  end