summary refs log tree commit diff stats
path: root/libs/cocos2d/Platforms/iOS/CCTouchDispatcher.m
diff options
context:
space:
mode:
Diffstat (limited to 'libs/cocos2d/Platforms/iOS/CCTouchDispatcher.m')
-rwxr-xr-xlibs/cocos2d/Platforms/iOS/CCTouchDispatcher.m347
1 files changed, 347 insertions, 0 deletions
diff --git a/libs/cocos2d/Platforms/iOS/CCTouchDispatcher.m b/libs/cocos2d/Platforms/iOS/CCTouchDispatcher.m new file mode 100755 index 0000000..1553b48 --- /dev/null +++ b/libs/cocos2d/Platforms/iOS/CCTouchDispatcher.m
@@ -0,0 +1,347 @@
1/*
2 * cocos2d for iPhone: http://www.cocos2d-iphone.org
3 *
4 * Copyright (c) 2009 Valentin Milea
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 */
25
26// Only compile this code on iOS. These files should NOT be included on your Mac project.
27// But in case they are included, it won't be compiled.
28#import <Availability.h>
29#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
30
31
32#import "CCTouchDispatcher.h"
33#import "CCTouchHandler.h"
34
35@implementation CCTouchDispatcher
36
37@synthesize dispatchEvents;
38
39static CCTouchDispatcher *sharedDispatcher = nil;
40
41+(CCTouchDispatcher*) sharedDispatcher
42{
43 @synchronized(self) {
44 if (sharedDispatcher == nil)
45 sharedDispatcher = [[self alloc] init]; // assignment not done here
46 }
47 return sharedDispatcher;
48}
49
50+(id) allocWithZone:(NSZone *)zone
51{
52 @synchronized(self) {
53 NSAssert(sharedDispatcher == nil, @"Attempted to allocate a second instance of a singleton.");
54 return [super allocWithZone:zone];
55 }
56 return nil; // on subsequent allocation attempts return nil
57}
58
59-(id) init
60{
61 if((self = [super init])) {
62
63 dispatchEvents = YES;
64 targetedHandlers = [[NSMutableArray alloc] initWithCapacity:8];
65 standardHandlers = [[NSMutableArray alloc] initWithCapacity:4];
66
67 handlersToAdd = [[NSMutableArray alloc] initWithCapacity:8];
68 handlersToRemove = [[NSMutableArray alloc] initWithCapacity:8];
69
70 toRemove = NO;
71 toAdd = NO;
72 toQuit = NO;
73 locked = NO;
74
75 handlerHelperData[kCCTouchBegan] = (struct ccTouchHandlerHelperData) {@selector(ccTouchesBegan:withEvent:),@selector(ccTouchBegan:withEvent:),kCCTouchSelectorBeganBit};
76 handlerHelperData[kCCTouchMoved] = (struct ccTouchHandlerHelperData) {@selector(ccTouchesMoved:withEvent:),@selector(ccTouchMoved:withEvent:),kCCTouchSelectorMovedBit};
77 handlerHelperData[kCCTouchEnded] = (struct ccTouchHandlerHelperData) {@selector(ccTouchesEnded:withEvent:),@selector(ccTouchEnded:withEvent:),kCCTouchSelectorEndedBit};
78 handlerHelperData[kCCTouchCancelled] = (struct ccTouchHandlerHelperData) {@selector(ccTouchesCancelled:withEvent:),@selector(ccTouchCancelled:withEvent:),kCCTouchSelectorCancelledBit};
79
80 }
81
82 return self;
83}
84
85-(void) dealloc
86{
87 [targetedHandlers release];
88 [standardHandlers release];
89 [handlersToAdd release];
90 [handlersToRemove release];
91 [super dealloc];
92}
93
94//
95// handlers management
96//
97
98#pragma mark TouchDispatcher - Add Hanlder
99
100-(void) forceAddHandler:(CCTouchHandler*)handler array:(NSMutableArray*)array
101{
102 NSUInteger i = 0;
103
104 for( CCTouchHandler *h in array ) {
105 if( h.priority < handler.priority )
106 i++;
107
108 NSAssert( h.delegate != handler.delegate, @"Delegate already added to touch dispatcher.");
109 }
110 [array insertObject:handler atIndex:i];
111}
112
113-(void) addStandardDelegate:(id<CCStandardTouchDelegate>) delegate priority:(int)priority
114{
115 CCTouchHandler *handler = [CCStandardTouchHandler handlerWithDelegate:delegate priority:priority];
116 if( ! locked ) {
117 [self forceAddHandler:handler array:standardHandlers];
118 } else {
119 [handlersToAdd addObject:handler];
120 toAdd = YES;
121 }
122}
123
124-(void) addTargetedDelegate:(id<CCTargetedTouchDelegate>) delegate priority:(int)priority swallowsTouches:(BOOL)swallowsTouches
125{
126 CCTouchHandler *handler = [CCTargetedTouchHandler handlerWithDelegate:delegate priority:priority swallowsTouches:swallowsTouches];
127 if( ! locked ) {
128 [self forceAddHandler:handler array:targetedHandlers];
129 } else {
130 [handlersToAdd addObject:handler];
131 toAdd = YES;
132 }
133}
134
135#pragma mark TouchDispatcher - removeDelegate
136
137-(void) forceRemoveDelegate:(id)delegate
138{
139 // XXX: remove it from both handlers ???
140
141 for( CCTouchHandler *handler in targetedHandlers ) {
142 if( handler.delegate == delegate ) {
143 [targetedHandlers removeObject:handler];
144 break;
145 }
146 }
147
148 for( CCTouchHandler *handler in standardHandlers ) {
149 if( handler.delegate == delegate ) {
150 [standardHandlers removeObject:handler];
151 break;
152 }
153 }
154}
155
156-(void) removeDelegate:(id) delegate
157{
158 if( delegate == nil )
159 return;
160
161 if( ! locked ) {
162 [self forceRemoveDelegate:delegate];
163 } else {
164 [handlersToRemove addObject:delegate];
165 toRemove = YES;
166 }
167}
168
169#pragma mark TouchDispatcher - removeAllDelegates
170
171-(void) forceRemoveAllDelegates
172{
173 [standardHandlers removeAllObjects];
174 [targetedHandlers removeAllObjects];
175}
176-(void) removeAllDelegates
177{
178 if( ! locked )
179 [self forceRemoveAllDelegates];
180 else
181 toQuit = YES;
182}
183
184#pragma mark Changing priority of added handlers
185
186-(CCTouchHandler*) findHandler:(id)delegate
187{
188 for( CCTouchHandler *handler in targetedHandlers ) {
189 if( handler.delegate == delegate ) {
190 return handler;
191 }
192 }
193
194 for( CCTouchHandler *handler in standardHandlers ) {
195 if( handler.delegate == delegate ) {
196 return handler;
197 }
198 }
199 return nil;
200}
201
202NSComparisonResult sortByPriority(id first, id second, void *context)
203{
204 if (((CCTouchHandler*)first).priority < ((CCTouchHandler*)second).priority)
205 return NSOrderedAscending;
206 else if (((CCTouchHandler*)first).priority > ((CCTouchHandler*)second).priority)
207 return NSOrderedDescending;
208 else
209 return NSOrderedSame;
210}
211
212-(void) rearrangeHandlers:(NSMutableArray*)array
213{
214 [array sortUsingFunction:sortByPriority context:nil];
215}
216
217-(void) setPriority:(int) priority forDelegate:(id) delegate
218{
219 NSAssert(delegate != nil, @"Got nil touch delegate!");
220
221 CCTouchHandler *handler = nil;
222 handler = [self findHandler:delegate];
223
224 NSAssert(handler != nil, @"Delegate not found!");
225
226 handler.priority = priority;
227
228 [self rearrangeHandlers:targetedHandlers];
229 [self rearrangeHandlers:standardHandlers];
230}
231
232//
233// dispatch events
234//
235-(void) touches:(NSSet*)touches withEvent:(UIEvent*)event withTouchType:(unsigned int)idx
236{
237 NSAssert(idx < 4, @"Invalid idx value");
238
239 id mutableTouches;
240 locked = YES;
241
242 // optimization to prevent a mutable copy when it is not necessary
243 unsigned int targetedHandlersCount = [targetedHandlers count];
244 unsigned int standardHandlersCount = [standardHandlers count];
245 BOOL needsMutableSet = (targetedHandlersCount && standardHandlersCount);
246
247 mutableTouches = (needsMutableSet ? [touches mutableCopy] : touches);
248
249 struct ccTouchHandlerHelperData helper = handlerHelperData[idx];
250 //
251 // process the target handlers 1st
252 //
253 if( targetedHandlersCount > 0 ) {
254 for( UITouch *touch in touches ) {
255 for(CCTargetedTouchHandler *handler in targetedHandlers) {
256
257 BOOL claimed = NO;
258 if( idx == kCCTouchBegan ) {
259 claimed = [handler.delegate ccTouchBegan:touch withEvent:event];
260 if( claimed )
261 [handler.claimedTouches addObject:touch];
262 }
263
264 // else (moved, ended, cancelled)
265 else if( [handler.claimedTouches containsObject:touch] ) {
266 claimed = YES;
267 if( handler.enabledSelectors & helper.type )
268 [handler.delegate performSelector:helper.touchSel withObject:touch withObject:event];
269
270 if( helper.type & (kCCTouchSelectorCancelledBit | kCCTouchSelectorEndedBit) )
271 [handler.claimedTouches removeObject:touch];
272 }
273
274 if( claimed && handler.swallowsTouches ) {
275 if( needsMutableSet )
276 [mutableTouches removeObject:touch];
277 break;
278 }
279 }
280 }
281 }
282
283 //
284 // process standard handlers 2nd
285 //
286 if( standardHandlersCount > 0 && [mutableTouches count]>0 ) {
287 for( CCTouchHandler *handler in standardHandlers ) {
288 if( handler.enabledSelectors & helper.type )
289 [handler.delegate performSelector:helper.touchesSel withObject:mutableTouches withObject:event];
290 }
291 }
292 if( needsMutableSet )
293 [mutableTouches release];
294
295 //
296 // Optimization. To prevent a [handlers copy] which is expensive
297 // the add/removes/quit is done after the iterations
298 //
299 locked = NO;
300 if( toRemove ) {
301 toRemove = NO;
302 for( id delegate in handlersToRemove )
303 [self forceRemoveDelegate:delegate];
304 [handlersToRemove removeAllObjects];
305 }
306 if( toAdd ) {
307 toAdd = NO;
308 for( CCTouchHandler *handler in handlersToAdd ) {
309 Class targetedClass = [CCTargetedTouchHandler class];
310 if( [handler isKindOfClass:targetedClass] )
311 [self forceAddHandler:handler array:targetedHandlers];
312 else
313 [self forceAddHandler:handler array:standardHandlers];
314 }
315 [handlersToAdd removeAllObjects];
316 }
317 if( toQuit ) {
318 toQuit = NO;
319 [self forceRemoveAllDelegates];
320 }
321}
322
323- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
324{
325 if( dispatchEvents )
326 [self touches:touches withEvent:event withTouchType:kCCTouchBegan];
327}
328- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
329{
330 if( dispatchEvents )
331 [self touches:touches withEvent:event withTouchType:kCCTouchMoved];
332}
333
334- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
335{
336 if( dispatchEvents )
337 [self touches:touches withEvent:event withTouchType:kCCTouchEnded];
338}
339
340- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
341{
342 if( dispatchEvents )
343 [self touches:touches withEvent:event withTouchType:kCCTouchCancelled];
344}
345@end
346
347#endif // __IPHONE_OS_VERSION_MAX_ALLOWED