diff options
Diffstat (limited to 'libs/cocos2d/Platforms/iOS/CCTouchDispatcher.m')
-rwxr-xr-x | libs/cocos2d/Platforms/iOS/CCTouchDispatcher.m | 347 |
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 | |||
39 | static 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 | |||
202 | NSComparisonResult 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 | ||