teacup 0.3.12 → 1.0.0
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 +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
|