169 } |
169 } |
170 |
170 |
171 |
171 |
172 - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration |
172 - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration |
173 { |
173 { |
174 [self.masterViewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
174 [self.masterViewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
175 [self.detailViewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
175 [self.detailViewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
176 } |
176 } |
177 |
177 |
178 |
178 |
179 - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation |
179 - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation |
180 { |
180 { |
181 [self.masterViewController didRotateFromInterfaceOrientation:fromInterfaceOrientation]; |
181 [self.masterViewController didRotateFromInterfaceOrientation:fromInterfaceOrientation]; |
182 [self.detailViewController didRotateFromInterfaceOrientation:fromInterfaceOrientation]; |
182 [self.detailViewController didRotateFromInterfaceOrientation:fromInterfaceOrientation]; |
183 } |
183 } |
184 |
184 |
185 |
185 |
186 - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation |
186 - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation |
187 duration:(NSTimeInterval)duration |
187 duration:(NSTimeInterval)duration |
188 { |
188 { |
189 [self.masterViewController willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
189 [self.masterViewController willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
190 [self.detailViewController willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
190 [self.detailViewController willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
191 |
191 |
192 // Hide popover. |
192 // Hide popover. |
193 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
193 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
194 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
194 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
195 } |
195 } |
196 |
196 |
197 // Re-tile views. |
197 // Re-tile views. |
198 _reconfigurePopup = YES; |
198 _reconfigurePopup = YES; |
199 [self layoutSubviewsForInterfaceOrientation:toInterfaceOrientation withAnimation:YES]; |
199 [self layoutSubviewsForInterfaceOrientation:toInterfaceOrientation withAnimation:YES]; |
200 } |
200 } |
201 |
201 |
202 |
202 |
203 - (void)willAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration |
203 - (void)willAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration |
204 { |
204 { |
205 [self.masterViewController willAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
205 [self.masterViewController willAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
206 [self.detailViewController willAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
206 [self.detailViewController willAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; |
207 } |
207 } |
208 |
208 |
209 |
209 |
210 - (void)didAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation |
210 - (void)didAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation |
211 { |
211 { |
212 [self.masterViewController didAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation]; |
212 [self.masterViewController didAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation]; |
213 [self.detailViewController didAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation]; |
213 [self.detailViewController didAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation]; |
214 } |
214 } |
215 |
215 |
216 |
216 |
217 - (void)willAnimateSecondHalfOfRotationFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation duration:(NSTimeInterval)duration |
217 - (void)willAnimateSecondHalfOfRotationFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation duration:(NSTimeInterval)duration |
218 { |
218 { |
219 [self.masterViewController willAnimateSecondHalfOfRotationFromInterfaceOrientation:fromInterfaceOrientation duration:duration]; |
219 [self.masterViewController willAnimateSecondHalfOfRotationFromInterfaceOrientation:fromInterfaceOrientation duration:duration]; |
220 [self.detailViewController willAnimateSecondHalfOfRotationFromInterfaceOrientation:fromInterfaceOrientation duration:duration]; |
220 [self.detailViewController willAnimateSecondHalfOfRotationFromInterfaceOrientation:fromInterfaceOrientation duration:duration]; |
221 } |
221 } |
222 |
222 |
223 |
223 |
224 - (CGSize)splitViewSizeForOrientation:(UIInterfaceOrientation)theOrientation |
224 - (CGSize)splitViewSizeForOrientation:(UIInterfaceOrientation)theOrientation |
225 { |
225 { |
226 UIScreen *screen = [UIScreen mainScreen]; |
226 UIScreen *screen = [UIScreen mainScreen]; |
227 CGRect fullScreenRect = screen.bounds; // always implicitly in Portrait orientation. |
227 CGRect fullScreenRect = screen.bounds; // always implicitly in Portrait orientation. |
228 CGRect appFrame = screen.applicationFrame; |
228 CGRect appFrame = screen.applicationFrame; |
229 |
229 |
230 // Find status bar height by checking which dimension of the applicationFrame is narrower than screen bounds. |
230 // Find status bar height by checking which dimension of the applicationFrame is narrower than screen bounds. |
231 // Little bit ugly looking, but it'll still work even if they change the status bar height in future. |
231 // Little bit ugly looking, but it'll still work even if they change the status bar height in future. |
232 float statusBarHeight = MAX((fullScreenRect.size.width - appFrame.size.width), (fullScreenRect.size.height - appFrame.size.height)); |
232 float statusBarHeight = MAX((fullScreenRect.size.width - appFrame.size.width), (fullScreenRect.size.height - appFrame.size.height)); |
233 |
233 |
234 // Initially assume portrait orientation. |
234 // Initially assume portrait orientation. |
235 float width = fullScreenRect.size.width; |
235 float width = fullScreenRect.size.width; |
236 float height = fullScreenRect.size.height; |
236 float height = fullScreenRect.size.height; |
237 |
237 |
238 // Correct for orientation. |
238 // Correct for orientation. |
239 if (UIInterfaceOrientationIsLandscape(theOrientation)) { |
239 if (UIInterfaceOrientationIsLandscape(theOrientation)) { |
240 width = height; |
240 width = height; |
241 height = fullScreenRect.size.width; |
241 height = fullScreenRect.size.width; |
242 } |
242 } |
243 |
243 |
244 // Account for status bar, which always subtracts from the height (since it's always at the top of the screen). |
244 // Account for status bar, which always subtracts from the height (since it's always at the top of the screen). |
245 height -= statusBarHeight; |
245 height -= statusBarHeight; |
246 |
246 |
247 return CGSizeMake(width, height); |
247 return CGSizeMake(width, height); |
248 } |
248 } |
249 |
249 |
250 |
250 |
251 - (void)layoutSubviewsForInterfaceOrientation:(UIInterfaceOrientation)theOrientation withAnimation:(BOOL)animate |
251 - (void)layoutSubviewsForInterfaceOrientation:(UIInterfaceOrientation)theOrientation withAnimation:(BOOL)animate |
252 { |
252 { |
253 if (_reconfigurePopup) { |
253 if (_reconfigurePopup) { |
254 [self reconfigureForMasterInPopover:![self shouldShowMasterForInterfaceOrientation:theOrientation]]; |
254 [self reconfigureForMasterInPopover:![self shouldShowMasterForInterfaceOrientation:theOrientation]]; |
255 } |
255 } |
256 |
256 |
257 // Layout the master, detail and divider views appropriately, adding/removing subviews as needed. |
257 // Layout the master, detail and divider views appropriately, adding/removing subviews as needed. |
258 // First obtain relevant geometry. |
258 // First obtain relevant geometry. |
259 CGSize fullSize = [self splitViewSizeForOrientation:theOrientation]; |
259 CGSize fullSize = [self splitViewSizeForOrientation:theOrientation]; |
260 float width = fullSize.width; |
260 float width = fullSize.width; |
261 float height = fullSize.height; |
261 float height = fullSize.height; |
262 |
262 |
263 if (NO) { // Just for debugging. |
263 if (NO) { // Just for debugging. |
264 NSLog(@"Target orientation is %@, dimensions will be %.0f x %.0f", |
264 NSLog(@"Target orientation is %@, dimensions will be %.0f x %.0f", |
265 [self nameOfInterfaceOrientation:theOrientation], width, height); |
265 [self nameOfInterfaceOrientation:theOrientation], width, height); |
266 } |
266 } |
267 |
267 |
268 // Layout the master, divider and detail views. |
268 // Layout the master, divider and detail views. |
269 CGRect newFrame = CGRectMake(0, 0, width, height); |
269 CGRect newFrame = CGRectMake(0, 0, width, height); |
270 UIViewController *controller; |
270 UIViewController *controller; |
271 UIView *theView; |
271 UIView *theView; |
272 BOOL shouldShowMaster = [self shouldShowMasterForInterfaceOrientation:theOrientation]; |
272 BOOL shouldShowMaster = [self shouldShowMasterForInterfaceOrientation:theOrientation]; |
273 BOOL masterFirst = [self isMasterBeforeDetail]; |
273 BOOL masterFirst = [self isMasterBeforeDetail]; |
274 if ([self isVertical]) { |
274 if ([self isVertical]) { |
275 // Master on left, detail on right (or vice versa). |
275 // Master on left, detail on right (or vice versa). |
276 CGRect masterRect, dividerRect, detailRect; |
276 CGRect masterRect, dividerRect, detailRect; |
277 if (masterFirst) { |
277 if (masterFirst) { |
278 if (!shouldShowMaster) { |
278 if (!shouldShowMaster) { |
279 // Move off-screen. |
279 // Move off-screen. |
280 newFrame.origin.x -= (_splitPosition + _splitWidth); |
280 newFrame.origin.x -= (_splitPosition + _splitWidth); |
281 } |
281 } |
282 |
282 |
283 newFrame.size.width = _splitPosition; |
283 newFrame.size.width = _splitPosition; |
284 masterRect = newFrame; |
284 masterRect = newFrame; |
285 |
285 |
286 newFrame.origin.x += newFrame.size.width; |
286 newFrame.origin.x += newFrame.size.width; |
287 newFrame.size.width = _splitWidth; |
287 newFrame.size.width = _splitWidth; |
288 dividerRect = newFrame; |
288 dividerRect = newFrame; |
289 |
289 |
290 newFrame.origin.x += newFrame.size.width; |
290 newFrame.origin.x += newFrame.size.width; |
291 newFrame.size.width = width - newFrame.origin.x; |
291 newFrame.size.width = width - newFrame.origin.x; |
292 detailRect = newFrame; |
292 detailRect = newFrame; |
293 |
293 |
294 } else { |
294 } else { |
295 if (!shouldShowMaster) { |
295 if (!shouldShowMaster) { |
296 // Move off-screen. |
296 // Move off-screen. |
297 newFrame.size.width += (_splitPosition + _splitWidth); |
297 newFrame.size.width += (_splitPosition + _splitWidth); |
298 } |
298 } |
299 |
299 |
300 newFrame.size.width -= (_splitPosition + _splitWidth); |
300 newFrame.size.width -= (_splitPosition + _splitWidth); |
301 detailRect = newFrame; |
301 detailRect = newFrame; |
302 |
302 |
303 newFrame.origin.x += newFrame.size.width; |
303 newFrame.origin.x += newFrame.size.width; |
304 newFrame.size.width = _splitWidth; |
304 newFrame.size.width = _splitWidth; |
305 dividerRect = newFrame; |
305 dividerRect = newFrame; |
306 |
306 |
307 newFrame.origin.x += newFrame.size.width; |
307 newFrame.origin.x += newFrame.size.width; |
308 newFrame.size.width = _splitPosition; |
308 newFrame.size.width = _splitPosition; |
309 masterRect = newFrame; |
309 masterRect = newFrame; |
310 } |
310 } |
311 |
311 |
312 // Position master. |
312 // Position master. |
313 controller = self.masterViewController; |
313 controller = self.masterViewController; |
314 if (controller && [controller isKindOfClass:[UIViewController class]]) { |
314 if (controller && [controller isKindOfClass:[UIViewController class]]) { |
315 theView = controller.view; |
315 theView = controller.view; |
316 if (theView) { |
316 if (theView) { |
317 theView.frame = masterRect; |
317 theView.frame = masterRect; |
318 if (!theView.superview) { |
318 if (!theView.superview) { |
319 [controller viewWillAppear:NO]; |
319 [controller viewWillAppear:NO]; |
320 [self.view addSubview:theView]; |
320 [self.view addSubview:theView]; |
321 [controller viewDidAppear:NO]; |
321 [controller viewDidAppear:NO]; |
322 } |
322 } |
323 } |
323 } |
324 } |
324 } |
325 |
325 |
326 // Position divider. |
326 // Position divider. |
327 theView = _dividerView; |
327 theView = _dividerView; |
328 theView.frame = dividerRect; |
328 theView.frame = dividerRect; |
329 if (!theView.superview) { |
329 if (!theView.superview) { |
330 [self.view addSubview:theView]; |
330 [self.view addSubview:theView]; |
331 } |
331 } |
332 |
332 |
333 // Position detail. |
333 // Position detail. |
334 controller = self.detailViewController; |
334 controller = self.detailViewController; |
335 if (controller && [controller isKindOfClass:[UIViewController class]]) { |
335 if (controller && [controller isKindOfClass:[UIViewController class]]) { |
336 theView = controller.view; |
336 theView = controller.view; |
337 if (theView) { |
337 if (theView) { |
338 theView.frame = detailRect; |
338 theView.frame = detailRect; |
339 if (!theView.superview) { |
339 if (!theView.superview) { |
340 [self.view insertSubview:theView aboveSubview:self.masterViewController.view]; |
340 [self.view insertSubview:theView aboveSubview:self.masterViewController.view]; |
341 } else { |
341 } else { |
342 [self.view bringSubviewToFront:theView]; |
342 [self.view bringSubviewToFront:theView]; |
343 } |
343 } |
344 } |
344 } |
345 } |
345 } |
346 |
346 |
347 } else { |
347 } else { |
348 // Master above, detail below (or vice versa). |
348 // Master above, detail below (or vice versa). |
349 CGRect masterRect, dividerRect, detailRect; |
349 CGRect masterRect, dividerRect, detailRect; |
350 if (masterFirst) { |
350 if (masterFirst) { |
351 if (!shouldShowMaster) { |
351 if (!shouldShowMaster) { |
352 // Move off-screen. |
352 // Move off-screen. |
353 newFrame.origin.y -= (_splitPosition + _splitWidth); |
353 newFrame.origin.y -= (_splitPosition + _splitWidth); |
354 } |
354 } |
355 |
355 |
356 newFrame.size.height = _splitPosition; |
356 newFrame.size.height = _splitPosition; |
357 masterRect = newFrame; |
357 masterRect = newFrame; |
358 |
358 |
359 newFrame.origin.y += newFrame.size.height; |
359 newFrame.origin.y += newFrame.size.height; |
360 newFrame.size.height = _splitWidth; |
360 newFrame.size.height = _splitWidth; |
361 dividerRect = newFrame; |
361 dividerRect = newFrame; |
362 |
362 |
363 newFrame.origin.y += newFrame.size.height; |
363 newFrame.origin.y += newFrame.size.height; |
364 newFrame.size.height = height - newFrame.origin.y; |
364 newFrame.size.height = height - newFrame.origin.y; |
365 detailRect = newFrame; |
365 detailRect = newFrame; |
366 |
366 |
367 } else { |
367 } else { |
368 if (!shouldShowMaster) { |
368 if (!shouldShowMaster) { |
369 // Move off-screen. |
369 // Move off-screen. |
370 newFrame.size.height += (_splitPosition + _splitWidth); |
370 newFrame.size.height += (_splitPosition + _splitWidth); |
371 } |
371 } |
372 |
372 |
373 newFrame.size.height -= (_splitPosition + _splitWidth); |
373 newFrame.size.height -= (_splitPosition + _splitWidth); |
374 detailRect = newFrame; |
374 detailRect = newFrame; |
375 |
375 |
376 newFrame.origin.y += newFrame.size.height; |
376 newFrame.origin.y += newFrame.size.height; |
377 newFrame.size.height = _splitWidth; |
377 newFrame.size.height = _splitWidth; |
378 dividerRect = newFrame; |
378 dividerRect = newFrame; |
379 |
379 |
380 newFrame.origin.y += newFrame.size.height; |
380 newFrame.origin.y += newFrame.size.height; |
381 newFrame.size.height = _splitPosition; |
381 newFrame.size.height = _splitPosition; |
382 masterRect = newFrame; |
382 masterRect = newFrame; |
383 } |
383 } |
384 |
384 |
385 // Position master. |
385 // Position master. |
386 controller = self.masterViewController; |
386 controller = self.masterViewController; |
387 if (controller && [controller isKindOfClass:[UIViewController class]]) { |
387 if (controller && [controller isKindOfClass:[UIViewController class]]) { |
388 theView = controller.view; |
388 theView = controller.view; |
389 if (theView) { |
389 if (theView) { |
390 theView.frame = masterRect; |
390 theView.frame = masterRect; |
391 if (!theView.superview) { |
391 if (!theView.superview) { |
392 [controller viewWillAppear:NO]; |
392 [controller viewWillAppear:NO]; |
393 [self.view addSubview:theView]; |
393 [self.view addSubview:theView]; |
394 [controller viewDidAppear:NO]; |
394 [controller viewDidAppear:NO]; |
395 } |
395 } |
396 } |
396 } |
397 } |
397 } |
398 |
398 |
399 // Position divider. |
399 // Position divider. |
400 theView = _dividerView; |
400 theView = _dividerView; |
401 theView.frame = dividerRect; |
401 theView.frame = dividerRect; |
402 if (!theView.superview) { |
402 if (!theView.superview) { |
403 [self.view addSubview:theView]; |
403 [self.view addSubview:theView]; |
404 } |
404 } |
405 |
405 |
406 // Position detail. |
406 // Position detail. |
407 controller = self.detailViewController; |
407 controller = self.detailViewController; |
408 if (controller && [controller isKindOfClass:[UIViewController class]]) { |
408 if (controller && [controller isKindOfClass:[UIViewController class]]) { |
409 theView = controller.view; |
409 theView = controller.view; |
410 if (theView) { |
410 if (theView) { |
411 theView.frame = detailRect; |
411 theView.frame = detailRect; |
412 if (!theView.superview) { |
412 if (!theView.superview) { |
413 [self.view insertSubview:theView aboveSubview:self.masterViewController.view]; |
413 [self.view insertSubview:theView aboveSubview:self.masterViewController.view]; |
414 } else { |
414 } else { |
415 [self.view bringSubviewToFront:theView]; |
415 [self.view bringSubviewToFront:theView]; |
416 } |
416 } |
417 } |
417 } |
418 } |
418 } |
419 } |
419 } |
420 |
420 |
421 // Create corner views if necessary. |
421 // Create corner views if necessary. |
422 MGSplitCornersView *leadingCorners; // top/left of screen in vertical/horizontal split. |
422 MGSplitCornersView *leadingCorners; // top/left of screen in vertical/horizontal split. |
423 MGSplitCornersView *trailingCorners; // bottom/right of screen in vertical/horizontal split. |
423 MGSplitCornersView *trailingCorners; // bottom/right of screen in vertical/horizontal split. |
424 if (!_cornerViews) { |
424 if (!_cornerViews) { |
425 CGRect cornerRect = CGRectMake(0, 0, 10, 10); // arbitrary, will be resized below. |
425 CGRect cornerRect = CGRectMake(0, 0, 10, 10); // arbitrary, will be resized below. |
426 leadingCorners = [[MGSplitCornersView alloc] initWithFrame:cornerRect]; |
426 leadingCorners = [[MGSplitCornersView alloc] initWithFrame:cornerRect]; |
427 leadingCorners.splitViewController = self; |
427 leadingCorners.splitViewController = self; |
428 leadingCorners.cornerBackgroundColor = MG_DEFAULT_CORNER_COLOR; |
428 leadingCorners.cornerBackgroundColor = MG_DEFAULT_CORNER_COLOR; |
429 leadingCorners.cornerRadius = MG_DEFAULT_CORNER_RADIUS; |
429 leadingCorners.cornerRadius = MG_DEFAULT_CORNER_RADIUS; |
430 trailingCorners = [[MGSplitCornersView alloc] initWithFrame:cornerRect]; |
430 trailingCorners = [[MGSplitCornersView alloc] initWithFrame:cornerRect]; |
431 trailingCorners.splitViewController = self; |
431 trailingCorners.splitViewController = self; |
432 trailingCorners.cornerBackgroundColor = MG_DEFAULT_CORNER_COLOR; |
432 trailingCorners.cornerBackgroundColor = MG_DEFAULT_CORNER_COLOR; |
433 trailingCorners.cornerRadius = MG_DEFAULT_CORNER_RADIUS; |
433 trailingCorners.cornerRadius = MG_DEFAULT_CORNER_RADIUS; |
434 _cornerViews = [[NSArray alloc] initWithObjects:leadingCorners, trailingCorners, nil]; |
434 _cornerViews = [[NSArray alloc] initWithObjects:leadingCorners, trailingCorners, nil]; |
435 [leadingCorners release]; |
435 [leadingCorners release]; |
436 [trailingCorners release]; |
436 [trailingCorners release]; |
437 |
437 |
438 } else if ([_cornerViews count] == 2) { |
438 } else if ([_cornerViews count] == 2) { |
439 leadingCorners = [_cornerViews objectAtIndex:0]; |
439 leadingCorners = [_cornerViews objectAtIndex:0]; |
440 trailingCorners = [_cornerViews objectAtIndex:1]; |
440 trailingCorners = [_cornerViews objectAtIndex:1]; |
441 } |
441 } |
442 |
442 |
443 // Configure and layout the corner-views. |
443 // Configure and layout the corner-views. |
444 leadingCorners.cornersPosition = (_vertical) ? MGCornersPositionLeadingVertical : MGCornersPositionLeadingHorizontal; |
444 leadingCorners.cornersPosition = (_vertical) ? MGCornersPositionLeadingVertical : MGCornersPositionLeadingHorizontal; |
445 trailingCorners.cornersPosition = (_vertical) ? MGCornersPositionTrailingVertical : MGCornersPositionTrailingHorizontal; |
445 trailingCorners.cornersPosition = (_vertical) ? MGCornersPositionTrailingVertical : MGCornersPositionTrailingHorizontal; |
446 leadingCorners.autoresizingMask = (_vertical) ? UIViewAutoresizingFlexibleBottomMargin : UIViewAutoresizingFlexibleRightMargin; |
446 leadingCorners.autoresizingMask = (_vertical) ? UIViewAutoresizingFlexibleBottomMargin : UIViewAutoresizingFlexibleRightMargin; |
447 trailingCorners.autoresizingMask = (_vertical) ? UIViewAutoresizingFlexibleTopMargin : UIViewAutoresizingFlexibleLeftMargin; |
447 trailingCorners.autoresizingMask = (_vertical) ? UIViewAutoresizingFlexibleTopMargin : UIViewAutoresizingFlexibleLeftMargin; |
448 |
448 |
449 float x, y, cornersWidth, cornersHeight; |
449 float x, y, cornersWidth, cornersHeight; |
450 CGRect leadingRect, trailingRect; |
450 CGRect leadingRect, trailingRect; |
451 float radius = leadingCorners.cornerRadius; |
451 float radius = leadingCorners.cornerRadius; |
452 if (_vertical) { // left/right split |
452 if (_vertical) { // left/right split |
453 cornersWidth = (radius * 2.0) + _splitWidth; |
453 cornersWidth = (radius * 2.0) + _splitWidth; |
454 cornersHeight = radius; |
454 cornersHeight = radius; |
455 x = ((shouldShowMaster) ? ((masterFirst) ? _splitPosition : width - (_splitPosition + _splitWidth)) : (0 - _splitWidth)) - radius; |
455 x = ((shouldShowMaster) ? ((masterFirst) ? _splitPosition : width - (_splitPosition + _splitWidth)) : (0 - _splitWidth)) - radius; |
456 y = 0; |
456 y = 0; |
457 leadingRect = CGRectMake(x, y, cornersWidth, cornersHeight); // top corners |
457 leadingRect = CGRectMake(x, y, cornersWidth, cornersHeight); // top corners |
458 trailingRect = CGRectMake(x, (height - cornersHeight), cornersWidth, cornersHeight); // bottom corners |
458 trailingRect = CGRectMake(x, (height - cornersHeight), cornersWidth, cornersHeight); // bottom corners |
459 |
459 |
460 } else { // top/bottom split |
460 } else { // top/bottom split |
461 x = 0; |
461 x = 0; |
462 y = ((shouldShowMaster) ? ((masterFirst) ? _splitPosition : height - (_splitPosition + _splitWidth)) : (0 - _splitWidth)) - radius; |
462 y = ((shouldShowMaster) ? ((masterFirst) ? _splitPosition : height - (_splitPosition + _splitWidth)) : (0 - _splitWidth)) - radius; |
463 cornersWidth = radius; |
463 cornersWidth = radius; |
464 cornersHeight = (radius * 2.0) + _splitWidth; |
464 cornersHeight = (radius * 2.0) + _splitWidth; |
465 leadingRect = CGRectMake(x, y, cornersWidth, cornersHeight); // left corners |
465 leadingRect = CGRectMake(x, y, cornersWidth, cornersHeight); // left corners |
466 trailingRect = CGRectMake((width - cornersWidth), y, cornersWidth, cornersHeight); // right corners |
466 trailingRect = CGRectMake((width - cornersWidth), y, cornersWidth, cornersHeight); // right corners |
467 } |
467 } |
468 |
468 |
469 leadingCorners.frame = leadingRect; |
469 leadingCorners.frame = leadingRect; |
470 trailingCorners.frame = trailingRect; |
470 trailingCorners.frame = trailingRect; |
471 |
471 |
472 // Ensure corners are visible and frontmost. |
472 // Ensure corners are visible and frontmost. |
473 if (!leadingCorners.superview) { |
473 if (!leadingCorners.superview) { |
474 [self.view insertSubview:leadingCorners aboveSubview:self.detailViewController.view]; |
474 [self.view insertSubview:leadingCorners aboveSubview:self.detailViewController.view]; |
475 [self.view insertSubview:trailingCorners aboveSubview:self.detailViewController.view]; |
475 [self.view insertSubview:trailingCorners aboveSubview:self.detailViewController.view]; |
476 } else { |
476 } else { |
477 [self.view bringSubviewToFront:leadingCorners]; |
477 [self.view bringSubviewToFront:leadingCorners]; |
478 [self.view bringSubviewToFront:trailingCorners]; |
478 [self.view bringSubviewToFront:trailingCorners]; |
479 } |
479 } |
480 } |
480 } |
481 |
481 |
482 |
482 |
483 - (void)layoutSubviewsWithAnimation:(BOOL)animate |
483 - (void)layoutSubviewsWithAnimation:(BOOL)animate |
484 { |
484 { |
485 [self layoutSubviewsForInterfaceOrientation:self.interfaceOrientation withAnimation:animate]; |
485 [self layoutSubviewsForInterfaceOrientation:self.interfaceOrientation withAnimation:animate]; |
486 } |
486 } |
487 |
487 |
488 |
488 |
489 - (void)layoutSubviews |
489 - (void)layoutSubviews |
490 { |
490 { |
491 [self layoutSubviewsForInterfaceOrientation:self.interfaceOrientation withAnimation:YES]; |
491 [self layoutSubviewsForInterfaceOrientation:self.interfaceOrientation withAnimation:YES]; |
492 } |
492 } |
493 |
493 |
494 |
494 |
495 - (void)viewWillAppear:(BOOL)animated |
495 - (void)viewWillAppear:(BOOL)animated |
496 { |
496 { |
497 [super viewWillAppear:animated]; |
497 [super viewWillAppear:animated]; |
498 |
498 |
499 if ([self isShowingMaster]) { |
499 if ([self isShowingMaster]) { |
500 [self.masterViewController viewWillAppear:animated]; |
500 [self.masterViewController viewWillAppear:animated]; |
501 } |
501 } |
502 [self.detailViewController viewWillAppear:animated]; |
502 [self.detailViewController viewWillAppear:animated]; |
503 |
503 |
504 _reconfigurePopup = YES; |
504 _reconfigurePopup = YES; |
505 [self layoutSubviews]; |
505 [self layoutSubviews]; |
506 } |
506 } |
507 |
507 |
508 |
508 |
509 - (void)viewDidAppear:(BOOL)animated |
509 - (void)viewDidAppear:(BOOL)animated |
510 { |
510 { |
511 [super viewDidAppear:animated]; |
511 [super viewDidAppear:animated]; |
512 |
512 |
513 if ([self isShowingMaster]) { |
513 if ([self isShowingMaster]) { |
514 [self.masterViewController viewDidAppear:animated]; |
514 [self.masterViewController viewDidAppear:animated]; |
515 } |
515 } |
516 [self.detailViewController viewDidAppear:animated]; |
516 [self.detailViewController viewDidAppear:animated]; |
517 } |
517 } |
518 |
518 |
519 |
519 |
520 - (void)viewWillDisappear:(BOOL)animated |
520 - (void)viewWillDisappear:(BOOL)animated |
521 { |
521 { |
522 [super viewWillDisappear:animated]; |
522 [super viewWillDisappear:animated]; |
523 |
523 |
524 if ([self isShowingMaster]) { |
524 if ([self isShowingMaster]) { |
525 [self.masterViewController viewWillDisappear:animated]; |
525 [self.masterViewController viewWillDisappear:animated]; |
526 } |
526 } |
527 [self.detailViewController viewWillDisappear:animated]; |
527 [self.detailViewController viewWillDisappear:animated]; |
528 } |
528 } |
529 |
529 |
530 |
530 |
531 - (void)viewDidDisappear:(BOOL)animated |
531 - (void)viewDidDisappear:(BOOL)animated |
532 { |
532 { |
533 [super viewDidDisappear:animated]; |
533 [super viewDidDisappear:animated]; |
534 |
534 |
535 if ([self isShowingMaster]) { |
535 if ([self isShowingMaster]) { |
536 [self.masterViewController viewDidDisappear:animated]; |
536 [self.masterViewController viewDidDisappear:animated]; |
537 } |
537 } |
538 [self.detailViewController viewDidDisappear:animated]; |
538 [self.detailViewController viewDidDisappear:animated]; |
539 } |
539 } |
540 |
540 |
541 |
541 |
542 #pragma mark - |
542 #pragma mark - |
543 #pragma mark Popover handling |
543 #pragma mark Popover handling |
544 |
544 |
545 |
545 |
546 - (void)reconfigureForMasterInPopover:(BOOL)inPopover |
546 - (void)reconfigureForMasterInPopover:(BOOL)inPopover |
547 { |
547 { |
548 _reconfigurePopup = NO; |
548 _reconfigurePopup = NO; |
549 |
549 |
550 if ((inPopover && _hiddenPopoverController) || (!inPopover && !_hiddenPopoverController) || !self.masterViewController) { |
550 if ((inPopover && _hiddenPopoverController) || (!inPopover && !_hiddenPopoverController) || !self.masterViewController) { |
551 // Nothing to do. |
551 // Nothing to do. |
552 return; |
552 return; |
553 } |
553 } |
554 |
554 |
555 if (inPopover && !_hiddenPopoverController && !_barButtonItem) { |
555 if (inPopover && !_hiddenPopoverController && !_barButtonItem) { |
556 // Create and configure popover for our masterViewController. |
556 // Create and configure popover for our masterViewController. |
557 [_hiddenPopoverController release]; |
557 [_hiddenPopoverController release]; |
558 _hiddenPopoverController = nil; |
558 _hiddenPopoverController = nil; |
559 [self.masterViewController viewWillDisappear:NO]; |
559 [self.masterViewController viewWillDisappear:NO]; |
560 _hiddenPopoverController = [[UIPopoverController alloc] initWithContentViewController:self.masterViewController]; |
560 _hiddenPopoverController = [[UIPopoverController alloc] initWithContentViewController:self.masterViewController]; |
561 [self.masterViewController viewDidDisappear:NO]; |
561 [self.masterViewController viewDidDisappear:NO]; |
562 |
562 |
563 // Create and configure _barButtonItem. |
563 // Create and configure _barButtonItem. |
564 _barButtonItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Master", nil) |
564 _barButtonItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Master", nil) |
565 style:UIBarButtonItemStyleBordered |
565 style:UIBarButtonItemStyleBordered |
566 target:self |
566 target:self |
567 action:@selector(showMasterPopover:)]; |
567 action:@selector(showMasterPopover:)]; |
568 |
568 |
569 // Inform delegate of this state of affairs. |
569 // Inform delegate of this state of affairs. |
570 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:willHideViewController:withBarButtonItem:forPopoverController:)]) { |
570 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:willHideViewController:withBarButtonItem:forPopoverController:)]) { |
571 [(NSObject <MGSplitViewControllerDelegate> *)_delegate splitViewController:self |
571 [(NSObject <MGSplitViewControllerDelegate> *)_delegate splitViewController:self |
572 willHideViewController:self.masterViewController |
572 willHideViewController:self.masterViewController |
573 withBarButtonItem:_barButtonItem |
573 withBarButtonItem:_barButtonItem |
574 forPopoverController:_hiddenPopoverController]; |
574 forPopoverController:_hiddenPopoverController]; |
575 } |
575 } |
576 |
576 |
577 } else if (!inPopover && _hiddenPopoverController && _barButtonItem) { |
577 } else if (!inPopover && _hiddenPopoverController && _barButtonItem) { |
578 // I know this looks strange, but it fixes a bizarre issue with UIPopoverController leaving masterViewController's views in disarray. |
578 // I know this looks strange, but it fixes a bizarre issue with UIPopoverController leaving masterViewController's views in disarray. |
579 [_hiddenPopoverController presentPopoverFromRect:CGRectZero inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:NO]; |
579 [_hiddenPopoverController presentPopoverFromRect:CGRectZero inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:NO]; |
580 |
580 |
581 // Remove master from popover and destroy popover, if it exists. |
581 // Remove master from popover and destroy popover, if it exists. |
582 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
582 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
583 [_hiddenPopoverController release]; |
583 [_hiddenPopoverController release]; |
584 _hiddenPopoverController = nil; |
584 _hiddenPopoverController = nil; |
585 |
585 |
586 // Inform delegate that the _barButtonItem will become invalid. |
586 // Inform delegate that the _barButtonItem will become invalid. |
587 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:willShowViewController:invalidatingBarButtonItem:)]) { |
587 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:willShowViewController:invalidatingBarButtonItem:)]) { |
588 [(NSObject <MGSplitViewControllerDelegate> *)_delegate splitViewController:self |
588 [(NSObject <MGSplitViewControllerDelegate> *)_delegate splitViewController:self |
589 willShowViewController:self.masterViewController |
589 willShowViewController:self.masterViewController |
590 invalidatingBarButtonItem:_barButtonItem]; |
590 invalidatingBarButtonItem:_barButtonItem]; |
591 } |
591 } |
592 |
592 |
593 // Destroy _barButtonItem. |
593 // Destroy _barButtonItem. |
594 [_barButtonItem release]; |
594 [_barButtonItem release]; |
595 _barButtonItem = nil; |
595 _barButtonItem = nil; |
596 |
596 |
597 // Move master view. |
597 // Move master view. |
598 UIView *masterView = self.masterViewController.view; |
598 UIView *masterView = self.masterViewController.view; |
599 if (masterView && masterView.superview != self.view) { |
599 if (masterView && masterView.superview != self.view) { |
600 [masterView removeFromSuperview]; |
600 [masterView removeFromSuperview]; |
601 } |
601 } |
602 } |
602 } |
603 } |
603 } |
604 |
604 |
605 |
605 |
606 - (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController |
606 - (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController |
607 { |
607 { |
608 [self reconfigureForMasterInPopover:NO]; |
608 [self reconfigureForMasterInPopover:NO]; |
609 } |
609 } |
610 |
610 |
611 |
611 |
612 - (void)notePopoverDismissed |
612 - (void)notePopoverDismissed |
613 { |
613 { |
614 [self popoverControllerDidDismissPopover:_hiddenPopoverController]; |
614 [self popoverControllerDidDismissPopover:_hiddenPopoverController]; |
615 } |
615 } |
616 |
616 |
617 |
617 |
618 #pragma mark - |
618 #pragma mark - |
619 #pragma mark Animations |
619 #pragma mark Animations |
620 |
620 |
621 |
621 |
622 - (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context |
622 - (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context |
623 { |
623 { |
624 if (([animationID isEqualToString:MG_ANIMATION_CHANGE_SPLIT_ORIENTATION] || |
624 if (([animationID isEqualToString:MG_ANIMATION_CHANGE_SPLIT_ORIENTATION] || |
625 [animationID isEqualToString:MG_ANIMATION_CHANGE_SUBVIEWS_ORDER]) |
625 [animationID isEqualToString:MG_ANIMATION_CHANGE_SUBVIEWS_ORDER]) |
626 && _cornerViews) { |
626 && _cornerViews) { |
627 for (UIView *corner in _cornerViews) { |
627 for (UIView *corner in _cornerViews) { |
628 corner.hidden = NO; |
628 corner.hidden = NO; |
629 } |
629 } |
630 _dividerView.hidden = NO; |
630 _dividerView.hidden = NO; |
631 } |
631 } |
632 } |
632 } |
633 |
633 |
634 |
634 |
635 #pragma mark - |
635 #pragma mark - |
636 #pragma mark IB Actions |
636 #pragma mark IB Actions |
637 |
637 |
638 |
638 |
639 - (IBAction)toggleSplitOrientation:(id)sender |
639 - (IBAction)toggleSplitOrientation:(id)sender |
640 { |
640 { |
641 BOOL showingMaster = [self isShowingMaster]; |
641 BOOL showingMaster = [self isShowingMaster]; |
642 if (showingMaster) { |
642 if (showingMaster) { |
643 if (_cornerViews) { |
643 if (_cornerViews) { |
644 for (UIView *corner in _cornerViews) { |
644 for (UIView *corner in _cornerViews) { |
645 corner.hidden = YES; |
645 corner.hidden = YES; |
646 } |
646 } |
647 _dividerView.hidden = YES; |
647 _dividerView.hidden = YES; |
648 } |
648 } |
649 [UIView beginAnimations:MG_ANIMATION_CHANGE_SPLIT_ORIENTATION context:nil]; |
649 [UIView beginAnimations:MG_ANIMATION_CHANGE_SPLIT_ORIENTATION context:nil]; |
650 [UIView setAnimationDelegate:self]; |
650 [UIView setAnimationDelegate:self]; |
651 [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)]; |
651 [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)]; |
652 } |
652 } |
653 self.vertical = (!self.vertical); |
653 self.vertical = (!self.vertical); |
654 if (showingMaster) { |
654 if (showingMaster) { |
655 [UIView commitAnimations]; |
655 [UIView commitAnimations]; |
656 } |
656 } |
657 } |
657 } |
658 |
658 |
659 |
659 |
660 - (IBAction)toggleMasterBeforeDetail:(id)sender |
660 - (IBAction)toggleMasterBeforeDetail:(id)sender |
661 { |
661 { |
662 BOOL showingMaster = [self isShowingMaster]; |
662 BOOL showingMaster = [self isShowingMaster]; |
663 if (showingMaster) { |
663 if (showingMaster) { |
664 if (_cornerViews) { |
664 if (_cornerViews) { |
665 for (UIView *corner in _cornerViews) { |
665 for (UIView *corner in _cornerViews) { |
666 corner.hidden = YES; |
666 corner.hidden = YES; |
667 } |
667 } |
668 _dividerView.hidden = YES; |
668 _dividerView.hidden = YES; |
669 } |
669 } |
670 [UIView beginAnimations:MG_ANIMATION_CHANGE_SUBVIEWS_ORDER context:nil]; |
670 [UIView beginAnimations:MG_ANIMATION_CHANGE_SUBVIEWS_ORDER context:nil]; |
671 [UIView setAnimationDelegate:self]; |
671 [UIView setAnimationDelegate:self]; |
672 [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)]; |
672 [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)]; |
673 } |
673 } |
674 self.masterBeforeDetail = (!self.masterBeforeDetail); |
674 self.masterBeforeDetail = (!self.masterBeforeDetail); |
675 if (showingMaster) { |
675 if (showingMaster) { |
676 [UIView commitAnimations]; |
676 [UIView commitAnimations]; |
677 } |
677 } |
678 } |
678 } |
679 |
679 |
680 |
680 |
681 - (IBAction)toggleMasterView:(id)sender |
681 - (IBAction)toggleMasterView:(id)sender |
682 { |
682 { |
683 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
683 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
684 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
684 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
685 } |
685 } |
686 |
686 |
687 if (![self isShowingMaster]) { |
687 if (![self isShowingMaster]) { |
688 // We're about to show the master view. Ensure it's in place off-screen to be animated in. |
688 // We're about to show the master view. Ensure it's in place off-screen to be animated in. |
689 _reconfigurePopup = YES; |
689 _reconfigurePopup = YES; |
690 [self reconfigureForMasterInPopover:NO]; |
690 [self reconfigureForMasterInPopover:NO]; |
691 [self layoutSubviews]; |
691 [self layoutSubviews]; |
692 } |
692 } |
693 |
693 |
694 // This action functions on the current primary orientation; it is independent of the other primary orientation. |
694 // This action functions on the current primary orientation; it is independent of the other primary orientation. |
695 [UIView beginAnimations:@"toggleMaster" context:nil]; |
695 [UIView beginAnimations:@"toggleMaster" context:nil]; |
696 if (self.isLandscape) { |
696 if (self.isLandscape) { |
697 self.showsMasterInLandscape = !_showsMasterInLandscape; |
697 self.showsMasterInLandscape = !_showsMasterInLandscape; |
698 } else { |
698 } else { |
699 self.showsMasterInPortrait = !_showsMasterInPortrait; |
699 self.showsMasterInPortrait = !_showsMasterInPortrait; |
700 } |
700 } |
701 [UIView commitAnimations]; |
701 [UIView commitAnimations]; |
702 } |
702 } |
703 |
703 |
704 |
704 |
705 - (IBAction)showMasterPopover:(id) sender |
705 - (IBAction)showMasterPopover:(id) sender |
706 { |
706 { |
707 if (_hiddenPopoverController && !(_hiddenPopoverController.popoverVisible)) { |
707 if (_hiddenPopoverController && !(_hiddenPopoverController.popoverVisible)) { |
708 // Inform delegate. |
708 // Inform delegate. |
709 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:popoverController:willPresentViewController:)]) { |
709 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:popoverController:willPresentViewController:)]) { |
710 [(NSObject <MGSplitViewControllerDelegate> *)_delegate splitViewController:self |
710 [(NSObject <MGSplitViewControllerDelegate> *)_delegate splitViewController:self |
711 popoverController:_hiddenPopoverController |
711 popoverController:_hiddenPopoverController |
712 willPresentViewController:self.masterViewController]; |
712 willPresentViewController:self.masterViewController]; |
713 } |
713 } |
714 |
714 |
715 // Show popover. |
715 // Show popover. |
716 [_hiddenPopoverController presentPopoverFromBarButtonItem:_barButtonItem permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; |
716 [_hiddenPopoverController presentPopoverFromBarButtonItem:_barButtonItem permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; |
717 } |
717 } |
718 } |
718 } |
719 |
719 |
720 |
720 |
721 #pragma mark - |
721 #pragma mark - |
722 #pragma mark Accessors and properties |
722 #pragma mark Accessors and properties |
723 |
723 |
724 |
724 |
725 - (id)delegate |
725 - (id)delegate |
726 { |
726 { |
727 return _delegate; |
727 return _delegate; |
728 } |
728 } |
729 |
729 |
730 |
730 |
731 - (void)setDelegate:(id <MGSplitViewControllerDelegate>)newDelegate |
731 - (void)setDelegate:(id <MGSplitViewControllerDelegate>)newDelegate |
732 { |
732 { |
733 if (newDelegate != _delegate && |
733 if (newDelegate != _delegate && |
734 (!newDelegate || [(NSObject *)newDelegate conformsToProtocol:@protocol(MGSplitViewControllerDelegate)])) { |
734 (!newDelegate || [(NSObject *)newDelegate conformsToProtocol:@protocol(MGSplitViewControllerDelegate)])) { |
735 _delegate = newDelegate; |
735 _delegate = newDelegate; |
736 } |
736 } |
737 } |
737 } |
738 |
738 |
739 |
739 |
740 - (BOOL)showsMasterInPortrait |
740 - (BOOL)showsMasterInPortrait |
741 { |
741 { |
742 return _showsMasterInPortrait; |
742 return _showsMasterInPortrait; |
743 } |
743 } |
744 |
744 |
745 |
745 |
746 - (void)setShowsMasterInPortrait:(BOOL)flag |
746 - (void)setShowsMasterInPortrait:(BOOL)flag |
747 { |
747 { |
748 if (flag != _showsMasterInPortrait) { |
748 if (flag != _showsMasterInPortrait) { |
749 _showsMasterInPortrait = flag; |
749 _showsMasterInPortrait = flag; |
750 |
750 |
751 if (![self isLandscape]) { // i.e. if this will cause a visual change. |
751 if (![self isLandscape]) { // i.e. if this will cause a visual change. |
752 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
752 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
753 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
753 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
754 } |
754 } |
755 |
755 |
756 // Rearrange views. |
756 // Rearrange views. |
757 _reconfigurePopup = YES; |
757 _reconfigurePopup = YES; |
758 [self layoutSubviews]; |
758 [self layoutSubviews]; |
759 } |
759 } |
760 } |
760 } |
761 } |
761 } |
762 |
762 |
763 |
763 |
764 - (BOOL)showsMasterInLandscape |
764 - (BOOL)showsMasterInLandscape |
765 { |
765 { |
766 return _showsMasterInLandscape; |
766 return _showsMasterInLandscape; |
767 } |
767 } |
768 |
768 |
769 |
769 |
770 - (void)setShowsMasterInLandscape:(BOOL)flag |
770 - (void)setShowsMasterInLandscape:(BOOL)flag |
771 { |
771 { |
772 if (flag != _showsMasterInLandscape) { |
772 if (flag != _showsMasterInLandscape) { |
773 _showsMasterInLandscape = flag; |
773 _showsMasterInLandscape = flag; |
774 |
774 |
775 if ([self isLandscape]) { // i.e. if this will cause a visual change. |
775 if ([self isLandscape]) { // i.e. if this will cause a visual change. |
776 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
776 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
777 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
777 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
778 } |
778 } |
779 |
779 |
780 // Rearrange views. |
780 // Rearrange views. |
781 _reconfigurePopup = YES; |
781 _reconfigurePopup = YES; |
782 [self layoutSubviews]; |
782 [self layoutSubviews]; |
783 } |
783 } |
784 } |
784 } |
785 } |
785 } |
786 |
786 |
787 |
787 |
788 - (BOOL)isVertical |
788 - (BOOL)isVertical |
789 { |
789 { |
790 return _vertical; |
790 return _vertical; |
791 } |
791 } |
792 |
792 |
793 |
793 |
794 - (void)setVertical:(BOOL)flag |
794 - (void)setVertical:(BOOL)flag |
795 { |
795 { |
796 if (flag != _vertical) { |
796 if (flag != _vertical) { |
797 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
797 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
798 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
798 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
799 } |
799 } |
800 |
800 |
801 _vertical = flag; |
801 _vertical = flag; |
802 |
802 |
803 // Inform delegate. |
803 // Inform delegate. |
804 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:willChangeSplitOrientationToVertical:)]) { |
804 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:willChangeSplitOrientationToVertical:)]) { |
805 [_delegate splitViewController:self willChangeSplitOrientationToVertical:_vertical]; |
805 [_delegate splitViewController:self willChangeSplitOrientationToVertical:_vertical]; |
806 } |
806 } |
807 |
807 |
808 [self layoutSubviews]; |
808 [self layoutSubviews]; |
809 } |
809 } |
810 } |
810 } |
811 |
811 |
812 |
812 |
813 - (BOOL)isMasterBeforeDetail |
813 - (BOOL)isMasterBeforeDetail |
814 { |
814 { |
815 return _masterBeforeDetail; |
815 return _masterBeforeDetail; |
816 } |
816 } |
817 |
817 |
818 |
818 |
819 - (void)setMasterBeforeDetail:(BOOL)flag |
819 - (void)setMasterBeforeDetail:(BOOL)flag |
820 { |
820 { |
821 if (flag != _masterBeforeDetail) { |
821 if (flag != _masterBeforeDetail) { |
822 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
822 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
823 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
823 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
824 } |
824 } |
825 |
825 |
826 _masterBeforeDetail = flag; |
826 _masterBeforeDetail = flag; |
827 |
827 |
828 if ([self isShowingMaster]) { |
828 if ([self isShowingMaster]) { |
829 [self layoutSubviews]; |
829 [self layoutSubviews]; |
830 } |
830 } |
831 } |
831 } |
832 } |
832 } |
833 |
833 |
834 |
834 |
835 - (float)splitPosition |
835 - (float)splitPosition |
836 { |
836 { |
837 return _splitPosition; |
837 return _splitPosition; |
838 } |
838 } |
839 |
839 |
840 |
840 |
841 - (void)setSplitPosition:(float)posn |
841 - (void)setSplitPosition:(float)posn |
842 { |
842 { |
843 // Check to see if delegate wishes to constrain the position. |
843 // Check to see if delegate wishes to constrain the position. |
844 float newPosn = posn; |
844 float newPosn = posn; |
845 BOOL constrained = NO; |
845 BOOL constrained = NO; |
846 CGSize fullSize = [self splitViewSizeForOrientation:self.interfaceOrientation]; |
846 CGSize fullSize = [self splitViewSizeForOrientation:self.interfaceOrientation]; |
847 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:constrainSplitPosition:splitViewSize:)]) { |
847 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:constrainSplitPosition:splitViewSize:)]) { |
848 newPosn = [_delegate splitViewController:self constrainSplitPosition:newPosn splitViewSize:fullSize]; |
848 newPosn = [_delegate splitViewController:self constrainSplitPosition:newPosn splitViewSize:fullSize]; |
849 constrained = YES; // implicitly trust delegate's response. |
849 constrained = YES; // implicitly trust delegate's response. |
850 |
850 |
851 } else { |
851 } else { |
852 // Apply default constraints if delegate doesn't wish to participate. |
852 // Apply default constraints if delegate doesn't wish to participate. |
853 float minPos = MG_MIN_VIEW_WIDTH; |
853 float minPos = MG_MIN_VIEW_WIDTH; |
854 float maxPos = ((_vertical) ? fullSize.width : fullSize.height) - (MG_MIN_VIEW_WIDTH + _splitWidth); |
854 float maxPos = ((_vertical) ? fullSize.width : fullSize.height) - (MG_MIN_VIEW_WIDTH + _splitWidth); |
855 constrained = (newPosn != _splitPosition && newPosn >= minPos && newPosn <= maxPos); |
855 constrained = (newPosn != _splitPosition && newPosn >= minPos && newPosn <= maxPos); |
856 } |
856 } |
857 |
857 |
858 if (constrained) { |
858 if (constrained) { |
859 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
859 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
860 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
860 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
861 } |
861 } |
862 |
862 |
863 _splitPosition = newPosn; |
863 _splitPosition = newPosn; |
864 |
864 |
865 // Inform delegate. |
865 // Inform delegate. |
866 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:willMoveSplitToPosition:)]) { |
866 if (_delegate && [_delegate respondsToSelector:@selector(splitViewController:willMoveSplitToPosition:)]) { |
867 [_delegate splitViewController:self willMoveSplitToPosition:_splitPosition]; |
867 [_delegate splitViewController:self willMoveSplitToPosition:_splitPosition]; |
868 } |
868 } |
869 |
869 |
870 if ([self isShowingMaster]) { |
870 if ([self isShowingMaster]) { |
871 [self layoutSubviews]; |
871 [self layoutSubviews]; |
872 } |
872 } |
873 } |
873 } |
874 } |
874 } |
875 |
875 |
876 |
876 |
877 - (void)setSplitPosition:(float)posn animated:(BOOL)animate |
877 - (void)setSplitPosition:(float)posn animated:(BOOL)animate |
878 { |
878 { |
879 BOOL shouldAnimate = (animate && [self isShowingMaster]); |
879 BOOL shouldAnimate = (animate && [self isShowingMaster]); |
880 if (shouldAnimate) { |
880 if (shouldAnimate) { |
881 [UIView beginAnimations:@"SplitPosition" context:nil]; |
881 [UIView beginAnimations:@"SplitPosition" context:nil]; |
882 } |
882 } |
883 [self setSplitPosition:posn]; |
883 [self setSplitPosition:posn]; |
884 if (shouldAnimate) { |
884 if (shouldAnimate) { |
885 [UIView commitAnimations]; |
885 [UIView commitAnimations]; |
886 } |
886 } |
887 } |
887 } |
888 |
888 |
889 |
889 |
890 - (float)splitWidth |
890 - (float)splitWidth |
891 { |
891 { |
892 return _splitWidth; |
892 return _splitWidth; |
893 } |
893 } |
894 |
894 |
895 |
895 |
896 - (void)setSplitWidth:(float)width |
896 - (void)setSplitWidth:(float)width |
897 { |
897 { |
898 if (width != _splitWidth && width >= 0) { |
898 if (width != _splitWidth && width >= 0) { |
899 _splitWidth = width; |
899 _splitWidth = width; |
900 if ([self isShowingMaster]) { |
900 if ([self isShowingMaster]) { |
901 [self layoutSubviews]; |
901 [self layoutSubviews]; |
902 } |
902 } |
903 } |
903 } |
904 } |
904 } |
905 |
905 |
906 |
906 |
907 - (NSArray *)viewControllers |
907 - (NSArray *)viewControllers |
908 { |
908 { |
909 return [[_viewControllers copy] autorelease]; |
909 return [[_viewControllers copy] autorelease]; |
910 } |
910 } |
911 |
911 |
912 |
912 |
913 - (void)setViewControllers:(NSArray *)controllers |
913 - (void)setViewControllers:(NSArray *)controllers |
914 { |
914 { |
915 if (controllers != _viewControllers) { |
915 if (controllers != _viewControllers) { |
916 for (UIViewController *controller in _viewControllers) { |
916 for (UIViewController *controller in _viewControllers) { |
917 if ([controller isKindOfClass:[UIViewController class]]) { |
917 if ([controller isKindOfClass:[UIViewController class]]) { |
918 [controller.view removeFromSuperview]; |
918 [controller.view removeFromSuperview]; |
919 } |
919 } |
920 } |
920 } |
921 [_viewControllers release]; |
921 [_viewControllers release]; |
922 _viewControllers = [[NSMutableArray alloc] initWithCapacity:2]; |
922 _viewControllers = [[NSMutableArray alloc] initWithCapacity:2]; |
923 if (controllers && [controllers count] >= 2) { |
923 if (controllers && [controllers count] >= 2) { |
924 self.masterViewController = [controllers objectAtIndex:0]; |
924 self.masterViewController = [controllers objectAtIndex:0]; |
925 self.detailViewController = [controllers objectAtIndex:1]; |
925 self.detailViewController = [controllers objectAtIndex:1]; |
926 } else { |
926 } else { |
927 NSLog(@"Error: %@ requires 2 view-controllers. (%@)", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); |
927 NSLog(@"Error: %@ requires 2 view-controllers. (%@)", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); |
928 } |
928 } |
929 |
929 |
930 [self layoutSubviews]; |
930 [self layoutSubviews]; |
931 } |
931 } |
932 } |
932 } |
933 |
933 |
934 |
934 |
935 - (UIViewController *)masterViewController |
935 - (UIViewController *)masterViewController |
936 { |
936 { |
937 if (_viewControllers && [_viewControllers count] > 0) { |
937 if (_viewControllers && [_viewControllers count] > 0) { |
938 NSObject *controller = [_viewControllers objectAtIndex:0]; |
938 NSObject *controller = [_viewControllers objectAtIndex:0]; |
939 if ([controller isKindOfClass:[UIViewController class]]) { |
939 if ([controller isKindOfClass:[UIViewController class]]) { |
940 return [[controller retain] autorelease]; |
940 return [[controller retain] autorelease]; |
941 } |
941 } |
942 } |
942 } |
943 |
943 |
944 return nil; |
944 return nil; |
945 } |
945 } |
946 |
946 |
947 |
947 |
948 - (void)setMasterViewController:(UIViewController *)master |
948 - (void)setMasterViewController:(UIViewController *)master |
949 { |
949 { |
950 if (!_viewControllers) { |
950 if (!_viewControllers) { |
951 _viewControllers = [[NSMutableArray alloc] initWithCapacity:2]; |
951 _viewControllers = [[NSMutableArray alloc] initWithCapacity:2]; |
952 } |
952 } |
953 |
953 |
954 NSObject *newMaster = master; |
954 NSObject *newMaster = master; |
955 if (!newMaster) { |
955 if (!newMaster) { |
956 newMaster = [NSNull null]; |
956 newMaster = [NSNull null]; |
957 } |
957 } |
958 |
958 |
959 BOOL changed = YES; |
959 BOOL changed = YES; |
960 if ([_viewControllers count] > 0) { |
960 if ([_viewControllers count] > 0) { |
961 if ([_viewControllers objectAtIndex:0] == newMaster) { |
961 if ([_viewControllers objectAtIndex:0] == newMaster) { |
962 changed = NO; |
962 changed = NO; |
963 } else { |
963 } else { |
964 [_viewControllers replaceObjectAtIndex:0 withObject:newMaster]; |
964 [_viewControllers replaceObjectAtIndex:0 withObject:newMaster]; |
965 } |
965 } |
966 |
966 |
967 } else { |
967 } else { |
968 [_viewControllers addObject:newMaster]; |
968 [_viewControllers addObject:newMaster]; |
969 } |
969 } |
970 |
970 |
971 if (changed) { |
971 if (changed) { |
972 [self layoutSubviews]; |
972 [self layoutSubviews]; |
973 } |
973 } |
974 } |
974 } |
975 |
975 |
976 |
976 |
977 - (UIViewController *)detailViewController |
977 - (UIViewController *)detailViewController |
978 { |
978 { |
979 if (_viewControllers && [_viewControllers count] > 1) { |
979 if (_viewControllers && [_viewControllers count] > 1) { |
980 NSObject *controller = [_viewControllers objectAtIndex:1]; |
980 NSObject *controller = [_viewControllers objectAtIndex:1]; |
981 if ([controller isKindOfClass:[UIViewController class]]) { |
981 if ([controller isKindOfClass:[UIViewController class]]) { |
982 return [[controller retain] autorelease]; |
982 return [[controller retain] autorelease]; |
983 } |
983 } |
984 } |
984 } |
985 |
985 |
986 return nil; |
986 return nil; |
987 } |
987 } |
988 |
988 |
989 |
989 |
990 - (void)setDetailViewController:(UIViewController *)detail |
990 - (void)setDetailViewController:(UIViewController *)detail |
991 { |
991 { |
992 if (!_viewControllers) { |
992 if (!_viewControllers) { |
993 _viewControllers = [[NSMutableArray alloc] initWithCapacity:2]; |
993 _viewControllers = [[NSMutableArray alloc] initWithCapacity:2]; |
994 [_viewControllers addObject:[NSNull null]]; |
994 [_viewControllers addObject:[NSNull null]]; |
995 } |
995 } |
996 |
996 |
997 BOOL changed = YES; |
997 BOOL changed = YES; |
998 if ([_viewControllers count] > 1) { |
998 if ([_viewControllers count] > 1) { |
999 if ([_viewControllers objectAtIndex:1] == detail) { |
999 if ([_viewControllers objectAtIndex:1] == detail) { |
1000 changed = NO; |
1000 changed = NO; |
1001 } else { |
1001 } else { |
1002 [_viewControllers replaceObjectAtIndex:1 withObject:detail]; |
1002 [_viewControllers replaceObjectAtIndex:1 withObject:detail]; |
1003 } |
1003 } |
1004 |
1004 |
1005 } else { |
1005 } else { |
1006 [_viewControllers addObject:detail]; |
1006 [_viewControllers addObject:detail]; |
1007 } |
1007 } |
1008 |
1008 |
1009 if (changed) { |
1009 if (changed) { |
1010 [self layoutSubviews]; |
1010 [self layoutSubviews]; |
1011 } |
1011 } |
1012 } |
1012 } |
1013 |
1013 |
1014 |
1014 |
1015 - (MGSplitDividerView *)dividerView |
1015 - (MGSplitDividerView *)dividerView |
1016 { |
1016 { |
1017 return [[_dividerView retain] autorelease]; |
1017 return [[_dividerView retain] autorelease]; |
1018 } |
1018 } |
1019 |
1019 |
1020 |
1020 |
1021 - (void)setDividerView:(MGSplitDividerView *)divider |
1021 - (void)setDividerView:(MGSplitDividerView *)divider |
1022 { |
1022 { |
1023 if (divider != _dividerView) { |
1023 if (divider != _dividerView) { |
1024 [_dividerView removeFromSuperview]; |
1024 [_dividerView removeFromSuperview]; |
1025 [_dividerView release]; |
1025 [_dividerView release]; |
1026 _dividerView = [divider retain]; |
1026 _dividerView = [divider retain]; |
1027 _dividerView.splitViewController = self; |
1027 _dividerView.splitViewController = self; |
1028 _dividerView.backgroundColor = MG_DEFAULT_CORNER_COLOR; |
1028 _dividerView.backgroundColor = MG_DEFAULT_CORNER_COLOR; |
1029 if ([self isShowingMaster]) { |
1029 if ([self isShowingMaster]) { |
1030 [self layoutSubviews]; |
1030 [self layoutSubviews]; |
1031 } |
1031 } |
1032 } |
1032 } |
1033 } |
1033 } |
1034 |
1034 |
1035 |
1035 |
1036 - (BOOL)allowsDraggingDivider |
1036 - (BOOL)allowsDraggingDivider |
1037 { |
1037 { |
1038 if (_dividerView) { |
1038 if (_dividerView) { |
1039 return _dividerView.allowsDragging; |
1039 return _dividerView.allowsDragging; |
1040 } |
1040 } |
1041 |
1041 |
1042 return NO; |
1042 return NO; |
1043 } |
1043 } |
1044 |
1044 |
1045 |
1045 |
1046 - (void)setAllowsDraggingDivider:(BOOL)flag |
1046 - (void)setAllowsDraggingDivider:(BOOL)flag |
1047 { |
1047 { |
1048 if (self.allowsDraggingDivider != flag && _dividerView) { |
1048 if (self.allowsDraggingDivider != flag && _dividerView) { |
1049 _dividerView.allowsDragging = flag; |
1049 _dividerView.allowsDragging = flag; |
1050 } |
1050 } |
1051 } |
1051 } |
1052 |
1052 |
1053 |
1053 |
1054 - (MGSplitViewDividerStyle)dividerStyle |
1054 - (MGSplitViewDividerStyle)dividerStyle |
1055 { |
1055 { |
1056 return _dividerStyle; |
1056 return _dividerStyle; |
1057 } |
1057 } |
1058 |
1058 |
1059 |
1059 |
1060 - (void)setDividerStyle:(MGSplitViewDividerStyle)newStyle |
1060 - (void)setDividerStyle:(MGSplitViewDividerStyle)newStyle |
1061 { |
1061 { |
1062 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
1062 if (_hiddenPopoverController && _hiddenPopoverController.popoverVisible) { |
1063 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
1063 [_hiddenPopoverController dismissPopoverAnimated:NO]; |
1064 } |
1064 } |
1065 |
1065 |
1066 // We don't check to see if newStyle equals _dividerStyle, because it's a meta-setting. |
1066 // We don't check to see if newStyle equals _dividerStyle, because it's a meta-setting. |
1067 // Aspects could have been changed since it was set. |
1067 // Aspects could have been changed since it was set. |
1068 _dividerStyle = newStyle; |
1068 _dividerStyle = newStyle; |
1069 |
1069 |
1070 // Reconfigure general appearance and behaviour. |
1070 // Reconfigure general appearance and behaviour. |
1071 float cornerRadius; |
1071 float cornerRadius; |
1072 if (_dividerStyle == MGSplitViewDividerStyleThin) { |
1072 if (_dividerStyle == MGSplitViewDividerStyleThin) { |
1073 cornerRadius = MG_DEFAULT_CORNER_RADIUS; |
1073 cornerRadius = MG_DEFAULT_CORNER_RADIUS; |
1074 _splitWidth = MG_DEFAULT_SPLIT_WIDTH; |
1074 _splitWidth = MG_DEFAULT_SPLIT_WIDTH; |
1075 self.allowsDraggingDivider = NO; |
1075 self.allowsDraggingDivider = NO; |
1076 |
1076 |
1077 } else if (_dividerStyle == MGSplitViewDividerStylePaneSplitter) { |
1077 } else if (_dividerStyle == MGSplitViewDividerStylePaneSplitter) { |
1078 cornerRadius = MG_PANESPLITTER_CORNER_RADIUS; |
1078 cornerRadius = MG_PANESPLITTER_CORNER_RADIUS; |
1079 _splitWidth = MG_PANESPLITTER_SPLIT_WIDTH; |
1079 _splitWidth = MG_PANESPLITTER_SPLIT_WIDTH; |
1080 self.allowsDraggingDivider = YES; |
1080 self.allowsDraggingDivider = YES; |
1081 } |
1081 } |
1082 |
1082 |
1083 // Update divider and corners. |
1083 // Update divider and corners. |
1084 [_dividerView setNeedsDisplay]; |
1084 [_dividerView setNeedsDisplay]; |
1085 if (_cornerViews) { |
1085 if (_cornerViews) { |
1086 for (MGSplitCornersView *corner in _cornerViews) { |
1086 for (MGSplitCornersView *corner in _cornerViews) { |
1087 corner.cornerRadius = cornerRadius; |
1087 corner.cornerRadius = cornerRadius; |
1088 } |
1088 } |
1089 } |
1089 } |
1090 |
1090 |
1091 // Layout all views. |
1091 // Layout all views. |
1092 [self layoutSubviews]; |
1092 [self layoutSubviews]; |
1093 } |
1093 } |
1094 |
1094 |
1095 |
1095 |
1096 - (void)setDividerStyle:(MGSplitViewDividerStyle)newStyle animated:(BOOL)animate |
1096 - (void)setDividerStyle:(MGSplitViewDividerStyle)newStyle animated:(BOOL)animate |
1097 { |
1097 { |
1098 BOOL shouldAnimate = (animate && [self isShowingMaster]); |
1098 BOOL shouldAnimate = (animate && [self isShowingMaster]); |
1099 if (shouldAnimate) { |
1099 if (shouldAnimate) { |
1100 [UIView beginAnimations:@"DividerStyle" context:nil]; |
1100 [UIView beginAnimations:@"DividerStyle" context:nil]; |
1101 } |
1101 } |
1102 [self setDividerStyle:newStyle]; |
1102 [self setDividerStyle:newStyle]; |
1103 if (shouldAnimate) { |
1103 if (shouldAnimate) { |
1104 [UIView commitAnimations]; |
1104 [UIView commitAnimations]; |
1105 } |
1105 } |
1106 } |
1106 } |
1107 |
1107 |
1108 |
1108 |
1109 - (NSArray *)cornerViews |
1109 - (NSArray *)cornerViews |
1110 { |
1110 { |
1111 if (_cornerViews) { |
1111 if (_cornerViews) { |
1112 return [[_cornerViews retain] autorelease]; |
1112 return [[_cornerViews retain] autorelease]; |
1113 } |
1113 } |
1114 |
1114 |
1115 return nil; |
1115 return nil; |
1116 } |
1116 } |
1117 |
1117 |
1118 |
1118 |
1119 @synthesize showsMasterInPortrait; |
1119 @synthesize showsMasterInPortrait; |
1120 @synthesize showsMasterInLandscape; |
1120 @synthesize showsMasterInLandscape; |