teacup 0.0.1.pre → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +5 -3
- data/CHANGES.md +26 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +1 -1
- data/LICENSE +26 -0
- data/README.md +383 -95
- data/Rakefile +8 -36
- data/app/app_delegate.rb +14 -0
- data/app/controllers/first_controller.rb +71 -0
- data/app/controllers/landscape_only_controller.rb +16 -0
- data/app/controllers/tableview_controller.rb +0 -0
- data/app/styles/main_styles.rb +111 -0
- data/app/views/custom_view.rb +4 -0
- data/lib/dummy.rb +56 -0
- data/lib/teacup/handler.rb +99 -0
- data/lib/teacup/layout.rb +22 -74
- data/lib/teacup/merge_defaults.rb +45 -0
- data/lib/teacup/style.rb +93 -0
- data/lib/teacup/stylesheet.rb +242 -0
- data/lib/teacup/stylesheet_extensions/rotation.rb +38 -0
- data/lib/teacup/version.rb +1 -1
- data/lib/teacup/z_core_extensions/ca_layer.rb +6 -0
- data/lib/teacup/z_core_extensions/ui_view.rb +119 -0
- data/lib/teacup/z_core_extensions/ui_view_controller.rb +179 -0
- data/lib/teacup/z_core_extensions/ui_view_getters.rb +34 -0
- data/lib/teacup/z_core_extensions/z_handlers.rb +57 -0
- data/lib/teacup.rb +16 -33
- data/samples/Hai/Rakefile +7 -2
- data/samples/Hai/app/app_delegate.rb +2 -2
- data/samples/Hai/app/hai_controller.rb +8 -4
- data/samples/Hai/styles/iphone.rb +40 -0
- data/spec/main_spec.rb +226 -0
- data/spec/style_spec.rb +171 -0
- data/spec/stylesheet_spec.rb +348 -0
- data/spec/view_spec.rb +103 -0
- data/teacup.gemspec +13 -13
- metadata +47 -46
- data/.rspec +0 -2
- data/lib/teacup/contributors.rb +0 -7
- data/lib/teacup/core_extensions/ui_view.rb +0 -4
- data/lib/teacup/core_extensions/ui_view_controller.rb +0 -62
- data/lib/teacup/style_sheet.rb +0 -195
- data/lib/teacup/view.rb +0 -123
- data/pkg/teacup-0.0.0.gem +0 -0
- data/pkg/teacup-0.0.1.gem +0 -0
- data/proposals/other/README.md +0 -45
- data/proposals/other/app/config/application.rb +0 -1
- data/proposals/other/app/config/boot.rb +0 -1
- data/proposals/other/app/config/initializers/twitter.rb +0 -7
- data/proposals/other/app/controllers/events_controller.rb +0 -28
- data/proposals/other/app/controllers/venues_controller.rb +0 -4
- data/proposals/other/app/db/README.md +0 -16
- data/proposals/other/app/db/migrations/20120514201043_create_events.rb +0 -9
- data/proposals/other/app/db/migrations/20120514201044_add_price_to_events.rb +0 -5
- data/proposals/other/app/db/migrations/20120514201045_create_venues.rb +0 -8
- data/proposals/other/app/db/schema.rb +0 -19
- data/proposals/other/app/models/event.rb +0 -14
- data/proposals/other/app/models/venue.rb +0 -3
- data/proposals/other/app/views/events/edit.ipad.rb +0 -8
- data/proposals/other/app/views/events/edit.iphone.rb +0 -7
- data/proposals/other/app/views/events/show.ipad.rb +0 -2
- data/proposals/other/app/views/events/show.iphone.rb +0 -3
- data/samples/Hai/styles/ipad.rb +0 -11
- data/samples/Hai/styles/ipad_vertical.rb +0 -3
- data/spec/spec_helper.rb +0 -5
- data/spec/teacup/contributions_spec.rb +0 -13
- data/spec/teacup/version_spec.rb +0 -9
@@ -0,0 +1,242 @@
|
|
1
|
+
module Teacup
|
2
|
+
# Stylesheets in Teacup act as a central configuration mechanism,
|
3
|
+
# they have two aims:
|
4
|
+
#
|
5
|
+
# 1. Allow you to store "Details" away from the main body of your code.
|
6
|
+
# (controllers shouldn't have to be filled with style rules)
|
7
|
+
# 2. Allow you to easily re-use configuration in many places.
|
8
|
+
#
|
9
|
+
# The API really provides only two methods, {Stylesheet#style} to store properties
|
10
|
+
# on the Stylesheet; and {Stylesheet#query} to get them out again:
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# stylesheet = Teacup::Stylesheet.new
|
14
|
+
# stylesheet.style :buttons, :corners => :rounded
|
15
|
+
# # => nil
|
16
|
+
# stylesheet.query :buttons
|
17
|
+
# # => {:corners => :rounded}
|
18
|
+
#
|
19
|
+
# In addition to this, two separate mechanisms are provided for sharing
|
20
|
+
# configuration within stylesheets.
|
21
|
+
#
|
22
|
+
# Firstly, if you set the ':extends' property for a given stylename, then on lookup
|
23
|
+
# the Stylesheet will merge the properties for the ':extends' stylename into the return
|
24
|
+
# value. Conflicts are resolved so that properties with the original stylename
|
25
|
+
# are resolved in its favour.
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# Teacup::Stylesheet.new(:ipad) do
|
29
|
+
# style :button,
|
30
|
+
# backgroundImage: UIImage.imageNamed("big_red_shiny_button"),
|
31
|
+
# top: 100
|
32
|
+
#
|
33
|
+
# style :ok_button, extends: :button,
|
34
|
+
# title: "OK!",
|
35
|
+
# top: 200
|
36
|
+
#
|
37
|
+
# end
|
38
|
+
# Teacup::Stylesheet[:ipad].query(:ok_button)
|
39
|
+
# # => {backgroundImage: UIImage.imageNamed("big_red_shiny_button"), top: 200, title: "OK!"}
|
40
|
+
#
|
41
|
+
# Secondly, you can import Stylesheets into each other, in exactly the same way as you
|
42
|
+
# can include Modules into each other in Ruby. This allows you to share rules between
|
43
|
+
# Stylesheets.
|
44
|
+
#
|
45
|
+
# As you'd expect, conflicts are resolved so that the Stylesheet on which you
|
46
|
+
# call query has the highest precedence.
|
47
|
+
#
|
48
|
+
# @example
|
49
|
+
# Teacup::Stylesheet.new(:ipad) do
|
50
|
+
# style :ok_button,
|
51
|
+
# title: "OK!"
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# Teacup::Stylesheet.new(:ipadvertical) do
|
55
|
+
# import :ipad
|
56
|
+
# style :ok_button,
|
57
|
+
# width: 80
|
58
|
+
# end
|
59
|
+
# Teacup::Stylesheet[:ipadvertical].query(:ok_button)
|
60
|
+
# # => {title: "OK!", width: 80}
|
61
|
+
#
|
62
|
+
# The two merging mechanisms are considered independently, so you can override
|
63
|
+
# a property both in a ':extends' rule, and also in an imported Stylesheet. In such a
|
64
|
+
# a case the Stylesheet inclusion conflicts are resolved independently; and then in
|
65
|
+
# a second phase, the ':extends' chain is flattened.
|
66
|
+
#
|
67
|
+
class Stylesheet
|
68
|
+
attr_reader :name
|
69
|
+
|
70
|
+
class << self
|
71
|
+
def stylesheets
|
72
|
+
@stylesheets ||= {}
|
73
|
+
end
|
74
|
+
|
75
|
+
def [] name
|
76
|
+
stylesheets[name]
|
77
|
+
end
|
78
|
+
|
79
|
+
def []= name, stylesheet
|
80
|
+
stylesheets[name] = stylesheet
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Create a new Stylesheet.
|
85
|
+
#
|
86
|
+
# If a name is provided then a new constant will be created using that name.
|
87
|
+
#
|
88
|
+
# @param name, The (optional) name to give.
|
89
|
+
# @param &block, The body of the Stylesheet instance_eval'd.
|
90
|
+
#
|
91
|
+
# @example
|
92
|
+
# Teacup::Stylesheet.new(:ipadvertical) do
|
93
|
+
# import :ipadbase
|
94
|
+
# style :continue_button,
|
95
|
+
# top: 50
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# Teacup::Stylesheet[:ipadvertical].query(:continue_button)
|
99
|
+
# # => {top: 50}
|
100
|
+
#
|
101
|
+
def initialize(name=nil, &block)
|
102
|
+
if name
|
103
|
+
@name = name.to_sym
|
104
|
+
Teacup::Stylesheet[@name] = self
|
105
|
+
end
|
106
|
+
|
107
|
+
# we just store the block for now, because some classes are not "ready"
|
108
|
+
# for instance, calling `UIFont.systemFontOfSize()` will cause the
|
109
|
+
# application to crash. We will lazily-load this block in `query`, and
|
110
|
+
# then set it to nil.
|
111
|
+
@block = block
|
112
|
+
end
|
113
|
+
|
114
|
+
# Include another Stylesheet into this one, the rules defined
|
115
|
+
# within it will have lower precedence than those defined here
|
116
|
+
# in the case that they share the same keys.
|
117
|
+
#
|
118
|
+
# @param Symbol|Teacup::Stylesheet the name of the stylesheet,
|
119
|
+
# or the stylesheet to include.
|
120
|
+
#
|
121
|
+
# When defining a stylesheet declaratively, it is better to use the symbol
|
122
|
+
# that represents a stylesheet, as the constant may not be defined yet:
|
123
|
+
#
|
124
|
+
# @example
|
125
|
+
# Teacup::Stylesheet.new(:ipadvertical) do
|
126
|
+
# import :ipadbase
|
127
|
+
# import :verticaltweaks
|
128
|
+
# end
|
129
|
+
#
|
130
|
+
#
|
131
|
+
# If you are using anonymous stylesheets however, then it will be necessary
|
132
|
+
# to pass an actual stylesheet object.
|
133
|
+
#
|
134
|
+
# @example
|
135
|
+
# @stylesheet.import(base_stylesheet)
|
136
|
+
#
|
137
|
+
def import(name_or_stylesheet)
|
138
|
+
imported << name_or_stylesheet
|
139
|
+
end
|
140
|
+
|
141
|
+
# Get the properties defined for the given stylename, in this Stylesheet and
|
142
|
+
# all those that have been imported.
|
143
|
+
#
|
144
|
+
# The Style class handles precedence rules, and extending via `:extends` and
|
145
|
+
# `import`. If needs the orientation in order to merge and remove the
|
146
|
+
# appropriate orientation styles.
|
147
|
+
#
|
148
|
+
# @param Symbol stylename, the stylename to look up.
|
149
|
+
# @return Hash[Symbol, *] the resulting properties.
|
150
|
+
# @example
|
151
|
+
# Teacup::Stylesheet[:ipadbase].query(:continue_button)
|
152
|
+
# # => {backgroundImage: UIImage.imageNamed("big_red_shiny_button"), title: "Continue!", top: 50}
|
153
|
+
def query(stylename, target=nil, orientation=nil, seen={})
|
154
|
+
return {} if seen[self]
|
155
|
+
|
156
|
+
# the block handed to Stylesheet#new is not run immediately - it is run
|
157
|
+
# the first time the stylesheet is queried. This fixes bugs related to
|
158
|
+
# some resources (fonts) not available when the application is first
|
159
|
+
# started. The downside is that @instance variables and variables that
|
160
|
+
# should be closed over are not.
|
161
|
+
if @block
|
162
|
+
instance_eval &@block
|
163
|
+
@block = nil
|
164
|
+
end
|
165
|
+
seen[self] = true
|
166
|
+
|
167
|
+
styles[stylename].build(target, orientation, seen)
|
168
|
+
end
|
169
|
+
|
170
|
+
# Add a set of properties for a given stylename or multiple stylenames.
|
171
|
+
#
|
172
|
+
# @param Symbol, *stylename
|
173
|
+
# @param Hash[Symbol, Object], properties
|
174
|
+
#
|
175
|
+
# @example
|
176
|
+
# Teacup::Stylesheet.new(:ipadbase) do
|
177
|
+
# style :pretty_button,
|
178
|
+
# backgroundImage: UIImage.imageNamed("big_red_shiny_button")
|
179
|
+
#
|
180
|
+
# style :continue_button, extends: :pretty_button,
|
181
|
+
# title: "Continue!",
|
182
|
+
# top: 50
|
183
|
+
# end
|
184
|
+
def style(*queries)
|
185
|
+
if queries[-1].is_a? Hash
|
186
|
+
properties = queries.pop
|
187
|
+
else
|
188
|
+
# empty style declarations are allowed
|
189
|
+
return
|
190
|
+
end
|
191
|
+
|
192
|
+
queries.each do |stylename|
|
193
|
+
# merge into styles[stylename], new properties "win"
|
194
|
+
Teacup::merge_defaults(properties, styles[stylename], styles[stylename])
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# A unique and hopefully meaningful description of this Object.
|
199
|
+
#
|
200
|
+
# @return String
|
201
|
+
def inspect
|
202
|
+
"Teacup::Stylesheet[#{name.inspect}] = #{styles.inspect}"
|
203
|
+
end
|
204
|
+
|
205
|
+
# The array of Stylesheets that have been imported into this one.
|
206
|
+
#
|
207
|
+
# @return Array[Stylesheet]
|
208
|
+
def imported_stylesheets
|
209
|
+
imported.map do |name_or_stylesheet|
|
210
|
+
if name_or_stylesheet.is_a? Teacup::Stylesheet
|
211
|
+
name_or_stylesheet
|
212
|
+
elsif Teacup::Stylesheet.stylesheets.has_key? name_or_stylesheet
|
213
|
+
Teacup::Stylesheet.stylesheets[name_or_stylesheet]
|
214
|
+
else
|
215
|
+
raise "Teacup tried to import Stylesheet #{name_or_stylesheet.inspect} into Stylesheet[#{self.name.inspect}], but it didn't exist"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
protected
|
221
|
+
|
222
|
+
# The list of Stylesheets or names that have been imported into this one.
|
223
|
+
#
|
224
|
+
# @return Array[Symbol|Stylesheet]
|
225
|
+
def imported
|
226
|
+
@imported ||= []
|
227
|
+
end
|
228
|
+
|
229
|
+
# The actual contents of this stylesheet as a Hash from stylename to properties.
|
230
|
+
#
|
231
|
+
# @return Hash[Symbol, Hash]
|
232
|
+
def styles
|
233
|
+
@styles ||= Hash.new{ |_styles, stylename|
|
234
|
+
@styles[stylename] = Style.new
|
235
|
+
@styles[stylename].stylename = stylename
|
236
|
+
@styles[stylename].stylesheet = self
|
237
|
+
@styles[stylename]
|
238
|
+
}
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
242
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
module Teacup
|
3
|
+
|
4
|
+
class Stylesheet
|
5
|
+
def identity
|
6
|
+
[1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]
|
7
|
+
end
|
8
|
+
|
9
|
+
def pi
|
10
|
+
3.1415926
|
11
|
+
end
|
12
|
+
|
13
|
+
# rotates the "up & down" direction. The bottom of the view will rotate
|
14
|
+
# towards the user as angle increases.
|
15
|
+
def flip matrix, angle
|
16
|
+
CATransform3DRotate(matrix, angle, 1, 0, 0)
|
17
|
+
end
|
18
|
+
|
19
|
+
# rotates the "left & right" direction. The right side of the view will
|
20
|
+
# rotate towards the user as angle increases.
|
21
|
+
def twist matrix, angle
|
22
|
+
CATransform3DRotate(matrix, angle, 0, 1, 0)
|
23
|
+
end
|
24
|
+
|
25
|
+
# spins, along the z axis. This is probably the one you want, for
|
26
|
+
# "spinning" a view like you might a drink coaster or paper napkin.
|
27
|
+
def spin matrix, angle
|
28
|
+
CATransform3DRotate(matrix, angle, 0, 0, 1)
|
29
|
+
end
|
30
|
+
|
31
|
+
# rotates the layer arbitrarily
|
32
|
+
def rotate matrix, angle, x, y, z
|
33
|
+
CATransform3DRotate(matrix, angle, x, y, z)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
data/lib/teacup/version.rb
CHANGED
@@ -0,0 +1,119 @@
|
|
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
|
+
# Enable debug messages for this object
|
13
|
+
attr_accessor :debug
|
14
|
+
|
15
|
+
# The current stylesheet will be looked at when properties are needed. It
|
16
|
+
# is loaded lazily, so that assignment can occur before the Stylesheet has
|
17
|
+
# been created.
|
18
|
+
def stylesheet
|
19
|
+
if Symbol === @stylesheet
|
20
|
+
@stylesheet = Teacup::Stylesheet[@stylesheet]
|
21
|
+
end
|
22
|
+
|
23
|
+
@stylesheet
|
24
|
+
end
|
25
|
+
|
26
|
+
# Alter the stylename of this view.
|
27
|
+
#
|
28
|
+
# This will cause new styles to be applied from the stylesheet.
|
29
|
+
#
|
30
|
+
# @param Symbol stylename
|
31
|
+
def stylename=(new_stylename)
|
32
|
+
@stylename = new_stylename
|
33
|
+
restyle!
|
34
|
+
end
|
35
|
+
|
36
|
+
# Alter the stylesheet of this view.
|
37
|
+
#
|
38
|
+
# This will cause new styles to be applied using the current stylename,
|
39
|
+
# and will recurse into subviews.
|
40
|
+
#
|
41
|
+
# If you would prefer that a given UIView object does not inherit the
|
42
|
+
# stylesheet from its parents, override the 'stylesheet' method to
|
43
|
+
# return the correct value at all times.
|
44
|
+
#
|
45
|
+
# @param Teacup::Stylesheet stylesheet.
|
46
|
+
def stylesheet=(new_stylesheet)
|
47
|
+
@stylesheet = new_stylesheet
|
48
|
+
restyle!
|
49
|
+
subviews.each{ |subview| subview.stylesheet = new_stylesheet }
|
50
|
+
end
|
51
|
+
|
52
|
+
def restyle!(orientation=nil)
|
53
|
+
style(stylesheet.query(stylename, self, orientation)) if stylesheet
|
54
|
+
subviews.each{ |subview| subview.restyle!(orientation) }
|
55
|
+
end
|
56
|
+
|
57
|
+
# Animate a change to a new stylename.
|
58
|
+
#
|
59
|
+
# This is equivalent to wrapping a call to .stylename= inside
|
60
|
+
# UIView.beginAnimations.
|
61
|
+
#
|
62
|
+
# @param Symbol the new stylename
|
63
|
+
# @param Options the options for the animation (may include the
|
64
|
+
# duration and the curve)
|
65
|
+
#
|
66
|
+
def animate_to_stylename(stylename, options={})
|
67
|
+
return if self.stylename == stylename
|
68
|
+
|
69
|
+
UIView.beginAnimations(nil, context: nil)
|
70
|
+
# TODO: This should be in a style-sheet!
|
71
|
+
UIView.setAnimationDuration(options[:duration]) if options[:duration]
|
72
|
+
UIView.setAnimationCurve(options[:curve]) if options[:curve]
|
73
|
+
self.stylename = stylename
|
74
|
+
UIView.commitAnimations
|
75
|
+
end
|
76
|
+
|
77
|
+
# Animate a change to new styles
|
78
|
+
#
|
79
|
+
# This is equivalent to wrapping a call to .style() inside
|
80
|
+
# UIView.beginAnimations.
|
81
|
+
#
|
82
|
+
# @param Hash the new styles and options for the animation
|
83
|
+
#
|
84
|
+
def animate_to_style(style)
|
85
|
+
UIView.beginAnimations(nil, context: nil)
|
86
|
+
UIView.setAnimationDuration(style[:duration]) if style[:duration]
|
87
|
+
UIView.setAnimationCurve(style[:curve]) if style[:curve]
|
88
|
+
style(style)
|
89
|
+
UIView.commitAnimations
|
90
|
+
end
|
91
|
+
|
92
|
+
# Apply style properties to this element.
|
93
|
+
#
|
94
|
+
# Takes a hash of properties such as may have been read from a stylesheet
|
95
|
+
# or passed as parameters to {Teacup::Layout#layout}, and applies them to
|
96
|
+
# the element.
|
97
|
+
#
|
98
|
+
# Does a little bit of magic (that may be split out as 'sugarcube') to
|
99
|
+
# make properties work as you'd expect.
|
100
|
+
#
|
101
|
+
# If you try and assign something in properties that is not supported,
|
102
|
+
# a warning message will be emitted.
|
103
|
+
#
|
104
|
+
# @param Hash the properties to set.
|
105
|
+
def style(properties, orientation=nil)
|
106
|
+
Teacup.apply_hash self, properties
|
107
|
+
properties.each do |key, value|
|
108
|
+
Teacup.apply self, key, value
|
109
|
+
end
|
110
|
+
|
111
|
+
self.setNeedsDisplay
|
112
|
+
self.setNeedsLayout
|
113
|
+
end
|
114
|
+
|
115
|
+
def top_level_view
|
116
|
+
return self
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
@@ -0,0 +1,179 @@
|
|
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
|
+
# Returns a stylesheet to use to style the contents of this controller's
|
57
|
+
# view. You can also assign a stylesheet to {stylesheet=}, which will in
|
58
|
+
# turn call {restyle!}.
|
59
|
+
#
|
60
|
+
# This method will be queried each time {restyle!} is called, and also
|
61
|
+
# implicitly whenever Teacup needs to draw your layout (currently only at
|
62
|
+
# view load time).
|
63
|
+
#
|
64
|
+
# @return Teacup::Stylesheet
|
65
|
+
#
|
66
|
+
# @example
|
67
|
+
#
|
68
|
+
# def stylesheet
|
69
|
+
# if [UIDeviceOrientationLandscapeLeft,
|
70
|
+
# UIDeviceOrientationLandscapeRight].include?(UIDevice.currentDevice.orientation)
|
71
|
+
# Teacup::Stylesheet[:ipad]
|
72
|
+
# else
|
73
|
+
# Teacup::Stylesheet[:ipadvertical]
|
74
|
+
# end
|
75
|
+
# end
|
76
|
+
def stylesheet
|
77
|
+
@stylesheet
|
78
|
+
end
|
79
|
+
|
80
|
+
# Assigning a new stylesheet triggers {restyle!}, so do this during a
|
81
|
+
# rotation to get your different layouts applied.
|
82
|
+
#
|
83
|
+
# Assigning a stylesheet is an *alternative* to returning a Stylesheet in
|
84
|
+
# the {stylesheet} method. Note that {restyle!} calls {stylesheet}, so while
|
85
|
+
# assigning a stylesheet will trigger {restyle!}, your stylesheet will not
|
86
|
+
# be picked up if you don't return it in a custom stylesheet method.
|
87
|
+
#
|
88
|
+
# @return Teacup::Stylesheet
|
89
|
+
#
|
90
|
+
# @example
|
91
|
+
#
|
92
|
+
# stylesheet = Teacup::Stylesheet[:ipadhorizontal]
|
93
|
+
# stylesheet = :ipadhorizontal
|
94
|
+
def stylesheet=(new_stylesheet)
|
95
|
+
@stylesheet = new_stylesheet
|
96
|
+
if view
|
97
|
+
view.stylesheet = new_stylesheet
|
98
|
+
view.restyle!
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def top_level_view
|
103
|
+
return self.view
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
# Instantiate the layout from the class, and then call layoutDidLoad.
|
108
|
+
#
|
109
|
+
# If you want to use Teacup in your controller, please hook into layoutDidLoad,
|
110
|
+
# not viewDidLoad.
|
111
|
+
def viewDidLoad
|
112
|
+
|
113
|
+
if not self.stylesheet
|
114
|
+
self.stylesheet = self.class.stylesheet
|
115
|
+
end
|
116
|
+
|
117
|
+
if self.class.layout_definition
|
118
|
+
stylename, properties, block = self.class.layout_definition
|
119
|
+
layout(view, stylename, properties, &block)
|
120
|
+
end
|
121
|
+
|
122
|
+
layoutDidLoad
|
123
|
+
end
|
124
|
+
|
125
|
+
def viewWillAppear(animated)
|
126
|
+
self.view.restyle!
|
127
|
+
end
|
128
|
+
|
129
|
+
def layoutDidLoad
|
130
|
+
true
|
131
|
+
end
|
132
|
+
|
133
|
+
# The compiling mechanisms combined with how UIKit works of rubymotion do
|
134
|
+
# not allow the `shouldAutorotateToInterfaceOrientation` method to be
|
135
|
+
# overridden in modules/extensions. So instead, HERE is the code for what
|
136
|
+
# `shouldAutorotateToInterfaceOrientation` should look like if you want
|
137
|
+
# to use the teacup rotation stuff. Call this method from your own
|
138
|
+
# `shouldAutorotateToInterfaceOrientation` method.
|
139
|
+
#
|
140
|
+
# the teacup developers apologize for any inconvenience. :-)
|
141
|
+
def autorotateToOrientation(orientation)
|
142
|
+
if view.stylesheet and view.stylename
|
143
|
+
properties = view.stylesheet.query(view.stylename, self, orientation)
|
144
|
+
|
145
|
+
# check for orientation-specific properties
|
146
|
+
case orientation
|
147
|
+
when UIInterfaceOrientationPortrait
|
148
|
+
# portrait is "on" by default, must be turned off explicitly
|
149
|
+
if properties.supports?(:portrait) == nil and properties.supports?(:upside_up) == nil
|
150
|
+
return true
|
151
|
+
end
|
152
|
+
|
153
|
+
return (properties.supports?(:portrait) or properties.supports?(:upside_up))
|
154
|
+
when UIInterfaceOrientationPortraitUpsideDown
|
155
|
+
if UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPhone
|
156
|
+
# iphone must have an explicit upside-down style, otherwise this returns
|
157
|
+
# false
|
158
|
+
return properties.supports?(:upside_down)
|
159
|
+
else
|
160
|
+
# ipad can just have a portrait style
|
161
|
+
return (properties.supports?(:portrait) or properties.supports?(:upside_down))
|
162
|
+
end
|
163
|
+
when UIInterfaceOrientationLandscapeLeft
|
164
|
+
return (properties.supports?(:landscape) or properties.supports?(:landscape_left))
|
165
|
+
when UIInterfaceOrientationLandscapeRight
|
166
|
+
return (properties.supports?(:landscape) or properties.supports?(:landscape_right))
|
167
|
+
end
|
168
|
+
|
169
|
+
return false
|
170
|
+
end
|
171
|
+
|
172
|
+
return orientation == UIInterfaceOrientationPortrait
|
173
|
+
end
|
174
|
+
|
175
|
+
def willAnimateRotationToInterfaceOrientation(orientation, duration:duration)
|
176
|
+
view.restyle!(orientation)
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Methods to retrieve a subview using the stylename as a key
|
2
|
+
# Kinda similar to jQuery-style $().find('stylename')
|
3
|
+
class UIView
|
4
|
+
|
5
|
+
# get one stylesheet by stylename
|
6
|
+
# my_view[:button] :button => #<UIButton..>
|
7
|
+
def viewWithStylename name
|
8
|
+
subviews.each do |view|
|
9
|
+
if view.stylename == name
|
10
|
+
return view
|
11
|
+
end
|
12
|
+
end
|
13
|
+
subviews.each do |view|
|
14
|
+
if v = view.viewWithStylename(name)
|
15
|
+
return v
|
16
|
+
end
|
17
|
+
end
|
18
|
+
nil # couldn't find it
|
19
|
+
end
|
20
|
+
|
21
|
+
# get stylesheets by stylename
|
22
|
+
# my_view.all :button => [#<UIButton..>, #<UIButton...>]
|
23
|
+
def viewsWithStylename name
|
24
|
+
r = []
|
25
|
+
subviews.each do |view|
|
26
|
+
if view.stylename == name
|
27
|
+
r.push name
|
28
|
+
end
|
29
|
+
r += view.viewsWithStylename name
|
30
|
+
end
|
31
|
+
r
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
##|
|
2
|
+
##| UIView.frame
|
3
|
+
##|
|
4
|
+
Teacup.handler UIView, :left, :x { |view, x|
|
5
|
+
f = view.frame
|
6
|
+
f.origin.x = x
|
7
|
+
view.frame = f
|
8
|
+
}
|
9
|
+
|
10
|
+
Teacup.handler UIView, :right { |view, r|
|
11
|
+
f = view.frame
|
12
|
+
f.origin.x = r - f.size.width
|
13
|
+
view.frame = f
|
14
|
+
}
|
15
|
+
|
16
|
+
Teacup.handler UIView, :top, :y { |view, y|
|
17
|
+
f = view.frame
|
18
|
+
f.origin.y = y
|
19
|
+
view.frame = f
|
20
|
+
}
|
21
|
+
|
22
|
+
Teacup.handler UIView, :bottom { |view, b|
|
23
|
+
f = view.frame
|
24
|
+
f.origin.y = b - f.size.height
|
25
|
+
view.frame = f
|
26
|
+
}
|
27
|
+
|
28
|
+
Teacup.handler UIView, :width { |view, w|
|
29
|
+
f = view.frame
|
30
|
+
f.size.width = w
|
31
|
+
view.frame = f
|
32
|
+
}
|
33
|
+
|
34
|
+
Teacup.handler UIView, :height { |view, h|
|
35
|
+
f = view.frame
|
36
|
+
f.size.height = h
|
37
|
+
view.frame = f
|
38
|
+
}
|
39
|
+
|
40
|
+
Teacup.handler UIView, :origin { |view, origin|
|
41
|
+
f = view.frame
|
42
|
+
f.origin = origin
|
43
|
+
view.frame = f
|
44
|
+
}
|
45
|
+
|
46
|
+
Teacup.handler UIView, :size { |view, size|
|
47
|
+
f = view.frame
|
48
|
+
f.size = size
|
49
|
+
view.frame = f
|
50
|
+
}
|
51
|
+
|
52
|
+
##|
|
53
|
+
##| UIButton
|
54
|
+
##|
|
55
|
+
Teacup.handler UIButton, :title { |view, title|
|
56
|
+
view.setTitle(title, forState: UIControlStateNormal)
|
57
|
+
}
|