motion-xray 1.0.4
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/.gitignore +21 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +28 -0
- data/README.md +426 -0
- data/Rakefile +11 -0
- data/app/app_delegate.rb +44 -0
- data/lib/motion-xray.rb +37 -0
- data/lib/motion-xray/plugins/accessibility_plugin.rb +129 -0
- data/lib/motion-xray/plugins/log_plugin.rb +301 -0
- data/lib/motion-xray/plugins/save_ui_plugin.rb +142 -0
- data/lib/motion-xray/plugins/ui_plugin.rb +41 -0
- data/lib/motion-xray/version.rb +5 -0
- data/lib/motion-xray/views/xray_color_swatch.rb +234 -0
- data/lib/motion-xray/views/xray_dpad.rb +142 -0
- data/lib/motion-xray/views/xray_gradient_view.rb +23 -0
- data/lib/motion-xray/views/xray_headers.rb +101 -0
- data/lib/motion-xray/views/xray_lock_button.rb +50 -0
- data/lib/motion-xray/views/xray_scroll_view.rb +12 -0
- data/lib/motion-xray/views/xray_toolbar.rb +173 -0
- data/lib/motion-xray/views/xray_window.rb +13 -0
- data/lib/motion-xray/xray.rb +56 -0
- data/lib/motion-xray/xray_constants.rb +5 -0
- data/lib/motion-xray/xray_dummy.rb +8 -0
- data/lib/motion-xray/xray_editors.rb +62 -0
- data/lib/motion-xray/xray_ext.rb +125 -0
- data/lib/motion-xray/xray_plugin.rb +40 -0
- data/lib/motion-xray/xray_typewriter.rb +217 -0
- data/lib/motion-xray/xray_ui.rb +723 -0
- data/lib/motion-xray/z_editors/xray_boolean_editor.rb +24 -0
- data/lib/motion-xray/z_editors/xray_color_editor.rb +119 -0
- data/lib/motion-xray/z_editors/xray_frame_editor.rb +108 -0
- data/lib/motion-xray/z_editors/xray_image_editor.rb +78 -0
- data/lib/motion-xray/z_editors/xray_text_editor.rb +94 -0
- data/lib/resources/xray_button_bg@2x.png +0 -0
- data/lib/resources/xray_choose_button@2x.png +0 -0
- data/lib/resources/xray_clear_button@2x.png +0 -0
- data/lib/resources/xray_detail_button@2x.png +0 -0
- data/lib/resources/xray_dpad@2x.png +0 -0
- data/lib/resources/xray_dpad_center@2x.png +0 -0
- data/lib/resources/xray_dpad_down@2x.png +0 -0
- data/lib/resources/xray_dpad_left@2x.png +0 -0
- data/lib/resources/xray_dpad_right@2x.png +0 -0
- data/lib/resources/xray_dpad_up@2x.png +0 -0
- data/lib/resources/xray_drawer_left@2x.png +0 -0
- data/lib/resources/xray_drawer_right@2x.png +0 -0
- data/lib/resources/xray_edit_button@2x.png +0 -0
- data/lib/resources/xray_email_button@2x.png +0 -0
- data/lib/resources/xray_lock_button_horizontal@2x.png +0 -0
- data/lib/resources/xray_lock_button_locked@2x.png +0 -0
- data/lib/resources/xray_lock_button_unlocked@2x.png +0 -0
- data/lib/resources/xray_lock_button_vertical@2x.png +0 -0
- data/motion-xray.gemspec +40 -0
- data/resources/Default-568h@2x.png +0 -0
- data/spec/xray_view_spec.rb +43 -0
- data/vendor/Podfile.lock +11 -0
- metadata +177 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
module Motion ; module Xray
|
|
2
|
+
|
|
3
|
+
class SaveUIPlugin < Plugin
|
|
4
|
+
name 'Save UI'
|
|
5
|
+
|
|
6
|
+
def initialize(type=nil)
|
|
7
|
+
@type = type
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def type
|
|
11
|
+
@type || :teacup
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
|
|
16
|
+
# @param format [Symbol] :teacup or :pixate
|
|
17
|
+
# @param type [Class] The class that this encoder can handle
|
|
18
|
+
# @block handler This block should accept an instance (of `type`) and return a string.
|
|
19
|
+
def register(format, type, &handler)
|
|
20
|
+
# don't care about the return - the side effect is to establish
|
|
21
|
+
# @encoders
|
|
22
|
+
encoders(format)[type] = handler
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def encoders(format, type=nil)
|
|
26
|
+
@encoders ||= {}
|
|
27
|
+
@encoders[format] ||= {}
|
|
28
|
+
unless @did_startup
|
|
29
|
+
@did_startup = true
|
|
30
|
+
startup
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
if type
|
|
34
|
+
retval = nil
|
|
35
|
+
while type
|
|
36
|
+
retval = @encoders[format][type]
|
|
37
|
+
break if retval
|
|
38
|
+
type = type.superclass
|
|
39
|
+
end
|
|
40
|
+
return retval
|
|
41
|
+
else
|
|
42
|
+
return @encoders[format]
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def encode(format, object)
|
|
47
|
+
handler = encoders(format, object.class)
|
|
48
|
+
if handler
|
|
49
|
+
handler.call(object)
|
|
50
|
+
else
|
|
51
|
+
nil
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def startup
|
|
56
|
+
register(:teacup, CGRect) { |rect| "[[#{rect.origin.x}, #{rect.origin.y}], [#{rect.size.width}, #{rect.size.height}]]"}
|
|
57
|
+
register(:teacup, CGPoint) { |rect| "[#{rect.origin.x}, #{rect.origin.y}]"}
|
|
58
|
+
register(:teacup, CGSize) { |rect| "[#{rect.size.width}, #{rect.size.height}]"}
|
|
59
|
+
register(:teacup, true.class) { |t| 'true' }
|
|
60
|
+
register(:teacup, false.class) { |t| 'false' }
|
|
61
|
+
# fall back
|
|
62
|
+
register(:teacup, NSObject) { |v| v.inspect }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def initialize
|
|
68
|
+
# uiview instance => list of changes
|
|
69
|
+
@changes = {}
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def plugin_view(canvas)
|
|
73
|
+
@log = UITextView.alloc.initWithFrame(canvas.bounds)
|
|
74
|
+
@log.editable = false
|
|
75
|
+
@log.font = :monospace.uifont
|
|
76
|
+
@log.textColor = 0xBCBEAB.uicolor
|
|
77
|
+
@log.backgroundColor = 0x2b2b2b.uicolor
|
|
78
|
+
return @log
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def save_changes(notification)
|
|
82
|
+
@changes[@target] ||= {}
|
|
83
|
+
property = notification.userInfo['property']
|
|
84
|
+
value = notification.userInfo['value']
|
|
85
|
+
original = notification.userInfo['original']
|
|
86
|
+
|
|
87
|
+
if value == original
|
|
88
|
+
@changes[@target].delete(property)
|
|
89
|
+
else
|
|
90
|
+
@changes[@target][property] = notification.userInfo['value']
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def edit(target)
|
|
95
|
+
super
|
|
96
|
+
XrayTargetDidChangeNotification.remove_observer(self)
|
|
97
|
+
XrayTargetDidChangeNotification.add_observer(self, :'save_changes:', @target)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def show
|
|
101
|
+
if type
|
|
102
|
+
@log.text = send("#{type}_text")
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def teacup_text
|
|
107
|
+
apply = {}
|
|
108
|
+
@changes.each do |view, properties|
|
|
109
|
+
properties.each do |property, value|
|
|
110
|
+
encoded = SaveUIPlugin.encode(:teacup, value)
|
|
111
|
+
if encoded
|
|
112
|
+
apply[view] ||= []
|
|
113
|
+
apply[view] << [property, encoded]
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
text = ''
|
|
119
|
+
apply.each do |view, stuff|
|
|
120
|
+
first_line = true
|
|
121
|
+
if view.stylesheet && view.stylename
|
|
122
|
+
name = "Teacup::Stylesheet[#{view.stylesheet.name.inspect}].style #{view.stylename.inspect},\n "
|
|
123
|
+
else
|
|
124
|
+
name = "#{view.class.name.downcase}.style "
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
text << "#{name}"
|
|
128
|
+
stuff.each do |property, encoded|
|
|
129
|
+
unless first_line
|
|
130
|
+
text << ",\n "
|
|
131
|
+
end
|
|
132
|
+
text << "#{property}: #{encoded}"
|
|
133
|
+
first_line = false
|
|
134
|
+
end
|
|
135
|
+
text << "\n\n"
|
|
136
|
+
end
|
|
137
|
+
return text
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
end end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Motion ; module Xray
|
|
2
|
+
|
|
3
|
+
class UIPlugin < Plugin
|
|
4
|
+
name 'UI'
|
|
5
|
+
|
|
6
|
+
def initialize
|
|
7
|
+
@editor_instances = []
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def plugin_view(canvas)
|
|
11
|
+
@editors = XrayTypewriterView.alloc.initWithFrame(canvas.bounds)
|
|
12
|
+
@editors.scroll_view = canvas
|
|
13
|
+
@editors
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def edit(target)
|
|
17
|
+
super
|
|
18
|
+
@editors.subviews.each &:removeFromSuperview
|
|
19
|
+
@editor_instances = []
|
|
20
|
+
|
|
21
|
+
properties = @target.xray
|
|
22
|
+
sections = properties.keys
|
|
23
|
+
properties.each do |section, editors|
|
|
24
|
+
section_view = XraySectionHeader.alloc.initWithFrame([[0, 0], [Xray.ui.full_screen_width, 20]])
|
|
25
|
+
section_view.text = section
|
|
26
|
+
@editors << section_view
|
|
27
|
+
editors.each do |property, editor_class|
|
|
28
|
+
next unless editor_class
|
|
29
|
+
|
|
30
|
+
editor_instance = editor_class.with_target(@target, property:property)
|
|
31
|
+
@editor_instances << editor_instance
|
|
32
|
+
section_view.tracking_view << editor_instance.get_edit_view(@editors.bounds.size.width)
|
|
33
|
+
end
|
|
34
|
+
@editors << section_view.tracking_view
|
|
35
|
+
end
|
|
36
|
+
@editors.layoutIfNeeded
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end end
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
module Motion ; module Xray
|
|
2
|
+
|
|
3
|
+
class XrayColorSwatch < UIControl
|
|
4
|
+
|
|
5
|
+
def initWithFrame(frame)
|
|
6
|
+
super.tap do
|
|
7
|
+
gradient_view = XrayGradientView.alloc.initWithFrame(self.bounds).tap do |gradient_view|
|
|
8
|
+
gradient_view.layer.borderWidth = 1
|
|
9
|
+
gradient_view.layer.borderColor = :gray.uicolor.CGColor
|
|
10
|
+
gradient_view.userInteractionEnabled = false
|
|
11
|
+
end
|
|
12
|
+
self << gradient_view
|
|
13
|
+
|
|
14
|
+
swatch_rect = gradient_view.bounds.shrink(3)
|
|
15
|
+
|
|
16
|
+
gradient_view << XrayTriangleSwatch.alloc.initWithFrame(swatch_rect)
|
|
17
|
+
|
|
18
|
+
@color_swatch = UIView.alloc.initWithFrame(swatch_rect).tap do |color_swatch|
|
|
19
|
+
color_swatch.layer.borderWidth = 1
|
|
20
|
+
color_swatch.layer.borderColor = :dimgray.uicolor.CGColor
|
|
21
|
+
end
|
|
22
|
+
gradient_view << @color_swatch
|
|
23
|
+
|
|
24
|
+
@pressed_shader = UIView.alloc.initWithFrame(self.bounds).tap do |pressed_shader|
|
|
25
|
+
pressed_shader.backgroundColor = :black.uicolor(0.5)
|
|
26
|
+
pressed_shader.hide
|
|
27
|
+
end
|
|
28
|
+
self << @pressed_shader
|
|
29
|
+
|
|
30
|
+
self.on :touch_start do
|
|
31
|
+
@pressed_shader.show
|
|
32
|
+
end
|
|
33
|
+
self.on :touch_stop do
|
|
34
|
+
@pressed_shader.hide
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def color=(value)
|
|
40
|
+
@color_swatch.backgroundColor = value && value.uicolor
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def color
|
|
44
|
+
@color_swatch.backgroundColor
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
class XrayTriangleSwatch < UIView
|
|
50
|
+
|
|
51
|
+
def drawRect(rect)
|
|
52
|
+
context = UIGraphicsGetCurrentContext()
|
|
53
|
+
|
|
54
|
+
path = UIBezierPath.bezierPath
|
|
55
|
+
path.moveToPoint(bounds.top_right)
|
|
56
|
+
path.addLineToPoint(bounds.bottom_right)
|
|
57
|
+
path.addLineToPoint(bounds.bottom_left)
|
|
58
|
+
CGContextAddPath(context, path.CGPath)
|
|
59
|
+
:black.uicolor.setFill
|
|
60
|
+
CGContextFillPath(context)
|
|
61
|
+
|
|
62
|
+
path = UIBezierPath.bezierPath
|
|
63
|
+
path.moveToPoint(bounds.bottom_left)
|
|
64
|
+
path.addLineToPoint(bounds.top_left)
|
|
65
|
+
path.addLineToPoint(bounds.top_right)
|
|
66
|
+
CGContextAddPath(context, path.CGPath)
|
|
67
|
+
:white.uicolor.setFill
|
|
68
|
+
CGContextFillPath(context)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
class XrayColorSliders < UIControl
|
|
74
|
+
attr_reader :color
|
|
75
|
+
|
|
76
|
+
def initWithFrame(frame)
|
|
77
|
+
super.tap do
|
|
78
|
+
self.backgroundColor = :black.uicolor
|
|
79
|
+
@color = :clear.uicolor
|
|
80
|
+
@triangle = XrayTriangleSwatch.alloc.initWithFrame(CGRect.empty)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def color=(value)
|
|
85
|
+
@color = value.uicolor
|
|
86
|
+
setNeedsDisplay
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def drawRect(rect)
|
|
90
|
+
super
|
|
91
|
+
|
|
92
|
+
r = color.red
|
|
93
|
+
g = color.green
|
|
94
|
+
b = color.blue
|
|
95
|
+
a = color.alpha
|
|
96
|
+
return unless r && g && b && a
|
|
97
|
+
|
|
98
|
+
context = UIGraphicsGetCurrentContext()
|
|
99
|
+
color_space = CGColorSpaceCreateDeviceRGB()
|
|
100
|
+
slider_height = bounds.height / 5
|
|
101
|
+
slider_size = bounds.size
|
|
102
|
+
slider_size.height = slider_height
|
|
103
|
+
path = UIBezierPath.bezierPathWithRect([[0, 0], slider_size])
|
|
104
|
+
@triangle.frame = [[0, 0], slider_size]
|
|
105
|
+
@triangle.drawRect(rect)
|
|
106
|
+
|
|
107
|
+
CGContextSaveGState(context)
|
|
108
|
+
CGContextTranslateCTM(context, 0, 0)
|
|
109
|
+
color.setFill
|
|
110
|
+
path.fill
|
|
111
|
+
CGContextRestoreGState(context)
|
|
112
|
+
|
|
113
|
+
big_oval_width = slider_height - 4
|
|
114
|
+
big_oval = [[-big_oval_width / 2, (slider_height - big_oval_width) / 2], [big_oval_width, big_oval_width]]
|
|
115
|
+
big_oval_path = UIBezierPath.bezierPathWithOvalInRect(big_oval)
|
|
116
|
+
small_oval_width = 4
|
|
117
|
+
small_oval = [[-small_oval_width / 2, (slider_height - small_oval_width) / 2], [small_oval_width, small_oval_width]]
|
|
118
|
+
small_oval_path = UIBezierPath.bezierPathWithOvalInRect(small_oval)
|
|
119
|
+
|
|
120
|
+
points = [0, 1].to_pointer(:float)
|
|
121
|
+
|
|
122
|
+
cgcolors_red = [
|
|
123
|
+
UIColor.colorWithRed(0, green:g, blue:b, alpha:1).CGColor,
|
|
124
|
+
UIColor.colorWithRed(1, green:g, blue:b, alpha:1).CGColor,
|
|
125
|
+
]
|
|
126
|
+
gradient_red = CGGradientCreateWithColors(color_space, cgcolors_red, points)
|
|
127
|
+
CGContextSaveGState(context)
|
|
128
|
+
CGContextTranslateCTM(context, 0, 1 * slider_height)
|
|
129
|
+
path.addClip
|
|
130
|
+
CGContextDrawLinearGradient(context, gradient_red, self.bounds.top_left, self.bounds.top_right, 0)
|
|
131
|
+
CGContextTranslateCTM(context, r * bounds.width, 0)
|
|
132
|
+
UIColor.colorWithRed(1, green:g, blue:b, alpha:1).invert.setStroke
|
|
133
|
+
big_oval_path.stroke
|
|
134
|
+
small_oval_path.stroke
|
|
135
|
+
CGContextRestoreGState(context)
|
|
136
|
+
|
|
137
|
+
cgcolors_green = [
|
|
138
|
+
UIColor.colorWithRed(r, green:0, blue:b, alpha:1).CGColor,
|
|
139
|
+
UIColor.colorWithRed(r, green:1, blue:b, alpha:1).CGColor,
|
|
140
|
+
]
|
|
141
|
+
gradient_green = CGGradientCreateWithColors(color_space, cgcolors_green, points)
|
|
142
|
+
CGContextSaveGState(context)
|
|
143
|
+
CGContextTranslateCTM(context, 0, 2 * slider_height)
|
|
144
|
+
path.addClip
|
|
145
|
+
CGContextDrawLinearGradient(context, gradient_green, self.bounds.top_left, self.bounds.top_right, 0)
|
|
146
|
+
CGContextTranslateCTM(context, g * bounds.width, 0)
|
|
147
|
+
UIColor.colorWithRed(r, green:1, blue:b, alpha:1).invert.setStroke
|
|
148
|
+
big_oval_path.stroke
|
|
149
|
+
small_oval_path.stroke
|
|
150
|
+
CGContextRestoreGState(context)
|
|
151
|
+
|
|
152
|
+
cgcolors_blue = [
|
|
153
|
+
UIColor.colorWithRed(r, green:g, blue:0, alpha:1).CGColor,
|
|
154
|
+
UIColor.colorWithRed(r, green:g, blue:1, alpha:1).CGColor,
|
|
155
|
+
]
|
|
156
|
+
gradient_blue = CGGradientCreateWithColors(color_space, cgcolors_blue, points)
|
|
157
|
+
CGContextSaveGState(context)
|
|
158
|
+
CGContextTranslateCTM(context, 0, 3 * slider_height)
|
|
159
|
+
path.addClip
|
|
160
|
+
CGContextDrawLinearGradient(context, gradient_blue, self.bounds.top_left, self.bounds.top_right, 0)
|
|
161
|
+
CGContextTranslateCTM(context, b * bounds.width, 0)
|
|
162
|
+
UIColor.colorWithRed(r, green:g, blue:1, alpha:1).invert.setStroke
|
|
163
|
+
big_oval_path.stroke
|
|
164
|
+
small_oval_path.stroke
|
|
165
|
+
CGContextRestoreGState(context)
|
|
166
|
+
|
|
167
|
+
cgcolors_alpha = [
|
|
168
|
+
UIColor.colorWithRed(r, green:g, blue:b, alpha:0).CGColor,
|
|
169
|
+
UIColor.colorWithRed(r, green:g, blue:b, alpha:1).CGColor,
|
|
170
|
+
]
|
|
171
|
+
gradient_alpha = CGGradientCreateWithColors(color_space, cgcolors_alpha, points)
|
|
172
|
+
CGContextSaveGState(context)
|
|
173
|
+
CGContextTranslateCTM(context, 0, 4 * slider_height)
|
|
174
|
+
path.addClip
|
|
175
|
+
CGContextDrawLinearGradient(context, gradient_alpha, self.bounds.top_left, self.bounds.top_right, 0)
|
|
176
|
+
CGContextTranslateCTM(context, a * bounds.width, 0)
|
|
177
|
+
:white.uicolor.mix_with(color.uicolor(1).invert, a).setStroke
|
|
178
|
+
big_oval_path.stroke
|
|
179
|
+
small_oval_path.stroke
|
|
180
|
+
CGContextRestoreGState(context)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def touchesBegan(touches, withEvent:event)
|
|
184
|
+
point = touches.anyObject.locationInView(self)
|
|
185
|
+
@touched_section = nil
|
|
186
|
+
touched_color_at(point)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def touchesMoved(touches, withEvent:event)
|
|
190
|
+
point = touches.anyObject.locationInView(self)
|
|
191
|
+
touched_color_at(point)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
ColorSection = 0
|
|
195
|
+
RedSection = 1
|
|
196
|
+
GreenSection = 2
|
|
197
|
+
BlueSection = 3
|
|
198
|
+
AlphaSection = 4
|
|
199
|
+
|
|
200
|
+
def touched_color_at(point)
|
|
201
|
+
slider_height = bounds.height / 5
|
|
202
|
+
section = (point.y / slider_height).floor
|
|
203
|
+
amount = [[point.x / bounds.width, 0].max, 1].min
|
|
204
|
+
|
|
205
|
+
# assigns @touched_section only the first time (in `touchesBegan()`)
|
|
206
|
+
@touched_section ||= section
|
|
207
|
+
# makes sure we're still touching the same section
|
|
208
|
+
section = @touched_section
|
|
209
|
+
return if section == ColorSection
|
|
210
|
+
|
|
211
|
+
r = color.red
|
|
212
|
+
g = color.green
|
|
213
|
+
b = color.blue
|
|
214
|
+
a = color.alpha
|
|
215
|
+
|
|
216
|
+
case section
|
|
217
|
+
when RedSection
|
|
218
|
+
r = amount
|
|
219
|
+
when GreenSection
|
|
220
|
+
g = amount
|
|
221
|
+
when BlueSection
|
|
222
|
+
b = amount
|
|
223
|
+
when AlphaSection
|
|
224
|
+
amount = (amount * 100).round / 100.0
|
|
225
|
+
a = amount
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
self.color = UIColor.colorWithRed(r, green:g, blue:b, alpha:a)
|
|
229
|
+
self.sendActionsForControlEvents(:value_changed.uicontrolevent)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
end end
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
module Motion ; module Xray
|
|
2
|
+
|
|
3
|
+
class XrayDpad < UIView
|
|
4
|
+
|
|
5
|
+
def initWithFrame(frame)
|
|
6
|
+
super.tap do
|
|
7
|
+
@pressed = {
|
|
8
|
+
up: 'xray_dpad_up'.uiimage,
|
|
9
|
+
down: 'xray_dpad_down'.uiimage,
|
|
10
|
+
left: 'xray_dpad_left'.uiimage,
|
|
11
|
+
right: 'xray_dpad_right'.uiimage,
|
|
12
|
+
center: 'xray_dpad_center'.uiimage,
|
|
13
|
+
}
|
|
14
|
+
@default = 'xray_dpad'.uiimage
|
|
15
|
+
@image_view = 'xray_dpad'.uiimageview
|
|
16
|
+
@pressing = nil
|
|
17
|
+
self << @image_view
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def set_pressing_image(direction)
|
|
22
|
+
image = @pressed[direction] || @default
|
|
23
|
+
@image_view.image = image
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def get_pressing(point)
|
|
27
|
+
center = CGRect.new([24.5, 24.5], [23.0, 23.0])
|
|
28
|
+
pressing = nil
|
|
29
|
+
if not self.bounds.contains? point
|
|
30
|
+
return nil
|
|
31
|
+
elsif center.contains? point
|
|
32
|
+
return :center
|
|
33
|
+
else
|
|
34
|
+
if point.x < point.y
|
|
35
|
+
if point.x < self.frame.height - point.y
|
|
36
|
+
return :left
|
|
37
|
+
else
|
|
38
|
+
return :down
|
|
39
|
+
end
|
|
40
|
+
else
|
|
41
|
+
if point.x < self.frame.height - point.y
|
|
42
|
+
return :up
|
|
43
|
+
else
|
|
44
|
+
return :right
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def targets
|
|
51
|
+
@targets ||= []
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def add_listener(target, action)
|
|
55
|
+
targets << [target, action]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def fire(delta)
|
|
59
|
+
if delta.is_a?(Symbol)
|
|
60
|
+
dx = 0
|
|
61
|
+
dy = 0
|
|
62
|
+
case delta
|
|
63
|
+
when :up
|
|
64
|
+
dy = -1
|
|
65
|
+
when :down
|
|
66
|
+
dy = 1
|
|
67
|
+
when :left
|
|
68
|
+
dx = -1
|
|
69
|
+
when :right
|
|
70
|
+
dx = 1
|
|
71
|
+
when :center
|
|
72
|
+
# pass
|
|
73
|
+
else
|
|
74
|
+
raise "huh? #{delta.inspect}"
|
|
75
|
+
end
|
|
76
|
+
delta = CGPoint.new(dx, dy)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
targets.each { |target, action| target.send(action, delta) }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def touchesBegan(touches, withEvent:event)
|
|
83
|
+
super
|
|
84
|
+
point = touches.anyObject.locationInView(self)
|
|
85
|
+
|
|
86
|
+
@pressing = get_pressing(point)
|
|
87
|
+
@was_pressing = true
|
|
88
|
+
@started_location = point
|
|
89
|
+
if @pressing != :center
|
|
90
|
+
@started_time = NSDate.new.to_i
|
|
91
|
+
@started_timer = 0.1.every do
|
|
92
|
+
new_time = NSDate.new.to_i
|
|
93
|
+
delta = new_time - @started_time
|
|
94
|
+
break if delta < 0.5
|
|
95
|
+
|
|
96
|
+
if @was_pressing
|
|
97
|
+
fire(@pressing)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
fire(@pressing)
|
|
101
|
+
end
|
|
102
|
+
set_pressing_image(@pressing)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def touchesMoved(touches, withEvent:event)
|
|
106
|
+
super
|
|
107
|
+
return unless @pressing
|
|
108
|
+
|
|
109
|
+
point = touches.anyObject.locationInView(self)
|
|
110
|
+
if @pressing == :center
|
|
111
|
+
dx = point.x - @started_location.x
|
|
112
|
+
dy = point.y - @started_location.y
|
|
113
|
+
fire(CGPoint.new(dx, dy))
|
|
114
|
+
@started_location = point
|
|
115
|
+
else
|
|
116
|
+
if get_pressing(point) != @pressing
|
|
117
|
+
@was_pressing = false
|
|
118
|
+
set_pressing_image(nil)
|
|
119
|
+
else
|
|
120
|
+
@was_pressing = true
|
|
121
|
+
set_pressing_image(@pressing)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def touchesEnded(touches, withEvent:event)
|
|
127
|
+
super
|
|
128
|
+
@started_timer.invalidate if @started_timer
|
|
129
|
+
set_pressing_image(nil)
|
|
130
|
+
@started_timer = nil
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def touchesCancelled(touches, withEvent:event)
|
|
134
|
+
super
|
|
135
|
+
@started_timer.invalidate if @started_timer
|
|
136
|
+
set_pressing_image(nil)
|
|
137
|
+
@started_timer = nil
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
end end
|