Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(243)

Side by Side Diff: chrome/browser/ui/views/toolbar/browser_actions_container.cc

Issue 556293003: Allow the user to drag an extension to the overflow menu, even when its empty (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h" 5 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
6 6
7 #include "base/compiler_specific.h" 7 #include "base/compiler_specific.h"
8 #include "base/stl_util.h" 8 #include "base/stl_util.h"
9 #include "chrome/browser/extensions/extension_action_manager.h" 9 #include "chrome/browser/extensions/extension_action_manager.h"
10 #include "chrome/browser/extensions/extension_util.h" 10 #include "chrome/browser/extensions/extension_util.h"
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after
261 // Global commands are handled by the ExtensionCommandsGlobalRegistry 261 // Global commands are handled by the ExtensionCommandsGlobalRegistry
262 // instance. 262 // instance.
263 DCHECK(!command.global()); 263 DCHECK(!command.global());
264 extension_keybinding_registry_->ExecuteCommand(extension->id(), 264 extension_keybinding_registry_->ExecuteCommand(extension->id(),
265 command.accelerator()); 265 command.accelerator());
266 } 266 }
267 267
268 void BrowserActionsContainer::NotifyActionMovedToOverflow() { 268 void BrowserActionsContainer::NotifyActionMovedToOverflow() {
269 // When an action is moved to overflow, we shrink the size of the container 269 // When an action is moved to overflow, we shrink the size of the container
270 // by 1. 270 // by 1.
271 if (!profile_->IsOffTheRecord()) 271 if (!profile_->IsOffTheRecord()) {
272 model_->SetVisibleIconCount(model_->GetVisibleIconCount() - 1); 272 int icon_count = model_->GetVisibleIconCount();
273 if (icon_count == -1)
274 icon_count = browser_action_views_.size();
275 model_->SetVisibleIconCount(icon_count - 1);
Peter Kasting 2014/09/16 21:40:54 What if |icon_count| is 0? Do we really want to c
Devlin 2014/09/16 21:58:29 Interestingly, VisibleIconCount() *cannot* be 0 he
276 }
273 Animate(gfx::Tween::EASE_OUT, 277 Animate(gfx::Tween::EASE_OUT,
274 VisibleBrowserActionsAfterAnimation() - 1); 278 VisibleBrowserActionsAfterAnimation() - 1);
275 } 279 }
276 280
277 bool BrowserActionsContainer::ShownInsideMenu() const { 281 bool BrowserActionsContainer::ShownInsideMenu() const {
278 return in_overflow_mode(); 282 return in_overflow_mode();
279 } 283 }
280 284
281 void BrowserActionsContainer::OnBrowserActionViewDragDone() { 285 void BrowserActionsContainer::OnBrowserActionViewDragDone() {
282 ToolbarVisibleCountChanged(); 286 ToolbarVisibleCountChanged();
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 BrowserActionsContainerObserver* observer) { 319 BrowserActionsContainerObserver* observer) {
316 observers_.AddObserver(observer); 320 observers_.AddObserver(observer);
317 } 321 }
318 322
319 void BrowserActionsContainer::RemoveObserver( 323 void BrowserActionsContainer::RemoveObserver(
320 BrowserActionsContainerObserver* observer) { 324 BrowserActionsContainerObserver* observer) {
321 observers_.RemoveObserver(observer); 325 observers_.RemoveObserver(observer);
322 } 326 }
323 327
324 gfx::Size BrowserActionsContainer::GetPreferredSize() const { 328 gfx::Size BrowserActionsContainer::GetPreferredSize() const {
325 // Note: We can't use GetIconCount() for the main bar, since we may also
326 // have to include items that are in the chevron's overflow.
327 size_t icon_count =
328 in_overflow_mode() ? GetIconCount() : browser_action_views_.size();
329
330 // If there are no actions to show, or we are in overflow mode and the main
331 // container is already showing them all, then no further work is required.
332 if (icon_count == 0)
333 return gfx::Size();
334
335 if (in_overflow_mode()) { 329 if (in_overflow_mode()) {
336 // When in overflow, y is multiline, so the pixel count is IconHeight() 330 int icon_count = GetIconCount();
337 // times the number of rows needed. 331 // In overflow, we always have a preferred size of a full row (even if we
332 // don't use it), and always of at least one row. If there's nothing to
333 // display, the container won't be shown.
Peter Kasting 2014/09/16 21:40:54 Nit: Isn't this comment incorrect, in that sometim
Devlin 2014/09/16 21:58:29 Fair - I was counting a "drop area" as "something
334 int row_count =
335 ((std::max(0, icon_count - 1)) / icons_per_overflow_menu_row_) + 1;
338 return gfx::Size( 336 return gfx::Size(
339 IconCountToWidth(icons_per_overflow_menu_row_, false), 337 IconCountToWidth(icons_per_overflow_menu_row_, false),
340 (((icon_count - 1) / icons_per_overflow_menu_row_) + 1) * IconHeight()); 338 row_count * IconHeight());
341 } 339 }
340 DCHECK(!in_overflow_mode());
Peter Kasting 2014/09/16 21:40:54 Nit: I'd remove this DCHECK as it's obviously true
Devlin 2014/09/16 21:58:29 Done.
341
342 // If there are no actions to show, then don't show the container at all.
343 if (browser_action_views_.size() == 0)
Peter Kasting 2014/09/16 21:40:54 Nit: empty()?
Devlin 2014/09/16 21:58:29 Done.
344 return gfx::Size();
342 345
343 // We calculate the size of the view by taking the current width and 346 // We calculate the size of the view by taking the current width and
344 // subtracting resize_amount_ (the latter represents how far the user is 347 // subtracting resize_amount_ (the latter represents how far the user is
345 // resizing the view or, if animating the snapping, how far to animate it). 348 // resizing the view or, if animating the snapping, how far to animate it).
346 // But we also clamp it to a minimum size and the maximum size, so that the 349 // But we also clamp it to a minimum size and the maximum size, so that the
347 // container can never shrink too far or take up more space than it needs. 350 // container can never shrink too far or take up more space than it needs.
348 // In other words: MinimumNonemptyWidth() < width() - resize < ClampTo(MAX). 351 // In other words: MinimumNonemptyWidth() < width() - resize < ClampTo(MAX).
349 int preferred_width = std::min( 352 int preferred_width = std::min(
350 std::max(MinimumNonemptyWidth(), container_width_ - resize_amount_), 353 std::max(MinimumNonemptyWidth(), container_width_ - resize_amount_),
351 IconCountToWidth(-1, false)); 354 IconCountToWidth(-1, false));
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
441 int BrowserActionsContainer::OnDragUpdated( 444 int BrowserActionsContainer::OnDragUpdated(
442 const ui::DropTargetEvent& event) { 445 const ui::DropTargetEvent& event) {
443 // First check if we are above the chevron (overflow) menu. 446 // First check if we are above the chevron (overflow) menu.
444 if (chevron_ && GetEventHandlerForPoint(event.location()) == chevron_) { 447 if (chevron_ && GetEventHandlerForPoint(event.location()) == chevron_) {
445 if (!show_menu_task_factory_.HasWeakPtrs() && !overflow_menu_) 448 if (!show_menu_task_factory_.HasWeakPtrs() && !overflow_menu_)
446 StartShowFolderDropMenuTimer(); 449 StartShowFolderDropMenuTimer();
447 return ui::DragDropTypes::DRAG_MOVE; 450 return ui::DragDropTypes::DRAG_MOVE;
448 } 451 }
449 StopShowFolderDropMenuTimer(); 452 StopShowFolderDropMenuTimer();
450 453
451 // Figure out where to display the indicator. This is a complex calculation: 454 size_t row_index = 0;
455 size_t before_icon_in_row = 0;
456 // If there are no visible browser actions (such as when dragging an icon to
457 // an empty overflow/main container), then 0, 0 for row, column is correct.
458 if (VisibleBrowserActions() != 0) {
459 // Figure out where to display the indicator. This is a complex calculation:
Devlin 2014/09/16 19:28:35 The body of this if is just the indented version o
452 460
453 // First, we figure out how much space is to the left of the icon area, so we 461 // First, we subtract out the padding to the left of the icon area, which is
454 // can calculate the true offset into the icon area. The easiest way to do 462 // ToolbarView::kStandardSpacing. If we're right-to-left, we also mirror the
455 // this is to just find where the first icon starts. 463 // event.x() so that our calculations are consistent with left-to-right.
456 int width_before_icons = 464 int offset_into_icon_area =
457 browser_action_views_[GetFirstVisibleIconIndex()]->x(); 465 GetMirroredXInView(event.x()) - ToolbarView::kStandardSpacing;
458 466
459 // If we're right-to-left, we flip the mirror the event.x() so that our 467 // Next, figure out what row we're on. This only matters for overflow mode,
460 // calculations are consistent with left-to-right. 468 // but the calculation is the same for both.
461 int offset_into_icon_area = 469 row_index = event.y() / IconHeight();
462 GetMirroredXInView(event.x()) - width_before_icons;
463 470
464 // Next, figure out what row we're on. This only matters for overflow mode, 471 // Sanity check - we should never be on a different row in the main
465 // but the calculation is the same for both. 472 // container.
466 size_t row_index = event.y() / IconHeight(); 473 DCHECK(in_overflow_mode() || row_index == 0);
467 474
468 // Sanity check - we should never be on a different row in the main container. 475 // Next, we determine which icon to place the indicator in front of. We want
469 DCHECK(in_overflow_mode() || row_index == 0); 476 // to place the indicator in front of icon n when the cursor is between the
477 // midpoints of icons (n - 1) and n. To do this we take the offset into the
478 // icon area and transform it as follows:
479 //
480 // Real icon area:
481 // 0 a * b c
482 // | | | |
483 // |[IC|ON] [IC|ON] [IC|ON]
484 // We want to be before icon 0 for 0 < x <= a, icon 1 for a < x <= b, etc.
485 // Here the "*" represents the offset into the icon area, and since it's
486 // between a and b, we want to return "1".
487 //
488 // Transformed "icon area":
489 // 0 a * b c
490 // | | | |
491 // |[ICON] |[ICON] |[ICON] |
492 // If we shift both our offset and our divider points later by half an icon
493 // plus one spacing unit, then it becomes very easy to calculate how many
494 // divider points we've passed, because they're the multiples of "one icon
495 // plus padding".
496 int before_icon_unclamped =
497 (offset_into_icon_area + (IconWidth(false) / 2) +
498 kItemSpacing) / IconWidth(true);
470 499
471 // Next, we determine which icon to place the indicator in front of. We want 500 // We need to figure out how many icons are visible on the relevant row.
472 // to place the indicator in front of icon n when the cursor is between the 501 // In the main container, this will just be the visible actions.
473 // midpoints of icons (n - 1) and n. To do this we take the offset into the 502 int visible_icons_on_row = VisibleBrowserActionsAfterAnimation();
474 // icon area and transform it as follows: 503 if (in_overflow_mode()) {
475 // 504 // If this is the final row of the overflow, then this is the remainder of
476 // Real icon area: 505 // visible icons. Otherwise, it's a full row (kIconsPerRow).
477 // 0 a * b c 506 visible_icons_on_row =
478 // | | | | 507 row_index ==
479 // |[IC|ON] [IC|ON] [IC|ON] 508 static_cast<size_t>(visible_icons_on_row /
480 // We want to be before icon 0 for 0 < x <= a, icon 1 for a < x <= b, etc. 509 icons_per_overflow_menu_row_) ?
481 // Here the "*" represents the offset into the icon area, and since it's 510 visible_icons_on_row % icons_per_overflow_menu_row_ :
482 // between a and b, we want to return "1". 511 icons_per_overflow_menu_row_;
483 // 512 }
484 // Transformed "icon area":
485 // 0 a * b c
486 // | | | |
487 // |[ICON] |[ICON] |[ICON] |
488 // If we shift both our offset and our divider points later by half an icon
489 // plus one spacing unit, then it becomes very easy to calculate how many
490 // divider points we've passed, because they're the multiples of "one icon
491 // plus padding".
492 int before_icon_unclamped = (offset_into_icon_area + (IconWidth(false) / 2) +
493 kItemSpacing) / IconWidth(true);
494 513
495 // We need to figure out how many icons are visible on the relevant row. 514 // Because the user can drag outside the container bounds, we need to clamp
496 // In the main container, this will just be the visible actions. 515 // to the valid range. Note that the maximum allowable value is (num icons),
497 int visible_icons_on_row = VisibleBrowserActionsAfterAnimation(); 516 // not (num icons - 1), because we represent the indicator being past the
498 if (in_overflow_mode()) { 517 // last icon as being "before the (last + 1) icon".
499 // If this is the final row of the overflow, then this is the remainder of 518 before_icon_in_row =
500 // visible icons. Otherwise, it's a full row (kIconsPerRow). 519 std::min(std::max(before_icon_unclamped, 0), visible_icons_on_row);
501 visible_icons_on_row =
502 row_index ==
503 static_cast<size_t>(visible_icons_on_row /
504 icons_per_overflow_menu_row_) ?
505 visible_icons_on_row % icons_per_overflow_menu_row_ :
506 icons_per_overflow_menu_row_;
507 } 520 }
508 521
509 // Because the user can drag outside the container bounds, we need to clamp to
510 // the valid range. Note that the maximum allowable value is (num icons), not
511 // (num icons - 1), because we represent the indicator being past the last
512 // icon as being "before the (last + 1) icon".
513 size_t before_icon_in_row =
514 std::min(std::max(before_icon_unclamped, 0), visible_icons_on_row);
515
516 if (!drop_position_.get() || 522 if (!drop_position_.get() ||
517 !(drop_position_->row == row_index && 523 !(drop_position_->row == row_index &&
518 drop_position_->icon_in_row == before_icon_in_row)) { 524 drop_position_->icon_in_row == before_icon_in_row)) {
519 drop_position_.reset(new DropPosition(row_index, before_icon_in_row)); 525 drop_position_.reset(new DropPosition(row_index, before_icon_in_row));
520 SchedulePaint(); 526 SchedulePaint();
521 } 527 }
522 528
523 return ui::DragDropTypes::DRAG_MOVE; 529 return ui::DragDropTypes::DRAG_MOVE;
524 } 530 }
525 531
(...skipping 10 matching lines...) Expand all
536 return ui::DragDropTypes::DRAG_NONE; 542 return ui::DragDropTypes::DRAG_NONE;
537 543
538 // Make sure we have the same view as we started with. 544 // Make sure we have the same view as we started with.
539 DCHECK_EQ(browser_action_views_[data.index()]->extension()->id(), 545 DCHECK_EQ(browser_action_views_[data.index()]->extension()->id(),
540 data.id()); 546 data.id());
541 DCHECK(model_); 547 DCHECK(model_);
542 548
543 size_t i = drop_position_->row * icons_per_overflow_menu_row_ + 549 size_t i = drop_position_->row * icons_per_overflow_menu_row_ +
544 drop_position_->icon_in_row; 550 drop_position_->icon_in_row;
545 if (in_overflow_mode()) 551 if (in_overflow_mode())
546 i += GetFirstVisibleIconIndex(); 552 i += main_container_->VisibleBrowserActionsAfterAnimation();
Peter Kasting 2014/09/16 21:40:54 It looks like now |i| is going to be based on the
Devlin 2014/09/16 21:58:29 Line 551 ensures that we're in the overflow contai
Peter Kasting 2014/09/16 22:08:49 I know. I'm saying, the old code here called GetF
Devlin 2014/09/16 22:10:39 GetFirstVisibleIconIndex() would always return mai
Peter Kasting 2014/09/16 22:15:57 Oh, I'm dumb, I mentally reversed the contents of
Devlin 2014/09/16 22:25:37 Happens to all of us. :)
547 // |i| now points to the item to the right of the drop indicator*, which is 553 // |i| now points to the item to the right of the drop indicator*, which is
548 // correct when dragging an icon to the left. When dragging to the right, 554 // correct when dragging an icon to the left. When dragging to the right,
549 // however, we want the icon being dragged to get the index of the item to 555 // however, we want the icon being dragged to get the index of the item to
550 // the left of the drop indicator, so we subtract one. 556 // the left of the drop indicator, so we subtract one.
551 // * Well, it can also point to the end, but not when dragging to the left. :) 557 // * Well, it can also point to the end, but not when dragging to the left. :)
552 if (i > data.index()) 558 if (i > data.index())
553 --i; 559 --i;
554 560
555 if (profile_->IsOffTheRecord()) 561 if (profile_->IsOffTheRecord())
556 i = model_->IncognitoIndexToOriginal(i); 562 i = model_->IncognitoIndexToOriginal(i);
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
695 extensions::ActiveTabPermissionGranter* 701 extensions::ActiveTabPermissionGranter*
696 BrowserActionsContainer::GetActiveTabPermissionGranter() { 702 BrowserActionsContainer::GetActiveTabPermissionGranter() {
697 content::WebContents* web_contents = 703 content::WebContents* web_contents =
698 browser_->tab_strip_model()->GetActiveWebContents(); 704 browser_->tab_strip_model()->GetActiveWebContents();
699 if (!web_contents) 705 if (!web_contents)
700 return NULL; 706 return NULL;
701 return extensions::TabHelper::FromWebContents(web_contents)-> 707 return extensions::TabHelper::FromWebContents(web_contents)->
702 active_tab_permission_granter(); 708 active_tab_permission_granter();
703 } 709 }
704 710
705 size_t BrowserActionsContainer::GetFirstVisibleIconIndex() const {
706 return in_overflow_mode() ?
707 main_container_->VisibleBrowserActionsAfterAnimation() : 0;
708 }
709
710 ExtensionPopup* BrowserActionsContainer::TestGetPopup() { 711 ExtensionPopup* BrowserActionsContainer::TestGetPopup() {
711 return popup_owner_ ? popup_owner_->view_controller()->popup() : NULL; 712 return popup_owner_ ? popup_owner_->view_controller()->popup() : NULL;
712 } 713 }
713 714
714 void BrowserActionsContainer::TestSetIconVisibilityCount(size_t icons) { 715 void BrowserActionsContainer::TestSetIconVisibilityCount(size_t icons) {
715 model_->SetVisibleIconCountForTest(icons); 716 model_->SetVisibleIconCountForTest(icons);
716 } 717 }
717 718
718 void BrowserActionsContainer::OnPaint(gfx::Canvas* canvas) { 719 void BrowserActionsContainer::OnPaint(gfx::Canvas* canvas) {
719 // If the views haven't been initialized yet, wait for the next call to 720 // If the views haven't been initialized yet, wait for the next call to
720 // paint (one will be triggered by entering highlight mode). 721 // paint (one will be triggered by entering highlight mode).
721 if (model_->is_highlighting() && !browser_action_views_.empty()) { 722 if (model_->is_highlighting() && !browser_action_views_.empty()) {
722 views::Painter::PaintPainterAt( 723 views::Painter::PaintPainterAt(
723 canvas, highlight_painter_.get(), GetLocalBounds()); 724 canvas, highlight_painter_.get(), GetLocalBounds());
724 } 725 }
725 726
726 // TODO(sky/glen): Instead of using a drop indicator, animate the icons while 727 // TODO(sky/glen): Instead of using a drop indicator, animate the icons while
727 // dragging (like we do for tab dragging). 728 // dragging (like we do for tab dragging).
728 if (drop_position_.get()) { 729 if (drop_position_.get()) {
729 // The two-pixel width drop indicator. 730 // The two-pixel width drop indicator.
730 static const int kDropIndicatorWidth = 2; 731 static const int kDropIndicatorWidth = 2;
731 732
732 // Convert back to a pixel offset into the container. First find the X 733 // Convert back to a pixel offset into the container. First find the X
733 // coordinate of the drop icon. 734 // coordinate of the drop icon.
734 int drop_icon_x = browser_action_views_[GetFirstVisibleIconIndex()]->x() + 735 int drop_icon_x = ToolbarView::kStandardSpacing +
Peter Kasting 2014/09/16 21:40:54 This seems very different than the old code. Why
Devlin 2014/09/16 21:58:29 Before, we would say "The start of the first visib
735 (drop_position_->icon_in_row * IconWidth(true)); 736 (drop_position_->icon_in_row * IconWidth(true));
Peter Kasting 2014/09/16 21:40:54 Nit: Previous indenting was correct
Devlin 2014/09/16 21:58:29 changed back.
736 // Next, find the space before the drop icon. This will either be 737 // Next, find the space before the drop icon. This will either be
737 // kItemSpacing or ToolbarView::kStandardSpacing, depending on whether this 738 // kItemSpacing or ToolbarView::kStandardSpacing, depending on whether this
738 // is the first icon. 739 // is the first icon.
739 // NOTE: Right now, these are the same. But let's do this right for if they 740 // NOTE: Right now, these are the same. But let's do this right for if they
740 // ever aren't. 741 // ever aren't.
741 int space_before_drop_icon = drop_position_->icon_in_row == 0 ? 742 int space_before_drop_icon = drop_position_->icon_in_row == 0 ?
742 ToolbarView::kStandardSpacing : kItemSpacing; 743 ToolbarView::kStandardSpacing : kItemSpacing;
743 // Now place the drop indicator halfway between this and the end of the 744 // Now place the drop indicator halfway between this and the end of the
744 // previous icon. If there is an odd amount of available space between the 745 // previous icon. If there is an odd amount of available space between the
745 // two icons (or the icon and the address bar) after subtracting the drop 746 // two icons (or the icon and the address bar) after subtracting the drop
(...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after
1132 if (initialized_ && profile_->IsOffTheRecord()) { 1133 if (initialized_ && profile_->IsOffTheRecord()) {
1133 main_displayed = in_overflow_mode() ? 1134 main_displayed = in_overflow_mode() ?
1134 main_container_->VisibleBrowserActionsAfterAnimation() : 1135 main_container_->VisibleBrowserActionsAfterAnimation() :
1135 VisibleBrowserActionsAfterAnimation(); 1136 VisibleBrowserActionsAfterAnimation();
1136 } 1137 }
1137 1138
1138 // The overflow displays any (displayable) icons not shown by the main bar. 1139 // The overflow displays any (displayable) icons not shown by the main bar.
1139 return in_overflow_mode() ? 1140 return in_overflow_mode() ?
1140 displayable_icon_count - main_displayed : main_displayed; 1141 displayable_icon_count - main_displayed : main_displayed;
1141 } 1142 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698