Commit 9bdf4531 authored by rdevlin.cronin's avatar rdevlin.cronin Committed by Commit bot

Allow the user to drag an extension to the overflow menu, even when its empty

We need to show an empty bar for the user to drag extension actions into for
overflow when there are none currently overflowed. Obviously, this empty bar
should only be displayed when the user is dragging an extension action.

BUG=414386

Review URL: https://codereview.chromium.org/556293003

Cr-Commit-Position: refs/heads/master@{#295179}
parent fedbb0d1
...@@ -268,8 +268,15 @@ void BrowserActionsContainer::ExecuteExtensionCommand( ...@@ -268,8 +268,15 @@ void BrowserActionsContainer::ExecuteExtensionCommand(
void BrowserActionsContainer::NotifyActionMovedToOverflow() { void BrowserActionsContainer::NotifyActionMovedToOverflow() {
// When an action is moved to overflow, we shrink the size of the container // When an action is moved to overflow, we shrink the size of the container
// by 1. // by 1.
if (!profile_->IsOffTheRecord()) if (!profile_->IsOffTheRecord()) {
model_->SetVisibleIconCount(model_->GetVisibleIconCount() - 1); int icon_count = model_->GetVisibleIconCount();
// Since this happens when an icon moves from the main bar to overflow, we
// can't possibly have had no visible icons on the main bar.
DCHECK_NE(0, icon_count);
if (icon_count == -1)
icon_count = browser_action_views_.size();
model_->SetVisibleIconCount(icon_count - 1);
}
Animate(gfx::Tween::EASE_OUT, Animate(gfx::Tween::EASE_OUT,
VisibleBrowserActionsAfterAnimation() - 1); VisibleBrowserActionsAfterAnimation() - 1);
} }
...@@ -322,24 +329,23 @@ void BrowserActionsContainer::RemoveObserver( ...@@ -322,24 +329,23 @@ void BrowserActionsContainer::RemoveObserver(
} }
gfx::Size BrowserActionsContainer::GetPreferredSize() const { gfx::Size BrowserActionsContainer::GetPreferredSize() const {
// Note: We can't use GetIconCount() for the main bar, since we may also
// have to include items that are in the chevron's overflow.
size_t icon_count =
in_overflow_mode() ? GetIconCount() : browser_action_views_.size();
// If there are no actions to show, or we are in overflow mode and the main
// container is already showing them all, then no further work is required.
if (icon_count == 0)
return gfx::Size();
if (in_overflow_mode()) { if (in_overflow_mode()) {
// When in overflow, y is multiline, so the pixel count is IconHeight() int icon_count = GetIconCount();
// times the number of rows needed. // In overflow, we always have a preferred size of a full row (even if we
// don't use it), and always of at least one row. The parent may decide to
// show us even when empty, e.g. as a drag target for dragging in icons from
// the main container.
int row_count =
((std::max(0, icon_count - 1)) / icons_per_overflow_menu_row_) + 1;
return gfx::Size( return gfx::Size(
IconCountToWidth(icons_per_overflow_menu_row_, false), IconCountToWidth(icons_per_overflow_menu_row_, false),
(((icon_count - 1) / icons_per_overflow_menu_row_) + 1) * IconHeight()); row_count * IconHeight());
} }
// If there are no actions to show, then don't show the container at all.
if (browser_action_views_.empty())
return gfx::Size();
// We calculate the size of the view by taking the current width and // We calculate the size of the view by taking the current width and
// subtracting resize_amount_ (the latter represents how far the user is // subtracting resize_amount_ (the latter represents how far the user is
// resizing the view or, if animating the snapping, how far to animate it). // resizing the view or, if animating the snapping, how far to animate it).
...@@ -448,70 +454,73 @@ int BrowserActionsContainer::OnDragUpdated( ...@@ -448,70 +454,73 @@ int BrowserActionsContainer::OnDragUpdated(
} }
StopShowFolderDropMenuTimer(); StopShowFolderDropMenuTimer();
// Figure out where to display the indicator. This is a complex calculation: size_t row_index = 0;
size_t before_icon_in_row = 0;
// First, we figure out how much space is to the left of the icon area, so we // If there are no visible browser actions (such as when dragging an icon to
// can calculate the true offset into the icon area. The easiest way to do // an empty overflow/main container), then 0, 0 for row, column is correct.
// this is to just find where the first icon starts. if (VisibleBrowserActions() != 0) {
int width_before_icons = // Figure out where to display the indicator. This is a complex calculation:
browser_action_views_[GetFirstVisibleIconIndex()]->x();
// First, we subtract out the padding to the left of the icon area, which is
// If we're right-to-left, we flip the mirror the event.x() so that our // ToolbarView::kStandardSpacing. If we're right-to-left, we also mirror the
// calculations are consistent with left-to-right. // event.x() so that our calculations are consistent with left-to-right.
int offset_into_icon_area = int offset_into_icon_area =
GetMirroredXInView(event.x()) - width_before_icons; GetMirroredXInView(event.x()) - ToolbarView::kStandardSpacing;
// Next, figure out what row we're on. This only matters for overflow mode, // Next, figure out what row we're on. This only matters for overflow mode,
// but the calculation is the same for both. // but the calculation is the same for both.
size_t row_index = event.y() / IconHeight(); row_index = event.y() / IconHeight();
// Sanity check - we should never be on a different row in the main container. // Sanity check - we should never be on a different row in the main
DCHECK(in_overflow_mode() || row_index == 0); // container.
DCHECK(in_overflow_mode() || row_index == 0);
// 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 // Next, we determine which icon to place the indicator in front of. We want
// midpoints of icons (n - 1) and n. To do this we take the offset into the // to place the indicator in front of icon n when the cursor is between the
// icon area and transform it as follows: // 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 // 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. // |[IC|ON] [IC|ON] [IC|ON]
// Here the "*" represents the offset into the icon area, and since it's // We want to be before icon 0 for 0 < x <= a, icon 1 for a < x <= b, etc.
// between a and b, we want to return "1". // 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 // 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 // |[ICON] |[ICON] |[ICON] |
// plus one spacing unit, then it becomes very easy to calculate how many // If we shift both our offset and our divider points later by half an icon
// divider points we've passed, because they're the multiples of "one icon // plus one spacing unit, then it becomes very easy to calculate how many
// plus padding". // divider points we've passed, because they're the multiples of "one icon
int before_icon_unclamped = (offset_into_icon_area + (IconWidth(false) / 2) + // plus padding".
kItemSpacing) / IconWidth(true); int before_icon_unclamped =
(offset_into_icon_area + (IconWidth(false) / 2) +
// We need to figure out how many icons are visible on the relevant row. kItemSpacing) / IconWidth(true);
// In the main container, this will just be the visible actions.
int visible_icons_on_row = VisibleBrowserActionsAfterAnimation(); // We need to figure out how many icons are visible on the relevant row.
if (in_overflow_mode()) { // In the main container, this will just be the visible actions.
// If this is the final row of the overflow, then this is the remainder of int visible_icons_on_row = VisibleBrowserActionsAfterAnimation();
// visible icons. Otherwise, it's a full row (kIconsPerRow). if (in_overflow_mode()) {
visible_icons_on_row = // If this is the final row of the overflow, then this is the remainder of
row_index == // visible icons. Otherwise, it's a full row (kIconsPerRow).
static_cast<size_t>(visible_icons_on_row / visible_icons_on_row =
icons_per_overflow_menu_row_) ? row_index ==
visible_icons_on_row % icons_per_overflow_menu_row_ : static_cast<size_t>(visible_icons_on_row /
icons_per_overflow_menu_row_; icons_per_overflow_menu_row_) ?
} visible_icons_on_row % icons_per_overflow_menu_row_ :
icons_per_overflow_menu_row_;
}
// Because the user can drag outside the container bounds, we need to clamp to // Because the user can drag outside the container bounds, we need to clamp
// the valid range. Note that the maximum allowable value is (num icons), not // to the valid range. Note that the maximum allowable value is (num icons),
// (num icons - 1), because we represent the indicator being past the last // not (num icons - 1), because we represent the indicator being past the
// icon as being "before the (last + 1) icon". // last icon as being "before the (last + 1) icon".
size_t before_icon_in_row = before_icon_in_row =
std::min(std::max(before_icon_unclamped, 0), visible_icons_on_row); std::min(std::max(before_icon_unclamped, 0), visible_icons_on_row);
}
if (!drop_position_.get() || if (!drop_position_.get() ||
!(drop_position_->row == row_index && !(drop_position_->row == row_index &&
...@@ -543,7 +552,7 @@ int BrowserActionsContainer::OnPerformDrop( ...@@ -543,7 +552,7 @@ int BrowserActionsContainer::OnPerformDrop(
size_t i = drop_position_->row * icons_per_overflow_menu_row_ + size_t i = drop_position_->row * icons_per_overflow_menu_row_ +
drop_position_->icon_in_row; drop_position_->icon_in_row;
if (in_overflow_mode()) if (in_overflow_mode())
i += GetFirstVisibleIconIndex(); i += main_container_->VisibleBrowserActionsAfterAnimation();
// |i| now points to the item to the right of the drop indicator*, which is // |i| now points to the item to the right of the drop indicator*, which is
// correct when dragging an icon to the left. When dragging to the right, // correct when dragging an icon to the left. When dragging to the right,
// however, we want the icon being dragged to get the index of the item to // however, we want the icon being dragged to get the index of the item to
...@@ -702,11 +711,6 @@ extensions::ActiveTabPermissionGranter* ...@@ -702,11 +711,6 @@ extensions::ActiveTabPermissionGranter*
active_tab_permission_granter(); active_tab_permission_granter();
} }
size_t BrowserActionsContainer::GetFirstVisibleIconIndex() const {
return in_overflow_mode() ?
main_container_->VisibleBrowserActionsAfterAnimation() : 0;
}
ExtensionPopup* BrowserActionsContainer::TestGetPopup() { ExtensionPopup* BrowserActionsContainer::TestGetPopup() {
return popup_owner_ ? popup_owner_->view_controller()->popup() : NULL; return popup_owner_ ? popup_owner_->view_controller()->popup() : NULL;
} }
...@@ -731,7 +735,7 @@ void BrowserActionsContainer::OnPaint(gfx::Canvas* canvas) { ...@@ -731,7 +735,7 @@ void BrowserActionsContainer::OnPaint(gfx::Canvas* canvas) {
// Convert back to a pixel offset into the container. First find the X // Convert back to a pixel offset into the container. First find the X
// coordinate of the drop icon. // coordinate of the drop icon.
int drop_icon_x = browser_action_views_[GetFirstVisibleIconIndex()]->x() + int drop_icon_x = ToolbarView::kStandardSpacing +
(drop_position_->icon_in_row * IconWidth(true)); (drop_position_->icon_in_row * IconWidth(true));
// Next, find the space before the drop icon. This will either be // Next, find the space before the drop icon. This will either be
// kItemSpacing or ToolbarView::kStandardSpacing, depending on whether this // kItemSpacing or ToolbarView::kStandardSpacing, depending on whether this
......
...@@ -349,9 +349,6 @@ class BrowserActionsContainer ...@@ -349,9 +349,6 @@ class BrowserActionsContainer
// for incognito. // for incognito.
bool ShouldDisplayBrowserAction(const extensions::Extension* extension) const; bool ShouldDisplayBrowserAction(const extensions::Extension* extension) const;
// Return the index of the first visible icon.
size_t GetFirstVisibleIconIndex() const;
// Returns the number of icons that this container should draw. This differs // Returns the number of icons that this container should draw. This differs
// from the model's GetVisibleIconCount if this container is for the overflow. // from the model's GetVisibleIconCount if this container is for the overflow.
size_t GetIconCount() const; size_t GetIconCount() const;
......
...@@ -44,6 +44,9 @@ ExtensionToolbarMenuView::ExtensionToolbarMenuView(Browser* browser, ...@@ -44,6 +44,9 @@ ExtensionToolbarMenuView::ExtensionToolbarMenuView(Browser* browser,
main); main);
container_->Init(); container_->Init();
AddChildView(container_); AddChildView(container_);
// We Layout() the container here so that we know the number of actions
// that will be visible in ShouldShow().
container_->Layout();
// If we were opened for a drop command, we have to wait for the drop to // If we were opened for a drop command, we have to wait for the drop to
// finish so we can close the wrench menu. // finish so we can close the wrench menu.
...@@ -56,6 +59,11 @@ ExtensionToolbarMenuView::ExtensionToolbarMenuView(Browser* browser, ...@@ -56,6 +59,11 @@ ExtensionToolbarMenuView::ExtensionToolbarMenuView(Browser* browser,
ExtensionToolbarMenuView::~ExtensionToolbarMenuView() { ExtensionToolbarMenuView::~ExtensionToolbarMenuView() {
} }
bool ExtensionToolbarMenuView::ShouldShow() {
return wrench_menu_->for_drop() ||
container_->VisibleBrowserActionsAfterAnimation();
}
gfx::Size ExtensionToolbarMenuView::GetPreferredSize() const { gfx::Size ExtensionToolbarMenuView::GetPreferredSize() const {
return container_->GetPreferredSize(); return container_->GetPreferredSize();
} }
......
...@@ -25,6 +25,11 @@ class ExtensionToolbarMenuView : public views::View, ...@@ -25,6 +25,11 @@ class ExtensionToolbarMenuView : public views::View,
ExtensionToolbarMenuView(Browser* browser, WrenchMenu* wrench_menu); ExtensionToolbarMenuView(Browser* browser, WrenchMenu* wrench_menu);
virtual ~ExtensionToolbarMenuView(); virtual ~ExtensionToolbarMenuView();
// Returns whether the wrench menu should show this view. This is true when
// either |container_| has icons to display or the menu was opened for a drag-
// and-drop operation.
bool ShouldShow();
// views::View: // views::View:
virtual gfx::Size GetPreferredSize() const OVERRIDE; virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual int GetHeightForWidth(int width) const OVERRIDE; virtual int GetHeightForWidth(int width) const OVERRIDE;
......
...@@ -1137,7 +1137,7 @@ void WrenchMenu::PopulateMenu(MenuItemView* parent, ...@@ -1137,7 +1137,7 @@ void WrenchMenu::PopulateMenu(MenuItemView* parent,
case IDC_EXTENSIONS_OVERFLOW_MENU: { case IDC_EXTENSIONS_OVERFLOW_MENU: {
scoped_ptr<ExtensionToolbarMenuView> extension_toolbar( scoped_ptr<ExtensionToolbarMenuView> extension_toolbar(
new ExtensionToolbarMenuView(browser_, this)); new ExtensionToolbarMenuView(browser_, this));
if (extension_toolbar->GetPreferredSize().height() > 0) if (extension_toolbar->ShouldShow())
item->AddChildView(extension_toolbar.release()); item->AddChildView(extension_toolbar.release());
else else
item->SetVisible(false); item->SetVisible(false);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment