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

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

Issue 2488833002: [Mac] Reverse tabs in RTL mode (Closed)
Patch Set: Update icon mask and add force RTL direction 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 | NSViewMinYMargin
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_
124 setAutoresizingMask:isRTL ? NSViewMaxXMargin : NSViewMinXMargin];
104 [closeButton_ setTarget:self]; 125 [closeButton_ setTarget:self];
105 [closeButton_ setAction:@selector(closeTab:)]; 126 [closeButton_ setAction:@selector(closeTab:)];
106 127
107 base::scoped_nsobject<TabView> view([[TabView alloc] 128 base::scoped_nsobject<TabView> view([[TabView alloc]
108 initWithFrame:NSMakeRect(0, 0, 160, [TabController defaultTabHeight]) 129 initWithFrame:NSMakeRect(0, 0, kInitialTabWidth,
130 [TabController defaultTabHeight])
109 controller:self 131 controller:self
110 closeButton:closeButton_]); 132 closeButton:closeButton_]);
111 [view setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin]; 133 [view setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
112 [view setPostsFrameChangedNotifications:NO]; 134 [view setPostsFrameChangedNotifications:NO];
113 [view setPostsBoundsChangedNotifications:NO]; 135 [view setPostsBoundsChangedNotifications:NO];
114 [view addSubview:iconView_]; 136 [view addSubview:iconView_];
115 [view addSubview:closeButton_]; 137 [view addSubview:closeButton_];
116 [view setTitleFrame:titleFrame]; 138 [view setTitleFrame:titleFrame];
117 [super setView:view]; 139 [super setView:view];
118 140
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
277 } 299 }
278 300
279 - (void)setToolTip:(NSString*)toolTip { 301 - (void)setToolTip:(NSString*)toolTip {
280 [[self tabView] setToolTipText:toolTip]; 302 [[self tabView] setToolTipText:toolTip];
281 } 303 }
282 304
283 // Return a rough approximation of the number of icons we could fit in the 305 // 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 306 // tab. We never actually do this, but it's a helpful guide for determining
285 // how much space we have available. 307 // how much space we have available.
286 - (int)iconCapacity { 308 - (int)iconCapacity {
287 const CGFloat availableWidth = std::max<CGFloat>( 309 const CGFloat availableWidth =
288 0, NSMaxX([closeButton_ frame]) - NSMinX(originalIconFrame_)); 310 std::max<CGFloat>(0, NSWidth([[self tabView] frame]) -
289 const CGFloat widthPerIcon = NSWidth(originalIconFrame_); 311 kTabLeadingPadding - kTabTrailingPadding);
312 const CGFloat widthPerIcon = kIconSize;
290 const int kPaddingBetweenIcons = 2; 313 const int kPaddingBetweenIcons = 2;
291 if (availableWidth >= widthPerIcon && 314 if (availableWidth >= widthPerIcon &&
292 availableWidth < (widthPerIcon + kPaddingBetweenIcons)) { 315 availableWidth < (widthPerIcon + kPaddingBetweenIcons)) {
293 return 1; 316 return 1;
294 } 317 }
295 return availableWidth / (widthPerIcon + kPaddingBetweenIcons); 318 return availableWidth / (widthPerIcon + kPaddingBetweenIcons);
296 } 319 }
297 320
298 - (BOOL)shouldShowIcon { 321 - (BOOL)shouldShowIcon {
299 return chrome::ShouldTabShowFavicon( 322 return chrome::ShouldTabShowFavicon(
(...skipping 15 matching lines...) Expand all
315 } 338 }
316 339
317 - (void)setIconImage:(NSImage*)image { 340 - (void)setIconImage:(NSImage*)image {
318 [self setIconImage:image withToastAnimation:NO]; 341 [self setIconImage:image withToastAnimation:NO];
319 } 342 }
320 343
321 - (void)setIconImage:(NSImage*)image withToastAnimation:(BOOL)animate { 344 - (void)setIconImage:(NSImage*)image withToastAnimation:(BOOL)animate {
322 if (image == nil) { 345 if (image == nil) {
323 [self setIconView:nil]; 346 [self setIconView:nil];
324 } else { 347 } else {
348 BOOL isRTL = cocoa_l10n_util::ShouldDoExperimentalRTLLayout();
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:isRTL
352 ? NSViewMinXMargin | NSViewMinYMargin
353 : NSViewMaxXMargin | NSViewMinYMargin];
328 [self setIconView:iconView]; 354 [self setIconView:iconView];
329 } 355 }
330 356
331 [iconView_ setImage:image withToastAnimation:animate]; 357 [iconView_ setImage:image withToastAnimation:animate];
332 358
333 if ([self pinned]) { 359 if ([self pinned]) {
334 NSRect appIconFrame = [iconView_ frame]; 360 NSRect appIconFrame = [iconView_ frame];
335 appIconFrame.origin = originalIconFrame_.origin;
336 361
337 const CGFloat tabWidth = [TabController pinnedTabWidth]; 362 const CGFloat tabWidth = [TabController pinnedTabWidth];
338 363
339 // Center the icon. 364 // Center the icon.
340 appIconFrame.origin.x = 365 appIconFrame.origin = NSMakePoint(
341 std::floor((tabWidth - NSWidth(appIconFrame)) / 2.0); 366 std::floor((tabWidth - kIconSize) / 2.0), kTabElementYOrigin);
342 [iconView_ setFrame:appIconFrame]; 367 [iconView_ setFrame:appIconFrame];
343 } else { 368 } else {
344 [iconView_ setFrame:originalIconFrame_]; 369 const CGFloat tabWidth = NSWidth([[self tabView] frame]);
370 const CGFloat iconOrigin = isRTL
371 ? tabWidth - kIconSize - kTabLeadingPadding
372 : kTabLeadingPadding;
373 NSRect iconFrame =
374 NSMakeRect(iconOrigin, kTabElementYOrigin, kIconSize, kIconSize);
375 [iconView_ setFrame:iconFrame];
345 } 376 }
346 } 377 }
347 } 378 }
348 379
349 - (void)updateVisibility { 380 - (void)updateVisibility {
350 // iconView_ may have been replaced or it may be nil, so [iconView_ isHidden] 381 // 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 382 // won't work. Instead, the state of the icon is tracked separately in
352 // isIconShowing_. 383 // isIconShowing_.
353 BOOL newShowIcon = [self shouldShowIcon]; 384 BOOL newShowIcon = [self shouldShowIcon];
354 385
355 [iconView_ setHidden:!newShowIcon]; 386 [iconView_ setHidden:!newShowIcon];
356 isIconShowing_ = newShowIcon; 387 isIconShowing_ = newShowIcon;
357 388
358 // If the tab is a pinned-tab, hide the title. 389 // If the tab is a pinned-tab, hide the title.
359 TabView* tabView = [self tabView]; 390 TabView* tabView = [self tabView];
360 [tabView setTitleHidden:[self pinned]]; 391 [tabView setTitleHidden:[self pinned]];
361 392
362 BOOL newShowCloseButton = [self shouldShowCloseButton]; 393 BOOL newShowCloseButton = [self shouldShowCloseButton];
363 394
364 [closeButton_ setHidden:!newShowCloseButton]; 395 [closeButton_ setHidden:!newShowCloseButton];
365 396
366 BOOL newShowAlertIndicator = [self shouldShowAlertIndicator]; 397 BOOL newShowAlertIndicator = [self shouldShowAlertIndicator];
367 398
368 [alertIndicatorButton_ setHidden:!newShowAlertIndicator]; 399 [alertIndicatorButton_ setHidden:!newShowAlertIndicator];
369 400
401 BOOL isRTL = cocoa_l10n_util::ShouldDoExperimentalRTLLayout();
402
370 if (newShowAlertIndicator) { 403 if (newShowAlertIndicator) {
371 NSRect newFrame = [alertIndicatorButton_ frame]; 404 NSRect newFrame = [alertIndicatorButton_ frame];
372 newFrame.size = [[alertIndicatorButton_ image] size]; 405 newFrame.size = [[alertIndicatorButton_ image] size];
373 if ([self pinned]) { 406 if ([self pinned]) {
374 // Tab is pinned: Position the alert indicator in the center. 407 // Tab is pinned: Position the alert indicator in the center.
375 const CGFloat tabWidth = [TabController pinnedTabWidth]; 408 const CGFloat tabWidth = [TabController pinnedTabWidth];
376 newFrame.origin.x = std::floor((tabWidth - NSWidth(newFrame)) / 2); 409 newFrame.origin.x = std::floor((tabWidth - NSWidth(newFrame)) / 2);
377 newFrame.origin.y = NSMinY(originalIconFrame_) - 410 newFrame.origin.y =
378 std::floor((NSHeight(newFrame) - NSHeight(originalIconFrame_)) / 2); 411 kTabElementYOrigin - std::floor((NSHeight(newFrame) - kIconSize) / 2);
379 } else { 412 } else {
380 // The Frame for the alertIndicatorButton_ depends on whether iconView_ 413 // The Frame for the alertIndicatorButton_ depends on whether iconView_
381 // and/or closeButton_ are visible, and where they have been positioned. 414 // and/or closeButton_ are visible, and where they have been positioned.
382 const NSRect closeButtonFrame = [closeButton_ frame]; 415 const NSRect closeButtonFrame = [closeButton_ frame];
383 newFrame.origin.x = NSMinX(closeButtonFrame); 416 newFrame.origin.x = NSMinX(closeButtonFrame);
384 // Position to the left of the close button when it is showing. 417 // Position before the close button when it is showing.
385 if (newShowCloseButton) 418 if (newShowCloseButton)
386 newFrame.origin.x -= NSWidth(newFrame); 419 newFrame.origin.x += isRTL ? NSWidth(newFrame) : -NSWidth(newFrame);
387 // Alert indicator is centered vertically, with respect to closeButton_. 420 // Alert indicator is centered vertically, with respect to closeButton_.
388 newFrame.origin.y = NSMinY(closeButtonFrame) - 421 newFrame.origin.y = NSMinY(closeButtonFrame) -
389 std::floor((NSHeight(newFrame) - NSHeight(closeButtonFrame)) / 2); 422 std::floor((NSHeight(newFrame) - NSHeight(closeButtonFrame)) / 2);
390 } 423 }
391 [alertIndicatorButton_ setFrame:newFrame]; 424 [alertIndicatorButton_ setFrame:newFrame];
392 [alertIndicatorButton_ updateEnabledForMuteToggle]; 425 [alertIndicatorButton_ updateEnabledForMuteToggle];
393 } 426 }
394 427
395 // Adjust the title view based on changes to the icon's and close button's 428 // Adjust the title view based on changes to the icon's and close button's
396 // visibility. 429 // visibility.
397 NSRect oldTitleFrame = [tabView titleFrame]; 430 NSRect oldTitleFrame = [tabView titleFrame];
398 NSRect newTitleFrame; 431 NSRect newTitleFrame;
399 newTitleFrame.size.height = oldTitleFrame.size.height; 432 newTitleFrame.size.height = oldTitleFrame.size.height;
400 newTitleFrame.origin.y = oldTitleFrame.origin.y; 433 newTitleFrame.origin.y = oldTitleFrame.origin.y;
401 434
402 if (newShowIcon) { 435 CGFloat titleLeft, titleRight;
403 newTitleFrame.origin.x = NSMaxX([iconView_ frame]) + 4; 436 if (isRTL) {
437 if (newShowAlertIndicator) {
438 titleLeft = NSMaxX([alertIndicatorButton_ frame]);
439 } else if (newShowCloseButton) {
440 titleLeft = NSMaxX([closeButton_ frame]);
441 } else {
442 titleLeft = kTabLeadingPadding;
443 }
444 titleRight = newShowIcon
445 ? NSMinX([iconView_ frame]) - kTitleLeadingPadding
446 : NSWidth([[self tabView] frame]) - kTabLeadingPadding;
404 } else { 447 } else {
405 newTitleFrame.origin.x = originalIconFrame_.origin.x; 448 titleLeft = newShowIcon ? NSMaxX([iconView_ frame]) + kTitleLeadingPadding
449 : kTabLeadingPadding;
450 if (newShowAlertIndicator) {
451 titleRight = NSMinX([alertIndicatorButton_ frame]);
452 } else if (newShowCloseButton) {
453 titleRight = NSMinX([closeButton_ frame]);
454 } else {
455 titleRight = NSWidth([[self tabView] frame]) - kTabTrailingPadding;
456 }
406 } 457 }
407 458
408 if (newShowAlertIndicator) { 459 newTitleFrame.size.width = titleRight - titleLeft;
409 newTitleFrame.size.width = NSMinX([alertIndicatorButton_ frame]) - 460 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 461
419 [tabView setTitleFrame:newTitleFrame]; 462 [tabView setTitleFrame:newTitleFrame];
420 } 463 }
421 464
422 - (void)updateTitleColor { 465 - (void)updateTitleColor {
423 NSColor* titleColor = nil; 466 NSColor* titleColor = nil;
424 const ui::ThemeProvider* theme = [[[self view] window] themeProvider]; 467 const ui::ThemeProvider* theme = [[[self view] window] themeProvider];
425 if (theme && ![self selected]) 468 if (theme && ![self selected])
426 titleColor = theme->GetNSColor(ThemeProperties::COLOR_BACKGROUND_TAB_TEXT); 469 titleColor = theme->GetNSColor(ThemeProperties::COLOR_BACKGROUND_TAB_TEXT);
427 // Default to the selected text color unless told otherwise. 470 // Default to the selected text color unless told otherwise.
(...skipping 13 matching lines...) Expand all
441 YES : NO; 484 YES : NO;
442 } 485 }
443 return NO; 486 return NO;
444 } 487 }
445 488
446 - (void)maybeStartDrag:(NSEvent*)event forTab:(TabController*)tab { 489 - (void)maybeStartDrag:(NSEvent*)event forTab:(TabController*)tab {
447 [[target_ dragController] maybeStartDrag:event forTab:tab]; 490 [[target_ dragController] maybeStartDrag:event forTab:tab];
448 } 491 }
449 492
450 @end 493 @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