walt 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +14 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +61 -0
- data/LICENSE +26 -0
- data/README.md +193 -0
- data/Rakefile +17 -0
- data/app/app_delegate.rb +71 -0
- data/examples/Apple/.gitignore +13 -0
- data/examples/Apple/Rakefile +14 -0
- data/examples/Apple/app/app_delegate.rb +99 -0
- data/examples/Apple/spec/main_spec.rb +9 -0
- data/examples/Apple/vendor/Podfile.lock +11 -0
- data/examples/Bouncing/.gitignore +13 -0
- data/examples/Bouncing/Rakefile +14 -0
- data/examples/Bouncing/app/app_delegate.rb +49 -0
- data/examples/Bouncing/spec/main_spec.rb +9 -0
- data/examples/Bouncing/vendor/Podfile.lock +11 -0
- data/lib/walt.rb +27 -0
- data/lib/walt/animation.rb +124 -0
- data/lib/walt/animation_set.rb +64 -0
- data/lib/walt/asset/asset.rb +79 -0
- data/lib/walt/asset/image.rb +48 -0
- data/lib/walt/asset/text.rb +64 -0
- data/lib/walt/operation/base.rb +60 -0
- data/lib/walt/operation/fade.rb +35 -0
- data/lib/walt/operation/move.rb +73 -0
- data/lib/walt/operation/rotate.rb +41 -0
- data/lib/walt/operation/scale.rb +41 -0
- data/lib/walt/patch/ui_color.rb +5 -0
- data/lib/walt/support/attr_default.rb +16 -0
- data/lib/walt/support/const_get.rb +60 -0
- data/lib/walt/support/font.rb +87 -0
- data/lib/walt/version.rb +3 -0
- data/lib/walt/walt.rb +53 -0
- data/spec/animation_set_spec.rb +49 -0
- data/spec/animation_spec.rb +128 -0
- data/spec/asset/image_spec.rb +16 -0
- data/spec/asset/text_spec.rb +24 -0
- data/spec/asset_spec.rb +11 -0
- data/spec/main_spec.rb +9 -0
- data/spec/operation/fade_spec.rb +25 -0
- data/spec/operation/move_spec.rb +43 -0
- data/spec/operation_spec.rb +26 -0
- data/spec/support_spec.rb +46 -0
- data/vendor/Podfile.lock +11 -0
- data/walt.gemspec +21 -0
- metadata +172 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
=begin
|
2
|
+
{
|
3
|
+
text: "This goes on the screen",
|
4
|
+
text_color: "ff0000",
|
5
|
+
background_color: "00ff00",
|
6
|
+
number_of_lines: 2,
|
7
|
+
text_alignment: :center,
|
8
|
+
font: "MarkerFelt" # see support/font.rb
|
9
|
+
attributes: {...} # see support/font.rb
|
10
|
+
}
|
11
|
+
=end
|
12
|
+
module Walt
|
13
|
+
class TextAsset < Asset
|
14
|
+
PROPERTIES = [:text, :text_color, :background_color, :number_of_lines, :font, :attributes, :text_alignment]
|
15
|
+
attr_accessor *PROPERTIES
|
16
|
+
|
17
|
+
attr_default :content_mode, [UIViewContentModeRedraw]
|
18
|
+
attr_default :text_color, UIColor.blackColor
|
19
|
+
attr_default :background_color, UIColor.clearColor
|
20
|
+
attr_default :number_of_lines, 1
|
21
|
+
|
22
|
+
def initialize(params = {})
|
23
|
+
super
|
24
|
+
|
25
|
+
params.is_a?(NSDictionary) && params.each do |key, value|
|
26
|
+
if PROPERTIES.include?(key.to_sym)
|
27
|
+
self.send("#{key}=", value)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def view
|
33
|
+
@view ||= UILabel.alloc.initWithFrame(CGRectZero).tap do |view|
|
34
|
+
view.frame = [self.position || CGPointZero, self.size || CGSizeZero]
|
35
|
+
view.contentMode = self.view_content_mode
|
36
|
+
view.clipsToBounds = self.clips_to_bounds
|
37
|
+
view.text = self.text
|
38
|
+
view.textColor = self.text_color.to_color
|
39
|
+
view.backgroundColor = self.background_color.to_color
|
40
|
+
view.numberOfLines = self.number_of_lines
|
41
|
+
view.font = Walt::Font.make(self.font) if self.font
|
42
|
+
view.textAlignment = Walt::Support.constant("UITextAlignment", self.text_alignment) if self.text_alignment
|
43
|
+
|
44
|
+
if self.attributes
|
45
|
+
attributes = Walt::Font.attributes(self.attributes)
|
46
|
+
view.font = attributes[UITextAttributeFont] if attributes[UITextAttributeFont]
|
47
|
+
view.textColor = attributes[UITextAttributeTextColor] if attributes[UITextAttributeTextColor]
|
48
|
+
view.shadowColor = attributes[UITextAttributeTextShadowColor] if attributes[UITextAttributeTextShadowColor]
|
49
|
+
if attributes[UITextAttributeTextShadowOffset]
|
50
|
+
view.shadowOffset = CGSizeMake(self.attributes[:shadow_offset][:x], self.attributes[:shadow_offset][:y])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
if !self.size
|
55
|
+
view.sizeToFit
|
56
|
+
end
|
57
|
+
|
58
|
+
Dispatch::Queue.main.async do
|
59
|
+
self.on_ready(true)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
=begin
|
2
|
+
{
|
3
|
+
type: :move,
|
4
|
+
id: :one
|
5
|
+
}
|
6
|
+
=end
|
7
|
+
|
8
|
+
module Walt
|
9
|
+
module Operation
|
10
|
+
class Base
|
11
|
+
extend Walt::Support::AttrDefault
|
12
|
+
|
13
|
+
PROPERTIES = [:id, :type]
|
14
|
+
attr_accessor *PROPERTIES
|
15
|
+
|
16
|
+
def initialize(params = {})
|
17
|
+
params.each do |key, value|
|
18
|
+
if PROPERTIES.include?(key.to_sym)
|
19
|
+
self.send("#{key}=", value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def setup(view, animation)
|
25
|
+
# do initial before animation
|
26
|
+
end
|
27
|
+
|
28
|
+
def finalize(view, animation = nil)
|
29
|
+
# do whatever occurs during the animation
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module_function
|
34
|
+
def for(hash)
|
35
|
+
# Check classes in module for corresponding operation
|
36
|
+
type = hash[:type] || hash["type"]
|
37
|
+
|
38
|
+
# Check for the form {operation_type: :id}
|
39
|
+
if !type
|
40
|
+
type = (hash.keys.map(&:to_s) | self.operation_types)[0]
|
41
|
+
hash[:id] = (hash[type] || hash[type.to_sym])
|
42
|
+
hash[:type] = type
|
43
|
+
end
|
44
|
+
|
45
|
+
if type.is_a?(Symbol) || type.is_a?(String)
|
46
|
+
string = "#{type.to_s.downcase}_operation".camelize
|
47
|
+
if not const_defined? string
|
48
|
+
raise "Invalid Operation value for operation #{hash.inspect}. Create a class called #{string}."
|
49
|
+
end
|
50
|
+
return Walt::Operation.const_get(string).new(hash)
|
51
|
+
end
|
52
|
+
|
53
|
+
self.new(hash)
|
54
|
+
end
|
55
|
+
|
56
|
+
def operation_types
|
57
|
+
Walt::Operation.constants(false).select { |constant_name| constant_name =~ /Operation$/ }.collect! { |op| op.to_s.gsub("Operation", "").underscore }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
=begin
|
2
|
+
{
|
3
|
+
from: 0.0,
|
4
|
+
to: 0.8
|
5
|
+
}
|
6
|
+
=end
|
7
|
+
|
8
|
+
module Walt
|
9
|
+
module Operation
|
10
|
+
class FadeOperation < Base
|
11
|
+
PROPERTIES = [:from, :to]
|
12
|
+
attr_accessor *PROPERTIES
|
13
|
+
|
14
|
+
def initialize(params = {})
|
15
|
+
super
|
16
|
+
|
17
|
+
params.each do |key, value|
|
18
|
+
if PROPERTIES.include?(key.to_sym)
|
19
|
+
self.send("#{key}=", value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def setup(view, animation)
|
25
|
+
if self.from
|
26
|
+
view.alpha = self.from
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def finalize(view, animation)
|
31
|
+
view.alpha = self.to
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
=begin
|
2
|
+
{
|
3
|
+
from: [0, 0],
|
4
|
+
to: [10, 20]
|
5
|
+
}
|
6
|
+
|
7
|
+
{
|
8
|
+
from: 100,
|
9
|
+
to: 200,
|
10
|
+
axis: :y
|
11
|
+
}
|
12
|
+
=end
|
13
|
+
|
14
|
+
module Walt
|
15
|
+
module Operation
|
16
|
+
class MoveOperation < Base
|
17
|
+
PROPERTIES = [:from, :to, :axis]
|
18
|
+
attr_accessor *PROPERTIES
|
19
|
+
|
20
|
+
attr_default :axis, :x
|
21
|
+
|
22
|
+
def initialize(params = {})
|
23
|
+
super
|
24
|
+
|
25
|
+
if axis = (params[:axis] || params["axis"])
|
26
|
+
self.axis = axis
|
27
|
+
end
|
28
|
+
|
29
|
+
params.each do |key, value|
|
30
|
+
if PROPERTIES.include?(key.to_sym)
|
31
|
+
self.send("#{key}=", value)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
["from", "to"].each do |point|
|
37
|
+
define_method("#{point}=") do |new_point|
|
38
|
+
_point = new_point
|
39
|
+
case new_point
|
40
|
+
when Numeric
|
41
|
+
if self.axis.to_sym == :x
|
42
|
+
_point = [new_point, nil]
|
43
|
+
else
|
44
|
+
_point = [nil, new_point]
|
45
|
+
end
|
46
|
+
when CGPoint
|
47
|
+
_point = [new_point.x, new_point.y]
|
48
|
+
when NSArray
|
49
|
+
else
|
50
|
+
raise "Invalid class for #{point}=: #{new_point.inspect}"
|
51
|
+
end
|
52
|
+
instance_variable_set("@#{point}", _point)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def setup(view, animation)
|
57
|
+
if self.from
|
58
|
+
origin = view.frame.origin
|
59
|
+
origin.x = (self.from[0] || origin.x)
|
60
|
+
origin.y = (self.from[1] || origin.y)
|
61
|
+
view.frame = [origin, view.frame.size]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def finalize(view, animation)
|
66
|
+
origin = view.frame.origin
|
67
|
+
origin.x = (self.to[0] || origin.x)
|
68
|
+
origin.y = (self.to[1] || origin.y)
|
69
|
+
view.frame = [origin, view.frame.size]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
=begin
|
2
|
+
{
|
3
|
+
from: 0,
|
4
|
+
to: 45
|
5
|
+
}
|
6
|
+
=end
|
7
|
+
|
8
|
+
module Walt
|
9
|
+
module Operation
|
10
|
+
class RotateOperation < Base
|
11
|
+
PROPERTIES = [:from, :to]
|
12
|
+
attr_accessor *PROPERTIES
|
13
|
+
|
14
|
+
def initialize(params = {})
|
15
|
+
super
|
16
|
+
|
17
|
+
params.each do |key, value|
|
18
|
+
if PROPERTIES.include?(key.to_sym)
|
19
|
+
self.send("#{key}=", value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def finalize(view, animation)
|
25
|
+
rotate = CABasicAnimation.animationWithKeyPath("transform.rotation")
|
26
|
+
|
27
|
+
from = self.from || view.instance_variable_get("@__last_rotation") || 0
|
28
|
+
rotate.fromValue = NSNumber.numberWithFloat(from)
|
29
|
+
|
30
|
+
rotate.toValue = NSNumber.numberWithFloat(self.to * Math::PI / 180)
|
31
|
+
view.instance_variable_set("@__last_rotation", rotate.toValue.to_f)
|
32
|
+
|
33
|
+
rotate.duration = animation.duration
|
34
|
+
rotate.removedOnCompletion = false
|
35
|
+
rotate.fillMode = KCAFillModeForwards
|
36
|
+
|
37
|
+
view.layer.addAnimation(rotate, forKey:nil)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
=begin
|
2
|
+
{
|
3
|
+
from: 1.0,
|
4
|
+
to: 1.2
|
5
|
+
}
|
6
|
+
=end
|
7
|
+
|
8
|
+
module Walt
|
9
|
+
module Operation
|
10
|
+
class ScaleOperation < Base
|
11
|
+
PROPERTIES = [:from, :to]
|
12
|
+
attr_accessor *PROPERTIES
|
13
|
+
|
14
|
+
def initialize(params = {})
|
15
|
+
super
|
16
|
+
|
17
|
+
params.each do |key, value|
|
18
|
+
if PROPERTIES.include?(key.to_sym)
|
19
|
+
self.send("#{key}=", value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def finalize(view, animation)
|
25
|
+
scale = CABasicAnimation.animationWithKeyPath("transform.scale")
|
26
|
+
|
27
|
+
from = self.from || view.instance_variable_get("@__last_scale") || 1.0
|
28
|
+
scale.fromValue = NSNumber.numberWithFloat(from)
|
29
|
+
|
30
|
+
scale.toValue = NSNumber.numberWithFloat(self.to)
|
31
|
+
view.instance_variable_set("@__last_scale", scale.toValue.to_f)
|
32
|
+
|
33
|
+
scale.duration = animation.duration
|
34
|
+
scale.removedOnCompletion = false
|
35
|
+
scale.fillMode = KCAFillModeForwards
|
36
|
+
|
37
|
+
view.layer.addAnimation(scale, forKey:nil)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Walt
|
2
|
+
module Support
|
3
|
+
module AttrDefault
|
4
|
+
def attr_default(attribute, default)
|
5
|
+
attr_accessor attribute
|
6
|
+
define_method(attribute) do
|
7
|
+
ivar = "@#{attribute}"
|
8
|
+
if !instance_variable_defined?(ivar)
|
9
|
+
instance_variable_set(ivar, default)
|
10
|
+
end
|
11
|
+
instance_variable_get(ivar)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Walt
|
2
|
+
module Support
|
3
|
+
module_function
|
4
|
+
|
5
|
+
=begin
|
6
|
+
Constant.for("UIViewAnimationOption", value)
|
7
|
+
=end
|
8
|
+
|
9
|
+
def constant(base, value)
|
10
|
+
return value if value.is_a? Numeric
|
11
|
+
value = value.to_s.camelize
|
12
|
+
Kernel.const_get("#{base}#{value}")
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def hack
|
17
|
+
[
|
18
|
+
UIViewAnimationOptionLayoutSubviews,
|
19
|
+
UIViewAnimationOptionAllowUserInteraction,
|
20
|
+
UIViewAnimationOptionBeginFromCurrentState,
|
21
|
+
UIViewAnimationOptionRepeat,
|
22
|
+
UIViewAnimationOptionAutoreverse,
|
23
|
+
UIViewAnimationOptionOverrideInheritedDuration,
|
24
|
+
UIViewAnimationOptionOverrideInheritedCurve,
|
25
|
+
UIViewAnimationOptionAllowAnimatedContent,
|
26
|
+
UIViewAnimationOptionShowHideTransitionViews,
|
27
|
+
UIViewAnimationOptionCurveEaseInOut,
|
28
|
+
UIViewAnimationOptionCurveEaseIn,
|
29
|
+
UIViewAnimationOptionCurveEaseOut,
|
30
|
+
UIViewAnimationOptionCurveLinear,
|
31
|
+
UIViewAnimationOptionTransitionNone,
|
32
|
+
UIViewAnimationOptionTransitionFlipFromLeft,
|
33
|
+
UIViewAnimationOptionTransitionFlipFromRight,
|
34
|
+
UIViewAnimationOptionTransitionCurlUp,
|
35
|
+
UIViewAnimationOptionTransitionCurlDown,
|
36
|
+
UIViewAnimationOptionTransitionCrossDissolve,
|
37
|
+
UIViewAnimationOptionTransitionFlipFromTop,
|
38
|
+
UIViewAnimationOptionTransitionFlipFromBottom,
|
39
|
+
|
40
|
+
UIViewContentModeScaleToFill,
|
41
|
+
UIViewContentModeScaleAspectFit,
|
42
|
+
UIViewContentModeScaleAspectFill,
|
43
|
+
UIViewContentModeRedraw,
|
44
|
+
UIViewContentModeCenter,
|
45
|
+
UIViewContentModeTop,
|
46
|
+
UIViewContentModeBottom,
|
47
|
+
UIViewContentModeLeft,
|
48
|
+
UIViewContentModeRight,
|
49
|
+
UIViewContentModeTopLeft,
|
50
|
+
UIViewContentModeTopRight,
|
51
|
+
UIViewContentModeBottomLeft,
|
52
|
+
UIViewContentModeBottomRight,
|
53
|
+
|
54
|
+
UITextAlignmentLeft,
|
55
|
+
UITextAlignmentRight,
|
56
|
+
UITextAlignmentCenter
|
57
|
+
]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Walt
|
2
|
+
module Font
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def bold(size)
|
6
|
+
Font.make(:bold, size)
|
7
|
+
end
|
8
|
+
|
9
|
+
def system(size)
|
10
|
+
Font.make(:system, size)
|
11
|
+
end
|
12
|
+
|
13
|
+
def italic(size)
|
14
|
+
Font.make(:italic, size)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Create font with params:
|
18
|
+
# String => The name of the font
|
19
|
+
# Hash => {
|
20
|
+
# size: Integer,
|
21
|
+
# name: String (see above)
|
22
|
+
# }
|
23
|
+
def make(params = {}, *args)
|
24
|
+
if params.is_a?(UIFont)
|
25
|
+
return params
|
26
|
+
end
|
27
|
+
|
28
|
+
_font = nil
|
29
|
+
if params.is_a?(NSString)
|
30
|
+
params = {name: params}
|
31
|
+
end
|
32
|
+
if args && args[0]
|
33
|
+
params.merge!({size: args[0]})
|
34
|
+
end
|
35
|
+
params[:size] ||= UIFont.systemFontSize
|
36
|
+
if [:system, :bold, :italic].member?(params[:name])
|
37
|
+
case params[:name]
|
38
|
+
when :system
|
39
|
+
_font = UIFont.systemFontOfSize(params[:size].to_f)
|
40
|
+
when :bold
|
41
|
+
_font = UIFont.boldSystemFontOfSize(params[:size].to_f)
|
42
|
+
when :italic
|
43
|
+
_font = UIFont.italicSystemFontOfSize(params[:size].to_f)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
if !_font
|
48
|
+
begin
|
49
|
+
_font = UIFont.fontWithName(params[:name], size: params[:size])
|
50
|
+
rescue
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
if !_font
|
55
|
+
raise "Invalid font for parameters: #{params.inspect} args #{args.inspect}"
|
56
|
+
end
|
57
|
+
|
58
|
+
_font
|
59
|
+
end
|
60
|
+
|
61
|
+
# Create font attributes with keys:
|
62
|
+
# {
|
63
|
+
# font: String or Hash (see Font.make),
|
64
|
+
# color: String,
|
65
|
+
# shadow_color: String,
|
66
|
+
# shadow_offset: {
|
67
|
+
# x: Integer,
|
68
|
+
# y: Integer
|
69
|
+
# }
|
70
|
+
# }
|
71
|
+
def attributes(params = {})
|
72
|
+
_attributes = {}
|
73
|
+
|
74
|
+
_attributes[UITextAttributeFont] = Font.make(params[:font]) if params[:font]
|
75
|
+
_attributes[UITextAttributeTextColor] = params[:color].to_color if params[:color]
|
76
|
+
_attributes[UITextAttributeTextShadowColor] = params[:shadow_color].to_color if params[:shadow_color]
|
77
|
+
_attributes[UITextAttributeTextShadowOffset] = begin
|
78
|
+
x = params[:shadow_offset][:x]
|
79
|
+
y = params[:shadow_offset][:y]
|
80
|
+
offset = UIOffsetMake(x,y)
|
81
|
+
NSValue.valueWithUIOffset(offset)
|
82
|
+
end if params[:shadow_offset]
|
83
|
+
|
84
|
+
_attributes
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|