teacup 0.3.12 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile.lock +1 -1
- data/README.md +40 -0
- data/Rakefile +1 -0
- data/app/app_delegate.rb +3 -1
- data/app/controllers/first_controller.rb +0 -6
- data/lib/dummy.rb +13 -0
- data/lib/teacup/constraint.rb +258 -0
- data/lib/teacup/handler.rb +6 -3
- data/lib/teacup/layout.rb +52 -9
- data/lib/teacup/restyle.rb +12 -5
- data/lib/teacup/style.rb +1 -1
- data/lib/teacup/stylesheet.rb +45 -11
- data/lib/teacup/stylesheet_extensions/autoresize.rb +39 -0
- data/lib/teacup/stylesheet_extensions/constraints.rb +69 -0
- data/lib/teacup/stylesheet_extensions/geometry.rb +75 -0
- data/lib/teacup/stylesheet_extensions/rotation.rb +1 -2
- data/lib/teacup/version.rb +1 -1
- data/lib/teacup/z_core_extensions/ui_view.rb +115 -16
- data/lib/teacup/z_core_extensions/ui_view_controller.rb +54 -26
- data/lib/teacup/z_core_extensions/ui_view_getters.rb +8 -6
- data/lib/teacup/z_core_extensions/z_handlers.rb +45 -11
- data/lib/teacup.rb +2 -0
- data/spec/main_spec.rb +139 -191
- data/teacup.gemspec +1 -0
- data/vendor/TeacupDummy/TeacupDummy.h +11 -0
- data/vendor/TeacupDummy/TeacupDummy.m +8 -0
- metadata +9 -3
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -162,6 +162,46 @@ Any method that accepts a single value can be assigned here. Please don't abuse
|
|
162
162
|
this by hiding application logic in your stylesheets - these are meant for
|
163
163
|
*design*, not behavior. That said, if you're coding by yourself - go for it! ;)
|
164
164
|
|
165
|
+
Stylesheets
|
166
|
+
===========
|
167
|
+
|
168
|
+
The `Teacup::Stylesheet` class has methods that create a micro-DSL in the
|
169
|
+
context of a `style` declaration. You can view the source (most of them are
|
170
|
+
very short methods) in `lib/teacup/stylesheet_extensions/*.rb`.
|
171
|
+
|
172
|
+
```ruby
|
173
|
+
# autoresizingMask
|
174
|
+
style :spinner,
|
175
|
+
center: [320, 460],
|
176
|
+
autoresizingMask: flexible_left|flexible_right|flexible_top|flexible_bottom
|
177
|
+
|
178
|
+
|
179
|
+
# device-specific geometries - app_size, screen_size, and device/device? methods
|
180
|
+
style :root,
|
181
|
+
origin: [0, 0],
|
182
|
+
size: app_size # doesn't include the status bar - screen_size does
|
183
|
+
|
184
|
+
if device? iPhone
|
185
|
+
style :image, image: UIImage.imageNamed "my iphone image"
|
186
|
+
elsif device? iPad
|
187
|
+
style :image, image: UIImage.imageNamed "my ipad image"
|
188
|
+
end
|
189
|
+
|
190
|
+
# the device method can be OR'd with the devices. The return value is always a
|
191
|
+
# number, so make sure to compare to 0
|
192
|
+
if device|iPhone > 0
|
193
|
+
# ...
|
194
|
+
end
|
195
|
+
# so yeah, you might as well use `device? iPhone`, in my opinion.
|
196
|
+
|
197
|
+
|
198
|
+
# rotations - use the identity and pi methods
|
199
|
+
style :button,
|
200
|
+
layer: {
|
201
|
+
transform: spin identity, 2*pi
|
202
|
+
}
|
203
|
+
```
|
204
|
+
|
165
205
|
Orientations
|
166
206
|
============
|
167
207
|
|
data/Rakefile
CHANGED
data/app/app_delegate.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
class AppDelegate
|
2
2
|
|
3
3
|
def application(application, didFinishLaunchingWithOptions:launchOptions)
|
4
|
-
|
4
|
+
return true if RUBYMOTION_ENV == 'test'
|
5
|
+
|
6
|
+
application.setStatusBarHidden(true, withAnimation:UIStatusBarAnimationSlide)
|
5
7
|
|
6
8
|
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
|
7
9
|
@window.rootViewController = FirstController.new
|
@@ -13,13 +13,7 @@ class FirstController < UIViewController
|
|
13
13
|
@button.addTarget(self, action: :next_message, forControlEvents:UIControlEventTouchUpInside)
|
14
14
|
end
|
15
15
|
|
16
|
-
# used in testing
|
17
|
-
def landscape_only
|
18
|
-
UIApplication.sharedApplication.windows[0].rootViewController = LandscapeOnlyController.alloc.init
|
19
|
-
end
|
20
|
-
|
21
16
|
def next_view
|
22
|
-
landscape_only
|
23
17
|
end
|
24
18
|
|
25
19
|
def next_message
|
data/lib/dummy.rb
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
class TeacupDummy
|
2
|
+
def anyMethodName
|
3
|
+
@anyobject.type = nil
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
1
7
|
class DummyView < UIView
|
2
8
|
private
|
3
9
|
def dummy
|
@@ -46,6 +52,13 @@ private
|
|
46
52
|
end
|
47
53
|
end
|
48
54
|
|
55
|
+
class DummyPickerView < UIPickerView
|
56
|
+
private
|
57
|
+
def dummy
|
58
|
+
setShowsSelectionIndicator(nil)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
49
62
|
class DummyLayer < CALayer
|
50
63
|
private
|
51
64
|
def dummy
|
@@ -0,0 +1,258 @@
|
|
1
|
+
module Teacup
|
2
|
+
class Constraint
|
3
|
+
attr_accessor :target
|
4
|
+
attr_accessor :attribute
|
5
|
+
attr_accessor :relationship
|
6
|
+
attr_accessor :relative_to
|
7
|
+
attr_accessor :attribute2
|
8
|
+
attr_accessor :multiplier
|
9
|
+
attr_accessor :constant
|
10
|
+
attr_accessor :priority
|
11
|
+
|
12
|
+
if defined? NSLayoutRelationEqual
|
13
|
+
Priorities = {
|
14
|
+
required: 1000, # NSLayoutPriorityRequired
|
15
|
+
high: 750, # NSLayoutPriorityDefaultHigh
|
16
|
+
low: 250, # NSLayoutPriorityDefaultLow
|
17
|
+
}
|
18
|
+
Relationships = {
|
19
|
+
equal: NSLayoutRelationEqual,
|
20
|
+
lte: NSLayoutRelationLessThanOrEqual,
|
21
|
+
gte: NSLayoutRelationGreaterThanOrEqual,
|
22
|
+
}
|
23
|
+
Attributes = {
|
24
|
+
none: NSLayoutAttributeNotAnAttribute,
|
25
|
+
left: NSLayoutAttributeLeft,
|
26
|
+
right: NSLayoutAttributeRight,
|
27
|
+
top: NSLayoutAttributeTop,
|
28
|
+
bottom: NSLayoutAttributeBottom,
|
29
|
+
leading: NSLayoutAttributeLeading,
|
30
|
+
trailing: NSLayoutAttributeTrailing,
|
31
|
+
width: NSLayoutAttributeWidth,
|
32
|
+
height: NSLayoutAttributeHeight,
|
33
|
+
center_x: NSLayoutAttributeCenterX,
|
34
|
+
center_y: NSLayoutAttributeCenterY,
|
35
|
+
baseline: NSLayoutAttributeBaseline,
|
36
|
+
}
|
37
|
+
else
|
38
|
+
Relationships = {}
|
39
|
+
Attributes = {}
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.from_sym(sym, relative_to=:superview)
|
43
|
+
case sym
|
44
|
+
when :full
|
45
|
+
[
|
46
|
+
Teacup::Constraint.new(:self, :left).equals(relative_to, :left),
|
47
|
+
Teacup::Constraint.new(:self, :top).equals(relative_to, :top),
|
48
|
+
Teacup::Constraint.new(:self, :width).equals(relative_to, :width),
|
49
|
+
Teacup::Constraint.new(:self, :height).equals(relative_to, :height),
|
50
|
+
]
|
51
|
+
when :full_width
|
52
|
+
[
|
53
|
+
Teacup::Constraint.new(:self, :left).equals(relative_to, :left),
|
54
|
+
Teacup::Constraint.new(:self, :width).equals(relative_to, :width),
|
55
|
+
]
|
56
|
+
when :full_height
|
57
|
+
[
|
58
|
+
Teacup::Constraint.new(:self, :top).equals(relative_to, :top),
|
59
|
+
Teacup::Constraint.new(:self, :height).equals(relative_to, :height),
|
60
|
+
]
|
61
|
+
when :center_x
|
62
|
+
[
|
63
|
+
Teacup::Constraint.new(:self, :center_x).equals(:superview, :center_x),
|
64
|
+
]
|
65
|
+
when :center_y
|
66
|
+
[
|
67
|
+
Teacup::Constraint.new(:self, :center_y).equals(:superview, :center_y),
|
68
|
+
]
|
69
|
+
when :centered
|
70
|
+
[
|
71
|
+
Teacup::Constraint.new(:self, :center_x).equals(:superview, :center_x),
|
72
|
+
Teacup::Constraint.new(:self, :center_y).equals(:superview, :center_y),
|
73
|
+
]
|
74
|
+
when :top
|
75
|
+
[
|
76
|
+
Teacup::Constraint.new(:self, :top).equals(relative_to, :top),
|
77
|
+
]
|
78
|
+
when :right
|
79
|
+
[
|
80
|
+
Teacup::Constraint.new(:self, :right).equals(relative_to, :right),
|
81
|
+
]
|
82
|
+
when :bottom
|
83
|
+
[
|
84
|
+
Teacup::Constraint.new(:self, :bottom).equals(relative_to, :bottom),
|
85
|
+
]
|
86
|
+
when :left
|
87
|
+
[
|
88
|
+
Teacup::Constraint.new(:self, :left).equals(relative_to, :left),
|
89
|
+
]
|
90
|
+
when :top_left
|
91
|
+
[
|
92
|
+
Teacup::Constraint.new(:self, :left).equals(relative_to, :left),
|
93
|
+
Teacup::Constraint.new(:self, :top).equals(relative_to, :top),
|
94
|
+
]
|
95
|
+
when :top_right
|
96
|
+
[
|
97
|
+
Teacup::Constraint.new(:self, :right).equals(relative_to, :right),
|
98
|
+
Teacup::Constraint.new(:self, :top).equals(relative_to, :top),
|
99
|
+
]
|
100
|
+
when :bottom_right
|
101
|
+
[
|
102
|
+
Teacup::Constraint.new(:self, :right).equals(relative_to, :right),
|
103
|
+
Teacup::Constraint.new(:self, :bottom).equals(relative_to, :bottom),
|
104
|
+
]
|
105
|
+
when :bottom_left
|
106
|
+
[
|
107
|
+
Teacup::Constraint.new(:self, :left).equals(relative_to, :left),
|
108
|
+
Teacup::Constraint.new(:self, :bottom).equals(relative_to, :bottom),
|
109
|
+
]
|
110
|
+
else
|
111
|
+
raise "Unknown symbol #{sym.inspect}"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def initialize(target=nil, attribute=nil)
|
116
|
+
self.target = target
|
117
|
+
self.attribute = attribute
|
118
|
+
self.constant = 0
|
119
|
+
self.multiplier = 1
|
120
|
+
self.priority = :high
|
121
|
+
end
|
122
|
+
|
123
|
+
def equals(relative_to, attribute2=nil)
|
124
|
+
self.set_relationship(NSLayoutRelationEqual, relative_to, attribute2)
|
125
|
+
end
|
126
|
+
|
127
|
+
def lte(relative_to, attribute2=nil)
|
128
|
+
self.set_relationship(NSLayoutRelationLessThanOrEqual, relative_to, attribute2)
|
129
|
+
end
|
130
|
+
alias at_most lte
|
131
|
+
alias is_at_most lte
|
132
|
+
|
133
|
+
def gte(relative_to, attribute2=nil)
|
134
|
+
self.set_relationship(NSLayoutRelationGreaterThanOrEqual, relative_to, attribute2)
|
135
|
+
end
|
136
|
+
alias at_least gte
|
137
|
+
alias is_at_least gte
|
138
|
+
|
139
|
+
def set_relationship(relation, relative_to, attribute2)
|
140
|
+
if attribute2.nil?
|
141
|
+
self.constant = relative_to
|
142
|
+
self.relative_to = nil
|
143
|
+
self.attribute2 = :none
|
144
|
+
else
|
145
|
+
self.relative_to = relative_to
|
146
|
+
self.attribute2 = attribute2
|
147
|
+
end
|
148
|
+
self.relationship = relation
|
149
|
+
|
150
|
+
self
|
151
|
+
end
|
152
|
+
|
153
|
+
def attribute=(attribute)
|
154
|
+
@attribute = attribute_lookup attribute
|
155
|
+
end
|
156
|
+
|
157
|
+
def attribute2=(attribute)
|
158
|
+
@attribute2 = attribute_lookup attribute
|
159
|
+
end
|
160
|
+
|
161
|
+
def times(multiplier)
|
162
|
+
self.multiplier *= multiplier
|
163
|
+
self
|
164
|
+
end
|
165
|
+
|
166
|
+
def divided_by(multiplier)
|
167
|
+
times 1.0/multiplier
|
168
|
+
end
|
169
|
+
|
170
|
+
def plus(constant)
|
171
|
+
self.constant += constant
|
172
|
+
self
|
173
|
+
end
|
174
|
+
|
175
|
+
def minus(constant)
|
176
|
+
plus -constant
|
177
|
+
end
|
178
|
+
|
179
|
+
def priority(priority=nil)
|
180
|
+
return @priority if priority.nil?
|
181
|
+
|
182
|
+
self.priority = priority
|
183
|
+
self
|
184
|
+
end
|
185
|
+
|
186
|
+
def copy
|
187
|
+
copy = Teacup::Constraint.new(self.target, self.attribute)
|
188
|
+
copy.relationship = self.relationship
|
189
|
+
copy.relative_to = self.relative_to
|
190
|
+
copy.attribute2 = self.attribute2
|
191
|
+
copy.multiplier = self.multiplier
|
192
|
+
copy.constant = self.constant
|
193
|
+
copy.priority = self.priority
|
194
|
+
copy
|
195
|
+
end
|
196
|
+
|
197
|
+
def inspect
|
198
|
+
"#<#{self.class.name} ##{object_id.to_s(16)}" +
|
199
|
+
" target=#{target.inspect}" +
|
200
|
+
" attribute=#{attribute_reverse(attribute).inspect}" +
|
201
|
+
" relationship=#{relationship_reverse(relationship).inspect}" +
|
202
|
+
" relative_to=#{relative_to.inspect}" +
|
203
|
+
" attribute2=#{attribute_reverse(attribute2).inspect}" +
|
204
|
+
" multiplier=#{multiplier.inspect}" +
|
205
|
+
" constant=#{constant.inspect}" +
|
206
|
+
">"
|
207
|
+
end
|
208
|
+
|
209
|
+
def nslayoutconstraint
|
210
|
+
NSLayoutConstraint.constraintWithItem( self.target,
|
211
|
+
attribute: self.attribute,
|
212
|
+
relatedBy: self.relationship,
|
213
|
+
toItem: self.relative_to,
|
214
|
+
attribute: self.attribute2,
|
215
|
+
multiplier: self.multiplier,
|
216
|
+
constant: self.constant
|
217
|
+
) .tap do |nsconstraint|
|
218
|
+
nsconstraint.priority = priority_lookup self.priority
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
private
|
223
|
+
def attribute_lookup(attribute)
|
224
|
+
return attribute if attribute.is_a? Fixnum
|
225
|
+
raise "Unsupported attribute #{attribute.inspect}" unless Attributes.key? attribute
|
226
|
+
Attributes[attribute]
|
227
|
+
end
|
228
|
+
|
229
|
+
def priority_lookup(priority)
|
230
|
+
return priority if priority.is_a? Fixnum
|
231
|
+
raise "Unsupported priority #{priority.inspect}" unless Priorities.key? priority
|
232
|
+
Priorities[priority]
|
233
|
+
end
|
234
|
+
|
235
|
+
def relationship_lookup(relationship)
|
236
|
+
return relationship if relationship.is_a? Fixnum
|
237
|
+
raise "Unsupported relationship #{relationship.inspect}" unless Relationships.key? relationship
|
238
|
+
Relationships[relationship]
|
239
|
+
end
|
240
|
+
|
241
|
+
def attribute_reverse(attribute)
|
242
|
+
Attributes.key(attribute) || :none
|
243
|
+
end
|
244
|
+
|
245
|
+
def relationship_reverse(relationship)
|
246
|
+
Relationships.key(relationship)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
# constraintWithItem: target
|
252
|
+
# attribute: attribute
|
253
|
+
# relatedBy: relationship
|
254
|
+
# toItem: relative_to
|
255
|
+
# attribute: attribute2
|
256
|
+
# multiplier: multiplier
|
257
|
+
# constant: constant
|
258
|
+
|
data/lib/teacup/handler.rb
CHANGED
@@ -38,6 +38,9 @@ module Teacup
|
|
38
38
|
def apply(target, key, value)
|
39
39
|
# note about `debug`: not all objects in this method are a UIView instance,
|
40
40
|
# so don't assume that the object *has* a debug method.
|
41
|
+
if value.is_a? Proc
|
42
|
+
value = target.instance_exec(&value)
|
43
|
+
end
|
41
44
|
|
42
45
|
handled = false
|
43
46
|
target.class.ancestors.each do |ancestor|
|
@@ -56,7 +59,7 @@ module Teacup
|
|
56
59
|
|
57
60
|
# you can send methods to subviews (e.g. UIButton#titleLabel) and CALayers
|
58
61
|
# (e.g. UIView#layer) by assigning a hash to a style name.
|
59
|
-
if Hash
|
62
|
+
if value.is_a? Hash
|
60
63
|
return Teacup.apply_hash target.send(key), value
|
61
64
|
end
|
62
65
|
|
@@ -64,7 +67,7 @@ module Teacup
|
|
64
67
|
assign = nil
|
65
68
|
setter = key.to_s + ':'
|
66
69
|
else
|
67
|
-
assign =
|
70
|
+
assign = key.to_s + '='
|
68
71
|
setter = 'set' + key.to_s.sub(/^./) {|c| c.capitalize} + ':'
|
69
72
|
end
|
70
73
|
|
@@ -75,7 +78,7 @@ module Teacup
|
|
75
78
|
NSLog "Calling target(#{key}, #{value.inspect})" if target.respond_to? :debug and target.debug
|
76
79
|
target.send(setter, value)
|
77
80
|
else
|
78
|
-
NSLog "
|
81
|
+
NSLog "TEACUP WARNING: Can't apply #{setter.inspect}#{assign and " or " + assign.inspect or ""} to #{target.inspect}"
|
79
82
|
end
|
80
83
|
end
|
81
84
|
|
data/lib/teacup/layout.rb
CHANGED
@@ -11,16 +11,57 @@ module Teacup
|
|
11
11
|
#
|
12
12
|
# @example
|
13
13
|
# class MyViewController < UIViewController
|
14
|
+
# stylesheet :logo
|
15
|
+
#
|
14
16
|
# layout(:my_view) do
|
15
17
|
# layout UIImage, :logo
|
16
18
|
# end
|
17
|
-
#
|
18
|
-
# def stylesheet
|
19
|
-
# Teacup::Stylesheet[:logo]
|
20
|
-
# end
|
21
19
|
# end
|
22
20
|
module Layout
|
23
|
-
|
21
|
+
# Assign a Stylesheet or Stylesheet name (Symbol)
|
22
|
+
#
|
23
|
+
# @return val
|
24
|
+
#
|
25
|
+
# @example
|
26
|
+
#
|
27
|
+
# stylesheet = Stylesheet.new do
|
28
|
+
# style :root, backgroundColor: UIColor.blueColor
|
29
|
+
# end
|
30
|
+
# controller.stylesheet = stylesheet
|
31
|
+
# # or use a stylename
|
32
|
+
# view.stylesheet = :stylesheet_name
|
33
|
+
#
|
34
|
+
def stylesheet= val
|
35
|
+
@stylesheet = val
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns a stylesheet to use to style the contents of this controller's
|
39
|
+
# view. You can also assign a stylesheet to {stylesheet=}, which will in
|
40
|
+
# turn call {restyle!}.
|
41
|
+
#
|
42
|
+
# This method will be queried each time {restyle!} is called, and also
|
43
|
+
# implicitly whenever Teacup needs to draw your layout (currently only at
|
44
|
+
# view load time).
|
45
|
+
#
|
46
|
+
# @return Teacup::Stylesheet
|
47
|
+
#
|
48
|
+
# @example
|
49
|
+
#
|
50
|
+
# def stylesheet
|
51
|
+
# if [UIInterfaceOrientationLandscapeLeft,
|
52
|
+
# UIInterfaceOrientationLandscapeRight].include?(UIInterface.currentDevice.orientation)
|
53
|
+
# Teacup::Stylesheet[:ipad]
|
54
|
+
# else
|
55
|
+
# Teacup::Stylesheet[:ipadvertical]
|
56
|
+
# end
|
57
|
+
# end
|
58
|
+
def stylesheet
|
59
|
+
if @stylesheet.is_a? Symbol
|
60
|
+
@stylesheet = Teacup::Stylesheet[@stylesheet]
|
61
|
+
end
|
62
|
+
|
63
|
+
@stylesheet
|
64
|
+
end
|
24
65
|
|
25
66
|
# Alter the layout of a view
|
26
67
|
#
|
@@ -65,7 +106,7 @@ module Teacup
|
|
65
106
|
name = nil
|
66
107
|
properties = properties_or_nil
|
67
108
|
|
68
|
-
if Hash
|
109
|
+
if name_or_properties.is_a? Hash
|
69
110
|
name = nil
|
70
111
|
properties = name_or_properties
|
71
112
|
elsif name_or_properties
|
@@ -75,7 +116,9 @@ module Teacup
|
|
75
116
|
# prevents the calling of restyle! until we return to this method
|
76
117
|
should_restyle = Teacup.should_restyle_and_block
|
77
118
|
|
78
|
-
view.stylesheet
|
119
|
+
unless view.stylesheet
|
120
|
+
view.stylesheet = stylesheet
|
121
|
+
end
|
79
122
|
view.stylename = name
|
80
123
|
if properties
|
81
124
|
view.style(properties) if properties
|
@@ -88,9 +131,8 @@ module Teacup
|
|
88
131
|
end
|
89
132
|
|
90
133
|
if should_restyle
|
91
|
-
view.restyle!
|
92
|
-
# restore to whatever it was, either nil or true
|
93
134
|
Teacup.should_restyle!
|
135
|
+
view.restyle!
|
94
136
|
end
|
95
137
|
view
|
96
138
|
end
|
@@ -165,5 +207,6 @@ module Teacup
|
|
165
207
|
def superview_chain
|
166
208
|
@superview_chain ||= []
|
167
209
|
end
|
210
|
+
|
168
211
|
end
|
169
212
|
end
|
data/lib/teacup/restyle.rb
CHANGED
@@ -1,22 +1,29 @@
|
|
1
1
|
module Teacup
|
2
2
|
module_function
|
3
3
|
|
4
|
-
def dont_restyle
|
4
|
+
def dont_restyle?
|
5
5
|
@dont_restyle ||= nil
|
6
6
|
end
|
7
7
|
|
8
8
|
def should_restyle?
|
9
|
-
return ! self.dont_restyle
|
9
|
+
return ! self.dont_restyle?
|
10
10
|
end
|
11
11
|
|
12
12
|
def should_restyle_and_block
|
13
13
|
should_restyle = self.should_restyle?
|
14
|
-
@
|
14
|
+
@dont_restyle = true
|
15
15
|
return should_restyle
|
16
16
|
end
|
17
17
|
|
18
|
-
def should_restyle!
|
19
|
-
|
18
|
+
def should_restyle! &block
|
19
|
+
if block
|
20
|
+
_dont_restyle = dont_restyle?
|
21
|
+
@dont_restyle = nil
|
22
|
+
yield
|
23
|
+
@dont_restyle = _dont_restyle
|
24
|
+
else
|
25
|
+
@dont_restyle = nil
|
26
|
+
end
|
20
27
|
end
|
21
28
|
|
22
29
|
end
|
data/lib/teacup/style.rb
CHANGED
@@ -60,7 +60,7 @@ module Teacup
|
|
60
60
|
|
61
61
|
# now we can merge extends, and importing. before merging, these will go
|
62
62
|
# through the same process that we just finished on the local style
|
63
|
-
if stylesheet
|
63
|
+
if stylesheet && stylesheet.is_a?(Teacup::Stylesheet)
|
64
64
|
stylesheet.imported_stylesheets.reverse.each do |stylesheet|
|
65
65
|
imported_properties = stylesheet.query(self.stylename, target, orientation, seen)
|
66
66
|
Teacup::merge_defaults! properties, imported_properties
|
data/lib/teacup/stylesheet.rb
CHANGED
@@ -102,7 +102,7 @@ module Teacup
|
|
102
102
|
if name
|
103
103
|
@name = name.to_sym
|
104
104
|
if Teacup::Stylesheet[@name]
|
105
|
-
NSLog("WARNING: A stylesheet with the name #{@name.inspect} has already been created.")
|
105
|
+
NSLog("TEACUP WARNING: A stylesheet with the name #{@name.inspect} has already been created.")
|
106
106
|
end
|
107
107
|
Teacup::Stylesheet[@name] = self
|
108
108
|
end
|
@@ -114,6 +114,30 @@ module Teacup
|
|
114
114
|
@block = block
|
115
115
|
end
|
116
116
|
|
117
|
+
# The stylesheet_cache stores "compiled" styles. It is reset whenever the
|
118
|
+
# stylesheet imports a new Stylesheet, and when a style entry is added or
|
119
|
+
# changed (then only that entry is removed)
|
120
|
+
#
|
121
|
+
# This method builds the gnarly hash that stores this stuff - the get/set
|
122
|
+
# methods use this method to ensure the object exists, in other places the
|
123
|
+
# @stylesheet_cache object is manipulated directly (to invalidate entries,
|
124
|
+
# or the entire cache)
|
125
|
+
def stylesheet_cache
|
126
|
+
@stylesheet_cache ||= Hash.new { |cache,_stylename|
|
127
|
+
cache[_stylename] = Hash.new { |_target,_orientation|
|
128
|
+
_target[_orientation] = {}
|
129
|
+
}
|
130
|
+
}
|
131
|
+
end
|
132
|
+
|
133
|
+
def get_stylesheet_cache(stylename, target, orientation)
|
134
|
+
stylesheet_cache[stylename][target][orientation]
|
135
|
+
end
|
136
|
+
|
137
|
+
def set_stylesheet_cache(stylename, target, orientation, value)
|
138
|
+
self.stylesheet_cache[stylename][target][orientation] = value
|
139
|
+
end
|
140
|
+
|
117
141
|
# Include another Stylesheet into this one, the rules defined
|
118
142
|
# within it will have lower precedence than those defined here
|
119
143
|
# in the case that they share the same keys.
|
@@ -138,6 +162,7 @@ module Teacup
|
|
138
162
|
# @stylesheet.import(base_stylesheet)
|
139
163
|
#
|
140
164
|
def import(name_or_stylesheet)
|
165
|
+
@stylesheet_cache = nil
|
141
166
|
imported << name_or_stylesheet
|
142
167
|
end
|
143
168
|
|
@@ -155,19 +180,25 @@ module Teacup
|
|
155
180
|
# # => {backgroundImage: UIImage.imageNamed("big_red_shiny_button"), title: "Continue!", top: 50}
|
156
181
|
def query(stylename, target=nil, orientation=nil, seen={})
|
157
182
|
return {} if seen[self]
|
183
|
+
return {} unless stylename
|
158
184
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
185
|
+
unless get_stylesheet_cache(stylename, target, orientation)
|
186
|
+
# the block handed to Stylesheet#new is not run immediately - it is run
|
187
|
+
# the first time the stylesheet is queried. This fixes bugs related to
|
188
|
+
# some resources (fonts) not available when the application is first
|
189
|
+
# started. The downside is that @instance variables and variables that
|
190
|
+
# should be closed over are not.
|
191
|
+
if @block
|
192
|
+
instance_eval &@block
|
193
|
+
@block = nil
|
194
|
+
end
|
195
|
+
seen[self] = true
|
196
|
+
|
197
|
+
set_stylesheet_cache(stylename, target, orientation, styles[stylename].build(target, orientation, seen))
|
167
198
|
end
|
168
|
-
seen[self] = true
|
169
199
|
|
170
|
-
|
200
|
+
# mutable hashes could mess with our cache, so return a duplicate
|
201
|
+
get_stylesheet_cache(stylename, target, orientation).dup
|
171
202
|
end
|
172
203
|
|
173
204
|
# Add a set of properties for a given stylename or multiple stylenames.
|
@@ -193,6 +224,9 @@ module Teacup
|
|
193
224
|
end
|
194
225
|
|
195
226
|
queries.each do |stylename|
|
227
|
+
# reset the stylesheet_cache for this stylename
|
228
|
+
@stylesheet_cache.delete(stylename) if @stylesheet_cache
|
229
|
+
|
196
230
|
# merge into styles[stylename], new properties "win"
|
197
231
|
Teacup::merge_defaults(properties, styles[stylename], styles[stylename])
|
198
232
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Example:
|
2
|
+
# Teacup::Stylesheet.new :main do
|
3
|
+
# style :root,
|
4
|
+
# # stays centered and grows in height
|
5
|
+
# autoresizingMask: left|right|height
|
6
|
+
# end
|
7
|
+
module Teacup
|
8
|
+
class Stylesheet
|
9
|
+
|
10
|
+
def none
|
11
|
+
UIViewAutoresizingNone
|
12
|
+
end
|
13
|
+
|
14
|
+
def flexible_left
|
15
|
+
UIViewAutoresizingFlexibleLeftMargin
|
16
|
+
end
|
17
|
+
|
18
|
+
def flexible_width
|
19
|
+
UIViewAutoresizingFlexibleWidth
|
20
|
+
end
|
21
|
+
|
22
|
+
def flexible_right
|
23
|
+
UIViewAutoresizingFlexibleRightMargin
|
24
|
+
end
|
25
|
+
|
26
|
+
def flexible_top
|
27
|
+
UIViewAutoresizingFlexibleTopMargin
|
28
|
+
end
|
29
|
+
|
30
|
+
def flexible_height
|
31
|
+
UIViewAutoresizingFlexibleHeight
|
32
|
+
end
|
33
|
+
|
34
|
+
def flexible_bottom
|
35
|
+
UIViewAutoresizingFlexibleBottomMargin
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|