lib/teacup/layout.rb in teacup-1.3.4 vs lib/teacup/layout.rb in teacup-2.0.0
- old
+ new
@@ -1,6 +1,25 @@
module Teacup
+ # Adds the class `stylesheet` method to
+ module LayoutClass
+
+ # Calling this method in the class body will assign a default stylesheet for
+ # all instances of your class
+ def stylesheet(new_stylesheet=nil)
+ if new_stylesheet.nil?
+ if @stylesheet.is_a? Symbol
+ @stylesheet = Teacup::Stylesheet[@stylesheet]
+ end
+
+ return @stylesheet
+ end
+
+ @stylesheet = new_stylesheet
+ end
+
+ end
+
# Teacup::Layout defines a layout and subview function that can be used to
# declare and configure the layout of views and the view hierarchy in your
# application.
#
# This module is included into UIView and UIViewController directly so these
@@ -16,10 +35,14 @@
# layout(:my_view) do
# layout UIImage, :logo
# end
# end
module Layout
+ def self.included(base)
+ base.extend LayoutClass
+ end
+
# Assign a Stylesheet or Stylesheet name (Symbol)
#
# @return val
#
# @example
@@ -58,11 +81,11 @@
def stylesheet
if @stylesheet.is_a? Symbol
@stylesheet = Teacup::Stylesheet[@stylesheet]
end
- @stylesheet
+ @stylesheet || self.class.stylesheet
end
# Alter the layout of a view
#
# @param instance The first parameter is the view that you want to
@@ -72,11 +95,14 @@
# stylename to apply to the element. When using
# stylesheets any properties defined in the
# current stylesheet (see {stylesheet}) for this
# element will be immediately applied.
#
- # @param properties The third parameter is optional, and is a Hash
+ # @param classes The third parameter is optional, and is a list
+ # of style classes.
+ #
+ # @param properties The fourth parameter is optional, and is a Hash
# of properties to apply to the view directly.
#
# @param &block If a block is passed, it is evaluated such that
# any calls to {subview} that occur within that
# block cause created subviews to be added to *this*
@@ -98,38 +124,53 @@
# @example
# layout(carousel) do
# subview(UIImage, backgroundColor: UIColor.colorWithImagePattern(image)
# end
#
- def layout(view_or_class, name_or_properties=nil, properties_or_nil=nil, &block)
+ def layout(view_or_class, *teacup_settings, &block)
view = Teacup.to_instance(view_or_class)
- name = nil
- properties = properties_or_nil
+ # prevents the calling of restyle! until we return to this method
+ should_restyle = Teacup.should_restyle_and_block
- if name_or_properties.is_a? Hash
- name = nil
- properties = name_or_properties
- elsif name_or_properties
- name = name_or_properties.to_sym
+ teacup_style = Style.new
+
+ teacup_settings.each do |setting|
+ case setting
+ when Symbol, String
+ view.stylename = setting
+ when Hash
+ # override settings, but apply them to teacup_style so that it remains
+ # a Teacup::Style object
+ Teacup::merge_defaults(setting, teacup_style, teacup_style)
+ when Enumerable
+ view.style_classes = setting
+ when nil
+ # skip. this is so that helper methods that accept arguments like
+ # stylename can pass those on to this method without having to
+ # introspect the values (just set the default value to `nil`)
+ #
+ # long story short: tests will fail `nil` is not ignore here
+ else
+ raise "The argument #{setting.inspect} is not supported in Teacup::Layout::layout()"
+ end
end
- # prevents the calling of restyle! until we return to this method
- should_restyle = Teacup.should_restyle_and_block
+ Teacup.apply_hash view, teacup_style.build(view)
# assign the 'teacup_next_responder', which is queried for a stylesheet if
# one is not explicitly assigned to the view
- view.teacup_next_responder = self
- view.stylename = name
- if properties
- view.style(properties) if properties
+ if view.is_a? Layout
+ view.teacup_next_responder = self
end
if block_given?
superview_chain << view
begin
- instance_exec(view, &block) if block_given?
+ # yield will not work if this is defined in the context of the
+ # UIViewController `layout` class method.
+ instance_exec(view, &block)
rescue NoMethodError => e
NSLog("Exception executing layout(#{view.inspect}) in #{self.inspect} (stylesheet=#{stylesheet})")
raise e
end
@@ -138,10 +179,11 @@
if should_restyle
Teacup.should_restyle!
view.restyle!
end
+
view
end
# Add a new subview to the view heirarchy.
#
@@ -187,9 +229,44 @@
(superview_chain.last || top_level_view).addSubview(instance)
layout(instance, *args, &block)
instance
+ end
+
+ ##|
+ ##| Motion-Layout support
+ ##|
+
+ # Calling this method uses Nick Quaranto's motion-layout gem to provide ASCII
+ # art style access to autolayout. It assigns all the subviews by stylename,
+ # and assigns `self.view` as the target view. Beyond that, it's up to you to
+ # implement the layout methods:
+ #
+ # auto do
+ # metrics 'margin' => 20
+ # vertical "|-[top]-margin-[bottom]-|"
+ # horizontal "|-margin-[top]-margin-|"
+ # horizontal "|-margin-[bottom]-margin-|"
+ # end
+ def auto(layout_view=top_level_view, layout_subviews={}, &layout_block)
+ raise "gem install 'motion-layout'" unless defined? Motion::Layout
+
+ Teacup.get_styled_subviews(top_level_view).each do |view|
+ if ! layout_subviews[view.stylename.to_s]
+ layout_subviews[view.stylename.to_s] = view
+ end
+ end
+
+ Motion::Layout.new do |layout|
+ layout.view layout_view
+ layout.subviews layout_subviews
+ layout.instance_eval(&layout_block)
+ end
+ end
+
+ def top_level_view
+ raise "No default view has been defined for #{self.class}. Implement `top_level_view`."
end
protected
# Get's the current stack of views in nested calls to layout.