motion-ui-geometry 0.5.1
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/.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
|