diff -r 2cccf6b2b89d -r a6030b32b222 project_files/HedgewarsMobile/MGSplitViewController.m --- a/project_files/HedgewarsMobile/MGSplitViewController.m Thu Feb 09 18:59:46 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1133 +0,0 @@ -// -// MGSplitViewController.m -// MGSplitView -// -// Created by Matt Gemmell on 26/07/2010. -// Copyright 2010 Instinctive Code. -// - -#import "MGSplitViewController.h" -#import "MGSplitDividerView.h" -#import "MGSplitCornersView.h" - -#define MG_DEFAULT_SPLIT_POSITION 320.0 // default width of master view in UISplitViewController. -#define MG_DEFAULT_SPLIT_WIDTH 1.0 // default width of split-gutter in UISplitViewController. -#define MG_DEFAULT_CORNER_RADIUS 5.0 // default corner-radius of overlapping split-inner corners on the master and detail views. -#define MG_DEFAULT_CORNER_COLOR [UIColor blackColor] // default color of intruding inner corners (and divider background). - -#define MG_PANESPLITTER_CORNER_RADIUS 0.0 // corner-radius of split-inner corners for MGSplitViewDividerStylePaneSplitter style. -#define MG_PANESPLITTER_SPLIT_WIDTH 25.0 // width of split-gutter for MGSplitViewDividerStylePaneSplitter style. - -#define MG_MIN_VIEW_WIDTH 200.0 // minimum width a view is allowed to become as a result of changing the splitPosition. - -#define MG_ANIMATION_CHANGE_SPLIT_ORIENTATION @"ChangeSplitOrientation" // Animation ID for internal use. -#define MG_ANIMATION_CHANGE_SUBVIEWS_ORDER @"ChangeSubviewsOrder" // Animation ID for internal use. - - -@interface MGSplitViewController (MGPrivateMethods) - -- (void)setup; -- (CGSize)splitViewSizeForOrientation:(UIInterfaceOrientation)theOrientation; -- (void)layoutSubviews; -- (void)layoutSubviewsWithAnimation:(BOOL)animate; -- (void)layoutSubviewsForInterfaceOrientation:(UIInterfaceOrientation)theOrientation withAnimation:(BOOL)animate; -- (BOOL)shouldShowMasterForInterfaceOrientation:(UIInterfaceOrientation)theOrientation; -- (BOOL)shouldShowMaster; -- (NSString *)nameOfInterfaceOrientation:(UIInterfaceOrientation)theOrientation; -- (void)reconfigureForMasterInPopover:(BOOL)inPopover; - -@end - - -@implementation MGSplitViewController - - -#pragma mark - -#pragma mark Orientation helpers - - -- (NSString *)nameOfInterfaceOrientation:(UIInterfaceOrientation)theOrientation -{ - NSString *orientationName = nil; - switch (theOrientation) { - case UIInterfaceOrientationPortrait: - orientationName = @"Portrait"; // Home button at bottom - break; - case UIInterfaceOrientationPortraitUpsideDown: - orientationName = @"Portrait (Upside Down)"; // Home button at top - break; - case UIInterfaceOrientationLandscapeLeft: - orientationName = @"Landscape (Left)"; // Home button on left - break; - case UIInterfaceOrientationLandscapeRight: - orientationName = @"Landscape (Right)"; // Home button on right - break; - default: - break; - } - - return orientationName; -} - - -- (BOOL)isLandscape -{ - return UIInterfaceOrientationIsLandscape(self.interfaceOrientation); -} - - -- (BOOL)shouldShowMasterForInterfaceOrientation:(UIInterfaceOrientation)theOrientation -{ - // Returns YES if master view should be shown directly embedded in the splitview, instead of hidden in a popover. - return ((UIInterfaceOrientationIsLandscape(theOrientation)) ? _showsMasterInLandscape : _showsMasterInPortrait); -} - - -- (BOOL)shouldShowMaster -{ - return [self shouldShowMasterForInterfaceOrientation:self.interfaceOrientation]; -} - - -- (BOOL)isShowingMaster -{ - return [self shouldShowMaster] && self.masterViewController && self.masterViewController.view && ([self.masterViewController.view superview] == self.view); -} - - -#pragma mark - -#pragma mark Setup and Teardown - - -- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil -{ - if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) { - [self setup]; - } - - return self; -} - - -- (id)initWithCoder:(NSCoder *)aDecoder -{ - if ((self = [super initWithCoder:aDecoder])) { - [self setup]; - } - - return self; -} - - -- (void)setup -{ - // Configure default behaviour. - _viewControllers = [[NSMutableArray alloc] initWithObjects:[NSNull null], [NSNull null], nil]; - _splitWidth = MG_DEFAULT_SPLIT_WIDTH; - _showsMasterInPortrait = NO; - _showsMasterInLandscape = YES; - _reconfigurePopup = NO; - _vertical = YES; - _masterBeforeDetail = YES; - _splitPosition = MG_DEFAULT_SPLIT_POSITION; - CGRect divRect = self.view.bounds; - if ([self isVertical]) { - divRect.origin.y = _splitPosition; - divRect.size.height = _splitWidth; - } else { - divRect.origin.x = _splitPosition; - divRect.size.width = _splitWidth; - } - _dividerView = [[MGSplitDividerView alloc] initWithFrame:divRect]; - _dividerView.splitViewController = self; - _dividerView.backgroundColor = MG_DEFAULT_CORNER_COLOR; - _dividerStyle = MGSplitViewDividerStyleThin; -} - - -- (void)dealloc -{ - _delegate = nil; - [self.view.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; - [_viewControllers release]; - [_barButtonItem release]; - [_hiddenPopoverController release]; - [_dividerView release]; - [_cornerViews release]; - - [super dealloc]; -} - - -#pragma mark - -#pragma mark View management - - -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - return YES; -} - - -- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration -{ - [self.masterViewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; - [self.detailViewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; -} - - -- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation -{ - [self.masterViewController didRotateFromInterfaceOrientation:fromInterfaceOrientation]; - [self.detailViewController didRotateFromInterfaceOrientation:fromInterfaceOrientation]; -} - - -- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation - duration:(NSTimeInterval)duration -{ - [self.masterViewController willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; - [self.detailViewController willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; - - // Hide popover. - if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { - [_hiddenPopoverController dismissPopoverAnimated:NO]; - } - - // Re-tile views. - _reconfigurePopup = YES; - [self layoutSubviewsForInterfaceOrientation:toInterfaceOrientation withAnimation:YES]; -} - - -- (void)willAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration -{ - [self.masterViewController willAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; - [self.detailViewController willAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; -} - - -- (void)didAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation -{ - [self.masterViewController didAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation]; - [self.detailViewController didAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation]; -} - - -- (void)willAnimateSecondHalfOfRotationFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation duration:(NSTimeInterval)duration -{ - [self.masterViewController willAnimateSecondHalfOfRotationFromInterfaceOrientation:fromInterfaceOrientation duration:duration]; - [self.detailViewController willAnimateSecondHalfOfRotationFromInterfaceOrientation:fromInterfaceOrientation duration:duration]; -} - - -- (CGSize)splitViewSizeForOrientation:(UIInterfaceOrientation)theOrientation -{ - UIScreen *screen = [UIScreen mainScreen]; - CGRect fullScreenRect = screen.bounds; // always implicitly in Portrait orientation. - CGRect appFrame = screen.applicationFrame; - - // Find status bar height by checking which dimension of the applicationFrame is narrower than screen bounds. - // Little bit ugly looking, but it'll still work even if they change the status bar height in future. - float statusBarHeight = MAX((fullScreenRect.size.width - appFrame.size.width), (fullScreenRect.size.height - appFrame.size.height)); - - // Initially assume portrait orientation. - float width = fullScreenRect.size.width; - float height = fullScreenRect.size.height; - - // Correct for orientation. - if (UIInterfaceOrientationIsLandscape(theOrientation)) { - width = height; - height = fullScreenRect.size.width; - } - - // Account for status bar, which always subtracts from the height (since it's always at the top of the screen). - height -= statusBarHeight; - - return CGSizeMake(width, height); -} - - -- (void)layoutSubviewsForInterfaceOrientation:(UIInterfaceOrientation)theOrientation withAnimation:(BOOL)animate -{ - if (_reconfigurePopup) { - [self reconfigureForMasterInPopover:![self shouldShowMasterForInterfaceOrientation:theOrientation]]; - } - - // Layout the master, detail and divider views appropriately, adding/removing subviews as needed. - // First obtain relevant geometry. - CGSize fullSize = [self splitViewSizeForOrientation:theOrientation]; - float width = fullSize.width; - float height = fullSize.height; - - if (NO) { // Just for debugging. - NSLog(@"Target orientation is %@, dimensions will be %.0f x %.0f", - [self nameOfInterfaceOrientation:theOrientation], width, height); - } - - // Layout the master, divider and detail views. - CGRect newFrame = CGRectMake(0, 0, width, height); - UIViewController *controller; - UIView *theView; - BOOL shouldShowMaster = [self shouldShowMasterForInterfaceOrientation:theOrientation]; - BOOL masterFirst = [self isMasterBeforeDetail]; - if ([self isVertical]) { - // Master on left, detail on right (or vice versa). - CGRect masterRect, dividerRect, detailRect; - if (masterFirst) { - if (!shouldShowMaster) { - // Move off-screen. - newFrame.origin.x -= (_splitPosition + _splitWidth); - } - - newFrame.size.width = _splitPosition; - masterRect = newFrame; - - newFrame.origin.x += newFrame.size.width; - newFrame.size.width = _splitWidth; - dividerRect = newFrame; - - newFrame.origin.x += newFrame.size.width; - newFrame.size.width = width - newFrame.origin.x; - detailRect = newFrame; - - } else { - if (!shouldShowMaster) { - // Move off-screen. - newFrame.size.width += (_splitPosition + _splitWidth); - } - - newFrame.size.width -= (_splitPosition + _splitWidth); - detailRect = newFrame; - - newFrame.origin.x += newFrame.size.width; - newFrame.size.width = _splitWidth; - dividerRect = newFrame; - - newFrame.origin.x += newFrame.size.width; - newFrame.size.width = _splitPosition; - masterRect = newFrame; - } - - // Position master. - controller = self.masterViewController; - if (controller && [controller isKindOfClass:[UIViewController class]]) { - theView = controller.view; - if (theView) { - theView.frame = masterRect; - if (!theView.superview) { - [controller viewWillAppear:NO]; - [self.view addSubview:theView]; - [controller viewDidAppear:NO]; - } - } - } - - // Position divider. - theView = _dividerView; - theView.frame = dividerRect; - if (!theView.superview) { - [self.view addSubview:theView]; - } - - // Position detail. - controller = self.detailViewController; - if (controller && [controller isKindOfClass:[UIViewController class]]) { - theView = controller.view; - if (theView) { - theView.frame = detailRect; - if (!theView.superview) { - [self.view insertSubview:theView aboveSubview:self.masterViewController.view]; - } else { - [self.view bringSubviewToFront:theView]; - } - } - } - - } else { - // Master above, detail below (or vice versa). - CGRect masterRect, dividerRect, detailRect; - if (masterFirst) { - if (!shouldShowMaster) { - // Move off-screen. - newFrame.origin.y -= (_splitPosition + _splitWidth); - } - - newFrame.size.height = _splitPosition; - masterRect = newFrame; - - newFrame.origin.y += newFrame.size.height; - newFrame.size.height = _splitWidth; - dividerRect = newFrame; - - newFrame.origin.y += newFrame.size.height; - newFrame.size.height = height - newFrame.origin.y; - detailRect = newFrame; - - } else { - if (!shouldShowMaster) { - // Move off-screen. - newFrame.size.height += (_splitPosition + _splitWidth); - } - - newFrame.size.height -= (_splitPosition + _splitWidth); - detailRect = newFrame; - - newFrame.origin.y += newFrame.size.height; - newFrame.size.height = _splitWidth; - dividerRect = newFrame; - - newFrame.origin.y += newFrame.size.height; - newFrame.size.height = _splitPosition; - masterRect = newFrame; - } - - // Position master. - controller = self.masterViewController; - if (controller && [controller isKindOfClass:[UIViewController class]]) { - theView = controller.view; - if (theView) { - theView.frame = masterRect; - if (!theView.superview) { - [controller viewWillAppear:NO]; - [self.view addSubview:theView]; - [controller viewDidAppear:NO]; - } - } - } - - // Position divider. - theView = _dividerView; - theView.frame = dividerRect; - if (!theView.superview) { - [self.view addSubview:theView]; - } - - // Position detail. - controller = self.detailViewController; - if (controller && [controller isKindOfClass:[UIViewController class]]) { - theView = controller.view; - if (theView) { - theView.frame = detailRect; - if (!theView.superview) { - [self.view insertSubview:theView aboveSubview:self.masterViewController.view]; - } else { - [self.view bringSubviewToFront:theView]; - } - } - } - } - - // Create corner views if necessary. - MGSplitCornersView *leadingCorners; // top/left of screen in vertical/horizontal split. - MGSplitCornersView *trailingCorners; // bottom/right of screen in vertical/horizontal split. - if (!_cornerViews) { - CGRect cornerRect = CGRectMake(0, 0, 10, 10); // arbitrary, will be resized below. - leadingCorners = [[MGSplitCornersView alloc] initWithFrame:cornerRect]; - leadingCorners.splitViewController = self; - leadingCorners.cornerBackgroundColor = MG_DEFAULT_CORNER_COLOR; - leadingCorners.cornerRadius = MG_DEFAULT_CORNER_RADIUS; - trailingCorners = [[MGSplitCornersView alloc] initWithFrame:cornerRect]; - trailingCorners.splitViewController = self; - trailingCorners.cornerBackgroundColor = MG_DEFAULT_CORNER_COLOR; - trailingCorners.cornerRadius = MG_DEFAULT_CORNER_RADIUS; - _cornerViews = [[NSArray alloc] initWithObjects:leadingCorners, trailingCorners, nil]; - [leadingCorners release]; - [trailingCorners release]; - - } else if ([_cornerViews count] == 2) { - leadingCorners = [_cornerViews objectAtIndex:0]; - trailingCorners = [_cornerViews objectAtIndex:1]; - } - - // Configure and layout the corner-views. - leadingCorners.cornersPosition = (_vertical) ? MGCornersPositionLeadingVertical : MGCornersPositionLeadingHorizontal; - trailingCorners.cornersPosition = (_vertical) ? MGCornersPositionTrailingVertical : MGCornersPositionTrailingHorizontal; - leadingCorners.autoresizingMask = (_vertical) ? UIViewAutoresizingFlexibleBottomMargin : UIViewAutoresizingFlexibleRightMargin; - trailingCorners.autoresizingMask = (_vertical) ? UIViewAutoresizingFlexibleTopMargin : UIViewAutoresizingFlexibleLeftMargin; - - float x, y, cornersWidth, cornersHeight; - CGRect leadingRect, trailingRect; - float radius = leadingCorners.cornerRadius; - if (_vertical) { // left/right split - cornersWidth = (radius * 2.0) + _splitWidth; - cornersHeight = radius; - x = ((shouldShowMaster) ? ((masterFirst) ? _splitPosition : width - (_splitPosition + _splitWidth)) : (0 - _splitWidth)) - radius; - y = 0; - leadingRect = CGRectMake(x, y, cornersWidth, cornersHeight); // top corners - trailingRect = CGRectMake(x, (height - cornersHeight), cornersWidth, cornersHeight); // bottom corners - - } else { // top/bottom split - x = 0; - y = ((shouldShowMaster) ? ((masterFirst) ? _splitPosition : height - (_splitPosition + _splitWidth)) : (0 - _splitWidth)) - radius; - cornersWidth = radius; - cornersHeight = (radius * 2.0) + _splitWidth; - leadingRect = CGRectMake(x, y, cornersWidth, cornersHeight); // left corners - trailingRect = CGRectMake((width - cornersWidth), y, cornersWidth, cornersHeight); // right corners - } - - leadingCorners.frame = leadingRect; - trailingCorners.frame = trailingRect; - - // Ensure corners are visible and frontmost. - if (!leadingCorners.superview) { - [self.view insertSubview:leadingCorners aboveSubview:self.detailViewController.view]; - [self.view insertSubview:trailingCorners aboveSubview:self.detailViewController.view]; - } else { - [self.view bringSubviewToFront:leadingCorners]; - [self.view bringSubviewToFront:trailingCorners]; - } -} - - -- (void)layoutSubviewsWithAnimation:(BOOL)animate -{ - [self layoutSubviewsForInterfaceOrientation:self.interfaceOrientation withAnimation:animate]; -} - - -- (void)layoutSubviews -{ - [self layoutSubviewsForInterfaceOrientation:self.interfaceOrientation withAnimation:YES]; -} - - -- (void)viewWillAppear:(BOOL)animated -{ - [super viewWillAppear:animated]; - - if ([self isShowingMaster]) { - [self.masterViewController viewWillAppear:animated]; - } - [self.detailViewController viewWillAppear:animated]; - - _reconfigurePopup = YES; - [self layoutSubviews]; -} - - -- (void)viewDidAppear:(BOOL)animated -{ - [super viewDidAppear:animated]; - - if ([self isShowingMaster]) { - [self.masterViewController viewDidAppear:animated]; - } - [self.detailViewController viewDidAppear:animated]; -} - - -- (void)viewWillDisappear:(BOOL)animated -{ - [super viewWillDisappear:animated]; - - if ([self isShowingMaster]) { - [self.masterViewController viewWillDisappear:animated]; - } - [self.detailViewController viewWillDisappear:animated]; -} - - -- (void)viewDidDisappear:(BOOL)animated -{ - [super viewDidDisappear:animated]; - - if ([self isShowingMaster]) { - [self.masterViewController viewDidDisappear:animated]; - } - [self.detailViewController viewDidDisappear:animated]; -} - - -#pragma mark - -#pragma mark Popover handling - - -- (void)reconfigureForMasterInPopover:(BOOL)inPopover -{ - _reconfigurePopup = NO; - - if ((inPopover && _hiddenPopoverController) || (!inPopover && !_hiddenPopoverController) || !self.masterViewController) { - // Nothing to do. - return; - } - - if (inPopover && !_hiddenPopoverController && !_barButtonItem) { - // Create and configure popover for our masterViewController. - [_hiddenPopoverController release]; - _hiddenPopoverController = nil; - [self.masterViewController viewWillDisappear:NO]; - _hiddenPopoverController = [[UIPopoverController alloc] initWithContentViewController:self.masterViewController]; - [self.masterViewController viewDidDisappear:NO]; - - // Create and configure _barButtonItem. - _barButtonItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Master", nil) - style:UIBarButtonItemStyleBordered - target:self - action:@selector(showMasterPopover:)]; - - // Inform delegate of this state of affairs. - if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:willHideViewController:withBarButtonItem:forPopoverController:)]) { - [(NSObject *)_delegate splitViewController:self - willHideViewController:self.masterViewController - withBarButtonItem:_barButtonItem - forPopoverController:_hiddenPopoverController]; - } - - } else if (!inPopover && _hiddenPopoverController && _barButtonItem) { - // I know this looks strange, but it fixes a bizarre issue with UIPopoverController leaving masterViewController's views in disarray. - [_hiddenPopoverController presentPopoverFromRect:CGRectZero inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:NO]; - - // Remove master from popover and destroy popover, if it exists. - [_hiddenPopoverController dismissPopoverAnimated:NO]; - [_hiddenPopoverController release]; - _hiddenPopoverController = nil; - - // Inform delegate that the _barButtonItem will become invalid. - if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:willShowViewController:invalidatingBarButtonItem:)]) { - [(NSObject *)_delegate splitViewController:self - willShowViewController:self.masterViewController - invalidatingBarButtonItem:_barButtonItem]; - } - - // Destroy _barButtonItem. - [_barButtonItem release]; - _barButtonItem = nil; - - // Move master view. - UIView *masterView = self.masterViewController.view; - if (masterView && masterView.superview != self.view) { - [masterView removeFromSuperview]; - } - } -} - - -- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController -{ - [self reconfigureForMasterInPopover:NO]; -} - - -- (void)notePopoverDismissed -{ - [self popoverControllerDidDismissPopover:_hiddenPopoverController]; -} - - -#pragma mark - -#pragma mark Animations - - -- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context -{ - if (([animationID isEqualToString:MG_ANIMATION_CHANGE_SPLIT_ORIENTATION] || - [animationID isEqualToString:MG_ANIMATION_CHANGE_SUBVIEWS_ORDER]) - && _cornerViews) { - for (UIView *corner in _cornerViews) { - corner.hidden = NO; - } - _dividerView.hidden = NO; - } -} - - -#pragma mark - -#pragma mark IB Actions - - -- (IBAction)toggleSplitOrientation:(id)sender -{ - BOOL showingMaster = [self isShowingMaster]; - if (showingMaster) { - if (_cornerViews) { - for (UIView *corner in _cornerViews) { - corner.hidden = YES; - } - _dividerView.hidden = YES; - } - [UIView beginAnimations:MG_ANIMATION_CHANGE_SPLIT_ORIENTATION context:nil]; - [UIView setAnimationDelegate:self]; - [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)]; - } - self.vertical = (!self.vertical); - if (showingMaster) { - [UIView commitAnimations]; - } -} - - -- (IBAction)toggleMasterBeforeDetail:(id)sender -{ - BOOL showingMaster = [self isShowingMaster]; - if (showingMaster) { - if (_cornerViews) { - for (UIView *corner in _cornerViews) { - corner.hidden = YES; - } - _dividerView.hidden = YES; - } - [UIView beginAnimations:MG_ANIMATION_CHANGE_SUBVIEWS_ORDER context:nil]; - [UIView setAnimationDelegate:self]; - [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)]; - } - self.masterBeforeDetail = (!self.masterBeforeDetail); - if (showingMaster) { - [UIView commitAnimations]; - } -} - - -- (IBAction)toggleMasterView:(id)sender -{ - if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { - [_hiddenPopoverController dismissPopoverAnimated:NO]; - } - - if (![self isShowingMaster]) { - // We're about to show the master view. Ensure it's in place off-screen to be animated in. - _reconfigurePopup = YES; - [self reconfigureForMasterInPopover:NO]; - [self layoutSubviews]; - } - - // This action functions on the current primary orientation; it is independent of the other primary orientation. - [UIView beginAnimations:@"toggleMaster" context:nil]; - if (self.isLandscape) { - self.showsMasterInLandscape = !_showsMasterInLandscape; - } else { - self.showsMasterInPortrait = !_showsMasterInPortrait; - } - [UIView commitAnimations]; -} - - -- (IBAction)showMasterPopover:(id)sender -{ - if (_hiddenPopoverController && !(_hiddenPopoverController.popoverVisible)) { - // Inform delegate. - if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:popoverController:willPresentViewController:)]) { - [(NSObject *)_delegate splitViewController:self - popoverController:_hiddenPopoverController - willPresentViewController:self.masterViewController]; - } - - // Show popover. - [_hiddenPopoverController presentPopoverFromBarButtonItem:_barButtonItem permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; - } -} - - -#pragma mark - -#pragma mark Accessors and properties - - -- (id)delegate -{ - return _delegate; -} - - -- (void)setDelegate:(id )newDelegate -{ - if (newDelegate != _delegate && - (!newDelegate || [(NSObject *)newDelegate conformsToProtocol:@protocol(MGSplitViewControllerDelegate)])) { - _delegate = newDelegate; - } -} - - -- (BOOL)showsMasterInPortrait -{ - return _showsMasterInPortrait; -} - - -- (void)setShowsMasterInPortrait:(BOOL)flag -{ - if (flag != _showsMasterInPortrait) { - _showsMasterInPortrait = flag; - - if (![self isLandscape]) { // i.e. if this will cause a visual change. - if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { - [_hiddenPopoverController dismissPopoverAnimated:NO]; - } - - // Rearrange views. - _reconfigurePopup = YES; - [self layoutSubviews]; - } - } -} - - -- (BOOL)showsMasterInLandscape -{ - return _showsMasterInLandscape; -} - - -- (void)setShowsMasterInLandscape:(BOOL)flag -{ - if (flag != _showsMasterInLandscape) { - _showsMasterInLandscape = flag; - - if ([self isLandscape]) { // i.e. if this will cause a visual change. - if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { - [_hiddenPopoverController dismissPopoverAnimated:NO]; - } - - // Rearrange views. - _reconfigurePopup = YES; - [self layoutSubviews]; - } - } -} - - -- (BOOL)isVertical -{ - return _vertical; -} - - -- (void)setVertical:(BOOL)flag -{ - if (flag != _vertical) { - if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { - [_hiddenPopoverController dismissPopoverAnimated:NO]; - } - - _vertical = flag; - - // Inform delegate. - if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:willChangeSplitOrientationToVertical:)]) { - [_delegate splitViewController:self willChangeSplitOrientationToVertical:_vertical]; - } - - [self layoutSubviews]; - } -} - - -- (BOOL)isMasterBeforeDetail -{ - return _masterBeforeDetail; -} - - -- (void)setMasterBeforeDetail:(BOOL)flag -{ - if (flag != _masterBeforeDetail) { - if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { - [_hiddenPopoverController dismissPopoverAnimated:NO]; - } - - _masterBeforeDetail = flag; - - if ([self isShowingMaster]) { - [self layoutSubviews]; - } - } -} - - -- (float)splitPosition -{ - return _splitPosition; -} - - -- (void)setSplitPosition:(float)posn -{ - // Check to see if delegate wishes to constrain the position. - float newPosn = posn; - BOOL constrained = NO; - CGSize fullSize = [self splitViewSizeForOrientation:self.interfaceOrientation]; - if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:constrainSplitPosition:splitViewSize:)]) { - newPosn = [_delegate splitViewController:self constrainSplitPosition:newPosn splitViewSize:fullSize]; - constrained = YES; // implicitly trust delegate's response. - - } else { - // Apply default constraints if delegate doesn't wish to participate. - float minPos = MG_MIN_VIEW_WIDTH; - float maxPos = ((_vertical) ? fullSize.width : fullSize.height) - (MG_MIN_VIEW_WIDTH + _splitWidth); - constrained = (newPosn != _splitPosition && newPosn >= minPos && newPosn <= maxPos); - } - - if (constrained) { - if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { - [_hiddenPopoverController dismissPopoverAnimated:NO]; - } - - _splitPosition = newPosn; - - // Inform delegate. - if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:willMoveSplitToPosition:)]) { - [_delegate splitViewController:self willMoveSplitToPosition:_splitPosition]; - } - - if ([self isShowingMaster]) { - [self layoutSubviews]; - } - } -} - - -- (void)setSplitPosition:(float)posn animated:(BOOL)animate -{ - BOOL shouldAnimate = (animate && [self isShowingMaster]); - if (shouldAnimate) { - [UIView beginAnimations:@"SplitPosition" context:nil]; - } - [self setSplitPosition:posn]; - if (shouldAnimate) { - [UIView commitAnimations]; - } -} - - -- (float)splitWidth -{ - return _splitWidth; -} - - -- (void)setSplitWidth:(float)width -{ - if (width != _splitWidth && width >= 0) { - _splitWidth = width; - if ([self isShowingMaster]) { - [self layoutSubviews]; - } - } -} - - -- (NSArray *)viewControllers -{ - return [[_viewControllers copy] autorelease]; -} - - -- (void)setViewControllers:(NSArray *)controllers -{ - if (controllers != _viewControllers) { - for (UIViewController *controller in _viewControllers) { - if ([controller isKindOfClass:[UIViewController class]]) { - [controller.view removeFromSuperview]; - } - } - [_viewControllers release]; - _viewControllers = [[NSMutableArray alloc] initWithCapacity:2]; - if (controllers && [controllers count] >= 2) { - self.masterViewController = [controllers objectAtIndex:0]; - self.detailViewController = [controllers objectAtIndex:1]; - } else { - NSLog(@"Error: %@ requires 2 view-controllers. (%@)", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); - } - - [self layoutSubviews]; - } -} - - -- (UIViewController *)masterViewController -{ - if (_viewControllers && [_viewControllers count] > 0) { - NSObject *controller = [_viewControllers objectAtIndex:0]; - if ([controller isKindOfClass:[UIViewController class]]) { - return [[controller retain] autorelease]; - } - } - - return nil; -} - - -- (void)setMasterViewController:(UIViewController *)master -{ - if (!_viewControllers) { - _viewControllers = [[NSMutableArray alloc] initWithCapacity:2]; - } - - NSObject *newMaster = master; - if (!newMaster) { - newMaster = [NSNull null]; - } - - BOOL changed = YES; - if ([_viewControllers count] > 0) { - if ([_viewControllers objectAtIndex:0] == newMaster) { - changed = NO; - } else { - [_viewControllers replaceObjectAtIndex:0 withObject:newMaster]; - } - - } else { - [_viewControllers addObject:newMaster]; - } - - if (changed) { - [self layoutSubviews]; - } -} - - -- (UIViewController *)detailViewController -{ - if (_viewControllers && [_viewControllers count] > 1) { - NSObject *controller = [_viewControllers objectAtIndex:1]; - if ([controller isKindOfClass:[UIViewController class]]) { - return [[controller retain] autorelease]; - } - } - - return nil; -} - - -- (void)setDetailViewController:(UIViewController *)detail -{ - if (!_viewControllers) { - _viewControllers = [[NSMutableArray alloc] initWithCapacity:2]; - [_viewControllers addObject:[NSNull null]]; - } - - BOOL changed = YES; - if ([_viewControllers count] > 1) { - if ([_viewControllers objectAtIndex:1] == detail) { - changed = NO; - } else { - [_viewControllers replaceObjectAtIndex:1 withObject:detail]; - } - - } else { - [_viewControllers addObject:detail]; - } - - if (changed) { - [self layoutSubviews]; - } -} - - -- (MGSplitDividerView *)dividerView -{ - return [[_dividerView retain] autorelease]; -} - - -- (void)setDividerView:(MGSplitDividerView *)divider -{ - if (divider != _dividerView) { - [_dividerView removeFromSuperview]; - [_dividerView release]; - _dividerView = [divider retain]; - _dividerView.splitViewController = self; - _dividerView.backgroundColor = MG_DEFAULT_CORNER_COLOR; - if ([self isShowingMaster]) { - [self layoutSubviews]; - } - } -} - - -- (BOOL)allowsDraggingDivider -{ - if (_dividerView) { - return _dividerView.allowsDragging; - } - - return NO; -} - - -- (void)setAllowsDraggingDivider:(BOOL)flag -{ - if (self.allowsDraggingDivider != flag && _dividerView) { - _dividerView.allowsDragging = flag; - } -} - - -- (MGSplitViewDividerStyle)dividerStyle -{ - return _dividerStyle; -} - - -- (void)setDividerStyle:(MGSplitViewDividerStyle)newStyle -{ - if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { - [_hiddenPopoverController dismissPopoverAnimated:NO]; - } - - // We don't check to see if newStyle equals _dividerStyle, because it's a meta-setting. - // Aspects could have been changed since it was set. - _dividerStyle = newStyle; - - // Reconfigure general appearance and behaviour. - float cornerRadius; - if (_dividerStyle == MGSplitViewDividerStyleThin) { - cornerRadius = MG_DEFAULT_CORNER_RADIUS; - _splitWidth = MG_DEFAULT_SPLIT_WIDTH; - self.allowsDraggingDivider = NO; - - } else if (_dividerStyle == MGSplitViewDividerStylePaneSplitter) { - cornerRadius = MG_PANESPLITTER_CORNER_RADIUS; - _splitWidth = MG_PANESPLITTER_SPLIT_WIDTH; - self.allowsDraggingDivider = YES; - } - - // Update divider and corners. - [_dividerView setNeedsDisplay]; - if (_cornerViews) { - for (MGSplitCornersView *corner in _cornerViews) { - corner.cornerRadius = cornerRadius; - } - } - - // Layout all views. - [self layoutSubviews]; -} - - -- (void)setDividerStyle:(MGSplitViewDividerStyle)newStyle animated:(BOOL)animate -{ - BOOL shouldAnimate = (animate && [self isShowingMaster]); - if (shouldAnimate) { - [UIView beginAnimations:@"DividerStyle" context:nil]; - } - [self setDividerStyle:newStyle]; - if (shouldAnimate) { - [UIView commitAnimations]; - } -} - - -- (NSArray *)cornerViews -{ - if (_cornerViews) { - return [[_cornerViews retain] autorelease]; - } - - return nil; -} - - -@synthesize showsMasterInPortrait; -@synthesize showsMasterInLandscape; -@synthesize vertical; -@synthesize delegate; -@synthesize viewControllers; -@synthesize masterViewController; -@synthesize detailViewController; -@synthesize dividerView; -@synthesize splitPosition; -@synthesize splitWidth; -@synthesize allowsDraggingDivider; -@synthesize dividerStyle; - - -@end