cocoaTouch/OverlayViewController.m
changeset 3516 a8c673657b79
parent 3510 23145a950eae
parent 3515 3e8635f43972
child 3529 0e968ba12a84
equal deleted inserted replaced
3510:23145a950eae 3516:a8c673657b79
     1 //
       
     2 //  overlayViewController.m
       
     3 //  HedgewarsMobile
       
     4 //
       
     5 //  Created by Vittorio on 16/03/10.
       
     6 //  Copyright 2010 __MyCompanyName__. All rights reserved.
       
     7 //
       
     8 
       
     9 #import "OverlayViewController.h"
       
    10 #import "SDL_uikitappdelegate.h"
       
    11 #import "PascalImports.h"
       
    12 #import "CGPointUtils.h"
       
    13 #import "SDL_mouse.h"
       
    14 #import "SDL_config_iphoneos.h"
       
    15 #import "PopoverMenuViewController.h"
       
    16 #import "CommodityFunctions.h"
       
    17 
       
    18 #define HIDING_TIME_DEFAULT [NSDate dateWithTimeIntervalSinceNow:2.7]
       
    19 #define HIDING_TIME_NEVER   [NSDate dateWithTimeIntervalSinceNow:10000]
       
    20 
       
    21 
       
    22 @implementation OverlayViewController
       
    23 @synthesize popoverController, popupMenu, writeChatTextField;
       
    24 
       
    25 
       
    26 -(BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation) interfaceOrientation {
       
    27 	return rotationManager(interfaceOrientation);
       
    28 }
       
    29 
       
    30 
       
    31 -(void) didReceiveMemoryWarning {
       
    32 	// Releases the view if it doesn't have a superview.
       
    33     [super didReceiveMemoryWarning];
       
    34 	// Release any cached data, images, etc that aren't in use.
       
    35     if (popupMenu.view.superview == nil) 
       
    36         popupMenu = nil;
       
    37 }
       
    38 
       
    39 -(void) didRotate:(NSNotification *)notification {	
       
    40     UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
       
    41     CGRect rect = [[UIScreen mainScreen] bounds];
       
    42     CGRect usefulRect = CGRectMake(0, 0, rect.size.width, rect.size.height);
       
    43     UIView *sdlView = [[[UIApplication sharedApplication] keyWindow] viewWithTag:12345];
       
    44     
       
    45     [UIView beginAnimations:@"rotation" context:NULL];
       
    46     [UIView setAnimationDuration:0.8f];
       
    47     [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
       
    48 	switch (orientation) {
       
    49         case UIDeviceOrientationLandscapeLeft:
       
    50             sdlView.transform = CGAffineTransformMakeRotation(degreesToRadian(0));
       
    51             self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
       
    52             [self chatDisappear];
       
    53             HW_setLandscape(YES);
       
    54             break;
       
    55         case UIDeviceOrientationLandscapeRight:
       
    56             sdlView.transform = CGAffineTransformMakeRotation(degreesToRadian(180));
       
    57             self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(-90));
       
    58             [self chatDisappear];
       
    59             HW_setLandscape(YES);
       
    60             break;
       
    61         case UIDeviceOrientationPortrait:
       
    62             sdlView.transform = CGAffineTransformMakeRotation(degreesToRadian(270));
       
    63             self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(0));
       
    64             [self chatAppear];
       
    65             HW_setLandscape(NO);
       
    66             break;
       
    67         case UIDeviceOrientationPortraitUpsideDown:
       
    68             sdlView.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
       
    69             self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(180));
       
    70             [self chatAppear];
       
    71             HW_setLandscape(NO);
       
    72             break;
       
    73         default:
       
    74             NSLog(@"warning - Unknown rotation status");
       
    75             break;
       
    76     }
       
    77     self.view.frame = usefulRect;
       
    78     //sdlView.frame = usefulRect;
       
    79     [UIView commitAnimations];
       
    80 }
       
    81 
       
    82 -(void) chatAppear {
       
    83     if (writeChatTextField == nil) {
       
    84         writeChatTextField = [[UITextField alloc] initWithFrame:CGRectMake(0, 100, 768, [UIFont systemFontSize]+8)];
       
    85         writeChatTextField.textColor = [UIColor whiteColor];
       
    86         writeChatTextField.backgroundColor = [UIColor blueColor];
       
    87         writeChatTextField.autocapitalizationType = UITextAutocapitalizationTypeNone;
       
    88         writeChatTextField.autocorrectionType = UITextAutocorrectionTypeNo;
       
    89         writeChatTextField.enablesReturnKeyAutomatically = NO;
       
    90         writeChatTextField.keyboardAppearance = UIKeyboardAppearanceDefault;
       
    91         writeChatTextField.keyboardType = UIKeyboardTypeDefault;
       
    92         writeChatTextField.returnKeyType = UIReturnKeyDefault;
       
    93         writeChatTextField.secureTextEntry = NO;	
       
    94         [self.view addSubview:writeChatTextField];
       
    95     }
       
    96     writeChatTextField.alpha = 1;
       
    97     [self activateOverlay];
       
    98     [dimTimer setFireDate:HIDING_TIME_NEVER];
       
    99 }
       
   100 
       
   101 -(void) chatDisappear {
       
   102     writeChatTextField.alpha = 0;
       
   103     [writeChatTextField resignFirstResponder];
       
   104     [dimTimer setFireDate:HIDING_TIME_DEFAULT];
       
   105 }
       
   106 
       
   107 -(void) viewDidLoad {
       
   108     isPopoverVisible = NO;
       
   109     self.view.alpha = 0;
       
   110     self.view.center = CGPointMake(self.view.frame.size.height/2.0, self.view.frame.size.width/2.0);
       
   111     
       
   112     
       
   113     dimTimer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:6]
       
   114                                         interval:1000
       
   115                                           target:self
       
   116                                         selector:@selector(dimOverlay)
       
   117                                         userInfo:nil
       
   118                                          repeats:YES];
       
   119     
       
   120     // add timer too runloop, otherwise it doesn't work
       
   121     [[NSRunLoop currentRunLoop] addTimer:dimTimer forMode:NSDefaultRunLoopMode];
       
   122     
       
   123     // listen for dismissal of the popover (see below)
       
   124     [[NSNotificationCenter defaultCenter] addObserver:self
       
   125                                              selector:@selector(dismissPopover)
       
   126                                                  name:@"dismissPopover"
       
   127                                                object:nil];
       
   128     
       
   129     // need to split paths because iphone doesn't rotate (so we don't need to subscribe to any notification
       
   130     // nor perform engine actions when rotating
       
   131     if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
       
   132         [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];	
       
   133         [[NSNotificationCenter defaultCenter] addObserver:self
       
   134                                                  selector:@selector(didRotate:)
       
   135                                                      name:@"UIDeviceOrientationDidChangeNotification"
       
   136                                                    object:nil];
       
   137         
       
   138         [self didRotate:nil];
       
   139     } else 
       
   140         self.view.transform = CGAffineTransformRotate(self.view.transform, (M_PI/2.0));
       
   141     
       
   142 	[UIView beginAnimations:@"showing overlay" context:NULL];
       
   143 	[UIView setAnimationDuration:1];
       
   144 	self.view.alpha = 1;
       
   145 	[UIView commitAnimations];
       
   146 }
       
   147 
       
   148 -(void) viewDidUnload {
       
   149     self.writeChatTextField = nil;
       
   150     self.popoverController = nil;
       
   151     self.popupMenu = nil;
       
   152     [super viewDidUnload];
       
   153     MSG_DIDUNLOAD();
       
   154 }
       
   155 
       
   156 -(void) dealloc {
       
   157 	[dimTimer invalidate];
       
   158     [writeChatTextField release];
       
   159     [popupMenu release];
       
   160     [popoverController release];
       
   161     // dimTimer is autoreleased
       
   162     [super dealloc];
       
   163 }
       
   164 
       
   165 // dim the overlay when there's no more input for a certain amount of time
       
   166 -(IBAction) buttonReleased:(id) sender {
       
   167 	HW_allKeysUp();
       
   168     [dimTimer setFireDate:HIDING_TIME_DEFAULT];
       
   169 }
       
   170 
       
   171 // nice transition for dimming, should be called only by the timer himself
       
   172 -(void) dimOverlay {
       
   173     [UIView beginAnimations:@"overlay dim" context:NULL];
       
   174    	[UIView setAnimationDuration:0.6];
       
   175     self.view.alpha = 0.2;
       
   176 	[UIView commitAnimations];
       
   177 }
       
   178 
       
   179 // set the overlay visible and put off the timer for enough time
       
   180 -(void) activateOverlay {
       
   181     self.view.alpha = 1;
       
   182     [dimTimer setFireDate:HIDING_TIME_NEVER];
       
   183 }
       
   184 
       
   185 // issue certain action based on the tag of the button 
       
   186 -(IBAction) buttonPressed:(id) sender {
       
   187     [self activateOverlay];
       
   188     if (isPopoverVisible) {
       
   189         [self dismissPopover];
       
   190     }
       
   191     UIButton *theButton = (UIButton *)sender;
       
   192     
       
   193     switch (theButton.tag) {
       
   194         case 0:
       
   195             HW_walkLeft();
       
   196             break;
       
   197         case 1:
       
   198             HW_walkRight();
       
   199             break;
       
   200         case 2:
       
   201             HW_aimUp();
       
   202             break;
       
   203         case 3:
       
   204             HW_aimDown();
       
   205             break;
       
   206         case 4:
       
   207             HW_shoot();
       
   208             break;
       
   209         case 5:
       
   210             HW_jump();
       
   211             break;
       
   212         case 6:
       
   213             HW_backjump();
       
   214             break;
       
   215         case 7:
       
   216             HW_tab();
       
   217             break;
       
   218         case 10:
       
   219             [self showPopover];
       
   220             break;
       
   221         default:
       
   222             NSLog(@"Nope");
       
   223             break;
       
   224     }
       
   225 }
       
   226 
       
   227 // present a further check before closing game
       
   228 -(void) actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger) buttonIndex {
       
   229 	if ([actionSheet cancelButtonIndex] != buttonIndex)
       
   230 	    HW_terminate(NO);
       
   231 	else
       
   232         HW_pause();		
       
   233 }
       
   234 
       
   235 // show up a popover containing a popupMenuViewController; we hook it with setPopoverContentSize
       
   236 // on iphone instead just use the tableViewController directly (and implement manually all animations)
       
   237 -(IBAction) showPopover{
       
   238     isPopoverVisible = YES;
       
   239     CGRect anchorForPopover;
       
   240     Class popoverControllerClass = NSClassFromString(@"UIPopoverController");
       
   241     if (popoverControllerClass) {
       
   242 #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
       
   243         if (popupMenu == nil) 
       
   244             popupMenu = [[PopoverMenuViewController alloc] initWithStyle:UITableViewStylePlain];
       
   245         popoverController = [[popoverControllerClass alloc] initWithContentViewController:popupMenu];
       
   246         [popoverController setPopoverContentSize:CGSizeMake(220, 170) animated:YES];
       
   247         [popoverController setPassthroughViews:[NSArray arrayWithObject:self.view]];
       
   248 
       
   249         if (UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation]))
       
   250             anchorForPopover = CGRectMake(960, 0, 220, 32);
       
   251         else
       
   252             anchorForPopover = CGRectMake(736, 0, 220, 32);
       
   253         
       
   254         [popoverController presentPopoverFromRect:anchorForPopover
       
   255                                            inView:self.view
       
   256                          permittedArrowDirections:UIPopoverArrowDirectionUp
       
   257                                          animated:YES];
       
   258 #endif
       
   259     } else {
       
   260         if (popupMenu == nil) 
       
   261             popupMenu = [[PopoverMenuViewController alloc] initWithStyle:UITableViewStyleGrouped];
       
   262         popupMenu.view.backgroundColor = [UIColor clearColor];
       
   263         popupMenu.view.frame = CGRectMake(480, 0, 200, 170);
       
   264         [self.view addSubview:popupMenu.view];
       
   265 
       
   266         [UIView beginAnimations:@"showing popover" context:NULL];
       
   267         [UIView setAnimationDuration:0.35];
       
   268         popupMenu.view.frame = CGRectMake(280, 0, 200, 170);
       
   269         [UIView commitAnimations];
       
   270     }
       
   271     popupMenu.tableView.scrollEnabled = NO;
       
   272 }
       
   273 
       
   274 // on ipad just dismiss it, on iphone transtion to the right
       
   275 -(void) dismissPopover {
       
   276     if (YES == isPopoverVisible) {
       
   277         isPopoverVisible = NO;
       
   278         
       
   279         if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
       
   280 #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
       
   281             [popoverController dismissPopoverAnimated:YES];
       
   282 #endif
       
   283         } else {
       
   284             [UIView beginAnimations:@"hiding popover" context:NULL];
       
   285             [UIView setAnimationDuration:0.35];
       
   286             popupMenu.view.frame = CGRectMake(480, 0, 200, 170);
       
   287             [UIView commitAnimations];
       
   288         
       
   289             [popupMenu.view performSelector:@selector(removeFromSuperview) withObject:nil afterDelay:0.35];
       
   290             [popupMenu performSelector:@selector(release) withObject:nil afterDelay:0.35];
       
   291         }
       
   292         [self buttonReleased:nil];
       
   293     }
       
   294 }
       
   295 
       
   296 -(void) textFieldDoneEditing:(id) sender{
       
   297     [sender resignFirstResponder];
       
   298 }
       
   299 
       
   300 #pragma mark -
       
   301 #pragma mark Custom touch event handling
       
   302 
       
   303 #define kMinimumPinchDelta      50
       
   304 
       
   305 
       
   306 -(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
       
   307 	NSArray *twoTouches;
       
   308 	UITouch *touch = [touches anyObject];
       
   309     
       
   310     if (isPopoverVisible) {
       
   311         [self dismissPopover];
       
   312     }
       
   313     if (writeChatTextField) {
       
   314         [self.writeChatTextField resignFirstResponder];
       
   315         [dimTimer setFireDate:HIDING_TIME_DEFAULT];
       
   316     }
       
   317     
       
   318     gestureStartPoint = [touch locationInView:self.view];
       
   319         
       
   320 	switch ([touches count]) {
       
   321 		case 1:
       
   322 			initialDistanceForPinching = 0;
       
   323 			switch ([touch tapCount]) {
       
   324 				case 1:
       
   325 					NSLog(@"X:%d Y:%d", (int)gestureStartPoint.x, (int)gestureStartPoint.y );
       
   326 					//SDL_WarpMouseInWindow([SDLUIKitDelegate sharedAppDelegate].window, 
       
   327 					//		      (int)gestureStartPoint.y, width - (int)gestureStartPoint.x);
       
   328 					//HW_click();
       
   329 					break;
       
   330 				case 2:
       
   331 					HW_ammoMenu();
       
   332 					break;
       
   333 				default:
       
   334 					break;
       
   335 			}
       
   336 			break;
       
   337 		case 2:
       
   338 			if (2 == [touch tapCount]) {
       
   339 				HW_zoomReset();
       
   340 			}
       
   341 			
       
   342 			// pinching
       
   343             gestureStartPoint.x = 0;
       
   344             gestureStartPoint.y = 0;
       
   345 			twoTouches = [touches allObjects];
       
   346 			UITouch *first = [twoTouches objectAtIndex:0];
       
   347 			UITouch *second = [twoTouches objectAtIndex:1];
       
   348 			initialDistanceForPinching = distanceBetweenPoints([first locationInView:self.view], [second locationInView:self.view]);
       
   349 			break;
       
   350 		default:
       
   351 			break;
       
   352 	}
       
   353 
       
   354 }
       
   355 
       
   356 -(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
       
   357 	initialDistanceForPinching = 0;
       
   358 	HW_allKeysUp();
       
   359 }
       
   360 
       
   361 -(void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
       
   362 	// this can happen if the user puts more than 5 touches on the screen at once, or perhaps in other circumstances
       
   363 	[self touchesEnded:touches withEvent:event];
       
   364 }
       
   365 
       
   366 -(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
       
   367     CGFloat minimumGestureLength;
       
   368     int logCoeff;
       
   369     
       
   370     if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
       
   371         minimumGestureLength = 5.0f;
       
   372         logCoeff = 19;
       
   373     } else {
       
   374         minimumGestureLength = 3.0f;
       
   375         logCoeff = 3;
       
   376     }
       
   377     
       
   378 	NSArray *twoTouches;
       
   379 	CGPoint currentPosition;
       
   380 	UITouch *touch = [touches anyObject];
       
   381 
       
   382 	switch ([touches count]) {
       
   383 		case 1:
       
   384 			currentPosition = [touch locationInView:self.view];
       
   385 			// panning
       
   386 			CGFloat deltaX = fabsf(gestureStartPoint.x - currentPosition.x);
       
   387 			CGFloat deltaY = fabsf(gestureStartPoint.y - currentPosition.y);
       
   388 			
       
   389             if (deltaX >= minimumGestureLength) {
       
   390                 NSLog(@"Horizontal swipe detected, deltaX: %f deltaY: %f",deltaX, deltaY);
       
   391                 if (currentPosition.x > gestureStartPoint.x) {
       
   392                     HW_cursorLeft(logCoeff*log(deltaX));
       
   393                 } else {
       
   394                     HW_cursorRight(logCoeff*log(deltaX));
       
   395                 }
       
   396 
       
   397             } 
       
   398             if (deltaY >= minimumGestureLength) {
       
   399                 NSLog(@"Horizontal swipe detected, deltaX: %f deltaY: %f",deltaX, deltaY);
       
   400                 if (currentPosition.y < gestureStartPoint.y) {
       
   401                     HW_cursorDown(logCoeff*log(deltaY));
       
   402                 } else {
       
   403                     HW_cursorUp(logCoeff*log(deltaY));
       
   404                 }            
       
   405             }
       
   406 
       
   407 			break;
       
   408 		case 2:
       
   409 			twoTouches = [touches allObjects];
       
   410 			UITouch *first = [twoTouches objectAtIndex:0];
       
   411 			UITouch *second = [twoTouches objectAtIndex:1];
       
   412 			CGFloat currentDistanceOfPinching = distanceBetweenPoints([first locationInView:self.view], [second locationInView:self.view]);
       
   413 			
       
   414 			if (0 == initialDistanceForPinching) 
       
   415 				initialDistanceForPinching = currentDistanceOfPinching;
       
   416 
       
   417 			if (currentDistanceOfPinching < initialDistanceForPinching + kMinimumPinchDelta)
       
   418 				HW_zoomOut();
       
   419 			else if (currentDistanceOfPinching > initialDistanceForPinching + kMinimumPinchDelta)
       
   420 				HW_zoomIn();
       
   421 
       
   422 			currentDistanceOfPinching = initialDistanceForPinching;
       
   423 			break;
       
   424 		default:
       
   425 			break;
       
   426 	}
       
   427 }
       
   428 
       
   429 
       
   430 @end