teacup 1.3.4 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +1 -1
- data/Gemfile.lock +3 -3
- data/README.md +1172 -319
- data/Rakefile +8 -1
- data/app/app_delegate.rb +1 -1
- data/app/controllers/appearance_controller.rb +13 -0
- data/app/controllers/landscape_only_controller.rb +1 -1
- data/app/controllers/{first_controller.rb → main_controller.rb} +4 -3
- data/app/controllers/motion_layout_controller.rb +22 -0
- data/app/styles/appearance.rb +24 -0
- data/app/styles/main_styles.rb +8 -6
- data/app/views/custom_view.rb +1 -0
- data/lib/teacup/calculations.rb +2 -2
- data/lib/teacup/{z_core_extensions → core_extensions}/ca_layer.rb +0 -0
- data/lib/teacup/core_extensions/view_getters.rb +61 -0
- data/lib/teacup/handler.rb +14 -14
- data/lib/teacup/layout.rb +94 -17
- data/lib/teacup/stylesheet.rb +61 -26
- data/lib/teacup/stylesheet_extensions/transform.rb +88 -0
- data/lib/teacup/teacup_controller.rb +122 -0
- data/lib/teacup/teacup_util.rb +12 -7
- data/lib/teacup/teacup_view.rb +329 -0
- data/lib/teacup/version.rb +1 -1
- data/lib/teacup-ios/appearance.rb +96 -0
- data/lib/teacup-ios/core_extensions/teacup_handlers.rb +183 -0
- data/lib/teacup-ios/core_extensions/ui_view.rb +30 -0
- data/lib/teacup-ios/core_extensions/ui_view_controller.rb +110 -0
- data/lib/{dummy.rb → teacup-ios/dummy.rb} +2 -6
- data/lib/teacup-ios/handler.rb +23 -0
- data/lib/{teacup → teacup-ios}/style.rb +9 -10
- data/lib/teacup-ios/stylesheet_extensions/autoresize.rb +169 -0
- data/lib/{teacup/stylesheet_extensions/geometry.rb → teacup-ios/stylesheet_extensions/device.rb} +0 -0
- data/lib/teacup-osx/core_extensions/ns_view.rb +39 -0
- data/lib/teacup-osx/core_extensions/ns_view_controller.rb +21 -0
- data/lib/teacup-osx/core_extensions/ns_window.rb +39 -0
- data/lib/teacup-osx/core_extensions/ns_window_controller.rb +29 -0
- data/lib/{teacup/z_core_extensions/z_handlers.rb → teacup-osx/core_extensions/teacup_handlers.rb} +30 -47
- data/lib/teacup-osx/dummy.rb +80 -0
- data/lib/teacup-osx/handler.rb +16 -0
- data/lib/teacup-osx/style.rb +83 -0
- data/lib/teacup-osx/style_extensions/autoresize.rb +169 -0
- data/lib/teacup.rb +12 -11
- data/samples/Tweets/Gemfile +4 -0
- data/samples/Tweets/Gemfile.lock +16 -0
- data/samples/Tweets/README +7 -0
- data/samples/Tweets/Rakefile +9 -0
- data/samples/Tweets/app/app_delegate.rb +18 -0
- data/samples/Tweets/app/data_parser.rb +10 -0
- data/samples/Tweets/app/json_parser.rb +12 -0
- data/samples/Tweets/app/main_window.rb +99 -0
- data/samples/Tweets/app/menu.rb +108 -0
- data/samples/Tweets/app/stylesheet.rb +21 -0
- data/samples/Tweets/app/tweet.rb +11 -0
- data/samples/Tweets/resources/Credits.rtf +29 -0
- data/samples/Tweets/spec/main_spec.rb +9 -0
- data/samples/teacup-osx/.gitignore +1 -0
- data/samples/teacup-osx/Gemfile +4 -0
- data/samples/teacup-osx/Gemfile.lock +16 -0
- data/samples/teacup-osx/Rakefile +9 -0
- data/samples/teacup-osx/app/app_delegate.rb +23 -0
- data/samples/teacup-osx/app/controller.rb +11 -0
- data/samples/teacup-osx/app/menu.rb +108 -0
- data/samples/teacup-osx/app/window.rb +12 -0
- data/samples/teacup-osx/resources/Credits.rtf +29 -0
- data/samples/teacup-osx/resources/teacup.png +0 -0
- data/samples/teacup-osx/spec/main_spec.rb +9 -0
- data/spec/ios/appearance_spec.rb +18 -0
- data/spec/{calculations_spec.rb → ios/calculations_spec.rb} +0 -0
- data/spec/{constraints_spec.rb → ios/constraints_spec.rb} +0 -0
- data/spec/{custom_class_spec.rb → ios/custom_class_spec.rb} +0 -0
- data/spec/{gradient_spec.rb → ios/gradient_spec.rb} +1 -1
- data/spec/ios/layout_module_spec.rb +54 -0
- data/spec/ios/layout_spec.rb +50 -0
- data/spec/{main_spec.rb → ios/main_spec.rb} +52 -13
- data/spec/ios/motion_layout_spec.rb +44 -0
- data/spec/{present_modal_spec.rb → ios/present_modal_spec.rb} +0 -0
- data/spec/{style_spec.rb → ios/style_spec.rb} +1 -1
- data/spec/ios/stylesheet_extensions/autoresize_spec.rb +50 -0
- data/spec/{stylesheet_spec.rb → ios/stylesheet_spec.rb} +12 -0
- data/spec/{ui_view_getters_spec.rb → ios/ui_view_getters_spec.rb} +0 -0
- data/spec/{uiswitch_spec.rb → ios/uiswitch_spec.rb} +0 -0
- data/spec/{view_spec.rb → ios/view_spec.rb} +23 -2
- metadata +85 -35
- data/lib/teacup/stylesheet_extensions/autoresize.rb +0 -39
- data/lib/teacup/stylesheet_extensions/rotation.rb +0 -37
- data/lib/teacup/z_core_extensions/ui_view.rb +0 -262
- data/lib/teacup/z_core_extensions/ui_view_controller.rb +0 -263
- data/lib/teacup/z_core_extensions/ui_view_getters.rb +0 -58
data/Rakefile
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
$:.unshift('/Library/RubyMotion/lib')
|
|
2
|
-
|
|
2
|
+
if ENV.fetch('platform', 'ios') == 'ios'
|
|
3
|
+
require 'motion/project/template/ios'
|
|
4
|
+
elsif ENV['platform'] == 'osx'
|
|
5
|
+
require 'motion/project/template/osx'
|
|
6
|
+
else
|
|
7
|
+
raise "Unsupported platform #{ENV['platform']}"
|
|
8
|
+
end
|
|
3
9
|
require 'bundler'
|
|
4
10
|
Bundler.require
|
|
5
11
|
|
|
@@ -8,4 +14,5 @@ Motion::Project::App.setup do |app|
|
|
|
8
14
|
# Use `rake config' to see complete project settings.
|
|
9
15
|
app.name = 'teacup'
|
|
10
16
|
app.identifier = 'com.rubymotion.teacup'
|
|
17
|
+
app.specs_dir = "spec/#{app.template}/"
|
|
11
18
|
end
|
data/app/app_delegate.rb
CHANGED
|
@@ -6,7 +6,7 @@ class AppDelegate
|
|
|
6
6
|
application.setStatusBarHidden(true, withAnimation:UIStatusBarAnimationSlide)
|
|
7
7
|
|
|
8
8
|
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
|
|
9
|
-
ctlr =
|
|
9
|
+
ctlr = MotionLayoutController.new
|
|
10
10
|
@window.rootViewController = ctlr
|
|
11
11
|
@window.rootViewController.wantsFullScreenLayout = true
|
|
12
12
|
@window.makeKeyAndVisible
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class CustomAppearanceController < UIViewController
|
|
2
|
+
attr :label_1
|
|
3
|
+
attr :container
|
|
4
|
+
attr :label_2
|
|
5
|
+
|
|
6
|
+
layout do
|
|
7
|
+
@label_1 = subview(CustomAppearanceLabel)
|
|
8
|
+
@container = subview(CustomAppearanceContainer) do
|
|
9
|
+
@label_2 = subview(CustomAppearanceLabel)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
class LandscapeOnlyController < UIViewController
|
|
3
3
|
|
|
4
4
|
def viewDidLoad
|
|
5
|
-
UIApplication.sharedApplication.windows[0].rootViewController =
|
|
5
|
+
UIApplication.sharedApplication.windows[0].rootViewController = MainController.alloc.init
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
def shouldAutorotateToInterfaceOrientation(orientation)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
class MotionLayoutController < UIViewController
|
|
2
|
+
attr :label1
|
|
3
|
+
attr :label2
|
|
4
|
+
attr :label3
|
|
5
|
+
|
|
6
|
+
layout :root do
|
|
7
|
+
@label1 = subview(UILabel, :label1, text: 'label1')
|
|
8
|
+
@label2 = subview(UILabel, :label2, text: 'label2')
|
|
9
|
+
@label3 = subview(UILabel, :label3, text: 'label3')
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def layoutDidLoad
|
|
13
|
+
auto do
|
|
14
|
+
metrics "margin" => 20, "top" => 100
|
|
15
|
+
horizontal '|-margin-[label1]-margin-[label2(==label1)]-margin-|'
|
|
16
|
+
horizontal '|-margin-[label3]-margin-|'
|
|
17
|
+
vertical '|-top-[label1]'
|
|
18
|
+
vertical '|-220-[label3(==label1)]'
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
class CustomAppearanceLabel < UILabel
|
|
2
|
+
end
|
|
3
|
+
|
|
4
|
+
class CustomAppearanceContainer < UIView
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
Teacup.handler UIView, :redHerring do |view, alpha|
|
|
8
|
+
view.alpha = alpha
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
Teacup::Appearance.new do
|
|
12
|
+
|
|
13
|
+
style CustomAppearanceLabel,
|
|
14
|
+
redHerring: 0.75,
|
|
15
|
+
numberOfLines: 3
|
|
16
|
+
|
|
17
|
+
style CustomAppearanceContainer,
|
|
18
|
+
backgroundColor: UIColor.whiteColor
|
|
19
|
+
|
|
20
|
+
style CustomAppearanceLabel, when_contained_in: CustomAppearanceContainer,
|
|
21
|
+
redHerring: 0.5,
|
|
22
|
+
numberOfLines: 2
|
|
23
|
+
|
|
24
|
+
end
|
data/app/styles/main_styles.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
Teacup::Stylesheet.new(:
|
|
2
|
+
Teacup::Stylesheet.new(:main) do
|
|
3
3
|
|
|
4
4
|
# enable orientations on the root view
|
|
5
5
|
style :root,
|
|
@@ -8,8 +8,8 @@ Teacup::Stylesheet.new(:first) do
|
|
|
8
8
|
width: 320,
|
|
9
9
|
height: 480,
|
|
10
10
|
backgroundColor: UIColor.yellowColor,
|
|
11
|
-
portrait:
|
|
12
|
-
upside_down:
|
|
11
|
+
portrait: true,
|
|
12
|
+
upside_down: false,
|
|
13
13
|
|
|
14
14
|
layer: {
|
|
15
15
|
cornerRadius: 10.0,
|
|
@@ -21,13 +21,13 @@ Teacup::Stylesheet.new(:first) do
|
|
|
21
21
|
|
|
22
22
|
landscape_left: {
|
|
23
23
|
layer: {
|
|
24
|
-
transform: spin(
|
|
24
|
+
transform: transform_layer.spin(-pi / 2),
|
|
25
25
|
},
|
|
26
26
|
},
|
|
27
27
|
|
|
28
28
|
landscape_right: {
|
|
29
29
|
layer: {
|
|
30
|
-
transform: spin(
|
|
30
|
+
transform: transform_layer.spin(pi / 2),
|
|
31
31
|
},
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -50,6 +50,7 @@ Teacup::Stylesheet.new(:first) do
|
|
|
50
50
|
left: 10,
|
|
51
51
|
top: 30,
|
|
52
52
|
backgroundColor: UIColor.blackColor,
|
|
53
|
+
custom_attr: :custom_value,
|
|
53
54
|
|
|
54
55
|
portrait: {
|
|
55
56
|
width: 300,
|
|
@@ -90,7 +91,6 @@ Teacup::Stylesheet.new(:first) do
|
|
|
90
91
|
|
|
91
92
|
|
|
92
93
|
style :next_message,
|
|
93
|
-
width: 130,
|
|
94
94
|
height: 20,
|
|
95
95
|
portrait: nil,
|
|
96
96
|
title: "Next Message..."
|
|
@@ -101,11 +101,13 @@ Teacup::Stylesheet.new(:first) do
|
|
|
101
101
|
portrait: {
|
|
102
102
|
left: 150,
|
|
103
103
|
top: 370,
|
|
104
|
+
width: 140, # this should get overridden
|
|
104
105
|
},
|
|
105
106
|
|
|
106
107
|
landscape: {
|
|
107
108
|
left: 20,
|
|
108
109
|
top: 200,
|
|
110
|
+
width: 140, # this should get overridden
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
end
|
data/app/views/custom_view.rb
CHANGED
data/lib/teacup/calculations.rb
CHANGED
|
@@ -10,9 +10,9 @@ module Teacup
|
|
|
10
10
|
|
|
11
11
|
case dimension
|
|
12
12
|
when :width
|
|
13
|
-
|
|
13
|
+
view.superview.bounds.size.width * percent + offset
|
|
14
14
|
when :height
|
|
15
|
-
|
|
15
|
+
view.superview.bounds.size.height * percent + offset
|
|
16
16
|
else
|
|
17
17
|
raise "Unknown dimension #{dimension}"
|
|
18
18
|
end
|
|
File without changes
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Methods to retrieve a subview using the stylename as a key
|
|
2
|
+
# Kinda similar to jQuery-style $(el).find('stylename')
|
|
3
|
+
module Teacup
|
|
4
|
+
module View
|
|
5
|
+
|
|
6
|
+
# get one subview by stylename or class. If the receiver matches, it will be
|
|
7
|
+
# returned
|
|
8
|
+
# my_view.viewWithStylename :button => #<UIButton..>
|
|
9
|
+
# my_view.viewWithStylename UIButton => #<UIButton..>
|
|
10
|
+
def viewWithStylename name_or_class
|
|
11
|
+
return self if self._teacup_check_stylename(name_or_class)
|
|
12
|
+
|
|
13
|
+
view = subviews.find { |view| view._teacup_check_stylename(name_or_class) }
|
|
14
|
+
return view if view
|
|
15
|
+
|
|
16
|
+
# found_subview will get assigned to the view we want, but the subview is
|
|
17
|
+
# what is returned.
|
|
18
|
+
found_subview = nil
|
|
19
|
+
view = subviews.find { |subview| found_subview = subview.viewWithStylename(name_or_class) }
|
|
20
|
+
return found_subview if view
|
|
21
|
+
|
|
22
|
+
return nil # couldn't find it
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# get all subviews by stylename or class
|
|
26
|
+
# my_view.viewsWithStylename :button => [#<UIButton..>, #<UIButton...>]
|
|
27
|
+
# my_view.viewsWithStylename UIButton => [#<UIButton..>, #<UIButton...>]
|
|
28
|
+
def viewsWithStylename name_or_class
|
|
29
|
+
retval = []
|
|
30
|
+
retval << self if self._teacup_check_stylename(name_or_class)
|
|
31
|
+
|
|
32
|
+
search_views = [].concat(self.subviews)
|
|
33
|
+
# ewww, a traditional for loop! the search_views array is modified in place,
|
|
34
|
+
# and `each` and other methods don't like that.
|
|
35
|
+
index = 0
|
|
36
|
+
while index < search_views.length
|
|
37
|
+
view = search_views[index]
|
|
38
|
+
if view._teacup_check_stylename(name_or_class)
|
|
39
|
+
retval << view
|
|
40
|
+
end
|
|
41
|
+
search_views.concat(view.subviews)
|
|
42
|
+
index += 1
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
return retval
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def _teacup_check_stylename(name_or_class)
|
|
49
|
+
if name_or_class.is_a? Class
|
|
50
|
+
return self.is_a?(name_or_class)
|
|
51
|
+
elsif stylename == name_or_class
|
|
52
|
+
return true
|
|
53
|
+
elsif stylesheet.is_a?(Teacup::Stylesheet)
|
|
54
|
+
return stylesheet.extends_style?(self.stylename, name_or_class)
|
|
55
|
+
end
|
|
56
|
+
return false
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
data/lib/teacup/handler.rb
CHANGED
|
@@ -27,23 +27,31 @@ module Teacup
|
|
|
27
27
|
|
|
28
28
|
# applies a Hash of styles, and converts the frame styles (origin, size, top,
|
|
29
29
|
# left, width, height) into one frame property.
|
|
30
|
-
|
|
30
|
+
#
|
|
31
|
+
# For UIAppearance support, the class of the UIView class that is being
|
|
32
|
+
# modified can be passed in
|
|
33
|
+
def apply_hash(target, properties, klass=nil)
|
|
31
34
|
properties.each do |key, value|
|
|
32
|
-
Teacup.apply target, key, value
|
|
35
|
+
Teacup.apply target, key, value, klass
|
|
33
36
|
end
|
|
34
37
|
end
|
|
35
38
|
|
|
36
39
|
# Applies a single style to a target. Delegates to a teacup handler if one is
|
|
37
40
|
# found.
|
|
38
|
-
def apply(target, key, value)
|
|
41
|
+
def apply(target, key, value, klass=nil)
|
|
39
42
|
# note about `debug`: not all objects in this method are a UIView instance,
|
|
40
43
|
# so don't assume that the object *has* a debug method.
|
|
41
44
|
if value.is_a? Proc
|
|
42
|
-
value
|
|
45
|
+
if value.arity == 1
|
|
46
|
+
value = value.call(target)
|
|
47
|
+
else
|
|
48
|
+
value = target.instance_exec(&value)
|
|
49
|
+
end
|
|
43
50
|
end
|
|
44
51
|
|
|
52
|
+
klass ||= target.class
|
|
45
53
|
handled = false
|
|
46
|
-
|
|
54
|
+
klass.ancestors.each do |ancestor|
|
|
47
55
|
if Teacup.handlers[ancestor].has_key? key
|
|
48
56
|
NSLog "#{ancestor.name} is handling #{key} = #{value.inspect}" if target.respond_to? :debug and target.debug
|
|
49
57
|
if Teacup.handlers[ancestor][key].arity == 1
|
|
@@ -71,15 +79,7 @@ module Teacup
|
|
|
71
79
|
setter = 'set' + key.to_s.sub(/^./) {|c| c.capitalize} + ':'
|
|
72
80
|
end
|
|
73
81
|
|
|
74
|
-
|
|
75
|
-
NSLog "Setting #{key} = #{value.inspect}" if target.respond_to? :debug and target.debug
|
|
76
|
-
target.send(assign, value)
|
|
77
|
-
elsif target.respondsToSelector(setter)
|
|
78
|
-
NSLog "Calling target(#{key}, #{value.inspect})" if target.respond_to? :debug and target.debug
|
|
79
|
-
target.send(setter, value)
|
|
80
|
-
else
|
|
81
|
-
NSLog "TEACUP WARNING: Can't apply #{setter.inspect}#{assign and " or " + assign.inspect or ""} to #{target.inspect}"
|
|
82
|
-
end
|
|
82
|
+
Teacup.apply_method(target, assign, setter, value)
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
def handlers
|
data/lib/teacup/layout.rb
CHANGED
|
@@ -1,4 +1,23 @@
|
|
|
1
1
|
module Teacup
|
|
2
|
+
# Adds the class `stylesheet` method to
|
|
3
|
+
module LayoutClass
|
|
4
|
+
|
|
5
|
+
# Calling this method in the class body will assign a default stylesheet for
|
|
6
|
+
# all instances of your class
|
|
7
|
+
def stylesheet(new_stylesheet=nil)
|
|
8
|
+
if new_stylesheet.nil?
|
|
9
|
+
if @stylesheet.is_a? Symbol
|
|
10
|
+
@stylesheet = Teacup::Stylesheet[@stylesheet]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
return @stylesheet
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
@stylesheet = new_stylesheet
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
|
|
2
21
|
# Teacup::Layout defines a layout and subview function that can be used to
|
|
3
22
|
# declare and configure the layout of views and the view hierarchy in your
|
|
4
23
|
# application.
|
|
@@ -18,6 +37,10 @@ module Teacup
|
|
|
18
37
|
# end
|
|
19
38
|
# end
|
|
20
39
|
module Layout
|
|
40
|
+
def self.included(base)
|
|
41
|
+
base.extend LayoutClass
|
|
42
|
+
end
|
|
43
|
+
|
|
21
44
|
# Assign a Stylesheet or Stylesheet name (Symbol)
|
|
22
45
|
#
|
|
23
46
|
# @return val
|
|
@@ -60,7 +83,7 @@ module Teacup
|
|
|
60
83
|
@stylesheet = Teacup::Stylesheet[@stylesheet]
|
|
61
84
|
end
|
|
62
85
|
|
|
63
|
-
@stylesheet
|
|
86
|
+
@stylesheet || self.class.stylesheet
|
|
64
87
|
end
|
|
65
88
|
|
|
66
89
|
# Alter the layout of a view
|
|
@@ -74,7 +97,10 @@ module Teacup
|
|
|
74
97
|
# current stylesheet (see {stylesheet}) for this
|
|
75
98
|
# element will be immediately applied.
|
|
76
99
|
#
|
|
77
|
-
# @param
|
|
100
|
+
# @param classes The third parameter is optional, and is a list
|
|
101
|
+
# of style classes.
|
|
102
|
+
#
|
|
103
|
+
# @param properties The fourth parameter is optional, and is a Hash
|
|
78
104
|
# of properties to apply to the view directly.
|
|
79
105
|
#
|
|
80
106
|
# @param &block If a block is passed, it is evaluated such that
|
|
@@ -100,34 +126,49 @@ module Teacup
|
|
|
100
126
|
# subview(UIImage, backgroundColor: UIColor.colorWithImagePattern(image)
|
|
101
127
|
# end
|
|
102
128
|
#
|
|
103
|
-
def layout(view_or_class,
|
|
129
|
+
def layout(view_or_class, *teacup_settings, &block)
|
|
104
130
|
view = Teacup.to_instance(view_or_class)
|
|
105
131
|
|
|
106
|
-
|
|
107
|
-
|
|
132
|
+
# prevents the calling of restyle! until we return to this method
|
|
133
|
+
should_restyle = Teacup.should_restyle_and_block
|
|
108
134
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
135
|
+
teacup_style = Style.new
|
|
136
|
+
|
|
137
|
+
teacup_settings.each do |setting|
|
|
138
|
+
case setting
|
|
139
|
+
when Symbol, String
|
|
140
|
+
view.stylename = setting
|
|
141
|
+
when Hash
|
|
142
|
+
# override settings, but apply them to teacup_style so that it remains
|
|
143
|
+
# a Teacup::Style object
|
|
144
|
+
Teacup::merge_defaults(setting, teacup_style, teacup_style)
|
|
145
|
+
when Enumerable
|
|
146
|
+
view.style_classes = setting
|
|
147
|
+
when nil
|
|
148
|
+
# skip. this is so that helper methods that accept arguments like
|
|
149
|
+
# stylename can pass those on to this method without having to
|
|
150
|
+
# introspect the values (just set the default value to `nil`)
|
|
151
|
+
#
|
|
152
|
+
# long story short: tests will fail `nil` is not ignore here
|
|
153
|
+
else
|
|
154
|
+
raise "The argument #{setting.inspect} is not supported in Teacup::Layout::layout()"
|
|
155
|
+
end
|
|
114
156
|
end
|
|
115
157
|
|
|
116
|
-
|
|
117
|
-
should_restyle = Teacup.should_restyle_and_block
|
|
158
|
+
Teacup.apply_hash view, teacup_style.build(view)
|
|
118
159
|
|
|
119
160
|
# assign the 'teacup_next_responder', which is queried for a stylesheet if
|
|
120
161
|
# one is not explicitly assigned to the view
|
|
121
|
-
view.
|
|
122
|
-
|
|
123
|
-
if properties
|
|
124
|
-
view.style(properties) if properties
|
|
162
|
+
if view.is_a? Layout
|
|
163
|
+
view.teacup_next_responder = self
|
|
125
164
|
end
|
|
126
165
|
|
|
127
166
|
if block_given?
|
|
128
167
|
superview_chain << view
|
|
129
168
|
begin
|
|
130
|
-
|
|
169
|
+
# yield will not work if this is defined in the context of the
|
|
170
|
+
# UIViewController `layout` class method.
|
|
171
|
+
instance_exec(view, &block)
|
|
131
172
|
rescue NoMethodError => e
|
|
132
173
|
NSLog("Exception executing layout(#{view.inspect}) in #{self.inspect} (stylesheet=#{stylesheet})")
|
|
133
174
|
raise e
|
|
@@ -140,6 +181,7 @@ module Teacup
|
|
|
140
181
|
Teacup.should_restyle!
|
|
141
182
|
view.restyle!
|
|
142
183
|
end
|
|
184
|
+
|
|
143
185
|
view
|
|
144
186
|
end
|
|
145
187
|
|
|
@@ -191,6 +233,41 @@ module Teacup
|
|
|
191
233
|
instance
|
|
192
234
|
end
|
|
193
235
|
|
|
236
|
+
##|
|
|
237
|
+
##| Motion-Layout support
|
|
238
|
+
##|
|
|
239
|
+
|
|
240
|
+
# Calling this method uses Nick Quaranto's motion-layout gem to provide ASCII
|
|
241
|
+
# art style access to autolayout. It assigns all the subviews by stylename,
|
|
242
|
+
# and assigns `self.view` as the target view. Beyond that, it's up to you to
|
|
243
|
+
# implement the layout methods:
|
|
244
|
+
#
|
|
245
|
+
# auto do
|
|
246
|
+
# metrics 'margin' => 20
|
|
247
|
+
# vertical "|-[top]-margin-[bottom]-|"
|
|
248
|
+
# horizontal "|-margin-[top]-margin-|"
|
|
249
|
+
# horizontal "|-margin-[bottom]-margin-|"
|
|
250
|
+
# end
|
|
251
|
+
def auto(layout_view=top_level_view, layout_subviews={}, &layout_block)
|
|
252
|
+
raise "gem install 'motion-layout'" unless defined? Motion::Layout
|
|
253
|
+
|
|
254
|
+
Teacup.get_styled_subviews(top_level_view).each do |view|
|
|
255
|
+
if ! layout_subviews[view.stylename.to_s]
|
|
256
|
+
layout_subviews[view.stylename.to_s] = view
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
Motion::Layout.new do |layout|
|
|
261
|
+
layout.view layout_view
|
|
262
|
+
layout.subviews layout_subviews
|
|
263
|
+
layout.instance_eval(&layout_block)
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def top_level_view
|
|
268
|
+
raise "No default view has been defined for #{self.class}. Implement `top_level_view`."
|
|
269
|
+
end
|
|
270
|
+
|
|
194
271
|
protected
|
|
195
272
|
|
|
196
273
|
# Get's the current stack of views in nested calls to layout.
|
data/lib/teacup/stylesheet.rb
CHANGED
|
@@ -68,6 +68,7 @@ module Teacup
|
|
|
68
68
|
attr_reader :name
|
|
69
69
|
|
|
70
70
|
class << self
|
|
71
|
+
|
|
71
72
|
def stylesheets
|
|
72
73
|
@stylesheets ||= {}
|
|
73
74
|
end
|
|
@@ -79,6 +80,7 @@ module Teacup
|
|
|
79
80
|
def []= name, stylesheet
|
|
80
81
|
stylesheets[name] = stylesheet
|
|
81
82
|
end
|
|
83
|
+
|
|
82
84
|
end
|
|
83
85
|
|
|
84
86
|
# Create a new Stylesheet.
|
|
@@ -123,20 +125,18 @@ module Teacup
|
|
|
123
125
|
# @stylesheet_cache object is manipulated directly (to invalidate entries,
|
|
124
126
|
# or the entire cache)
|
|
125
127
|
def stylesheet_cache
|
|
126
|
-
@stylesheet_cache ||= Hash.new
|
|
127
|
-
cache[_stylename] = Hash.new
|
|
128
|
+
@stylesheet_cache ||= Hash.new do |cache,_stylename|
|
|
129
|
+
cache[_stylename] = Hash.new do |_target,_orientation|
|
|
128
130
|
_target[_orientation] = {}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
+
end
|
|
132
|
+
end
|
|
131
133
|
end
|
|
132
134
|
|
|
133
135
|
def get_stylesheet_cache(stylename, target, orientation)
|
|
134
|
-
orientation ||= UIApplication.sharedApplication.statusBarOrientation
|
|
135
136
|
stylesheet_cache[stylename][target][orientation]
|
|
136
137
|
end
|
|
137
138
|
|
|
138
139
|
def set_stylesheet_cache(stylename, target, orientation, value)
|
|
139
|
-
orientation ||= UIApplication.sharedApplication.statusBarOrientation
|
|
140
140
|
self.stylesheet_cache[stylename][target][orientation] = value
|
|
141
141
|
end
|
|
142
142
|
|
|
@@ -166,6 +166,33 @@ module Teacup
|
|
|
166
166
|
def import(name_or_stylesheet)
|
|
167
167
|
@stylesheet_cache = nil
|
|
168
168
|
imported << name_or_stylesheet
|
|
169
|
+
|
|
170
|
+
sheet = nil
|
|
171
|
+
if name_or_stylesheet.is_a? Teacup::Stylesheet
|
|
172
|
+
sheet = name_or_stylesheet
|
|
173
|
+
elsif Teacup::Stylesheet.stylesheets.has_key? name_or_stylesheet
|
|
174
|
+
sheet = Teacup::Stylesheet.stylesheets[name_or_stylesheet]
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
if sheet
|
|
178
|
+
import_instance_vars(sheet)
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# the block handed to Stylesheet#new is not run immediately - it is run
|
|
183
|
+
# the first time the stylesheet is queried. This fixes bugs related to
|
|
184
|
+
# some resources (fonts) not available when the application is first
|
|
185
|
+
# started. The downside is that @instance variables and variables that
|
|
186
|
+
# should be closed over are not.
|
|
187
|
+
#
|
|
188
|
+
# @return true if the block was run. false otherwise
|
|
189
|
+
def run_block
|
|
190
|
+
if @block
|
|
191
|
+
_block = @block
|
|
192
|
+
@block = nil
|
|
193
|
+
instance_eval &_block
|
|
194
|
+
true
|
|
195
|
+
end
|
|
169
196
|
end
|
|
170
197
|
|
|
171
198
|
# Get the properties defined for the given stylename, in this Stylesheet and
|
|
@@ -185,15 +212,7 @@ module Teacup
|
|
|
185
212
|
return {} unless stylename
|
|
186
213
|
|
|
187
214
|
unless get_stylesheet_cache(stylename, target, orientation)
|
|
188
|
-
|
|
189
|
-
# the first time the stylesheet is queried. This fixes bugs related to
|
|
190
|
-
# some resources (fonts) not available when the application is first
|
|
191
|
-
# started. The downside is that @instance variables and variables that
|
|
192
|
-
# should be closed over are not.
|
|
193
|
-
if @block
|
|
194
|
-
instance_eval &@block
|
|
195
|
-
@block = nil
|
|
196
|
-
end
|
|
215
|
+
run_block
|
|
197
216
|
seen[self] = true
|
|
198
217
|
|
|
199
218
|
set_stylesheet_cache(stylename, target, orientation, styles[stylename].build(target, orientation, seen))
|
|
@@ -221,7 +240,7 @@ module Teacup
|
|
|
221
240
|
if queries[-1].is_a? Hash
|
|
222
241
|
properties = queries.pop
|
|
223
242
|
else
|
|
224
|
-
# empty style declarations are allowed
|
|
243
|
+
# empty style declarations are allowed, but accomplish nothing.
|
|
225
244
|
return
|
|
226
245
|
end
|
|
227
246
|
|
|
@@ -239,7 +258,7 @@ module Teacup
|
|
|
239
258
|
#
|
|
240
259
|
# @return String
|
|
241
260
|
def inspect
|
|
242
|
-
"
|
|
261
|
+
"#{self.class.name}[#{name.inspect}] = #{styles.inspect}"
|
|
243
262
|
end
|
|
244
263
|
|
|
245
264
|
# The array of Stylesheets that have been imported into this one.
|
|
@@ -248,12 +267,14 @@ module Teacup
|
|
|
248
267
|
def imported_stylesheets
|
|
249
268
|
imported.map do |name_or_stylesheet|
|
|
250
269
|
if name_or_stylesheet.is_a? Teacup::Stylesheet
|
|
251
|
-
name_or_stylesheet
|
|
270
|
+
sheet = name_or_stylesheet
|
|
252
271
|
elsif Teacup::Stylesheet.stylesheets.has_key? name_or_stylesheet
|
|
253
|
-
Teacup::Stylesheet.stylesheets[name_or_stylesheet]
|
|
272
|
+
sheet = Teacup::Stylesheet.stylesheets[name_or_stylesheet]
|
|
254
273
|
else
|
|
255
274
|
raise "Teacup tried to import Stylesheet #{name_or_stylesheet.inspect} into Stylesheet[#{self.name.inspect}], but it didn't exist"
|
|
256
275
|
end
|
|
276
|
+
|
|
277
|
+
sheet
|
|
257
278
|
end
|
|
258
279
|
end
|
|
259
280
|
|
|
@@ -281,6 +302,19 @@ module Teacup
|
|
|
281
302
|
return retval
|
|
282
303
|
end
|
|
283
304
|
|
|
305
|
+
def exclude_instance_vars
|
|
306
|
+
@exclude_instance_vars ||= [:@name, :@block, :@imported, :@styles, :@stylesheet_cache]
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def import_instance_vars(from_stylesheet)
|
|
310
|
+
from_stylesheet.run_block
|
|
311
|
+
|
|
312
|
+
from_stylesheet.instance_variables.each do |var|
|
|
313
|
+
next if exclude_instance_vars.include? var
|
|
314
|
+
self.instance_variable_set(var, from_stylesheet.instance_variable_get(var))
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
284
318
|
protected
|
|
285
319
|
|
|
286
320
|
# The list of Stylesheets or names that have been imported into this one.
|
|
@@ -290,16 +324,17 @@ protected
|
|
|
290
324
|
@imported ||= []
|
|
291
325
|
end
|
|
292
326
|
|
|
293
|
-
# The
|
|
327
|
+
# The styles hash contains Teacup::Style objects, which get linked to the
|
|
328
|
+
# current stylesheet.
|
|
294
329
|
#
|
|
295
330
|
# @return Hash[Symbol, Hash]
|
|
296
331
|
def styles
|
|
297
|
-
@styles ||= Hash.new
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
332
|
+
@styles ||= Hash.new do |_styles, stylename|
|
|
333
|
+
_styles[stylename] = Style.new
|
|
334
|
+
_styles[stylename].stylename = stylename
|
|
335
|
+
_styles[stylename].stylesheet = self
|
|
336
|
+
_styles[stylename]
|
|
337
|
+
end
|
|
303
338
|
end
|
|
304
339
|
|
|
305
340
|
end
|