Module: Teacup

Defined in:
lib/teacup/handler.rb,
lib/teacup/layout.rb,
lib/teacup/restyle.rb,
lib/teacup/version.rb,
lib/teacup-ios/style.rb,
lib/teacup-osx/style.rb,
lib/teacup/constraint.rb,
lib/teacup/stylesheet.rb,
lib/teacup-ios/handler.rb,
lib/teacup-osx/handler.rb,
lib/teacup/teacup_util.rb,
lib/teacup/teacup_view.rb,
lib/teacup/calculations.rb,
lib/teacup-ios/appearance.rb,
lib/teacup/merge_defaults.rb,
lib/teacup/teacup_controller.rb,
lib/teacup/core_extensions/view_getters.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/table_view/table_view_delegate.rb,
lib/teacup-ios/stylesheet_extensions/autoresize.rb

Overview

Example:

Teacup::Stylesheet.new :main do
  style :root,
    # stays centered and grows in height
    autoresizingMask: autoresize.flexible_left | autoresize.flexible_right | autoresize.flexible_height
    # same, in block form
    autoresizingMask: autoresize { flexible_left | flexible_right | flexible_height }
end

Defined Under Namespace

Modules: Controller, ControllerClass, Layout, LayoutClass, TableViewDelegate, View Classes: Appearance, Autoresize, Constraint, Style, Stylesheet, TransformLayer, TransformView

Constant Summary collapse

Priorities =

Some properties need to be assigned before others (size in particular, so that ‘:center_x` can work properly). This hash makes sure higher priority style names before lower-numbers.

{
  frame: 2,
  size: 1,
  sizeToFit: 1,
  width: 1,
  height: 1,
}
VERSION =
'2.1.12'

Class Method Summary collapse

Class Method Details

.alias(klass, aliases) ⇒ Object



116
117
118
119
120
121
122
123
# File 'lib/teacup/handler.rb', line 116

def alias klass, aliases
  aliases.each do |style_alias, style_name|
    Teacup.handlers[klass][style_alias] = proc { |view, value|
      Teacup.apply view, style_name, value
    }
  end
  self
end

.AppearanceClassObject



19
20
21
# File 'lib/teacup-ios/handler.rb', line 19

def AppearanceClass
  @appearance_klass ||= UIView.appearance.class
end

.apply(target, key, value, klass = nil) ⇒ Object

Applies a single style to a target. Delegates to a teacup handler if one is found.



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/teacup/handler.rb', line 57

def apply(target, key, value, klass=nil)
  # note about `debug`: not all objects in this method are a UIView instance,
  # so don't assume that the object *has* a debug method.
  if value.is_a? Proc
    if value.arity == 1
      value = value.call(target)
    else
      value = target.instance_exec(&value)
    end
  end

  klass ||= target.class
  handled = false
  klass.ancestors.each do |ancestor|
    if Teacup.handlers[ancestor].has_key? key
      NSLog "#{ancestor.name} is handling #{key} = #{value.inspect}"  if target.respond_to? :debug and target.debug
      if Teacup.handlers[ancestor][key].arity == 1
        target.instance_exec(value, &Teacup.handlers[ancestor][key])
      else
        Teacup.handlers[ancestor][key].call(target, value)
      end
      handled = true
      break
    end
  end
  return if handled

  # you can send methods to subviews (e.g. UIButton#titleLabel) and CALayers
  # (e.g. UIView#layer) by assigning a hash to a style name.
  if value.is_a? Hash
    return Teacup.apply_hash target.send(key), value
  end

  if key =~ /^set[A-Z]/
    assign = nil
    setter = key.to_s + ':'
  else
    assign = key.to_s + '='
    setter = 'set' + key.to_s.sub(/^./) {|c| c.capitalize} + ':'
  end

  Teacup.apply_method(target, assign, setter, value)
end

.apply_hash(target, properties, klass = nil) ⇒ Object

applies a Hash of styles, and converts the frame styles (origin, size, top, left, width, height) into one frame property.

For UIAppearance support, the class of the UIView class that is being modified can be passed in



45
46
47
48
49
50
51
52
53
# File 'lib/teacup/handler.rb', line 45

def apply_hash(target, properties, klass=nil)
  properties.sort do |a, b|
    priority_a = Priorities[a[0]]
    priority_b = Priorities[b[0]]
    priority_b <=> priority_a
  end.each do |key, value|
    Teacup.apply target, key, value, klass
  end
end

.apply_method(target, assign, setter, value) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
# File 'lib/teacup-ios/handler.rb', line 4

def apply_method(target, assign, setter, value)
  if assign and target.respond_to?(assign)
    NSLog "Setting #{key} = #{value.inspect}" if target.respond_to? :debug and target.debug
    target.send(assign, value)
  elsif target.respondsToSelector(setter)
    NSLog "Calling target.#{setter}(#{value.inspect})" if target.respond_to? :debug and target.debug
    target.send(setter, value)
  elsif target.is_a?(self.AppearanceClass)
    NSLog "Calling target.#{setter}(#{value.inspect})" if target.respond_to? :debug and target.debug
    target.send(setter, value)
  else
    NSLog "TEACUP WARNING: Can't apply #{setter.inspect}#{assign and " or " + assign.inspect or ""} to #{target.inspect}"
  end
end

.calculate(view, dimension, amount) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/teacup/calculations.rb', line 3

def calculate(view, dimension, amount)
  if amount.is_a? Proc
    view.instance_exec(&amount)
  elsif amount.is_a?(String) && amount.include?('%')
    location = amount.index '%'
    offset = amount.slice(location+1, amount.size).gsub(' ', '').to_f
    percent = amount.slice(0, location).to_f / 100.0

    case dimension
    when :width
      view.superview.bounds.size.width * percent + offset
    when :height
      view.superview.bounds.size.height * percent + offset
    else
      raise "Unknown dimension #{dimension}"
    end
  else
    amount
  end
end

.dont_restyle?Boolean

Returns:

  • (Boolean)


4
5
6
# File 'lib/teacup/restyle.rb', line 4

def dont_restyle?
  @dont_restyle ||= nil
end

.handler(klass, *stylenames, &block) ⇒ Object



105
106
107
108
109
110
111
112
113
114
# File 'lib/teacup/handler.rb', line 105

def handler klass, *stylenames, &block
  if stylenames.length == 0
    raise TypeError.new "No style names assigned in Teacup[#{klass.inspect}]##handler"
  else
    stylenames.each do |stylename|
      Teacup.handlers[klass][stylename] = block
    end
  end
  self
end

.handlersObject



101
102
103
# File 'lib/teacup/handler.rb', line 101

def handlers
  @teacup_handlers ||= Hash.new{ |hash,klass| hash[klass] = {} }
end

.merge_defaults(left, right, target = {}) ⇒ Object

Merges two Hashes. This is similar to ‘Hash#merge`, except the values will be merged recursively (aka deep merge) when both values for a key are Hashes, and values for the left argument are preferred over values on the right.

If you pass in a third argument, it will be acted upon directly instead of creating a new Hash. Usually used with ‘merge_defaults!`, which merges values from `right` into `left`.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/teacup/merge_defaults.rb', line 12

def merge_defaults(left, right, target={})
  if target != left
    left.each do |key, value|
      if target.has_key? key and value.is_a?(Hash) and target[key].is_a?(Hash)
        target[key] = Teacup::merge_defaults(target[key], value)
      else
        if value.is_a?(Hash)
          # make a copy of the Hash
          value = Teacup::merge_defaults!({}, value)
        end
        target[key] = value
      end
    end
  end

  right.each do |key, value|
    if not target.has_key? key
      target[key] = value
    elsif value.is_a?(Hash) and left[key].is_a?(Hash)
      target[key] = Teacup::merge_defaults(left[key], value, (left==target ? left[key] : {}))
    end
  end
  target
end

.merge_defaults!(left, right) ⇒ Object

modifies left by passing it in as the ‘target`.



38
39
40
# File 'lib/teacup/merge_defaults.rb', line 38

def merge_defaults!(left, right)
  Teacup::merge_defaults(left, right, left)
end

.should_restyle!(&block) ⇒ Object



18
19
20
21
22
23
24
25
26
27
# File 'lib/teacup/restyle.rb', line 18

def should_restyle! &block
  if block
    _dont_restyle = dont_restyle?
    @dont_restyle = nil
    yield
    @dont_restyle = _dont_restyle
  else
    @dont_restyle = nil
  end
end

.should_restyle?Boolean

Returns:

  • (Boolean)


8
9
10
# File 'lib/teacup/restyle.rb', line 8

def should_restyle?
  return ! self.dont_restyle?
end

.should_restyle_and_blockObject



12
13
14
15
16
# File 'lib/teacup/restyle.rb', line 12

def should_restyle_and_block
  should_restyle = self.should_restyle?
  @dont_restyle = true
  return should_restyle
end

.to_instance(class_or_instance) ⇒ Object



4
5
6
7
8
9
10
# File 'lib/teacup/teacup_util.rb', line 4

def to_instance(class_or_instance)
  if class_or_instance.is_a? Class
    return class_or_instance.new
  else
    return class_or_instance
  end
end