| Index: ios/chrome/browser/ui/ntp/new_tab_page_bar.mm
|
| diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_bar.mm b/ios/chrome/browser/ui/ntp/new_tab_page_bar.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e374a729cdba9502c9733ed8f69460c2797aaf1a
|
| --- /dev/null
|
| +++ b/ios/chrome/browser/ui/ntp/new_tab_page_bar.mm
|
| @@ -0,0 +1,330 @@
|
| +// Copyright 2012 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.
|
| +
|
| +#import "ios/chrome/browser/ui/ntp/new_tab_page_bar.h"
|
| +
|
| +#import <QuartzCore/QuartzCore.h>
|
| +#include <cmath>
|
| +
|
| +#include "base/logging.h"
|
| +#include "base/mac/objc_property_releaser.h"
|
| +#include "base/mac/scoped_nsobject.h"
|
| +#import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
|
| +#import "ios/chrome/browser/ui/ntp/new_tab_page_bar_button.h"
|
| +#import "ios/chrome/browser/ui/ntp/new_tab_page_bar_item.h"
|
| +#import "ios/chrome/browser/ui/rtl_geometry.h"
|
| +#include "ios/chrome/browser/ui/ui_util.h"
|
| +#import "ios/chrome/browser/ui/uikit_ui_util.h"
|
| +#import "ui/gfx/ios/NSString+CrStringDrawing.h"
|
| +#include "ui/gfx/scoped_ui_graphics_push_context_ios.h"
|
| +
|
| +namespace {
|
| +
|
| +const CGFloat kBarHeight = 48.0f;
|
| +
|
| +const CGFloat kRegularLayoutButtonWidth = 168;
|
| +
|
| +const int kOverlayViewColor = 0x5A7EF5;
|
| +const int kOverlayColorWidth = 98;
|
| +const int kNumberOfTabsIncognito = 2;
|
| +
|
| +} // anonymous namespace
|
| +
|
| +@interface NewTabPageBar () {
|
| + base::scoped_nsobject<UIImageView> shadow_;
|
| +}
|
| +
|
| +@property(nonatomic, readwrite, retain) NSArray* buttons;
|
| +@property(nonatomic, readwrite, retain) UIButton* popupButton;
|
| +
|
| +- (void)setup;
|
| +- (void)calculateButtonWidth;
|
| +- (void)setupButton:(UIButton*)button;
|
| +- (BOOL)useIconsInButtons;
|
| +- (BOOL)showOverlay;
|
| +@end
|
| +
|
| +@implementation NewTabPageBar {
|
| + // Tabbar buttons.
|
| + NSArray* buttons_; // UIButton
|
| + NSArray* items_; // NewTabPageBarItem
|
| + // Which button is currently selected.
|
| + NSUInteger selectedIndex_;
|
| + // Popup button helper, for iPhone labels.
|
| + UIButton* popupButton_;
|
| + // Don't allow tabbar animations on startup, only after first tap.
|
| + BOOL canAnimate_;
|
| + id<NewTabPageBarDelegate> delegate_; // weak
|
| + // Logo view, used to center the tab buttons.
|
| + base::scoped_nsobject<UIImageView> logoView_;
|
| + // Overlay view, used to highlight the selected button.
|
| + base::scoped_nsobject<UIImageView> overlayView_;
|
| + // Overlay view, used to highlight the selected button.
|
| + base::scoped_nsobject<UIView> overlayColorView_;
|
| + // Width of a button.
|
| + CGFloat buttonWidth_;
|
| + // Percentage overlay sits over tab bar buttons.
|
| + CGFloat overlayPercentage_;
|
| +
|
| + base::mac::ObjCPropertyReleaser propertyReleaser_NewTabPageBar_;
|
| +}
|
| +
|
| +@synthesize items = items_;
|
| +@synthesize selectedIndex = selectedIndex_;
|
| +@synthesize popupButton = popupButton_;
|
| +@synthesize buttons = buttons_;
|
| +@synthesize delegate = delegate_;
|
| +@synthesize overlayPercentage = overlayPercentage_;
|
| +
|
| +- (id)initWithFrame:(CGRect)frame {
|
| + self = [super initWithFrame:frame];
|
| + if (self) {
|
| + [self setup];
|
| + }
|
| + return self;
|
| +}
|
| +
|
| +- (id)initWithCoder:(NSCoder*)aDecoder {
|
| + self = [super initWithCoder:aDecoder];
|
| + if (self) {
|
| + [self setup];
|
| + }
|
| + return self;
|
| +}
|
| +
|
| +- (void)setup {
|
| + propertyReleaser_NewTabPageBar_.Init(self, [NewTabPageBar class]);
|
| + self.selectedIndex = NSNotFound;
|
| + canAnimate_ = NO;
|
| + self.autoresizingMask =
|
| + UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;
|
| + self.autoresizesSubviews = YES;
|
| + self.backgroundColor = [UIColor clearColor];
|
| +
|
| + if ([self showOverlay]) {
|
| + overlayView_.reset(
|
| + [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, buttonWidth_, 2)]);
|
| +
|
| + // Center |overlayColorView_| inside |overlayView_|.
|
| + CGFloat colorX = AlignValueToPixel((buttonWidth_ - kOverlayColorWidth) / 2);
|
| + overlayColorView_.reset([[UIView alloc]
|
| + initWithFrame:CGRectMake(colorX, 0, kOverlayColorWidth, 2)]);
|
| + [overlayColorView_
|
| + setBackgroundColor:UIColorFromRGB(kOverlayViewColor, 1.0)];
|
| + [overlayColorView_ layer].cornerRadius = 1.0;
|
| + [overlayColorView_
|
| + setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin |
|
| + UIViewAutoresizingFlexibleRightMargin];
|
| + [overlayView_ addSubview:overlayColorView_];
|
| + [self addSubview:overlayView_];
|
| + }
|
| +
|
| + // Make the drop shadow.
|
| + UIImage* shadowImage = [UIImage imageNamed:@"ntp_bottom_bar_shadow"];
|
| + shadow_.reset([[UIImageView alloc] initWithImage:shadowImage]);
|
| + // Shadow is positioned directly above the new tab page bar.
|
| + [shadow_
|
| + setFrame:CGRectMake(0, -shadowImage.size.height, self.bounds.size.width,
|
| + shadowImage.size.height)];
|
| + [shadow_ setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
|
| + [self addSubview:shadow_];
|
| +
|
| + self.contentMode = UIViewContentModeRedraw;
|
| +}
|
| +
|
| +- (void)layoutSubviews {
|
| + [super layoutSubviews];
|
| +
|
| + // |buttonWidth_| changes with the screen orientation when the NTP button bar
|
| + // is enabled.
|
| + [self calculateButtonWidth];
|
| +
|
| + CGFloat logoWidth = logoView_.get().image.size.width;
|
| + CGFloat padding = [self useIconsInButtons] ? logoWidth : 0;
|
| + CGFloat buttonPadding = floor((CGRectGetWidth(self.bounds) - padding -
|
| + (buttonWidth_ * self.buttons.count) / 2) +
|
| + padding);
|
| +
|
| + for (NSUInteger i = 0; i < self.buttons.count; ++i) {
|
| + NewTabPageBarButton* button = [self.buttons objectAtIndex:i];
|
| + LayoutRect layout = LayoutRectMake(
|
| + buttonPadding + (i * buttonWidth_), CGRectGetWidth(self.bounds), 0,
|
| + buttonWidth_, CGRectGetHeight(self.bounds));
|
| + button.frame = LayoutRectGetRect(layout);
|
| + [button
|
| + setContentToDisplay:[self useIconsInButtons]
|
| + ? new_tab_page_bar_button::ContentType::IMAGE
|
| + : new_tab_page_bar_button::ContentType::TEXT];
|
| + }
|
| +
|
| + // Position overlay image over percentage of tab bar button(s).
|
| + CGRect frame = [overlayView_ frame];
|
| + frame.origin.x = floor(
|
| + buttonWidth_ * self.buttons.count * overlayPercentage_ + buttonPadding);
|
| + frame.size.width = buttonWidth_;
|
| + DCHECK(!std::isnan(frame.origin.x));
|
| + DCHECK(!std::isnan(frame.size.width));
|
| + [overlayView_ setFrame:frame];
|
| +}
|
| +
|
| +- (CGSize)sizeThatFits:(CGSize)size {
|
| + return CGSizeMake(size.width, kBarHeight);
|
| +}
|
| +
|
| +- (void)calculateButtonWidth {
|
| + if ([self useIconsInButtons]) {
|
| + if ([items_ count] > 0) {
|
| + buttonWidth_ = self.bounds.size.width / [items_ count];
|
| + } else {
|
| + // In incognito on phones, there are no items shown.
|
| + buttonWidth_ = 0;
|
| + }
|
| + return;
|
| + }
|
| +
|
| + buttonWidth_ = kRegularLayoutButtonWidth;
|
| +}
|
| +
|
| +// When setting a new set of items on the tab bar, the buttons need to be
|
| +// regenerated and the old buttons need to be removed.
|
| +- (void)setItems:(NSArray*)newItems {
|
| + if (newItems == items_)
|
| + return;
|
| +
|
| + [items_ autorelease];
|
| + items_ = [newItems retain];
|
| + // Remove all the existing buttons from the view.
|
| + for (UIButton* button in self.buttons) {
|
| + [button removeFromSuperview];
|
| + }
|
| +
|
| + // Create a set of new buttons.
|
| + [self calculateButtonWidth];
|
| + if (newItems.count) {
|
| + NSMutableArray* newButtons = [NSMutableArray array];
|
| + for (NSUInteger i = 0; i < newItems.count; ++i) {
|
| + NewTabPageBarItem* item = [newItems objectAtIndex:i];
|
| + NewTabPageBarButton* button = [NewTabPageBarButton buttonWithItem:item];
|
| + button.frame = CGRectIntegral(CGRectMake(
|
| + i * buttonWidth_, 0, buttonWidth_, self.bounds.size.height));
|
| + [self setupButton:button];
|
| + [self addSubview:button];
|
| + [newButtons addObject:button];
|
| + }
|
| + self.buttons = newButtons;
|
| + } else {
|
| + self.buttons = nil;
|
| + }
|
| + [self setNeedsLayout];
|
| +}
|
| +
|
| +- (void)setOverlayPercentage:(CGFloat)overlayPercentage {
|
| + DCHECK(!std::isnan(overlayPercentage));
|
| + overlayPercentage_ = overlayPercentage;
|
| + [self setNeedsLayout];
|
| +}
|
| +
|
| +- (void)setupButton:(UIButton*)button {
|
| + // Old NTP tab bar buttons have a non-standard control event for firing
|
| + // actions. Because they are tied to a scrollView that reacts immediately,
|
| + // and on phone there is a tooltip that fires on touchdown that needs to
|
| + // display while on the new tab, the control event for -buttonDidTap is touch
|
| + // down. On phone with dialogs enabled, treat the NTP buttons as normal
|
| + // buttons, where the standard is to fire an action on touch up inside.
|
| + if ([self showOverlay]) {
|
| + [button addTarget:self
|
| + action:@selector(buttonDidTap:)
|
| + forControlEvents:UIControlEventTouchDown];
|
| + } else {
|
| + [button addTarget:self
|
| + action:@selector(buttonDidTap:)
|
| + forControlEvents:UIControlEventTouchUpInside];
|
| + }
|
| +}
|
| +
|
| +- (void)setSelectedIndex:(NSUInteger)newIndex {
|
| + // When not showing the overlay, the Bookmarks and Recent Tabs are displayed
|
| + // in modal view controllers, so the tab bar buttons should not be selected.
|
| + if (![self showOverlay])
|
| + return;
|
| + if (newIndex != self.selectedIndex) {
|
| + if (newIndex < self.items.count) {
|
| + for (NSUInteger i = 0; i < self.buttons.count; ++i) {
|
| + UIButton* button = [self.buttons objectAtIndex:i];
|
| + button.selected = (i == newIndex);
|
| + }
|
| + }
|
| + selectedIndex_ = newIndex;
|
| + }
|
| +}
|
| +
|
| +- (void)buttonDidTap:(UIButton*)button {
|
| + canAnimate_ = YES;
|
| + NSUInteger buttonIndex = [self.buttons indexOfObject:button];
|
| + if (buttonIndex != NSNotFound) {
|
| + self.selectedIndex = buttonIndex;
|
| + [delegate_ newTabBarItemDidChange:[self.items objectAtIndex:buttonIndex]
|
| + changePanel:YES];
|
| + }
|
| +}
|
| +
|
| +- (void)setShadowAlpha:(CGFloat)alpha {
|
| + CGFloat currentAlpha = [shadow_ alpha];
|
| + CGFloat diff = std::abs(alpha - currentAlpha);
|
| + if (diff >= 1) {
|
| + [UIView animateWithDuration:0.3
|
| + animations:^{
|
| + [shadow_ setAlpha:alpha];
|
| + }];
|
| + } else {
|
| + [shadow_ setAlpha:alpha];
|
| + }
|
| +}
|
| +
|
| +- (void)updateColorsForScrollView:(UIScrollView*)scrollView {
|
| + if (![self showOverlay]) {
|
| + return;
|
| + }
|
| +
|
| + UIColor* backgroundViewColorBookmarks = [UIColor whiteColor];
|
| + CGFloat viewWidth = self.bounds.size.width;
|
| + CGFloat progress = LeadingContentOffsetForScrollView(scrollView) / viewWidth;
|
| + progress = fminf(progress, 1.0f);
|
| + progress = fmaxf(progress, 0.0f);
|
| +
|
| + if ([self.items count] == kNumberOfTabsIncognito) {
|
| + UIColor* overlayViewColor = UIColorFromRGB(kOverlayViewColor, 1.0);
|
| + UIColor* overlayViewColorIncognito = [UIColor whiteColor];
|
| + UIColor* updatedOverlayColor = InterpolateFromColorToColor(
|
| + overlayViewColor, overlayViewColorIncognito, progress);
|
| + [overlayColorView_ setBackgroundColor:updatedOverlayColor];
|
| +
|
| + UIColor* backgroundViewColorIncognito =
|
| + [UIColor colorWithWhite:34 / 255.0 alpha:1.0];
|
| + UIColor* backgroundColor = InterpolateFromColorToColor(
|
| + backgroundViewColorBookmarks, backgroundViewColorIncognito, progress);
|
| + self.backgroundColor = backgroundColor;
|
| + scrollView.backgroundColor = backgroundColor;
|
| +
|
| + for (NewTabPageBarButton* button in self.buttons) {
|
| + [button useIncognitoColorScheme:progress];
|
| + }
|
| + } else {
|
| + UIColor* backgroundColor = backgroundViewColorBookmarks;
|
| + self.backgroundColor = backgroundViewColorBookmarks;
|
| + scrollView.backgroundColor = backgroundColor;
|
| + }
|
| +}
|
| +
|
| +- (BOOL)useIconsInButtons {
|
| + return !IsIPadIdiom() || IsCompactTablet();
|
| +}
|
| +
|
| +- (BOOL)showOverlay {
|
| + // The bar buttons launch modal dialogs on tap on iPhone. Don't show overlay
|
| + // in this case.
|
| + return IsIPadIdiom();
|
| +}
|
| +
|
| +@end
|
|
|