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.
- checksums.yaml +4 -4
- data/README.md +24 -1478
- data/motion/ext.rb +1 -1
- data/motion/ruby_motion_query/actions.rb +68 -4
- data/motion/ruby_motion_query/animations.rb +3 -0
- data/motion/ruby_motion_query/debug.rb +1 -0
- data/motion/ruby_motion_query/device.rb +8 -0
- data/motion/ruby_motion_query/grid.rb +370 -0
- data/motion/ruby_motion_query/image.rb +2 -0
- data/motion/ruby_motion_query/inspector.rb +354 -0
- data/motion/ruby_motion_query/inspector_stylesheet.rb +106 -0
- data/motion/ruby_motion_query/position.rb +39 -20
- data/motion/ruby_motion_query/rect.rb +557 -0
- data/motion/ruby_motion_query/stylers/ui_button_styler.rb +16 -3
- data/motion/ruby_motion_query/stylers/ui_view_styler.rb +71 -43
- data/motion/ruby_motion_query/stylesheet.rb +11 -0
- data/motion/ruby_motion_query/subviews.rb +2 -0
- data/motion/ruby_motion_query/tags.rb +14 -0
- data/motion/ruby_motion_query/utils.rb +8 -5
- data/motion/ruby_motion_query/version.rb +1 -1
- data/templates/view/app/views/name.rb +2 -1
- metadata +8 -4
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
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
@@ -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)
|