Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/tabs/tab_strip.h" | 5 #include "chrome/browser/ui/views/tabs/tab_strip.h" |
| 6 | 6 |
| 7 #if defined(OS_WIN) | 7 #if defined(OS_WIN) |
| 8 #include <windowsx.h> | 8 #include <windowsx.h> |
| 9 #endif | 9 #endif |
| 10 | 10 |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 120 base::string16 GetClipboardText() { | 120 base::string16 GetClipboardText() { |
| 121 if (!ui::Clipboard::IsSupportedClipboardType(ui::CLIPBOARD_TYPE_SELECTION)) | 121 if (!ui::Clipboard::IsSupportedClipboardType(ui::CLIPBOARD_TYPE_SELECTION)) |
| 122 return base::string16(); | 122 return base::string16(); |
| 123 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); | 123 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); |
| 124 CHECK(clipboard); | 124 CHECK(clipboard); |
| 125 base::string16 clipboard_text; | 125 base::string16 clipboard_text; |
| 126 clipboard->ReadText(ui::CLIPBOARD_TYPE_SELECTION, &clipboard_text); | 126 clipboard->ReadText(ui::CLIPBOARD_TYPE_SELECTION, &clipboard_text); |
| 127 return clipboard_text; | 127 return clipboard_text; |
| 128 } | 128 } |
| 129 | 129 |
| 130 // Animation delegate used for any automatic tab movement. Hides the tab if it | |
| 131 // is not fully visible within the tabstrip area, to prevent overflow clipping. | |
| 132 class TabAnimationDelegate : public gfx::AnimationDelegate { | |
| 133 public: | |
| 134 TabAnimationDelegate(TabStrip* tab_strip, Tab* tab); | |
| 135 virtual ~TabAnimationDelegate(); | |
| 136 | |
| 137 virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE; | |
| 138 | |
| 139 protected: | |
| 140 TabStrip* tab_strip() { return tab_strip_; } | |
| 141 Tab* tab() { return tab_; } | |
| 142 | |
| 143 private: | |
| 144 TabStrip* const tab_strip_; | |
| 145 Tab* const tab_; | |
| 146 | |
| 147 DISALLOW_COPY_AND_ASSIGN(TabAnimationDelegate); | |
| 148 }; | |
| 149 | |
| 150 TabAnimationDelegate::TabAnimationDelegate(TabStrip* tab_strip, Tab* tab) | |
| 151 : tab_strip_(tab_strip), | |
| 152 tab_(tab) { | |
| 153 } | |
| 154 | |
| 155 TabAnimationDelegate::~TabAnimationDelegate() { | |
| 156 } | |
| 157 | |
| 158 void TabAnimationDelegate::AnimationProgressed( | |
| 159 const gfx::Animation* animation) { | |
| 160 tab_->SetVisible(tab_strip_->ShouldTabBeVisible(tab_)); | |
| 161 } | |
| 162 | |
| 130 // Animation delegate used when a dragged tab is released. When done sets the | 163 // Animation delegate used when a dragged tab is released. When done sets the |
| 131 // dragging state to false. | 164 // dragging state to false. |
| 132 class ResetDraggingStateDelegate : public gfx::AnimationDelegate { | 165 class ResetDraggingStateDelegate : public TabAnimationDelegate { |
| 133 public: | 166 public: |
| 134 explicit ResetDraggingStateDelegate(Tab* tab); | 167 ResetDraggingStateDelegate(TabStrip* tab_strip, Tab* tab); |
| 135 virtual ~ResetDraggingStateDelegate(); | 168 virtual ~ResetDraggingStateDelegate(); |
| 136 | 169 |
| 137 virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE; | 170 virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE; |
| 138 virtual void AnimationCanceled(const gfx::Animation* animation) OVERRIDE; | 171 virtual void AnimationCanceled(const gfx::Animation* animation) OVERRIDE; |
| 139 | 172 |
| 140 private: | 173 private: |
| 141 Tab* tab_; | |
| 142 | |
| 143 DISALLOW_COPY_AND_ASSIGN(ResetDraggingStateDelegate); | 174 DISALLOW_COPY_AND_ASSIGN(ResetDraggingStateDelegate); |
| 144 }; | 175 }; |
| 145 | 176 |
| 146 ResetDraggingStateDelegate::ResetDraggingStateDelegate(Tab* tab) : tab_(tab) { | 177 ResetDraggingStateDelegate::ResetDraggingStateDelegate(TabStrip* tab_strip, |
| 178 Tab* tab) | |
| 179 : TabAnimationDelegate(tab_strip, tab) { | |
| 147 } | 180 } |
| 148 | 181 |
| 149 ResetDraggingStateDelegate::~ResetDraggingStateDelegate() { | 182 ResetDraggingStateDelegate::~ResetDraggingStateDelegate() { |
| 150 } | 183 } |
| 151 | 184 |
| 152 void ResetDraggingStateDelegate::AnimationEnded( | 185 void ResetDraggingStateDelegate::AnimationEnded( |
| 153 const gfx::Animation* animation) { | 186 const gfx::Animation* animation) { |
| 154 tab_->set_dragging(false); | 187 tab()->set_dragging(false); |
| 188 AnimationProgressed(animation); // Forces tab visibility to update. | |
| 155 } | 189 } |
| 156 | 190 |
| 157 void ResetDraggingStateDelegate::AnimationCanceled( | 191 void ResetDraggingStateDelegate::AnimationCanceled( |
| 158 const gfx::Animation* animation) { | 192 const gfx::Animation* animation) { |
| 159 AnimationEnded(animation); | 193 AnimationEnded(animation); |
| 160 } | 194 } |
| 161 | 195 |
| 162 // If |dest| contains the point |point_in_source| the event handler from |dest| | 196 // If |dest| contains the point |point_in_source| the event handler from |dest| |
| 163 // is returned. Otherwise NULL is returned. | 197 // is returned. Otherwise NULL is returned. |
| 164 views::View* ConvertPointToViewAndGetEventHandler( | 198 views::View* ConvertPointToViewAndGetEventHandler( |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 449 } | 483 } |
| 450 | 484 |
| 451 DISALLOW_COPY_AND_ASSIGN(NewTabButtonTargeter); | 485 DISALLOW_COPY_AND_ASSIGN(NewTabButtonTargeter); |
| 452 }; | 486 }; |
| 453 | 487 |
| 454 /////////////////////////////////////////////////////////////////////////////// | 488 /////////////////////////////////////////////////////////////////////////////// |
| 455 // TabStrip::RemoveTabDelegate | 489 // TabStrip::RemoveTabDelegate |
| 456 // | 490 // |
| 457 // AnimationDelegate used when removing a tab. Does the necessary cleanup when | 491 // AnimationDelegate used when removing a tab. Does the necessary cleanup when |
| 458 // done. | 492 // done. |
| 459 class TabStrip::RemoveTabDelegate : public gfx::AnimationDelegate { | 493 class TabStrip::RemoveTabDelegate : public TabAnimationDelegate { |
| 460 public: | 494 public: |
| 461 RemoveTabDelegate(TabStrip* tab_strip, Tab* tab); | 495 RemoveTabDelegate(TabStrip* tab_strip, Tab* tab); |
| 462 | 496 |
| 463 virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE; | 497 virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE; |
| 464 virtual void AnimationCanceled(const gfx::Animation* animation) OVERRIDE; | 498 virtual void AnimationCanceled(const gfx::Animation* animation) OVERRIDE; |
| 465 | 499 |
| 466 private: | 500 private: |
| 467 void CompleteRemove(); | |
| 468 | |
| 469 // When the animation completes, we send the Container a message to simulate | |
| 470 // a mouse moved event at the current mouse position. This tickles the Tab | |
| 471 // the mouse is currently over to show the "hot" state of the close button. | |
| 472 void HighlightCloseButton(); | |
| 473 | |
| 474 TabStrip* tabstrip_; | |
| 475 Tab* tab_; | |
| 476 | |
| 477 DISALLOW_COPY_AND_ASSIGN(RemoveTabDelegate); | 501 DISALLOW_COPY_AND_ASSIGN(RemoveTabDelegate); |
| 478 }; | 502 }; |
| 479 | 503 |
| 480 TabStrip::RemoveTabDelegate::RemoveTabDelegate(TabStrip* tab_strip, | 504 TabStrip::RemoveTabDelegate::RemoveTabDelegate(TabStrip* tab_strip, |
| 481 Tab* tab) | 505 Tab* tab) |
| 482 : tabstrip_(tab_strip), | 506 : TabAnimationDelegate(tab_strip, tab) { |
| 483 tab_(tab) { | |
| 484 } | 507 } |
| 485 | 508 |
| 486 void TabStrip::RemoveTabDelegate::AnimationEnded( | 509 void TabStrip::RemoveTabDelegate::AnimationEnded( |
| 487 const gfx::Animation* animation) { | 510 const gfx::Animation* animation) { |
| 488 CompleteRemove(); | 511 DCHECK(tab()->closing()); |
| 512 tab_strip()->RemoveAndDeleteTab(tab()); | |
| 513 | |
| 514 // Send the Container a message to simulate a mouse moved event at the current | |
| 515 // mouse position. This tickles the Tab the mouse is currently over to show | |
| 516 // the "hot" state of the close button. Note that this is not required (and | |
| 517 // indeed may crash!) for removes spawned by non-mouse closes and | |
| 518 // drag-detaches. | |
| 519 if (!tab_strip()->IsDragSessionActive() && | |
| 520 tab_strip()->ShouldHighlightCloseButtonAfterRemove()) { | |
| 521 // The widget can apparently be null during shutdown. | |
| 522 views::Widget* widget = tab_strip()->GetWidget(); | |
| 523 if (widget) | |
| 524 widget->SynthesizeMouseMoveEvent(); | |
| 525 } | |
| 489 } | 526 } |
| 490 | 527 |
| 491 void TabStrip::RemoveTabDelegate::AnimationCanceled( | 528 void TabStrip::RemoveTabDelegate::AnimationCanceled( |
| 492 const gfx::Animation* animation) { | 529 const gfx::Animation* animation) { |
| 493 AnimationEnded(animation); | 530 AnimationEnded(animation); |
| 494 } | 531 } |
| 495 | 532 |
| 496 void TabStrip::RemoveTabDelegate::CompleteRemove() { | |
| 497 DCHECK(tab_->closing()); | |
| 498 tabstrip_->RemoveAndDeleteTab(tab_); | |
| 499 HighlightCloseButton(); | |
| 500 } | |
| 501 | |
| 502 void TabStrip::RemoveTabDelegate::HighlightCloseButton() { | |
| 503 if (tabstrip_->IsDragSessionActive() || | |
| 504 !tabstrip_->ShouldHighlightCloseButtonAfterRemove()) { | |
| 505 // This function is not required (and indeed may crash!) for removes | |
| 506 // spawned by non-mouse closes and drag-detaches. | |
| 507 return; | |
| 508 } | |
| 509 | |
| 510 views::Widget* widget = tabstrip_->GetWidget(); | |
| 511 // This can be null during shutdown. See http://crbug.com/42737. | |
| 512 if (!widget) | |
| 513 return; | |
| 514 | |
| 515 widget->SynthesizeMouseMoveEvent(); | |
| 516 } | |
| 517 | |
| 518 /////////////////////////////////////////////////////////////////////////////// | 533 /////////////////////////////////////////////////////////////////////////////// |
| 519 // TabStrip, public: | 534 // TabStrip, public: |
| 520 | 535 |
| 521 // static | 536 // static |
| 522 const char TabStrip::kViewClassName[] = "TabStrip"; | 537 const char TabStrip::kViewClassName[] = "TabStrip"; |
| 523 const int TabStrip::kNewTabButtonHorizontalOffset = -11; | 538 const int TabStrip::kNewTabButtonHorizontalOffset = -11; |
| 524 const int TabStrip::kNewTabButtonVerticalOffset = 7; | 539 const int TabStrip::kNewTabButtonVerticalOffset = 7; |
| 525 const int TabStrip::kMiniToNonMiniGap = 3; | 540 const int TabStrip::kMiniToNonMiniGap = 3; |
| 526 const int TabStrip::kNewTabButtonAssetWidth = 34; | 541 const int TabStrip::kNewTabButtonAssetWidth = 34; |
| 527 const int TabStrip::kNewTabButtonAssetHeight = 18; | 542 const int TabStrip::kNewTabButtonAssetHeight = 18; |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 713 touch_layout_->SetXAndMiniCount(start_x, mini_tab_count); | 728 touch_layout_->SetXAndMiniCount(start_x, mini_tab_count); |
| 714 } | 729 } |
| 715 if (GetWidget() && GetWidget()->IsVisible()) | 730 if (GetWidget() && GetWidget()->IsVisible()) |
| 716 StartMiniTabAnimation(); | 731 StartMiniTabAnimation(); |
| 717 else | 732 else |
| 718 DoLayout(); | 733 DoLayout(); |
| 719 } | 734 } |
| 720 SwapLayoutIfNecessary(); | 735 SwapLayoutIfNecessary(); |
| 721 } | 736 } |
| 722 | 737 |
| 738 bool TabStrip::ShouldTabBeVisible(const Tab* tab) const { | |
| 739 // When stacking tabs, all tabs should always be visible. | |
| 740 if (stacked_layout_) | |
|
sky
2014/06/17 19:41:17
touch_layout_ is more correct here.
Peter Kasting
2014/06/17 20:20:20
Why? If stacked_layout_ is true, then either we'r
sky
2014/06/17 23:53:13
No, you're right.
| |
| 741 return true; | |
| 742 | |
| 743 // If the tab is currently clipped, it shouldn't be visible. Note that we | |
| 744 // allow dragged tabs to draw over the "New Tab button" region as well, | |
| 745 // because either the New Tab button will be hidden, or the dragged tabs will | |
| 746 // be animating back to their normal positions and we don't want to hide them | |
| 747 // in the New Tab button region in case they re-appear after leaving it. | |
| 748 // (This prevents flickeriness.) We never draw non-dragged tabs in New Tab | |
| 749 // button area, even when the button is invisible, so that they don't appear | |
| 750 // to "pop in" when the button disappears. | |
| 751 // TODO: Probably doesn't work for RTL | |
| 752 int right_edge = tab->bounds().right(); | |
| 753 const int visible_width = tab->dragging() ? width() : tab_area_width(); | |
| 754 if (right_edge > visible_width) | |
| 755 return false; | |
| 756 | |
| 757 // Non-clipped dragging tabs should always be visible. | |
| 758 if (tab->dragging()) | |
| 759 return true; | |
| 760 | |
| 761 // Let all non-clipped closing tabs be visible. These will probably finish | |
| 762 // closing before the user changes the active tab, so there's little reason to | |
| 763 // try and make the more complex logic below apply. | |
| 764 if (tab->closing()) | |
| 765 return true; | |
| 766 | |
| 767 // Now we need to check whether the tab isn't currently clipped, but could | |
| 768 // become clipped if we changed the active tab, widening either this tab or | |
| 769 // the tabstrip portion before it. | |
| 770 | |
| 771 // Mini tabs don't change size when activated, so any tab in the mini tab | |
| 772 // region is safe. | |
| 773 const int tab_index = GetModelIndexOfTab(tab); | |
| 774 if (tab_index <= GetMiniTabCount()) | |
|
sky
2014/06/17 19:41:18
I would check tab->data().mini here. The condition
Peter Kasting
2014/06/17 20:20:20
Done.
| |
| 775 return true; | |
| 776 | |
| 777 // If the active tab is on or before this tab, we're safe. | |
| 778 if (controller_->GetActiveIndex() <= tab_index) | |
| 779 return true; | |
| 780 | |
| 781 // We need to check what would happen if the active tab were to move to this | |
| 782 // tab or before. | |
| 783 return (right_edge + current_selected_width_ - current_unselected_width_) <= | |
| 784 tab_area_width(); | |
| 785 } | |
| 786 | |
| 723 void TabStrip::PrepareForCloseAt(int model_index, CloseTabSource source) { | 787 void TabStrip::PrepareForCloseAt(int model_index, CloseTabSource source) { |
| 724 if (!in_tab_close_ && IsAnimating()) { | 788 if (!in_tab_close_ && IsAnimating()) { |
| 725 // Cancel any current animations. We do this as remove uses the current | 789 // Cancel any current animations. We do this as remove uses the current |
| 726 // ideal bounds and we need to know ideal bounds is in a good state. | 790 // ideal bounds and we need to know ideal bounds is in a good state. |
| 727 StopAnimating(true); | 791 StopAnimating(true); |
| 728 } | 792 } |
| 729 | 793 |
| 730 if (!GetWidget()) | 794 if (!GetWidget()) |
| 731 return; | 795 return; |
| 732 | 796 |
| (...skipping 752 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1485 // strip. | 1549 // strip. |
| 1486 if (TabDragController::IsAttachedTo(this)) { | 1550 if (TabDragController::IsAttachedTo(this)) { |
| 1487 bounds_animator_.StopAnimatingView(newtab_button_); | 1551 bounds_animator_.StopAnimatingView(newtab_button_); |
| 1488 newtab_button_->SetBoundsRect(newtab_button_bounds_); | 1552 newtab_button_->SetBoundsRect(newtab_button_bounds_); |
| 1489 } | 1553 } |
| 1490 } | 1554 } |
| 1491 | 1555 |
| 1492 void TabStrip::AnimateToIdealBounds() { | 1556 void TabStrip::AnimateToIdealBounds() { |
| 1493 for (int i = 0; i < tab_count(); ++i) { | 1557 for (int i = 0; i < tab_count(); ++i) { |
| 1494 Tab* tab = tab_at(i); | 1558 Tab* tab = tab_at(i); |
| 1495 if (!tab->dragging()) | 1559 if (!tab->dragging()) { |
| 1496 bounds_animator_.AnimateViewTo(tab, ideal_bounds(i)); | 1560 bounds_animator_.AnimateViewTo(tab, ideal_bounds(i)); |
| 1561 bounds_animator_.SetAnimationDelegate( | |
| 1562 tab, make_scoped_ptr(new TabAnimationDelegate(this, tab))); | |
| 1563 } | |
| 1497 } | 1564 } |
| 1498 | 1565 |
| 1499 bounds_animator_.AnimateViewTo(newtab_button_, newtab_button_bounds_); | 1566 bounds_animator_.AnimateViewTo(newtab_button_, newtab_button_bounds_); |
| 1500 } | 1567 } |
| 1501 | 1568 |
| 1502 bool TabStrip::ShouldHighlightCloseButtonAfterRemove() { | 1569 bool TabStrip::ShouldHighlightCloseButtonAfterRemove() { |
| 1503 return in_tab_close_; | 1570 return in_tab_close_; |
| 1504 } | 1571 } |
| 1505 | 1572 |
| 1506 void TabStrip::DoLayout() { | 1573 void TabStrip::DoLayout() { |
| 1507 last_layout_size_ = size(); | 1574 last_layout_size_ = size(); |
| 1508 | 1575 |
| 1509 StopAnimating(false); | 1576 StopAnimating(false); |
| 1510 | 1577 |
| 1511 SwapLayoutIfNecessary(); | 1578 SwapLayoutIfNecessary(); |
| 1512 | 1579 |
| 1513 if (touch_layout_) | 1580 if (touch_layout_) |
| 1514 touch_layout_->SetWidth(tab_area_width()); | 1581 touch_layout_->SetWidth(tab_area_width()); |
| 1515 | 1582 |
| 1516 GenerateIdealBounds(); | 1583 GenerateIdealBounds(); |
| 1517 | 1584 |
| 1518 views::ViewModelUtils::SetViewBoundsToIdealBounds(tabs_); | 1585 views::ViewModelUtils::SetViewBoundsToIdealBounds(tabs_); |
| 1586 SetTabVisibility(); | |
| 1519 | 1587 |
| 1520 SchedulePaint(); | 1588 SchedulePaint(); |
| 1521 | 1589 |
| 1522 bounds_animator_.StopAnimatingView(newtab_button_); | 1590 bounds_animator_.StopAnimatingView(newtab_button_); |
| 1523 newtab_button_->SetBoundsRect(newtab_button_bounds_); | 1591 newtab_button_->SetBoundsRect(newtab_button_bounds_); |
| 1524 } | 1592 } |
| 1525 | 1593 |
| 1594 void TabStrip::SetTabVisibility() { | |
|
sky
2014/06/17 19:41:17
Can you still hit the crash you sent to me with yo
Peter Kasting
2014/06/17 20:20:20
I removed the DCHECK in ShouldTabBeVisible() that
| |
| 1595 // We could probably be more efficient here by making use of the fact that the | |
| 1596 // tabstrip will always have any visible tabs, and then any invisible tabs, so | |
| 1597 // we could e.g. binary-search for the changeover point. But since we have to | |
| 1598 // iterate through all the tabs to call SetVisible() anyway, it doesn't seem | |
| 1599 // worth it. | |
| 1600 for (int i = 0; i < tab_count(); ++i) { | |
| 1601 Tab* tab = tab_at(i); | |
| 1602 tab->SetVisible(ShouldTabBeVisible(tab)); | |
| 1603 } | |
| 1604 for (TabsClosingMap::const_iterator i(tabs_closing_map_.begin()); | |
| 1605 i != tabs_closing_map_.end(); ++i) { | |
| 1606 for (Tabs::const_iterator j(i->second.begin()); j != i->second.end(); ++j) { | |
| 1607 Tab* tab = *j; | |
| 1608 tab->SetVisible(ShouldTabBeVisible(tab)); | |
| 1609 } | |
| 1610 } | |
| 1611 } | |
| 1612 | |
| 1526 void TabStrip::DragActiveTab(const std::vector<int>& initial_positions, | 1613 void TabStrip::DragActiveTab(const std::vector<int>& initial_positions, |
| 1527 int delta) { | 1614 int delta) { |
| 1528 DCHECK_EQ(tab_count(), static_cast<int>(initial_positions.size())); | 1615 DCHECK_EQ(tab_count(), static_cast<int>(initial_positions.size())); |
| 1529 if (!touch_layout_) { | 1616 if (!touch_layout_) { |
| 1530 StackDraggedTabs(delta); | 1617 StackDraggedTabs(delta); |
| 1531 return; | 1618 return; |
| 1532 } | 1619 } |
| 1533 SetIdealBoundsFromPositions(initial_positions); | 1620 SetIdealBoundsFromPositions(initial_positions); |
| 1534 touch_layout_->DragActiveTab(delta); | 1621 touch_layout_->DragActiveTab(delta); |
| 1535 DoLayout(); | 1622 DoLayout(); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1646 // consecutive animate the view into position. Do the same if the tab is | 1733 // consecutive animate the view into position. Do the same if the tab is |
| 1647 // already animating (which means we previously caused it to animate). | 1734 // already animating (which means we previously caused it to animate). |
| 1648 if ((initial_drag && | 1735 if ((initial_drag && |
| 1649 GetModelIndexOfTab(tabs[i]) != consecutive_index) || | 1736 GetModelIndexOfTab(tabs[i]) != consecutive_index) || |
| 1650 bounds_animator_.IsAnimating(tabs[i])) { | 1737 bounds_animator_.IsAnimating(tabs[i])) { |
| 1651 bounds_animator_.SetTargetBounds(tabs[i], new_bounds); | 1738 bounds_animator_.SetTargetBounds(tabs[i], new_bounds); |
| 1652 } else { | 1739 } else { |
| 1653 tab->SetBoundsRect(new_bounds); | 1740 tab->SetBoundsRect(new_bounds); |
| 1654 } | 1741 } |
| 1655 } | 1742 } |
| 1743 SetTabVisibility(); | |
| 1656 } | 1744 } |
| 1657 | 1745 |
| 1658 void TabStrip::CalculateBoundsForDraggedTabs(const Tabs& tabs, | 1746 void TabStrip::CalculateBoundsForDraggedTabs(const Tabs& tabs, |
| 1659 std::vector<gfx::Rect>* bounds) { | 1747 std::vector<gfx::Rect>* bounds) { |
| 1660 int x = 0; | 1748 int x = 0; |
| 1661 for (size_t i = 0; i < tabs.size(); ++i) { | 1749 for (size_t i = 0; i < tabs.size(); ++i) { |
| 1662 Tab* tab = tabs[i]; | 1750 Tab* tab = tabs[i]; |
| 1663 if (i > 0 && tab->data().mini != tabs[i - 1]->data().mini) | 1751 if (i > 0 && tab->data().mini != tabs[i - 1]->data().mini) |
| 1664 x += kMiniToNonMiniGap; | 1752 x += kMiniToNonMiniGap; |
| 1665 gfx::Rect new_bounds = tab->bounds(); | 1753 gfx::Rect new_bounds = tab->bounds(); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 1683 } | 1771 } |
| 1684 | 1772 |
| 1685 int TabStrip::GetMiniTabCount() const { | 1773 int TabStrip::GetMiniTabCount() const { |
| 1686 int mini_count = 0; | 1774 int mini_count = 0; |
| 1687 while (mini_count < tab_count() && tab_at(mini_count)->data().mini) | 1775 while (mini_count < tab_count() && tab_at(mini_count)->data().mini) |
| 1688 mini_count++; | 1776 mini_count++; |
| 1689 return mini_count; | 1777 return mini_count; |
| 1690 } | 1778 } |
| 1691 | 1779 |
| 1692 const Tab* TabStrip::GetLastVisibleTab() const { | 1780 const Tab* TabStrip::GetLastVisibleTab() const { |
| 1693 return tab_at(tab_count() - 1); | 1781 for (int i = tab_count() - 1; i >= 0; --i) { |
| 1782 const Tab* tab = tab_at(i); | |
| 1783 if (tab->visible()) | |
| 1784 return tab; | |
| 1785 } | |
| 1786 NOTREACHED(); | |
| 1787 return NULL; | |
| 1694 } | 1788 } |
| 1695 | 1789 |
| 1696 void TabStrip::RemoveTabFromViewModel(int index) { | 1790 void TabStrip::RemoveTabFromViewModel(int index) { |
| 1697 // We still need to paint the tab until we actually remove it. Put it | 1791 // We still need to paint the tab until we actually remove it. Put it |
| 1698 // in tabs_closing_map_ so we can find it. | 1792 // in tabs_closing_map_ so we can find it. |
| 1699 tabs_closing_map_[index].push_back(tab_at(index)); | 1793 tabs_closing_map_[index].push_back(tab_at(index)); |
| 1700 UpdateTabsClosingMap(index + 1, -1); | 1794 UpdateTabsClosingMap(index + 1, -1); |
| 1701 tabs_.Remove(index); | 1795 tabs_.Remove(index); |
| 1702 } | 1796 } |
| 1703 | 1797 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1754 | 1848 |
| 1755 // Move the dragged tabs to their ideal bounds. | 1849 // Move the dragged tabs to their ideal bounds. |
| 1756 GenerateIdealBounds(); | 1850 GenerateIdealBounds(); |
| 1757 | 1851 |
| 1758 // Sets the bounds of the dragged tabs. | 1852 // Sets the bounds of the dragged tabs. |
| 1759 for (size_t i = 0; i < tabs.size(); ++i) { | 1853 for (size_t i = 0; i < tabs.size(); ++i) { |
| 1760 int tab_data_index = GetModelIndexOfTab(tabs[i]); | 1854 int tab_data_index = GetModelIndexOfTab(tabs[i]); |
| 1761 DCHECK_NE(-1, tab_data_index); | 1855 DCHECK_NE(-1, tab_data_index); |
| 1762 tabs[i]->SetBoundsRect(ideal_bounds(tab_data_index)); | 1856 tabs[i]->SetBoundsRect(ideal_bounds(tab_data_index)); |
| 1763 } | 1857 } |
| 1858 SetTabVisibility(); | |
| 1764 SchedulePaint(); | 1859 SchedulePaint(); |
| 1765 } | 1860 } |
| 1766 | 1861 |
| 1767 void TabStrip::DraggedTabsDetached() { | 1862 void TabStrip::DraggedTabsDetached() { |
| 1768 // Let the controller know that the user is not dragging this tabstrip's tabs | 1863 // Let the controller know that the user is not dragging this tabstrip's tabs |
| 1769 // anymore. | 1864 // anymore. |
| 1770 controller()->OnStoppedDraggingTabs(); | 1865 controller()->OnStoppedDraggingTabs(); |
| 1771 newtab_button_->SetVisible(true); | 1866 newtab_button_->SetVisible(true); |
| 1772 } | 1867 } |
| 1773 | 1868 |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 1803 | 1898 |
| 1804 // Animate the view back to its correct position. | 1899 // Animate the view back to its correct position. |
| 1805 GenerateIdealBounds(); | 1900 GenerateIdealBounds(); |
| 1806 AnimateToIdealBounds(); | 1901 AnimateToIdealBounds(); |
| 1807 } | 1902 } |
| 1808 bounds_animator_.AnimateViewTo(tab, ideal_bounds(tab_data_index)); | 1903 bounds_animator_.AnimateViewTo(tab, ideal_bounds(tab_data_index)); |
| 1809 // Install a delegate to reset the dragging state when done. We have to leave | 1904 // Install a delegate to reset the dragging state when done. We have to leave |
| 1810 // dragging true for the tab otherwise it'll draw beneath the new tab button. | 1905 // dragging true for the tab otherwise it'll draw beneath the new tab button. |
| 1811 bounds_animator_.SetAnimationDelegate( | 1906 bounds_animator_.SetAnimationDelegate( |
| 1812 tab, | 1907 tab, |
| 1813 scoped_ptr<gfx::AnimationDelegate>(new ResetDraggingStateDelegate(tab))); | 1908 scoped_ptr<gfx::AnimationDelegate>( |
| 1909 new ResetDraggingStateDelegate(this, tab))); | |
| 1814 } | 1910 } |
| 1815 | 1911 |
| 1816 void TabStrip::OwnDragController(TabDragController* controller) { | 1912 void TabStrip::OwnDragController(TabDragController* controller) { |
| 1817 // Typically, ReleaseDragController() and OwnDragController() calls are paired | 1913 // Typically, ReleaseDragController() and OwnDragController() calls are paired |
| 1818 // via corresponding calls to TabDragController::Detach() and | 1914 // via corresponding calls to TabDragController::Detach() and |
| 1819 // TabDragController::Attach(). There is one exception to that rule: when a | 1915 // TabDragController::Attach(). There is one exception to that rule: when a |
| 1820 // drag might start, we create a TabDragController that is owned by the | 1916 // drag might start, we create a TabDragController that is owned by the |
| 1821 // potential source tabstrip in MaybeStartDrag(). If a drag actually starts, | 1917 // potential source tabstrip in MaybeStartDrag(). If a drag actually starts, |
| 1822 // we then call Attach() on the source tabstrip, but since the source tabstrip | 1918 // we then call Attach() on the source tabstrip, but since the source tabstrip |
| 1823 // already owns the TabDragController, so we don't need to do anything. | 1919 // already owns the TabDragController, so we don't need to do anything. |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1951 | 2047 |
| 1952 *unselected_width = min_unselected_width; | 2048 *unselected_width = min_unselected_width; |
| 1953 *selected_width = min_selected_width; | 2049 *selected_width = min_selected_width; |
| 1954 | 2050 |
| 1955 if (tab_count == 0) { | 2051 if (tab_count == 0) { |
| 1956 // Return immediately to avoid divide-by-zero below. | 2052 // Return immediately to avoid divide-by-zero below. |
| 1957 return; | 2053 return; |
| 1958 } | 2054 } |
| 1959 | 2055 |
| 1960 // Determine how much space we can actually allocate to tabs. | 2056 // Determine how much space we can actually allocate to tabs. |
| 1961 int available_width; | 2057 int available_width = (available_width_for_tabs_ < 0) ? |
| 1962 if (available_width_for_tabs_ < 0) { | 2058 tab_area_width() : available_width_for_tabs_; |
| 1963 available_width = width() - new_tab_button_width(); | |
| 1964 } else { | |
| 1965 // Interesting corner case: if |available_width_for_tabs_| > the result | |
| 1966 // of the calculation in the conditional arm above, the strip is in | |
| 1967 // overflow. We can either use the specified width or the true available | |
| 1968 // width here; the first preserves the consistent "leave the last tab under | |
| 1969 // the user's mouse so they can close many tabs" behavior at the cost of | |
| 1970 // prolonging the glitchy appearance of the overflow state, while the second | |
| 1971 // gets us out of overflow as soon as possible but forces the user to move | |
| 1972 // their mouse for a few tabs' worth of closing. We choose visual | |
| 1973 // imperfection over behavioral imperfection and select the first option. | |
| 1974 available_width = available_width_for_tabs_; | |
| 1975 } | |
| 1976 | |
| 1977 if (mini_tab_count > 0) { | 2059 if (mini_tab_count > 0) { |
| 1978 available_width -= | 2060 available_width -= |
| 1979 mini_tab_count * (Tab::GetMiniWidth() + kTabHorizontalOffset); | 2061 mini_tab_count * (Tab::GetMiniWidth() + kTabHorizontalOffset); |
| 1980 tab_count -= mini_tab_count; | 2062 tab_count -= mini_tab_count; |
| 1981 if (tab_count == 0) { | 2063 if (tab_count == 0) { |
| 1982 *selected_width = *unselected_width = Tab::GetStandardSize().width(); | 2064 *selected_width = *unselected_width = Tab::GetStandardSize().width(); |
| 1983 return; | 2065 return; |
| 1984 } | 2066 } |
| 1985 // Account for gap between the last mini-tab and first non-mini-tab. | 2067 // Account for gap between the last mini-tab and first non-mini-tab. |
| 1986 available_width -= kMiniToNonMiniGap; | 2068 available_width -= kMiniToNonMiniGap; |
| (...skipping 466 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2453 // many mini-tabs there are). | 2535 // many mini-tabs there are). |
| 2454 GenerateIdealBoundsForMiniTabs(NULL); | 2536 GenerateIdealBoundsForMiniTabs(NULL); |
| 2455 touch_layout_->SetXAndMiniCount(GetStartXForNormalTabs(), | 2537 touch_layout_->SetXAndMiniCount(GetStartXForNormalTabs(), |
| 2456 GetMiniTabCount()); | 2538 GetMiniTabCount()); |
| 2457 touch_layout_->SetActiveIndex(controller_->GetActiveIndex()); | 2539 touch_layout_->SetActiveIndex(controller_->GetActiveIndex()); |
| 2458 } else { | 2540 } else { |
| 2459 touch_layout_.reset(); | 2541 touch_layout_.reset(); |
| 2460 } | 2542 } |
| 2461 PrepareForAnimation(); | 2543 PrepareForAnimation(); |
| 2462 GenerateIdealBounds(); | 2544 GenerateIdealBounds(); |
| 2545 SetTabVisibility(); | |
| 2463 AnimateToIdealBounds(); | 2546 AnimateToIdealBounds(); |
| 2464 } | 2547 } |
| 2465 | 2548 |
| 2466 bool TabStrip::NeedsTouchLayout() const { | 2549 bool TabStrip::NeedsTouchLayout() const { |
| 2467 if (!stacked_layout_) | 2550 if (!stacked_layout_) |
| 2468 return false; | 2551 return false; |
| 2469 | 2552 |
| 2470 int mini_tab_count = GetMiniTabCount(); | 2553 int mini_tab_count = GetMiniTabCount(); |
| 2471 int normal_count = tab_count() - mini_tab_count; | 2554 int normal_count = tab_count() - mini_tab_count; |
| 2472 if (normal_count <= 1 || normal_count == mini_tab_count) | 2555 if (normal_count <= 1 || normal_count == mini_tab_count) |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2605 action = TouchUMA::GESTURE_TABSWITCH_TAP; | 2688 action = TouchUMA::GESTURE_TABSWITCH_TAP; |
| 2606 TouchUMA::RecordGestureAction(action); | 2689 TouchUMA::RecordGestureAction(action); |
| 2607 break; | 2690 break; |
| 2608 } | 2691 } |
| 2609 | 2692 |
| 2610 default: | 2693 default: |
| 2611 break; | 2694 break; |
| 2612 } | 2695 } |
| 2613 event->SetHandled(); | 2696 event->SetHandled(); |
| 2614 } | 2697 } |
| OLD | NEW |