Class: Teacup::Stylesheet
- Inherits:
-
Object
- Object
- Teacup::Stylesheet
- Defined in:
- lib/teacup/stylesheet.rb,
lib/teacup/stylesheet_extensions/geometry.rb,
lib/teacup/stylesheet_extensions/rotation.rb,
lib/teacup/stylesheet_extensions/autoresize.rb,
lib/teacup/stylesheet_extensions/constraints.rb
Overview
Stylesheets in Teacup act as a central configuration mechanism, they have two aims:
-
Allow you to store “Details” away from the main body of your code. (controllers shouldn’t have to be filled with style rules)
-
Allow you to easily re-use configuration in many places.
The API really provides only two methods, #style to store properties on the Stylesheet; and #query to get them out again:
In addition to this, two separate mechanisms are provided for sharing configuration within stylesheets.
Firstly, if you set the ‘:extends’ property for a given stylename, then on lookup the Stylesheet will merge the properties for the ‘:extends’ stylename into the return value. Conflicts are resolved so that properties with the original stylename are resolved in its favour.
Secondly, you can import Stylesheets into each other, in exactly the same way as you can include Modules into each other in Ruby. This allows you to share rules between Stylesheets.
As you’d expect, conflicts are resolved so that the Stylesheet on which you call query has the highest precedence.
The two merging mechanisms are considered independently, so you can override a property both in a ‘:extends’ rule, and also in an imported Stylesheet. In such a a case the Stylesheet inclusion conflicts are resolved independently; and then in a second phase, the ‘:extends’ chain is flattened.
Instance Attribute Summary collapse
-
#name ⇒ Object
readonly
Returns the value of attribute name.
Class Method Summary collapse
Instance Method Summary collapse
-
#app_size ⇒ Object
returns the application frame, which takes the status bar into account.
- #constrain(target, attribute = nil) ⇒ Object
- #constrain_above(relative_to, margin = 0) ⇒ Object
-
#constrain_below(relative_to, margin = 0) ⇒ Object
|.
- #constrain_bottom(y) ⇒ Object
- #constrain_height(height) ⇒ Object
- #constrain_left(x) ⇒ Object
- #constrain_right(x) ⇒ Object
- #constrain_size(width, height) ⇒ Object
- #constrain_to_left(relative_to, margin = 0) ⇒ Object
- #constrain_to_right(relative_to, margin = 0) ⇒ Object
- #constrain_top(y) ⇒ Object
- #constrain_width(width) ⇒ Object
-
#constrain_xy(x, y) ⇒ Object
|.
-
#device ⇒ Object
returns a bit-wise OR of the device masks.
- #device_is?(this_device) ⇒ Boolean
- #flexible_bottom ⇒ Object
- #flexible_height ⇒ Object
- #flexible_left ⇒ Object
- #flexible_right ⇒ Object
- #flexible_top ⇒ Object
- #flexible_width ⇒ Object
-
#flip(matrix, angle) ⇒ Object
rotates the “up & down” direction.
- #get_stylesheet_cache(stylename, target, orientation) ⇒ Object
- #identity ⇒ Object
-
#import(name_or_stylesheet) ⇒ Object
Include another Stylesheet into this one, the rules defined within it will have lower precedence than those defined here in the case that they share the same keys.
-
#imported_stylesheets ⇒ Object
The array of Stylesheets that have been imported into this one.
-
#initialize(name = nil, &block) ⇒ Stylesheet
constructor
Create a new Stylesheet.
-
#inspect ⇒ Object
A unique and hopefully meaningful description of this Object.
- #iPad ⇒ Object
- #iPadRetina ⇒ Object
- #iPhone ⇒ Object
- #iPhone5 ⇒ Object
- #iPhoneRetina ⇒ Object
- #none ⇒ Object
- #pi ⇒ Object
-
#query(stylename, target = nil, orientation = nil, seen = {}) ⇒ Object
Get the properties defined for the given stylename, in this Stylesheet and all those that have been imported.
-
#rotate(matrix, angle, x, y, z) ⇒ Object
rotates the layer arbitrarily.
-
#screen_size ⇒ Object
returns the device size in points, regardless of status bar.
- #set_stylesheet_cache(stylename, target, orientation, value) ⇒ Object
-
#spin(matrix, angle) ⇒ Object
spins, along the z axis.
-
#style(*queries) ⇒ Object
Add a set of properties for a given stylename or multiple stylenames.
-
#stylesheet_cache ⇒ Object
The stylesheet_cache stores “compiled” styles.
-
#twist(matrix, angle) ⇒ Object
rotates the “left & right” direction.
Constructor Details
#initialize(name = nil, &block) ⇒ Stylesheet
Create a new Stylesheet.
If a name is provided then a new constant will be created using that name.
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/teacup/stylesheet.rb', line 101 def initialize(name=nil, &block) if name @name = name.to_sym if Teacup::Stylesheet[@name] NSLog("TEACUP WARNING: A stylesheet with the name #{@name.inspect} has already been created.") end Teacup::Stylesheet[@name] = self end # we just store the block for now, because some classes are not "ready" # for instance, calling `UIFont.systemFontOfSize()` will cause the # application to crash. We will lazily-load this block in `query`, and # then set it to nil. @block = block end |
Instance Attribute Details
#name ⇒ Object (readonly)
Returns the value of attribute name.
68 69 70 |
# File 'lib/teacup/stylesheet.rb', line 68 def name @name end |
Class Method Details
.[](name) ⇒ Object
75 76 77 |
# File 'lib/teacup/stylesheet.rb', line 75 def [] name stylesheets[name] end |
.[]=(name, stylesheet) ⇒ Object
79 80 81 |
# File 'lib/teacup/stylesheet.rb', line 79 def []= name, stylesheet stylesheets[name] = stylesheet end |
.stylesheets ⇒ Object
71 72 73 |
# File 'lib/teacup/stylesheet.rb', line 71 def stylesheets @stylesheets ||= {} end |
Instance Method Details
#app_size ⇒ Object
returns the application frame, which takes the status bar into account
41 42 43 |
# File 'lib/teacup/stylesheet_extensions/geometry.rb', line 41 def app_size UIScreen.mainScreen.applicationFrame.size end |
#constrain(target, attribute = nil) ⇒ Object
4 5 6 7 8 9 10 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 4 def constrain(target, attribute=nil) if attribute.nil? attribute = target target = :self end Teacup::Constraint.new(target, attribute) end |
#constrain_above(relative_to, margin = 0) ⇒ Object
57 58 59 60 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 57 def constrain_above(relative_to, margin=0) margin = 8 if margin == :auto Teacup::Constraint.new(:self, :bottom).equals(relative_to, :top).minus(margin) end |
#constrain_below(relative_to, margin = 0) ⇒ Object
|
52 53 54 55 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 52 def constrain_below(relative_to, margin=0) margin = 8 if margin == :auto Teacup::Constraint.new(:self, :top).equals(relative_to, :bottom).plus(margin) end |
#constrain_bottom(y) ⇒ Object
32 33 34 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 32 def constrain_bottom(y) Teacup::Constraint.new(:self, :bottom).equals(:superview, :bottom).plus(y) end |
#constrain_height(height) ⇒ Object
40 41 42 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 40 def constrain_height(height) Teacup::Constraint.new(:self, :height).equals(height) end |
#constrain_left(x) ⇒ Object
20 21 22 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 20 def constrain_left(x) Teacup::Constraint.new(:self, :left).equals(:superview, :left).plus(x) end |
#constrain_right(x) ⇒ Object
24 25 26 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 24 def constrain_right(x) Teacup::Constraint.new(:self, :right).equals(:superview, :right).plus(x) end |
#constrain_size(width, height) ⇒ Object
44 45 46 47 48 49 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 44 def constrain_size(width, height) [ Teacup::Constraint.new(:self, :width).equals(width), Teacup::Constraint.new(:self, :height).equals(height), ] end |
#constrain_to_left(relative_to, margin = 0) ⇒ Object
67 68 69 70 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 67 def constrain_to_left(relative_to, margin=0) margin = 20 if margin == :auto Teacup::Constraint.new(:self, :right).equals(relative_to, :left).minus(margin) end |
#constrain_to_right(relative_to, margin = 0) ⇒ Object
62 63 64 65 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 62 def constrain_to_right(relative_to, margin=0) margin = 20 if margin == :auto Teacup::Constraint.new(:self, :left).equals(relative_to, :right).plus(margin) end |
#constrain_top(y) ⇒ Object
28 29 30 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 28 def constrain_top(y) Teacup::Constraint.new(:self, :top).equals(:superview, :top).plus(y) end |
#constrain_width(width) ⇒ Object
36 37 38 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 36 def constrain_width(width) Teacup::Constraint.new(:self, :width).equals(width) end |
#constrain_xy(x, y) ⇒ Object
|
13 14 15 16 17 18 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 13 def constrain_xy(x, y) [ Teacup::Constraint.new(:self, :left).equals(:superview, :left).plus(x), Teacup::Constraint.new(:self, :top).equals(:superview, :top).plus(y), ] end |
#device ⇒ Object
returns a bit-wise OR of the device masks
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/teacup/stylesheet_extensions/geometry.rb', line 46 def device @@this_device ||= nil return @@this_device if @@this_device @@this_device = 0 if UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPhone @@this_device |= iPhone if UIScreen.mainScreen.respond_to? :scale @@this_device |= iPhoneRetina if UIScreen.mainScreen.bounds.size.height == 568 @@this_device |= iPhone5 end end else @@this_device |= iPad if UIScreen.mainScreen.respond_to? :scale @@this_device |= iPadRetina end end return @@this_device end |
#device_is?(this_device) ⇒ Boolean
69 70 71 72 |
# File 'lib/teacup/stylesheet_extensions/geometry.rb', line 69 def device_is?(this_device) this_device = self.send(this_device) if this_device.is_a? Symbol return device & this_device > 0 end |
#flexible_bottom ⇒ Object
34 35 36 |
# File 'lib/teacup/stylesheet_extensions/autoresize.rb', line 34 def flexible_bottom UIViewAutoresizingFlexibleBottomMargin end |
#flexible_height ⇒ Object
30 31 32 |
# File 'lib/teacup/stylesheet_extensions/autoresize.rb', line 30 def flexible_height UIViewAutoresizingFlexibleHeight end |
#flexible_left ⇒ Object
14 15 16 |
# File 'lib/teacup/stylesheet_extensions/autoresize.rb', line 14 def flexible_left UIViewAutoresizingFlexibleLeftMargin end |
#flexible_right ⇒ Object
22 23 24 |
# File 'lib/teacup/stylesheet_extensions/autoresize.rb', line 22 def flexible_right UIViewAutoresizingFlexibleRightMargin end |
#flexible_top ⇒ Object
26 27 28 |
# File 'lib/teacup/stylesheet_extensions/autoresize.rb', line 26 def flexible_top UIViewAutoresizingFlexibleTopMargin end |
#flexible_width ⇒ Object
18 19 20 |
# File 'lib/teacup/stylesheet_extensions/autoresize.rb', line 18 def flexible_width UIViewAutoresizingFlexibleWidth end |
#flip(matrix, angle) ⇒ Object
rotates the “up & down” direction. The bottom of the view will rotate towards the user as angle increases.
15 16 17 |
# File 'lib/teacup/stylesheet_extensions/rotation.rb', line 15 def flip matrix, angle CATransform3DRotate(matrix, angle, 1, 0, 0) end |
#get_stylesheet_cache(stylename, target, orientation) ⇒ Object
133 134 135 |
# File 'lib/teacup/stylesheet.rb', line 133 def get_stylesheet_cache(stylename, target, orientation) stylesheet_cache[stylename][target][orientation] end |
#identity ⇒ Object
5 6 7 |
# File 'lib/teacup/stylesheet_extensions/rotation.rb', line 5 def identity [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1] end |
#import(name_or_stylesheet) ⇒ Object
Include another Stylesheet into this one, the rules defined within it will have lower precedence than those defined here in the case that they share the same keys.
When defining a stylesheet declaratively, it is better to use the symbol that represents a stylesheet, as the constant may not be defined yet:
If you are using anonymous stylesheets however, then it will be necessary to pass an actual stylesheet object.
164 165 166 167 |
# File 'lib/teacup/stylesheet.rb', line 164 def import(name_or_stylesheet) @stylesheet_cache = nil imported << name_or_stylesheet end |
#imported_stylesheets ⇒ Object
The array of Stylesheets that have been imported into this one.
245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/teacup/stylesheet.rb', line 245 def imported_stylesheets imported.map do |name_or_stylesheet| if name_or_stylesheet.is_a? Teacup::Stylesheet name_or_stylesheet elsif Teacup::Stylesheet.stylesheets.has_key? name_or_stylesheet Teacup::Stylesheet.stylesheets[name_or_stylesheet] else raise "Teacup tried to import Stylesheet #{name_or_stylesheet.inspect} into Stylesheet[#{self.name.inspect}], but it didn't exist" end end end |
#inspect ⇒ Object
A unique and hopefully meaningful description of this Object.
238 239 240 |
# File 'lib/teacup/stylesheet.rb', line 238 def inspect "Teacup::Stylesheet[#{name.inspect}] = #{styles.inspect}" end |
#iPad ⇒ Object
32 |
# File 'lib/teacup/stylesheet_extensions/geometry.rb', line 32 def iPad ; 1 << 4 ; end |
#iPadRetina ⇒ Object
33 |
# File 'lib/teacup/stylesheet_extensions/geometry.rb', line 33 def iPadRetina ; 1 << 5 ; end |
#iPhone ⇒ Object
29 |
# File 'lib/teacup/stylesheet_extensions/geometry.rb', line 29 def iPhone ; 1 << 1 ; end |
#iPhone5 ⇒ Object
31 |
# File 'lib/teacup/stylesheet_extensions/geometry.rb', line 31 def iPhone5 ; 1 << 3 ; end |
#iPhoneRetina ⇒ Object
30 |
# File 'lib/teacup/stylesheet_extensions/geometry.rb', line 30 def iPhoneRetina ; 1 << 2 ; end |
#none ⇒ Object
10 11 12 |
# File 'lib/teacup/stylesheet_extensions/autoresize.rb', line 10 def none UIViewAutoresizingNone end |
#pi ⇒ Object
9 10 11 |
# File 'lib/teacup/stylesheet_extensions/rotation.rb', line 9 def pi 3.1415926 end |
#query(stylename, target = nil, orientation = nil, seen = {}) ⇒ Object
Get the properties defined for the given stylename, in this Stylesheet and all those that have been imported.
The Style class handles precedence rules, and extending via ‘:extends` and `import`. If needs the orientation in order to merge and remove the appropriate orientation styles.
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/teacup/stylesheet.rb', line 181 def query(stylename, target=nil, orientation=nil, seen={}) return {} if seen[self] return {} unless stylename unless get_stylesheet_cache(stylename, target, orientation) # the block handed to Stylesheet#new is not run immediately - it is run # the first time the stylesheet is queried. This fixes bugs related to # some resources (fonts) not available when the application is first # started. The downside is that @instance variables and variables that # should be closed over are not. if @block instance_eval &@block @block = nil end seen[self] = true set_stylesheet_cache(stylename, target, orientation, styles[stylename].build(target, orientation, seen)) end # mutable hashes could mess with our cache, so return a duplicate get_stylesheet_cache(stylename, target, orientation).dup end |
#rotate(matrix, angle, x, y, z) ⇒ Object
rotates the layer arbitrarily
32 33 34 |
# File 'lib/teacup/stylesheet_extensions/rotation.rb', line 32 def rotate matrix, angle, x, y, z CATransform3DRotate(matrix, angle, x, y, z) end |
#screen_size ⇒ Object
returns the device size in points, regardless of status bar
36 37 38 |
# File 'lib/teacup/stylesheet_extensions/geometry.rb', line 36 def screen_size UIScreen.mainScreen.bounds.size end |
#set_stylesheet_cache(stylename, target, orientation, value) ⇒ Object
137 138 139 |
# File 'lib/teacup/stylesheet.rb', line 137 def set_stylesheet_cache(stylename, target, orientation, value) self.stylesheet_cache[stylename][target][orientation] = value end |
#spin(matrix, angle) ⇒ Object
spins, along the z axis. This is probably the one you want, for “spinning” a view like you might a drink coaster or paper napkin.
27 28 29 |
# File 'lib/teacup/stylesheet_extensions/rotation.rb', line 27 def spin matrix, angle CATransform3DRotate(matrix, angle, 0, 0, 1) end |
#style(*queries) ⇒ Object
Add a set of properties for a given stylename or multiple stylenames.
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/teacup/stylesheet.rb', line 218 def style(*queries) if queries[-1].is_a? Hash properties = queries.pop else # empty style declarations are allowed return end queries.each do |stylename| # reset the stylesheet_cache for this stylename @stylesheet_cache.delete(stylename) if @stylesheet_cache # merge into styles[stylename], new properties "win" Teacup::merge_defaults(properties, styles[stylename], styles[stylename]) end end |
#stylesheet_cache ⇒ Object
The stylesheet_cache stores “compiled” styles. It is reset whenever the stylesheet imports a new Stylesheet, and when a style entry is added or changed (then only that entry is removed)
This method builds the gnarly hash that stores this stuff - the get/set methods use this method to ensure the object exists, in other places the or the entire cache)
125 126 127 128 129 130 131 |
# File 'lib/teacup/stylesheet.rb', line 125 def stylesheet_cache @stylesheet_cache ||= Hash.new { |cache,_stylename| cache[_stylename] = Hash.new { |_target,_orientation| _target[_orientation] = {} } } end |
#twist(matrix, angle) ⇒ Object
rotates the “left & right” direction. The right side of the view will rotate towards the user as angle increases.
21 22 23 |
# File 'lib/teacup/stylesheet_extensions/rotation.rb', line 21 def twist matrix, angle CATransform3DRotate(matrix, angle, 0, 1, 0) end |