summary refs log tree commit diff stats
path: root/libs/cocos2d/CCMenu.m
diff options
context:
space:
mode:
Diffstat (limited to 'libs/cocos2d/CCMenu.m')
-rwxr-xr-xlibs/cocos2d/CCMenu.m523
1 files changed, 523 insertions, 0 deletions
diff --git a/libs/cocos2d/CCMenu.m b/libs/cocos2d/CCMenu.m new file mode 100755 index 0000000..c3cb8f2 --- /dev/null +++ b/libs/cocos2d/CCMenu.m
@@ -0,0 +1,523 @@
1/*
2 * cocos2d for iPhone: http://www.cocos2d-iphone.org
3 *
4 * Copyright (c) 2008-2010 Ricardo Quesada
5 * Copyright (c) 2011 Zynga Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 *
25 */
26
27
28
29#import "CCMenu.h"
30#import "CCDirector.h"
31#import "Support/CGPointExtension.h"
32#import "ccMacros.h"
33
34#import <Availability.h>
35#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
36#import "Platforms/iOS/CCDirectorIOS.h"
37#import "Platforms/iOS/CCTouchDispatcher.h"
38#elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED)
39#import "Platforms/Mac/MacGLView.h"
40#import "Platforms/Mac/CCDirectorMac.h"
41#endif
42
43enum {
44 kDefaultPadding = 5,
45};
46
47@implementation CCMenu
48
49@synthesize opacity = opacity_, color = color_;
50
51- (id) init
52{
53 NSAssert(NO, @"CCMenu: Init not supported.");
54 [self release];
55 return nil;
56}
57
58+(id) menuWithItems: (CCMenuItem*) item, ...
59{
60 va_list args;
61 va_start(args,item);
62
63 id s = [[[self alloc] initWithItems: item vaList:args] autorelease];
64
65 va_end(args);
66 return s;
67}
68
69-(id) initWithItems: (CCMenuItem*) item vaList: (va_list) args
70{
71 if( (self=[super init]) ) {
72
73#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
74 self.isTouchEnabled = YES;
75#elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED)
76 self.isMouseEnabled = YES;
77#endif
78
79 // menu in the center of the screen
80 CGSize s = [[CCDirector sharedDirector] winSize];
81
82 self.isRelativeAnchorPoint = NO;
83 anchorPoint_ = ccp(0.5f, 0.5f);
84 [self setContentSize:s];
85
86 // XXX: in v0.7, winSize should return the visible size
87 // XXX: so the bar calculation should be done there
88#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
89 CGRect r = [[UIApplication sharedApplication] statusBarFrame];
90 ccDeviceOrientation orientation = [[CCDirector sharedDirector] deviceOrientation];
91 if( orientation == CCDeviceOrientationLandscapeLeft || orientation == CCDeviceOrientationLandscapeRight )
92 s.height -= r.size.width;
93 else
94 s.height -= r.size.height;
95#endif
96 self.position = ccp(s.width/2, s.height/2);
97
98 int z=0;
99
100 if (item) {
101 [self addChild: item z:z];
102 CCMenuItem *i = va_arg(args, CCMenuItem*);
103 while(i) {
104 z++;
105 [self addChild: i z:z];
106 i = va_arg(args, CCMenuItem*);
107 }
108 }
109 // [self alignItemsVertically];
110
111 selectedItem_ = nil;
112 state_ = kCCMenuStateWaiting;
113 }
114
115 return self;
116}
117
118-(void) dealloc
119{
120 [super dealloc];
121}
122
123/*
124 * override add:
125 */
126-(void) addChild:(CCMenuItem*)child z:(NSInteger)z tag:(NSInteger) aTag
127{
128 NSAssert( [child isKindOfClass:[CCMenuItem class]], @"Menu only supports MenuItem objects as children");
129 [super addChild:child z:z tag:aTag];
130}
131
132- (void) onExit
133{
134 if(state_ == kCCMenuStateTrackingTouch)
135 {
136 [selectedItem_ unselected];
137 state_ = kCCMenuStateWaiting;
138 selectedItem_ = nil;
139 }
140 [super onExit];
141}
142
143#pragma mark Menu - Touches
144
145#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
146-(void) registerWithTouchDispatcher
147{
148 [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:kCCMenuTouchPriority swallowsTouches:YES];
149}
150
151-(CCMenuItem *) itemForTouch: (UITouch *) touch
152{
153 CGPoint touchLocation = [touch locationInView: [touch view]];
154 touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];
155
156 CCMenuItem* item;
157 CCARRAY_FOREACH(children_, item){
158 // ignore invisible and disabled items: issue #779, #866
159 if ( [item visible] && [item isEnabled] ) {
160
161 CGPoint local = [item convertToNodeSpace:touchLocation];
162 CGRect r = [item rect];
163 r.origin = CGPointZero;
164
165 if( CGRectContainsPoint( r, local ) )
166 return item;
167 }
168 }
169 return nil;
170}
171
172-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
173{
174 if( state_ != kCCMenuStateWaiting || !visible_ )
175 return NO;
176
177 selectedItem_ = [self itemForTouch:touch];
178 [selectedItem_ selected];
179
180 if( selectedItem_ ) {
181 state_ = kCCMenuStateTrackingTouch;
182 return YES;
183 }
184 return NO;
185}
186
187-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
188{
189 NSAssert(state_ == kCCMenuStateTrackingTouch, @"[Menu ccTouchEnded] -- invalid state");
190
191 [selectedItem_ unselected];
192 [selectedItem_ activate];
193
194 state_ = kCCMenuStateWaiting;
195}
196
197-(void) ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event
198{
199 NSAssert(state_ == kCCMenuStateTrackingTouch, @"[Menu ccTouchCancelled] -- invalid state");
200
201 [selectedItem_ unselected];
202
203 state_ = kCCMenuStateWaiting;
204}
205
206-(void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
207{
208 NSAssert(state_ == kCCMenuStateTrackingTouch, @"[Menu ccTouchMoved] -- invalid state");
209
210 CCMenuItem *currentItem = [self itemForTouch:touch];
211
212 if (currentItem != selectedItem_) {
213 [selectedItem_ unselected];
214 selectedItem_ = currentItem;
215 [selectedItem_ selected];
216 }
217}
218
219#pragma mark Menu - Mouse
220
221#elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED)
222
223-(NSInteger) mouseDelegatePriority
224{
225 return kCCMenuMousePriority+1;
226}
227
228-(CCMenuItem *) itemForMouseEvent: (NSEvent *) event
229{
230 CGPoint location = [(CCDirectorMac*)[CCDirector sharedDirector] convertEventToGL:event];
231
232 CCMenuItem* item;
233 CCARRAY_FOREACH(children_, item){
234 // ignore invisible and disabled items: issue #779, #866
235 if ( [item visible] && [item isEnabled] ) {
236
237 CGPoint local = [item convertToNodeSpace:location];
238
239 CGRect r = [item rect];
240 r.origin = CGPointZero;
241
242 if( CGRectContainsPoint( r, local ) )
243 return item;
244 }
245 }
246 return nil;
247}
248
249-(BOOL) ccMouseUp:(NSEvent *)event
250{
251 if( ! visible_ )
252 return NO;
253
254 if(state_ == kCCMenuStateTrackingTouch) {
255 if( selectedItem_ ) {
256 [selectedItem_ unselected];
257 [selectedItem_ activate];
258 }
259 state_ = kCCMenuStateWaiting;
260
261 return YES;
262 }
263 return NO;
264}
265
266-(BOOL) ccMouseDown:(NSEvent *)event
267{
268 if( ! visible_ )
269 return NO;
270
271 selectedItem_ = [self itemForMouseEvent:event];
272 [selectedItem_ selected];
273
274 if( selectedItem_ ) {
275 state_ = kCCMenuStateTrackingTouch;
276 return YES;
277 }
278
279 return NO;
280}
281
282-(BOOL) ccMouseDragged:(NSEvent *)event
283{
284 if( ! visible_ )
285 return NO;
286
287 if(state_ == kCCMenuStateTrackingTouch) {
288 CCMenuItem *currentItem = [self itemForMouseEvent:event];
289
290 if (currentItem != selectedItem_) {
291 [selectedItem_ unselected];
292 selectedItem_ = currentItem;
293 [selectedItem_ selected];
294 }
295
296 return YES;
297 }
298 return NO;
299}
300
301#endif // Mac Mouse support
302
303#pragma mark Menu - Alignment
304-(void) alignItemsVertically
305{
306 [self alignItemsVerticallyWithPadding:kDefaultPadding];
307}
308-(void) alignItemsVerticallyWithPadding:(float)padding
309{
310 float height = -padding;
311
312 CCMenuItem *item;
313 CCARRAY_FOREACH(children_, item)
314 height += item.contentSize.height * item.scaleY + padding;
315
316 float y = height / 2.0f;
317
318 CCARRAY_FOREACH(children_, item) {
319 CGSize itemSize = item.contentSize;
320 [item setPosition:ccp(0, y - itemSize.height * item.scaleY / 2.0f)];
321 y -= itemSize.height * item.scaleY + padding;
322 }
323}
324
325-(void) alignItemsHorizontally
326{
327 [self alignItemsHorizontallyWithPadding:kDefaultPadding];
328}
329
330-(void) alignItemsHorizontallyWithPadding:(float)padding
331{
332
333 float width = -padding;
334 CCMenuItem *item;
335 CCARRAY_FOREACH(children_, item)
336 width += item.contentSize.width * item.scaleX + padding;
337
338 float x = -width / 2.0f;
339
340 CCARRAY_FOREACH(children_, item){
341 CGSize itemSize = item.contentSize;
342 [item setPosition:ccp(x + itemSize.width * item.scaleX / 2.0f, 0)];
343 x += itemSize.width * item.scaleX + padding;
344 }
345}
346
347-(void) alignItemsInColumns: (NSNumber *) columns, ...
348{
349 va_list args;
350 va_start(args, columns);
351
352 [self alignItemsInColumns:columns vaList:args];
353
354 va_end(args);
355}
356
357-(void) alignItemsInColumns: (NSNumber *) columns vaList: (va_list) args
358{
359 NSMutableArray *rows = [[NSMutableArray alloc] initWithObjects:columns, nil];
360 columns = va_arg(args, NSNumber*);
361 while(columns) {
362 [rows addObject:columns];
363 columns = va_arg(args, NSNumber*);
364 }
365
366 int height = -5;
367 NSUInteger row = 0, rowHeight = 0, columnsOccupied = 0, rowColumns;
368 CCMenuItem *item;
369 CCARRAY_FOREACH(children_, item){
370 NSAssert( row < [rows count], @"Too many menu items for the amount of rows/columns.");
371
372 rowColumns = [(NSNumber *) [rows objectAtIndex:row] unsignedIntegerValue];
373 NSAssert( rowColumns, @"Can't have zero columns on a row");
374
375 rowHeight = fmaxf(rowHeight, item.contentSize.height);
376 ++columnsOccupied;
377
378 if(columnsOccupied >= rowColumns) {
379 height += rowHeight + 5;
380
381 columnsOccupied = 0;
382 rowHeight = 0;
383 ++row;
384 }
385 }
386 NSAssert( !columnsOccupied, @"Too many rows/columns for available menu items." );
387
388 CGSize winSize = [[CCDirector sharedDirector] winSize];
389
390 row = 0; rowHeight = 0; rowColumns = 0;
391 float w, x, y = height / 2;
392 CCARRAY_FOREACH(children_, item) {
393 if(rowColumns == 0) {
394 rowColumns = [(NSNumber *) [rows objectAtIndex:row] unsignedIntegerValue];
395 w = winSize.width / (1 + rowColumns);
396 x = w;
397 }
398
399 CGSize itemSize = item.contentSize;
400 rowHeight = fmaxf(rowHeight, itemSize.height);
401 [item setPosition:ccp(x - winSize.width / 2,
402 y - itemSize.height / 2)];
403
404 x += w;
405 ++columnsOccupied;
406
407 if(columnsOccupied >= rowColumns) {
408 y -= rowHeight + 5;
409
410 columnsOccupied = 0;
411 rowColumns = 0;
412 rowHeight = 0;
413 ++row;
414 }
415 }
416
417 [rows release];
418}
419
420-(void) alignItemsInRows: (NSNumber *) rows, ...
421{
422 va_list args;
423 va_start(args, rows);
424
425 [self alignItemsInRows:rows vaList:args];
426
427 va_end(args);
428}
429
430-(void) alignItemsInRows: (NSNumber *) rows vaList: (va_list) args
431{
432 NSMutableArray *columns = [[NSMutableArray alloc] initWithObjects:rows, nil];
433 rows = va_arg(args, NSNumber*);
434 while(rows) {
435 [columns addObject:rows];
436 rows = va_arg(args, NSNumber*);
437 }
438
439 NSMutableArray *columnWidths = [[NSMutableArray alloc] init];
440 NSMutableArray *columnHeights = [[NSMutableArray alloc] init];
441
442 int width = -10, columnHeight = -5;
443 NSUInteger column = 0, columnWidth = 0, rowsOccupied = 0, columnRows;
444 CCMenuItem *item;
445 CCARRAY_FOREACH(children_, item){
446 NSAssert( column < [columns count], @"Too many menu items for the amount of rows/columns.");
447
448 columnRows = [(NSNumber *) [columns objectAtIndex:column] unsignedIntegerValue];
449 NSAssert( columnRows, @"Can't have zero rows on a column");
450
451 CGSize itemSize = item.contentSize;
452 columnWidth = fmaxf(columnWidth, itemSize.width);
453 columnHeight += itemSize.height + 5;
454 ++rowsOccupied;
455
456 if(rowsOccupied >= columnRows) {
457 [columnWidths addObject:[NSNumber numberWithUnsignedInteger:columnWidth]];
458 [columnHeights addObject:[NSNumber numberWithUnsignedInteger:columnHeight]];
459 width += columnWidth + 10;
460
461 rowsOccupied = 0;
462 columnWidth = 0;
463 columnHeight = -5;
464 ++column;
465 }
466 }
467 NSAssert( !rowsOccupied, @"Too many rows/columns for available menu items.");
468
469 CGSize winSize = [[CCDirector sharedDirector] winSize];
470
471 column = 0; columnWidth = 0; columnRows = 0;
472 float x = -width / 2, y;
473
474 CCARRAY_FOREACH(children_, item){
475 if(columnRows == 0) {
476 columnRows = [(NSNumber *) [columns objectAtIndex:column] unsignedIntegerValue];
477 y = ([(NSNumber *) [columnHeights objectAtIndex:column] intValue] + winSize.height) / 2;
478 }
479
480 CGSize itemSize = item.contentSize;
481 columnWidth = fmaxf(columnWidth, itemSize.width);
482 [item setPosition:ccp(x + [(NSNumber *) [columnWidths objectAtIndex:column] unsignedIntegerValue] / 2,
483 y - winSize.height / 2)];
484
485 y -= itemSize.height + 10;
486 ++rowsOccupied;
487
488 if(rowsOccupied >= columnRows) {
489 x += columnWidth + 5;
490
491 rowsOccupied = 0;
492 columnRows = 0;
493 columnWidth = 0;
494 ++column;
495 }
496 }
497
498 [columns release];
499 [columnWidths release];
500 [columnHeights release];
501}
502
503#pragma mark Menu - Opacity Protocol
504
505/** Override synthesized setOpacity to recurse items */
506- (void) setOpacity:(GLubyte)newOpacity
507{
508 opacity_ = newOpacity;
509
510 id<CCRGBAProtocol> item;
511 CCARRAY_FOREACH(children_, item)
512 [item setOpacity:opacity_];
513}
514
515-(void) setColor:(ccColor3B)color
516{
517 color_ = color;
518
519 id<CCRGBAProtocol> item;
520 CCARRAY_FOREACH(children_, item)
521 [item setColor:color_];
522}
523@end