ruby_motion_query 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/LICENSE +21 -0
- data/README.md +964 -0
- data/lib/ruby_motion_query.rb +8 -0
- data/motion/ext.rb +34 -0
- data/motion/ruby_motion_query/actions.rb +44 -0
- data/motion/ruby_motion_query/animations.rb +125 -0
- data/motion/ruby_motion_query/app.rb +71 -0
- data/motion/ruby_motion_query/base.rb +161 -0
- data/motion/ruby_motion_query/color.rb +80 -0
- data/motion/ruby_motion_query/data.rb +32 -0
- data/motion/ruby_motion_query/device.rb +73 -0
- data/motion/ruby_motion_query/enumerablish.rb +74 -0
- data/motion/ruby_motion_query/event.rb +125 -0
- data/motion/ruby_motion_query/events.rb +65 -0
- data/motion/ruby_motion_query/factory.rb +32 -0
- data/motion/ruby_motion_query/font.rb +66 -0
- data/motion/ruby_motion_query/format.rb +54 -0
- data/motion/ruby_motion_query/image.rb +79 -0
- data/motion/ruby_motion_query/position.rb +45 -0
- data/motion/ruby_motion_query/selectors.rb +56 -0
- data/motion/ruby_motion_query/stylers/ui_button_styler.rb +32 -0
- data/motion/ruby_motion_query/stylers/ui_control_styler.rb +8 -0
- data/motion/ruby_motion_query/stylers/ui_date_picker_styler.rb +8 -0
- data/motion/ruby_motion_query/stylers/ui_image_view_styler.rb +14 -0
- data/motion/ruby_motion_query/stylers/ui_label_styler.rb +36 -0
- data/motion/ruby_motion_query/stylers/ui_navigation_bar_styler.rb +8 -0
- data/motion/ruby_motion_query/stylers/ui_page_control_styler.rb +8 -0
- data/motion/ruby_motion_query/stylers/ui_refresh_control_styler.rb +8 -0
- data/motion/ruby_motion_query/stylers/ui_scroll_view_styler.rb +10 -0
- data/motion/ruby_motion_query/stylers/ui_segmented_control_styler.rb +8 -0
- data/motion/ruby_motion_query/stylers/ui_slider_styler.rb +8 -0
- data/motion/ruby_motion_query/stylers/ui_stepper_styler.rb +8 -0
- data/motion/ruby_motion_query/stylers/ui_switch_styler.rb +10 -0
- data/motion/ruby_motion_query/stylers/ui_tab_bar_styler.rb +8 -0
- data/motion/ruby_motion_query/stylers/ui_table_view_cell_styler.rb +8 -0
- data/motion/ruby_motion_query/stylers/ui_table_view_styler.rb +8 -0
- data/motion/ruby_motion_query/stylers/ui_text_field_styler.rb +8 -0
- data/motion/ruby_motion_query/stylers/ui_text_view_styler.rb +8 -0
- data/motion/ruby_motion_query/stylers/ui_view_styler.rb +243 -0
- data/motion/ruby_motion_query/stylesheet.rb +185 -0
- data/motion/ruby_motion_query/subviews.rb +52 -0
- data/motion/ruby_motion_query/tags.rb +14 -0
- data/motion/ruby_motion_query/traverse.rb +183 -0
- data/motion/ruby_motion_query/utils.rb +53 -0
- metadata +89 -0
data/README.md
ADDED
@@ -0,0 +1,964 @@
|
|
1
|
+
![RQM logo](http://ir_wp.s3.amazonaws.com/wp-content/uploads/sites/9/2013/07/rmq_logo.png)
|
2
|
+
|
3
|
+
RubyMotionQuery - RMQ - A small, light, muggle, nonpolluting, jQuery-like library for [RubyMotion](http://rubymotion.com).
|
4
|
+
|
5
|
+
#### The [RMQ Introductory Guide and other info][1] is a great place to start.
|
6
|
+
|
7
|
+
|
8
|
+
----------
|
9
|
+
|
10
|
+
|
11
|
+
#### Some of the very cool features:
|
12
|
+
- **selecting** (*querying*) views
|
13
|
+
- **traversal** through view hierarchy (moving around the tree)
|
14
|
+
- tagging
|
15
|
+
- **events and gestures**
|
16
|
+
- animations
|
17
|
+
- **stylers and stylesheets**
|
18
|
+
- colors
|
19
|
+
- fonts
|
20
|
+
- image utilities
|
21
|
+
- app
|
22
|
+
- device
|
23
|
+
|
24
|
+
#### Other wrapper libraries
|
25
|
+
There are a lot of great wrappers out there such as Teacup and Sugarcube. I've used these and I enjoy them. However, many of the wrappers heavily pollute the standard classes, which is great if you like that sort of thing. RMQ is designed to have minimal pollution, to be very simple and high performance (it will be when it's done). RMQ shouldn't conflict with anything.
|
26
|
+
|
27
|
+
RMQ **doesn't require any** other wrapper or gem.
|
28
|
+
|
29
|
+
> If you preferred jQuery over Prototype, you'll love RMQ.
|
30
|
+
|
31
|
+
Some of the code in RMQ came from BubbleWrap and Sugarcube. Not too much but some did. I thank you BubbleWrap and Sugarcube teams for your work.
|
32
|
+
|
33
|
+
----------
|
34
|
+
|
35
|
+
### * Alpha * Warning *
|
36
|
+
|
37
|
+
This is in the **alpha** stage right now, it works well and we've used some of RMQ in production apps, but it **needs** more **testing**, **performance** optimizations, **documentation**, and the **TODOs** to be finished.
|
38
|
+
|
39
|
+
RDocs are not done. I'd appreciate help on these. This readme isn't up to the quality I'd like either. I figure it's better to get it out to the community sooner rather than wait for it to be more finished. My ideal is jQuery quality docs in addition to basic RDoc reference.
|
40
|
+
|
41
|
+
Nothing is optimized for speed yet. Well, that isn't true, somethings are.
|
42
|
+
|
43
|
+
Memory leaks may exist.
|
44
|
+
|
45
|
+
Tested only on iOS, not OS X (nor is there any OS X specific code)
|
46
|
+
|
47
|
+
----------
|
48
|
+
|
49
|
+
## Installation
|
50
|
+
|
51
|
+
RMQ **requires no other gems**. If you use stuff like **scale** and certain animations it will require some frameworks (like QuartzCore or CoreGraphics)
|
52
|
+
|
53
|
+
- `gem install ruby_motion_query`
|
54
|
+
- `require 'ruby_motion_query'`
|
55
|
+
|
56
|
+
or add it to your `Gemfile`:
|
57
|
+
|
58
|
+
- `gem 'ruby_motion_query'`
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
## Usage
|
63
|
+
|
64
|
+
### Example App
|
65
|
+
*Clone this repo and run the example app to see an example of use.*
|
66
|
+
|
67
|
+
git clone git@github.com:infinitered/rmq.git
|
68
|
+
cd rmq
|
69
|
+
rake retina=4
|
70
|
+
|
71
|
+
The example app works in any orientation, on both iPhone and iPad. Notice how the benchmark popup is done with RMQ, then think about how you'd do that without it.
|
72
|
+
|
73
|
+
### What's an rmq instance?
|
74
|
+
|
75
|
+
- an rmq instance is an array-like object containing UIViews
|
76
|
+
- rmq() never returns nil. If nothing is selected, it's an empty [ ] array-like
|
77
|
+
object
|
78
|
+
- an rmq object always (almost always) returns either itself or a new
|
79
|
+
rmq object. This is how chaining works. You do not need to worry if
|
80
|
+
an rmq is blank or not, everything always works without throwing a
|
81
|
+
nil exception
|
82
|
+
- jQuery uses the DOM, what is rmq using for the "DOM"? It uses the
|
83
|
+
controller it was called in. The "DOM" is the controller's subview
|
84
|
+
tree. If you call rmq inside a view, it will attach to the
|
85
|
+
controller that the view is currently in or to the current screen's
|
86
|
+
controller
|
87
|
+
|
88
|
+
### Basic syntax
|
89
|
+
|
90
|
+
The main command is `rmq` and you use it everywhere. You can rename this by aliasing the methods in `ext.rb`.
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
# Like jQuery you wrap your objects or selectors in a rmq(), here are some examples
|
94
|
+
rmq(my_view).show
|
95
|
+
rmq(UILabel).hide
|
96
|
+
|
97
|
+
# You can use zero or more selectors, all these are valid
|
98
|
+
rmq(my_view, UILabel).hide
|
99
|
+
rmq(:a_tag, :a_style_name, UIImageView).hide
|
100
|
+
rmq(hidden: true).show
|
101
|
+
|
102
|
+
# If you use a set of selectors, they are an "or", to do an "and" use .and
|
103
|
+
rmq(:UIImageView).and(hidden: true).show
|
104
|
+
```
|
105
|
+
|
106
|
+
**rmq by itself is the rmq instance of the current UIViewController if you're inside a UIViewController**.
|
107
|
+
|
108
|
+
If you're inside a UIView you've created, `rmq.closest(UIControl)` is the same as `rmq(self).closest(UIControl)`.
|
109
|
+
|
110
|
+
#### rmq is always an array-like object (enumerablish), never nil, etc:
|
111
|
+
|
112
|
+
Because of this, you **never have to check** if your selectors return anything before calling actions or other methods on your rmq object.
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
# This will hide any UILabel in the controller, if any exist. If not, nothing happens
|
116
|
+
rmq(UILabel).hide
|
117
|
+
|
118
|
+
# Because of this, you can create chains without worry of exceptions
|
119
|
+
rmq(:this_tag_does_not_exist).show.apply_style(:my_style_name).on(:touch_down){puts 'score!'}
|
120
|
+
```
|
121
|
+
|
122
|
+
#### Almost all methods of an rmq object return either itself or another rmq object, so you can chain:
|
123
|
+
```ruby
|
124
|
+
rmq.append(UILabel, :label_style).on(:tap){|sender,event| sender.hide}
|
125
|
+
|
126
|
+
# or
|
127
|
+
|
128
|
+
rmq.closest(AddEntry).find(:delete_button).hide
|
129
|
+
rmq(AddEntry).find(UILabel).blink
|
130
|
+
|
131
|
+
```
|
132
|
+
|
133
|
+
If you want the actual inner object(s), use **.get**
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
# returns my_view
|
137
|
+
rmq(my_view).get
|
138
|
+
|
139
|
+
# returns an array
|
140
|
+
rmq(UILabel).get
|
141
|
+
```
|
142
|
+
|
143
|
+
### Selectors
|
144
|
+
|
145
|
+
- Constant
|
146
|
+
- :a_tag
|
147
|
+
- :a_style_name
|
148
|
+
- my_view_instance
|
149
|
+
- text: 'you can select via attributes also'
|
150
|
+
- :another_tag, UILabel, text: 'an array' <- this is an "or", use .and for and
|
151
|
+
|
152
|
+
### Traversing
|
153
|
+
|
154
|
+
- all
|
155
|
+
- and
|
156
|
+
- not
|
157
|
+
- and_self
|
158
|
+
- end
|
159
|
+
- find
|
160
|
+
- children
|
161
|
+
- siblings
|
162
|
+
- closest
|
163
|
+
- parent
|
164
|
+
- parents
|
165
|
+
- filter
|
166
|
+
- view_controller
|
167
|
+
- root_view
|
168
|
+
|
169
|
+
### Enumerablish
|
170
|
+
A rmq object is like an enumerable, but each method returns a rmq object instead of a enumerable. For example, these methods:
|
171
|
+
|
172
|
+
- each
|
173
|
+
- map
|
174
|
+
- select
|
175
|
+
- grep
|
176
|
+
- detect
|
177
|
+
- inject
|
178
|
+
- first
|
179
|
+
- last
|
180
|
+
- []
|
181
|
+
- <<
|
182
|
+
- *etc*
|
183
|
+
|
184
|
+
all return another rmq instance, so you can chain.
|
185
|
+
|
186
|
+
You can also do **rmq.length** and **rmq[0]** like an array
|
187
|
+
|
188
|
+
**.to_a** gives you an actual array, so will **.get** (this is preferred)
|
189
|
+
|
190
|
+
### Events and Gestures
|
191
|
+
|
192
|
+
#### On / Off
|
193
|
+
|
194
|
+
To add an event, use .on, to remove it it, use .off
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
# Simple example
|
198
|
+
rmq(UIView).on(:tap){|sender| rmq(sender).hide}
|
199
|
+
|
200
|
+
# Adding an Event during creation
|
201
|
+
view_q = rmq.append(UIView).on(:tap) do |sender, event|
|
202
|
+
# do something here
|
203
|
+
end
|
204
|
+
|
205
|
+
# removing an Event
|
206
|
+
view_q.off(:tap)
|
207
|
+
|
208
|
+
# or you remove them all
|
209
|
+
view_q.off
|
210
|
+
|
211
|
+
# like everything in RMQ, this works on all items selected
|
212
|
+
rmq(UIView).off(:tap)
|
213
|
+
```
|
214
|
+
|
215
|
+
#### RubyMotionQuery::Event
|
216
|
+
|
217
|
+
In RMQ events and gestures are normalized with the same API. For example removing events or gestures is foo.off, and the appropriate thing happens.
|
218
|
+
|
219
|
+
If you see Event, just remember that's either an event or gesture. I decided to call them Events
|
220
|
+
|
221
|
+
##### Type of events and gestures
|
222
|
+
```ruby
|
223
|
+
# Events on controls
|
224
|
+
:touch
|
225
|
+
:touch_up
|
226
|
+
:touch_down
|
227
|
+
:touch_start
|
228
|
+
:touch_stop
|
229
|
+
:change
|
230
|
+
|
231
|
+
:touch_down_repeat
|
232
|
+
:touch_drag_inside
|
233
|
+
:touch_drag_outside
|
234
|
+
:touch_drag_enter
|
235
|
+
:touch_drag_exit
|
236
|
+
:touch_up_inside
|
237
|
+
:touch_up_outside
|
238
|
+
:touch_cancel
|
239
|
+
|
240
|
+
:value_changed
|
241
|
+
|
242
|
+
:editing_did_begin
|
243
|
+
:editing_changed
|
244
|
+
:editing_did_change
|
245
|
+
:editing_did_end
|
246
|
+
:editing_did_endonexit
|
247
|
+
|
248
|
+
:all_touch
|
249
|
+
:all_editing
|
250
|
+
|
251
|
+
:application
|
252
|
+
:system
|
253
|
+
:all
|
254
|
+
|
255
|
+
# Gestures
|
256
|
+
:tap
|
257
|
+
:pinch
|
258
|
+
:rotate
|
259
|
+
:swipe
|
260
|
+
:pan
|
261
|
+
:long_press
|
262
|
+
```
|
263
|
+
|
264
|
+
##### Interesting methods of an RubyMotionQuery::Event:
|
265
|
+
```ruby
|
266
|
+
foo.sender
|
267
|
+
foo.event
|
268
|
+
|
269
|
+
foo.gesture?
|
270
|
+
foo.recognizer
|
271
|
+
foo.gesture
|
272
|
+
|
273
|
+
foo.location
|
274
|
+
foo.location_in
|
275
|
+
|
276
|
+
foo.sdk_event_or_recognizer
|
277
|
+
```
|
278
|
+
|
279
|
+
TODO, need many examples here
|
280
|
+
|
281
|
+
#### RubyMotionQuery::Events
|
282
|
+
|
283
|
+
The internal store of events in a UIView. It's rmq.events, you won't use it too often
|
284
|
+
|
285
|
+
### Tags
|
286
|
+
|
287
|
+
```ruby
|
288
|
+
# Add tags
|
289
|
+
rmq(my_view).tag(:your_tag)
|
290
|
+
|
291
|
+
rmq(my_view).find(UILabel).tag(:selected, :customer)
|
292
|
+
|
293
|
+
# You can use a tag or tags as selecors
|
294
|
+
rmq(:selected).hide
|
295
|
+
rmq(:your_tag).and(:selected).hide
|
296
|
+
```
|
297
|
+
|
298
|
+
### Actions
|
299
|
+
```ruby
|
300
|
+
rmq(UILabel).attr(text: 'Foo bar')
|
301
|
+
rmq(UILabel).send(:some_method, args)
|
302
|
+
rmq(my_view).hide
|
303
|
+
rmq(my_view).show
|
304
|
+
rmq(my_view).toggle
|
305
|
+
rmq(my_view).toggle_enabled
|
306
|
+
```
|
307
|
+
|
308
|
+
### Subviews
|
309
|
+
|
310
|
+
```ruby
|
311
|
+
rmq.append(UILabel) # Creates a UILabel in the current controller
|
312
|
+
rmq.append(UILabel, :my_label_style)
|
313
|
+
rmq.append(UILabel.alloc.initWithFrame([[0,0],[10,10]]), :my_label_style)
|
314
|
+
rmq(my_view).append(UIButton) # A custom button
|
315
|
+
rmq(my_view).remove
|
316
|
+
rmq(my_vuew).children.remove
|
317
|
+
rmq(UIView).append(UIButton, :delete_me)
|
318
|
+
|
319
|
+
rmq(my_view).parent # .superview works too
|
320
|
+
rmq(my_view).parents # all parents up the tree, up to the root
|
321
|
+
rmq(my_view).children
|
322
|
+
rmq(my_view).find # children, grandchildren, etc
|
323
|
+
rmq.root_view
|
324
|
+
rmq.view_controller
|
325
|
+
```
|
326
|
+
|
327
|
+
### Animate
|
328
|
+
|
329
|
+
```ruby
|
330
|
+
rmq(my_view).animate(
|
331
|
+
duration: 0.3,
|
332
|
+
animations: lambda{|q|
|
333
|
+
q.move left: 20
|
334
|
+
}
|
335
|
+
)
|
336
|
+
```
|
337
|
+
|
338
|
+
```ruby
|
339
|
+
# As an example, this is the implementation of .animations.throb
|
340
|
+
rmq(selectors).animate(
|
341
|
+
duration: 0.1,
|
342
|
+
animations: -> (q) {
|
343
|
+
q.style {|st| st.scale = 1.1}
|
344
|
+
},
|
345
|
+
completion: -> (did_finish, q) {
|
346
|
+
q.animate(
|
347
|
+
duration: 0.4,
|
348
|
+
animations: -> (cq) {
|
349
|
+
cq.style {|st| st.scale = 1.0}
|
350
|
+
}
|
351
|
+
)
|
352
|
+
}
|
353
|
+
)
|
354
|
+
|
355
|
+
# You can pass any options that animateWithDuration allows: options: YOUR_OPTIONS
|
356
|
+
```
|
357
|
+
|
358
|
+
### Animations
|
359
|
+
|
360
|
+
#### Current animations included:
|
361
|
+
|
362
|
+
```ruby
|
363
|
+
rmq(my_view).animations.fade_in
|
364
|
+
rmq(my_view).animations.fade_in(duration: 0.8)
|
365
|
+
rmq(my_view).animations.fade_out
|
366
|
+
rmq(my_view).animations.fade_out(duration: 0.8)
|
367
|
+
|
368
|
+
rmq(my_view).animations.blink
|
369
|
+
rmq(my_view).animations.throb
|
370
|
+
|
371
|
+
rmq.animations.start_spinner
|
372
|
+
rmq.animations.stop_spinner
|
373
|
+
```
|
374
|
+
|
375
|
+
### Color
|
376
|
+
|
377
|
+
```ruby
|
378
|
+
rmq.color.red
|
379
|
+
rmq.color.from_hex('#ffffff')
|
380
|
+
rmq.color.from_hex('ffffff')
|
381
|
+
rmq.color.from_rgba(128, 128, 128, 0.5)
|
382
|
+
|
383
|
+
# Add a new standard color
|
384
|
+
rmq.color.add_named :pitch_black, '#000000'
|
385
|
+
# Or
|
386
|
+
rmq.color.add_named :pitch_black, rmq.color.black
|
387
|
+
|
388
|
+
# In a stylesheet you don't need the rmq
|
389
|
+
color.pitch_black
|
390
|
+
color.red
|
391
|
+
```
|
392
|
+
|
393
|
+
### Font
|
394
|
+
|
395
|
+
```ruby
|
396
|
+
rmq.font.system(12)
|
397
|
+
rmq.font_with_name('Helvetica', 18)
|
398
|
+
rmq.font.family_list # useful in console
|
399
|
+
rmq.font.for_family('Helvetica') # useful in console
|
400
|
+
|
401
|
+
# Add a new standard font
|
402
|
+
font_family = 'Helvetica Neue'
|
403
|
+
font.add_named :large, font_family, 36
|
404
|
+
font.add_named :medium, font_family, 24
|
405
|
+
font.add_named :small, font_family, 18
|
406
|
+
|
407
|
+
# then use them like so
|
408
|
+
rmq.font.large
|
409
|
+
rmq.font.small
|
410
|
+
|
411
|
+
# In a stylesheet you don't need the rmq
|
412
|
+
font.medium
|
413
|
+
font.system(14)
|
414
|
+
```
|
415
|
+
|
416
|
+
### Position (moving, sizing, and nudging)
|
417
|
+
|
418
|
+
```ruby
|
419
|
+
# Move/Size changes size and origin of selected view(s)
|
420
|
+
rmq(your_view).move(l: 20)
|
421
|
+
rmq(your_view).move(left: 20)
|
422
|
+
rmq(your_view).move(l: 20, t: 20, w: 100, h: 50)
|
423
|
+
rmq(your_view).move(left: 20, top: 20, width: 100, height: 50)
|
424
|
+
rmq(your_view).size(left: 20, top: 20, width: 100, height: 50) # alias
|
425
|
+
|
426
|
+
# Nudge pushes them in a direction
|
427
|
+
rmq(your_view).nudge(d: 20)
|
428
|
+
rmq(your_view).nudge(down: 20)
|
429
|
+
rmq(your_view).nudge(l: 20, r: 20, u: 100, d: 50)
|
430
|
+
rmq(your_view).nudge(left: 20, right: 20, up: 100, down: 50)
|
431
|
+
```
|
432
|
+
|
433
|
+
### Images
|
434
|
+
|
435
|
+
```ruby
|
436
|
+
RubyMotionQuery::ImageUtils.resource('logo')
|
437
|
+
rmq.image.resource('logo')
|
438
|
+
rmq.image.resource('subfolder/foo')
|
439
|
+
rmq.image.resource_for_device('logo') # will look for 4inch or 3.5inch
|
440
|
+
rmq.image.resource('logo', cached: false)
|
441
|
+
|
442
|
+
rmq.image.resource_resizable('foo', left: 10, top: 10, right: 10, bottom: 10)
|
443
|
+
|
444
|
+
rmq.image.from_view(my_view)
|
445
|
+
|
446
|
+
# In a stylesheet you don't need the rmq
|
447
|
+
image.resource('logo')
|
448
|
+
```
|
449
|
+
|
450
|
+
### App
|
451
|
+
```ruby
|
452
|
+
RubyMotionQuery::App.window
|
453
|
+
rmq.app.window
|
454
|
+
rmq.app.delegate
|
455
|
+
rmq.app.environment
|
456
|
+
rmq.app.release? # .production? also
|
457
|
+
rmq.app.test?
|
458
|
+
rmq.app.development?
|
459
|
+
rmq.app.version
|
460
|
+
rmq.app.name
|
461
|
+
rmq.app.identifier
|
462
|
+
rmq.app.resource_path
|
463
|
+
rmq.app.document_path
|
464
|
+
```
|
465
|
+
|
466
|
+
### Device
|
467
|
+
|
468
|
+
```ruby
|
469
|
+
RubyMotionQuery::Device.screen
|
470
|
+
rmq.device.screen
|
471
|
+
rmq.device.width # screen width
|
472
|
+
rmq.device.height # screen height
|
473
|
+
rmq.device.ipad?
|
474
|
+
rmq.device.iphone?
|
475
|
+
rmq.device.four_inch?
|
476
|
+
rmq.device.retina?
|
477
|
+
|
478
|
+
# return values are :unkown, :portrait, :portrait_upside_down, :landscape_Left,
|
479
|
+
# :landscape_right, :face_up, :face_down
|
480
|
+
rmq.device.orientation
|
481
|
+
rmq.device.landscape?
|
482
|
+
rmq.device.portrait?
|
483
|
+
```
|
484
|
+
|
485
|
+
### Format
|
486
|
+
A performant way to format numbers and dates.
|
487
|
+
|
488
|
+
```ruby
|
489
|
+
rmq.format.number(1232, '#,##0.##')
|
490
|
+
rmq.format.date(Time.now, 'EEE, MMM d, ''yy')
|
491
|
+
rmq.format.numeric_formatter(your_format_here) # returns cached numeric formatter
|
492
|
+
rmq.format.date_formatter(your_format_here) # returns cached date formatter
|
493
|
+
```
|
494
|
+
See <http://www.unicode.org/reports/tr35/tr35-19.html#Date_Format_Patterns> for more information about date format strings.
|
495
|
+
|
496
|
+
### Utils
|
497
|
+
|
498
|
+
These are mostly used internally by rmq.
|
499
|
+
|
500
|
+
```ruby
|
501
|
+
RubyMotionQuery::RMQ.is_class?(foo)
|
502
|
+
RubyMotionQuery::RMQ.is_blank?(foo)
|
503
|
+
RubyMotionQuery::RMQ.controller_for_view(view)
|
504
|
+
RubyMotionQuery::RMQ.view_to_s(view)
|
505
|
+
```
|
506
|
+
|
507
|
+
### Pollution
|
508
|
+
|
509
|
+
The following are the only pollution in RMQ
|
510
|
+
|
511
|
+
- UIView
|
512
|
+
- rmq
|
513
|
+
- rmq_data
|
514
|
+
- UIViewController
|
515
|
+
- rmq
|
516
|
+
- rmq_data
|
517
|
+
- TopLevel *(Only in development, used for console)*
|
518
|
+
- rmq
|
519
|
+
|
520
|
+
### Console Fun
|
521
|
+
|
522
|
+
rmq.all.log
|
523
|
+
rmq.all.log :wide
|
524
|
+
rmq(UIView).show
|
525
|
+
rmq(UILabel).animations.blink
|
526
|
+
rmq(UIButton).nudge l: 10
|
527
|
+
|
528
|
+
### A recommended project structure
|
529
|
+
|
530
|
+
- app
|
531
|
+
- controllers
|
532
|
+
- your_controller.rb
|
533
|
+
- your_other_controller.rb
|
534
|
+
- models
|
535
|
+
- stylers
|
536
|
+
- ui_view_styler.rb
|
537
|
+
- ui_button_styler.rb
|
538
|
+
- etc
|
539
|
+
- stylesheets
|
540
|
+
- application_stylesheet.rb (inherit from RubyMotionQuery::Stylesheet)
|
541
|
+
- your_stylesheet.rb (inherit from ApplicationStylesheet)
|
542
|
+
- your_other_stylesheet.rb (inherit from ApplicationStylesheet)
|
543
|
+
- views
|
544
|
+
|
545
|
+
----------
|
546
|
+
|
547
|
+
### Styles and stylesheets
|
548
|
+
|
549
|
+
A very lightweight style system, designed for a low memory footprint, fast startup, and fast operation. Most everything is done at compile-time, as it's all just ruby code. Low magic.
|
550
|
+
|
551
|
+
**You don't have to use this system, you can use Teacup instead**, or whatever you like. RMQ works great without using the style system.
|
552
|
+
|
553
|
+
#### Example controller
|
554
|
+
|
555
|
+
```ruby
|
556
|
+
class MainController < UIViewController
|
557
|
+
|
558
|
+
def viewDidLoad
|
559
|
+
super
|
560
|
+
|
561
|
+
rmq.stylesheet = MainControllerStyleSheet
|
562
|
+
view.rmq.apply_style :root_view
|
563
|
+
|
564
|
+
@title_label = rmq.append(UILabel, :title_label).get
|
565
|
+
rmq.append UIImageView, :logo
|
566
|
+
|
567
|
+
rmq.append(UIButton, :make_labels_blink).on(:tap) do |sender|
|
568
|
+
rmq(UILabel).animations.blink
|
569
|
+
end
|
570
|
+
|
571
|
+
rmq.append(UIButton.buttonWithType(UIButtonTypeRoundedRect), :make_buttons_throb).on(:tap) do |sender|
|
572
|
+
rmq(UIButton).animations.throb
|
573
|
+
end
|
574
|
+
|
575
|
+
rmq.append(UIView, :section).tap do |section|
|
576
|
+
section.append(UILabel, :section_title)
|
577
|
+
|
578
|
+
section.append(UILabel, :section_enabled_title)
|
579
|
+
|
580
|
+
section.append(UISwitch, :section_enabled).on(:change) do |sender|
|
581
|
+
style = sender.isOn ? :section_button_enabled : :section_button_disabled
|
582
|
+
buttons = sender.rmq.parent.find(UIButton).apply_style(style)
|
583
|
+
end
|
584
|
+
|
585
|
+
section.append(UIButton, :start_spinner).on(:tap) do |sender|
|
586
|
+
rmq.animations.start_spinner
|
587
|
+
end
|
588
|
+
|
589
|
+
section.append(UIButton, :stop_spinner).on(:tap) do |sender|
|
590
|
+
rmq.animations.stop_spinner
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
end
|
595
|
+
end
|
596
|
+
```
|
597
|
+
|
598
|
+
#### Example stylesheet
|
599
|
+
|
600
|
+
```ruby
|
601
|
+
class ApplicationStylesheet < RubyMotionQuery::Stylesheet
|
602
|
+
PADDING = 10
|
603
|
+
|
604
|
+
def application_setup
|
605
|
+
font_family = 'Helvetica Neue'
|
606
|
+
font.add_named :large, font_family, 36
|
607
|
+
font.add_named :medium, font_family, 24
|
608
|
+
font.add_named :small, font_family, 18
|
609
|
+
|
610
|
+
color.add_named :translucent_black, color.from_rgba(0, 0, 0, 0.4)
|
611
|
+
color.add_named :battleship_gray, '#7F7F7F'
|
612
|
+
end
|
613
|
+
|
614
|
+
def label(st)
|
615
|
+
st.background_color = color.clear
|
616
|
+
end
|
617
|
+
|
618
|
+
end
|
619
|
+
|
620
|
+
class MainStylesheet < ApplicationStylesheet
|
621
|
+
def setup
|
622
|
+
# Add sytlesheet specific setup stuff here.
|
623
|
+
# Add application specific setup stuff in application_stylesheet.rb
|
624
|
+
end
|
625
|
+
|
626
|
+
def root_view(st)
|
627
|
+
st.background_color = color.white
|
628
|
+
end
|
629
|
+
|
630
|
+
def logo(st)
|
631
|
+
st.frame = {t: 10, w: 200, h: 96}
|
632
|
+
st.centered = :horizontal
|
633
|
+
st.image = image.resource('logo')
|
634
|
+
end
|
635
|
+
|
636
|
+
def title_label(st)
|
637
|
+
label st # stack styles
|
638
|
+
st.frame = {l: PADDING, t: 120, w: 200, h: 20}
|
639
|
+
st.text = 'Test label'
|
640
|
+
st.color = color.from_rgba(34, 132, 198, 1.0)
|
641
|
+
st.font = font.medium
|
642
|
+
end
|
643
|
+
|
644
|
+
def make_labels_blink(st)
|
645
|
+
st.frame = {t: 120, w: 150, h: 20}
|
646
|
+
st.from_right = PADDING
|
647
|
+
|
648
|
+
# ipad? (and landscape?, etc) is just a convenience methods for
|
649
|
+
# rmq.device.ipad?
|
650
|
+
|
651
|
+
# Here is a complete example of different formatting for orientatinos
|
652
|
+
# and devices
|
653
|
+
# if ipad?
|
654
|
+
# if landscape?
|
655
|
+
# st.frame = {l: 20, t: 120, w: 150, h: four_inch? ? 20 : 30}
|
656
|
+
# else
|
657
|
+
# st.frame = {l: 90, t: 120, w: 150, h: four_inch? ? 25 : 35}
|
658
|
+
# end
|
659
|
+
# else
|
660
|
+
# if landscape?
|
661
|
+
# st.frame = {l: 20, t: 20, w: 150, h: four_inch? ? 22 : 32}
|
662
|
+
# else
|
663
|
+
# st.frame = {l: 90, t: 20, w: 150, h: four_inch? ? 30 : 40}
|
664
|
+
# end
|
665
|
+
# end
|
666
|
+
|
667
|
+
# If you don't want something to be reapplied during orientation
|
668
|
+
# changes (assuming you're reapplying durring orientation changes
|
669
|
+
# in your controller, it's not automatic)
|
670
|
+
unless st.view_has_been_styled?
|
671
|
+
st.text = 'Blink labels'
|
672
|
+
st.font = font.system(10)
|
673
|
+
st.color = color.white
|
674
|
+
st.background_color = color.from_hex('ed1160')
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|
678
|
+
def make_buttons_throb(st)
|
679
|
+
st.frame = {t: 150, w: 150, h: 20}
|
680
|
+
st.from_right = PADDING
|
681
|
+
st.text = 'Throb buttons'
|
682
|
+
st.color = color.black
|
683
|
+
end
|
684
|
+
|
685
|
+
def section(st)
|
686
|
+
st.frame = {w: 270, h: 110}
|
687
|
+
|
688
|
+
if landscape? && iphone?
|
689
|
+
st.left = PADDING
|
690
|
+
else
|
691
|
+
st.centered = :horizontal
|
692
|
+
end
|
693
|
+
|
694
|
+
st.from_bottom = PADDING
|
695
|
+
|
696
|
+
st.z_position = 1
|
697
|
+
st.background_color = color.battleship_gray
|
698
|
+
end
|
699
|
+
|
700
|
+
def section_label(st)
|
701
|
+
label st
|
702
|
+
st.color = color.white
|
703
|
+
end
|
704
|
+
|
705
|
+
def section_title(st)
|
706
|
+
section_label st
|
707
|
+
st.frame = {l: PADDING, t: PADDING, w: 150, h: 20}
|
708
|
+
st.text = 'Section title'
|
709
|
+
end
|
710
|
+
|
711
|
+
def section_enabled(st)
|
712
|
+
label st
|
713
|
+
st.frame = {l: PADDING, t: 30}
|
714
|
+
st.on = true
|
715
|
+
end
|
716
|
+
|
717
|
+
def section_enabled_title(st)
|
718
|
+
section_label st
|
719
|
+
st.frame = {l: 93, t: 34, w: 150, h: 20}
|
720
|
+
st.text = 'Enabled'
|
721
|
+
end
|
722
|
+
|
723
|
+
def section_buttons(st)
|
724
|
+
st.frame = {l: PADDING, t: 64, w: 120, h: 40}
|
725
|
+
st.background_color = color.black
|
726
|
+
section_button_enabled st
|
727
|
+
end
|
728
|
+
|
729
|
+
def start_spinner(st)
|
730
|
+
section_buttons st
|
731
|
+
st.text = 'Start spinner'
|
732
|
+
end
|
733
|
+
|
734
|
+
def stop_spinner(st)
|
735
|
+
section_buttons st
|
736
|
+
st.from_right = PADDING
|
737
|
+
st.text = 'Stop spinner'
|
738
|
+
end
|
739
|
+
|
740
|
+
def section_button_disabled(st)
|
741
|
+
st.enabled = false
|
742
|
+
st.color = color.dark_gray
|
743
|
+
end
|
744
|
+
|
745
|
+
def section_button_enabled(st)
|
746
|
+
st.enabled = true
|
747
|
+
st.color = color.white
|
748
|
+
end
|
749
|
+
|
750
|
+
def animate_move(st)
|
751
|
+
st.scale = 1.0
|
752
|
+
st.frame = {t: 180, w: 150, h: 20}
|
753
|
+
st.from_right = PADDING
|
754
|
+
st.text = 'Animate move and scale'
|
755
|
+
st.font = font.system(10)
|
756
|
+
st.color = color.white
|
757
|
+
st.background_color = color.from_hex('ed1160')
|
758
|
+
st.z_position = 99
|
759
|
+
st.color = color.white
|
760
|
+
end
|
761
|
+
|
762
|
+
def overlay(st)
|
763
|
+
st.frame = :full
|
764
|
+
st.background_color = color.translucent_black
|
765
|
+
st.hidden = true
|
766
|
+
st.z_position = 99
|
767
|
+
end
|
768
|
+
|
769
|
+
def benchmarks_results_wrapper(st)
|
770
|
+
st.hidden = true
|
771
|
+
st.frame = {w: app_width - 20, h: 120}
|
772
|
+
st.centered = :both
|
773
|
+
st.background_color = color.white
|
774
|
+
st.z_position = 100
|
775
|
+
end
|
776
|
+
|
777
|
+
def benchmarks_results_label(st)
|
778
|
+
label st
|
779
|
+
st.padded = {l: 10, t: 10, b:10, r: 10}
|
780
|
+
st.text_alignment = :left
|
781
|
+
st.color = color.black
|
782
|
+
st.font = font.system(10)
|
783
|
+
|
784
|
+
# If the styler doesn't have the method, you can add it or
|
785
|
+
# just use st.view to get the actual object
|
786
|
+
st.view.numberOfLines = 0
|
787
|
+
st.view.lineBreakMode = NSLineBreakByWordWrapping
|
788
|
+
end
|
789
|
+
|
790
|
+
def run_benchmarks(st)
|
791
|
+
st.frame = {l: PADDING, t: 150, w: 130, h: 20}
|
792
|
+
st.text = 'Run benchmarks'
|
793
|
+
st.font = font.system(11)
|
794
|
+
st.color = color.white
|
795
|
+
st.enabled = true
|
796
|
+
st.background_color = color.from_hex('faa619')
|
797
|
+
end
|
798
|
+
|
799
|
+
def run_benchmarks_disabled(st)
|
800
|
+
st.enabled = false
|
801
|
+
st.color = color.from_hex('de8714')
|
802
|
+
end
|
803
|
+
|
804
|
+
def benchmark(st)
|
805
|
+
st.hidden = false
|
806
|
+
st.text = 'foo'
|
807
|
+
st.color = color.white
|
808
|
+
st.left = 10
|
809
|
+
end
|
810
|
+
|
811
|
+
end
|
812
|
+
```
|
813
|
+
|
814
|
+
#### Stylers
|
815
|
+
|
816
|
+
A styler wraps around a view, augmenting it with styling power and sugar.
|
817
|
+
|
818
|
+
Each UIView subclass can have its own styler (many exist in RMQ, but not all *yet*). There is a UIViewStyler class they all inherit from, and a UIControlStyler controls inherit from. Much of the code is in UIViewStyler.
|
819
|
+
|
820
|
+
When you create a "style method", it will be passed the view, wrapped in a styler. You can get the view using st.view.
|
821
|
+
|
822
|
+
##### UIViewStyler
|
823
|
+
Here is a silly example, showing you a bunch of methods the UIViewStyler gives you:
|
824
|
+
|
825
|
+
```ruby
|
826
|
+
def ui_view_kitchen_sink(st)
|
827
|
+
st.frame = {l: 1, t: 2, w: 3, h: 4}
|
828
|
+
st.frame = {left: 1, top: 2, width: 3, height: 4}
|
829
|
+
st.frame = {left: 10}
|
830
|
+
st.left = 20
|
831
|
+
st.top = 30
|
832
|
+
st.width = 40
|
833
|
+
st.height = 50
|
834
|
+
st.right = 100
|
835
|
+
st.bottom = 110
|
836
|
+
st.from_right = 10
|
837
|
+
st.from_bottom = 12
|
838
|
+
st.padded = {l: 1, t: 2, r: 3, b: 4}
|
839
|
+
st.padded = {left: 1, top: 2, right: 3, bottom: 4}
|
840
|
+
st.center = st.superview.center
|
841
|
+
st.center_x = 50
|
842
|
+
st.center_y = 60
|
843
|
+
st.centered = :horizontal
|
844
|
+
st.centered = :vertical
|
845
|
+
st.centered = :both
|
846
|
+
|
847
|
+
st.enabled = true
|
848
|
+
st.hidden = false
|
849
|
+
st.z_position = 66
|
850
|
+
st.opaque = false
|
851
|
+
|
852
|
+
st.background_color = color.red
|
853
|
+
|
854
|
+
st.scale = 1.5
|
855
|
+
end
|
856
|
+
```
|
857
|
+
|
858
|
+
##### UIControlStyler
|
859
|
+
Nothing yet
|
860
|
+
|
861
|
+
##### UILabelStyler
|
862
|
+
|
863
|
+
```ruby
|
864
|
+
def ui_label_kitchen_sink(st)
|
865
|
+
st.text = 'rmq is awesome'
|
866
|
+
st.font = font.system(12)
|
867
|
+
st.color = color.black
|
868
|
+
st.text_alignment = :center
|
869
|
+
|
870
|
+
st.resize_to_fit_text
|
871
|
+
st.size_to_fit
|
872
|
+
end
|
873
|
+
```
|
874
|
+
|
875
|
+
##### UIButtonStyler
|
876
|
+
|
877
|
+
```ruby
|
878
|
+
def ui_button_kitchen_sink(st)
|
879
|
+
st.text = 'foo'
|
880
|
+
st.font = font.system(12)
|
881
|
+
st.color = color.red
|
882
|
+
st.image_normal = image.resource('logo')
|
883
|
+
st.image_highlighted = image.resource('logo')
|
884
|
+
end
|
885
|
+
```
|
886
|
+
|
887
|
+
##### UIImageViewStyler
|
888
|
+
|
889
|
+
```ruby
|
890
|
+
def u_image_view_kitchen_sink(st)
|
891
|
+
st.image = image.resource('logo')
|
892
|
+
end
|
893
|
+
```
|
894
|
+
|
895
|
+
##### UIScrollViewStyler
|
896
|
+
|
897
|
+
```ruby
|
898
|
+
def ui_scroll_view_kitchen_sink(st)
|
899
|
+
st.paging = true
|
900
|
+
end
|
901
|
+
```
|
902
|
+
|
903
|
+
##### UISwitchStyler
|
904
|
+
|
905
|
+
```ruby
|
906
|
+
def ui_switch_kitchen_sink(st)
|
907
|
+
st.on = true
|
908
|
+
end
|
909
|
+
```
|
910
|
+
|
911
|
+
**There should be a styler for each UIView type. And each one should wrap all common methods and attributes, plus add functionality for common operations. This will come in future versions**
|
912
|
+
|
913
|
+
#### Add your own stylers
|
914
|
+
|
915
|
+
In the example app, look in **/app/stylers**, you can just copy that whole folder to start. Then add methods to the appropriate class.
|
916
|
+
|
917
|
+
Here is an example of adding a method to all stylers:
|
918
|
+
```ruby
|
919
|
+
module RubyMotionQuery
|
920
|
+
module Stylers
|
921
|
+
class UIViewStyler
|
922
|
+
|
923
|
+
def border_width=(value)
|
924
|
+
@view.layer.borderWidth = value
|
925
|
+
end
|
926
|
+
def border_width
|
927
|
+
@view.layer.borderWidth
|
928
|
+
end
|
929
|
+
|
930
|
+
end
|
931
|
+
end
|
932
|
+
end
|
933
|
+
```
|
934
|
+
|
935
|
+
You can also include all of your custom stylers in one file, which works well if you don't have a lot.
|
936
|
+
|
937
|
+
|
938
|
+
## Contact
|
939
|
+
|
940
|
+
created by **Todd Werth** ([http://toddwerth.com](http://toddwerth.com))
|
941
|
+
|
942
|
+
- [@twerth](http://twitter.com/twerth)
|
943
|
+
- [todd@infinitered.com](mailto:todd@infinitered.com)
|
944
|
+
- [github](https://github.com/twerth)
|
945
|
+
|
946
|
+
with help from the team at **InfiniteRed** ([http://infinitered.com](http://infinitered.com))
|
947
|
+
|
948
|
+
- [@infinite_red](http://twitter.com/infinite_red)
|
949
|
+
- [github](https://github.com/infinitered)
|
950
|
+
|
951
|
+
|
952
|
+
## License
|
953
|
+
|
954
|
+
RMQ is available under the MIT license. See the LICENSE file for more info.
|
955
|
+
|
956
|
+
## Contributing
|
957
|
+
|
958
|
+
1. Fork it
|
959
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
960
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
961
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
962
|
+
5. Create new Pull Request
|
963
|
+
|
964
|
+
[1]: http://infinitered.com/rmq
|