OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "browser_actions_controller.h" | 5 #import "browser_actions_controller.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "app/resource_bundle.h" | 10 #include "base/nsimage_cache_mac.h" |
11 #include "base/sys_string_conversions.h" | 11 #include "base/sys_string_conversions.h" |
12 #include "chrome/browser/browser.h" | 12 #include "chrome/browser/browser.h" |
13 #include "chrome/browser/pref_service.h" | 13 #include "chrome/browser/pref_service.h" |
14 #import "chrome/browser/cocoa/extensions/browser_action_button.h" | 14 #import "chrome/browser/cocoa/extensions/browser_action_button.h" |
15 #import "chrome/browser/cocoa/extensions/browser_actions_container_view.h" | 15 #import "chrome/browser/cocoa/extensions/browser_actions_container_view.h" |
16 #import "chrome/browser/cocoa/extensions/extension_popup_controller.h" | 16 #import "chrome/browser/cocoa/extensions/extension_popup_controller.h" |
17 #import "chrome/browser/cocoa/menu_button.h" | 17 #import "chrome/browser/cocoa/menu_button.h" |
18 #include "chrome/browser/extensions/extension_browser_event_router.h" | 18 #include "chrome/browser/extensions/extension_browser_event_router.h" |
19 #include "chrome/browser/extensions/extension_host.h" | 19 #include "chrome/browser/extensions/extension_host.h" |
20 #include "chrome/browser/extensions/extension_toolbar_model.h" | 20 #include "chrome/browser/extensions/extension_toolbar_model.h" |
21 #include "chrome/browser/extensions/extensions_service.h" | 21 #include "chrome/browser/extensions/extensions_service.h" |
22 #include "chrome/browser/profile.h" | 22 #include "chrome/browser/profile.h" |
23 #include "chrome/browser/tab_contents/tab_contents.h" | 23 #include "chrome/browser/tab_contents/tab_contents.h" |
24 #include "chrome/common/extensions/extension_action.h" | 24 #include "chrome/common/extensions/extension_action.h" |
25 #include "chrome/common/notification_observer.h" | 25 #include "chrome/common/notification_observer.h" |
26 #include "chrome/common/notification_registrar.h" | 26 #include "chrome/common/notification_registrar.h" |
27 #include "chrome/common/pref_names.h" | 27 #include "chrome/common/pref_names.h" |
28 #include "grit/theme_resources.h" | |
29 #import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h" | 28 #import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h" |
30 | 29 |
31 const CGFloat kBrowserActionButtonPadding = 3; | |
32 | |
33 NSString* const kBrowserActionVisibilityChangedNotification = | 30 NSString* const kBrowserActionVisibilityChangedNotification = |
34 @"BrowserActionVisibilityChangedNotification"; | 31 @"BrowserActionVisibilityChangedNotification"; |
35 | 32 |
36 namespace { | 33 namespace { |
37 const CGFloat kAnimationDuration = 0.2; | 34 const CGFloat kAnimationDuration = 0.2; |
38 // When determining the opacity during a drag, we artificially reduce the | 35 // When determining the opacity during a drag, we artificially reduce the |
39 // distance to the edge in order to make the fade more apparent. | 36 // distance to the edge in order to make the fade more apparent. |
40 const CGFloat kButtonOpacityLeadPadding = 5.0; | 37 const CGFloat kButtonOpacityLeadPadding = 5.0; |
41 const CGFloat kChevronHeight = 28.0; | |
42 const CGFloat kChevronLowerPadding = 5.0; | |
43 const CGFloat kChevronRightPadding = 5.0; | |
44 const CGFloat kChevronWidth = 14.0; | 38 const CGFloat kChevronWidth = 14.0; |
45 const CGFloat kGrippyXOffset = 5.0; | 39 |
| 40 // Image used for the overflow button. |
| 41 NSString* const kOverflowChevronsName = |
| 42 @"browser_actions_overflow_Template.pdf"; |
| 43 |
| 44 // Since the container is the maximum height of the toolbar, we have |
| 45 // to move the buttons up by this amount in order to have them look |
| 46 // vertically centered within the toolbar. |
| 47 const CGFloat kBrowserActionOriginYOffset = 5.0; |
| 48 |
| 49 // The size of each button on the toolbar. |
| 50 const CGFloat kBrowserActionHeight = 29.0; |
| 51 const CGFloat kBrowserActionWidth = 29.0; |
| 52 |
| 53 // The padding between browser action buttons. |
| 54 const CGFloat kBrowserActionButtonPadding = 2.0; |
| 55 |
| 56 // Padding between Omnibox and first button. Since the buttons have a |
| 57 // pixel of internal padding, this needs an extra pixel. |
| 58 const CGFloat kBrowserActionLeftPadding = kBrowserActionButtonPadding + 1.0; |
| 59 |
46 } // namespace | 60 } // namespace |
47 | 61 |
48 @interface BrowserActionsController(Private) | 62 @interface BrowserActionsController(Private) |
49 // Used during initialization to create the BrowserActionButton objects from the | 63 // Used during initialization to create the BrowserActionButton objects from the |
50 // stored toolbar model. | 64 // stored toolbar model. |
51 - (void)createButtons; | 65 - (void)createButtons; |
52 | 66 |
53 // Creates and then adds the given extension's action button to the container | 67 // Creates and then adds the given extension's action button to the container |
54 // at the given index within the container. It does not affect the toolbar model | 68 // at the given index within the container. It does not affect the toolbar model |
55 // object since it is called when the toolbar model changes. | 69 // object since it is called when the toolbar model changes. |
(...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
442 return; | 456 return; |
443 | 457 |
444 if (profile_->IsOffTheRecord()) | 458 if (profile_->IsOffTheRecord()) |
445 index = toolbarModel_->OriginalIndexToIncognito(index); | 459 index = toolbarModel_->OriginalIndexToIncognito(index); |
446 | 460 |
447 // Show the container if it's the first button. Otherwise it will be shown | 461 // Show the container if it's the first button. Otherwise it will be shown |
448 // already. | 462 // already. |
449 if ([self buttonCount] == 0) | 463 if ([self buttonCount] == 0) |
450 [containerView_ setHidden:NO]; | 464 [containerView_ setHidden:NO]; |
451 | 465 |
452 BrowserActionButton* newButton = [[[BrowserActionButton alloc] | 466 NSRect buttonFrame = NSMakeRect(0.0, kBrowserActionOriginYOffset, |
453 initWithExtension:extension | 467 kBrowserActionWidth, kBrowserActionHeight); |
454 profile:profile_ | 468 BrowserActionButton* newButton = |
455 tabId:[self currentTabId]] autorelease]; | 469 [[[BrowserActionButton alloc] |
| 470 initWithFrame:buttonFrame |
| 471 extension:extension |
| 472 profile:profile_ |
| 473 tabId:[self currentTabId]] autorelease]; |
456 [newButton setTarget:self]; | 474 [newButton setTarget:self]; |
457 [newButton setAction:@selector(browserActionClicked:)]; | 475 [newButton setAction:@selector(browserActionClicked:)]; |
458 NSString* buttonKey = base::SysUTF8ToNSString(extension->id()); | 476 NSString* buttonKey = base::SysUTF8ToNSString(extension->id()); |
459 if (!buttonKey) | 477 if (!buttonKey) |
460 return; | 478 return; |
461 [buttons_ setObject:newButton forKey:buttonKey]; | 479 [buttons_ setObject:newButton forKey:buttonKey]; |
462 | 480 |
463 [self positionActionButtonsAndAnimate:NO]; | 481 [self positionActionButtonsAndAnimate:NO]; |
464 | 482 |
465 [[NSNotificationCenter defaultCenter] | 483 [[NSNotificationCenter defaultCenter] |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
542 | 560 |
543 - (BrowserActionButton*)buttonForExtension:(Extension*)extension { | 561 - (BrowserActionButton*)buttonForExtension:(Extension*)extension { |
544 NSString* extensionId = base::SysUTF8ToNSString(extension->id()); | 562 NSString* extensionId = base::SysUTF8ToNSString(extension->id()); |
545 DCHECK(extensionId); | 563 DCHECK(extensionId); |
546 if (!extensionId) | 564 if (!extensionId) |
547 return nil; | 565 return nil; |
548 return [buttons_ objectForKey:extensionId]; | 566 return [buttons_ objectForKey:extensionId]; |
549 } | 567 } |
550 | 568 |
551 - (CGFloat)containerWidthWithButtonCount:(NSUInteger)buttonCount { | 569 - (CGFloat)containerWidthWithButtonCount:(NSUInteger)buttonCount { |
552 CGFloat width = 0.0; | 570 // Left-side padding which works regardless of whether a button or |
| 571 // chevron leads. |
| 572 CGFloat width = kBrowserActionLeftPadding; |
| 573 |
| 574 // Include the buttons and padding between. |
553 if (buttonCount > 0) { | 575 if (buttonCount > 0) { |
554 width = kGrippyXOffset + (2 * kBrowserActionButtonPadding) + | 576 width += buttonCount * kBrowserActionWidth; |
555 (buttonCount * (kBrowserActionWidth + kBrowserActionButtonPadding)); | 577 width += (buttonCount - 1) * kBrowserActionButtonPadding; |
556 } | 578 } |
| 579 |
557 // Make room for the chevron if any buttons are hidden. | 580 // Make room for the chevron if any buttons are hidden. |
558 if ([self buttonCount] != [self visibleButtonCount]) { | 581 if ([self buttonCount] != [self visibleButtonCount]) { |
559 width += kChevronWidth + kBrowserActionButtonPadding; | 582 // Chevron and buttons both include 1px padding w/in their bounds, |
560 // Add more space if all buttons are hidden. | 583 // so this leaves 2px between the last browser action and chevron, |
561 if ([self visibleButtonCount] == 0) | 584 // and also works right if the chevron is the only button. |
562 width += 3 * kBrowserActionButtonPadding; | 585 width += kChevronWidth; |
563 } | 586 } |
564 | 587 |
565 return width; | 588 return width; |
566 } | 589 } |
567 | 590 |
568 - (NSUInteger)containerButtonCapacity { | 591 - (NSUInteger)containerButtonCapacity { |
569 CGFloat containerWidth = [self savedWidth]; | 592 // Edge-to-edge span of the browser action buttons. |
570 return (containerWidth - kGrippyXOffset) / | 593 CGFloat actionSpan = [self savedWidth] - kBrowserActionLeftPadding; |
| 594 |
| 595 // Add in some padding for the browser action on the end, then |
| 596 // divide out to get the number of action buttons that fit. |
| 597 return (actionSpan + kBrowserActionButtonPadding) / |
571 (kBrowserActionWidth + kBrowserActionButtonPadding); | 598 (kBrowserActionWidth + kBrowserActionButtonPadding); |
572 } | 599 } |
573 | 600 |
574 - (void)containerFrameChanged:(NSNotification*)notification { | 601 - (void)containerFrameChanged:(NSNotification*)notification { |
575 [self updateButtonOpacity]; | 602 [self updateButtonOpacity]; |
576 [[containerView_ window] invalidateCursorRectsForView:containerView_]; | 603 [[containerView_ window] invalidateCursorRectsForView:containerView_]; |
577 [self updateChevronPositionInFrame:[containerView_ frame]]; | 604 [self updateChevronPositionInFrame:[containerView_ frame]]; |
578 } | 605 } |
579 | 606 |
580 - (void)containerDragStart:(NSNotification*)notification { | 607 - (void)containerDragStart:(NSNotification*)notification { |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
661 } | 688 } |
662 | 689 |
663 - (void)actionButtonDragFinished:(NSNotification*)notification { | 690 - (void)actionButtonDragFinished:(NSNotification*)notification { |
664 [self showChevronIfNecessaryInFrame:[containerView_ frame] animate:YES]; | 691 [self showChevronIfNecessaryInFrame:[containerView_ frame] animate:YES]; |
665 [self positionActionButtonsAndAnimate:YES]; | 692 [self positionActionButtonsAndAnimate:YES]; |
666 } | 693 } |
667 | 694 |
668 - (void)moveButton:(BrowserActionButton*)button | 695 - (void)moveButton:(BrowserActionButton*)button |
669 toIndex:(NSUInteger)index | 696 toIndex:(NSUInteger)index |
670 animate:(BOOL)animate { | 697 animate:(BOOL)animate { |
671 CGFloat xOffset = kGrippyXOffset + | 698 CGFloat xOffset = kBrowserActionLeftPadding + |
672 (index * (kBrowserActionWidth + kBrowserActionButtonPadding)); | 699 (index * (kBrowserActionWidth + kBrowserActionButtonPadding)); |
673 NSRect buttonFrame = [button frame]; | 700 NSRect buttonFrame = [button frame]; |
674 buttonFrame.origin.x = xOffset; | 701 buttonFrame.origin.x = xOffset; |
675 [button setFrame:buttonFrame animate:animate]; | 702 [button setFrame:buttonFrame animate:animate]; |
676 | 703 |
677 if (index < [self containerButtonCapacity]) { | 704 if (index < [self containerButtonCapacity]) { |
678 // Make sure the button is within the visible container. | 705 // Make sure the button is within the visible container. |
679 if ([button superview] != containerView_) { | 706 if ([button superview] != containerView_) { |
680 [containerView_ addSubview:button]; | 707 [containerView_ addSubview:button]; |
681 [button setAlphaValue:1.0]; | 708 [button setAlphaValue:1.0]; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
726 profile_->GetExtensionsService()->IsIncognitoEnabled(extension)); | 753 profile_->GetExtensionsService()->IsIncognitoEnabled(extension)); |
727 } | 754 } |
728 | 755 |
729 - (void)showChevronIfNecessaryInFrame:(NSRect)frame animate:(BOOL)animate { | 756 - (void)showChevronIfNecessaryInFrame:(NSRect)frame animate:(BOOL)animate { |
730 [self setChevronHidden:([self buttonCount] == [self visibleButtonCount]) | 757 [self setChevronHidden:([self buttonCount] == [self visibleButtonCount]) |
731 inFrame:frame | 758 inFrame:frame |
732 animate:animate]; | 759 animate:animate]; |
733 } | 760 } |
734 | 761 |
735 - (void)updateChevronPositionInFrame:(NSRect)frame { | 762 - (void)updateChevronPositionInFrame:(NSRect)frame { |
736 CGFloat xPos = NSWidth(frame) - kChevronWidth - kChevronRightPadding; | 763 CGFloat xPos = NSWidth(frame) - kChevronWidth; |
737 NSRect buttonFrame = NSMakeRect(xPos, | 764 NSRect buttonFrame = NSMakeRect(xPos, |
738 kChevronLowerPadding, | 765 kBrowserActionOriginYOffset, |
739 kChevronWidth, | 766 kChevronWidth, |
740 kChevronHeight); | 767 kBrowserActionHeight); |
741 [chevronMenuButton_ setFrame:buttonFrame]; | 768 [chevronMenuButton_ setFrame:buttonFrame]; |
742 } | 769 } |
743 | 770 |
744 - (void)setChevronHidden:(BOOL)hidden | 771 - (void)setChevronHidden:(BOOL)hidden |
745 inFrame:(NSRect)frame | 772 inFrame:(NSRect)frame |
746 animate:(BOOL)animate { | 773 animate:(BOOL)animate { |
747 if (hidden == [self chevronIsHidden]) | 774 if (hidden == [self chevronIsHidden]) |
748 return; | 775 return; |
749 | 776 |
750 if (!chevronMenuButton_.get()) { | 777 if (!chevronMenuButton_.get()) { |
751 chevronMenuButton_.reset([[MenuButton alloc] init]); | 778 chevronMenuButton_.reset([[MenuButton alloc] init]); |
752 [chevronMenuButton_ setBordered:NO]; | 779 [chevronMenuButton_ setBordered:NO]; |
753 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 780 [chevronMenuButton_ setShowsBorderOnlyWhileMouseInside:YES]; |
754 [chevronMenuButton_ setImage:rb.GetNSImageNamed(IDR_BOOKMARK_BAR_CHEVRONS)]; | 781 NSImage* chevronImage = nsimage_cache::ImageNamed(kOverflowChevronsName); |
| 782 [chevronMenuButton_ setImage:chevronImage]; |
755 [containerView_ addSubview:chevronMenuButton_]; | 783 [containerView_ addSubview:chevronMenuButton_]; |
756 } | 784 } |
757 | 785 |
758 if (!hidden) | 786 if (!hidden) |
759 [self updateOverflowMenu]; | 787 [self updateOverflowMenu]; |
760 | 788 |
761 [self updateChevronPositionInFrame:frame]; | 789 [self updateChevronPositionInFrame:frame]; |
762 | 790 |
763 // Stop any running animation. | 791 // Stop any running animation. |
764 [chevronAnimation_ stopAnimation]; | 792 [chevronAnimation_ stopAnimation]; |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
829 if (profile_->IsOffTheRecord()) | 857 if (profile_->IsOffTheRecord()) |
830 index = toolbarModel_->IncognitoIndexToOriginal(index); | 858 index = toolbarModel_->IncognitoIndexToOriginal(index); |
831 if (index < toolbarModel_->size()) { | 859 if (index < toolbarModel_->size()) { |
832 Extension* extension = toolbarModel_->GetExtensionByIndex(index); | 860 Extension* extension = toolbarModel_->GetExtensionByIndex(index); |
833 return [buttons_ objectForKey:base::SysUTF8ToNSString(extension->id())]; | 861 return [buttons_ objectForKey:base::SysUTF8ToNSString(extension->id())]; |
834 } | 862 } |
835 return nil; | 863 return nil; |
836 } | 864 } |
837 | 865 |
838 @end | 866 @end |
OLD | NEW |