teacup 1.3.4 → 2.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/Gemfile +1 -1
- data/Gemfile.lock +3 -3
- data/README.md +1172 -319
- data/Rakefile +8 -1
- data/app/app_delegate.rb +1 -1
- data/app/controllers/appearance_controller.rb +13 -0
- data/app/controllers/landscape_only_controller.rb +1 -1
- data/app/controllers/{first_controller.rb → main_controller.rb} +4 -3
- data/app/controllers/motion_layout_controller.rb +22 -0
- data/app/styles/appearance.rb +24 -0
- data/app/styles/main_styles.rb +8 -6
- data/app/views/custom_view.rb +1 -0
- data/lib/teacup/calculations.rb +2 -2
- data/lib/teacup/{z_core_extensions → core_extensions}/ca_layer.rb +0 -0
- data/lib/teacup/core_extensions/view_getters.rb +61 -0
- data/lib/teacup/handler.rb +14 -14
- data/lib/teacup/layout.rb +94 -17
- data/lib/teacup/stylesheet.rb +61 -26
- data/lib/teacup/stylesheet_extensions/transform.rb +88 -0
- data/lib/teacup/teacup_controller.rb +122 -0
- data/lib/teacup/teacup_util.rb +12 -7
- data/lib/teacup/teacup_view.rb +329 -0
- data/lib/teacup/version.rb +1 -1
- data/lib/teacup-ios/appearance.rb +96 -0
- data/lib/teacup-ios/core_extensions/teacup_handlers.rb +183 -0
- data/lib/teacup-ios/core_extensions/ui_view.rb +30 -0
- data/lib/teacup-ios/core_extensions/ui_view_controller.rb +110 -0
- data/lib/{dummy.rb → teacup-ios/dummy.rb} +2 -6
- data/lib/teacup-ios/handler.rb +23 -0
- data/lib/{teacup → teacup-ios}/style.rb +9 -10
- data/lib/teacup-ios/stylesheet_extensions/autoresize.rb +169 -0
- data/lib/{teacup/stylesheet_extensions/geometry.rb → teacup-ios/stylesheet_extensions/device.rb} +0 -0
- data/lib/teacup-osx/core_extensions/ns_view.rb +39 -0
- data/lib/teacup-osx/core_extensions/ns_view_controller.rb +21 -0
- data/lib/teacup-osx/core_extensions/ns_window.rb +39 -0
- data/lib/teacup-osx/core_extensions/ns_window_controller.rb +29 -0
- data/lib/{teacup/z_core_extensions/z_handlers.rb → teacup-osx/core_extensions/teacup_handlers.rb} +30 -47
- data/lib/teacup-osx/dummy.rb +80 -0
- data/lib/teacup-osx/handler.rb +16 -0
- data/lib/teacup-osx/style.rb +83 -0
- data/lib/teacup-osx/style_extensions/autoresize.rb +169 -0
- data/lib/teacup.rb +12 -11
- data/samples/Tweets/Gemfile +4 -0
- data/samples/Tweets/Gemfile.lock +16 -0
- data/samples/Tweets/README +7 -0
- data/samples/Tweets/Rakefile +9 -0
- data/samples/Tweets/app/app_delegate.rb +18 -0
- data/samples/Tweets/app/data_parser.rb +10 -0
- data/samples/Tweets/app/json_parser.rb +12 -0
- data/samples/Tweets/app/main_window.rb +99 -0
- data/samples/Tweets/app/menu.rb +108 -0
- data/samples/Tweets/app/stylesheet.rb +21 -0
- data/samples/Tweets/app/tweet.rb +11 -0
- data/samples/Tweets/resources/Credits.rtf +29 -0
- data/samples/Tweets/spec/main_spec.rb +9 -0
- data/samples/teacup-osx/.gitignore +1 -0
- data/samples/teacup-osx/Gemfile +4 -0
- data/samples/teacup-osx/Gemfile.lock +16 -0
- data/samples/teacup-osx/Rakefile +9 -0
- data/samples/teacup-osx/app/app_delegate.rb +23 -0
- data/samples/teacup-osx/app/controller.rb +11 -0
- data/samples/teacup-osx/app/menu.rb +108 -0
- data/samples/teacup-osx/app/window.rb +12 -0
- data/samples/teacup-osx/resources/Credits.rtf +29 -0
- data/samples/teacup-osx/resources/teacup.png +0 -0
- data/samples/teacup-osx/spec/main_spec.rb +9 -0
- data/spec/ios/appearance_spec.rb +18 -0
- data/spec/{calculations_spec.rb → ios/calculations_spec.rb} +0 -0
- data/spec/{constraints_spec.rb → ios/constraints_spec.rb} +0 -0
- data/spec/{custom_class_spec.rb → ios/custom_class_spec.rb} +0 -0
- data/spec/{gradient_spec.rb → ios/gradient_spec.rb} +1 -1
- data/spec/ios/layout_module_spec.rb +54 -0
- data/spec/ios/layout_spec.rb +50 -0
- data/spec/{main_spec.rb → ios/main_spec.rb} +52 -13
- data/spec/ios/motion_layout_spec.rb +44 -0
- data/spec/{present_modal_spec.rb → ios/present_modal_spec.rb} +0 -0
- data/spec/{style_spec.rb → ios/style_spec.rb} +1 -1
- data/spec/ios/stylesheet_extensions/autoresize_spec.rb +50 -0
- data/spec/{stylesheet_spec.rb → ios/stylesheet_spec.rb} +12 -0
- data/spec/{ui_view_getters_spec.rb → ios/ui_view_getters_spec.rb} +0 -0
- data/spec/{uiswitch_spec.rb → ios/uiswitch_spec.rb} +0 -0
- data/spec/{view_spec.rb → ios/view_spec.rb} +23 -2
- metadata +85 -35
- data/lib/teacup/stylesheet_extensions/autoresize.rb +0 -39
- data/lib/teacup/stylesheet_extensions/rotation.rb +0 -37
- data/lib/teacup/z_core_extensions/ui_view.rb +0 -262
- data/lib/teacup/z_core_extensions/ui_view_controller.rb +0 -263
- data/lib/teacup/z_core_extensions/ui_view_getters.rb +0 -58
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
# Teacup's UIView extensions defines some utility functions for UIView that
|
|
2
|
-
# enable a lot of the magic for Teacup::Layout.
|
|
3
|
-
|
|
4
|
-
# Users of teacup should be able to ignore the contents of this file for
|
|
5
|
-
# the most part.
|
|
6
|
-
class UIView
|
|
7
|
-
include Teacup::Layout
|
|
8
|
-
|
|
9
|
-
# The current stylename that is used to look up properties in the stylesheet.
|
|
10
|
-
attr_reader :stylename
|
|
11
|
-
|
|
12
|
-
# Any class that includes Teacup::Layout gets a `layout` method, which assigns
|
|
13
|
-
# itself as the 'teacup_next_responder'.
|
|
14
|
-
attr_accessor :teacup_next_responder
|
|
15
|
-
|
|
16
|
-
# Enable debug messages for this object
|
|
17
|
-
attr_accessor :debug
|
|
18
|
-
|
|
19
|
-
# Alter the stylename of this view.
|
|
20
|
-
#
|
|
21
|
-
# This will cause new styles to be applied from the stylesheet.
|
|
22
|
-
#
|
|
23
|
-
# @param Symbol stylename
|
|
24
|
-
def stylename=(new_stylename)
|
|
25
|
-
@stylename = new_stylename
|
|
26
|
-
restyle!
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Alter the stylesheet of this view.
|
|
30
|
-
#
|
|
31
|
-
# This will cause new styles to be applied using the current stylename,
|
|
32
|
-
# and will recurse into subviews.
|
|
33
|
-
#
|
|
34
|
-
# If you would prefer that a given UIView object does not inherit the
|
|
35
|
-
# stylesheet from its parents, override the 'stylesheet' method to
|
|
36
|
-
# return the correct value at all times.
|
|
37
|
-
#
|
|
38
|
-
# @param Teacup::Stylesheet stylesheet.
|
|
39
|
-
def stylesheet=(new_stylesheet)
|
|
40
|
-
should_restyle = Teacup.should_restyle_and_block
|
|
41
|
-
|
|
42
|
-
@stylesheet = new_stylesheet
|
|
43
|
-
|
|
44
|
-
if should_restyle
|
|
45
|
-
Teacup.should_restyle!
|
|
46
|
-
restyle!
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def stylesheet
|
|
51
|
-
if @stylesheet.is_a? Symbol
|
|
52
|
-
@stylesheet = Teacup::Stylesheet[@stylesheet]
|
|
53
|
-
end
|
|
54
|
-
# is a stylesheet assigned explicitly?
|
|
55
|
-
retval = @stylesheet
|
|
56
|
-
return retval if retval
|
|
57
|
-
|
|
58
|
-
# the 'teacup_next_responder' is assigned in the `layout` method, and links
|
|
59
|
-
# any views created there to the custom class (could be a controller, could
|
|
60
|
-
# be any class that includes Teacup::Layout). That responder is checked
|
|
61
|
-
# next, but only if it wouldn't result in a circular loop.
|
|
62
|
-
if ! retval && @teacup_next_responder && teacup_next_responder != self
|
|
63
|
-
retval = @teacup_next_responder.stylesheet
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# lastly, go up the chain; either a controller or superview
|
|
67
|
-
if ! retval && nextResponder && nextResponder.respond_to?(:stylesheet)
|
|
68
|
-
retval = nextResponder.stylesheet
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
return retval
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def restyle!(orientation=nil)
|
|
75
|
-
if Teacup.should_restyle?
|
|
76
|
-
if stylesheet && stylesheet.is_a?(Teacup::Stylesheet)
|
|
77
|
-
style(stylesheet.query(stylename, self, orientation))
|
|
78
|
-
end
|
|
79
|
-
subviews.each{ |subview| subview.restyle!(orientation) }
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def get_ns_constraints
|
|
84
|
-
# gets the array of Teacup::Constraint objects
|
|
85
|
-
my_constraints = (@teacup_constraints || []).map { |constraint, relative_to|
|
|
86
|
-
if constraint.is_a?(Teacup::Constraint)
|
|
87
|
-
constraint
|
|
88
|
-
else
|
|
89
|
-
if relative_to == true
|
|
90
|
-
Teacup::Constraint.from_sym(constraint)
|
|
91
|
-
else
|
|
92
|
-
Teacup::Constraint.from_sym(constraint, relative_to)
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
}.flatten.tap{ |my_constraints|
|
|
96
|
-
unless my_constraints.empty?
|
|
97
|
-
self.setTranslatesAutoresizingMaskIntoConstraints(false)
|
|
98
|
-
end
|
|
99
|
-
}.map do |original_constraint|
|
|
100
|
-
constraint = original_constraint.copy
|
|
101
|
-
|
|
102
|
-
case original_constraint.target
|
|
103
|
-
when UIView
|
|
104
|
-
constraint.target = original_constraint.target
|
|
105
|
-
when :self
|
|
106
|
-
constraint.target = self
|
|
107
|
-
when :superview
|
|
108
|
-
constraint.target = self.superview
|
|
109
|
-
when Symbol, String
|
|
110
|
-
container = self
|
|
111
|
-
constraint.target = nil
|
|
112
|
-
while container && constraint.target.nil?
|
|
113
|
-
constraint.target = container.viewWithStylename(original_constraint.target)
|
|
114
|
-
container = container.superview
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
case original_constraint.relative_to
|
|
119
|
-
when nil
|
|
120
|
-
constraint.relative_to = nil
|
|
121
|
-
when UIView
|
|
122
|
-
constraint.relative_to = original_constraint.relative_to
|
|
123
|
-
when :self
|
|
124
|
-
constraint.relative_to = self
|
|
125
|
-
when :superview
|
|
126
|
-
constraint.relative_to = self.superview
|
|
127
|
-
when Symbol, String
|
|
128
|
-
# TODO: this re-checks lots of views - everytime it goes up to the
|
|
129
|
-
# superview, it checks all the leaves again.
|
|
130
|
-
container = self
|
|
131
|
-
constraint.relative_to = nil
|
|
132
|
-
while container && constraint.relative_to.nil?
|
|
133
|
-
constraint.relative_to = container.viewWithStylename(original_constraint.relative_to)
|
|
134
|
-
container = container.superview
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
if original_constraint.relative_to && ! constraint.relative_to
|
|
139
|
-
puts "Could not find #{original_constraint.relative_to.inspect}"
|
|
140
|
-
container = self
|
|
141
|
-
tab = ' '
|
|
142
|
-
while container && constraint.relative_to.nil?
|
|
143
|
-
tab << '->'
|
|
144
|
-
puts "#{tab} #{container.stylename.inspect}"
|
|
145
|
-
container = container.superview
|
|
146
|
-
end
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
# the return value, for the map
|
|
150
|
-
constraint.nslayoutconstraint
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
# now add all che child constraints
|
|
154
|
-
subviews.each do |subview|
|
|
155
|
-
my_constraints.concat(subview.get_ns_constraints)
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
my_constraints
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
def apply_constraints
|
|
162
|
-
if @teacup_added_constraints
|
|
163
|
-
@teacup_added_constraints.each do |constraint|
|
|
164
|
-
self.removeConstraint(constraint)
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
@teacup_added_constraints = nil
|
|
168
|
-
all_constraints = get_ns_constraints
|
|
169
|
-
|
|
170
|
-
return if all_constraints.empty?
|
|
171
|
-
|
|
172
|
-
@teacup_added_constraints = []
|
|
173
|
-
all_constraints.each do |ns_constraint|
|
|
174
|
-
@teacup_added_constraints << ns_constraint
|
|
175
|
-
self.addConstraint(ns_constraint)
|
|
176
|
-
end
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
# Animate a change to a new stylename.
|
|
180
|
-
#
|
|
181
|
-
# This is equivalent to wrapping a call to .stylename= inside
|
|
182
|
-
# UIView.beginAnimations.
|
|
183
|
-
#
|
|
184
|
-
# @param Symbol the new stylename
|
|
185
|
-
# @param Options the options for the animation (may include the
|
|
186
|
-
# duration and the curve)
|
|
187
|
-
#
|
|
188
|
-
def animate_to_stylename(stylename, options={})
|
|
189
|
-
return if self.stylename == stylename
|
|
190
|
-
|
|
191
|
-
UIView.beginAnimations(nil, context: nil)
|
|
192
|
-
# TODO: This should be in a style-sheet!
|
|
193
|
-
UIView.setAnimationDuration(options[:duration]) if options[:duration]
|
|
194
|
-
UIView.setAnimationCurve(options[:curve]) if options[:curve]
|
|
195
|
-
UIView.setAnimationDelay(options[:delay]) if options[:delay]
|
|
196
|
-
self.stylename = stylename
|
|
197
|
-
UIView.commitAnimations
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
# Animate a change to new styles
|
|
201
|
-
#
|
|
202
|
-
# This is equivalent to wrapping a call to .style() inside
|
|
203
|
-
# UIView.beginAnimations.
|
|
204
|
-
#
|
|
205
|
-
# @param Hash the new styles and options for the animation
|
|
206
|
-
#
|
|
207
|
-
def animate_to_style(style)
|
|
208
|
-
UIView.beginAnimations(nil, context: nil)
|
|
209
|
-
UIView.setAnimationDuration(style[:duration]) if style[:duration]
|
|
210
|
-
UIView.setAnimationCurve(style[:curve]) if style[:curve]
|
|
211
|
-
UIView.setAnimationDelay(style[:delay]) if style[:delay]
|
|
212
|
-
style(style)
|
|
213
|
-
UIView.commitAnimations
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
# Apply style properties to this element.
|
|
217
|
-
#
|
|
218
|
-
# Takes a hash of properties such as may have been read from a stylesheet
|
|
219
|
-
# or passed as parameters to {Teacup::Layout#layout}, and applies them to
|
|
220
|
-
# the element.
|
|
221
|
-
#
|
|
222
|
-
# Does a little bit of magic (that may be split out as 'sugarcube') to
|
|
223
|
-
# make properties work as you'd expect.
|
|
224
|
-
#
|
|
225
|
-
# If you try and assign something in properties that is not supported,
|
|
226
|
-
# a warning message will be emitted.
|
|
227
|
-
#
|
|
228
|
-
# @param Hash the properties to set.
|
|
229
|
-
def style(properties)
|
|
230
|
-
if properties.key?(:constraints)
|
|
231
|
-
add_uniq_constraints(properties.delete(:constraints))
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
Teacup.apply_hash self, properties
|
|
235
|
-
|
|
236
|
-
self.setNeedsDisplay
|
|
237
|
-
self.setNeedsLayout
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
def top_level_view
|
|
241
|
-
return self
|
|
242
|
-
end
|
|
243
|
-
|
|
244
|
-
def add_uniq_constraints(constraint)
|
|
245
|
-
@teacup_constraints ||= {}
|
|
246
|
-
|
|
247
|
-
if constraint.is_a? Array
|
|
248
|
-
constraint.each { |constraint|
|
|
249
|
-
add_uniq_constraints(constraint)
|
|
250
|
-
}
|
|
251
|
-
elsif constraint.is_a? Hash
|
|
252
|
-
constraint.each { |sym, relative_to|
|
|
253
|
-
@teacup_constraints[sym] = relative_to
|
|
254
|
-
}
|
|
255
|
-
elsif constraint.is_a?(Teacup::Constraint) || constraint.is_a?(Symbol)
|
|
256
|
-
@teacup_constraints[constraint] = true
|
|
257
|
-
else
|
|
258
|
-
raise "Unsupported constraint: #{constraint.inspect}"
|
|
259
|
-
end
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
end
|
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
# Adds methods to the UIViewController class to make defining a layout and
|
|
2
|
-
# stylesheet very easy. Also provides rotation methods that analyze
|
|
3
|
-
class UIViewController
|
|
4
|
-
include Teacup::Layout
|
|
5
|
-
|
|
6
|
-
class << self
|
|
7
|
-
attr_reader :layout_definition
|
|
8
|
-
|
|
9
|
-
# Define the layout of a controller's view.
|
|
10
|
-
#
|
|
11
|
-
# This function is analogous to Teacup::Layout#layout, though it is
|
|
12
|
-
# designed so you can create an entire layout in a declarative manner in
|
|
13
|
-
# your controller.
|
|
14
|
-
#
|
|
15
|
-
# The hope is that this declarativeness will allow us to automatically
|
|
16
|
-
# deal with common iOS programming tasks (like releasing views when
|
|
17
|
-
# low-memory conditions occur) for you. This is still not implemented
|
|
18
|
-
# though.
|
|
19
|
-
#
|
|
20
|
-
# @param name The stylename for your controller's view.
|
|
21
|
-
#
|
|
22
|
-
# @param properties Any extra styles that you want to apply.
|
|
23
|
-
#
|
|
24
|
-
# @param &block The block in which you should define your layout.
|
|
25
|
-
# It will be instance_exec'd in the context of a
|
|
26
|
-
# controller instance.
|
|
27
|
-
#
|
|
28
|
-
# @example
|
|
29
|
-
# MyViewController < UIViewController
|
|
30
|
-
# layout :my_view do
|
|
31
|
-
# subview UILabel, title: "Test"
|
|
32
|
-
# subview UITextField, {
|
|
33
|
-
# frame: [[200, 200], [100, 100]]
|
|
34
|
-
# delegate: self
|
|
35
|
-
# }
|
|
36
|
-
# subview UIView, :shiny_thing) {
|
|
37
|
-
# subview UIView, :centre_of_shiny_thing
|
|
38
|
-
# }
|
|
39
|
-
# end
|
|
40
|
-
# end
|
|
41
|
-
#
|
|
42
|
-
def layout(stylename=nil, properties={}, &block)
|
|
43
|
-
@layout_definition = [stylename, properties, block]
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def stylesheet(new_stylesheet=nil)
|
|
47
|
-
if new_stylesheet.nil?
|
|
48
|
-
return @stylesheet
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
@stylesheet = new_stylesheet
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
end # class << self
|
|
55
|
-
|
|
56
|
-
# Assigning a new stylesheet triggers {restyle!}.
|
|
57
|
-
#
|
|
58
|
-
# Assigning a stylesheet is an *alternative* to returning a Stylesheet in
|
|
59
|
-
# the {stylesheet} method. Note that {restyle!} calls {stylesheet}, so while
|
|
60
|
-
# assigning a stylesheet will trigger {restyle!}, your stylesheet will not
|
|
61
|
-
# be picked up if you don't return it in a custom stylesheet method.
|
|
62
|
-
#
|
|
63
|
-
# @return Teacup::Stylesheet
|
|
64
|
-
#
|
|
65
|
-
# @example
|
|
66
|
-
#
|
|
67
|
-
# stylesheet = Teacup::Stylesheet[:ipadhorizontal]
|
|
68
|
-
# stylesheet = :ipadhorizontal
|
|
69
|
-
def stylesheet=(new_stylesheet)
|
|
70
|
-
super
|
|
71
|
-
if self.viewLoaded?
|
|
72
|
-
self.view.restyle!
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def top_level_view
|
|
77
|
-
return self.view
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
# Instantiate the layout from the class, and then call layoutDidLoad.
|
|
82
|
-
#
|
|
83
|
-
# If you want to use Teacup in your controller, please hook into layoutDidLoad,
|
|
84
|
-
# not viewDidLoad.
|
|
85
|
-
def viewDidLoad
|
|
86
|
-
# look for a layout_definition in the list of ancestors
|
|
87
|
-
layout_definition = nil
|
|
88
|
-
my_stylesheet = self.stylesheet
|
|
89
|
-
parent_class = self.class
|
|
90
|
-
while parent_class != NSObject and not (layout_definition && my_stylesheet)
|
|
91
|
-
if not my_stylesheet and parent_class.respond_to?(:stylesheet)
|
|
92
|
-
my_stylesheet = parent_class.stylesheet
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
if not layout_definition and parent_class.respond_to?(:layout_definition)
|
|
96
|
-
layout_definition = parent_class.layout_definition
|
|
97
|
-
end
|
|
98
|
-
parent_class = parent_class.superclass
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
should_restyle = Teacup.should_restyle_and_block
|
|
102
|
-
|
|
103
|
-
if my_stylesheet and not self.stylesheet
|
|
104
|
-
self.stylesheet = my_stylesheet
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
if layout_definition
|
|
108
|
-
stylename, properties, block = layout_definition
|
|
109
|
-
layout(view, stylename, properties, &block)
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
if should_restyle
|
|
113
|
-
Teacup.should_restyle!
|
|
114
|
-
self.view.restyle!
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
if defined? NSLayoutConstraint
|
|
118
|
-
self.view.apply_constraints
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
layoutDidLoad
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def layoutDidLoad
|
|
125
|
-
true
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
# This method *used* to be useful for the `shouldAutorotateToOrientation`
|
|
129
|
-
# method, but the iOS 6 update deprecates that method. Instead, use the
|
|
130
|
-
# `supportedInterfaceOrientations` and return `autorotateMask`.
|
|
131
|
-
def autorotateToOrientation(orientation)
|
|
132
|
-
if view.stylesheet and view.stylesheet.is_a?(Teacup::Stylesheet) and view.stylename
|
|
133
|
-
properties = view.stylesheet.query(view.stylename, self, orientation)
|
|
134
|
-
|
|
135
|
-
# check for orientation-specific properties
|
|
136
|
-
case orientation
|
|
137
|
-
when UIInterfaceOrientationPortrait
|
|
138
|
-
# portrait is "on" by default, must be turned off explicitly
|
|
139
|
-
if properties.supports?(:portrait) == nil and properties.supports?(:upside_up) == nil
|
|
140
|
-
return true
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
return (properties.supports?(:portrait) or properties.supports?(:upside_up))
|
|
144
|
-
when UIInterfaceOrientationPortraitUpsideDown
|
|
145
|
-
if UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPhone
|
|
146
|
-
# iphone must have an explicit upside-down style, otherwise this returns
|
|
147
|
-
# false
|
|
148
|
-
return properties.supports?(:upside_down)
|
|
149
|
-
else
|
|
150
|
-
# ipad can just have a portrait style
|
|
151
|
-
return (properties.supports?(:portrait) or properties.supports?(:upside_down))
|
|
152
|
-
end
|
|
153
|
-
when UIInterfaceOrientationLandscapeLeft
|
|
154
|
-
return (properties.supports?(:landscape) or properties.supports?(:landscape_left))
|
|
155
|
-
when UIInterfaceOrientationLandscapeRight
|
|
156
|
-
return (properties.supports?(:landscape) or properties.supports?(:landscape_right))
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
return false
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
# returns the system default
|
|
163
|
-
if device == UIUserInterfaceIdiomPhone
|
|
164
|
-
return orientation != UIInterfaceOrientationPortraitUpsideDown
|
|
165
|
-
else
|
|
166
|
-
return true
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
# You can use this method in `supportedInterfaceOrientations`, and it will
|
|
171
|
-
# query the stylesheet for the supported orientations, based on what
|
|
172
|
-
# orientations are defined. At a minimum, to opt-in to this feature, you'll
|
|
173
|
-
# need to define styles like `style :root, landscape: true`
|
|
174
|
-
def autorotateMask
|
|
175
|
-
device = UIDevice.currentDevice.userInterfaceIdiom
|
|
176
|
-
if view.stylesheet and view.stylesheet.is_a?(Teacup::Stylesheet) and view.stylename
|
|
177
|
-
properties = view.stylesheet.query(view.stylename, self, orientation)
|
|
178
|
-
|
|
179
|
-
orientations = 0
|
|
180
|
-
if properties.supports?(:portrait) or properties.supports?(:upside_up)
|
|
181
|
-
orientations |= UIInterfaceOrientationPortrait
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
if device == UIUserInterfaceIdiomPhone
|
|
185
|
-
# :portrait does not imply upside_down on the iphone
|
|
186
|
-
if properties.supports?(:upside_down)
|
|
187
|
-
orientations |= UIInterfaceOrientationPortraitUpsideDown
|
|
188
|
-
end
|
|
189
|
-
else
|
|
190
|
-
# but does on the ipad
|
|
191
|
-
if properties.supports?(:portrait) or properties.supports?(:upside_down)
|
|
192
|
-
orientations |= UIInterfaceOrientationPortraitUpsideDown
|
|
193
|
-
end
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
if properties.supports?(:landscape) or properties.supports?(:landscape_left)
|
|
197
|
-
orientations |= UIInterfaceOrientationLandscapeLeft
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
if properties.supports?(:landscape) or properties.supports?(:landscape_right)
|
|
201
|
-
orientations |= UIInterfaceOrientationLandscapeRight
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
if orientations == 0
|
|
205
|
-
orientations |= UIInterfaceOrientationPortrait
|
|
206
|
-
end
|
|
207
|
-
return orientations
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
# returns the system default
|
|
211
|
-
if device == UIUserInterfaceIdiomPhone
|
|
212
|
-
return UIInterfaceOrientationMaskAllButUpsideDown
|
|
213
|
-
else
|
|
214
|
-
return UIInterfaceOrientationMaskAll
|
|
215
|
-
end
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
# restyles the view! be careful about putting styles in your stylesheet that
|
|
219
|
-
# you change in your controller. anything that might change over time should
|
|
220
|
-
# be applied in your controller using `style`
|
|
221
|
-
def willAnimateRotationToInterfaceOrientation(orientation, duration:duration)
|
|
222
|
-
view.restyle!(orientation)
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
##|
|
|
226
|
-
##| Motion-Layout support
|
|
227
|
-
##|
|
|
228
|
-
|
|
229
|
-
# Calling this method uses Nick Quaranto's motion-layout gem to provide ASCII
|
|
230
|
-
# art style access to autolayout. It assigns all the subviews by stylename,
|
|
231
|
-
# and assigns `self.view` as the target view. Beyond that, it's up to you to
|
|
232
|
-
# implement the layout methods:
|
|
233
|
-
#
|
|
234
|
-
# auto do
|
|
235
|
-
# metrics 'margin' => 20
|
|
236
|
-
# vertical "|-[top]-margin-[bottom]-|"
|
|
237
|
-
# horizontal "|-margin-[top]-margin-|"
|
|
238
|
-
# horizontal "|-margin-[bottom]-margin-|"
|
|
239
|
-
# end
|
|
240
|
-
def auto(layout_view=self.view, layout_subviews={}, &layout_block)
|
|
241
|
-
raise "gem install 'motion-layout'" unless defined? Motion::Layout
|
|
242
|
-
|
|
243
|
-
Teacup.get_subviews(self.view).each do |view|
|
|
244
|
-
if view.stylename && ! layout_subviews[view.stylename.to_s]
|
|
245
|
-
layout_subviews[view.stylename.to_s] = view
|
|
246
|
-
end
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
Motion::Layout.new do |layout|
|
|
250
|
-
layout.view layout_view
|
|
251
|
-
layout.subviews layout_subviews
|
|
252
|
-
layout.instance_eval(&layout_block)
|
|
253
|
-
end
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
def Teacup.get_subviews(target)
|
|
260
|
-
[target] + target.subviews.map { |subview|
|
|
261
|
-
get_subviews(subview).select{ |v| v.stylename }
|
|
262
|
-
}.flatten
|
|
263
|
-
end
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
# Methods to retrieve a subview using the stylename as a key
|
|
2
|
-
# Kinda similar to jQuery-style $(el).find('stylename')
|
|
3
|
-
class UIView
|
|
4
|
-
|
|
5
|
-
# get one subview by stylename or class. If the receiver matches, it will be
|
|
6
|
-
# returned
|
|
7
|
-
# my_view.viewWithStylename :button => #<UIButton..>
|
|
8
|
-
# my_view.viewWithStylename UIButton => #<UIButton..>
|
|
9
|
-
def viewWithStylename name_or_class
|
|
10
|
-
return self if self._teacup_check_stylename(name_or_class)
|
|
11
|
-
|
|
12
|
-
view = subviews.find { |view| view._teacup_check_stylename(name_or_class) }
|
|
13
|
-
return view if view
|
|
14
|
-
|
|
15
|
-
# found_subview will get assigned to the view we want, but the subview is
|
|
16
|
-
# what is returned.
|
|
17
|
-
found_subview = nil
|
|
18
|
-
view = subviews.find { |subview| found_subview = subview.viewWithStylename(name_or_class) }
|
|
19
|
-
return found_subview if view
|
|
20
|
-
|
|
21
|
-
return nil # couldn't find it
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# get all subviews by stylename or class
|
|
25
|
-
# my_view.viewsWithStylename :button => [#<UIButton..>, #<UIButton...>]
|
|
26
|
-
# my_view.viewsWithStylename UIButton => [#<UIButton..>, #<UIButton...>]
|
|
27
|
-
def viewsWithStylename name_or_class
|
|
28
|
-
retval = []
|
|
29
|
-
retval << self if self._teacup_check_stylename(name_or_class)
|
|
30
|
-
|
|
31
|
-
search_views = [].concat(self.subviews)
|
|
32
|
-
# ewww, a traditional for loop! the search_views array is modified in place,
|
|
33
|
-
# and `each` and other methods don't like that.
|
|
34
|
-
index = 0
|
|
35
|
-
while index < search_views.length
|
|
36
|
-
view = search_views[index]
|
|
37
|
-
if view._teacup_check_stylename(name_or_class)
|
|
38
|
-
retval << view
|
|
39
|
-
end
|
|
40
|
-
search_views.concat(view.subviews)
|
|
41
|
-
index += 1
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
return retval
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def _teacup_check_stylename(name_or_class)
|
|
48
|
-
if name_or_class.is_a? Class
|
|
49
|
-
return self.is_a?(name_or_class)
|
|
50
|
-
elsif stylename == name_or_class
|
|
51
|
-
return true
|
|
52
|
-
elsif stylesheet.is_a?(Teacup::Stylesheet)
|
|
53
|
-
return stylesheet.extends_style?(self.stylename, name_or_class)
|
|
54
|
-
end
|
|
55
|
-
return false
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
end
|