Class: Teacup::Stylesheet
- Inherits:
-
Object
- Object
- Teacup::Stylesheet
- Defined in:
- lib/teacup/stylesheet.rb,
lib/teacup-osx/style_extensions/autoresize.rb,
lib/teacup/stylesheet_extensions/transform.rb,
lib/teacup-ios/stylesheet_extensions/device.rb,
lib/teacup/stylesheet_extensions/constraints.rb,
lib/teacup-ios/stylesheet_extensions/autoresize.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.
Direct Known Subclasses
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.
- #autoresize(&block) ⇒ Object
- #constrain(target, attribute = nil) ⇒ Object
- #constrain_above(relative_to, margin = 0) ⇒ Object
-
#constrain_below(relative_to, margin = 0) ⇒ Object
|.
- #constrain_bottom(y) ⇒ Object
- #constrain_center_x(x = 0) ⇒ Object
- #constrain_center_y(y = 0) ⇒ 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
- #exclude_instance_vars ⇒ Object
-
#extends_style?(stylename, extended_name, checked = []) ⇒ Boolean
In the [rare] case you need to know whether the style extends another style, this method will find out quickly.
- #flexible_bottom ⇒ Object
- #flexible_height ⇒ Object
-
#flexible_left ⇒ Object
| | DEPRECATED |.
- #flexible_right ⇒ Object
- #flexible_top ⇒ Object
- #flexible_width ⇒ Object
- #flip(matrix, angle) ⇒ Object
- #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.
- #import_instance_vars(from_stylesheet) ⇒ Object
-
#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
- #iPhone35 ⇒ Object
- #iPhone4 ⇒ Object
- #iPhone5 ⇒ Object
- #iPhoneRetina ⇒ 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
-
#run_block ⇒ Object
the block handed to Stylesheet#new is not run immediately - it is run the first time the stylesheet is queried.
-
#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
-
#style(*queries) ⇒ Object
Add a set of properties for a given stylename or multiple stylenames.
-
#stylesheet_cache ⇒ Object
The stylesheet_cache stores “compiled” styles.
- #transform_layer ⇒ Object
- #transform_view ⇒ Object
- #twist(matrix, angle) ⇒ Object
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.
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/teacup/stylesheet.rb', line 103 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
76 77 78 |
# File 'lib/teacup/stylesheet.rb', line 76 def [] name stylesheets[name] end |
.[]=(name, stylesheet) ⇒ Object
80 81 82 |
# File 'lib/teacup/stylesheet.rb', line 80 def []= name, stylesheet stylesheets[name] = stylesheet end |
.stylesheets ⇒ Object
72 73 74 |
# File 'lib/teacup/stylesheet.rb', line 72 def stylesheets @stylesheets ||= {} end |
Instance Method Details
#app_size ⇒ Object
returns the application frame, which takes the status bar into account
47 48 49 |
# File 'lib/teacup-ios/stylesheet_extensions/device.rb', line 47 def app_size UIScreen.mainScreen.applicationFrame.size end |
#autoresize(&block) ⇒ Object
12 13 14 15 16 17 18 19 |
# File 'lib/teacup-osx/style_extensions/autoresize.rb', line 12 def autoresize &block @@autoresize ||= Autoresize.new if block return @@autoresize.instance_exec &block else return @@autoresize end 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
65 66 67 68 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 65 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
|
60 61 62 63 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 60 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
36 37 38 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 36 def constrain_bottom(y) Teacup::Constraint.new(:self, :bottom).equals(:superview, :bottom).plus(y) end |
#constrain_center_x(x = 0) ⇒ Object
28 29 30 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 28 def constrain_center_x(x=0) Teacup::Constraint.new(:self, :center_x).equals(:superview, :center_x).plus(x) end |
#constrain_center_y(y = 0) ⇒ Object
40 41 42 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 40 def constrain_center_y(y=0) Teacup::Constraint.new(:self, :center_y).equals(:superview, :center_y).plus(y) end |
#constrain_height(height) ⇒ Object
48 49 50 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 48 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
52 53 54 55 56 57 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 52 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
75 76 77 78 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 75 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
70 71 72 73 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 70 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
32 33 34 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 32 def constrain_top(y) Teacup::Constraint.new(:self, :top).equals(:superview, :top).plus(y) end |
#constrain_width(width) ⇒ Object
44 45 46 |
# File 'lib/teacup/stylesheet_extensions/constraints.rb', line 44 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
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/teacup-ios/stylesheet_extensions/device.rb', line 52 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) && UIScreen.mainScreen.scale == 2 @@this_device |= iPhoneRetina end if UIScreen.mainScreen.bounds.size.height == 568 @@this_device |= iPhone4 else @@this_device |= iPhone35 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
79 80 81 82 |
# File 'lib/teacup-ios/stylesheet_extensions/device.rb', line 79 def device_is?(this_device) this_device = self.send(this_device) if this_device.is_a? Symbol return self.device & this_device > 0 end |
#exclude_instance_vars ⇒ Object
305 306 307 |
# File 'lib/teacup/stylesheet.rb', line 305 def exclude_instance_vars @exclude_instance_vars ||= [:@name, :@block, :@imported, :@styles, :@stylesheet_cache] end |
#extends_style?(stylename, extended_name, checked = []) ⇒ Boolean
In the [rare] case you need to know whether the style extends another style, this method will find out quickly. This is mostly useful in the ‘UIView#viewWithStylename` method.
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
# File 'lib/teacup/stylesheet.rb', line 284 def extends_style?(stylename, extended_name, checked=[]) return true if stylename == extended_name extended_style_names = styles[stylename][:extends] return false unless extended_style_names extended_style_names = [extended_style_names] unless extended_style_names.is_a? Array return true if extended_style_names.any? { |name| name == extended_name } retval = false extended_style_names.each do |recusive_check| next if checked.include?(recusive_check) checked << recusive_check if extends_style?(recusive_check, extended_name, checked) retval = true break end end return retval end |
#flexible_bottom ⇒ Object
50 51 52 53 |
# File 'lib/teacup-osx/style_extensions/autoresize.rb', line 50 def flexible_bottom NSLog("The Stylesheet method `flexible_bottom` is deprecated, use `autoresize.flexible_bottom` instead") NSViewMinYMargin end |
#flexible_height ⇒ Object
45 46 47 48 |
# File 'lib/teacup-osx/style_extensions/autoresize.rb', line 45 def flexible_height NSLog("The Stylesheet method `flexible_height` is deprecated, use `autoresize.flexible_height` instead") NSViewHeightSizable end |
#flexible_left ⇒ Object
| | DEPRECATED |
25 26 27 28 |
# File 'lib/teacup-osx/style_extensions/autoresize.rb', line 25 def flexible_left NSLog("The Stylesheet method `flexible_left` is deprecated, use `autoresize.flexible_left` instead") NSViewMinXMargin end |
#flexible_right ⇒ Object
35 36 37 38 |
# File 'lib/teacup-osx/style_extensions/autoresize.rb', line 35 def flexible_right NSLog("The Stylesheet method `flexible_right` is deprecated, use `autoresize.flexible_right` instead") NSViewMaxXMargin end |
#flexible_top ⇒ Object
40 41 42 43 |
# File 'lib/teacup-osx/style_extensions/autoresize.rb', line 40 def flexible_top NSLog("The Stylesheet method `flexible_top` is deprecated, use `autoresize.flexible_top` instead") NSViewMaxYMargin end |
#flexible_width ⇒ Object
30 31 32 33 |
# File 'lib/teacup-osx/style_extensions/autoresize.rb', line 30 def flexible_width NSLog("The Stylesheet method `flexible_width` is deprecated, use `autoresize.flexible_width` instead") NSViewWidthSizable end |
#flip(matrix, angle) ⇒ Object
22 23 24 25 |
# File 'lib/teacup/stylesheet_extensions/transform.rb', line 22 def flip(matrix, angle) NSLog("The Stylesheet method `flip` is deprecated, use `transform_layer.flip` instead") transform_layer.flip(angle) end |
#get_stylesheet_cache(stylename, target, orientation) ⇒ Object
135 136 137 |
# File 'lib/teacup/stylesheet.rb', line 135 def get_stylesheet_cache(stylename, target, orientation) self.stylesheet_cache[stylename][target][orientation] end |
#identity ⇒ Object
17 18 19 20 |
# File 'lib/teacup/stylesheet_extensions/transform.rb', line 17 def identity NSLog("The Stylesheet method `identity` is deprecated, use `transform_layer.identity` instead") transform_layer.identity 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.
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/teacup/stylesheet.rb', line 166 def import(name_or_stylesheet) @stylesheet_cache = nil imported << name_or_stylesheet sheet = nil if name_or_stylesheet.is_a? Teacup::Stylesheet sheet = name_or_stylesheet elsif Teacup::Stylesheet.stylesheets.has_key? name_or_stylesheet sheet = Teacup::Stylesheet.stylesheets[name_or_stylesheet] end if sheet import_instance_vars(sheet) end end |
#import_instance_vars(from_stylesheet) ⇒ Object
309 310 311 312 313 314 315 316 |
# File 'lib/teacup/stylesheet.rb', line 309 def import_instance_vars(from_stylesheet) from_stylesheet.run_block from_stylesheet.instance_variables.each do |var| next if exclude_instance_vars.include? var self.instance_variable_set(var, from_stylesheet.instance_variable_get(var)) end end |
#imported_stylesheets ⇒ Object
The array of Stylesheets that have been imported into this one.
267 268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/teacup/stylesheet.rb', line 267 def imported_stylesheets imported.map do |name_or_stylesheet| if name_or_stylesheet.is_a? Teacup::Stylesheet sheet = name_or_stylesheet elsif Teacup::Stylesheet.stylesheets.has_key? name_or_stylesheet sheet = 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 sheet end end |
#inspect ⇒ Object
A unique and hopefully meaningful description of this Object.
260 261 262 |
# File 'lib/teacup/stylesheet.rb', line 260 def inspect "#{self.class.name}[#{name.inspect}] = #{styles.inspect}" end |
#iPad ⇒ Object
33 |
# File 'lib/teacup-ios/stylesheet_extensions/device.rb', line 33 def iPad ; 1 << 5 ; end |
#iPadRetina ⇒ Object
34 |
# File 'lib/teacup-ios/stylesheet_extensions/device.rb', line 34 def iPadRetina ; 1 << 6 ; end |
#iPhone ⇒ Object
29 |
# File 'lib/teacup-ios/stylesheet_extensions/device.rb', line 29 def iPhone ; 1 << 1 ; end |
#iPhone35 ⇒ Object
32 |
# File 'lib/teacup-ios/stylesheet_extensions/device.rb', line 32 def iPhone35 ; 1 << 4 ; end |
#iPhone4 ⇒ Object
31 |
# File 'lib/teacup-ios/stylesheet_extensions/device.rb', line 31 def iPhone4 ; 1 << 3 ; end |
#iPhone5 ⇒ Object
36 37 38 39 |
# File 'lib/teacup-ios/stylesheet_extensions/device.rb', line 36 def iPhone5 NSLog('TEACUP WARNING: iPhone5 method is deprecated in lieu of size-based method names (iPhone4, iPhone35)') 1 << 3 end |
#iPhoneRetina ⇒ Object
30 |
# File 'lib/teacup-ios/stylesheet_extensions/device.rb', line 30 def iPhoneRetina ; 1 << 2 ; end |
#pi ⇒ Object
5 6 7 |
# File 'lib/teacup/stylesheet_extensions/transform.rb', line 5 def pi Math::PI 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.
210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/teacup/stylesheet.rb', line 210 def query(stylename, target=nil, orientation=nil, seen={}) return {} if seen[self] return {} unless stylename unless get_stylesheet_cache(stylename, target, orientation) run_block 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
37 38 39 40 |
# File 'lib/teacup/stylesheet_extensions/transform.rb', line 37 def rotate(matrix, angle, x, y, z) NSLog("The Stylesheet method `rotate` is deprecated, use `transform_layer.rotate` instead") transform_layer.rotate(angle, x, y, z) end |
#run_block ⇒ Object
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.
189 190 191 192 193 194 195 196 |
# File 'lib/teacup/stylesheet.rb', line 189 def run_block if @block _block = @block @block = nil instance_eval &_block true end end |
#screen_size ⇒ Object
returns the device size in points, regardless of status bar
42 43 44 |
# File 'lib/teacup-ios/stylesheet_extensions/device.rb', line 42 def screen_size UIScreen.mainScreen.bounds.size end |
#set_stylesheet_cache(stylename, target, orientation, value) ⇒ Object
139 140 141 |
# File 'lib/teacup/stylesheet.rb', line 139 def set_stylesheet_cache(stylename, target, orientation, value) self.stylesheet_cache[stylename][target][orientation] = value end |
#spin(matrix, angle) ⇒ Object
32 33 34 35 |
# File 'lib/teacup/stylesheet_extensions/transform.rb', line 32 def spin(matrix, angle) NSLog("The Stylesheet method `spin` is deprecated, use `transform_layer.spin` instead") transform_layer.spin(angle) end |
#style(*queries) ⇒ Object
Add a set of properties for a given stylename or multiple stylenames.
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/teacup/stylesheet.rb', line 239 def style(*queries) if queries[-1].is_a? Hash properties = queries.pop else # empty style declarations are allowed, but accomplish nothing. return end queries.each do |stylename| # reset the stylesheet_cache for this stylename @stylesheet_cache.delete(stylename) if @stylesheet_cache # merge into styles[stylename] (an instance of Teacup::Style). new # properties "win" over existing properties. 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)
127 128 129 130 131 132 133 |
# File 'lib/teacup/stylesheet.rb', line 127 def stylesheet_cache @stylesheet_cache ||= Hash.new do |cache,_stylename| cache[_stylename] = Hash.new do |_target,_orientation| _target[_orientation] = {} end end end |
#transform_layer ⇒ Object
13 14 15 |
# File 'lib/teacup/stylesheet_extensions/transform.rb', line 13 def transform_layer @@transform_layer ||= TransformLayer.new end |
#transform_view ⇒ Object
9 10 11 |
# File 'lib/teacup/stylesheet_extensions/transform.rb', line 9 def transform_view @@transform_layer ||= TransformView.new end |
#twist(matrix, angle) ⇒ Object
27 28 29 30 |
# File 'lib/teacup/stylesheet_extensions/transform.rb', line 27 def twist(matrix, angle) NSLog("The Stylesheet method `twist` is deprecated, use `transform_layer.twist` instead") transform_layer.twist(angle) end |