Module: Teacup

Defined in:
lib/teacup/handler.rb,
lib/teacup/style.rb,
lib/teacup/layout.rb,
lib/teacup/restyle.rb,
lib/teacup/version.rb,
lib/teacup/constraint.rb,
lib/teacup/stylesheet.rb,
lib/teacup/teacup_util.rb,
lib/teacup/calculations.rb,
lib/teacup/merge_defaults.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

Example:

Teacup::Stylesheet.new :main do
  style :root,
    # stays centered and grows in height
    autoresizingMask: flexible_left|flexible_right|flexible_height
end

Defined Under Namespace

Modules: Layout Classes: Constraint, Style, Stylesheet

Constant Summary collapse

VERSION =
'1.3.3'

Class Method Summary collapse

Class Method Details

.alias(klass, aliases) ⇒ Object



100
101
102
103
104
105
106
107
# File 'lib/teacup/handler.rb', line 100

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

.apply(target, key, value) ⇒ Object

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



38
39
40
41
42
43
44
45
46
47
48
49
50
51
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
78
79
80
81
82
83
# File 'lib/teacup/handler.rb', line 38

def apply(target, key, value)
  # 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
    value = target.instance_exec(&value)
  end

  handled = false
  target.class.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

  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(#{key}, #{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

.apply_hash(target, properties) ⇒ Object

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



30
31
32
33
34
# File 'lib/teacup/handler.rb', line 30

def apply_hash(target, properties)
  properties.each do |key, value|
    Teacup.apply target, key, value
  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[(location+1)..-1].gsub(' ', '').to_f
    percent = amount[0...location].to_f / 100.0

    case dimension
    when :width
      CGRectGetWidth(view.superview.bounds) * percent + offset
    when :height
      CGRectGetHeight(view.superview.bounds) * 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

.get_subviews(target) ⇒ Object



259
260
261
262
263
# File 'lib/teacup/z_core_extensions/ui_view_controller.rb', line 259

def Teacup.get_subviews(target)
  [target] + target.subviews.map { |subview|
    get_subviews(subview).select{ |v| v.stylename }
  }.flatten
end

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



89
90
91
92
93
94
95
96
97
98
# File 'lib/teacup/handler.rb', line 89

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



85
86
87
# File 'lib/teacup/handler.rb', line 85

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
11
12
13
14
15
# File 'lib/teacup/teacup_util.rb', line 4

def to_instance(class_or_instance)
  if class_or_instance.is_a? Class
    unless class_or_instance <= UIView
      raise "Expected subclass of UIView, got: #{class_or_instance.inspect}"
    end
    return class_or_instance.new
  elsif class_or_instance.is_a?(UIView)
    return class_or_instance
  else
    raise "Expected a UIView, got: #{class_or_instance.inspect}"
  end
end