ruby_motion_query 0.5.8 → 0.6.0

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