sugarcube 0.16.9 → 0.18.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +85 -3
- data/app/animation_chain_controller.rb +12 -0
- data/lib/sugarcube/animation_chain.rb +66 -0
- data/lib/sugarcube/nsattributedstring.rb +247 -0
- data/lib/sugarcube/nsstring.rb +2 -1
- data/lib/sugarcube/symbol.rb +8 -2
- data/lib/sugarcube/uiview.rb +62 -37
- data/lib/sugarcube/version.rb +1 -1
- data/lib/sugarcube-unholy/ivar.rb +8 -0
- data/spec/nsattributedstring_spec.rb +149 -0
- data/spec/nsstring_spec.rb +6 -6
- data/spec/uiview_animation_chain_spec.rb +61 -0
- data/spec/uiview_attr_updates_spec.rb +54 -0
- data/spec/unholy_spec.rb +8 -0
- metadata +11 -2
data/README.md
CHANGED
@@ -129,6 +129,41 @@ distance.miles # => 0.932056427001953
|
|
129
129
|
10000.string_with_style(:currency) # => "$10,000.00"
|
130
130
|
```
|
131
131
|
|
132
|
+
NSAttributedString
|
133
|
+
---------
|
134
|
+
|
135
|
+
These become pretty fun! Check out `nsattributedstring_spec.rb` for all the
|
136
|
+
supported attributes (in theory they are all supported, but there's weird
|
137
|
+
issues with missing constants).
|
138
|
+
|
139
|
+
```ruby
|
140
|
+
'test'.nsattributedstring({}) #=> NSAttributedString.alloc.initWithString('test', attributes:{})
|
141
|
+
'test'.attrd # => alias for `nsattributedstring`
|
142
|
+
'test'.bold # => NSAttributedString.alloc.initWithString('test', attributes:{NSFontAttributeName => :bold.uifont})
|
143
|
+
'test'.italic # => NSAttributedString.alloc.initWithString('test', attributes:{NSFontAttributeName => :italic.uifont})
|
144
|
+
'test'.underline # => NSAttributedString.alloc.initWithString('test', attributes:{NSUnderlineStyleAttributeName => NSUnderlineStyleSingle})
|
145
|
+
|
146
|
+
# you can chain 'em, too.
|
147
|
+
'test'.bold.underline
|
148
|
+
# If you look up NSAttributedString Application Kit Additions, you can see all
|
149
|
+
# the constants. Each of those has a method on NSAttributedString.
|
150
|
+
|
151
|
+
# you can add 'em, but the FIRST one MUST be an NSAttributedString
|
152
|
+
'test'.attrd + '-ing'.italic
|
153
|
+
|
154
|
+
# And there's where it gets FUN:
|
155
|
+
('This'.italic + ' is going to be ' + 'FUN'.bold).underline
|
156
|
+
```
|
157
|
+
|
158
|
+
And you can easily turn this into a label!
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
view << (("We just met\n".attrd +
|
162
|
+
"and this is " + "CRAZY".italic + "\n"
|
163
|
+
"But here's my " + "id_rsa.pub".code + " file,\n" +
|
164
|
+
"so give me SSH access.").uilabel
|
165
|
+
```
|
166
|
+
|
132
167
|
NSCoder
|
133
168
|
---------
|
134
169
|
|
@@ -418,7 +453,7 @@ NSError.new('Error Message', code: 404, userInfo: { warnings: ['blabla'] })
|
|
418
453
|
```ruby
|
419
454
|
# UIImage from name
|
420
455
|
"my_image".uiimage # => UIImage.imageNamed("my_image")
|
421
|
-
"
|
456
|
+
"pattern".uicolor == "pattern".uiimage.uicolor # => UIColor.colorWithPatternImage(UIImage.imageNamed("pattern"))
|
422
457
|
|
423
458
|
# UIFont from name
|
424
459
|
"my_font".uifont # => UIFont.fontWithName("my_font", size:UIFont.systemFontSize)
|
@@ -428,9 +463,8 @@ NSError.new('Error Message', code: 404, userInfo: { warnings: ['blabla'] })
|
|
428
463
|
"blue".uicolor == :blue.uicolor # => UIColor.blueColor
|
429
464
|
"#ff00ff".uicolor == :fuchsia.uicolor == 0xff00ff.uicolor # => UIColor.colorWithRed(1.0, green:0.0, blue:1.0, alpha:1.0)
|
430
465
|
"#f0f".uicolor(0.5) == :fuchsia.uicolor(0.5) == 0xff00ff.uicolor(0.5) # => UIColor.colorWithRed(1.0, green:1.0, blue:1.0, alpha:0.5)
|
431
|
-
# note: 0xf0f.uicolor ==
|
466
|
+
# note: 0xf0f.uicolor == 0x000f0f.uicolor. There's no way to tell the difference
|
432
467
|
# at run time between those two Fixnum literals.
|
433
|
-
"my_image".uicolor == "my_image".uiimage.uicolor # => UIColor.colorWithPatternImage(UIImage.imageNamed("my_image"))
|
434
468
|
|
435
469
|
# NSLocalizedString from string
|
436
470
|
"hello".localized # => NSBundle.mainBundle.localizedStringForKey("hello", value:nil, table:nil)
|
@@ -647,6 +681,25 @@ self.view.hide # => self.hidden = true
|
|
647
681
|
my_view.uiimage
|
648
682
|
```
|
649
683
|
|
684
|
+
When defining a UIView subclass, you often have attributes that affect your
|
685
|
+
`drawRect` method (99% of the time, ALL the attributes affect drawing, right?).
|
686
|
+
So SugarCube adds a `attr_updates` method, which creates an attribute identical
|
687
|
+
to `attr_accessor` but the setter calls setNeedsDisplay if the new value != the
|
688
|
+
old value.
|
689
|
+
|
690
|
+
```ruby
|
691
|
+
class NiftyView < UIView
|
692
|
+
attr_updates :insets, :pattern
|
693
|
+
|
694
|
+
def drawRect(rect)
|
695
|
+
# ...
|
696
|
+
end
|
697
|
+
end
|
698
|
+
|
699
|
+
nifty_view.pattern = 'my_pattern' # => setNeedsDisplay gets called
|
700
|
+
nifty_view.pattern = 'my_pattern' # => setNeedsDisplay doesn't get called, because the value didn't change.
|
701
|
+
```
|
702
|
+
|
650
703
|
###### Animations
|
651
704
|
|
652
705
|
jQuery-like animation methods. They accept a "completed" callback handler that
|
@@ -716,6 +769,35 @@ view.slide(:left, 20) {
|
|
716
769
|
}
|
717
770
|
```
|
718
771
|
|
772
|
+
But isn't that ugly! Use an animation chain!
|
773
|
+
|
774
|
+
```ruby
|
775
|
+
UIView.animation_chain {
|
776
|
+
view.slide(:left, 20)
|
777
|
+
}.and_then {
|
778
|
+
view.slide(:up, 20)
|
779
|
+
}.and_then {
|
780
|
+
view.slide(:right, 20)
|
781
|
+
}.and_then {
|
782
|
+
view.slide(:down, 20)
|
783
|
+
}.and_then {
|
784
|
+
view.fade_out
|
785
|
+
}.start
|
786
|
+
```
|
787
|
+
|
788
|
+
Chains can also be written like this:
|
789
|
+
|
790
|
+
|
791
|
+
```ruby
|
792
|
+
chain = UIView.animation_chain
|
793
|
+
chain << proc { view.slide(:left, 20) }
|
794
|
+
chain << proc { view.slide(:up, 20) }
|
795
|
+
chain << proc { view.slide(:right, 20) }
|
796
|
+
chain << proc { view.slide(:down, 20) }
|
797
|
+
chain << proc { view.fade_out }
|
798
|
+
chain.start
|
799
|
+
```
|
800
|
+
|
719
801
|
##### View factories
|
720
802
|
|
721
803
|
###### UIButton
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module SugarCube
|
2
|
+
class AnimationChain
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def chains
|
6
|
+
@chains ||= []
|
7
|
+
end
|
8
|
+
|
9
|
+
def start_chain(chain)
|
10
|
+
chains << chain
|
11
|
+
end
|
12
|
+
|
13
|
+
def stop_chain(chain)
|
14
|
+
chains ||= []
|
15
|
+
@chains.delete(chain)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@blocks = []
|
22
|
+
end
|
23
|
+
|
24
|
+
def wait(duration)
|
25
|
+
and_then(duration: duration) {}
|
26
|
+
end
|
27
|
+
|
28
|
+
def and_then(options=nil, &block)
|
29
|
+
if options
|
30
|
+
options = options.dup
|
31
|
+
else
|
32
|
+
options = {}
|
33
|
+
end
|
34
|
+
@blocks << [options, block]
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def << block
|
39
|
+
and_then(&block)
|
40
|
+
end
|
41
|
+
|
42
|
+
def do_next
|
43
|
+
return nil if @block_index >= @blocks.length
|
44
|
+
|
45
|
+
options, _ = @blocks[@block_index]
|
46
|
+
@after_block = ->(completed){
|
47
|
+
self.do_next || AnimationChain.stop_chain(self)
|
48
|
+
}
|
49
|
+
options[:after] = @after_block
|
50
|
+
|
51
|
+
UIView.animate(options) {
|
52
|
+
_, block = @blocks[@block_index]
|
53
|
+
block.call
|
54
|
+
@block_index += 1
|
55
|
+
}
|
56
|
+
true
|
57
|
+
end
|
58
|
+
|
59
|
+
def start
|
60
|
+
AnimationChain.start_chain(self)
|
61
|
+
@block_index = 0
|
62
|
+
do_next
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,247 @@
|
|
1
|
+
class NSString
|
2
|
+
|
3
|
+
def bold(size=nil)
|
4
|
+
font = :bold.uifont(size)
|
5
|
+
nsattributedstring({NSFontAttributeName => font})
|
6
|
+
end
|
7
|
+
|
8
|
+
def italic(size=nil)
|
9
|
+
font = :italic.uifont(size)
|
10
|
+
nsattributedstring({NSFontAttributeName => font})
|
11
|
+
end
|
12
|
+
|
13
|
+
def monospace(size=nil)
|
14
|
+
font = :monospace.uifont(size)
|
15
|
+
nsattributedstring({NSFontAttributeName => font})
|
16
|
+
end
|
17
|
+
|
18
|
+
def underline(underline_style=nil)
|
19
|
+
underline_style ||= NSUnderlineStyleSingle
|
20
|
+
nsattributedstring({NSUnderlineStyleAttributeName => underline_style})
|
21
|
+
end
|
22
|
+
|
23
|
+
def nsattributedstring(attributes={})
|
24
|
+
NSAttributedString.alloc.initWithString(self, attributes: attributes)
|
25
|
+
end
|
26
|
+
alias attrd nsattributedstring
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
class NSMutableString
|
32
|
+
|
33
|
+
def nsattributedstring(attributes={})
|
34
|
+
NSMutableAttributedString.alloc.initWithString(self, attributes: attributes)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
class NSAttributedString
|
41
|
+
NSSuperscriptAttributeName = 'NSSuperscript'
|
42
|
+
NSAttachmentAttributeName = 'NSAttachment'
|
43
|
+
NSBaselineOffsetAttributeName = 'NSBaselineOffset'
|
44
|
+
NSLinkAttributeName = 'NSLink'
|
45
|
+
NSUnderlineColorAttributeName = 'NSUnderlineColor'
|
46
|
+
NSStrikethroughColorAttributeName = 'NSStrikethroughColor'
|
47
|
+
NSObliquenessAttributeName = 'NSObliqueness'
|
48
|
+
NSExpansionAttributeName = 'NSExpansion'
|
49
|
+
NSCursorAttributeName = 'NSCursor'
|
50
|
+
NSToolTipAttributeName = 'NSToolTip'
|
51
|
+
NSMarkedClauseSegmentAttributeName = 'NSMarkedClauseSegment'
|
52
|
+
NSWritingDirectionAttributeName = 'NSWritingDirection'
|
53
|
+
NSTextAlternativesAttributeName = 'NSTextAlternatives'
|
54
|
+
|
55
|
+
def dummy
|
56
|
+
self.foo = NSFontAttributeName
|
57
|
+
self.foo = NSParagraphStyleAttributeName
|
58
|
+
self.foo = NSForegroundColorAttributeName
|
59
|
+
self.foo = NSUnderlineStyleAttributeName
|
60
|
+
self.foo = NSSuperscriptAttributeName
|
61
|
+
self.foo = NSBackgroundColorAttributeName
|
62
|
+
self.foo = NSAttachmentAttributeName
|
63
|
+
self.foo = NSLigatureAttributeName
|
64
|
+
self.foo = NSBaselineOffsetAttributeName
|
65
|
+
self.foo = NSKernAttributeName
|
66
|
+
self.foo = NSLinkAttributeName
|
67
|
+
self.foo = NSStrokeWidthAttributeName
|
68
|
+
self.foo = NSStrokeColorAttributeName
|
69
|
+
self.foo = NSUnderlineColorAttributeName
|
70
|
+
self.foo = NSStrikethroughStyleAttributeName
|
71
|
+
self.foo = NSStrikethroughColorAttributeName
|
72
|
+
self.foo = NSShadowAttributeName
|
73
|
+
self.foo = NSObliquenessAttributeName
|
74
|
+
self.foo = NSExpansionAttributeName
|
75
|
+
self.foo = NSCursorAttributeName
|
76
|
+
self.foo = NSToolTipAttributeName
|
77
|
+
self.foo = NSMarkedClauseSegmentAttributeName
|
78
|
+
self.foo = NSWritingDirectionAttributeName
|
79
|
+
self.foo = NSVerticalGlyphFormAttributeName
|
80
|
+
self.foo = NSTextAlternativesAttributeName
|
81
|
+
|
82
|
+
self.foo = NSLeftTextAlignment
|
83
|
+
self.foo = NSRightTextAlignment
|
84
|
+
self.foo = NSCenterTextAlignment
|
85
|
+
self.foo = NSJustifiedTextAlignment
|
86
|
+
self.foo = NSNaturalTextAlignment
|
87
|
+
end
|
88
|
+
|
89
|
+
def to_s
|
90
|
+
string
|
91
|
+
end
|
92
|
+
|
93
|
+
def bold(size=nil)
|
94
|
+
font = :bold.uifont(size)
|
95
|
+
self.font(font)
|
96
|
+
end
|
97
|
+
|
98
|
+
def italic(size=nil)
|
99
|
+
font = :italic.uifont(size)
|
100
|
+
self.font(font)
|
101
|
+
end
|
102
|
+
|
103
|
+
def underlined
|
104
|
+
underline(NSUnderlinePatternSolid)
|
105
|
+
end
|
106
|
+
|
107
|
+
# @param font [UIFont] Optional, defaults to UIFont.systemFontOfSize(UIFont.systemFontSize)
|
108
|
+
# @return [UILabel]
|
109
|
+
def uilabel
|
110
|
+
UILabel.alloc.initWithFrame([[0, 0], [0, 0]]).tap { |label|
|
111
|
+
label.attributedText = self
|
112
|
+
label.backgroundColor = :clear.uicolor
|
113
|
+
label.sizeToFit
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
def font(value)
|
118
|
+
with_attributes({NSFontAttributeName => value.uifont})
|
119
|
+
end
|
120
|
+
|
121
|
+
def paragraph_style(value)
|
122
|
+
with_attributes({NSParagraphStyleAttributeName => value})
|
123
|
+
end
|
124
|
+
|
125
|
+
def foreground_color(value)
|
126
|
+
with_attributes({NSForegroundColorAttributeName => value})
|
127
|
+
end
|
128
|
+
alias color foreground_color
|
129
|
+
|
130
|
+
def underline_style(value)
|
131
|
+
with_attributes({NSUnderlineStyleAttributeName => value})
|
132
|
+
end
|
133
|
+
|
134
|
+
def superscript(value)
|
135
|
+
with_attributes({NSSuperscriptAttributeName => value})
|
136
|
+
end
|
137
|
+
|
138
|
+
def background_color(value)
|
139
|
+
with_attributes({NSBackgroundColorAttributeName => value})
|
140
|
+
end
|
141
|
+
alias bg_color background_color
|
142
|
+
|
143
|
+
def attachment(value)
|
144
|
+
with_attributes({NSAttachmentAttributeName => value})
|
145
|
+
end
|
146
|
+
|
147
|
+
def ligature(value)
|
148
|
+
with_attributes({NSLigatureAttributeName => value})
|
149
|
+
end
|
150
|
+
|
151
|
+
def baseline_offset(value)
|
152
|
+
with_attributes({NSBaselineOffsetAttributeName => value})
|
153
|
+
end
|
154
|
+
|
155
|
+
def kern(value)
|
156
|
+
with_attributes({NSKernAttributeName => value})
|
157
|
+
end
|
158
|
+
|
159
|
+
def link(value)
|
160
|
+
with_attributes({NSLinkAttributeName => value})
|
161
|
+
end
|
162
|
+
|
163
|
+
def stroke_width(value)
|
164
|
+
with_attributes({NSStrokeWidthAttributeName => value})
|
165
|
+
end
|
166
|
+
|
167
|
+
def stroke_color(value)
|
168
|
+
with_attributes({NSStrokeColorAttributeName => value})
|
169
|
+
end
|
170
|
+
|
171
|
+
def underline_color(value)
|
172
|
+
with_attributes({NSUnderlineColorAttributeName => value})
|
173
|
+
end
|
174
|
+
|
175
|
+
def strikethrough_style(value)
|
176
|
+
with_attributes({NSStrikethroughStyleAttributeName => value})
|
177
|
+
end
|
178
|
+
|
179
|
+
def strikethrough_color(value)
|
180
|
+
with_attributes({NSStrikethroughColorAttributeName => value})
|
181
|
+
end
|
182
|
+
|
183
|
+
def shadow(value)
|
184
|
+
with_attributes({NSShadowAttributeName => value})
|
185
|
+
end
|
186
|
+
|
187
|
+
def obliqueness(value)
|
188
|
+
with_attributes({NSObliquenessAttributeName => value})
|
189
|
+
end
|
190
|
+
|
191
|
+
def expansion(value)
|
192
|
+
with_attributes({NSExpansionAttributeName => value})
|
193
|
+
end
|
194
|
+
|
195
|
+
def cursor(value)
|
196
|
+
with_attributes({NSCursorAttributeName => value})
|
197
|
+
end
|
198
|
+
|
199
|
+
def tool_tip(value)
|
200
|
+
with_attributes({NSToolTipAttributeName => value})
|
201
|
+
end
|
202
|
+
|
203
|
+
def marked_clause_segment(value)
|
204
|
+
with_attributes({NSMarkedClauseSegmentAttributeName => value})
|
205
|
+
end
|
206
|
+
|
207
|
+
def writing_direction(value)
|
208
|
+
with_attributes({NSWritingDirectionAttributeName => value})
|
209
|
+
end
|
210
|
+
|
211
|
+
def vertical_glyph_form(value)
|
212
|
+
with_attributes({NSVerticalGlyphFormAttributeName => value})
|
213
|
+
end
|
214
|
+
|
215
|
+
def text_alternatives(value)
|
216
|
+
with_attributes({NSTextAlternativesAttributeName => value})
|
217
|
+
end
|
218
|
+
|
219
|
+
def with_attributes(attributes)
|
220
|
+
retval = NSMutableAttributedString.alloc.initWithAttributedString(self)
|
221
|
+
retval.addAttributes(attributes, range:[0, self.length])
|
222
|
+
retval
|
223
|
+
end
|
224
|
+
|
225
|
+
def nsattributedstring
|
226
|
+
self
|
227
|
+
end
|
228
|
+
|
229
|
+
def +(attributedstring)
|
230
|
+
NSMutableAttributedString.alloc.initWithAttributedString(self) + attributedstring
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
class NSMutableAttributedString
|
237
|
+
|
238
|
+
def with_attributes(attributes)
|
239
|
+
self.addAttributes(attributes, range:[0, self.length])
|
240
|
+
self
|
241
|
+
end
|
242
|
+
|
243
|
+
def +(attributedstring)
|
244
|
+
self.appendAttributedString(attributedstring.nsattributedstring)
|
245
|
+
end
|
246
|
+
|
247
|
+
end
|
data/lib/sugarcube/nsstring.rb
CHANGED
data/lib/sugarcube/symbol.rb
CHANGED
@@ -207,6 +207,7 @@ class Symbol
|
|
207
207
|
system: :"systemFontOfSize:",
|
208
208
|
bold: :"boldSystemFontOfSize:",
|
209
209
|
italic: :"italicSystemFontOfSize:",
|
210
|
+
monospace: 'Monaco',
|
210
211
|
}
|
211
212
|
|
212
213
|
@font_sizes = {
|
@@ -654,14 +655,19 @@ class Symbol
|
|
654
655
|
end
|
655
656
|
alias uigesturestate uigesturerecognizerstate
|
656
657
|
|
657
|
-
def uifont(size=
|
658
|
+
def uifont(size=nil)
|
659
|
+
size ||= UIFont.systemFontSize
|
658
660
|
# system fonts
|
659
661
|
if Symbol.system_fonts.has_key? self
|
660
662
|
font = look_in(Symbol.system_fonts)
|
661
663
|
if size.is_a? Symbol
|
662
664
|
size = Symbol.font_sizes.fetch(size).uifontsize
|
663
665
|
end
|
664
|
-
font
|
666
|
+
if font.is_a?(Symbol)
|
667
|
+
font = UIFont.send(font, size)
|
668
|
+
else
|
669
|
+
font.uifont(size)
|
670
|
+
end
|
665
671
|
else
|
666
672
|
size = look_in(font_sizes).uifontsize
|
667
673
|
font = UIFont.systemFontOfSize(size)
|
data/lib/sugarcube/uiview.rb
CHANGED
@@ -1,10 +1,65 @@
|
|
1
1
|
class UIView
|
2
2
|
|
3
3
|
class << self
|
4
|
+
|
4
5
|
# returns the first responder, starting at the Window and searching every subview
|
5
6
|
def first_responder
|
6
7
|
UIApplication.sharedApplication.keyWindow.first_responder
|
7
8
|
end
|
9
|
+
|
10
|
+
def attr_updates(*attrs)
|
11
|
+
attr_accessor(*attrs)
|
12
|
+
attrs.each do |attr|
|
13
|
+
define_method(attr.setter) { |value|
|
14
|
+
if instance_variable_get(attr.ivar) != value
|
15
|
+
setNeedsDisplay
|
16
|
+
end
|
17
|
+
instance_variable_set(attr.ivar, value)
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# If options is a Numeric, it is used as the duration. Otherwise, duration
|
23
|
+
# is an option, and defaults to 0.3. All the transition methods work this
|
24
|
+
# way.
|
25
|
+
def animate(options={}, &animations)
|
26
|
+
if options.is_a? Numeric
|
27
|
+
duration = options
|
28
|
+
options = {}
|
29
|
+
else
|
30
|
+
duration = options[:duration] || 0.3
|
31
|
+
end
|
32
|
+
|
33
|
+
after_animations = options[:after]
|
34
|
+
if after_animations
|
35
|
+
if after_animations.arity == 0
|
36
|
+
after_adjusted = ->(finished){ after_animations.call }
|
37
|
+
else
|
38
|
+
after_adjusted = after_animations
|
39
|
+
end
|
40
|
+
else
|
41
|
+
after_adjusted = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
UIView.animateWithDuration( duration,
|
45
|
+
delay: options[:delay] || 0,
|
46
|
+
options: options[:options] || UIViewAnimationOptionCurveEaseInOut,
|
47
|
+
animations: proc,
|
48
|
+
completion: after_adjusted
|
49
|
+
)
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
|
53
|
+
# Animation chains are great for consecutive animation blocks. Each chain can
|
54
|
+
# take the same options that UIView##animate take.
|
55
|
+
def animation_chain(options={}, &first)
|
56
|
+
chain = SugarCube::AnimationChain.new
|
57
|
+
if first
|
58
|
+
chain.and_then(options, &first)
|
59
|
+
end
|
60
|
+
return chain
|
61
|
+
end
|
62
|
+
|
8
63
|
end
|
9
64
|
|
10
65
|
# returns the first responder, or nil if it cannot be found
|
@@ -57,37 +112,6 @@ class UIView
|
|
57
112
|
self
|
58
113
|
end
|
59
114
|
|
60
|
-
# If options is a Numeric, it is used as the duration. Otherwise, duration
|
61
|
-
# is an option, and defaults to 0.3. All the transition methods work this
|
62
|
-
# way.
|
63
|
-
def self.animate(options={}, &animations)
|
64
|
-
if options.is_a? Numeric
|
65
|
-
duration = options
|
66
|
-
options = {}
|
67
|
-
else
|
68
|
-
duration = options[:duration] || 0.3
|
69
|
-
end
|
70
|
-
|
71
|
-
after_animations = options[:after]
|
72
|
-
if after_animations
|
73
|
-
if after_animations.arity == 0
|
74
|
-
after_adjusted = proc { |finished| after_animations.call }
|
75
|
-
else
|
76
|
-
after_adjusted = proc { |finished| after_animations.call(finished) }
|
77
|
-
end
|
78
|
-
else
|
79
|
-
after_adjusted = nil
|
80
|
-
end
|
81
|
-
|
82
|
-
UIView.animateWithDuration( duration,
|
83
|
-
delay: options[:delay] || 0,
|
84
|
-
options: options[:options] || UIViewAnimationOptionCurveEaseInOut,
|
85
|
-
animations: proc,
|
86
|
-
completion: after_adjusted
|
87
|
-
)
|
88
|
-
nil
|
89
|
-
end
|
90
|
-
|
91
115
|
# Same as UIView##animate, but acts on self
|
92
116
|
def animate(options={}, &animations)
|
93
117
|
if options.is_a? Numeric
|
@@ -204,19 +228,20 @@ class UIView
|
|
204
228
|
options = {size: options}
|
205
229
|
end
|
206
230
|
|
231
|
+
size = options[:size]
|
207
232
|
case direction
|
208
233
|
when :left
|
209
|
-
size
|
234
|
+
size ||= self.bounds.size.width
|
210
235
|
delta_to([-size, 0], options, &after)
|
211
236
|
when :right
|
212
|
-
size
|
213
|
-
delta_to([
|
237
|
+
size ||= self.bounds.size.width
|
238
|
+
delta_to([size, 0], options, &after)
|
214
239
|
when :up
|
215
|
-
size
|
240
|
+
size ||= self.bounds.size.height
|
216
241
|
delta_to([0, -size], options, &after)
|
217
242
|
when :down
|
218
|
-
size
|
219
|
-
delta_to([0,
|
243
|
+
size ||= self.bounds.size.height
|
244
|
+
delta_to([0, size], options, &after)
|
220
245
|
else
|
221
246
|
raise "Unknown direction #{direction.inspect}"
|
222
247
|
end
|
data/lib/sugarcube/version.rb
CHANGED
@@ -5,6 +5,10 @@ class Symbol
|
|
5
5
|
self.to_s.ivar
|
6
6
|
end
|
7
7
|
|
8
|
+
def setter
|
9
|
+
self.to_s.setter
|
10
|
+
end
|
11
|
+
|
8
12
|
def cvar
|
9
13
|
self.to_s.cvar
|
10
14
|
end
|
@@ -18,6 +22,10 @@ class NSString
|
|
18
22
|
"@#{self}"
|
19
23
|
end
|
20
24
|
|
25
|
+
def setter
|
26
|
+
"#{self}="
|
27
|
+
end
|
28
|
+
|
21
29
|
def cvar
|
22
30
|
"@@#{self}"
|
23
31
|
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
describe 'NSAttributeString' do
|
2
|
+
|
3
|
+
describe 'NSString attribute string methods' do
|
4
|
+
|
5
|
+
it 'should have #bold' do
|
6
|
+
subject = 'test'.bold
|
7
|
+
NSAttributedString.should === subject
|
8
|
+
subject.attributesAtIndex(0, effectiveRange:nil).should == {'NSFont' => :bold.uifont}
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should have #italic' do
|
12
|
+
subject = 'test'.italic
|
13
|
+
NSAttributedString.should === subject
|
14
|
+
subject.attributesAtIndex(0, effectiveRange:nil).should == {'NSFont' => :italic.uifont}
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should have #monospace' do
|
18
|
+
subject = 'test'.monospace
|
19
|
+
NSAttributedString.should === subject
|
20
|
+
subject.attributesAtIndex(0, effectiveRange:nil).should == {'NSFont' => :monospace.uifont}
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should have #underline' do
|
24
|
+
subject = 'test'.underline
|
25
|
+
NSAttributedString.should === subject
|
26
|
+
subject.attributesAtIndex(0, effectiveRange:nil).should == {'NSUnderline' => NSUnderlineStyleSingle}
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "should support all attribute names" do
|
32
|
+
before do
|
33
|
+
@subject = 'test'.attrd
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should be sane" do
|
37
|
+
@subject.isEqualToAttributedString('test'.attrd).should == true
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should have `font`' do
|
41
|
+
@subject.isEqualToAttributedString('test'.attrd.font(:bold.uifont)).should != true
|
42
|
+
@subject.isEqualToAttributedString('test'.attrd.font('Helvetica')).should != true
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should have `paragraph_style`' do
|
46
|
+
@subject.isEqualToAttributedString('test'.attrd.paragraph_style(NSMutableParagraphStyle.alloc.init.tap{|s| s.alignment = UITextAlignmentRight })).should != true
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should have `foreground_color`' do
|
50
|
+
@subject.isEqualToAttributedString('test'.attrd.foreground_color(UIColor.redColor)).should != true
|
51
|
+
@subject.isEqualToAttributedString('test'.attrd.color(UIColor.redColor)).should != true
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should have `underline_style`' do
|
55
|
+
@subject.isEqualToAttributedString('test'.attrd.underline_style(NSUnderlineStyleSingle)).should != true
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should have `superscript`' do
|
59
|
+
@subject.isEqualToAttributedString('test'.attrd.superscript(1)).should != true
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should have `background_color`' do
|
63
|
+
@subject.isEqualToAttributedString('test'.attrd.background_color(UIColor.redColor)).should != true
|
64
|
+
@subject.isEqualToAttributedString('test'.attrd.bg_color(UIColor.redColor)).should != true
|
65
|
+
end
|
66
|
+
|
67
|
+
# don't care about:
|
68
|
+
# it 'should have `attachment`' do
|
69
|
+
# @subject.isEqualToAttributedString('test'.attrd.attachment()).should != true
|
70
|
+
# end
|
71
|
+
|
72
|
+
it 'should have `ligature`' do
|
73
|
+
@subject.isEqualToAttributedString('test'.attrd.ligature(2)).should != true
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should have `baseline_offset`' do
|
77
|
+
@subject.isEqualToAttributedString('test'.attrd.baseline_offset(1)).should != true
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should have `kern`' do
|
81
|
+
@subject.isEqualToAttributedString('test'.attrd.kern(1)).should != true
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should have `link`' do
|
85
|
+
@subject.isEqualToAttributedString('test'.attrd.link('http://github.com'.nsurl)).should != true
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should have `stroke_width`' do
|
89
|
+
@subject.isEqualToAttributedString('test'.attrd.stroke_width(1)).should != true
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should have `stroke_color`' do
|
93
|
+
@subject.isEqualToAttributedString('test'.attrd.stroke_color(UIColor.redColor)).should != true
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should have `underline_color`' do
|
97
|
+
@subject.isEqualToAttributedString('test'.attrd.underline_color(UIColor.redColor)).should != true
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should have `strikethrough_style`' do
|
101
|
+
@subject.isEqualToAttributedString('test'.attrd.strikethrough_style(NSUnderlineStyleSingle)).should != true
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should have `strikethrough_color`' do
|
105
|
+
@subject.isEqualToAttributedString('test'.attrd.strikethrough_color(UIColor.redColor)).should != true
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should have `shadow`' do
|
109
|
+
@subject.isEqualToAttributedString('test'.attrd.shadow(NSShadow.alloc.init.tap{|s|s.shadowOffset = [1,1]})).should != true
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should have `obliqueness`' do
|
113
|
+
@subject.isEqualToAttributedString('test'.attrd.obliqueness(0.5)).should != true
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should have `expansion`' do
|
117
|
+
@subject.isEqualToAttributedString('test'.attrd.expansion(1)).should != true
|
118
|
+
end
|
119
|
+
|
120
|
+
# don't care about:
|
121
|
+
# it 'should have `cursor`' do
|
122
|
+
# @subject.isEqualToAttributedString('test'.attrd.cursor()).should != true
|
123
|
+
# end
|
124
|
+
|
125
|
+
it 'should have `tool_tip`' do
|
126
|
+
@subject.isEqualToAttributedString('test'.attrd.tool_tip('test')).should != true
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should have `marked_clause_segment`' do
|
130
|
+
@subject.isEqualToAttributedString('test'.attrd.marked_clause_segment(1)).should != true
|
131
|
+
end
|
132
|
+
|
133
|
+
# don't care about:
|
134
|
+
# it 'should have `writing_direction`' do
|
135
|
+
# @subject.isEqualToAttributedString('test'.attrd.writing_direction()).should != true
|
136
|
+
# end
|
137
|
+
|
138
|
+
it 'should have `vertical_glyph_form`' do
|
139
|
+
@subject.isEqualToAttributedString('test'.attrd.vertical_glyph_form(1)).should != true
|
140
|
+
end
|
141
|
+
|
142
|
+
# don't care about:
|
143
|
+
# it 'should have `text_alternatives`' do
|
144
|
+
# @subject.isEqualToAttributedString('test'.attrd.text_alternatives()).should != true
|
145
|
+
# end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
data/spec/nsstring_spec.rb
CHANGED
@@ -52,9 +52,9 @@ describe "NSString" do
|
|
52
52
|
str = 'test'
|
53
53
|
str_size = str.sizeWithFont(UIFont.systemFontOfSize(UIFont.labelFontSize))
|
54
54
|
label = str.uilabel
|
55
|
-
label.size.width == str_size.width
|
56
|
-
label.size.height == str_size.height
|
57
|
-
label.backgroundColor == UIColor.clearColor
|
55
|
+
label.size.width.should == str_size.width
|
56
|
+
label.size.height.should == str_size.height
|
57
|
+
label.backgroundColor.should == UIColor.clearColor
|
58
58
|
end
|
59
59
|
|
60
60
|
it "should have a #uilabel(font) method" do
|
@@ -63,9 +63,9 @@ describe "NSString" do
|
|
63
63
|
str_size = str.sizeWithFont(font)
|
64
64
|
label = str.uilabel(font)
|
65
65
|
label.font.should == font
|
66
|
-
label.size.width == str_size.width
|
67
|
-
label.size.height == str_size.height
|
68
|
-
label.backgroundColor == UIColor.clearColor
|
66
|
+
label.size.width.should == str_size.width
|
67
|
+
label.size.height.should == str_size.height
|
68
|
+
label.backgroundColor.should == UIColor.clearColor
|
69
69
|
end
|
70
70
|
|
71
71
|
it "should have a #escape_url method" do
|
@@ -0,0 +1,61 @@
|
|
1
|
+
describe "SugarCube::AnimationChain" do
|
2
|
+
tests SugarCube::AnimationChainController
|
3
|
+
|
4
|
+
it "should have a view" do
|
5
|
+
controller.view.should != nil
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should support chains" do
|
9
|
+
SugarCube::AnimationChain.chains.length.should == 0
|
10
|
+
@variable_a = nil
|
11
|
+
@variable_b = nil
|
12
|
+
UIView.animation_chain(duration:0.1){
|
13
|
+
@variable_a = 'a'
|
14
|
+
}.and_then(duration: 0.1){
|
15
|
+
@variable_b = 'b'
|
16
|
+
}.start
|
17
|
+
SugarCube::AnimationChain.chains.length.should == 1
|
18
|
+
|
19
|
+
wait 0.3 {
|
20
|
+
@variable_a.should == 'a'
|
21
|
+
@variable_b.should == 'b'
|
22
|
+
SugarCube::AnimationChain.chains.length.should == 0
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should support multiple chains" do
|
27
|
+
SugarCube::AnimationChain.chains.length.should == 0
|
28
|
+
@variable_a = nil
|
29
|
+
@variable_b = nil
|
30
|
+
UIView.animation_chain(duration:0.1, delay:0.1){
|
31
|
+
@variable_a = 'a'
|
32
|
+
}.start
|
33
|
+
UIView.animation_chain(duration:0.1, delay:0.1){
|
34
|
+
@variable_b = 'b'
|
35
|
+
}.start
|
36
|
+
SugarCube::AnimationChain.chains.length.should == 2
|
37
|
+
|
38
|
+
wait 0.3 {
|
39
|
+
@variable_a.should == 'a'
|
40
|
+
@variable_b.should == 'b'
|
41
|
+
SugarCube::AnimationChain.chains.length.should == 0
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should support << syntax" do
|
46
|
+
SugarCube::AnimationChain.chains.length.should == 0
|
47
|
+
@variable_a = nil
|
48
|
+
@variable_b = nil
|
49
|
+
chain = UIView.animation_chain
|
50
|
+
chain << proc { @variable_a = 'a' } << proc { @variable_b = 'b' }
|
51
|
+
chain.start
|
52
|
+
SugarCube::AnimationChain.chains.length.should == 1
|
53
|
+
|
54
|
+
wait 0.3 {
|
55
|
+
@variable_a.should == 'a'
|
56
|
+
@variable_b.should == 'b'
|
57
|
+
SugarCube::AnimationChain.chains.length.should == 0
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class AttrUpdatesTest < UIView
|
2
|
+
|
3
|
+
attr_updates :color
|
4
|
+
attr :did_update
|
5
|
+
|
6
|
+
def setNeedsDisplay
|
7
|
+
@did_update = true
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def reset!
|
12
|
+
@did_update = false
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'UIView##attr_updates' do
|
18
|
+
|
19
|
+
it 'should assign the ivar' do
|
20
|
+
subject = AttrUpdatesTest.new
|
21
|
+
subject.color = :red
|
22
|
+
subject.color.should == :red
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should reset did_update' do
|
26
|
+
subject = AttrUpdatesTest.new
|
27
|
+
subject.reset!
|
28
|
+
subject.did_update.should == false
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should cause setNeedsDisplay to be called' do
|
32
|
+
subject = AttrUpdatesTest.new
|
33
|
+
subject.reset!
|
34
|
+
subject.did_update.should == false
|
35
|
+
subject.color = :red # value changed from nil
|
36
|
+
subject.color.should == :red
|
37
|
+
subject.did_update.should == true
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should not cause setNeedsDisplay to be called if the value doesn\'t change' do
|
41
|
+
subject = AttrUpdatesTest.new
|
42
|
+
subject.reset!
|
43
|
+
subject.did_update.should == false
|
44
|
+
subject.color = :red # value changed from nil
|
45
|
+
subject.color.should == :red
|
46
|
+
subject.did_update.should == true
|
47
|
+
subject.reset!
|
48
|
+
subject.did_update.should == false
|
49
|
+
subject.color = :red # same value, so no update
|
50
|
+
subject.color.should == :red
|
51
|
+
subject.did_update.should == false
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/spec/unholy_spec.rb
CHANGED
@@ -4,10 +4,18 @@ describe "Sanity" do
|
|
4
4
|
:name.ivar.should == '@name'
|
5
5
|
end
|
6
6
|
|
7
|
+
it "should have Symbol#setter" do
|
8
|
+
:name.setter.should == 'name='
|
9
|
+
end
|
10
|
+
|
7
11
|
it "should have String#ivar" do
|
8
12
|
'another'.ivar.should == '@another'
|
9
13
|
end
|
10
14
|
|
15
|
+
it "should have String#setter" do
|
16
|
+
'another'.setter.should == 'another='
|
17
|
+
end
|
18
|
+
|
11
19
|
it "should have Symbol#cvar" do
|
12
20
|
:name.cvar.should == '@@name'
|
13
21
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sugarcube
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.18.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ authors:
|
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date: 2013-02-
|
16
|
+
date: 2013-02-15 00:00:00.000000000 Z
|
17
17
|
dependencies: []
|
18
18
|
description: ! '== Description
|
19
19
|
|
@@ -47,6 +47,7 @@ files:
|
|
47
47
|
- LICENSE
|
48
48
|
- README.md
|
49
49
|
- Rakefile
|
50
|
+
- app/animation_chain_controller.rb
|
50
51
|
- app/app_delegate.rb
|
51
52
|
- lib/sugarcube-568.rb
|
52
53
|
- lib/sugarcube-568/uiimage.rb
|
@@ -57,6 +58,7 @@ files:
|
|
57
58
|
- lib/sugarcube.rb
|
58
59
|
- lib/sugarcube/activesupport.rb
|
59
60
|
- lib/sugarcube/adjust.rb
|
61
|
+
- lib/sugarcube/animation_chain.rb
|
60
62
|
- lib/sugarcube/calayer.rb
|
61
63
|
- lib/sugarcube/core_graphics.rb
|
62
64
|
- lib/sugarcube/core_location.rb
|
@@ -65,6 +67,7 @@ files:
|
|
65
67
|
- lib/sugarcube/modal.rb
|
66
68
|
- lib/sugarcube/notifications.rb
|
67
69
|
- lib/sugarcube/nsarray.rb
|
70
|
+
- lib/sugarcube/nsattributedstring.rb
|
68
71
|
- lib/sugarcube/nscoder.rb
|
69
72
|
- lib/sugarcube/nsdata.rb
|
70
73
|
- lib/sugarcube/nsdate.rb
|
@@ -125,6 +128,7 @@ files:
|
|
125
128
|
- spec/fixnum_spec.rb
|
126
129
|
- spec/notification_spec.rb
|
127
130
|
- spec/nsarray_spec.rb
|
131
|
+
- spec/nsattributedstring_spec.rb
|
128
132
|
- spec/nscoder_spec.rb
|
129
133
|
- spec/nsdata_spec.rb
|
130
134
|
- spec/nsdate_spec.rb
|
@@ -138,7 +142,9 @@ files:
|
|
138
142
|
- spec/uicolor_spec.rb
|
139
143
|
- spec/uiimage_color_at_spec.rb
|
140
144
|
- spec/uiimage_scale_spec.rb
|
145
|
+
- spec/uiview_animation_chain_spec.rb
|
141
146
|
- spec/uiview_animation_spec.rb
|
147
|
+
- spec/uiview_attr_updates_spec.rb
|
142
148
|
- spec/uiview_spec.rb
|
143
149
|
- spec/unholy_spec.rb
|
144
150
|
- sugarcube.gemspec
|
@@ -177,6 +183,7 @@ test_files:
|
|
177
183
|
- spec/fixnum_spec.rb
|
178
184
|
- spec/notification_spec.rb
|
179
185
|
- spec/nsarray_spec.rb
|
186
|
+
- spec/nsattributedstring_spec.rb
|
180
187
|
- spec/nscoder_spec.rb
|
181
188
|
- spec/nsdata_spec.rb
|
182
189
|
- spec/nsdate_spec.rb
|
@@ -190,7 +197,9 @@ test_files:
|
|
190
197
|
- spec/uicolor_spec.rb
|
191
198
|
- spec/uiimage_color_at_spec.rb
|
192
199
|
- spec/uiimage_scale_spec.rb
|
200
|
+
- spec/uiview_animation_chain_spec.rb
|
193
201
|
- spec/uiview_animation_spec.rb
|
202
|
+
- spec/uiview_attr_updates_spec.rb
|
194
203
|
- spec/uiview_spec.rb
|
195
204
|
- spec/unholy_spec.rb
|
196
205
|
has_rdoc:
|