Chromium Code Reviews| 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 57aff05e5cf0437185da07fc29ae4233a606bd5e..8f625fef5d09a3f43265159c8588050021a8b857 100644 |
| --- a/chrome/browser/ui/views/toolbar/browser_actions_container.cc |
| +++ b/chrome/browser/ui/views/toolbar/browser_actions_container.cc |
| @@ -102,6 +102,25 @@ class ChevronMenuButton : public views::MenuButton { |
| // static |
| bool BrowserActionsContainer::disable_animations_during_testing_ = false; |
| +struct BrowserActionsContainer::DropPosition { |
| + DropPosition(size_t row, size_t icon_in_row); |
| + ~DropPosition(); |
| + |
| + // 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::DropPosition::~DropPosition() { |
| +} |
| + |
| //////////////////////////////////////////////////////////////////////////////// |
| // BrowserActionsContainer |
| @@ -123,7 +142,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 +377,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)) - |
|
Devlin
2014/07/17 22:26:30
We need this so that we can see the drop indicator
|
| (row_index * IconWidth(true) * kIconsPerMenuRow); |
| gfx::Rect rect_bounds( |
| x, IconHeight() * row_index, icon_width, IconHeight()); |
| @@ -407,20 +425,22 @@ 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; |
| - } |
| + // 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(); |
|
Finnur
2014/07/18 10:52:41
Will this work in RTL?
Devlin
2014/07/18 17:58:20
Nope! But it does now. :)
|
| int offset_into_icon_area = 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. |
| + int 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 |
| // midpoints of icons (n - 1) and n. To do this we take the offset into the |
| @@ -445,25 +465,33 @@ 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 == (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())); |
| + int before_icon_in_row = |
| + std::min(std::max(before_icon_unclamped, 0), visible_icons_on_row); |
|
Devlin
2014/07/17 22:26:30
These calculations plus using a row/icon_on_row st
|
| - // 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)); |
| + SetDropPosition(row_index, before_icon_in_row); |
| return ui::DragDropTypes::DRAG_MOVE; |
| } |
| void BrowserActionsContainer::OnDragExited() { |
| StopShowFolderDropMenuTimer(); |
| - drop_indicator_position_ = -1; |
| + ResetDropPosition(); |
| SchedulePaint(); |
| } |
| @@ -478,18 +506,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 +710,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 +751,32 @@ 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. We want to place |
| + // the center of the drop indicator at the midpoint of the space before our |
| + // chosen icon. |
|
Finnur
2014/07/18 10:52:41
Nit: "Chosen icon" is a bit weird here, because yo
Devlin
2014/07/18 17:58:20
Done.
|
| + // This is: |
| + // The width before the first icon, plus |
| + // The width of all icons before the target icon in the row, minus |
| + // Half the spacing between the target icon and the previous icon, minus |
| + // Half the width of the drop indicator, so it's centered. |
| + int drop_indicator_x = |
| + browser_action_views_[GetFirstVisibleIconIndex()]->x() + |
| + drop_position_->icon_in_row * IconWidth(true) - |
| + kItemSpacing / 2 - |
| + kDropIndicatorWidth / 2; |
| + |
| + // The y is simply the start of the row (which for the main container is |
| + // always 0). |
| + int drop_indicator_y = IconHeight() * drop_position_->row; |
| + |
| + gfx::Rect indicator_bounds(drop_indicator_x, |
| + drop_indicator_y, |
| + kDropIndicatorWidth, |
| + IconHeight()); |
| // Color of the drop indicator. |
| static const SkColor kDropIndicatorColor = SK_ColorBLACK; |
| @@ -945,7 +987,7 @@ void BrowserActionsContainer::StartShowFolderDropMenuTimer() { |
| void BrowserActionsContainer::ShowDropFolder() { |
| DCHECK(!overflow_menu_); |
| - SetDropIndicator(-1); |
| + ResetDropPosition(); |
| overflow_menu_ = |
| new BrowserActionOverflowMenuController(this, |
| browser_, |
| @@ -957,13 +999,19 @@ void BrowserActionsContainer::ShowDropFolder() { |
| overflow_menu_->RunMenu(GetWidget()); |
| } |
| -void BrowserActionsContainer::SetDropIndicator(int x_pos) { |
| - if (drop_indicator_position_ != x_pos) { |
| - drop_indicator_position_ = x_pos; |
| +void BrowserActionsContainer::SetDropPosition(size_t row, size_t icon_in_row) { |
| + if (!drop_position_.get() || |
| + !(drop_position_->row == row && |
| + drop_position_->icon_in_row == icon_in_row)) { |
| + drop_position_.reset(new DropPosition(row, icon_in_row)); |
| SchedulePaint(); |
| } |
| } |
| +void BrowserActionsContainer::ResetDropPosition() { |
| + drop_position_.reset(); |
| +} |
| + |
| int BrowserActionsContainer::IconCountToWidth(int icons, |
| bool display_chevron) const { |
| if (icons < 0) |