diff options
author | pkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-29 20:19:24 +0000 |
---|---|---|
committer | pkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-29 20:19:24 +0000 |
commit | fce1fb3963292596d548990fe0783d7c01bfdd48 (patch) | |
tree | 396c225ffd091e6aa48f99ba8dfa28b14f7cb98e | |
parent | c512b99ea3cb3d7c275850988336804d46f4d529 (diff) | |
download | chromium_src-fce1fb3963292596d548990fe0783d7c01bfdd48.zip chromium_src-fce1fb3963292596d548990fe0783d7c01bfdd48.tar.gz chromium_src-fce1fb3963292596d548990fe0783d7c01bfdd48.tar.bz2 |
Browser actions container layout changes for M6 theme.
In short, this:
* Eliminates the divider on the right (the new chevron has a built-in divider)
* Changes the padding between items (see updated comments in header for precise layout details)
* Updates the imagery for the new theme
* Makes the chevron respond to theme changes
BUG=50107
TEST=none
Review URL: http://codereview.chromium.org/3057016
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@54174 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/views/browser_actions_container.cc | 479 | ||||
-rw-r--r-- | chrome/browser/views/browser_actions_container.h | 75 | ||||
-rw-r--r-- | chrome/browser/views/toolbar_view.cc | 1 |
3 files changed, 278 insertions, 277 deletions
diff --git a/chrome/browser/views/browser_actions_container.cc b/chrome/browser/views/browser_actions_container.cc index 98cea22..3a1b5af 100644 --- a/chrome/browser/views/browser_actions_container.cc +++ b/chrome/browser/views/browser_actions_container.cc @@ -24,6 +24,7 @@ #include "chrome/browser/views/detachable_toolbar_view.h" #include "chrome/browser/views/extensions/browser_action_drag_data.h" #include "chrome/browser/views/extensions/extension_popup.h" +#include "chrome/browser/views/toolbar_view.h" #include "chrome/common/extensions/extension_action.h" #include "chrome/common/extensions/extension_resource.h" #include "chrome/common/notification_source.h" @@ -44,47 +45,13 @@ #include "grit/theme_resources.h" -namespace { +// Horizontal spacing between most items in the container, as well as after the +// last item or chevron (if visible). +static const int kItemSpacing = ToolbarView::kStandardSpacing; +// Horizontal spacing before the chevron (if visible). +static const int kChevronSpacing = kItemSpacing - 2; -// 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. -static const int kHorizontalPadding = 4; -static const int kHorizontalPaddingRtl = 8; - -// The padding between browser action buttons. Visually, the actual number of -// empty (non-drawing) pixels is this value + 2 when adjacent browser icons -// use their maximum allowed size. -static const int kBrowserActionButtonPadding = 3; - -// This is the same value from toolbar.cc. We position the browser actions -// container flush with the edges of the toolbar as a special case so that we -// can draw the badge outside the visual bounds of the container. -static const int kControlVertOffset = 6; - -// 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; - -// Width for the resize area. -static const int kResizeAreaWidth = 4; - -// The x offset for the drop indicator (how much we shift it by). -static const int kDropIndicatorOffsetLtr = 3; -static const int kDropIndicatorOffsetRtl = 9; - -} // namespace. - -// Static. +// static bool BrowserActionsContainer::disable_animations_during_testing_ = false; //////////////////////////////////////////////////////////////////////////////// @@ -99,6 +66,7 @@ BrowserActionButton::BrowserActionButton(Extension* extension, ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)), showing_context_menu_(false), panel_(panel) { + set_border(NULL); set_alignment(TextButton::ALIGN_CENTER); // No UpdateState() here because View hierarchy not setup yet. Our parent @@ -154,11 +122,40 @@ void BrowserActionButton::UpdateState() { if (tab_id < 0) return; - SkBitmap image = browser_action()->GetIcon(tab_id); - if (!image.isNull()) - SetIcon(image); - else if (!default_icon_.isNull()) - SetIcon(default_icon_); + SkBitmap icon(browser_action()->GetIcon(tab_id)); + if (icon.isNull()) + icon = default_icon_; + if (!icon.isNull()) { + SkPaint paint; + paint.setXfermode(SkXfermode::Create(SkXfermode::kSrcOver_Mode)); + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + + SkBitmap bg; + rb.GetBitmapNamed(IDR_BROWSER_ACTION)->copyTo(&bg, + SkBitmap::kARGB_8888_Config); + SkCanvas bg_canvas(bg); + bg_canvas.drawBitmap(icon, SkIntToScalar((bg.width() - icon.width()) / 2), + SkIntToScalar((bg.height() - icon.height()) / 2), &paint); + SetIcon(bg); + + SkBitmap bg_h; + rb.GetBitmapNamed(IDR_BROWSER_ACTION_H)->copyTo(&bg_h, + SkBitmap::kARGB_8888_Config); + SkCanvas bg_h_canvas(bg_h); + bg_h_canvas.drawBitmap(icon, + SkIntToScalar((bg_h.width() - icon.width()) / 2), + SkIntToScalar((bg_h.height() - icon.height()) / 2), &paint); + SetHoverIcon(bg_h); + + SkBitmap bg_p; + rb.GetBitmapNamed(IDR_BROWSER_ACTION_P)->copyTo(&bg_p, + SkBitmap::kARGB_8888_Config); + SkCanvas bg_p_canvas(bg_p); + bg_p_canvas.drawBitmap(icon, + SkIntToScalar((bg_p.width() - icon.width()) / 2), + SkIntToScalar((bg_p.height() - icon.height()) / 2), &paint); + SetPushedIcon(bg_p); + } // If the browser action name is empty, show the extension name instead. std::wstring name = UTF8ToWide(browser_action()->GetTitle(tab_id)); @@ -195,7 +192,7 @@ bool BrowserActionButton::Activate() { if (!IsPopup()) return true; - panel_->OnBrowserActionExecuted(this, false); // |inspect_with_devtools|. + panel_->OnBrowserActionExecuted(this, false); // TODO(erikkay): Run a nested modal loop while the mouse is down to // enable menu-like drag-select behavior. @@ -306,7 +303,7 @@ gfx::Canvas* BrowserActionView::GetIconWithBadge() { canvas->DrawBitmapInt(icon, 0, 0); if (tab_id >= 0) { - gfx::Rect bounds(icon.width(), icon.height() + kControlVertOffset); + gfx::Rect bounds(icon.width(), icon.height() + ToolbarView::kVertSpacing); button_->extension()->browser_action()->PaintBadge(canvas, bounds, tab_id); } @@ -320,7 +317,15 @@ bool BrowserActionView::GetAccessibleRole(AccessibilityTypes::Role* role) { } void BrowserActionView::Layout() { - button_->SetBounds(0, kControlVertOffset, width(), kButtonSize); + // We can't rely on button_->GetPreferredSize() here because that's not set + // correctly until the first call to + // BrowserActionsContainer::RefreshBrowserActionViews(), whereas this can be + // called before that when the initial bounds are set (and then not after, + // since the bounds don't change). So instead of setting the height from the + // button's preferred size, we use IconHeight(), since that's how big the + // button should be regardless of what it's displaying. + button_->SetBounds(0, ToolbarView::kVertSpacing, width(), + BrowserActionsContainer::IconHeight()); } void BrowserActionView::PaintChildren(gfx::Canvas* canvas) { @@ -342,6 +347,7 @@ BrowserActionsContainer::BrowserActionsContainer(Browser* browser, popup_(NULL), popup_button_(NULL), model_(NULL), + container_width_(0), chevron_(NULL), overflow_menu_(NULL), suppress_chevron_(false), @@ -362,32 +368,14 @@ BrowserActionsContainer::BrowserActionsContainer(Browser* browser, resize_area_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_SEPARATOR)); AddChildView(resize_area_); - // 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_->set_border(NULL); + chevron_->EnableCanvasFlippingForRTLUI(true); chevron_->SetAccessibleName( l10n_util::GetString(IDS_ACCNAME_EXTENSIONS_CHEVRON)); - // Chevron contains >> that should point left in LTR locales. - chevron_->EnableCanvasFlippingForRTLUI(true); + chevron_->SetVisible(false); AddChildView(chevron_); - if (model_ && - !profile_->GetPrefs()->HasPrefPath(prefs::kExtensionToolbarSize)) { - // Migration code to the new VisibleIconCount pref. - // TODO(mpcomplete): remove this after users are upgraded to 5.0. - int predefined_width = - profile_->GetPrefs()->GetInteger(prefs::kBrowserActionContainerWidth); - if (predefined_width != 0) { - model_->SetVisibleIconCount((predefined_width - WidthOfNonIconArea()) / - (kButtonSize + kBrowserActionButtonPadding)); - } - } - if (model_ && model_->extensions_initialized()) - SetContainerWidth(); - SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_EXTENSIONS)); } @@ -404,6 +392,24 @@ void BrowserActionsContainer::RegisterUserPrefs(PrefService* prefs) { prefs->RegisterIntegerPref(prefs::kBrowserActionContainerWidth, 0); } +void BrowserActionsContainer::Init() { + LoadImages(); + + // We wait to set the container width until now so that the chevron images + // will be loaded. The width calculation needs to know the chevron size. + if (model_ && + !profile_->GetPrefs()->HasPrefPath(prefs::kExtensionToolbarSize)) { + // Migration code to the new VisibleIconCount pref. + // TODO(mpcomplete): remove this after users are upgraded to 5.0. + int predefined_width = + profile_->GetPrefs()->GetInteger(prefs::kBrowserActionContainerWidth); + if (predefined_width != 0) + model_->SetVisibleIconCount(WidthToIconCount(predefined_width)); + } + if (model_ && model_->extensions_initialized()) + SetContainerWidth(); +} + int BrowserActionsContainer::GetCurrentTabId() const { TabContents* tab_contents = browser_->GetSelectedTabContents(); return tab_contents ? tab_contents->controller().session_id().id() : -1; @@ -510,7 +516,7 @@ void BrowserActionsContainer::OnBrowserActionExecuted( gfx::Size BrowserActionsContainer::GetPreferredSize() { if (browser_action_views_.empty()) - return gfx::Size(0, 0); + return gfx::Size(ToolbarView::kStandardSpacing, 0); // We calculate the size of the view by taking the current width and // subtracting resize_amount_ (the latter represents how far the user is @@ -520,58 +526,42 @@ gfx::Size BrowserActionsContainer::GetPreferredSize() { // other words: ContainerMinSize() < width() - resize < ClampTo(MAX). int clamped_width = std::min( std::max(ContainerMinSize(), container_width_ - resize_amount_), - ClampToNearestIconCount(-1, false)); - return gfx::Size(clamped_width, kButtonSize); + IconCountToWidth(-1, false)); + return gfx::Size(clamped_width, 0); } void BrowserActionsContainer::Layout() { if (browser_action_views_.empty()) { SetVisible(false); - chevron_->SetVisible(false); return; } SetVisible(true); + resize_area_->SetBounds(0, ToolbarView::kVertSpacing, kItemSpacing, + IconHeight()); - resize_area_->SetBounds(0, 0, kResizeAreaWidth, height()); - int x = kResizeAreaWidth; - - x += base::i18n::IsRTL() ? kHorizontalPaddingRtl : 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); - - gfx::Size sz = GetPreferredSize(); - int max_x = sz.width() - kDividerHorizontalMargin - kChevronRightMargin; - - // If they don't all fit, show the chevron (unless suppressed). - if (last_x_of_icons >= max_x && !suppress_chevron_) { + // If the icons don't all fit, show the chevron (unless suppressed). + int max_x = GetPreferredSize().width(); + if ((IconCountToWidth(-1, false) > max_x) && !suppress_chevron_) { chevron_->SetVisible(true); gfx::Size chevron_size(chevron_->GetPreferredSize()); - max_x -= chevron_size.width(); - chevron_->SetBounds(width() - chevron_size.width() - kChevronRightMargin, - kChevronTopMargin, - chevron_size.width(), chevron_size.height()); + max_x -= + ToolbarView::kStandardSpacing + chevron_size.width() + kChevronSpacing; + chevron_->SetBounds( + width() - ToolbarView::kStandardSpacing - chevron_size.width(), + ToolbarView::kVertSpacing, chevron_size.width(), chevron_size.height()); } else { chevron_->SetVisible(false); } // Now draw the icons for the browser actions in the available space. + int icon_width = IconWidth(false); for (size_t i = 0; i < browser_action_views_.size(); ++i) { BrowserActionView* view = browser_action_views_[i]; - // 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()); + int x = ToolbarView::kStandardSpacing + (i * IconWidth(true)); + if (x + icon_width <= max_x) { + view->SetBounds(x, 0, icon_width, height()); view->SetVisible(true); - x += kButtonSize; } else { view->SetVisible(false); } @@ -579,15 +569,6 @@ void BrowserActionsContainer::Layout() { } void BrowserActionsContainer::Paint(gfx::Canvas* canvas) { - // The one-pixel themed vertical divider to the right of the browser actions. - int x = base::i18n::IsRTL() ? - kDividerHorizontalMargin : (width() - kDividerHorizontalMargin); - DetachableToolbarView::PaintVerticalDivider( - canvas, x, height(), kDividerVerticalPadding, - DetachableToolbarView::kEdgeDividerColor, - DetachableToolbarView::kMiddleDividerColor, - GetThemeProvider()->GetColor(BrowserThemeProvider::COLOR_TOOLBAR)); - // TODO(sky/glen): Instead of using a drop indicator, animate the icons while // dragging (like we do for tab dragging). if (drop_indicator_position_ > -1) { @@ -595,8 +576,7 @@ void BrowserActionsContainer::Paint(gfx::Canvas* canvas) { static const int kDropIndicatorWidth = 2; gfx::Rect indicator_bounds( drop_indicator_position_ - (kDropIndicatorWidth / 2), - kDividerVerticalPadding, kDropIndicatorWidth, - height() - (2 * kDividerVerticalPadding)); + ToolbarView::kVertSpacing, kDropIndicatorWidth, IconHeight()); // Color of the drop indicator. static const SkColor kDropIndicatorColor = SK_ColorBLACK; @@ -653,30 +633,52 @@ int BrowserActionsContainer::OnDragUpdated( } StopShowFolderDropMenuTimer(); - // Modifying the x value before clamping affects how far you have to drag to - // get the drop indicator to shift to another position. Modifying after - // clamping affects where the drop indicator is drawn. - - // We add half a button size so that when you drag a button to the right and - // you are half-way dragging across a button the drop indicator moves from the - // left of that button to the right of that button. - int x = event.x() + (kButtonSize / 2) + (2 * kBrowserActionButtonPadding); - if (chevron_->IsVisible()) - x += chevron_->bounds().width(); - x = ClampToNearestIconCount(x, false); - - if (!base::i18n::IsRTL() && chevron_->IsVisible()) { - // The clamping function includes the chevron width. In LTR locales, the - // chevron is on the right and we never want to account for its width. In - // RTL it is on the left and we always want to count the width. - x -= chevron_->width(); - } + // Figure out where to display the indicator. This is a complex calculation: + + // First, we figure out how much space is to the left of the icon area, so we + // can calculate the true offset into the icon area. + int width_before_icons = ToolbarView::kStandardSpacing + + (base::i18n::IsRTL() ? + (chevron_->GetPreferredSize().width() + kChevronSpacing) : 0); + int offset_into_icon_area = event.x() - width_before_icons; + + // Next, we determine which icon to place the indicator in front of. We want + // to place the indicator in front of icon n when the cursor is between the + // midpoints of icons (n - 1) and n. To do this we take the offset into the + // icon area and transform it as follows: + // + // Real icon area: + // 0 a * b c + // | | | | + // |[IC|ON] [IC|ON] [IC|ON] + // We want to be before icon 0 for 0 < x <= a, icon 1 for a < x <= b, etc. + // Here the "*" represents the offset into the icon area, and since it's + // between a and b, we want to return "1". + // + // Transformed "icon area": + // 0 a * b c + // | | | | + // |[ICON] |[ICON] |[ICON] | + // If we shift both our offset and our divider points later by half an icon + // plus one spacing unit, then it becomes very easy to calculate how many + // divider points we've passed, because they're the multiples of "one icon + // plus padding". + int before_icon_unclamped = (offset_into_icon_area + (IconWidth(false) / 2) + + kItemSpacing) / IconWidth(true); + + // Because the user can drag outside the container bounds, we need to clamp to + // the valid range. Note that the maximum allowable value is (num icons), not + // (num icons - 1), because we represent the indicator being past the last + // icon as being "before the (last + 1) icon". + int before_icon = std::min(std::max(before_icon_unclamped, 0), + static_cast<int>(VisibleBrowserActions())); + + // Now we convert back to a pixel offset into the container. We want to place + // the center of the drop indicator at the midpoint of the space before our + // chosen icon. + SetDropIndicator(width_before_icons + (before_icon * IconWidth(true)) - + (kItemSpacing / 2)); - // Clamping gives us a value where the next button will be drawn, but we want - // to subtract the padding (and then some) to make it appear in-between the - // buttons. - SetDropIndicator(x - kBrowserActionButtonPadding - (base::i18n::IsRTL() ? - kDropIndicatorOffsetRtl : kDropIndicatorOffsetLtr)); return DragDropTypes::DRAG_MOVE; } @@ -728,6 +730,10 @@ int BrowserActionsContainer::OnPerformDrop( return DragDropTypes::DRAG_MOVE; } +void BrowserActionsContainer::OnThemeChanged() { + LoadImages(); +} + bool BrowserActionsContainer::GetAccessibleRole( AccessibilityTypes::Role* role) { DCHECK(role); @@ -779,28 +785,25 @@ bool BrowserActionsContainer::CanStartDrag(View* sender, } 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_width_ - resize_amount); - int max_width = ClampToNearestIconCount(-1, false); - new_width = std::min(new_width, max_width); - + if (done_resizing) { // 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_width_ = new_width; - animation_target_size_ = ClampToNearestIconCount(new_width, true); - resize_animation_->Reset(); - resize_animation_->SetTweenType(Tween::EASE_OUT); - resize_animation_->Show(); + // time to set the container size to the size we have resized to, and then + // animate to the nearest icon count size if necessary (which may be 0). + int max_width = IconCountToWidth(-1, false); + container_width_ = + std::min(std::max(0, container_width_ - resize_amount), max_width); + if (container_width_ < max_width) { + animation_target_size_ = + IconCountToWidth(WidthToIconCount(container_width_), true); + resize_animation_->Reset(); + resize_animation_->SetTweenType(Tween::EASE_OUT); + resize_animation_->Show(); + return; + } + } else { + resize_amount_ = resize_amount; } + OnBrowserActionVisibilityChanged(); } void BrowserActionsContainer::AnimationProgressed(const Animation* animation) { @@ -859,16 +862,41 @@ void BrowserActionsContainer::HidePopup() { void BrowserActionsContainer::TestExecuteBrowserAction(int index) { BrowserActionButton* button = browser_action_views_[index]->button(); - OnBrowserActionExecuted(button, false); // |inspect_with_devtools|. + OnBrowserActionExecuted(button, false); } void BrowserActionsContainer::TestSetIconVisibilityCount(size_t icons) { + model_->SetVisibleIconCount(icons); chevron_->SetVisible(icons < browser_action_views_.size()); - container_width_ = IconCountToWidth(icons); + container_width_ = IconCountToWidth(icons, chevron_->IsVisible()); Layout(); SchedulePaint(); } +// static +int BrowserActionsContainer::IconWidth(bool include_padding) { + static bool initialized = false; + static int icon_width = 0; + if (!initialized) { + initialized = true; + icon_width = ResourceBundle::GetSharedInstance().GetBitmapNamed( + IDR_BROWSER_ACTION)->width(); + } + return icon_width + (include_padding ? kItemSpacing : 0); +} + +// static +int BrowserActionsContainer::IconHeight() { + static bool initialized = false; + static int icon_height = 0; + if (!initialized) { + initialized = true; + icon_height = ResourceBundle::GetSharedInstance().GetBitmapNamed( + IDR_BROWSER_ACTION)->height(); + } + return icon_height; +} + void BrowserActionsContainer::BrowserActionAdded(Extension* extension, int index) { #if defined(DEBUG) @@ -888,7 +916,6 @@ void BrowserActionsContainer::BrowserActionAdded(Extension* extension, // Add the new browser action to the vector and the view hierarchy. if (profile_->IsOffTheRecord()) index = model_->OriginalIndexToIncognito(index); - BrowserActionView* view = new BrowserActionView(extension, this); browser_action_views_.insert(browser_action_views_.begin() + index, view); AddChildView(index, view); @@ -897,23 +924,15 @@ void BrowserActionsContainer::BrowserActionAdded(Extension* extension, if (!model_->extensions_initialized()) return; - // 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). - if (model_->GetVisibleIconCount() >= 0 || extension->being_upgraded()) { - // 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. - int 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(); - + // Enlarge the container if it was already at maximum size and we're not in + // the middle of upgrading. + if ((model_->GetVisibleIconCount() < 0) && !extension->being_upgraded()) { + int target_size = IconCountToWidth(visible_actions + 1, false); + suppress_chevron_ = true; Animate(Tween::LINEAR, target_size); + } else { + // Just redraw the (possibly modified) visible icon set. + OnBrowserActionVisibilityChanged(); } } @@ -936,18 +955,18 @@ void BrowserActionsContainer::BrowserActionRemoved(Extension* extension) { if (extension->being_upgraded()) return; - // 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). - int target_size = - ClampToNearestIconCount(IconCountToWidth(visible_actions), true); - - Animate(Tween::EASE_OUT, target_size); + if (browser_action_views_.size() > visible_actions) { + // If we have more icons than we can show, then we must not be changing + // the container size (since we either removed an icon from the main + // area and one from the overflow list will have shifted in, or we + // removed an entry directly from the overflow list). + OnBrowserActionVisibilityChanged(); + } else { + // Either we went from overflow to no-overflow, or we shrunk the no- + // overflow container by 1. Either way the size changed, so animate. + chevron_->SetVisible(false); + Animate(Tween::EASE_OUT, IconCountToWidth(-1, false)); + } return; } } @@ -973,12 +992,19 @@ void BrowserActionsContainer::ModelLoaded() { SetContainerWidth(); } +void BrowserActionsContainer::LoadImages() { + ThemeProvider* tp = GetThemeProvider(); + chevron_->SetIcon(*tp->GetBitmapNamed(IDR_BROWSER_ACTIONS_OVERFLOW)); + chevron_->SetHoverIcon(*tp->GetBitmapNamed(IDR_BROWSER_ACTIONS_OVERFLOW_H)); + chevron_->SetPushedIcon(*tp->GetBitmapNamed(IDR_BROWSER_ACTIONS_OVERFLOW_P)); +} + void BrowserActionsContainer::SetContainerWidth() { int visible_actions = model_->GetVisibleIconCount(); if (visible_actions < 0) // All icons should be visible. visible_actions = model_->size(); chevron_->SetVisible(static_cast<size_t>(visible_actions) < model_->size()); - container_width_ = IconCountToWidth(visible_actions); + container_width_ = IconCountToWidth(visible_actions, chevron_->IsVisible()); } void BrowserActionsContainer::CloseOverflowMenu() { @@ -1014,65 +1040,34 @@ void BrowserActionsContainer::SetDropIndicator(int x_pos) { } } -int BrowserActionsContainer::ClampToNearestIconCount( - int pixelWidth, - bool allow_shrink_to_minimum) 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, resize area 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; - - if (icon_count == 0 && allow_shrink_to_minimum) { - extras = ContainerMinSize(); // Allow very narrow width if no icons. - } else if (icon_count > browser_action_views_.size()) { - // No use allowing more than what we have. - icon_count = browser_action_views_.size(); - } - } else { - // A negative |pixels| count indicates caller wants to know the max width - // that fits all icons; - icon_count = browser_action_views_.size(); - } - - return extras + (icon_count * icon_width); -} - -int BrowserActionsContainer::WidthOfNonIconArea() const { - int chevron_size = (chevron_->IsVisible()) ? - chevron_->GetPreferredSize().width() : 0; - int padding = base::i18n::IsRTL() ? - kHorizontalPaddingRtl : kHorizontalPadding; - return kResizeAreaWidth + padding + chevron_size + kChevronRightMargin + - kDividerHorizontalMargin; +int BrowserActionsContainer::IconCountToWidth(int icons, + bool display_chevron) const { + if (icons < 0) + icons = browser_action_views_.size(); + if ((icons == 0) && !display_chevron) + return ToolbarView::kStandardSpacing; + int icons_size = + (icons == 0) ? 0 : ((icons * IconWidth(true)) - kItemSpacing); + int chevron_size = display_chevron ? + (kChevronSpacing + chevron_->GetPreferredSize().width()) : 0; + return ToolbarView::kStandardSpacing + icons_size + chevron_size + + ToolbarView::kStandardSpacing; } -int BrowserActionsContainer::IconCountToWidth(int icons) const { - DCHECK_GE(icons, 0); - if (icons == 0) - return ContainerMinSize(); - - int icon_width = kButtonSize + kBrowserActionButtonPadding; - - return WidthOfNonIconArea() + (icons * icon_width); +int BrowserActionsContainer::WidthToIconCount(int pixels) const { + // We need to reserve space for the resize area, chevron, and the spacing on + // either side of the chevron. + int available_space = pixels - ToolbarView::kStandardSpacing - + chevron_->GetPreferredSize().width() - kChevronSpacing - + ToolbarView::kStandardSpacing; + // Now we add an extra between-item padding value so the space can be divided + // evenly by (size of icon with padding). + return std::max(0, available_space + kItemSpacing) / IconWidth(true); } int BrowserActionsContainer::ContainerMinSize() const { - return kResizeAreaWidth + chevron_->width() + kChevronRightMargin; + return ToolbarView::kStandardSpacing + kChevronSpacing + + chevron_->GetPreferredSize().width() + ToolbarView::kStandardSpacing; } void BrowserActionsContainer::Animate(Tween::Type tween_type, int target_size) { diff --git a/chrome/browser/views/browser_actions_container.h b/chrome/browser/views/browser_actions_container.h index 5be6678..e8f649c 100644 --- a/chrome/browser/views/browser_actions_container.h +++ b/chrome/browser/views/browser_actions_container.h @@ -176,24 +176,24 @@ class BrowserActionView : public views::View { // The BrowserActionsContainer is a container view, responsible for drawing the // 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: -// -// r _ Icon _ Icon _ Icon _ [chevron] _ | _ -// ----------------------------------------- -// 1 2 3 4 5 6 7 8 -// -// 1) An invisible resize area. -// 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 container is placed flush against the omnibox and wrench menu, and its +// layout looks like: +// rI_I_IcCs +// Where the letters are as follows: +// r: An invisible resize area. This is ToolbarView::kStandardSpacing pixels +// wide and directly adjacent to the omnibox. +// I: An icon. This is as wide as the IDR_BROWSER_ACTION image. +// _: kItemSpacing pixels of empty space. +// c: kChevronSpacing pixels of empty space. Only present if C is present. +// C: An optional chevron, visible for overflow. As wide as the +// IDR_BROWSER_ACTIONS_OVERFLOW image. +// s: ToolbarView::kStandardSpacing pixels of empty space (before the wrench +// menu). +// The reason the container contains the trailing space "s", rather than having +// it be handled by the parent view, is so that when the chevron is invisible +// and the user starts dragging an icon around, we have the space to draw the +// ultimate drop indicator. (Otherwise, we'd be trying to draw it into the +// padding beyond our right edge, and it wouldn't appear.) // // The BrowserActionsContainer follows a few rules, in terms of user experience: // @@ -259,6 +259,8 @@ class BrowserActionsContainer static void RegisterUserPrefs(PrefService* prefs); + void Init(); + // Get the number of browser actions being displayed. int num_browser_actions() const { return browser_action_views_.size(); } @@ -319,6 +321,7 @@ class BrowserActionsContainer virtual int OnDragUpdated(const views::DropTargetEvent& event); virtual void OnDragExited(); virtual int OnPerformDrop(const views::DropTargetEvent& event); + virtual void OnThemeChanged(); virtual bool GetAccessibleRole(AccessibilityTypes::Role* role); // Overridden from views::ViewMenuDelegate: @@ -373,16 +376,25 @@ class BrowserActionsContainer static bool disable_animations_during_testing_; private: + friend class BrowserActionView; // So it can access IconHeight(). friend class ShowFolderMenuTask; typedef std::vector<BrowserActionView*> BrowserActionViews; + // Returns the width of an icon, optionally with its padding. + static int IconWidth(bool include_padding); + + // Returns the height of an icon. + static int IconHeight(); + // ExtensionToolbarModel::Observer implementation. virtual void BrowserActionAdded(Extension* extension, int index); virtual void BrowserActionRemoved(Extension* extension); virtual void BrowserActionMoved(Extension* extension, int index); virtual void ModelLoaded(); + void LoadImages(); + // Sets the initial container width. void SetContainerWidth(); @@ -402,26 +414,19 @@ class BrowserActionsContainer // changed). void SetDropIndicator(int x_pos); - // 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. |allow_shrink_to_minimum| specifies whether this function - // clamps the size down further (down to ContainerMinSize()) if there is not - // room for even one icon. When determining how large the container should be - // this should be |true|. When determining where to place items, such as the - // drop indicator, this should be |false|. - int ClampToNearestIconCount(int pixels, bool allow_shrink_to_minimum) 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| and whether to |display_chevron|, returns the + // amount of pixels needed to draw the entire container. For convenience, + // callers can set |icons| to -1 to mean "all icons". + int IconCountToWidth(int icons, bool display_chevron) const; - // Given a number of |icons| return the amount of pixels needed to draw it, - // including the controls (chevron if visible and resize area). - int IconCountToWidth(int icons) const; + // Given a pixel width, returns the number of icons that fit, assuming we need + // to show a chevron. + int WidthToIconCount(int pixels) 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. + // still show it. This assumes a visible chevron because the only way we + // would not have a chevron when shrinking down this far is if there were no + // icons, in which case the container wouldn't be shown at all. int ContainerMinSize() const; // Animate to the target value (unless testing, in which case we go straight diff --git a/chrome/browser/views/toolbar_view.cc b/chrome/browser/views/toolbar_view.cc index b1c7706..bfd9e3b 100644 --- a/chrome/browser/views/toolbar_view.cc +++ b/chrome/browser/views/toolbar_view.cc @@ -178,6 +178,7 @@ void ToolbarView::Init(Profile* profile) { location_bar_->Init(); show_home_button_.Init(prefs::kShowHomeButton, profile->GetPrefs(), this); + browser_actions_->Init(); SetProfile(profile); } |