teacup 0.0.1.pre → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/.gitignore +5 -3
  2. data/CHANGES.md +26 -0
  3. data/Gemfile +2 -0
  4. data/Gemfile.lock +1 -1
  5. data/LICENSE +26 -0
  6. data/README.md +383 -95
  7. data/Rakefile +8 -36
  8. data/app/app_delegate.rb +14 -0
  9. data/app/controllers/first_controller.rb +71 -0
  10. data/app/controllers/landscape_only_controller.rb +16 -0
  11. data/app/controllers/tableview_controller.rb +0 -0
  12. data/app/styles/main_styles.rb +111 -0
  13. data/app/views/custom_view.rb +4 -0
  14. data/lib/dummy.rb +56 -0
  15. data/lib/teacup/handler.rb +99 -0
  16. data/lib/teacup/layout.rb +22 -74
  17. data/lib/teacup/merge_defaults.rb +45 -0
  18. data/lib/teacup/style.rb +93 -0
  19. data/lib/teacup/stylesheet.rb +242 -0
  20. data/lib/teacup/stylesheet_extensions/rotation.rb +38 -0
  21. data/lib/teacup/version.rb +1 -1
  22. data/lib/teacup/z_core_extensions/ca_layer.rb +6 -0
  23. data/lib/teacup/z_core_extensions/ui_view.rb +119 -0
  24. data/lib/teacup/z_core_extensions/ui_view_controller.rb +179 -0
  25. data/lib/teacup/z_core_extensions/ui_view_getters.rb +34 -0
  26. data/lib/teacup/z_core_extensions/z_handlers.rb +57 -0
  27. data/lib/teacup.rb +16 -33
  28. data/samples/Hai/Rakefile +7 -2
  29. data/samples/Hai/app/app_delegate.rb +2 -2
  30. data/samples/Hai/app/hai_controller.rb +8 -4
  31. data/samples/Hai/styles/iphone.rb +40 -0
  32. data/spec/main_spec.rb +226 -0
  33. data/spec/style_spec.rb +171 -0
  34. data/spec/stylesheet_spec.rb +348 -0
  35. data/spec/view_spec.rb +103 -0
  36. data/teacup.gemspec +13 -13
  37. metadata +47 -46
  38. data/.rspec +0 -2
  39. data/lib/teacup/contributors.rb +0 -7
  40. data/lib/teacup/core_extensions/ui_view.rb +0 -4
  41. data/lib/teacup/core_extensions/ui_view_controller.rb +0 -62
  42. data/lib/teacup/style_sheet.rb +0 -195
  43. data/lib/teacup/view.rb +0 -123
  44. data/pkg/teacup-0.0.0.gem +0 -0
  45. data/pkg/teacup-0.0.1.gem +0 -0
  46. data/proposals/other/README.md +0 -45
  47. data/proposals/other/app/config/application.rb +0 -1
  48. data/proposals/other/app/config/boot.rb +0 -1
  49. data/proposals/other/app/config/initializers/twitter.rb +0 -7
  50. data/proposals/other/app/controllers/events_controller.rb +0 -28
  51. data/proposals/other/app/controllers/venues_controller.rb +0 -4
  52. data/proposals/other/app/db/README.md +0 -16
  53. data/proposals/other/app/db/migrations/20120514201043_create_events.rb +0 -9
  54. data/proposals/other/app/db/migrations/20120514201044_add_price_to_events.rb +0 -5
  55. data/proposals/other/app/db/migrations/20120514201045_create_venues.rb +0 -8
  56. data/proposals/other/app/db/schema.rb +0 -19
  57. data/proposals/other/app/models/event.rb +0 -14
  58. data/proposals/other/app/models/venue.rb +0 -3
  59. data/proposals/other/app/views/events/edit.ipad.rb +0 -8
  60. data/proposals/other/app/views/events/edit.iphone.rb +0 -7
  61. data/proposals/other/app/views/events/show.ipad.rb +0 -2
  62. data/proposals/other/app/views/events/show.iphone.rb +0 -3
  63. data/samples/Hai/styles/ipad.rb +0 -11
  64. data/samples/Hai/styles/ipad_vertical.rb +0 -3
  65. data/spec/spec_helper.rb +0 -5
  66. data/spec/teacup/contributions_spec.rb +0 -13
  67. 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
@@ -1,5 +1,5 @@
1
1
  module Teacup
2
2
 
3
- VERSION = '0.0.1'
3
+ VERSION = '0.3.1'
4
4
 
5
5
  end
@@ -0,0 +1,6 @@
1
+ # adds the `debug` property to CALayer
2
+ class CALayer
3
+
4
+ attr_accessor :debug
5
+
6
+ end
@@ -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
+ }