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.
data/motion/ext.rb CHANGED
@@ -26,7 +26,7 @@ class UIView
26
26
  def rmq_appended
27
27
  end
28
28
 
29
- # Technically my_view.rmq is the same as rmq(my_view), so it may seem enticing to use
29
+ # Technically my_view.rmq is the same as rmq(my_view), so it may seem enticing to use,
30
30
  # but the really nice thing about rmq is its consistent API, and doing this
31
31
  # for one view: my_view.rmq and this for two views: rmq(my_view, my_other_view) sucks
32
32
  def rmq(*working_selectors)
@@ -11,13 +11,77 @@ module RubyMotionQuery
11
11
  self
12
12
  end
13
13
 
14
+ # Get or set the most common data for a particuliar view(s) in a
15
+ # performant way (more performant than attr)
16
+ # For example, text for UILabel, image for UIImageView
17
+ #
18
+ # @return [RMQ]
19
+ def data(new_data = nil)
20
+ if new_data
21
+ selected.each do |view|
22
+ case view
23
+ when UILabel then view.setText new_data # set is faster than =
24
+ when UIButton then view.setTitle(new_data, forState: UIControlStateNormal)
25
+ when UIImageView then view.image = new_data
26
+ #when UITableView then
27
+ #when UISwitch then
28
+ #when UIDatePicker then
29
+ #when UISegmentedControl then
30
+ #when UIRefreshControl then
31
+ #when UIPageControl then
32
+ #when UISlider then
33
+ #when UIStepper then
34
+ #when UITabBar then
35
+ #when UITableViewCell then
36
+ when UITextView then view.setText new_data
37
+ when UITextField then view.setText new_data
38
+ #when UINavigationBar then
39
+ #when UIScrollView then
40
+
41
+ # TODO, finish
42
+ end
43
+ end
44
+
45
+ self
46
+ else
47
+ out = selected.map do |view|
48
+ case view
49
+ when UILabel then view.text
50
+ when UIButton then view.titleForState(UIControlStateNormal)
51
+ when UIImageView then view.image
52
+ #when UITableView then
53
+ #when UISwitch then
54
+ #when UIDatePicker then
55
+ #when UISegmentedControl then
56
+ #when UIRefreshControl then
57
+ #when UIPageControl then
58
+ #when UISlider then
59
+ #when UIStepper then
60
+ #when UITabBar then
61
+ #when UITableViewCell then
62
+ when UITextView then view.text
63
+ when UITextField then view.text
64
+ #when UINavigationBar then
65
+ #when UIScrollView then
66
+
67
+ # TODO, finish
68
+ end
69
+ end
70
+
71
+ out = out.first if out.length == 1
72
+ out
73
+ end
74
+ end
75
+
14
76
  # @return [RMQ]
15
77
  def send(method, args = nil)
16
78
  selected.each do |view|
17
- if args
18
- view.__send__ method, args
19
- else
20
- view.__send__ method
79
+ if view.respond_to?(method)
80
+ if args
81
+ view.__send__ method, args
82
+ else
83
+ view.__send__ method
84
+ end
21
85
  end
22
86
  end
23
87
  self
@@ -18,11 +18,14 @@ module RubyMotionQuery
18
18
  view_rmq = self_rmq.wrap(view)
19
19
 
20
20
  animations_lambda = -> do
21
+ # TODO, check arity and allow no params
21
22
  animations_callback.call(view_rmq)
22
23
  end
23
24
 
24
25
  after_lambda = if after_callback
25
26
  ->(did_finish) {
27
+ # TODO, check arity and allow just view_rmq or no params. Also
28
+ # this is backwards, should be view_rmq, did_finish
26
29
  after_callback.call(did_finish, view_rmq)
27
30
  }
28
31
  else
@@ -27,6 +27,7 @@ module RubyMotionQuery
27
27
  # /usr/bin/malloc_history 47706 0x937e5c0 | grep "rb_scope__.+?__"
28
28
  class Debug
29
29
  class << self
30
+
30
31
  # Warning, this is very slow
31
32
  def log_detailed(label, params = {})
32
33
  return unless RMQ.app.development? || RMQ.app.test?
@@ -28,6 +28,14 @@ module RubyMotionQuery
28
28
  @_height ||= Device.screen.bounds.size.height
29
29
  end
30
30
 
31
+ def screen_width
32
+ portrait? ? screen.bounds.size.width : screen.bounds.size.height
33
+ end
34
+
35
+ def screen_height
36
+ portrait? ? screen.bounds.size.height : screen.bounds.size.width
37
+ end
38
+
31
39
  def ipad?
32
40
  @_ipad = (UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad) if @_ipad.nil?
33
41
  @_ipad
@@ -0,0 +1,370 @@
1
+ module RubyMotionQuery
2
+ class App
3
+ class << self
4
+ def grid
5
+ @_app_grid ||= Grid.new(Grid::DEFAULT)
6
+ end
7
+ def grid=(value)
8
+ @_app_grid = value
9
+ end
10
+ end
11
+ end
12
+
13
+ class RMQ
14
+ # Current grid, wether the current controller's or the App's gri
15
+ def grid
16
+ if stylesheet && (g = stylesheet.grid)
17
+ g
18
+ else
19
+ App.grid
20
+ end
21
+ end
22
+ end
23
+
24
+ # A grid for layout.
25
+ # There is an app grid at: rmq.app.grid
26
+ # You can also have a grid per stylesheet. If none exists, the app
27
+ # grid will be used. rmq.stylesheet.grid (this will return app's if nil).
28
+ # If you want to create a grid for your stylesheet, you can just dup the app one
29
+ # like so (inside the stylesheet): self.grid = rmq.app.grid.dup
30
+ # Then you can mod it: self.grid.num_columns = 6
31
+ #
32
+ # @example If you want your view to be from b2 to d3, you can do any of the following:
33
+ #
34
+ # # a b c d e
35
+ # # ....................
36
+ # # 1 . a1 b1 c1 d1 e1
37
+ # # .....------------...
38
+ # # 2 . a2 |b2 c2 d2| e2
39
+ # # .....| |...
40
+ # # 3 . a3 |b3 c3 d3| e3
41
+ # # .....------------...
42
+ # # 4 . a4 b4 c4 d4 e4
43
+ # # ....................
44
+ # # 5 . a5 b5 c5 d5 e5
45
+ # # ....................
46
+ #
47
+ # st.frame = "b2:d3"
48
+ # st.origin = "b2:d3"
49
+ # st.frame = {grid: "b2", w: 100, h: 200}
50
+ # my_view.frame = some_grid['b2:d3']
51
+ # my_view.origin = some_grid['b2:d3']
52
+ # rmq.append(UIView).layout('b2:d3')
53
+ #
54
+ # @example Create a new grid inside a stylesheet by duping the app's grid
55
+ # self.grid = rmq.app.grid.dup
56
+ # # Then change the number of num_columns
57
+ # self.grid.num_columns = 6
58
+ #
59
+ # @example Creating a new grid
60
+ # Grid.new({
61
+ # num_columns: 10,
62
+ # num_rows: 13,
63
+ # column_gutter: 10,
64
+ # row_gutter: 10,
65
+ # content_left_margin: 5,
66
+ # content_right_margin: 5,
67
+ # content_top_margin: 70,
68
+ # content_bottom_margin: 5
69
+ # })
70
+ #
71
+ # @example Align all your buttons left on the c column
72
+ # rmq(UIButon).layout('c')
73
+ #
74
+ # @example Log your grid
75
+ # rmq.app.grid.log
76
+ #
77
+ # # {:num_columns=>10, :num_rows=>13, :column_gutter=>10, :content_left_margin=>5,
78
+ # # :content_right_margin=>5, :content_top_margin=>5, :content_bottom_margin=>5,
79
+ # # :row_gutter=>10, :status_bar_bottom=>20, :nav_bar_bottom=>64}
80
+ #
81
+ # # a b c d e f g h i j
82
+ # # 0 . . . . . . . . . .
83
+ # # 1 . . . . . . . . . .
84
+ # # 2 . . . . . . . . . .
85
+ # # 3 . . . . . . . . . .
86
+ # # 4 . . . . . . . . . .
87
+ # # 5 . . . . . . . . . .
88
+ # # 6 . . . . . . . . . .
89
+ # # 7 . . . . . . . . . .
90
+ # # 8 . . . . . . . . . .
91
+ # # 9 . . . . . . . . . .
92
+ # # 10 . . . . . . . . . .
93
+ # # 11 . . . . . . . . . .
94
+ # # 12 . . . . . . . . . .
95
+ #
96
+ class Grid
97
+ attr_reader :num_columns, :column_gutter, :content_left_margin, :content_right_margin,
98
+ :content_bottom_margin, :content_top_margin, :num_rows, :row_gutter,
99
+ :status_bar_bottom, :nav_bar_bottom
100
+
101
+ MAX_COLUMNS = 26
102
+ MAX_ROWS = 30
103
+ STATUS_BAR_BOTTOM = 20
104
+ NAV_BAR_BOTTOM = 64
105
+
106
+ DEFAULT = {
107
+ num_columns: 10,
108
+ column_gutter: 10,
109
+ num_rows: 16,
110
+ row_gutter: 10,
111
+ content_left_margin: 10,
112
+ content_right_margin: 10,
113
+ content_top_margin: 70,
114
+ content_bottom_margin: 10
115
+ }
116
+
117
+ def initialize(params)
118
+ @grid_hash = {}
119
+
120
+ self.num_columns = params[:num_columns]
121
+ self.num_rows = params[:num_rows]
122
+
123
+ @column_gutter = params[:column_gutter]
124
+ @content_left_margin = params[:content_left_margin]
125
+ @content_right_margin = params[:content_right_margin]
126
+ @content_top_margin = params[:content_top_margin]
127
+ @content_bottom_margin = params[:content_bottom_margin]
128
+ @row_gutter = params[:row_gutter]
129
+ @status_bar_bottom = params[:status_bar_bottom] || STATUS_BAR_BOTTOM
130
+ @nav_bar_bottom = params[:nav_bar_bottom] || NAV_BAR_BOTTOM
131
+ end
132
+
133
+ def num_columns=(value)
134
+ value = MAX_COLUMNS if value > MAX_COLUMNS
135
+ @num_columns = value
136
+ clear_cache
137
+ end
138
+ def num_rows=(value)
139
+ value = MAX_ROWS if value > MAX_ROWS
140
+ @num_rows = value
141
+ clear_cache
142
+ end
143
+ def column_gutter=(value)
144
+ @column_gutter = value
145
+ clear_cache
146
+ end
147
+ def content_left_margin=(value)
148
+ @content_left_margin = value
149
+ clear_cache
150
+ end
151
+ def content_right_margin=(value)
152
+ @content_right_margin = value
153
+ clear_cache
154
+ end
155
+ def content_top_margin=(value)
156
+ @content_top_margin = value
157
+ clear_cache
158
+ end
159
+ def content_bottom_margin=(value)
160
+ @content_bottom_margin = value
161
+ clear_cache
162
+ end
163
+ def row_gutter=(value)
164
+ @row_gutter = value
165
+ clear_cache
166
+ end
167
+ def status_bar_bottom=(value)
168
+ @status_bar_bottom = value
169
+ clear_cache
170
+ end
171
+ def nav_bar_bottom=(value)
172
+ @nav_bar_bottom = value
173
+ clear_cache
174
+ end
175
+
176
+ # @example
177
+ # my_grid['a1']
178
+ # my_grid['a']
179
+ # my_grid['1']
180
+ # my_grid['a1:f12']
181
+ # my_grid['a0:a0'] # Entire a0 block
182
+ # my_grid['a:d'] # Just width
183
+ # my_grid['1:4'] # Just height
184
+ # my_grid['a:4'] # Just width, and just height on the other end (interesting eh)
185
+ #
186
+ # @return hash with any combination of l:, t:, w:, or :h. Or nil if invalid
187
+ def [](coord)
188
+ @grid_hash[coord] ||= begin
189
+ if coord.is_a?(Array)
190
+
191
+ l = column_lefts[coord[0]]
192
+ t = row_tops[coord[1]]
193
+ case coord.length
194
+ when 2
195
+ RubyMotionQuery::Rect.new([l, t, column_width, row_height])
196
+ when 4
197
+ RubyMotionQuery::Rect.new([l, t, coord[2], coord[3]])
198
+ else
199
+ nil
200
+ end
201
+
202
+ else
203
+ return nil unless coord
204
+
205
+ # TODO this needs refactoring once the full tests are done
206
+ coord.gsub!(/\s/, '')
207
+ is_end_coord = coord.start_with?(':')
208
+ parts = coord.split(':')
209
+ parts.reject!{|o| o == ''}
210
+
211
+ case parts.length
212
+ when 0
213
+ nil
214
+ when 1
215
+ lefts = column_lefts
216
+ tops = row_tops
217
+
218
+ p1 = parts.first
219
+ digits = p1.gsub(/\D/, '')
220
+ if digits == ''
221
+ digits = nil
222
+ else
223
+ top_i = digits.to_i
224
+ top_i = (tops.length - 1) if top_i >= tops.length
225
+ end
226
+
227
+ letter = p1.gsub(/\d/, '')
228
+ if letter == ''
229
+ letter = nil
230
+ else
231
+ letter.downcase!
232
+ left_i = (letter.ord - 97)
233
+ left_i = (lefts.length - 1) if left_i >= lefts.length
234
+ end
235
+
236
+ if digits && letter
237
+ if lefts.length > left_i && tops.length > top_i
238
+ if is_end_coord
239
+ {r: lefts[left_i] + column_width, b: tops[top_i] + row_height}
240
+ else
241
+ {l: lefts[left_i], t: tops[top_i]}
242
+ end
243
+ else
244
+ nil
245
+ end
246
+ elsif digits
247
+ if is_end_coord
248
+ {b: tops[top_i] + row_height}
249
+ else
250
+ {t: tops[top_i]}
251
+ end
252
+ elsif letter
253
+ if is_end_coord
254
+ {r: lefts[left_i] + column_width}
255
+ else
256
+ {l: lefts[left_i]}
257
+ end
258
+ else
259
+ nil
260
+ end
261
+ when 2
262
+ self[parts.first].merge(self[":#{parts.last}"])
263
+ end
264
+ end.freeze
265
+ end
266
+ end
267
+
268
+ # TODO, do this when orientation changes
269
+ def clear_cache
270
+ @grid_hash = {}
271
+ @_usable_width = nil
272
+ @_column_width = nil
273
+ @_usable_height = nil
274
+ @_row_height = nil
275
+ end
276
+
277
+ def to_h
278
+ {
279
+ num_columns: @num_columns,
280
+ num_rows: @num_rows,
281
+ column_gutter: @column_gutter,
282
+ content_left_margin: @content_left_margin,
283
+ content_right_margin: @content_right_margin,
284
+ content_top_margin: @content_top_margin,
285
+ content_bottom_margin: @content_bottom_margin,
286
+ row_gutter: @row_gutter,
287
+ status_bar_bottom: @status_bar_bottom,
288
+ nav_bar_bottom: @nav_bar_bottom
289
+ }
290
+ end
291
+
292
+
293
+ def to_s
294
+ left_m = ""
295
+ out = left_m.dup
296
+ out << ' '
297
+
298
+ 0.upto(@num_columns - 1).each do |c|
299
+ out << "#{(c+97).chr} "
300
+ end
301
+
302
+ 0.upto(@num_rows - 1).each do |r|
303
+ out << "\n"
304
+ out << left_m
305
+ out << r.to_s.rjust(4)
306
+
307
+ 0.upto(@num_columns - 1).each do |c|
308
+ out << " ."
309
+ end
310
+ end
311
+
312
+ out
313
+ end
314
+ def log
315
+ puts self.inspect
316
+ puts self.to_s
317
+ end
318
+ def inspect
319
+ to_h.inspect
320
+ end
321
+
322
+ def dup
323
+ Grid.new(self.to_h)
324
+ end
325
+
326
+ def usable_width
327
+ @_usable_width ||= (RMQ.device.screen_width - (@column_gutter * (@num_columns - 1)) - @content_left_margin - @content_right_margin)
328
+ end
329
+
330
+ def column_width
331
+ @_column_width ||= usable_width / @num_columns
332
+ end
333
+
334
+ def column_lefts
335
+ out = []
336
+ if @num_columns
337
+ 0.upto(@num_columns - 1) do |i|
338
+ out << (@content_left_margin + (i * @column_gutter) + (i * column_width))
339
+ end
340
+ end
341
+ out
342
+ end
343
+
344
+ def column_rights
345
+ column_lefts.map{|x| x + column_width}
346
+ end
347
+
348
+ def usable_height
349
+ @_usable_height ||= (RMQ.device.screen_height - (@row_gutter * (@num_rows - 1)) - @content_top_margin - @content_bottom_margin)
350
+ end
351
+
352
+ def row_height
353
+ @_row_height ||= usable_height / @num_rows
354
+ end
355
+
356
+ def row_tops
357
+ out = []
358
+ if @num_rows
359
+ 0.upto(@num_rows - 1) do |i|
360
+ out << (@content_top_margin + (i * @row_gutter) + (i * row_height))
361
+ end
362
+ end
363
+ out
364
+ end
365
+ def row_bottoms
366
+ row_tops.map{|y| y + row_height}
367
+ end
368
+
369
+ end
370
+ end
@@ -67,6 +67,8 @@ module RubyMotionQuery
67
67
  #
68
68
  # @return [UIImage]
69
69
  def from_view(view, use_content_size = false)
70
+ #return nil if (view.origin.x == 0 || view.origin.y == 0)
71
+
70
72
  scale = UIScreen.mainScreen.scale
71
73
  if use_content_size
72
74
  UIGraphicsBeginImageContextWithOptions(view.contentSize, false, scale)