OLD | NEW |
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 Loading... |
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 // Since this happens when an icon moves from the main bar to overflow, we |
| 274 // can't possibly have had no visible icons on the main bar. |
| 275 DCHECK_NE(0, icon_count); |
| 276 if (icon_count == -1) |
| 277 icon_count = browser_action_views_.size(); |
| 278 model_->SetVisibleIconCount(icon_count - 1); |
| 279 } |
273 Animate(gfx::Tween::EASE_OUT, | 280 Animate(gfx::Tween::EASE_OUT, |
274 VisibleBrowserActionsAfterAnimation() - 1); | 281 VisibleBrowserActionsAfterAnimation() - 1); |
275 } | 282 } |
276 | 283 |
277 bool BrowserActionsContainer::ShownInsideMenu() const { | 284 bool BrowserActionsContainer::ShownInsideMenu() const { |
278 return in_overflow_mode(); | 285 return in_overflow_mode(); |
279 } | 286 } |
280 | 287 |
281 void BrowserActionsContainer::OnBrowserActionViewDragDone() { | 288 void BrowserActionsContainer::OnBrowserActionViewDragDone() { |
282 ToolbarVisibleCountChanged(); | 289 ToolbarVisibleCountChanged(); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
315 BrowserActionsContainerObserver* observer) { | 322 BrowserActionsContainerObserver* observer) { |
316 observers_.AddObserver(observer); | 323 observers_.AddObserver(observer); |
317 } | 324 } |
318 | 325 |
319 void BrowserActionsContainer::RemoveObserver( | 326 void BrowserActionsContainer::RemoveObserver( |
320 BrowserActionsContainerObserver* observer) { | 327 BrowserActionsContainerObserver* observer) { |
321 observers_.RemoveObserver(observer); | 328 observers_.RemoveObserver(observer); |
322 } | 329 } |
323 | 330 |
324 gfx::Size BrowserActionsContainer::GetPreferredSize() const { | 331 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()) { | 332 if (in_overflow_mode()) { |
336 // When in overflow, y is multiline, so the pixel count is IconHeight() | 333 int icon_count = GetIconCount(); |
337 // times the number of rows needed. | 334 // In overflow, we always have a preferred size of a full row (even if we |
| 335 // don't use it), and always of at least one row. The parent may decide to |
| 336 // show us even when empty, e.g. as a drag target for dragging in icons from |
| 337 // the main container. |
| 338 int row_count = |
| 339 ((std::max(0, icon_count - 1)) / icons_per_overflow_menu_row_) + 1; |
338 return gfx::Size( | 340 return gfx::Size( |
339 IconCountToWidth(icons_per_overflow_menu_row_, false), | 341 IconCountToWidth(icons_per_overflow_menu_row_, false), |
340 (((icon_count - 1) / icons_per_overflow_menu_row_) + 1) * IconHeight()); | 342 row_count * IconHeight()); |
341 } | 343 } |
342 | 344 |
| 345 // If there are no actions to show, then don't show the container at all. |
| 346 if (browser_action_views_.empty()) |
| 347 return gfx::Size(); |
| 348 |
343 // We calculate the size of the view by taking the current width and | 349 // 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 | 350 // 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). | 351 // 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 | 352 // 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. | 353 // container can never shrink too far or take up more space than it needs. |
348 // In other words: MinimumNonemptyWidth() < width() - resize < ClampTo(MAX). | 354 // In other words: MinimumNonemptyWidth() < width() - resize < ClampTo(MAX). |
349 int preferred_width = std::min( | 355 int preferred_width = std::min( |
350 std::max(MinimumNonemptyWidth(), container_width_ - resize_amount_), | 356 std::max(MinimumNonemptyWidth(), container_width_ - resize_amount_), |
351 IconCountToWidth(-1, false)); | 357 IconCountToWidth(-1, false)); |
352 return gfx::Size(preferred_width, IconHeight()); | 358 return gfx::Size(preferred_width, IconHeight()); |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
441 int BrowserActionsContainer::OnDragUpdated( | 447 int BrowserActionsContainer::OnDragUpdated( |
442 const ui::DropTargetEvent& event) { | 448 const ui::DropTargetEvent& event) { |
443 // First check if we are above the chevron (overflow) menu. | 449 // First check if we are above the chevron (overflow) menu. |
444 if (chevron_ && GetEventHandlerForPoint(event.location()) == chevron_) { | 450 if (chevron_ && GetEventHandlerForPoint(event.location()) == chevron_) { |
445 if (!show_menu_task_factory_.HasWeakPtrs() && !overflow_menu_) | 451 if (!show_menu_task_factory_.HasWeakPtrs() && !overflow_menu_) |
446 StartShowFolderDropMenuTimer(); | 452 StartShowFolderDropMenuTimer(); |
447 return ui::DragDropTypes::DRAG_MOVE; | 453 return ui::DragDropTypes::DRAG_MOVE; |
448 } | 454 } |
449 StopShowFolderDropMenuTimer(); | 455 StopShowFolderDropMenuTimer(); |
450 | 456 |
451 // Figure out where to display the indicator. This is a complex calculation: | 457 size_t row_index = 0; |
| 458 size_t before_icon_in_row = 0; |
| 459 // If there are no visible browser actions (such as when dragging an icon to |
| 460 // an empty overflow/main container), then 0, 0 for row, column is correct. |
| 461 if (VisibleBrowserActions() != 0) { |
| 462 // Figure out where to display the indicator. This is a complex calculation: |
452 | 463 |
453 // First, we figure out how much space is to the left of the icon area, so we | 464 // 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 | 465 // ToolbarView::kStandardSpacing. If we're right-to-left, we also mirror the |
455 // this is to just find where the first icon starts. | 466 // event.x() so that our calculations are consistent with left-to-right. |
456 int width_before_icons = | 467 int offset_into_icon_area = |
457 browser_action_views_[GetFirstVisibleIconIndex()]->x(); | 468 GetMirroredXInView(event.x()) - ToolbarView::kStandardSpacing; |
458 | 469 |
459 // If we're right-to-left, we flip the mirror the event.x() so that our | 470 // Next, figure out what row we're on. This only matters for overflow mode, |
460 // calculations are consistent with left-to-right. | 471 // but the calculation is the same for both. |
461 int offset_into_icon_area = | 472 row_index = event.y() / IconHeight(); |
462 GetMirroredXInView(event.x()) - width_before_icons; | |
463 | 473 |
464 // Next, figure out what row we're on. This only matters for overflow mode, | 474 // Sanity check - we should never be on a different row in the main |
465 // but the calculation is the same for both. | 475 // container. |
466 size_t row_index = event.y() / IconHeight(); | 476 DCHECK(in_overflow_mode() || row_index == 0); |
467 | 477 |
468 // Sanity check - we should never be on a different row in the main container. | 478 // Next, we determine which icon to place the indicator in front of. We want |
469 DCHECK(in_overflow_mode() || row_index == 0); | 479 // to place the indicator in front of icon n when the cursor is between the |
| 480 // midpoints of icons (n - 1) and n. To do this we take the offset into the |
| 481 // icon area and transform it as follows: |
| 482 // |
| 483 // Real icon area: |
| 484 // 0 a * b c |
| 485 // | | | | |
| 486 // |[IC|ON] [IC|ON] [IC|ON] |
| 487 // We want to be before icon 0 for 0 < x <= a, icon 1 for a < x <= b, etc. |
| 488 // Here the "*" represents the offset into the icon area, and since it's |
| 489 // between a and b, we want to return "1". |
| 490 // |
| 491 // Transformed "icon area": |
| 492 // 0 a * b c |
| 493 // | | | | |
| 494 // |[ICON] |[ICON] |[ICON] | |
| 495 // If we shift both our offset and our divider points later by half an icon |
| 496 // plus one spacing unit, then it becomes very easy to calculate how many |
| 497 // divider points we've passed, because they're the multiples of "one icon |
| 498 // plus padding". |
| 499 int before_icon_unclamped = |
| 500 (offset_into_icon_area + (IconWidth(false) / 2) + |
| 501 kItemSpacing) / IconWidth(true); |
470 | 502 |
471 // Next, we determine which icon to place the indicator in front of. We want | 503 // 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 | 504 // 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 | 505 int visible_icons_on_row = VisibleBrowserActionsAfterAnimation(); |
474 // icon area and transform it as follows: | 506 if (in_overflow_mode()) { |
475 // | 507 // If this is the final row of the overflow, then this is the remainder of |
476 // Real icon area: | 508 // visible icons. Otherwise, it's a full row (kIconsPerRow). |
477 // 0 a * b c | 509 visible_icons_on_row = |
478 // | | | | | 510 row_index == |
479 // |[IC|ON] [IC|ON] [IC|ON] | 511 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. | 512 icons_per_overflow_menu_row_) ? |
481 // Here the "*" represents the offset into the icon area, and since it's | 513 visible_icons_on_row % icons_per_overflow_menu_row_ : |
482 // between a and b, we want to return "1". | 514 icons_per_overflow_menu_row_; |
483 // | 515 } |
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 | 516 |
495 // We need to figure out how many icons are visible on the relevant row. | 517 // 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. | 518 // to the valid range. Note that the maximum allowable value is (num icons), |
497 int visible_icons_on_row = VisibleBrowserActionsAfterAnimation(); | 519 // not (num icons - 1), because we represent the indicator being past the |
498 if (in_overflow_mode()) { | 520 // 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 | 521 before_icon_in_row = |
500 // visible icons. Otherwise, it's a full row (kIconsPerRow). | 522 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 } | 523 } |
508 | 524 |
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() || | 525 if (!drop_position_.get() || |
517 !(drop_position_->row == row_index && | 526 !(drop_position_->row == row_index && |
518 drop_position_->icon_in_row == before_icon_in_row)) { | 527 drop_position_->icon_in_row == before_icon_in_row)) { |
519 drop_position_.reset(new DropPosition(row_index, before_icon_in_row)); | 528 drop_position_.reset(new DropPosition(row_index, before_icon_in_row)); |
520 SchedulePaint(); | 529 SchedulePaint(); |
521 } | 530 } |
522 | 531 |
523 return ui::DragDropTypes::DRAG_MOVE; | 532 return ui::DragDropTypes::DRAG_MOVE; |
524 } | 533 } |
525 | 534 |
(...skipping 10 matching lines...) Expand all Loading... |
536 return ui::DragDropTypes::DRAG_NONE; | 545 return ui::DragDropTypes::DRAG_NONE; |
537 | 546 |
538 // Make sure we have the same view as we started with. | 547 // Make sure we have the same view as we started with. |
539 DCHECK_EQ(browser_action_views_[data.index()]->extension()->id(), | 548 DCHECK_EQ(browser_action_views_[data.index()]->extension()->id(), |
540 data.id()); | 549 data.id()); |
541 DCHECK(model_); | 550 DCHECK(model_); |
542 | 551 |
543 size_t i = drop_position_->row * icons_per_overflow_menu_row_ + | 552 size_t i = drop_position_->row * icons_per_overflow_menu_row_ + |
544 drop_position_->icon_in_row; | 553 drop_position_->icon_in_row; |
545 if (in_overflow_mode()) | 554 if (in_overflow_mode()) |
546 i += GetFirstVisibleIconIndex(); | 555 i += main_container_->VisibleBrowserActionsAfterAnimation(); |
547 // |i| now points to the item to the right of the drop indicator*, which is | 556 // |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, | 557 // 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 | 558 // 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. | 559 // 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. :) | 560 // * Well, it can also point to the end, but not when dragging to the left. :) |
552 if (i > data.index()) | 561 if (i > data.index()) |
553 --i; | 562 --i; |
554 | 563 |
555 if (profile_->IsOffTheRecord()) | 564 if (profile_->IsOffTheRecord()) |
556 i = model_->IncognitoIndexToOriginal(i); | 565 i = model_->IncognitoIndexToOriginal(i); |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
695 extensions::ActiveTabPermissionGranter* | 704 extensions::ActiveTabPermissionGranter* |
696 BrowserActionsContainer::GetActiveTabPermissionGranter() { | 705 BrowserActionsContainer::GetActiveTabPermissionGranter() { |
697 content::WebContents* web_contents = | 706 content::WebContents* web_contents = |
698 browser_->tab_strip_model()->GetActiveWebContents(); | 707 browser_->tab_strip_model()->GetActiveWebContents(); |
699 if (!web_contents) | 708 if (!web_contents) |
700 return NULL; | 709 return NULL; |
701 return extensions::TabHelper::FromWebContents(web_contents)-> | 710 return extensions::TabHelper::FromWebContents(web_contents)-> |
702 active_tab_permission_granter(); | 711 active_tab_permission_granter(); |
703 } | 712 } |
704 | 713 |
705 size_t BrowserActionsContainer::GetFirstVisibleIconIndex() const { | |
706 return in_overflow_mode() ? | |
707 main_container_->VisibleBrowserActionsAfterAnimation() : 0; | |
708 } | |
709 | |
710 ExtensionPopup* BrowserActionsContainer::TestGetPopup() { | 714 ExtensionPopup* BrowserActionsContainer::TestGetPopup() { |
711 return popup_owner_ ? popup_owner_->view_controller()->popup() : NULL; | 715 return popup_owner_ ? popup_owner_->view_controller()->popup() : NULL; |
712 } | 716 } |
713 | 717 |
714 void BrowserActionsContainer::TestSetIconVisibilityCount(size_t icons) { | 718 void BrowserActionsContainer::TestSetIconVisibilityCount(size_t icons) { |
715 model_->SetVisibleIconCountForTest(icons); | 719 model_->SetVisibleIconCountForTest(icons); |
716 } | 720 } |
717 | 721 |
718 void BrowserActionsContainer::OnPaint(gfx::Canvas* canvas) { | 722 void BrowserActionsContainer::OnPaint(gfx::Canvas* canvas) { |
719 // If the views haven't been initialized yet, wait for the next call to | 723 // If the views haven't been initialized yet, wait for the next call to |
720 // paint (one will be triggered by entering highlight mode). | 724 // paint (one will be triggered by entering highlight mode). |
721 if (model_->is_highlighting() && !browser_action_views_.empty()) { | 725 if (model_->is_highlighting() && !browser_action_views_.empty()) { |
722 views::Painter::PaintPainterAt( | 726 views::Painter::PaintPainterAt( |
723 canvas, highlight_painter_.get(), GetLocalBounds()); | 727 canvas, highlight_painter_.get(), GetLocalBounds()); |
724 } | 728 } |
725 | 729 |
726 // TODO(sky/glen): Instead of using a drop indicator, animate the icons while | 730 // TODO(sky/glen): Instead of using a drop indicator, animate the icons while |
727 // dragging (like we do for tab dragging). | 731 // dragging (like we do for tab dragging). |
728 if (drop_position_.get()) { | 732 if (drop_position_.get()) { |
729 // The two-pixel width drop indicator. | 733 // The two-pixel width drop indicator. |
730 static const int kDropIndicatorWidth = 2; | 734 static const int kDropIndicatorWidth = 2; |
731 | 735 |
732 // Convert back to a pixel offset into the container. First find the X | 736 // Convert back to a pixel offset into the container. First find the X |
733 // coordinate of the drop icon. | 737 // coordinate of the drop icon. |
734 int drop_icon_x = browser_action_views_[GetFirstVisibleIconIndex()]->x() + | 738 int drop_icon_x = ToolbarView::kStandardSpacing + |
735 (drop_position_->icon_in_row * IconWidth(true)); | 739 (drop_position_->icon_in_row * IconWidth(true)); |
736 // Next, find the space before the drop icon. This will either be | 740 // Next, find the space before the drop icon. This will either be |
737 // kItemSpacing or ToolbarView::kStandardSpacing, depending on whether this | 741 // kItemSpacing or ToolbarView::kStandardSpacing, depending on whether this |
738 // is the first icon. | 742 // is the first icon. |
739 // NOTE: Right now, these are the same. But let's do this right for if they | 743 // NOTE: Right now, these are the same. But let's do this right for if they |
740 // ever aren't. | 744 // ever aren't. |
741 int space_before_drop_icon = drop_position_->icon_in_row == 0 ? | 745 int space_before_drop_icon = drop_position_->icon_in_row == 0 ? |
742 ToolbarView::kStandardSpacing : kItemSpacing; | 746 ToolbarView::kStandardSpacing : kItemSpacing; |
743 // Now place the drop indicator halfway between this and the end of the | 747 // 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 | 748 // previous icon. If there is an odd amount of available space between the |
(...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1132 if (initialized_ && profile_->IsOffTheRecord()) { | 1136 if (initialized_ && profile_->IsOffTheRecord()) { |
1133 main_displayed = in_overflow_mode() ? | 1137 main_displayed = in_overflow_mode() ? |
1134 main_container_->VisibleBrowserActionsAfterAnimation() : | 1138 main_container_->VisibleBrowserActionsAfterAnimation() : |
1135 VisibleBrowserActionsAfterAnimation(); | 1139 VisibleBrowserActionsAfterAnimation(); |
1136 } | 1140 } |
1137 | 1141 |
1138 // The overflow displays any (displayable) icons not shown by the main bar. | 1142 // The overflow displays any (displayable) icons not shown by the main bar. |
1139 return in_overflow_mode() ? | 1143 return in_overflow_mode() ? |
1140 displayable_icon_count - main_displayed : main_displayed; | 1144 displayable_icon_count - main_displayed : main_displayed; |
1141 } | 1145 } |
OLD | NEW |