Index: chrome/browser/ui/views/toolbar/browser_actions_container.cc |
diff --git a/chrome/browser/ui/views/toolbar/browser_actions_container.cc b/chrome/browser/ui/views/toolbar/browser_actions_container.cc |
index faae39a6e02f785a54441e2e9e704e569ff4fdee..9b4e08a489157e2d585d72c88df6b15d8590098f 100644 |
--- a/chrome/browser/ui/views/toolbar/browser_actions_container.cc |
+++ b/chrome/browser/ui/views/toolbar/browser_actions_container.cc |
@@ -99,12 +99,30 @@ class ChevronMenuButton : public views::MenuButton { |
} // namespace |
-// static |
-bool BrowserActionsContainer::disable_animations_during_testing_ = false; |
+//////////////////////////////////////////////////////////////////////////////// |
+// BrowserActionsContainer::DropPosition |
+ |
+struct BrowserActionsContainer::DropPosition { |
+ DropPosition(size_t row, size_t icon_in_row); |
+ |
+ // The (0-indexed) row into which the action will be dropped. |
+ size_t row; |
+ |
+ // The (0-indexed) icon in the row before the action will be dropped. |
+ size_t icon_in_row; |
+}; |
+ |
+BrowserActionsContainer::DropPosition::DropPosition( |
+ size_t row, size_t icon_in_row) |
+ : row(row), icon_in_row(icon_in_row) { |
+} |
//////////////////////////////////////////////////////////////////////////////// |
// BrowserActionsContainer |
+// static |
+bool BrowserActionsContainer::disable_animations_during_testing_ = false; |
+ |
BrowserActionsContainer::BrowserActionsContainer( |
Browser* browser, |
View* owner_view, |
@@ -123,7 +141,6 @@ BrowserActionsContainer::BrowserActionsContainer( |
suppress_chevron_(false), |
resize_amount_(0), |
animation_target_size_(0), |
- drop_indicator_position_(-1), |
task_factory_(this), |
show_menu_task_factory_(this) { |
set_id(VIEW_ID_BROWSER_ACTION_TOOLBAR); |
@@ -359,7 +376,7 @@ void BrowserActionsContainer::Layout() { |
BrowserActionView* view = browser_action_views_[i]; |
size_t index = i - main_container_->VisibleBrowserActionsAfterAnimation(); |
int row_index = static_cast<int>(index) / kIconsPerMenuRow; |
- int x = (index * IconWidth(true)) - |
+ int x = kItemSpacing + (index * IconWidth(true)) - |
(row_index * IconWidth(true) * kIconsPerMenuRow); |
gfx::Rect rect_bounds( |
x, IconHeight() * row_index, icon_width, IconHeight()); |
@@ -407,19 +424,25 @@ int BrowserActionsContainer::OnDragUpdated( |
} |
StopShowFolderDropMenuTimer(); |
- // TODO(devlin): This calculation needs to take 'overflow' mode into account |
- // once the wrench menu becomes a drag target for browser action icons. |
- |
// 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; |
- if (chevron_ && base::i18n::IsRTL()) { |
- width_before_icons += |
- chevron_->GetPreferredSize().width() + kChevronSpacing; |
- } |
- int offset_into_icon_area = event.x() - width_before_icons; |
+ // can calculate the true offset into the icon area. The easiest way to do |
+ // this is to just find where the first icon starts. |
+ int width_before_icons = |
+ browser_action_views_[GetFirstVisibleIconIndex()]->x(); |
+ |
+ // If we're right-to-left, we flip the mirror the event.x() so that our |
+ // calculations are consistent with left-to-right. |
+ int offset_into_icon_area = |
+ GetMirroredXInView(event.x()) - width_before_icons; |
+ |
+ // Next, figure out what row we're on. This only matters for overflow mode, |
+ // but the calculation is the same for both. |
+ size_t row_index = event.y() / IconHeight(); |
+ |
+ // Sanity check - we should never be on a different row in the main 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 |
@@ -445,25 +468,39 @@ int BrowserActionsContainer::OnDragUpdated( |
int before_icon_unclamped = (offset_into_icon_area + (IconWidth(false) / 2) + |
kItemSpacing) / IconWidth(true); |
+ // We need to figure out how many icons are visible on the relevant row. |
+ // In the main container, this will just be the visible actions. |
+ int visible_icons_on_row = VisibleBrowserActionsAfterAnimation(); |
+ if (in_overflow_mode()) { |
+ // If this is the final row of the overflow, then this is the remainder of |
+ // visible icons. Otherwise, it's a full row (kIconsPerRow). |
+ visible_icons_on_row = |
+ row_index == |
+ static_cast<size_t>(visible_icons_on_row / kIconsPerMenuRow) ? |
+ visible_icons_on_row % kIconsPerMenuRow : |
+ kIconsPerMenuRow; |
+ } |
+ |
// 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())); |
+ size_t before_icon_in_row = |
+ std::min(std::max(before_icon_unclamped, 0), visible_icons_on_row); |
- // 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)); |
+ if (!drop_position_.get() || |
+ !(drop_position_->row == row_index && |
+ drop_position_->icon_in_row == before_icon_in_row)) { |
+ drop_position_.reset(new DropPosition(row_index, before_icon_in_row)); |
+ SchedulePaint(); |
+ } |
return ui::DragDropTypes::DRAG_MOVE; |
} |
void BrowserActionsContainer::OnDragExited() { |
StopShowFolderDropMenuTimer(); |
- drop_indicator_position_ = -1; |
+ drop_position_.reset(); |
SchedulePaint(); |
} |
@@ -478,18 +515,10 @@ int BrowserActionsContainer::OnPerformDrop( |
data.id()); |
DCHECK(model_); |
- size_t i = 0; |
- for (; i < browser_action_views_.size(); ++i) { |
- int view_x = browser_action_views_[i]->GetMirroredBounds().x(); |
- if (!browser_action_views_[i]->visible() || |
- (base::i18n::IsRTL() ? (view_x < drop_indicator_position_) : |
- (view_x >= drop_indicator_position_))) { |
- // We have reached the end of the visible icons or found one that has a |
- // higher x position than the drop point. |
- break; |
- } |
- } |
- |
+ size_t i = |
+ drop_position_->row * kIconsPerMenuRow + drop_position_->icon_in_row; |
+ if (in_overflow_mode()) |
+ i += GetFirstVisibleIconIndex(); |
// |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, |
// however, we want the icon being dragged to get the index of the item to |
@@ -690,6 +719,10 @@ bool BrowserActionsContainer::ShowPopup(const extensions::Extension* extension, |
return false; |
} |
+size_t BrowserActionsContainer::GetFirstVisibleIconIndex() const { |
+ return in_overflow_mode() ? model_->GetVisibleIconCount() : 0; |
+} |
+ |
void BrowserActionsContainer::HidePopup() { |
// Remove this as an observer and clear |popup_| and |popup_button_| here, |
// since we might change them before OnWidgetDestroying() gets called. |
@@ -727,14 +760,36 @@ void BrowserActionsContainer::OnPaint(gfx::Canvas* canvas) { |
// 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) { |
+ if (drop_position_.get()) { |
// The two-pixel width drop indicator. |
static const int kDropIndicatorWidth = 2; |
- gfx::Rect indicator_bounds( |
- drop_indicator_position_ - (kDropIndicatorWidth / 2), |
- 0, |
- kDropIndicatorWidth, |
- height()); |
+ |
+ // Convert back to a pixel offset into the container. First find the X |
+ // coordinate of the drop icon. |
+ int drop_icon_x = browser_action_views_[GetFirstVisibleIconIndex()]->x() + |
+ (drop_position_->icon_in_row * IconWidth(true)); |
+ // Next, find the space before the drop icon. This will either be |
+ // kItemSpacing or ToolbarView::kStandardSpacing, depending on whether this |
+ // is the first icon. |
+ // NOTE: Right now, these are the same. But let's do this right for if they |
+ // ever aren't. |
+ int space_before_drop_icon = drop_position_->icon_in_row == 0 ? |
+ ToolbarView::kStandardSpacing : kItemSpacing; |
+ // Now place the drop indicator halfway between this and the end of the |
+ // previous icon. If there is an odd amount of available space between the |
+ // two icons (or the icon and the address bar) after subtracting the drop |
+ // indicator width, this calculation puts the extra pixel on the left side |
+ // of the indicator, since when the indicator is between the address bar and |
+ // the first icon, it looks better closer to the icon. |
+ int drop_indicator_x = drop_icon_x - |
+ ((space_before_drop_icon + kDropIndicatorWidth) / 2); |
+ int row_height = IconHeight(); |
+ int drop_indicator_y = row_height * drop_position_->row; |
+ gfx::Rect indicator_bounds(drop_indicator_x, |
+ drop_indicator_y, |
+ kDropIndicatorWidth, |
+ row_height); |
+ indicator_bounds.set_x(GetMirroredXForRect(indicator_bounds)); |
// Color of the drop indicator. |
static const SkColor kDropIndicatorColor = SK_ColorBLACK; |
@@ -945,7 +1000,7 @@ void BrowserActionsContainer::StartShowFolderDropMenuTimer() { |
void BrowserActionsContainer::ShowDropFolder() { |
DCHECK(!overflow_menu_); |
- SetDropIndicator(-1); |
+ drop_position_.reset(); |
overflow_menu_ = |
new BrowserActionOverflowMenuController(this, |
browser_, |
@@ -957,13 +1012,6 @@ void BrowserActionsContainer::ShowDropFolder() { |
overflow_menu_->RunMenu(GetWidget()); |
} |
-void BrowserActionsContainer::SetDropIndicator(int x_pos) { |
- if (drop_indicator_position_ != x_pos) { |
- drop_indicator_position_ = x_pos; |
- SchedulePaint(); |
- } |
-} |
- |
int BrowserActionsContainer::IconCountToWidth(int icons, |
bool display_chevron) const { |
if (icons < 0) |