cha_work 0.1

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.
@@ -0,0 +1,81 @@
1
+ class Numeric
2
+
3
+ def milliseconds
4
+ self / 1000.0
5
+ end
6
+ alias millisecond milliseconds
7
+ alias millisecs milliseconds
8
+ alias millisec milliseconds
9
+
10
+ def in_milliseconds
11
+ self * 1000
12
+ end
13
+
14
+ def seconds
15
+ self
16
+ end
17
+ alias second seconds
18
+ alias sec seconds
19
+ alias secs seconds
20
+
21
+ def in_seconds
22
+ self
23
+ end
24
+
25
+ def minutes
26
+ self * 60
27
+ end
28
+ alias minute minutes
29
+ alias min minutes
30
+ alias mins minutes
31
+
32
+ def in_minutes
33
+ self / 1.minute.to_f
34
+ end
35
+
36
+ def hours
37
+ self * 3600
38
+ end
39
+ alias hour hours
40
+
41
+ def in_hours
42
+ self / 1.hour.to_f
43
+ end
44
+
45
+ def days
46
+ self.hours * 24
47
+ end
48
+ alias day days
49
+
50
+ def in_days
51
+ self / 1.day.to_f
52
+ end
53
+
54
+ def weeks
55
+ self.days * 7
56
+ end
57
+ alias week weeks
58
+
59
+ def in_weeks
60
+ self / 1.week.to_f
61
+ end
62
+
63
+ def months
64
+ self.days * 30
65
+ end
66
+ alias month months
67
+
68
+ def in_months
69
+ self / 1.month.to_f
70
+ end
71
+
72
+ def years
73
+ self.days * 365
74
+ end
75
+ alias year years
76
+
77
+ def in_years
78
+ self / 1.year.to_f
79
+ end
80
+
81
+ end
@@ -0,0 +1,189 @@
1
+ class UIActionSheet
2
+
3
+ # For the purposes of whether the cancel or success handler gets called, the
4
+ # first button is considered the 'cancel' button, the second button is the
5
+ # 'destructive' button, and the rest are plain old buttons.
6
+ #
7
+ # If you use just one block, it will be used for *all* of the buttons.
8
+ #
9
+ # @example
10
+ # # use a different handler for each button type
11
+ # UIActionSheet.alert("title",
12
+ # buttons: %w"Cancel Delete No-way",
13
+ # cancel: proc{ puts "nevermind" },
14
+ # destructive: proc{ puts "OHHH YEAAH!" },
15
+ # success: proc{ |pressed| puts "pressed: #{pressed}" },
16
+ # )
17
+ # # use one handler for all buttons
18
+ # UIActionSheet.alert("title", buttons: [...]) { |button| }
19
+ def self.alert(title, options={}, &block)
20
+ if title.is_a?(NSDictionary)
21
+ options = title
22
+ title = options[:title]
23
+ end
24
+
25
+ # create the delegate
26
+ delegate = ChaWork::ActionSheetDelegate.new
27
+ delegate.on_default = block
28
+ delegate.on_success = options[:success]
29
+ delegate.on_destructive = options[:destructive]
30
+ delegate.on_cancel = options[:cancel]
31
+ delegate.send(:retain)
32
+
33
+ args = [title] # initWithTitle:
34
+ args << delegate # delegate:
35
+
36
+ buttons = (options[:buttons] || []).freeze
37
+ if buttons.empty?
38
+ buttons = [] # an empty Hash becomes an Array
39
+
40
+ # cancelButtonTitle:
41
+ buttons << nil
42
+
43
+ # destructiveButtonTitle
44
+ buttons << nil
45
+
46
+ # otherButtonTitles:
47
+ buttons << 'OK'
48
+ elsif buttons.length == 1 && (options[:cancel] || options[:destructive])
49
+ raise 'If you only have one button, use a :success handler, not :cancel or :destructive'
50
+ end
51
+
52
+ # the button titles, mapped to how UIActionSheet orders them. These are
53
+ # passed to the success handler.
54
+ buttons_mapped = {}
55
+
56
+ # cancelButtonTitle:destructiveButtonTitle:otherButtonTitles:
57
+ # uses localized buttons in the actual alert
58
+ if buttons.is_a?(NSDictionary)
59
+ button_keys = buttons.keys
60
+ if buttons.key?(:cancel)
61
+ args << (buttons[:cancel] && NSBundle.mainBundle.localizedStringForKey(buttons[:cancel], value: nil, table: nil))
62
+ else
63
+ args << nil
64
+ end
65
+ if buttons.key?(:destructive)
66
+ args << (buttons[:destructive] && NSBundle.mainBundle.localizedStringForKey(buttons[:destructive], value: nil, table: nil))
67
+ else
68
+ args << nil
69
+ end
70
+ args.concat(buttons.select { |k, m| k != :cancel && k != :destructive }.map { |k, m| m && NSBundle.mainBundle.localizedStringForKey(m, value: nil, table: nil) })
71
+ else
72
+ button_keys = buttons
73
+ args.concat(buttons.map { |m| m && NSBundle.mainBundle.localizedStringForKey(m, value: nil, table: nil) })
74
+ end
75
+ args << nil # otherButtonTitles:..., nil
76
+
77
+ if args[2] && args[3] # cancel && destructive buttons
78
+ buttons_mapped[0] = button_keys[1] # destructiveIndex == 0, button == 1
79
+ buttons_mapped[button_keys.length - 1] = button_keys[0] # cancelIndex == last, button == 0
80
+ # from first+1 to last-1
81
+ button_keys[2..-1].each_with_index do |button,index|
82
+ buttons_mapped[index + 1] = button
83
+ end
84
+ elsif args[3] # destructive button
85
+ buttons_mapped[0] = button_keys[1] # destructiveIndex == 0, button == 1
86
+ # from first+1 to last-1
87
+ buttons[2..-1].each_with_index do |button,index|
88
+ buttons_mapped[index + 1] = button
89
+ end
90
+ elsif args[2] # cancel button
91
+ buttons_mapped[buttons.length - 2] = button_keys[0] # cancelIndex == last, button == 0
92
+ button_keys[2..-1].each_with_index do |button,index|
93
+ buttons_mapped[index] = button
94
+ end
95
+ else
96
+ button_keys[2..-1].each_with_index do |button,index|
97
+ buttons_mapped[index] = button
98
+ end
99
+ end
100
+ delegate.buttons = buttons_mapped
101
+
102
+ alert = self.alloc
103
+ alert.send('initWithTitle:delegate:cancelButtonTitle:destructiveButtonTitle:otherButtonTitles:', *args)
104
+
105
+ if options.key?(:style)
106
+ style = options[:style]
107
+ if style.respond_to?(:uiactionstyle)
108
+ style = style.uiactionstyle
109
+ end
110
+ alert.actionSheetStyle = style
111
+ end
112
+
113
+ if options.fetch(:show, true)
114
+ if options.key?(:from)
115
+ from = options[:from]
116
+ else
117
+ from = UIApplication.sharedApplication.windows[0]
118
+ end
119
+
120
+ case from
121
+ when CGRect
122
+ view = options.fetch(:view, UIApplication.sharedApplication.windows[0])
123
+ alert.showFromRect(from, inView: view, animated: true)
124
+ when UIBarButtonItem
125
+ alert.showFromBarButtonItem(from, animated: true)
126
+ when UIToolbar
127
+ alert.showFromToolbar(from)
128
+ when UITabBar
129
+ alert.showFromTabBar(from)
130
+ when UIView
131
+ alert.showInView(from)
132
+ else
133
+ raise "Unknown :from option #{from.inspect}"
134
+ end
135
+ end
136
+
137
+ alert
138
+ end
139
+
140
+ def <<(title)
141
+ addButtonWithTitle(title)
142
+ end
143
+
144
+ private
145
+ def dummy
146
+ self.initWithTitle(nil, delegate:nil, cancelButtonTitle:nil, destructiveButtonTitle:nil, otherButtonTitles:nil)
147
+ end
148
+
149
+ end
150
+
151
+
152
+ module ChaWork
153
+ class ActionSheetDelegate
154
+ attr_accessor :buttons
155
+ attr_accessor :on_default
156
+ attr_accessor :on_cancel
157
+ attr_accessor :on_destructive
158
+ attr_accessor :on_success
159
+
160
+ def actionSheet(alert, didDismissWithButtonIndex: index)
161
+ handler = nil
162
+ if index == alert.destructiveButtonIndex && on_destructive
163
+ handler = on_destructive
164
+ elsif index == alert.cancelButtonIndex && on_cancel
165
+ handler = on_cancel
166
+ elsif index != alert.destructiveButtonIndex && index != alert.cancelButtonIndex && on_success
167
+ handler = on_success
168
+ end
169
+ handler ||= on_default
170
+
171
+ if handler
172
+ if handler.arity == 0
173
+ handler.call
174
+ else
175
+ button = buttons[index]
176
+
177
+ if handler.arity == 1
178
+ handler.call(button)
179
+ else
180
+ handler.call(button, index)
181
+ end
182
+ end
183
+ end
184
+
185
+ self.send(:autorelease)
186
+ end
187
+
188
+ end
189
+ end
@@ -0,0 +1,7 @@
1
+ class UIButton
2
+
3
+ def title=(text)
4
+ self.setTitle(text, forState:UIControlStateNormal)
5
+ self
6
+ end
7
+ end
@@ -0,0 +1,99 @@
1
+ # Additions to UIControl to support jQuery-style `on` and `off` methods.
2
+ class UIControl
3
+
4
+ # Add event handlers to UIControls. See symbol.rb for the uicontrolevent
5
+ # constant aliases.
6
+ #
7
+ # @example
8
+ # button = UIButton.alloc.initWithFrame([0, 0, 10, 10])
9
+ # button.on(:touch) { my_code }
10
+ # button.on(:touch_up_outside, :touch_cancel) { my_code }
11
+ # # up to two arguments can be passed in
12
+ # button.on(:touch) { |sender,touch_event| my_code }
13
+ def on(*events, &block)
14
+ handler = ChaWork::UIControlCallbackHelper.new(block)
15
+
16
+ events.each do |event|
17
+ event = event.uicontrolevent if event.respond_to?(:uicontrolevent)
18
+
19
+ sugarcube_callbacks(event).push(handler)
20
+ self.addTarget(handler, action:'call:event:', forControlEvents:event)
21
+ end
22
+
23
+ self
24
+ end
25
+
26
+ # Removes all events that were bound with `on`. See symbol.rb for the
27
+ # uicontrolevent constant aliases.
28
+ #
29
+ # @example
30
+ # button.off(:touch)
31
+ # button.off(:touch_up_outside, :touch_cancel)
32
+ # button.off # all events
33
+ def off(*events)
34
+ if events.length == 0
35
+ events = sugarcube_callbacks.keys
36
+ end
37
+
38
+ events.each do |event|
39
+ event = event.uicontrolevent if event.respond_to?(:uicontrolevent)
40
+
41
+ sugarcube_callbacks(event).each do |handler|
42
+ self.removeTarget(handler, action:'call:event:', forControlEvents:event)
43
+ end
44
+ sugarcube_callbacks.delete(event)
45
+ end
46
+
47
+ self
48
+ end
49
+
50
+ # Useful during testing, or to simulate a button press.
51
+ #
52
+ # @example
53
+ # button.trigger(:touch)
54
+ # button.trigger(:touch_drag_outside, :touch_drag_exits)
55
+ def trigger(*events)
56
+ event_mask = 0
57
+ events.each do |event|
58
+ event = event.uicontrolevent if event.respond_to?(:uicontrolevent)
59
+ event_mask |= event
60
+ end
61
+ sendActionsForControlEvents(event_mask)
62
+ end
63
+
64
+ private
65
+ # event blocks need to be retained, and the addTarget method explicitly does
66
+ # *not* retain `target`. This makes sure that callbacks are retained by
67
+ # pushing the block onto a stack.
68
+ def sugarcube_callbacks(event=nil)
69
+ @sugarcube_callbacks ||= {}
70
+ if event
71
+ @sugarcube_callbacks[event] ||= []
72
+ return @sugarcube_callbacks[event]
73
+ else
74
+ return @sugarcube_callbacks
75
+ end
76
+ end
77
+
78
+ end
79
+
80
+
81
+ module ChaWork
82
+ class UIControlCallbackHelper
83
+
84
+ def initialize(callback)
85
+ @callback = callback.respond_to?('weak!') ? callback.weak! : callback
86
+ end
87
+
88
+ def call(sender, event:event)
89
+ case @callback.arity
90
+ when 0
91
+ @callback.call
92
+ when 1
93
+ @callback.call(sender)
94
+ else
95
+ @callback.call(sender, event)
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,4 @@
1
+ class UIImageView
2
+
3
+
4
+ end
@@ -0,0 +1,21 @@
1
+ class UILabel
2
+
3
+ def on
4
+ self.becomeFirstResponder
5
+ end
6
+
7
+ def off
8
+ self.resignFirstResponder
9
+ end
10
+
11
+ def color(value)
12
+ self.textColor = value.class == UIColor ? value : value.uicolor
13
+ self
14
+ end
15
+
16
+ def size(value)
17
+ self.font = UIFont.systemFontOfSize(value)
18
+ self
19
+ end
20
+
21
+ end
@@ -0,0 +1,13 @@
1
+ class UITableView
2
+ class << self
3
+
4
+ def plain(frame=[[0, 0], [0, 0]])
5
+ UITableView.alloc.initWithFrame(frame, style: UITableViewStylePlain)
6
+ end
7
+
8
+ def grouped(frame=[[0, 0], [0, 0]])
9
+ UITableView.alloc.initWithFrame(frame, style: UITableViewStyleGrouped)
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,306 @@
1
+ class UIView
2
+
3
+ class << self
4
+
5
+ def attr_updates(*attrs)
6
+ attr_accessor(*attrs)
7
+ attrs.each do |attr|
8
+ define_method("#{attr}=") do |value|
9
+ if instance_variable_get("@#{attr}") != value
10
+ setNeedsDisplay
11
+ end
12
+ willChangeValueForKey(attr)
13
+ instance_variable_set("@#{attr}", value)
14
+ didChangeValueForKey(attr)
15
+ end
16
+ end
17
+ end
18
+
19
+ end
20
+
21
+ # superview << view
22
+ # => superview.addSubview(view)
23
+ def <<(view)
24
+ self.addSubview(view)
25
+ return self
26
+ end
27
+
28
+
29
+ def show
30
+ self.hidden = false
31
+ return self
32
+ end
33
+
34
+ def hide
35
+ self.hidden = true
36
+ return self
37
+ end
38
+
39
+ # Easily take a snapshot of a `UIView`.
40
+ #
41
+ # Calling `uiimage` with no arguments will return the image based on the
42
+ # `bounds` of the image. In the case of container views (notably
43
+ # `UIScrollView` and its children) this does not include the entire contents,
44
+ # which is something you probably want.
45
+ #
46
+ # If you pass a truthy value to this method, it will use the `contentSize` of
47
+ # the view instead of the `bounds`, and it will draw all the child views, not
48
+ # just those that are visible in the viewport.
49
+ #
50
+ # It is guaranteed that `true` and `:all` will always have this behavior. In
51
+ # the future, if this argument becomes something that accepts multiple values,
52
+ # those two are sacred.
53
+ def uiimage(use_content_size=false)
54
+ if use_content_size
55
+ UIGraphicsBeginImageContextWithOptions(contentSize, false, 0.0)
56
+ context = UIGraphicsGetCurrentContext()
57
+ self.subviews.each do |subview|
58
+ CGContextSaveGState(context)
59
+ CGContextTranslateCTM(context, subview.frame.origin.x, subview.frame.origin.y)
60
+ subview.layer.renderInContext(context)
61
+ CGContextRestoreGState(context)
62
+ end
63
+ image = UIGraphicsGetImageFromCurrentImageContext()
64
+ UIGraphicsEndImageContext()
65
+ else
66
+ UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0.0)
67
+ if self.respond_to?('drawViewHierarchyInRect:afterScreenUpdates:')
68
+ self.drawViewHierarchyInRect(self.bounds, afterScreenUpdates: true)
69
+ else
70
+ layer.renderInContext(UIGraphicsGetCurrentContext())
71
+ end
72
+ image = UIGraphicsGetImageFromCurrentImageContext()
73
+ UIGraphicsEndImageContext()
74
+ end
75
+ return image
76
+ end
77
+
78
+ # A generic gesture adder, but accepts a block like the other gesture methods
79
+ # @yield [recognizer] Handles the gesture event, and passes the recognizer instance to the block.
80
+ # @param options [Hash] method/value pairs to call on the gesture.
81
+ # @overload on_gesture(recognizer)
82
+ # Adds the gesture to the view, and yields the block when the gesture is recognized
83
+ # @overload on_gesture(recognizer_class)
84
+ # Instantiates a gesture and adds it to the view.
85
+ # @example Using a UIGestureRecognizer class
86
+ # view.on_gesture(UISwipeGestureRecognizer, direction: UISwipeGestureRecognizerDirectionLeft) { puts "swiped left" }
87
+ # @example Using a UIGestureRecognizer instance
88
+ # gesture = UISwipeGestureRecognizer
89
+ # gesture.direction = UISwipeGestureRecognizerDirectionLeft
90
+ # view.on_gesture(gesture) { puts "swiped left" }
91
+ def on_gesture(klass, options={}, &proc)
92
+ if klass.is_a? UIGestureRecognizer
93
+ recognizer = klass
94
+ recognizer.addTarget(self, action:'sugarcube_handle_gesture:')
95
+ else
96
+ recognizer = klass.alloc.initWithTarget(self, action:'sugarcube_handle_gesture:')
97
+ end
98
+
99
+ options.each do |method, value|
100
+ recognizer.send(method, value)
101
+ end
102
+ sugarcube_add_gesture(proc, recognizer)
103
+ end
104
+
105
+ def off_gestures
106
+ if @sugarcube_recognizers
107
+ @sugarcube_recognizers.each do |recognizer, proc|
108
+ self.removeGestureRecognizer(recognizer)
109
+ end
110
+ @sugarcube_recognizers = nil
111
+ end
112
+
113
+ self
114
+ end
115
+
116
+ # @yield [recognizer] Handles the gesture event, and passes the recognizer instance to the block.
117
+ # @overload on_tap(taps)
118
+ # @param taps [Fixnum] Number of taps
119
+ # @overload on_tap(options)
120
+ # @option options [Fixnum] :taps Number of taps before gesture is recognized
121
+ # @option options [Fixnum] :fingers Number of fingers before gesture is recognized
122
+ def on_tap(taps_or_options=nil, &proc)
123
+ taps = nil
124
+ fingers = nil
125
+
126
+ if taps_or_options
127
+ if taps_or_options.is_a? Hash
128
+ taps = taps_or_options[:taps] || taps
129
+ fingers = taps_or_options[:fingers] || fingers
130
+ else
131
+ taps = taps_or_options
132
+ end
133
+ end
134
+
135
+ recognizer = UITapGestureRecognizer.alloc.initWithTarget(self, action:'sugarcube_handle_gesture:')
136
+ recognizer.numberOfTapsRequired = taps if taps
137
+ recognizer.numberOfTouchesRequired = fingers if fingers
138
+ sugarcube_add_gesture(proc, recognizer)
139
+ end
140
+
141
+ # @yield [recognizer] Handles the gesture event, and passes the recognizer instance to the block.
142
+ def on_pinch(&proc)
143
+ recognizer = UIPinchGestureRecognizer.alloc.initWithTarget(self, action:'sugarcube_handle_gesture:')
144
+ sugarcube_add_gesture(proc, recognizer)
145
+ end
146
+
147
+ # @yield [recognizer] Handles the gesture event, and passes the recognizer instance to the block.
148
+ def on_rotate(&proc)
149
+ recognizer = UIRotationGestureRecognizer.alloc.initWithTarget(self, action:'sugarcube_handle_gesture:')
150
+ sugarcube_add_gesture(proc, recognizer)
151
+ end
152
+
153
+ # @yield [recognizer] Handles the gesture event, and passes the recognizer instance to the block.
154
+ # @overload on_swipe(taps)
155
+ # @param direction [Fixnum] Direction of swipe
156
+ # @overload on_swipe(options)
157
+ # @option options [Fixnum] :fingers Number of fingers before gesture is recognized
158
+ # @option options [Fixnum, Symbol] :direction Direction of swipe, as a UISwipeGestureRecognizerDirection constant or a symbol (`:left, :right, :up, :down`)
159
+ def on_swipe(direction_or_options=nil, &proc)
160
+ direction = nil
161
+ fingers = nil
162
+
163
+ if direction_or_options
164
+ if direction_or_options.is_a? Hash
165
+ direction = direction_or_options[:direction] || direction
166
+ fingers = direction_or_options[:fingers] || fingers
167
+ else
168
+ direction = direction_or_options
169
+ end
170
+ end
171
+
172
+ case direction
173
+ when :left
174
+ direction = UISwipeGestureRecognizerDirectionLeft
175
+ when :right
176
+ direction = UISwipeGestureRecognizerDirectionRight
177
+ when :up
178
+ direction = UISwipeGestureRecognizerDirectionUp
179
+ when :down
180
+ direction = UISwipeGestureRecognizerDirectionDown
181
+ end
182
+
183
+ recognizer = UISwipeGestureRecognizer.alloc.initWithTarget(self, action:'sugarcube_handle_gesture:')
184
+ recognizer.direction = direction if direction
185
+ recognizer.numberOfTouchesRequired = fingers if fingers
186
+ sugarcube_add_gesture(proc, recognizer)
187
+ end
188
+
189
+ # @yield [recognizer] Handles the gesture event, and passes the recognizer instance to the block.
190
+ # @overload on_tap(taps)
191
+ # @param taps [Fixnum] Number of taps
192
+ # @overload on_tap(options)
193
+ # @option options [Fixnum] :min_fingers Minimum number of fingers for gesture to be recognized
194
+ # @option options [Fixnum] :max_fingers Maximum number of fingers for gesture to be recognized
195
+ # @option options [Fixnum] :fingers If min_fingers or max_fingers is not assigned, this will be the default.
196
+ def on_pan(fingers_or_options=nil, &proc)
197
+ fingers = nil
198
+ min_fingers = nil
199
+ max_fingers = nil
200
+
201
+ if fingers_or_options
202
+ if fingers_or_options.is_a? Hash
203
+ fingers = fingers_or_options[:fingers] || fingers
204
+ min_fingers = fingers_or_options[:min_fingers] || min_fingers
205
+ max_fingers = fingers_or_options[:max_fingers] || max_fingers
206
+ else
207
+ fingers = fingers_or_options
208
+ end
209
+ end
210
+
211
+ # if fingers is assigned, but not min/max, assign it as a default
212
+ min_fingers ||= fingers
213
+ max_fingers ||= fingers
214
+
215
+ recognizer = UIPanGestureRecognizer.alloc.initWithTarget(self, action:'sugarcube_handle_gesture:')
216
+ recognizer.maximumNumberOfTouches = min_fingers if min_fingers
217
+ recognizer.minimumNumberOfTouches = max_fingers if max_fingers
218
+ sugarcube_add_gesture(proc, recognizer)
219
+ end
220
+
221
+ # @yield [recognizer] Handles the gesture event, and passes the recognizer instance to the block.
222
+ # @overload on_press(duration)
223
+ # @param duration [Fixnum] How long in seconds before gesture is recognized
224
+ # @overload on_tap(options)
225
+ # @option options [Fixnum] :duration How long in seconds before gesture is recognized
226
+ # @option options [Fixnum] :taps Number of taps before gesture is recognized
227
+ # @option options [Fixnum] :fingers Number of fingers before gesture is recognized
228
+ def on_press(duration_or_options=nil, &proc)
229
+ duration = nil
230
+ taps = nil
231
+ fingers = nil
232
+
233
+ if duration_or_options
234
+ if duration_or_options.is_a? Hash
235
+ duration = duration_or_options[:duration] || duration
236
+ taps = duration_or_options[:taps] || taps
237
+ fingers = duration_or_options[:fingers] || fingers
238
+ else
239
+ duration = duration_or_options
240
+ end
241
+ end
242
+
243
+ recognizer = UILongPressGestureRecognizer.alloc.initWithTarget(self, action:'sugarcube_handle_gesture:')
244
+ recognizer.minimumPressDuration = duration if duration
245
+ recognizer.numberOfTapsRequired = taps if taps
246
+ recognizer.numberOfTouchesRequired = fingers if fingers
247
+ sugarcube_add_gesture(proc, recognizer)
248
+ end
249
+
250
+ def on_press_begin(duration_or_options=nil, &proc)
251
+ duration = nil
252
+ taps = nil
253
+ fingers = nil
254
+
255
+ if duration_or_options
256
+ if duration_or_options.is_a? Hash
257
+ duration = duration_or_options[:duration] || duration
258
+ taps = duration_or_options[:taps] || taps
259
+ fingers = duration_or_options[:fingers] || fingers
260
+ else
261
+ duration = duration_or_options
262
+ end
263
+ end
264
+
265
+ recognizer = UILongPressGestureRecognizer.alloc.initWithTarget(self, action:'sugarcube_handle_gesture_long_press_on_begin:')
266
+ recognizer.minimumPressDuration = duration if duration
267
+ recognizer.numberOfTapsRequired = taps if taps
268
+ recognizer.numberOfTouchesRequired = fingers if fingers
269
+ sugarcube_add_gesture(proc, recognizer)
270
+ end
271
+
272
+
273
+ private
274
+ def sugarcube_handle_gesture(recognizer)
275
+ handler = @sugarcube_recognizers[recognizer]
276
+ if handler.arity == 0
277
+ handler.call
278
+ else
279
+ handler.call(recognizer)
280
+ end
281
+ end
282
+ def sugarcube_handle_gesture_long_press_on_begin(recognizer)
283
+ if recognizer.state==UIGestureRecognizerStateBegan
284
+ handler = @sugarcube_recognizers[recognizer]
285
+ if handler.arity == 0
286
+ handler.call
287
+ else
288
+ handler.call(recognizer)
289
+ end
290
+ end
291
+ end
292
+
293
+ # Adds the recognizer and keeps a strong reference to the Proc object.
294
+ def sugarcube_add_gesture(proc, recognizer)
295
+ unless self.userInteractionEnabled?
296
+ puts("SugarCube: userInteractionEnabled is false on #{self.inspect}. Adding a gesture will have no effect.")
297
+ end
298
+ self.addGestureRecognizer(recognizer)
299
+
300
+ @sugarcube_recognizers = {} unless @sugarcube_recognizers
301
+ @sugarcube_recognizers[recognizer] = proc.respond_to?('weak!') ? proc.weak! : proc
302
+
303
+ recognizer
304
+ end
305
+
306
+ end