| Index: ios/chrome/browser/ui/contextual_search/panel_configuration.mm
|
| diff --git a/ios/chrome/browser/ui/contextual_search/panel_configuration.mm b/ios/chrome/browser/ui/contextual_search/panel_configuration.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..7e836d9c329b20bb1e80ee062e788a34094d7fb1
|
| --- /dev/null
|
| +++ b/ios/chrome/browser/ui/contextual_search/panel_configuration.mm
|
| @@ -0,0 +1,238 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "ios/chrome/browser/ui/contextual_search/panel_configuration.h"
|
| +
|
| +#include "base/logging.h"
|
| +#include "base/mac/scoped_nsobject.h"
|
| +
|
| +namespace {
|
| +// Amount of tab that a previewing pane leaves visible, expressed as a fraction.
|
| +const CGFloat kPhonePreviewingDisplayRatio = 1.0 / 3.0;
|
| +// Phone peeking height equals phone toolbar height.
|
| +const CGFloat kPhonePeekingHeight = 64.0;
|
| +// Phone covering offset equals the status bar height;
|
| +const CGFloat kPhoneCoveringHeightOffset = 20.0;
|
| +
|
| +const CGFloat kPadPreviewingDisplayRatio = 1.0 / 3.0;
|
| +// iPad peeking height equals iPad toolbar height.
|
| +const CGFloat kPadPeekingHeight = 56.0;
|
| +// Pad covering offset = tab strip height (39) + status bar height (20).
|
| +const CGFloat kPadCoveringHeightOffset = 59.0;
|
| +// Offset to move the pad covering height down by so it looks better.
|
| +const CGFloat kPadCoveringHeightDecrease = 30.0;
|
| +// Width ratio for regular panel sizes.
|
| +const CGFloat kRegularPanelWidthRatio = 0.6;
|
| +
|
| +// Struct wrapper for passing around a C array.
|
| +typedef struct { CGFloat byState[ContextualSearch::COVERING + 1]; } Positions;
|
| +}
|
| +
|
| +@interface PanelConfiguration ()
|
| +@property(nonatomic, assign) Positions positions;
|
| +- (void)updatePositions;
|
| +@end
|
| +
|
| +@implementation PanelConfiguration
|
| +
|
| +@synthesize containerSize = _containerSize;
|
| +@synthesize positions = _positions;
|
| +@synthesize horizontalSizeClass = _horizontalSizeClass;
|
| +
|
| ++ (instancetype)configurationForContainerSize:(CGSize)containerSize
|
| + horizontalSizeClass:
|
| + (UIUserInterfaceSizeClass)horizontalSizeClass {
|
| + PanelConfiguration* config = [[[self alloc] init] autorelease];
|
| + config.containerSize = containerSize;
|
| + config.horizontalSizeClass = horizontalSizeClass;
|
| + return config;
|
| +}
|
| +
|
| +- (void)setContainerSize:(CGSize)containerSize {
|
| + DCHECK(containerSize.height > self.peekingHeight);
|
| + _containerSize = containerSize;
|
| + [self updatePositions];
|
| +}
|
| +
|
| +- (CGFloat)peekingHeight {
|
| + NOTIMPLEMENTED()
|
| + << "PanelConfiguation is an abstract superclass; use a concrete subclass";
|
| + return 0.0;
|
| +}
|
| +
|
| +- (void)updatePositions {
|
| + NOTIMPLEMENTED()
|
| + << "PanelConfiguation is an abstract superclass; use a concrete subclass";
|
| +}
|
| +
|
| +- (CGFloat)positionForPanelState:(ContextualSearch::PanelState)state {
|
| + return self.positions.byState[state];
|
| +}
|
| +
|
| +- (ContextualSearch::PanelState)panelStateForPosition:(CGFloat)position {
|
| + for (NSInteger i = ContextualSearch::DISMISSED;
|
| + i < ContextualSearch::COVERING; i++) {
|
| + if (position > self.positions.byState[i + 1])
|
| + return static_cast<ContextualSearch::PanelState>(i);
|
| + }
|
| + return ContextualSearch::COVERING;
|
| +}
|
| +
|
| +- (CGFloat)gradationToState:(ContextualSearch::PanelState)toState
|
| + fromState:(ContextualSearch::PanelState)fromState
|
| + atPosition:(CGFloat)position {
|
| + if (toState == fromState)
|
| + return 0;
|
| + CGFloat distance =
|
| + fabs(self.positions.byState[toState] - self.positions.byState[fromState]);
|
| + CGFloat progress = fabs(self.positions.byState[fromState] - position);
|
| + if (fromState > toState)
|
| + progress = distance - progress;
|
| + return progress / distance;
|
| +}
|
| +
|
| +- (NSArray*)constraintsForSizingPanel:(UIView*)panel {
|
| + // Panels in both width classes should be exactly visible on cover mode and
|
| + // horizontally centered in the container view.
|
| + DCHECK(panel.superview != nil);
|
| + NSMutableArray* constraints = [NSMutableArray arrayWithArray:@[
|
| + [panel.heightAnchor
|
| + constraintEqualToAnchor:panel.superview.heightAnchor
|
| + constant:-self.positions
|
| + .byState[ContextualSearch::COVERING]],
|
| + // This technically positions the panel, it doesn't size it.
|
| + [panel.centerXAnchor constraintEqualToAnchor:panel.superview.centerXAnchor],
|
| + ]];
|
| + if (self.horizontalSizeClass == UIUserInterfaceSizeClassCompact) {
|
| + // In a compact layout, the panel is the width of its superview.
|
| + [constraints
|
| + addObject:[panel.widthAnchor
|
| + constraintEqualToAnchor:panel.superview.widthAnchor]];
|
| + } else if (self.horizontalSizeClass == UIUserInterfaceSizeClassRegular) {
|
| + // In a regular layout, the panel width is |kRegularPanelWidthRatio| of its
|
| + // superview.
|
| + [constraints
|
| + addObject:[panel.widthAnchor
|
| + constraintEqualToAnchor:panel.superview.widthAnchor
|
| + multiplier:kRegularPanelWidthRatio]];
|
| + }
|
| + return constraints;
|
| +}
|
| +
|
| +- (NSLayoutConstraint*)
|
| +constraintForPositioningGuide:(UILayoutGuide*)guide
|
| + atState:(ContextualSearch::PanelState)state {
|
| + DCHECK(guide.owningView != nil);
|
| +
|
| + NSLayoutConstraint* positioningConstraint = nil;
|
| + switch (state) {
|
| + case ContextualSearch::DISMISSED:
|
| + positioningConstraint = [guide.heightAnchor
|
| + constraintEqualToAnchor:guide.owningView.heightAnchor];
|
| + break;
|
| + case ContextualSearch::PEEKING:
|
| + positioningConstraint = [guide.heightAnchor
|
| + constraintEqualToAnchor:guide.owningView.heightAnchor
|
| + constant:-self.peekingHeight];
|
| + break;
|
| + case ContextualSearch::PREVIEWING:
|
| + // Previewing height should be provided by a subclass.
|
| + NOTREACHED();
|
| + break;
|
| + case ContextualSearch::COVERING:
|
| + positioningConstraint = [guide.heightAnchor
|
| + constraintEqualToConstant:self.positions
|
| + .byState[ContextualSearch::COVERING]];
|
| + break;
|
| + default:
|
| + positioningConstraint = nil;
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| + return positioningConstraint;
|
| +}
|
| +@end
|
| +
|
| +@implementation PhonePanelConfiguration
|
| +
|
| +- (CGFloat)peekingHeight {
|
| + return kPhonePeekingHeight;
|
| +}
|
| +
|
| +- (void)updatePositions {
|
| + Positions newPositions;
|
| +
|
| + newPositions.byState[ContextualSearch::DISMISSED] = self.containerSize.height;
|
| + newPositions.byState[ContextualSearch::PEEKING] =
|
| + self.containerSize.height - self.peekingHeight;
|
| + newPositions.byState[ContextualSearch::PREVIEWING] =
|
| + self.containerSize.height * kPhonePreviewingDisplayRatio;
|
| + DCHECK(newPositions.byState[ContextualSearch::PREVIEWING] <
|
| + newPositions.byState[ContextualSearch::PEEKING]);
|
| + newPositions.byState[ContextualSearch::COVERING] = kPhoneCoveringHeightOffset;
|
| +
|
| + self.positions = newPositions;
|
| +}
|
| +
|
| +- (NSLayoutConstraint*)
|
| +constraintForPositioningGuide:(UILayoutGuide*)guide
|
| + atState:(ContextualSearch::PanelState)state {
|
| + NSLayoutConstraint* positioningConstraint;
|
| + switch (state) {
|
| + case ContextualSearch::PREVIEWING:
|
| + positioningConstraint = [guide.heightAnchor
|
| + constraintEqualToAnchor:guide.owningView.heightAnchor
|
| + multiplier:kPhonePreviewingDisplayRatio];
|
| + break;
|
| + default:
|
| + positioningConstraint =
|
| + [super constraintForPositioningGuide:guide atState:state];
|
| + break;
|
| + }
|
| + return positioningConstraint;
|
| +}
|
| +
|
| +@end
|
| +
|
| +@implementation PadPanelConfiguration
|
| +
|
| +- (CGFloat)peekingHeight {
|
| + return kPadPeekingHeight;
|
| +}
|
| +
|
| +- (void)updatePositions {
|
| + Positions newPositions;
|
| +
|
| + newPositions.byState[ContextualSearch::DISMISSED] = self.containerSize.height;
|
| + newPositions.byState[ContextualSearch::PEEKING] =
|
| + self.containerSize.height - self.peekingHeight;
|
| + newPositions.byState[ContextualSearch::PREVIEWING] =
|
| + self.containerSize.height * kPadPreviewingDisplayRatio;
|
| + DCHECK(newPositions.byState[ContextualSearch::PREVIEWING] <
|
| + newPositions.byState[ContextualSearch::PEEKING]);
|
| + newPositions.byState[ContextualSearch::COVERING] =
|
| + kPadCoveringHeightOffset + kPadCoveringHeightDecrease;
|
| +
|
| + self.positions = newPositions;
|
| +}
|
| +
|
| +- (NSLayoutConstraint*)
|
| +constraintForPositioningGuide:(UILayoutGuide*)guide
|
| + atState:(ContextualSearch::PanelState)state {
|
| + NSLayoutConstraint* positioningConstraint;
|
| + switch (state) {
|
| + case ContextualSearch::PREVIEWING:
|
| + positioningConstraint = [guide.heightAnchor
|
| + constraintEqualToAnchor:guide.owningView.heightAnchor
|
| + multiplier:kPadPreviewingDisplayRatio];
|
| + break;
|
| + default:
|
| + positioningConstraint =
|
| + [super constraintForPositioningGuide:guide atState:state];
|
| + break;
|
| + }
|
| + return positioningConstraint;
|
| +}
|
| +
|
| +@end
|
|
|