motion-ui-geometry 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +20 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +224 -0
- data/Rakefile +20 -0
- data/lib/motion-ui-geometry.rb +9 -0
- data/lib/motion-ui-geometry/cgaffinetransform.rb +141 -0
- data/lib/motion-ui-geometry/cgpoint.rb +142 -0
- data/lib/motion-ui-geometry/cgrect.rb +246 -0
- data/lib/motion-ui-geometry/cgsize.rb +111 -0
- data/lib/motion-ui-geometry/float.rb +42 -0
- data/lib/motion-ui-geometry/nsdictionary.rb +21 -0
- data/lib/motion-ui-geometry/nsstring.rb +17 -0
- data/lib/motion-ui-geometry/spec_app_delegate.rb +7 -0
- data/lib/motion-ui-geometry/version.rb +7 -0
- data/motion-ui-geometry.gemspec +17 -0
- data/spec/cgaffinetransform_spec.rb +272 -0
- data/spec/cgpoint_spec.rb +210 -0
- data/spec/cgrect_spec.rb +352 -0
- data/spec/cgsize_spec.rb +174 -0
- data/spec/float_spec.rb +107 -0
- data/spec/helpers/no_exception_logging.rb +1 -0
- data/spec/nsdictionary_spec.rb +15 -0
- data/spec/nsstring_spec.rb +42 -0
- metadata +84 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Sebastian Burkhart
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,224 @@
|
|
1
|
+
# motion-ui-geometry
|
2
|
+
|
3
|
+
Write Cocoa Touch UIs like a boss™! A gem
|
4
|
+
designed for [RubyMotion](http://rubymotion.com) for iOS.
|
5
|
+
|
6
|
+
##
|
7
|
+
|
8
|
+
## Usage
|
9
|
+
|
10
|
+
### OOP-Style Access to Geometry Functions
|
11
|
+
|
12
|
+
Carefully adapted to match Ruby's style while keeping method names
|
13
|
+
obvious for people with CoreGraphics knowledge.
|
14
|
+
|
15
|
+
Some examples:
|
16
|
+
|
17
|
+
#### `Float`
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
my_float.clamp(min, max)
|
21
|
+
my_float.to_radians
|
22
|
+
my_float.to_degrees
|
23
|
+
```
|
24
|
+
|
25
|
+
#### `CGPoint`
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
integer_point = point.round
|
29
|
+
integer_point = point.floor
|
30
|
+
point.distance_to other_point
|
31
|
+
point.clamp_to_rect boundary_rect # returns the nearest point inside given rect
|
32
|
+
point.to_size
|
33
|
+
```
|
34
|
+
|
35
|
+
#### `CGSize`
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
integer_size = size.round
|
39
|
+
integer_size = size.floor
|
40
|
+
size.to_point
|
41
|
+
```
|
42
|
+
|
43
|
+
#### `CGRect`
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
rect = CGRect.from_origin(origin, size)
|
47
|
+
|
48
|
+
rect.empty?
|
49
|
+
rect.intersect?(other_rect)
|
50
|
+
rect.contain?(other_rect)
|
51
|
+
rect.null?
|
52
|
+
|
53
|
+
rect.inset(5, 5)
|
54
|
+
rect.union(other_rect)
|
55
|
+
rect.intersection(other_rect)
|
56
|
+
[right_division, left_division] = rect.divide(0.2, :right)
|
57
|
+
|
58
|
+
rect.top_left, rect.bottom_left, rect.bottom_right, rect.top_right
|
59
|
+
center_point = rect.center
|
60
|
+
```
|
61
|
+
|
62
|
+
#### `CGAffineTransform`
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
identity_transform = CGAffineTransform.identity
|
66
|
+
|
67
|
+
CGAffineTransform.rotation(angle)
|
68
|
+
CGAffineTransform.scale(sx, sy)
|
69
|
+
CGAffineTransform.translation(tx, ty)
|
70
|
+
CGAffineTransform.skew(sx, sy)
|
71
|
+
|
72
|
+
my_transform.rotate(angle)
|
73
|
+
my_transform.scale(sx, sy)
|
74
|
+
my_transform.translate(tx, ty)
|
75
|
+
my_transform.skew(sx, sy)
|
76
|
+
|
77
|
+
transformed_transform = my_transform.concat other_transform
|
78
|
+
transformed_transform = other_transform.apply_on my_transform
|
79
|
+
determinant = transform.det
|
80
|
+
|
81
|
+
transform.identity?
|
82
|
+
|
83
|
+
inverse = some_transform.invert
|
84
|
+
some_transform * inverse == CGAffineTransform.identity
|
85
|
+
```
|
86
|
+
|
87
|
+
#### Obtaining `NSValue`s
|
88
|
+
|
89
|
+
Handy for use with CoreAnimation.
|
90
|
+
|
91
|
+
Just call `#to_value` on your geometry:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
float_value = some_float.to_value
|
95
|
+
point_value = some_point.to_value
|
96
|
+
size_value = some_size.to_value
|
97
|
+
rect_value = some_rect.to_value
|
98
|
+
transform_value = some_transform.to_value
|
99
|
+
```
|
100
|
+
|
101
|
+
#### Conversion from/to `NSString` and `NSDictionary`
|
102
|
+
|
103
|
+
Handy for serialization:
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
point.to_s
|
107
|
+
size.to_s
|
108
|
+
rect.to_s
|
109
|
+
transform.to_s
|
110
|
+
|
111
|
+
string.to_point
|
112
|
+
string.to_size
|
113
|
+
string.to_rect
|
114
|
+
string.to_transform
|
115
|
+
```
|
116
|
+
|
117
|
+
### Approximate Comparison of Geometry via `=~`
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
some_float =~ 1.5 # => true if float is ~1.5
|
121
|
+
some_float.roughly_equal?(1.5, 0.001) # => true if float is ~1.5 within 0.001 error margin
|
122
|
+
|
123
|
+
rect == other_rect # => true if coordinates are exactly equal
|
124
|
+
|
125
|
+
size =~ other_size # => true if coordinates are roughly equal
|
126
|
+
point =~ other_point # => true if coordinates are roughly equal
|
127
|
+
transform =~ other_transform # => true if coordinates are roughly equal
|
128
|
+
```
|
129
|
+
|
130
|
+
### Transforming Geometry Using Operators
|
131
|
+
|
132
|
+
I have tried to keep operator behavior obvious.
|
133
|
+
|
134
|
+
#### `+ - * /` + Operand Type Mixing
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
offset_point = point + other_point
|
138
|
+
offset_point = point - offset_size
|
139
|
+
negative_point = -point
|
140
|
+
|
141
|
+
offset_size = size + offset_point
|
142
|
+
offset_size = size - offset_size
|
143
|
+
negative_size = -size
|
144
|
+
|
145
|
+
offset_rect = rect + point
|
146
|
+
offset_rect = rect + size
|
147
|
+
negative_rect = -rect
|
148
|
+
|
149
|
+
scaled_point = point * 3.0
|
150
|
+
scaled_size = size * 2.0
|
151
|
+
scaled_rect = rect * 4.0
|
152
|
+
scaled_rect = rect * CGSizeMake(1, 2)
|
153
|
+
|
154
|
+
scaled_point = point / 3.0
|
155
|
+
scaled_size = size / 2.0
|
156
|
+
scaled_rect = rect / 4.0
|
157
|
+
|
158
|
+
offset_rect = rect + point
|
159
|
+
resized_rect = rect + size
|
160
|
+
```
|
161
|
+
|
162
|
+
#### Scale, Rotate, Transform and Skew `UIView`s and Geometry
|
163
|
+
|
164
|
+
Just create a `CGAffineTransform` and multiply with it to transform:
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
double_size = CGAffineTransform.scale(2.0, 2.0)
|
168
|
+
rotation = CGAffineTransform.rotation(30.0.to_rad)
|
169
|
+
|
170
|
+
my_image_view.transform = rotation
|
171
|
+
|
172
|
+
rotated_point = point * rotation
|
173
|
+
rotated_size = size * rotation
|
174
|
+
rotated_rect = rect * rotation
|
175
|
+
|
176
|
+
scaled_rotation = rotation * double_size
|
177
|
+
scaled_transform = some_transform * 2.0 # scales x and y
|
178
|
+
|
179
|
+
scaled_rotated_rect = rect * scaled_rotation
|
180
|
+
scaled_rotated_point = point * scaled_rotation
|
181
|
+
|
182
|
+
translated_transform = transform + offset_point
|
183
|
+
other_translated_transform = transform + offset_size
|
184
|
+
```
|
185
|
+
|
186
|
+
#### Unionize and Intersect `CGRect`s
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
union = rect1 | rect2
|
190
|
+
intersection = rect1 & rect2
|
191
|
+
```
|
192
|
+
|
193
|
+
## Installation
|
194
|
+
|
195
|
+
1. If not done yet, add `bundler` gem management to your RubyMotion app.
|
196
|
+
See <http://thunderboltlabs.com/posts/using-bundler-with-rubymotion> for
|
197
|
+
an explanation how.
|
198
|
+
|
199
|
+
2. Add this line to your application's Gemfile:
|
200
|
+
|
201
|
+
```ruby
|
202
|
+
gem 'motion-ui-geometry'
|
203
|
+
```
|
204
|
+
|
205
|
+
3. Execute:
|
206
|
+
|
207
|
+
```bash
|
208
|
+
$ bundle
|
209
|
+
```
|
210
|
+
|
211
|
+
## Contributing
|
212
|
+
|
213
|
+
Feel free to fork the project and send me a pull request if you would
|
214
|
+
like me to integrate your bugfix, enhancement, or feature. I'm also open for suggestions regarding new features and the interface design.
|
215
|
+
|
216
|
+
To contribute,
|
217
|
+
|
218
|
+
1. Fork it
|
219
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
220
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
221
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
222
|
+
5. Create new Pull Request
|
223
|
+
|
224
|
+
If the feature has specs, I will probably merge it :)
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
3
|
+
$:.unshift("/Library/RubyMotion/lib")
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'rake'
|
7
|
+
require 'motion/project'
|
8
|
+
require "bundler/gem_tasks"
|
9
|
+
|
10
|
+
Bundler.setup
|
11
|
+
Bundler.require
|
12
|
+
|
13
|
+
Motion::Project::App.setup do |app|
|
14
|
+
app.name = 'TestSuite'
|
15
|
+
app.identifier = 'com.screenfashion.motion.spec-app'
|
16
|
+
app.specs_dir = './spec'
|
17
|
+
app.development do
|
18
|
+
app.delegate_class = 'SpecAppDelegate'
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
unless defined?(Motion::Project::Config)
|
2
|
+
raise "This file must be required within a RubyMotion project Rakefile."
|
3
|
+
end
|
4
|
+
|
5
|
+
Motion::Project::App.setup do |app|
|
6
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'motion-ui-geometry/*.rb')).each do |file|
|
7
|
+
app.files.unshift(file)
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
class CGAffineTransform
|
2
|
+
|
3
|
+
def initialize(a, b, c, d, tx, ty)
|
4
|
+
CGAffineTransformMake(a, b, c, d, tx, ty)
|
5
|
+
end
|
6
|
+
|
7
|
+
|
8
|
+
def self.identity
|
9
|
+
CGAffineTransformIdentity
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.rotation(angle_in_rad)
|
13
|
+
CGAffineTransformMakeRotation(angle_in_rad)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.scale(sx, sy = nil)
|
17
|
+
CGAffineTransformMakeScale(sx, sy || sx)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.translation(tx, ty)
|
21
|
+
CGAffineTransformMakeTranslation(tx, ty)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.skew(sx, sy)
|
25
|
+
CGAffineTransformMake 1.0, sy, sx, 1.0, 0.0, 0.0
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def translate(tx, ty)
|
30
|
+
CGAffineTransformTranslate(self, tx, ty)
|
31
|
+
end
|
32
|
+
|
33
|
+
def scale(sx, sy = nil)
|
34
|
+
CGAffineTransformScale(self, sx, sy || sx)
|
35
|
+
end
|
36
|
+
|
37
|
+
def rotate(angle_in_rad)
|
38
|
+
CGAffineTransformRotate(self, angle_in_rad)
|
39
|
+
end
|
40
|
+
|
41
|
+
def skew(sx, sy)
|
42
|
+
self * self.class.skew(sx, sy)
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def invert
|
47
|
+
CGAffineTransformInvert self
|
48
|
+
end
|
49
|
+
alias :inverse :invert
|
50
|
+
|
51
|
+
def concat(other)
|
52
|
+
CGAffineTransformConcat self, other
|
53
|
+
end
|
54
|
+
|
55
|
+
def apply_on(other)
|
56
|
+
other.concat self
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def ==(other)
|
61
|
+
other.is_a?(CGAffineTransform) && CGAffineTransformEqualToTransform(self, other)
|
62
|
+
end
|
63
|
+
|
64
|
+
def =~(other)
|
65
|
+
unless other.is_a? CGAffineTransform
|
66
|
+
raise TypeError, "Right operand for =~ must be a CGAffineTransform (got #{other})."
|
67
|
+
end
|
68
|
+
|
69
|
+
a =~ other.a &&
|
70
|
+
b =~ other.b &&
|
71
|
+
c =~ other.c &&
|
72
|
+
d =~ other.d &&
|
73
|
+
tx =~ other.tx &&
|
74
|
+
ty =~ other.ty
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
def +(other)
|
79
|
+
case other
|
80
|
+
when CGSize
|
81
|
+
translate other.width, other.height
|
82
|
+
when CGPoint
|
83
|
+
translate other.x, other.y
|
84
|
+
else
|
85
|
+
raise TypeError, "Right operand for + and - must be "\
|
86
|
+
"CGSize or CGPoint (got #{other.class})."
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def -(other)
|
91
|
+
self + (-other)
|
92
|
+
end
|
93
|
+
|
94
|
+
def -@
|
95
|
+
invert
|
96
|
+
end
|
97
|
+
|
98
|
+
def *(other)
|
99
|
+
case other
|
100
|
+
when Float, Fixnum
|
101
|
+
scale other, other
|
102
|
+
when CGAffineTransform
|
103
|
+
concat other
|
104
|
+
else
|
105
|
+
raise TypeError, "Right operand for * must be Fixnum, "\
|
106
|
+
"Float or CGAffineTransform (got #{other.class})."
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def /(other)
|
111
|
+
case other
|
112
|
+
when Float, Fixnum
|
113
|
+
scale 1.0/other, 1.0/other
|
114
|
+
when CGAffineTransform
|
115
|
+
concat other.inverse
|
116
|
+
else
|
117
|
+
raise TypeError, "Right operand for / must be Fixnum, "\
|
118
|
+
"Float or CGAffineTransform (got #{other.class})."
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
def det
|
124
|
+
a * d - b * c
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
def identity?
|
129
|
+
CGAffineTransformIsIdentity self
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
def to_value
|
134
|
+
NSValue.valueWithCGAffineTransform self
|
135
|
+
end
|
136
|
+
|
137
|
+
def to_s
|
138
|
+
NSStringFromCGAffineTransform self
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|