diff options
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/browser_prefs.cc | 4 | ||||
-rw-r--r-- | chrome/browser/views/browser_actions_container.cc | 336 | ||||
-rw-r--r-- | chrome/browser/views/browser_actions_container.h | 159 | ||||
-rw-r--r-- | chrome/browser/views/detachable_toolbar_view.h | 12 | ||||
-rw-r--r-- | chrome/browser/views/extensions/extension_installed_bubble.cc | 32 | ||||
-rw-r--r-- | chrome/browser/views/extensions/extension_installed_bubble.h | 5 | ||||
-rw-r--r-- | chrome/browser/views/location_bar_view.cc | 5 | ||||
-rw-r--r-- | chrome/browser/views/location_bar_view.h | 4 | ||||
-rw-r--r-- | chrome/browser/views/toolbar_view.cc | 19 |
9 files changed, 497 insertions, 79 deletions
diff --git a/chrome/browser/browser_prefs.cc b/chrome/browser/browser_prefs.cc index b9e7fa2..710c4e0 100644 --- a/chrome/browser/browser_prefs.cc +++ b/chrome/browser/browser_prefs.cc @@ -34,6 +34,7 @@ #include "chrome/browser/task_manager.h" #if defined(TOOLKIT_VIEWS) // TODO(port): whittle this down as we port +#include "chrome/browser/views/browser_actions_container.h" #include "chrome/browser/views/frame/browser_view.h" #endif @@ -92,6 +93,9 @@ void RegisterUserPrefs(PrefService* user_prefs) { BlockedPopupContainer::RegisterUserPrefs(user_prefs); HostZoomMap::RegisterUserPrefs(user_prefs); DevToolsManager::RegisterUserPrefs(user_prefs); +#if defined(TOOLKIT_VIEWS) // TODO(port): whittle this down as we port. + BrowserActionsContainer::RegisterUserPrefs(user_prefs); +#endif #if defined(TOOLKIT_GTK) BrowserWindowGtk::RegisterUserPrefs(user_prefs); #endif diff --git a/chrome/browser/views/browser_actions_container.cc b/chrome/browser/views/browser_actions_container.cc index edea4e0..6aaa387 100644 --- a/chrome/browser/views/browser_actions_container.cc +++ b/chrome/browser/views/browser_actions_container.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -6,9 +6,11 @@ #include "app/gfx/canvas.h" #include "app/resource_bundle.h" +#include "app/slide_animation.h" #include "base/stl_util-inl.h" #include "base/string_util.h" #include "chrome/browser/browser.h" +#include "chrome/browser/browser_theme_provider.h" #include "chrome/browser/browser_window.h" #include "chrome/browser/extensions/extension_browser_event_router.h" #include "chrome/browser/extensions/extensions_service.h" @@ -16,20 +18,25 @@ #include "chrome/browser/renderer_host/render_widget_host_view.h" #include "chrome/browser/profile.h" #include "chrome/browser/view_ids.h" +#include "chrome/browser/views/detachable_toolbar_view.h" #include "chrome/browser/views/extensions/extension_popup.h" #include "chrome/browser/views/toolbar_view.h" #include "chrome/common/notification_source.h" #include "chrome/common/notification_type.h" +#include "chrome/common/pref_names.h" #include "grit/app_resources.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkTypeface.h" #include "third_party/skia/include/effects/SkGradientShader.h" +#include "views/controls/button/menu_button.h" #include "views/controls/button/text_button.h" +#include "grit/theme_resources.h" + // The size (both dimensions) of the buttons for page actions. static const int kButtonSize = 29; -// The padding between the browser actions and the omnibox/page menu. +// The padding between the browser actions and the OmniBox/page menu. static const int kHorizontalPadding = 4; // The padding between browser action buttons. Visually, the actual number of @@ -42,10 +49,20 @@ static const int kBrowserActionButtonPadding = 3; // can draw the badge outside the visual bounds of the container. static const int kControlVertOffset = 6; -// The maximum of the minimum number of browser actions present when there is -// not enough space to fit all the browser actions in the toolbar. -static const int kMinimumNumberOfVisibleBrowserActions = 2; +// The margin between the divider and the chrome menu buttons. +static const int kDividerHorizontalMargin = 2; + +// The padding above and below the divider. +static const int kDividerVerticalPadding = 9; + +// The margin above the chevron. +static const int kChevronTopMargin = 9; + +// The margin to the right of the chevron. +static const int kChevronRightMargin = 4; +// Extra hit-area for the resize gripper. +static const int kExtraResizeArea = 4; //////////////////////////////////////////////////////////////////////////////// // BrowserActionButton @@ -130,6 +147,9 @@ void BrowserActionButton::Observe(NotificationType type, const NotificationDetails& details) { if (type == NotificationType::EXTENSION_BROWSER_ACTION_UPDATED) { UpdateState(); + // The browser action may have become visible/hidden so we need to make + // sure the state gets updated. + panel_->OnBrowserActionVisibilityChanged(); } else { NOTREACHED() << L"Received unexpected notification"; } @@ -239,7 +259,6 @@ void BrowserActionView::PaintChildren(gfx::Canvas* canvas) { action->PaintBadge(canvas, gfx::Rect(width(), height()), tab_id); } - //////////////////////////////////////////////////////////////////////////////// // BrowserActionsContainer @@ -249,6 +268,11 @@ BrowserActionsContainer::BrowserActionsContainer( toolbar_(toolbar), popup_(NULL), popup_button_(NULL), + resize_gripper_(NULL), + chevron_(NULL), + suppress_chevron_(false), + resize_amount_(0), + animation_target_size_(0), ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) { ExtensionsService* extension_service = profile->GetExtensionsService(); if (!extension_service) // The |extension_service| can be NULL in Incognito. @@ -263,8 +287,25 @@ BrowserActionsContainer::BrowserActionsContainer( registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, Source<Profile>(profile_)); - for (size_t i = 0; i < extension_service->extensions()->size(); ++i) - AddBrowserAction(extension_service->extensions()->at(i)); + resize_animation_.reset(new SlideAnimation(this)); + + resize_gripper_ = new views::ResizeGripper(this); + resize_gripper_->SetVisible(false); + AddChildView(resize_gripper_); + + // TODO(glen): Come up with a new bitmap for the chevron. + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + SkBitmap* chevron_image = rb.GetBitmapNamed(IDR_BOOKMARK_BAR_CHEVRONS); + chevron_ = new views::MenuButton(NULL, std::wstring(), this, false); + chevron_->SetVisible(false); + chevron_->SetIcon(*chevron_image); + // Chevron contains >> that should point left in LTR locales. + chevron_->EnableCanvasFlippingForRTLUI(true); + AddChildView(chevron_); + + int predefined_width = + profile_->GetPrefs()->GetInteger(prefs::kBrowserActionContainerWidth); + container_size_ = gfx::Size(predefined_width, kButtonSize); SetID(VIEW_ID_BROWSER_ACTION_TOOLBAR); } @@ -274,7 +315,12 @@ BrowserActionsContainer::~BrowserActionsContainer() { DeleteBrowserActionViews(); } -int BrowserActionsContainer::GetCurrentTabId() { +// Static. +void BrowserActionsContainer::RegisterUserPrefs(PrefService* prefs) { + prefs->RegisterIntegerPref(prefs::kBrowserActionContainerWidth, 0); +} + +int BrowserActionsContainer::GetCurrentTabId() const { TabContents* tab_contents = toolbar_->browser()->GetSelectedTabContents(); if (!tab_contents) return -1; @@ -310,11 +356,40 @@ void BrowserActionsContainer::AddBrowserAction(Extension* extension) { if (!extension->browser_action()) return; + // Before we change anything, determine the number of visible browser actions. + size_t visible_actions = 0; + for (size_t i = 0; i < browser_action_views_.size(); ++i) { + if (browser_action_views_[i]->IsVisible()) + ++visible_actions; + } + + // Add the new browser action to the vector and the view hierarchy. BrowserActionView* view = new BrowserActionView(extension, this); browser_action_views_.push_back(view); AddChildView(view); - if (GetParent()) - GetParent()->SchedulePaint(); + + // For details on why we do the following see the class comments in the + // header. + + // Determine if we need to increase (we only do that if the container was + // showing all icons before the addition of this icon). We use -1 because + // we don't want to count the view that we just added. + if (visible_actions < browser_action_views_.size() - 1) { + // Some icons were hidden, don't increase the size of the container. + OnBrowserActionVisibilityChanged(); + } else { + // Container was at max, increase the size of it by one icon. + animation_target_size_ = IconCountToWidth(visible_actions + 1); + + // We don't want the chevron to appear while we animate. See documentation + // in the header for why we do this. + suppress_chevron_ = !chevron_->IsVisible(); + + // Animate! + resize_animation_->Reset(); + resize_animation_->SetTweenType(SlideAnimation::NONE); + resize_animation_->Show(); + } } void BrowserActionsContainer::RemoveBrowserAction(Extension* extension) { @@ -325,6 +400,13 @@ void BrowserActionsContainer::RemoveBrowserAction(Extension* extension) { HidePopup(); } + // Before we change anything, determine the number of visible browser actions. + int visible_actions = 0; + for (size_t i = 0; i < browser_action_views_.size(); ++i) { + if (browser_action_views_[i]->IsVisible()) + ++visible_actions; + } + for (std::vector<BrowserActionView*>::iterator iter = browser_action_views_.begin(); iter != browser_action_views_.end(); ++iter) { @@ -332,8 +414,22 @@ void BrowserActionsContainer::RemoveBrowserAction(Extension* extension) { RemoveChildView(*iter); delete *iter; browser_action_views_.erase(iter); - if (GetParent()) - GetParent()->SchedulePaint(); + + // For details on why we do the following see the class comments in the + // header. + + // Calculate the target size we'll animate to (end state). This might be + // the same size (if the icon we are removing is in the overflow bucket + // and there are other icons there). We don't decrement visible_actions + // because we want the container to stay the same size (clamping will take + // care of shrinking the container if there aren't enough icons to show). + animation_target_size_ = + ClampToNearestIconCount(IconCountToWidth(visible_actions)); + + // Animate! + resize_animation_->Reset(); + resize_animation_->SetTweenType(SlideAnimation::EASE_OUT); + resize_animation_->Show(); return; } } @@ -350,13 +446,16 @@ void BrowserActionsContainer::DeleteBrowserActionViews() { } void BrowserActionsContainer::OnBrowserActionVisibilityChanged() { + resize_gripper_->SetVisible(browser_action_views_.size() > 0); + toolbar_->Layout(); + toolbar_->SchedulePaint(); } void BrowserActionsContainer::HidePopup() { if (popup_) { // This sometimes gets called via a timer (See BubbleLostFocus), so clear - // the task factory. in case one is pending. + // the task factory in case one is pending. task_factory_.RevokeAll(); // Save these variables in local temporaries since destroying the popup @@ -427,27 +526,107 @@ void BrowserActionsContainer::OnBrowserActionExecuted( gfx::Size BrowserActionsContainer::GetPreferredSize() { if (browser_action_views_.empty()) return gfx::Size(0, 0); - int width = kHorizontalPadding * 2 + - browser_action_views_.size() * kButtonSize; - if (browser_action_views_.size() > 1) - width += (browser_action_views_.size() - 1) * kBrowserActionButtonPadding; + + // We calculate the size of the view by taking the current width and + // subtracting resize_amount_ (the latter represents how far the user is + // resizing the view or, if animating the snapping, how far to animate it). + // But we also clamp it to a minimum size and the maximum size, so that the + // container can never shrink too far or take up more space than it needs. In + // other words: ContainerMinSize() < width() - resize < ClampTo(MAX). + int width = std::max(ContainerMinSize(), + container_size_.width() - resize_amount_); + int max_width = ClampToNearestIconCount(-1); // -1 gives max width. + width = std::min(width, max_width); + return gfx::Size(width, kButtonSize); } void BrowserActionsContainer::Layout() { + if (!resize_gripper_ || !chevron_) + return; // These classes are not created in Incognito mode. + if (browser_action_views_.size() == 0) { + resize_gripper_->SetVisible(false); + chevron_->SetVisible(false); + return; + } + + int x = 0; + if (resize_gripper_->IsVisible()) { + // We'll draw the resize gripper a little wider, to add some invisible hit + // target area - but we don't account for it anywhere. + gfx::Size sz = resize_gripper_->GetPreferredSize(); + resize_gripper_->SetBounds(x, (height() - sz.height()) / 2 + 1, + sz.width() + kExtraResizeArea, sz.height()); + x += sz.width(); + } + + x += kHorizontalPadding; + + // Calculate if all icons fit without showing the chevron. We need to know + // this beforehand, because showing the chevron will decrease the space that + // we have to draw the visible ones (ie. if one icon is visible and another + // doesn't have enough room). + int last_x_of_icons = x + + (browser_action_views_.size() * kButtonSize) + + ((browser_action_views_.size() - 1) * + kBrowserActionButtonPadding); + + int max_x = width() - kDividerHorizontalMargin - kChevronRightMargin; + + // If they don't all fit, show the chevron (unless suppressed). + gfx::Size chevron_size; + if (last_x_of_icons >= max_x && !suppress_chevron_) { + chevron_->SetVisible(true); + chevron_size = chevron_->GetPreferredSize(); + max_x -= chevron_size.width(); + chevron_->SetBounds(width() - chevron_size.width() - kChevronRightMargin, + kChevronTopMargin, + chevron_size.width(), chevron_size.height()); + } else { + chevron_->SetVisible(false); + } + + // Now draw the icons for the browser actions in the available space. for (size_t i = 0; i < browser_action_views_.size(); ++i) { BrowserActionView* view = browser_action_views_[i]; - int x = kHorizontalPadding + - i * (kButtonSize + kBrowserActionButtonPadding); - if (x + kButtonSize <= width()) { + // Add padding between buttons if multiple buttons. + int padding = (i > 0) ? kBrowserActionButtonPadding : 0; + if (x + kButtonSize + padding < max_x) { + x += padding; view->SetBounds(x, 0, kButtonSize, height()); view->SetVisible(true); + x += kButtonSize; } else { view->SetVisible(false); } } } +void BrowserActionsContainer::Paint(gfx::Canvas* canvas) { + // The one pixel themed vertical divider to the right of the browser actions. + DetachableToolbarView::PaintVerticalDivider( + canvas, + width() - kDividerHorizontalMargin, height(), kDividerVerticalPadding, + DetachableToolbarView::kEdgeDividerColor, + DetachableToolbarView::kMiddleDividerColor, + GetThemeProvider()->GetColor(BrowserThemeProvider::COLOR_TOOLBAR)); +} + +void BrowserActionsContainer::ViewHierarchyChanged(bool is_add, + views::View* parent, + views::View* child) { + if (is_add && child == this) { + // We do this here instead of in the constructor because AddBrowserAction + // calls Layout on the Toolbar, which needs this object to be constructed + // before its Layout function is called. + ExtensionsService* extension_service = profile_->GetExtensionsService(); + if (!extension_service) + return; // The |extension_service| can be NULL in Incognito. + for (size_t i = 0; i < extension_service->extensions()->size(); ++i) + AddBrowserAction(extension_service->extensions()->at(i)); + } +} + void BrowserActionsContainer::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { @@ -518,19 +697,110 @@ void BrowserActionsContainer::BubbleLostFocus(BrowserBubble* bubble, task_factory_.NewRunnableMethod(&BrowserActionsContainer::HidePopup)); } -int BrowserActionsContainer::GetClippedPreferredWidth(int available_width) { - if (browser_action_views_.size() == 0) - return 0; +void BrowserActionsContainer::RunMenu(View* source, const gfx::Point& pt) { + // TODO(finnur): Show menu for all the hidden icons. +} + +int BrowserActionsContainer::ClampToNearestIconCount(int pixelWidth) const { + // Calculate the width of one icon. + int icon_width = (kButtonSize + kBrowserActionButtonPadding); + + // Calculate pixel count for the area not used by the icons. + int extras = WidthOfNonIconArea(); + + size_t icon_count = 0u; + if (pixelWidth >= 0) { + // Caller wants to know how many icons fit within a given space so we start + // by subtracting the padding, gripper and dividers. + int icon_area = pixelWidth - extras; + icon_area = std::max(0, icon_area); + + // Make sure we never throw an icon into the chevron menu just because + // there isn't enough enough space for the invisible padding around buttons. + icon_area += kBrowserActionButtonPadding - 1; + + // Count the number of icons that fit within that area. + icon_count = icon_area / icon_width; + + // No use allowing more than what we have. + if (icon_count > browser_action_views_.size()) + icon_count = browser_action_views_.size(); + else if (icon_count == 0) + extras = ContainerMinSize(); // Allow very narrow width if no icons. + } else { + // A negative |pixels| count indicates caller wants to know the max width + // that fits all icons; + icon_count = browser_action_views_.size(); + } + + int returning = extras + (icon_count * icon_width); + return returning; +} + +int BrowserActionsContainer::WidthOfNonIconArea() const { + int chevron_size = (chevron_->IsVisible()) ? + chevron_->GetPreferredSize().width() : 0; + return resize_gripper_->GetPreferredSize().width() + kHorizontalPadding + + chevron_size + kChevronRightMargin + kDividerHorizontalMargin; +} + +int BrowserActionsContainer::IconCountToWidth(int icons) const { + DCHECK(icons >= 0); + if (icons == 0) + return ContainerMinSize(); + + int icon_width = kButtonSize + kBrowserActionButtonPadding; + + return WidthOfNonIconArea() + (icons * icon_width); +} + +int BrowserActionsContainer::ContainerMinSize() const { + return resize_gripper_->width() + chevron_->width() + kChevronRightMargin; +} + +void BrowserActionsContainer::OnResize(int resize_amount, bool done_resizing) { + if (!done_resizing) { + resize_amount_ = resize_amount; + OnBrowserActionVisibilityChanged(); + } else { + // For details on why we do the following see the class comments in the + // header. + + // Clamp lower limit to 0 and upper limit to the amount that allows enough + // room for all icons to show. + int new_width = std::max(0, container_size_.width() - resize_amount); + int max_width = ClampToNearestIconCount(-1); + new_width = std::min(new_width, max_width); + + // Up until now we've only been modifying the resize_amount, but now it is + // time to set the container size to the size we have resized to, but then + // animate to the nearest icon count size (or down to min size if no icon). + container_size_.set_width(new_width); + animation_target_size_ = ClampToNearestIconCount(new_width); + resize_animation_->Reset(); + resize_animation_->SetTweenType(SlideAnimation::EASE_OUT); + resize_animation_->Show(); + } +} + +void BrowserActionsContainer::AnimationProgressed(const Animation* animation) { + DCHECK(animation == resize_animation_.get()); + + double e = resize_animation_->GetCurrentValue(); + int difference = container_size_.width() - animation_target_size_; - // We have at least one browser action. Make some of them sticky. - int min_width = kHorizontalPadding * 2 + - std::min(static_cast<int>(browser_action_views_.size()), - kMinimumNumberOfVisibleBrowserActions) * kButtonSize; + resize_amount_ = static_cast<int>(e * difference); + + OnBrowserActionVisibilityChanged(); +} - // Even if available_width is <= 0, we still return at least the |min_width|. - if (available_width <= 0) - return min_width; +void BrowserActionsContainer::AnimationEnded(const Animation* animation) { + container_size_.set_width(animation_target_size_); + animation_target_size_ = 0; + resize_amount_ = 0; + OnBrowserActionVisibilityChanged(); + suppress_chevron_ = false; - return std::max(min_width, available_width - available_width % kButtonSize + - kHorizontalPadding * 2); + profile_->GetPrefs()->SetInteger(prefs::kBrowserActionContainerWidth, + container_size_.width()); } diff --git a/chrome/browser/views/browser_actions_container.h b/chrome/browser/views/browser_actions_container.h index 7a6daf3..d2b87a4 100644 --- a/chrome/browser/views/browser_actions_container.h +++ b/chrome/browser/views/browser_actions_container.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -14,13 +14,17 @@ #include "chrome/common/notification_observer.h" #include "chrome/common/notification_registrar.h" #include "views/controls/button/menu_button.h" +#include "views/controls/menu/view_menu_delegate.h" +#include "views/controls/resize_gripper.h" #include "views/view.h" class BrowserActionsContainer; class Extension; class ExtensionAction; class ExtensionPopup; +class PrefService; class Profile; +class SlideAnimation; class ToolbarView; //////////////////////////////////////////////////////////////////////////////// @@ -132,26 +136,103 @@ class BrowserActionView : public views::View { BrowserActionButton* button_; }; - //////////////////////////////////////////////////////////////////////////////// // // The BrowserActionsContainer is a container view, responsible for drawing the -// icons that represent browser actions (extensions that add icons to the -// toolbar). +// browser action icons (extensions that add icons to the toolbar). +// +// The BrowserActionsContainer (when it contains one or more icons) consists of +// the following elements, numbered as seen below the line: +// +// || _ Icon _ Icon _ Icon _ [chevron] _ | _ +// ----------------------------------------- +// 1 2 3 4 5 6 7 8 +// +// 1) The ResizeGripper view. +// 2) Padding (kHorizontalPadding). +// 3) The browser action icon button (BrowserActionView). +// 4) Padding to visually separate icons from one another +// (kBrowserActionButtonPadding). Not included if only one icon visible. +// 5) The chevron menu (MenuButton), shown when there is not enough room to show +// all the icons. +// 6) Padding (kDividerHorizontalMargin). +// 7) A thin vertical divider drawn during Paint to create visual separation for +// the container from the Page and Wrench menus. +// 8) Padding (kChevronRightMargin). +// +// The BrowserActionsContainer follows a few rules, in terms of user experience: +// +// 1) The container can never grow beyond the space needed to show all icons +// (hereby referred to as the max width). +// 2) The container can never shrink below the space needed to show just the +// resize gripper and the chevron (ignoring the case where there are no icons to +// show, in which case the container won't be visible anyway). +// 3) The container snaps into place (to the pixel count that fits the visible +// icons) to make sure there is no wasted space at the edges of the container. +// 4) If the user adds or removes icons (read: installs/uninstalls browser +// actions) we grow and shrink the container as needed - but ONLY if the +// container was at max width to begin with. +// 5) If the container is NOT at max width (has an overflow menu), we respect +// that size when adding and removing icons and DON'T grow/shrink the container. +// This means that new icons (which always appear at the far right) will show up +// in the overflow menu. The install bubble for extensions points to the chevron +// menu in this case. +// +// Resizing the BrowserActionsContainer: +// +// The ResizeGripper view sends OnResize messages to the BrowserActionsContainer +// class as the user drags the gripper. This modifies the value for +// |resize_amount_|. That indicates to the container that a resize is in +// progress and is used to calculate the size in GetPreferredSize(), though +// that function never exceeds the defined minimum and maximum size of the +// container. +// +// When the user releases the mouse (ends the resize), we calculate a target +// size for the container (animation_target_size_), clamp that value to the +// containers min and max and then animate from the *current* position (that the +// user has dragged the view to) to the target size. +// +// Animating the BrowserActionsContainer: +// +// Animations are used when snapping the container to a value that fits all +// visible icons. This can be triggered when the user finishes resizing the +// container or when Browser Actions are added/removed. +// +// We always animate from the current width (container_size_.width()) to the +// target size (animation_target_size_), using |resize_amount| to keep track of +// the animation progress. +// +// NOTE: When adding Browser Actions to a maximum width container (no overflow) +// we make sure to suppress the chevron menu if it wasn't visible. This is +// because we won't have enough space to show the new Browser Action until the +// animation ends and we don't want the chevron to flash into view while we are +// growing the container. // //////////////////////////////////////////////////////////////////////////////// -class BrowserActionsContainer : public views::View, - public NotificationObserver, - public BrowserBubble::Delegate { +class BrowserActionsContainer + : public views::View, + public NotificationObserver, + public BrowserBubble::Delegate, + public views::ViewMenuDelegate, + public views::ResizeGripper::ResizeGripperDelegate, + public AnimationDelegate { public: BrowserActionsContainer(Profile* profile, ToolbarView* toolbar); virtual ~BrowserActionsContainer(); + static void RegisterUserPrefs(PrefService* prefs); + // Get the number of browser actions being displayed. - int num_browser_actions() { return browser_action_views_.size(); } + int num_browser_actions() const { return browser_action_views_.size(); } + + // Whether we are performing resize animation on the container. + bool animating() const { return animation_target_size_ > 0; } + + // Returns the chevron, if any. + const views::View* chevron() const { return chevron_; } // Returns the current tab's ID, or -1 if there is no current tab. - int GetCurrentTabId(); + int GetCurrentTabId() const; // Get a particular browser action view. BrowserActionView* GetBrowserActionViewAt(int index) { @@ -176,6 +257,10 @@ class BrowserActionsContainer : public views::View, // Overridden from views::View: virtual gfx::Size GetPreferredSize(); virtual void Layout(); + virtual void Paint(gfx::Canvas* canvas); + virtual void ViewHierarchyChanged(bool is_add, + views::View* parent, + views::View* child); // Overridden from NotificationObserver: virtual void Observe(NotificationType type, @@ -189,11 +274,15 @@ class BrowserActionsContainer : public views::View, virtual void BubbleLostFocus(BrowserBubble* bubble, gfx::NativeView focused_view); - // Get clipped width required to precisely fit the browser action icons - // given a tentative available width. The minimum size it returns is not - // zero, but depends on the minimum number of icons that have to be there - // by default irrespective of the available space to draw them. - int GetClippedPreferredWidth(int available_width); + // Overridden from views::ViewMenuDelegate: + virtual void RunMenu(View* source, const gfx::Point& pt); + + // Overridden from ResizeGripper::ResizeGripperDelegate: + virtual void OnResize(int resize_amount, bool done_resizing); + + // Overridden from AnimationDelegate: + virtual void AnimationProgressed(const Animation* animation); + virtual void AnimationEnded(const Animation* animation); // Hide the current popup. void HidePopup(); @@ -214,6 +303,24 @@ class BrowserActionsContainer : public views::View, // no such view. void RemoveBrowserAction(Extension* extension); + // Takes a width in pixels, calculates how many icons fit within that space + // (up to the maximum number of icons in our vector) and shaves off the + // excess pixels. + int ClampToNearestIconCount(int pixels) const; + + // Calculates the width of the container area NOT used to show the icons (the + // controls to the left and to the right of the icons). + int WidthOfNonIconArea() const; + + // Given a number of |icons| return the amount of pixels needed to draw it, + // including the controls (chevron if visible and resize gripper). + int IconCountToWidth(int icons) const; + + // Returns the absolute minimum size you can shrink the container down to and + // still show it. We account for the chevron and the resize gripper, but not + // all the padding that we normally show if there are icons. + int ContainerMinSize() const; + // The vector of browser actions (icons/image buttons for each action). std::vector<BrowserActionView*> browser_action_views_; @@ -231,6 +338,30 @@ class BrowserActionsContainer : public views::View, // from browser_action_views_). BrowserActionButton* popup_button_; + // The current size of the container. + gfx::Size container_size_; + + // The resize gripper for the container. + views::ResizeGripper* resize_gripper_; + + // The chevron for accessing the overflow items. + views::MenuButton* chevron_; + + // The animation that happens when the container snaps to place. + scoped_ptr<SlideAnimation> resize_animation_; + + // Don't show the chevron while animating. + bool suppress_chevron_; + + // This is used while the user is resizing (and when the animations are in + // progress) to know how wide the delta is between the current state and what + // we should draw. + int resize_amount_; + + // Keeps track of the absolute pixel width the container should have when we + // are done animating. + int animation_target_size_; + ScopedRunnableMethodFactory<BrowserActionsContainer> task_factory_; DISALLOW_COPY_AND_ASSIGN(BrowserActionsContainer); diff --git a/chrome/browser/views/detachable_toolbar_view.h b/chrome/browser/views/detachable_toolbar_view.h index d27ee53..7d49c9b 100644 --- a/chrome/browser/views/detachable_toolbar_view.h +++ b/chrome/browser/views/detachable_toolbar_view.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -66,9 +66,13 @@ class DetachableToolbarView : public AccessibleToolbarView { const SkRect& rect, double roundness); - // Paint a themed gradient divider at location |x|. The color of the divider - // is a gradient starting with |top_color| at the top, and changing into - // |middle_color| and then over to |bottom_color| as you go further down. + // Paint a themed gradient divider at location |x|. |height| is the full + // height of the view you want to paint the divider into, not the height of + // the divider. The height of the divider will become: + // |height| - 2 * |vertical_padding|. + // The color of the divider is a gradient starting with |top_color| at the + // top, and changing into |middle_color| and then over to |bottom_color| as + // you go further down. static void PaintVerticalDivider(gfx::Canvas* canvas, int x, int height, diff --git a/chrome/browser/views/extensions/extension_installed_bubble.cc b/chrome/browser/views/extensions/extension_installed_bubble.cc index 4d903ec..7f92bbc 100644 --- a/chrome/browser/views/extensions/extension_installed_bubble.cc +++ b/chrome/browser/views/extensions/extension_installed_bubble.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -46,6 +46,12 @@ const int kCloseButtonPadding = 3; // 4px to align with icon. const int kRightcolumnVerticalShift = -4; +// How long to wait for browser action animations to complete before retrying. +const int kAnimationWaitTime = 50; + +// How often we retry when waiting for browser action animation to end. +const int kAnimationWaitMaxRetry = 10; + // InstalledBubbleContent is the content view which is placed in the // ExtensionInstalledBubble. It displays the install icon and explanatory // text about the installed extension. @@ -188,7 +194,8 @@ ExtensionInstalledBubble::ExtensionInstalledBubble(Extension *extension, SkBitmap icon) : extension_(extension), browser_(browser), - icon_(icon) { + icon_(icon), + animation_wait_retries_(0) { AddRef(); // Balanced in InfoBubbleClosing. if (extension_->browser_action()) { @@ -215,6 +222,7 @@ void ExtensionInstalledBubble::Observe(NotificationType type, if (type == NotificationType::EXTENSION_LOADED) { Extension* extension = Details<Extension>(details).ptr(); if (extension == extension_) { + animation_wait_retries_ = 0; // PostTask to ourself to allow all EXTENSION_LOADED Observers to run. MessageLoopForUI::current()->PostTask(FROM_HERE, NewRunnableMethod(this, &ExtensionInstalledBubble::ShowInternal)); @@ -228,10 +236,24 @@ void ExtensionInstalledBubble::ShowInternal() { BrowserView* browser_view = BrowserView::GetBrowserViewForNativeWindow( browser_->window()->GetNativeHandle()); - views::View* reference_view = NULL; + const views::View* reference_view = NULL; if (type_ == BROWSER_ACTION) { - reference_view = browser_view->GetToolbarView()->browser_actions() - ->GetBrowserActionView(extension_); + BrowserActionsContainer* container = + browser_view->GetToolbarView()->browser_actions(); + if (container->animating() && + animation_wait_retries_++ < kAnimationWaitMaxRetry) { + // We don't know where the view will be until the container has stopped + // animating, so check back in a little while. + MessageLoopForUI::current()->PostDelayedTask( + FROM_HERE, NewRunnableMethod(this, + &ExtensionInstalledBubble::ShowInternal), kAnimationWaitTime); + return; + } + reference_view = container->GetBrowserActionView(extension_); + // If the view is not visible then it is in the chevron, so point the + // install bubble to the chevron instead. + if (!reference_view->IsVisible()) + reference_view = container->chevron(); DCHECK(reference_view); } else if (type_ == PAGE_ACTION) { LocationBarView* location_bar_view = browser_view->GetLocationBarView(); diff --git a/chrome/browser/views/extensions/extension_installed_bubble.h b/chrome/browser/views/extensions/extension_installed_bubble.h index 3c9f118..53c68e5 100644 --- a/chrome/browser/views/extensions/extension_installed_bubble.h +++ b/chrome/browser/views/extensions/extension_installed_bubble.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -75,6 +75,9 @@ class ExtensionInstalledBubble NotificationRegistrar registrar_; BubbleType type_; + // How many times we've deferred due to animations being in progress. + int animation_wait_retries_; + DISALLOW_COPY_AND_ASSIGN(ExtensionInstalledBubble); }; diff --git a/chrome/browser/views/location_bar_view.cc b/chrome/browser/views/location_bar_view.cc index e7a85f3..03a17f9 100644 --- a/chrome/browser/views/location_bar_view.cc +++ b/chrome/browser/views/location_bar_view.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -354,6 +354,7 @@ views::View* LocationBarView::GetPageActionView( } return NULL; } + gfx::Size LocationBarView::GetPreferredSize() { return gfx::Size(0, (popup_window_mode_ ? kPopupBackground : kBackground)->height()); @@ -1372,7 +1373,7 @@ bool LocationBarView::PageActionImageView::OnMousePressed( button = 2; } else if (event.IsRightMouseButton()) { // Get the top left point of this button in screen coordinates. - gfx::Point point = gfx::Point(0,0); + gfx::Point point = gfx::Point(0, 0); ConvertPointToScreen(this, &point); // Make the menu appear below the button. diff --git a/chrome/browser/views/location_bar_view.h b/chrome/browser/views/location_bar_view.h index 3319c39..cc7fb215 100644 --- a/chrome/browser/views/location_bar_view.h +++ b/chrome/browser/views/location_bar_view.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -403,7 +403,7 @@ class LocationBarView : public LocationBar, // is the current page URL. void UpdateVisibility(TabContents* contents, const GURL& url); - // Either notify listners or show a popup depending on the page action. + // Either notify listeners or show a popup depending on the page action. void ExecuteAction(int button); private: diff --git a/chrome/browser/views/toolbar_view.cc b/chrome/browser/views/toolbar_view.cc index 71037bb..1ff6636 100644 --- a/chrome/browser/views/toolbar_view.cc +++ b/chrome/browser/views/toolbar_view.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -62,9 +62,6 @@ static const int kStatusBubbleWidth = 480; // Separation between the location bar and the menus. static const int kMenuButtonOffset = 3; -// The minimum width of the location bar when browser actions are visible. -static const int kMinLocationBarWidthWithBrowserActions = 400; - // Padding to the right of the location bar static const int kPaddingRight = 2; @@ -402,20 +399,6 @@ void ToolbarView::Layout() { app_menu_width - page_menu_width - browser_actions_width - kMenuButtonOffset - go_button_width - location_x; - // We wait until the width of location bar is a minimum allowed. After this - // state, the width available for the browser actions is compromised until - // it can hold a minimum number of browser actions (currently 2). After this - // state, the location bar width starts shrinking again, with the minimum - // number of browser actions sticking on the the right of the location bar. - // TODO(sidchat): Use percentage width instead of fixed width to determine - // minimum width of the location bar. BUG=24316. - if (available_width < kMinLocationBarWidthWithBrowserActions && - browser_actions_width > 0) { - available_width += browser_actions_width; - browser_actions_width = browser_actions_->GetClippedPreferredWidth( - available_width - kMinLocationBarWidthWithBrowserActions); - available_width -= browser_actions_width; - } location_bar_->SetBounds(location_x, child_y, std::max(available_width, 0), child_height); |