Class: Teacup::Stylesheet

Inherits:
Object
  • Object
show all
Defined in:
lib/teacup/stylesheet.rb,
lib/teacup/stylesheet_extensions/rotation.rb

Overview

Stylesheets in Teacup act as a central configuration mechanism, they have two aims:

  1. Allow you to store "Details" away from the main body of your code. (controllers shouldn't have to be filled with style rules)

  2. 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.

Examples:

stylesheet = Teacup::Stylesheet.new
stylesheet.style :buttons, :corners => :rounded
# => nil
stylesheet.query :buttons
# => {:corners => :rounded}
Teacup::Stylesheet.new(:ipad) do
  style :button,
    backgroundImage: UIImage.imageNamed("big_red_shiny_button"),
    top: 100

  style :ok_button, extends: :button,
    title: "OK!",
    top: 200

end
Teacup::Stylesheet[:ipad].query(:ok_button)
# => {backgroundImage: UIImage.imageNamed("big_red_shiny_button"), top: 200, title: "OK!"}
Teacup::Stylesheet.new(:ipad) do
  style :ok_button,
    title: "OK!"
end

Teacup::Stylesheet.new(:ipadvertical) do
  import :ipad
  style :ok_button,
    width: 80
end
Teacup::Stylesheet[:ipadvertical].query(:ok_button)
# => {title: "OK!", width: 80}

Instance Attribute Summary (collapse)

Class Method Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (Stylesheet) initialize(name = nil, &block)

Create a new Stylesheet.

If a name is provided then a new constant will be created using that name.

Examples:

Teacup::Stylesheet.new(:ipadvertical) do
  import :ipadbase
  style :continue_button,
     top: 50
end

Teacup::Stylesheet[:ipadvertical].query(:continue_button)
# => {top: 50}

Parameters:

  • name,

    The (optional) name to give.

  • &block,

    The body of the Stylesheet instance_eval'd.



101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/teacup/stylesheet.rb', line 101

def initialize(name=nil, &block)
  if name
    @name = name.to_sym
    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

- (Object) name (readonly)

Returns the value of attribute name



68
69
70
# File 'lib/teacup/stylesheet.rb', line 68

def name
  @name
end

Class Method Details

+ (Object) [](name)



75
76
77
# File 'lib/teacup/stylesheet.rb', line 75

def [] name
  stylesheets[name]
end

+ (Object) []=(name, stylesheet)



79
80
81
# File 'lib/teacup/stylesheet.rb', line 79

def []= name, stylesheet
  stylesheets[name] = stylesheet
end

+ (Object) stylesheets



71
72
73
# File 'lib/teacup/stylesheet.rb', line 71

def stylesheets
  @stylesheets ||= {}
end

Instance Method Details

- (Object) flip(matrix, angle)

rotates the "up & down" direction



14
15
16
# File 'lib/teacup/stylesheet_extensions/rotation.rb', line 14

def flip matrix, angle
  CATransform3DRotate(matrix, angle, 1, 0, 0)
end

- (Object) identity



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

- (Object) import(name_or_stylesheet)

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.

Examples:

Teacup::Stylesheet.new(:ipadvertical) do
  import :ipadbase
  import :verticaltweaks
end
@stylesheet.import(base_stylesheet)

Parameters:

  • Symbol|Teacup::Stylesheet

    the name of the stylesheet, or the stylesheet to include.



137
138
139
# File 'lib/teacup/stylesheet.rb', line 137

def import(name_or_stylesheet)
  imported << name_or_stylesheet
end

- (Object) inspect

A unique and hopefully meaningful description of this Object.

Returns:

  • String



190
191
192
# File 'lib/teacup/stylesheet.rb', line 190

def inspect
  "Teacup::Stylesheet[#{name.inspect}] = #{@styles.inspect}"
end

- (Object) pi



9
10
11
# File 'lib/teacup/stylesheet_extensions/rotation.rb', line 9

def pi
  3.1415926
end

- (Object) query(stylename)

Get the properties defined for the given stylename, in this Stylesheet and all those that have been imported.

If the ':extends' property is set, we then repeat the process with the value of that, and include them into the result with lower precedence.

Examples:

Teacup::Stylesheet[:ipadbase].query(:continue_button)
# => {backgroundImage: UIImage.imageNamed("big_red_shiny_button"), title: "Continue!", top: 50}

Parameters:

  • Symbol

    stylename, the stylename to look up.



152
153
154
155
156
157
158
159
160
# File 'lib/teacup/stylesheet.rb', line 152

def query(stylename)
  this_rule = properties_for(stylename)

  if also_include = this_rule.delete(:extends)
    query(also_include).update(this_rule)
  else
    this_rule
  end
end

- (Object) rotate(matrix, angle, x, y, z)

rotates the layer arbitrarily



29
30
31
# File 'lib/teacup/stylesheet_extensions/rotation.rb', line 29

def rotate matrix, angle, x, y, z
  CATransform3DRotate(matrix, angle, x, y, z)
end

- (Object) spin(matrix, angle)

spins, along the z axis



24
25
26
# File 'lib/teacup/stylesheet_extensions/rotation.rb', line 24

def spin matrix, angle
  CATransform3DRotate(matrix, angle, 0, 0, 1)
end

- (Object) style(*queries, &block)

Add a set of properties for a given stylename or multiple stylenames.

Examples:

Teacup::Stylesheet.new(:ipadbase) do
  style :pretty_button,
    backgroundImage: UIImage.imageNamed("big_red_shiny_button")

  style :continue_button, extends: :pretty_button,
    title: "Continue!",
    top: 50
end

Parameters:

  • Symbol,

    *stylename

  • Hash (Symbol, Object)

    , properties



175
176
177
178
179
180
181
182
183
184
185
# File 'lib/teacup/stylesheet.rb', line 175

def style(*queries, &block)
  properties = {}

  # if the last argument is a Hash, include it
  properties.update(queries.pop) if Hash === queries[-1]

  # iterate over the style names and assign properties
  queries.each do |stylename|
    styles[stylename].update(properties)
  end
end

- (Object) twist(matrix, angle)

rotates the "left & right" direction



19
20
21
# File 'lib/teacup/stylesheet_extensions/rotation.rb', line 19

def twist matrix, angle
  CATransform3DRotate(matrix, angle, 0, 1, 0)
end