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

Side by Side Diff: chrome/browser/ui/cocoa/tabs/tab_controller.mm

Issue 2488833002: [Mac] Reverse tabs in RTL mode (Closed)
Patch Set: Created 4 years, 1 month 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "chrome/browser/ui/cocoa/tabs/tab_controller.h" 5 #import "chrome/browser/ui/cocoa/tabs/tab_controller.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cmath> 8 #include <cmath>
9 9
10 #include "base/i18n/rtl.h" 10 #include "base/i18n/rtl.h"
11 #include "base/mac/bundle_locations.h" 11 #include "base/mac/bundle_locations.h"
12 #import "chrome/browser/themes/theme_properties.h" 12 #import "chrome/browser/themes/theme_properties.h"
13 #import "chrome/browser/themes/theme_service.h" 13 #import "chrome/browser/themes/theme_service.h"
14 #include "chrome/browser/ui/cocoa/l10n_util.h"
14 #import "chrome/browser/ui/cocoa/sprite_view.h" 15 #import "chrome/browser/ui/cocoa/sprite_view.h"
15 #import "chrome/browser/ui/cocoa/tabs/alert_indicator_button_cocoa.h" 16 #import "chrome/browser/ui/cocoa/tabs/alert_indicator_button_cocoa.h"
16 #import "chrome/browser/ui/cocoa/tabs/tab_controller_target.h" 17 #import "chrome/browser/ui/cocoa/tabs/tab_controller_target.h"
17 #import "chrome/browser/ui/cocoa/tabs/tab_view.h" 18 #import "chrome/browser/ui/cocoa/tabs/tab_view.h"
18 #import "chrome/browser/ui/cocoa/themed_window.h" 19 #import "chrome/browser/ui/cocoa/themed_window.h"
19 #include "content/public/browser/user_metrics.h" 20 #include "content/public/browser/user_metrics.h"
20 #import "extensions/common/extension.h" 21 #import "extensions/common/extension.h"
21 #import "ui/base/cocoa/menu_controller.h" 22 #import "ui/base/cocoa/menu_controller.h"
22 #include "ui/base/material_design/material_design_controller.h" 23 #include "ui/base/material_design/material_design_controller.h"
23 24
(...skipping 29 matching lines...) Expand all
53 [target_ commandDispatch:command forController:owner_]; 54 [target_ commandDispatch:command forController:owner_];
54 } 55 }
55 56
56 private: 57 private:
57 id<TabControllerTarget> target_; // weak 58 id<TabControllerTarget> target_; // weak
58 TabController* owner_; // weak, owns me 59 TabController* owner_; // weak, owns me
59 }; 60 };
60 61
61 } // TabControllerInternal namespace 62 } // TabControllerInternal namespace
62 63
64 namespace {
65 static const CGFloat kTabLeadingPadding = 18;
66 static const CGFloat kTabTrailingPadding = 15;
67 static const CGFloat kIconSize = 16;
68 static const CGFloat kCloseButtonSize = 16;
69 static const CGFloat kInitialTabWidth = 160;
70 static const CGFloat kTitleLeadingPadding = 4;
71 static const CGFloat kInitialTitleWidth = 92;
72 static const CGFloat kTabElementYOrigin = 6;
73 } // namespace
74
63 + (CGFloat)defaultTabHeight { 75 + (CGFloat)defaultTabHeight {
64 return 29; 76 return 29;
65 } 77 }
66 78
67 // The min widths is the smallest number at which the right edge of the right 79 // The min widths is the smallest number at which the right edge of the right
68 // tab border image is not visibly clipped. It is a bit smaller than the sum 80 // tab border image is not visibly clipped. It is a bit smaller than the sum
69 // of the two tab edge bitmaps because these bitmaps have a few transparent 81 // of the two tab edge bitmaps because these bitmaps have a few transparent
70 // pixels on the side. The selected tab width includes the close button width. 82 // pixels on the side. The selected tab width includes the close button width.
71 + (CGFloat)minTabWidth { return 36; } 83 + (CGFloat)minTabWidth { return 36; }
72 + (CGFloat)minActiveTabWidth { return 52; } 84 + (CGFloat)minActiveTabWidth { return 52; }
73 + (CGFloat)maxTabWidth { return 246; } 85 + (CGFloat)maxTabWidth { return 246; }
74 86
75 + (CGFloat)pinnedTabWidth { return 58; } 87 + (CGFloat)pinnedTabWidth { return 58; }
76 88
77 - (TabView*)tabView { 89 - (TabView*)tabView {
78 DCHECK([[self view] isKindOfClass:[TabView class]]); 90 DCHECK([[self view] isKindOfClass:[TabView class]]);
79 return static_cast<TabView*>([self view]); 91 return static_cast<TabView*>([self view]);
80 } 92 }
81 93
82 - (id)init { 94 - (id)init {
83 if ((self = [super init])) { 95 if ((self = [super init])) {
96 BOOL isRTL = cocoa_l10n_util::ShouldDoExperimentalRTLLayout();
84 // Icon. 97 // Icon.
85 // Remember the icon's frame, so that if the icon is ever removed, a new 98 const CGFloat iconOrigin =
86 // one can later replace it in the proper location. 99 isRTL ? kInitialTabWidth - kTabLeadingPadding - kIconSize
87 originalIconFrame_ = NSMakeRect(18, 6, 16, 16); 100 : kTabLeadingPadding;
88 iconView_.reset([[SpriteView alloc] initWithFrame:originalIconFrame_]); 101 NSRect iconFrame =
89 [iconView_ setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin]; 102 NSMakeRect(iconOrigin, kTabElementYOrigin, kIconSize, kIconSize);
103 iconView_.reset([[SpriteView alloc] initWithFrame:iconFrame]);
104 [iconView_ setAutoresizingMask:isRTL ? NSViewMinXMargin
105 : NSViewMaxXMargin | NSViewMinYMargin];
90 106
91 // When the icon is removed, the title expands to the left to fill the 107 const CGFloat titleOrigin =
92 // space left by the icon. When the close button is removed, the title 108 isRTL
93 // expands to the right to fill its space. These are the amounts to expand 109 ? NSMinX([iconView_ frame]) - kTitleLeadingPadding -
94 // and contract the title frame under those conditions. We don't have to 110 kInitialTitleWidth
95 // explicilty save the offset between the title and the close button since 111 : NSMaxX([iconView_ frame]) + kTitleLeadingPadding;
96 // we can just get that value for the close button's frame. 112 NSRect titleFrame =
97 NSRect titleFrame = NSMakeRect(35, 6, 92, 17); 113 NSMakeRect(titleOrigin, kTabElementYOrigin, kInitialTitleWidth, 17);
98 114
99 // Close button. 115 // Close button.
100 NSRect closeButtonFrame = NSMakeRect(129, 6, 16, 16); 116 const CGFloat closeButtonOrigin =
117 isRTL ? kTabTrailingPadding
118 : kInitialTabWidth - kCloseButtonSize - kTabTrailingPadding;
119 NSRect closeButtonFrame = NSMakeRect(closeButtonOrigin, kTabElementYOrigin,
120 kCloseButtonSize, kCloseButtonSize);
101 closeButton_.reset([[HoverCloseButton alloc] initWithFrame: 121 closeButton_.reset([[HoverCloseButton alloc] initWithFrame:
102 closeButtonFrame]); 122 closeButtonFrame]);
103 [closeButton_ setAutoresizingMask:NSViewMinXMargin]; 123 [closeButton_ setAutoresizingMask:isRTL
124 ? NSViewMaxXMargin | NSViewMinYMargin
Nico 2016/11/09 15:27:34 why is the y autoresizing mask different in rtl mo
lgrey 2016/11/09 15:48:51 It doesn't. I decided (kind of arbitrarily), to fl
Nico 2016/11/09 15:52:29 No.
125 : NSViewMinXMargin];
104 [closeButton_ setTarget:self]; 126 [closeButton_ setTarget:self];
105 [closeButton_ setAction:@selector(closeTab:)]; 127 [closeButton_ setAction:@selector(closeTab:)];
106 128
107 base::scoped_nsobject<TabView> view([[TabView alloc] 129 base::scoped_nsobject<TabView> view([[TabView alloc]
108 initWithFrame:NSMakeRect(0, 0, 160, [TabController defaultTabHeight]) 130 initWithFrame:NSMakeRect(0, 0, kInitialTabWidth,
131 [TabController defaultTabHeight])
109 controller:self 132 controller:self
110 closeButton:closeButton_]); 133 closeButton:closeButton_]);
111 [view setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin]; 134 [view setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
112 [view setPostsFrameChangedNotifications:NO]; 135 [view setPostsFrameChangedNotifications:NO];
113 [view setPostsBoundsChangedNotifications:NO]; 136 [view setPostsBoundsChangedNotifications:NO];
114 [view addSubview:iconView_]; 137 [view addSubview:iconView_];
115 [view addSubview:closeButton_]; 138 [view addSubview:closeButton_];
116 [view setTitleFrame:titleFrame]; 139 [view setTitleFrame:titleFrame];
117 [super setView:view]; 140 [super setView:view];
118 141
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
277 } 300 }
278 301
279 - (void)setToolTip:(NSString*)toolTip { 302 - (void)setToolTip:(NSString*)toolTip {
280 [[self tabView] setToolTipText:toolTip]; 303 [[self tabView] setToolTipText:toolTip];
281 } 304 }
282 305
283 // Return a rough approximation of the number of icons we could fit in the 306 // Return a rough approximation of the number of icons we could fit in the
284 // tab. We never actually do this, but it's a helpful guide for determining 307 // tab. We never actually do this, but it's a helpful guide for determining
285 // how much space we have available. 308 // how much space we have available.
286 - (int)iconCapacity { 309 - (int)iconCapacity {
287 const CGFloat availableWidth = std::max<CGFloat>( 310 const CGFloat availableWidth =
288 0, NSMaxX([closeButton_ frame]) - NSMinX(originalIconFrame_)); 311 std::max<CGFloat>(0, NSWidth([[self tabView] frame]) -
289 const CGFloat widthPerIcon = NSWidth(originalIconFrame_); 312 kTabLeadingPadding - kTabTrailingPadding);
313 const CGFloat widthPerIcon = kIconSize;
290 const int kPaddingBetweenIcons = 2; 314 const int kPaddingBetweenIcons = 2;
291 if (availableWidth >= widthPerIcon && 315 if (availableWidth >= widthPerIcon &&
292 availableWidth < (widthPerIcon + kPaddingBetweenIcons)) { 316 availableWidth < (widthPerIcon + kPaddingBetweenIcons)) {
293 return 1; 317 return 1;
294 } 318 }
295 return availableWidth / (widthPerIcon + kPaddingBetweenIcons); 319 return availableWidth / (widthPerIcon + kPaddingBetweenIcons);
296 } 320 }
297 321
298 - (BOOL)shouldShowIcon { 322 - (BOOL)shouldShowIcon {
299 return chrome::ShouldTabShowFavicon( 323 return chrome::ShouldTabShowFavicon(
(...skipping 25 matching lines...) Expand all
325 if (iconView_.get() == nil) { 349 if (iconView_.get() == nil) {
326 base::scoped_nsobject<SpriteView> iconView([[SpriteView alloc] init]); 350 base::scoped_nsobject<SpriteView> iconView([[SpriteView alloc] init]);
327 [iconView setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin]; 351 [iconView setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
328 [self setIconView:iconView]; 352 [self setIconView:iconView];
329 } 353 }
330 354
331 [iconView_ setImage:image withToastAnimation:animate]; 355 [iconView_ setImage:image withToastAnimation:animate];
332 356
333 if ([self pinned]) { 357 if ([self pinned]) {
334 NSRect appIconFrame = [iconView_ frame]; 358 NSRect appIconFrame = [iconView_ frame];
335 appIconFrame.origin = originalIconFrame_.origin;
336 359
337 const CGFloat tabWidth = [TabController pinnedTabWidth]; 360 const CGFloat tabWidth = [TabController pinnedTabWidth];
338 361
339 // Center the icon. 362 // Center the icon.
340 appIconFrame.origin.x = 363 appIconFrame.origin = NSMakePoint(
341 std::floor((tabWidth - NSWidth(appIconFrame)) / 2.0); 364 std::floor((tabWidth - kIconSize) / 2.0), kTabElementYOrigin);
342 [iconView_ setFrame:appIconFrame]; 365 [iconView_ setFrame:appIconFrame];
343 } else { 366 } else {
344 [iconView_ setFrame:originalIconFrame_]; 367 const CGFloat tabWidth = NSWidth([[self tabView] frame]);
368 const CGFloat iconOrigin =
369 cocoa_l10n_util::ShouldDoExperimentalRTLLayout()
370 ? tabWidth - kIconSize - kTabLeadingPadding
371 : kTabLeadingPadding;
372 NSRect iconFrame =
373 NSMakeRect(iconOrigin, kTabElementYOrigin, kIconSize, kIconSize);
374 [iconView_ setFrame:iconFrame];
345 } 375 }
346 } 376 }
347 } 377 }
348 378
349 - (void)updateVisibility { 379 - (void)updateVisibility {
350 // iconView_ may have been replaced or it may be nil, so [iconView_ isHidden] 380 // iconView_ may have been replaced or it may be nil, so [iconView_ isHidden]
351 // won't work. Instead, the state of the icon is tracked separately in 381 // won't work. Instead, the state of the icon is tracked separately in
352 // isIconShowing_. 382 // isIconShowing_.
353 BOOL newShowIcon = [self shouldShowIcon]; 383 BOOL newShowIcon = [self shouldShowIcon];
354 384
355 [iconView_ setHidden:!newShowIcon]; 385 [iconView_ setHidden:!newShowIcon];
356 isIconShowing_ = newShowIcon; 386 isIconShowing_ = newShowIcon;
357 387
358 // If the tab is a pinned-tab, hide the title. 388 // If the tab is a pinned-tab, hide the title.
359 TabView* tabView = [self tabView]; 389 TabView* tabView = [self tabView];
360 [tabView setTitleHidden:[self pinned]]; 390 [tabView setTitleHidden:[self pinned]];
361 391
362 BOOL newShowCloseButton = [self shouldShowCloseButton]; 392 BOOL newShowCloseButton = [self shouldShowCloseButton];
363 393
364 [closeButton_ setHidden:!newShowCloseButton]; 394 [closeButton_ setHidden:!newShowCloseButton];
365 395
366 BOOL newShowAlertIndicator = [self shouldShowAlertIndicator]; 396 BOOL newShowAlertIndicator = [self shouldShowAlertIndicator];
367 397
368 [alertIndicatorButton_ setHidden:!newShowAlertIndicator]; 398 [alertIndicatorButton_ setHidden:!newShowAlertIndicator];
369 399
400 BOOL isRTL = cocoa_l10n_util::ShouldDoExperimentalRTLLayout();
401
370 if (newShowAlertIndicator) { 402 if (newShowAlertIndicator) {
371 NSRect newFrame = [alertIndicatorButton_ frame]; 403 NSRect newFrame = [alertIndicatorButton_ frame];
372 newFrame.size = [[alertIndicatorButton_ image] size]; 404 newFrame.size = [[alertIndicatorButton_ image] size];
373 if ([self pinned]) { 405 if ([self pinned]) {
374 // Tab is pinned: Position the alert indicator in the center. 406 // Tab is pinned: Position the alert indicator in the center.
375 const CGFloat tabWidth = [TabController pinnedTabWidth]; 407 const CGFloat tabWidth = [TabController pinnedTabWidth];
376 newFrame.origin.x = std::floor((tabWidth - NSWidth(newFrame)) / 2); 408 newFrame.origin.x = std::floor((tabWidth - NSWidth(newFrame)) / 2);
377 newFrame.origin.y = NSMinY(originalIconFrame_) - 409 newFrame.origin.y =
378 std::floor((NSHeight(newFrame) - NSHeight(originalIconFrame_)) / 2); 410 kTabElementYOrigin - std::floor((NSHeight(newFrame) - kIconSize) / 2);
379 } else { 411 } else {
380 // The Frame for the alertIndicatorButton_ depends on whether iconView_ 412 // The Frame for the alertIndicatorButton_ depends on whether iconView_
381 // and/or closeButton_ are visible, and where they have been positioned. 413 // and/or closeButton_ are visible, and where they have been positioned.
382 const NSRect closeButtonFrame = [closeButton_ frame]; 414 const NSRect closeButtonFrame = [closeButton_ frame];
383 newFrame.origin.x = NSMinX(closeButtonFrame); 415 newFrame.origin.x = NSMinX(closeButtonFrame);
384 // Position to the left of the close button when it is showing. 416 // Position before the close button when it is showing.
385 if (newShowCloseButton) 417 if (newShowCloseButton)
386 newFrame.origin.x -= NSWidth(newFrame); 418 newFrame.origin.x += isRTL ? NSWidth(newFrame) : -NSWidth(newFrame);
387 // Alert indicator is centered vertically, with respect to closeButton_. 419 // Alert indicator is centered vertically, with respect to closeButton_.
388 newFrame.origin.y = NSMinY(closeButtonFrame) - 420 newFrame.origin.y = NSMinY(closeButtonFrame) -
389 std::floor((NSHeight(newFrame) - NSHeight(closeButtonFrame)) / 2); 421 std::floor((NSHeight(newFrame) - NSHeight(closeButtonFrame)) / 2);
390 } 422 }
391 [alertIndicatorButton_ setFrame:newFrame]; 423 [alertIndicatorButton_ setFrame:newFrame];
392 [alertIndicatorButton_ updateEnabledForMuteToggle]; 424 [alertIndicatorButton_ updateEnabledForMuteToggle];
393 } 425 }
394 426
395 // Adjust the title view based on changes to the icon's and close button's 427 // Adjust the title view based on changes to the icon's and close button's
396 // visibility. 428 // visibility.
397 NSRect oldTitleFrame = [tabView titleFrame]; 429 NSRect oldTitleFrame = [tabView titleFrame];
398 NSRect newTitleFrame; 430 NSRect newTitleFrame;
399 newTitleFrame.size.height = oldTitleFrame.size.height; 431 newTitleFrame.size.height = oldTitleFrame.size.height;
400 newTitleFrame.origin.y = oldTitleFrame.origin.y; 432 newTitleFrame.origin.y = oldTitleFrame.origin.y;
401 433
402 if (newShowIcon) { 434 CGFloat titleLeft, titleRight;
403 newTitleFrame.origin.x = NSMaxX([iconView_ frame]) + 4; 435 if (isRTL) {
436 if (newShowAlertIndicator) {
437 titleLeft = NSMaxX([alertIndicatorButton_ frame]);
438 } else if (newShowCloseButton) {
439 titleLeft = NSMaxX([closeButton_ frame]);
440 } else {
441 titleLeft = kTabLeadingPadding;
442 }
443 titleRight = newShowIcon
444 ? NSMinX([iconView_ frame]) - kTitleLeadingPadding
445 : NSWidth([[self tabView] frame]) - kTabLeadingPadding;
404 } else { 446 } else {
405 newTitleFrame.origin.x = originalIconFrame_.origin.x; 447 titleLeft = newShowIcon ? NSMaxX([iconView_ frame]) + kTitleLeadingPadding
448 : kTabLeadingPadding;
449 if (newShowAlertIndicator) {
450 titleRight = NSMinX([alertIndicatorButton_ frame]);
451 } else if (newShowCloseButton) {
452 titleRight = NSMinX([closeButton_ frame]);
453 } else {
454 titleRight = NSWidth([[self tabView] frame]) - kTabTrailingPadding;
455 }
406 } 456 }
407 457
408 if (newShowAlertIndicator) { 458 newTitleFrame.size.width = titleRight - titleLeft;
409 newTitleFrame.size.width = NSMinX([alertIndicatorButton_ frame]) - 459 newTitleFrame.origin.x = titleLeft;
410 newTitleFrame.origin.x;
411 } else if (newShowCloseButton) {
412 newTitleFrame.size.width = NSMinX([closeButton_ frame]) -
413 newTitleFrame.origin.x;
414 } else {
415 newTitleFrame.size.width = NSMaxX([closeButton_ frame]) -
416 newTitleFrame.origin.x;
417 }
418 460
419 [tabView setTitleFrame:newTitleFrame]; 461 [tabView setTitleFrame:newTitleFrame];
420 } 462 }
421 463
422 - (void)updateTitleColor { 464 - (void)updateTitleColor {
423 NSColor* titleColor = nil; 465 NSColor* titleColor = nil;
424 const ui::ThemeProvider* theme = [[[self view] window] themeProvider]; 466 const ui::ThemeProvider* theme = [[[self view] window] themeProvider];
425 if (theme && ![self selected]) 467 if (theme && ![self selected])
426 titleColor = theme->GetNSColor(ThemeProperties::COLOR_BACKGROUND_TAB_TEXT); 468 titleColor = theme->GetNSColor(ThemeProperties::COLOR_BACKGROUND_TAB_TEXT);
427 // Default to the selected text color unless told otherwise. 469 // Default to the selected text color unless told otherwise.
(...skipping 13 matching lines...) Expand all
441 YES : NO; 483 YES : NO;
442 } 484 }
443 return NO; 485 return NO;
444 } 486 }
445 487
446 - (void)maybeStartDrag:(NSEvent*)event forTab:(TabController*)tab { 488 - (void)maybeStartDrag:(NSEvent*)event forTab:(TabController*)tab {
447 [[target_ dragController] maybeStartDrag:event forTab:tab]; 489 [[target_ dragController] maybeStartDrag:event forTab:tab];
448 } 490 }
449 491
450 @end 492 @end
OLDNEW
« no previous file with comments | « chrome/browser/ui/cocoa/tabs/tab_controller.h ('k') | chrome/browser/ui/cocoa/tabs/tab_controller_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698