Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(423)

Unified Diff: ios/chrome/browser/ui/tabs/tab_view.mm

Issue 2588733002: Upstream Chrome on iOS source code [9/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ios/chrome/browser/ui/tabs/tab_view.h ('k') | ios/chrome/browser/ui/tabs/target_frame_cache.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ios/chrome/browser/ui/tabs/tab_view.mm
diff --git a/ios/chrome/browser/ui/tabs/tab_view.mm b/ios/chrome/browser/ui/tabs/tab_view.mm
new file mode 100644
index 0000000000000000000000000000000000000000..2b27e3b2a20f3bcc2d80fe85a1e6aff05e108d7d
--- /dev/null
+++ b/ios/chrome/browser/ui/tabs/tab_view.mm
@@ -0,0 +1,380 @@
+
+// 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/tabs/tab_view.h"
+
+#include "base/i18n/rtl.h"
+#include "base/ios/ios_util.h"
+#include "base/logging.h"
+#include "base/mac/objc_property_releaser.h"
+#include "base/strings/sys_string_conversions.h"
+#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
+#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
+#import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
+#import "ios/chrome/browser/ui/image_util.h"
+#include "ios/chrome/browser/ui/rtl_geometry.h"
+#include "ios/chrome/browser/ui/tabs/tab_util.h"
+#include "ios/chrome/browser/ui/ui_util.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
+#include "ios/chrome/grit/ios_strings.h"
+#import "ios/third_party/material_components_ios/src/components/ActivityIndicator/src/MaterialActivityIndicator.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
+#include "third_party/google_toolbox_for_mac/src/iPhone/GTMFadeTruncatingLabel.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/l10n_util_mac.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image.h"
+#import "ui/gfx/ios/uikit_util.h"
+
+namespace {
+
+// Tab close button insets.
+const CGFloat kTabCloseTopInset = -1.0;
+const CGFloat kTabCloseLeftInset = 0.0;
+const CGFloat kTabCloseBottomInset = 0.0;
+const CGFloat kTabCloseRightInset = 0.0;
+const CGFloat kTabBackgroundLeftCapInset = 24.0;
+const CGFloat kFaviconLeftInset = 23.5;
+const CGFloat kFaviconVerticalOffset = 2.0;
+const CGFloat kTabStripLineMargin = 2.5;
+const CGFloat kTabStripLineHeight = 0.5;
+const CGFloat kCloseButtonHorizontalShift = 15;
+const CGFloat kCloseButtonVerticalShift = 4.0;
+const CGFloat kTitleLeftMargin = 8.0;
+const CGFloat kTitleRightMargin = 0.0;
+
+const CGFloat kCloseButtonSize = 24.0;
+const CGFloat kFaviconSize = 16.0;
+}
+
+@interface TabView () {
+ // Close button for this tab.
+ UIButton* _closeButton;
+
+ // View that draws the tab title.
+ GTMFadeTruncatingLabel* _titleLabel;
+
+ // Background image for this tab.
+ base::scoped_nsobject<UIImageView> _backgroundImageView;
+ // This view is used to draw a separator line at the bottom of the tab view.
+ // This view is hidden when the tab view is in a selected state.
+ base::scoped_nsobject<UIView> _lineSeparator;
+ BOOL _incognitoStyle;
+
+ // Set to YES when the layout constraints have been initialized.
+ BOOL _layoutConstraintsInitialized;
+
+ // Image view used to draw the favicon and spinner.
+ base::scoped_nsobject<UIImageView> _faviconView;
+
+ // If |YES|, this view will adjust its appearance and draw as a collapsed tab.
+ BOOL _collapsed;
+
+ base::scoped_nsobject<MDCActivityIndicator> _activityIndicator;
+
+ base::mac::ObjCPropertyReleaser _propertyReleaser_TabView;
+}
+@end
+
+@interface TabView (Private)
+
+// Creates the close button, favicon button, and title.
+- (void)createButtonsAndLabel;
+
+// Updates this tab's line separator color based on the current incognito style.
+- (void)updateLineSeparator;
+
+// Updates this tab's background image based on the value of |selected|.
+- (void)updateBackgroundImage:(BOOL)selected;
+
+// Updates this tab's close button image based on the current incognito style.
+- (void)updateCloseButtonImages;
+
+// Return the default favicon image based on the current incognito style.
+- (UIImage*)defaultFaviconImage;
+
+// Returns the rect in which to draw the favicon.
+- (CGRect)faviconRectForBounds:(CGRect)bounds;
+
+// Returns the rect in which to draw the tab title.
+- (CGRect)titleRectForBounds:(CGRect)bounds;
+
+// Returns the frame rect for the close button.
+- (CGRect)closeRectForBounds:(CGRect)bounds;
+
+@end
+
+@implementation TabView
+
+@synthesize closeButton = _closeButton;
+@synthesize titleLabel = _titleLabel;
+@synthesize collapsed = _collapsed;
+@synthesize background = background_;
+@synthesize incognitoStyle = _incognitoStyle;
+
+- (id)initWithEmptyView:(BOOL)emptyView selected:(BOOL)selected {
+ if ((self = [super initWithFrame:CGRectZero])) {
+ _propertyReleaser_TabView.Init(self, [TabView class]);
+ [self setOpaque:NO];
+ [self createCommonViews];
+ // -setSelected only calls -updateBackgroundImage if the selected state
+ // changes. |isSelected| defaults to NO, so if |selected| is also NO,
+ // -updateBackgroundImage needs to be called explicitly.
+ [self setSelected:selected];
+ [self updateLineSeparator];
+ [self updateBackgroundImage:selected];
+ if (!emptyView)
+ [self createButtonsAndLabel];
+ }
+ return self;
+}
+
+- (void)setSelected:(BOOL)selected {
+ BOOL wasSelected = [self isSelected];
+ [super setSelected:selected];
+
+ [_lineSeparator setHidden:selected];
+
+ if (selected != wasSelected)
+ [self updateBackgroundImage:selected];
+
+ // It would make more sense to set active/inactive on tab_view itself, but
+ // tab_view is not an an accessible element, and making it one would add
+ // several complicated layers to UIA. Instead, simply set active/inactive
+ // here to be used by UIA.
+ [_closeButton setAccessibilityValue:(selected ? @"active" : @"inactive")];
+}
+
+- (void)setCollapsed:(BOOL)collapsed {
+ if (_collapsed != collapsed)
+ [_closeButton setHidden:collapsed];
+
+ _collapsed = collapsed;
+}
+
+- (void)setTitle:(NSString*)title {
+ if ([_titleLabel.text isEqualToString:title])
+ return;
+ if (base::i18n::GetStringDirection(base::SysNSStringToUTF16(title)) ==
+ base::i18n::RIGHT_TO_LEFT) {
+ [_titleLabel setTruncateMode:GTMFadeTruncatingHead];
+ } else {
+ [_titleLabel setTruncateMode:GTMFadeTruncatingTail];
+ }
+ _titleLabel.text = title;
+}
+
+- (UIImage*)favicon {
+ return [_faviconView image];
+}
+
+- (void)setFavicon:(UIImage*)favicon {
+ if (!favicon)
+ favicon = [self defaultFaviconImage];
+ [_faviconView setImage:favicon];
+}
+
+- (void)setIncognitoStyle:(BOOL)incognitoStyle {
+ _incognitoStyle = incognitoStyle;
+ _titleLabel.textColor =
+ incognitoStyle ? [UIColor whiteColor] : [UIColor blackColor];
+ [_faviconView setImage:[self defaultFaviconImage]];
+ [self updateLineSeparator];
+ [self updateCloseButtonImages];
+ [self updateBackgroundImage:[self isSelected]];
+}
+
+- (void)startProgressSpinner {
+ [_activityIndicator startAnimating];
+ [_activityIndicator setHidden:NO];
+ [_faviconView setHidden:YES];
+}
+
+- (void)stopProgressSpinner {
+ [_activityIndicator stopAnimating];
+ [_activityIndicator setHidden:YES];
+ [_faviconView setHidden:NO];
+}
+
+#pragma mark - UIView overrides
+
+- (void)setFrame:(CGRect)frame {
+ const CGRect previousFrame = [self frame];
+ [super setFrame:frame];
+ // We are checking for a zero frame before triggering constraints updates in
+ // order to prevent computation of constraints that will never be used for the
+ // final layout. We could also initialize with a dummy frame but first this is
+ // inefficient and second it's non trivial to compute the minimum valid frame
+ // in regard to tweakable constants.
+ if (CGRectEqualToRect(CGRectZero, previousFrame) &&
+ !_layoutConstraintsInitialized) {
+ [self setNeedsUpdateConstraints];
+ }
+}
+
+- (void)updateConstraints {
+ [super updateConstraints];
+ if (!_layoutConstraintsInitialized &&
+ !CGRectEqualToRect(CGRectZero, self.frame)) {
+ _layoutConstraintsInitialized = YES;
+ [self addCommonConstraints];
+ // Add buttons and labels constraints if needed.
+ if (_closeButton)
+ [self addButtonsAndLabelConstraints];
+ }
+}
+
+- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event {
+ // Account for the trapezoidal shape of the tab. Inset the tab bounds by
+ // (y = -2.2x + 56), determined empirically from looking at the tab background
+ // images.
+ CGFloat inset = MAX(0.0, (point.y - 56) / -2.2);
+ return CGRectContainsPoint(CGRectInset([self bounds], inset, 0), point);
+}
+
+#pragma mark - Private
+
+- (void)createCommonViews {
+ _backgroundImageView.reset([[UIImageView alloc] init]);
+ [_backgroundImageView setTranslatesAutoresizingMaskIntoConstraints:NO];
+ [self addSubview:_backgroundImageView];
+
+ _lineSeparator.reset([[UIView alloc] initWithFrame:CGRectZero]);
+ [_lineSeparator setTranslatesAutoresizingMaskIntoConstraints:NO];
+ [self addSubview:_lineSeparator];
+}
+
+- (void)addCommonConstraints {
+ NSDictionary* commonViewsDictionary = @{
+ @"backgroundImageView" : _backgroundImageView.get(),
+ @"lineSeparator" : _lineSeparator.get()
+ };
+ NSArray* commonConstraints = @[
+ @"H:|-0-[backgroundImageView]-0-|",
+ @"V:|-0-[backgroundImageView]-0-|",
+ @"H:|-tabStripLineMargin-[lineSeparator]-tabStripLineMargin-|",
+ @"V:[lineSeparator(==tabStripLineHeight)]-0-|",
+ ];
+ NSDictionary* commonMetrics = @{
+ @"tabStripLineMargin" : @(kTabStripLineMargin),
+ @"tabStripLineHeight" : @(kTabStripLineHeight)
+ };
+ ApplyVisualConstraintsWithMetrics(commonConstraints, commonViewsDictionary,
+ commonMetrics, self);
+}
+
+- (void)createButtonsAndLabel {
+ _closeButton = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
+ [_closeButton setTranslatesAutoresizingMaskIntoConstraints:NO];
+ [_closeButton setImage:[UIImage imageNamed:@"tabstrip_tab_close"]
+ forState:UIControlStateNormal];
+ [_closeButton setImage:[UIImage imageNamed:@"tabstrip_tab_close_pressed"]
+ forState:UIControlStateHighlighted];
+ [_closeButton setContentEdgeInsets:UIEdgeInsetsMake(kTabCloseTopInset,
+ kTabCloseLeftInset,
+ kTabCloseBottomInset,
+ kTabCloseRightInset)];
+ [_closeButton setAccessibilityLabel:l10n_util::GetNSString(
+ IDS_IOS_TOOLS_MENU_CLOSE_TAB)];
+ [self addSubview:_closeButton];
+
+ // Add fade truncating label.
+ _titleLabel = [[GTMFadeTruncatingLabel alloc] initWithFrame:CGRectZero];
+ [_titleLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
+ [_titleLabel setFont:[MDCTypography body1Font]];
+ // Setting NSLineBreakByCharWrapping fixes an issue where the beginning of the
+ // text is truncated for RTL text writing direction. Anyway since the label is
+ // only one line and the end of the text is faded behind a gradient mask, it
+ // is visually almost equivalent to NSLineBreakByClipping.
+ [_titleLabel setLineBreakMode:NSLineBreakByCharWrapping];
+
+ [_titleLabel setTextAlignment:NSTextAlignmentNatural];
+ [self addSubview:_titleLabel];
+
+ CGRect faviconFrame = CGRectMake(0, 0, kFaviconSize, kFaviconSize);
+ _faviconView.reset([[UIImageView alloc] initWithFrame:faviconFrame]);
+ [_faviconView setTranslatesAutoresizingMaskIntoConstraints:NO];
+ [_faviconView setContentMode:UIViewContentModeScaleAspectFit];
+ [_faviconView setImage:[self defaultFaviconImage]];
+ [_faviconView setAccessibilityIdentifier:@"Favicon"];
+ [self addSubview:_faviconView];
+
+ _activityIndicator.reset(
+ [[MDCActivityIndicator alloc] initWithFrame:faviconFrame]);
+ [_activityIndicator setTranslatesAutoresizingMaskIntoConstraints:NO];
+ [_activityIndicator
+ setCycleColors:@[ [[MDCPalette cr_bluePalette] tint500] ]];
+ [_activityIndicator setRadius:ui::AlignValueToUpperPixel(kFaviconSize / 2)];
+ [self addSubview:_activityIndicator];
+}
+
+- (void)addButtonsAndLabelConstraints {
+ // Constraints on the Top bar, snapshot view, and shadow view.
+ NSDictionary* viewsDictionary = @{
+ @"close" : _closeButton,
+ @"title" : _titleLabel,
+ @"favicon" : _faviconView,
+ };
+ NSArray* constraints = @[
+ @"H:|-faviconLeftInset-[favicon(faviconSize)]",
+ @"V:|-faviconVerticalOffset-[favicon]-0-|",
+ @"H:[close(==closeButtonSize)]-closeButtonHorizontalShift-|",
+ @"V:|-closeButtonVerticalShift-[close]-0-|",
+ @"H:[favicon]-titleLeftMargin-[title]-titleRightMargin-[close]",
+ @"V:[title(==titleHeight)]",
+ ];
+ NSDictionary* metrics = @{
+ @"closeButtonSize" : @(kCloseButtonSize),
+ @"closeButtonHorizontalShift" : @(kCloseButtonHorizontalShift),
+ @"closeButtonVerticalShift" : @(kCloseButtonVerticalShift),
+ @"titleLeftMargin" : @(kTitleLeftMargin),
+ @"titleRightMargin" : @(kTitleRightMargin),
+ @"titleHeight" : @(kFaviconSize),
+ @"faviconLeftInset" : @(AlignValueToPixel(kFaviconLeftInset)),
+ @"faviconVerticalOffset" : @(kFaviconVerticalOffset),
+ @"faviconSize" : @(kFaviconSize),
+ };
+ ApplyVisualConstraintsWithMetrics(constraints, viewsDictionary, metrics,
+ self);
+ AddSameCenterXConstraint(self, _faviconView, _activityIndicator);
+ AddSameCenterYConstraint(self, _faviconView, _activityIndicator);
+ AddSameCenterYConstraint(self, _faviconView, _titleLabel);
+}
+
+- (void)updateLineSeparator {
+ UIColor* separatorColor =
+ _incognitoStyle ? [UIColor colorWithWhite:36 / 255.0 alpha:1.0]
+ : [UIColor colorWithWhite:185 / 255.0 alpha:1.0];
+ [_lineSeparator setBackgroundColor:separatorColor];
+}
+
+- (void)updateBackgroundImage:(BOOL)selected {
+ NSString* state = (selected ? @"foreground" : @"background");
+ NSString* incognito = _incognitoStyle ? @"incognito_" : @"";
+ NSString* imageName =
+ [NSString stringWithFormat:@"tabstrip_%@%@_tab", incognito, state];
+ UIImage* backgroundImage = StretchableImageFromUIImage(
+ [UIImage imageNamed:imageName], kTabBackgroundLeftCapInset, 0);
+ [_backgroundImageView setImage:backgroundImage];
+}
+
+- (void)updateCloseButtonImages {
+ UIImage* normalImage =
+ self.incognitoStyle ? [UIImage imageNamed:@"tabstrip_tab_close_incognito"]
+ : [UIImage imageNamed:@"tabstrip_tab_close"];
+ UIImage* pressedImage =
+ self.incognitoStyle
+ ? [UIImage imageNamed:@"tabstrip_tab_close_incognito_pressed"]
+ : [UIImage imageNamed:@"tabstrip_tab_close_pressed"];
+ [_closeButton setImage:normalImage forState:UIControlStateNormal];
+ [_closeButton setImage:pressedImage forState:UIControlStateHighlighted];
+}
+
+- (UIImage*)defaultFaviconImage {
+ return self.incognitoStyle ? [UIImage imageNamed:@"default_favicon_incognito"]
+ : [UIImage imageNamed:@"default_favicon"];
+}
+
+@end
« no previous file with comments | « ios/chrome/browser/ui/tabs/tab_view.h ('k') | ios/chrome/browser/ui/tabs/target_frame_cache.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698