| Index: chrome/browser/ui/views/ash/tab_scrubber.cc
|
| diff --git a/chrome/browser/ui/views/ash/tab_scrubber.cc b/chrome/browser/ui/views/ash/tab_scrubber.cc
|
| index 04258140fb3552325a1d1d6f24c55bf5c60dd4dc..68f6c148aeba7d0c4e496bb5c7673547306946d1 100644
|
| --- a/chrome/browser/ui/views/ash/tab_scrubber.cc
|
| +++ b/chrome/browser/ui/views/ash/tab_scrubber.cc
|
| @@ -10,25 +10,20 @@
|
| #include "chrome/browser/ui/browser_finder.h"
|
| #include "chrome/browser/ui/tabs/tab_strip_model.h"
|
| #include "chrome/browser/ui/views/frame/browser_view.h"
|
| +#include "chrome/browser/ui/views/immersive_mode_controller.h"
|
| #include "chrome/browser/ui/views/tabs/tab.h"
|
| #include "chrome/browser/ui/views/tabs/tab_strip.h"
|
| #include "chrome/common/chrome_notification_types.h"
|
| +#include "content/public/browser/notification_service.h"
|
| #include "content/public/browser/notification_source.h"
|
| #include "ui/aura/window.h"
|
| #include "ui/base/events/event.h"
|
| #include "ui/base/events/event_utils.h"
|
| +#include "ui/views/controls/glow_hover_controller.h"
|
|
|
| namespace {
|
| -Tab* GetTabAt(TabStrip* tab_strip, gfx::Point point) {
|
| - for (int i = 0; i < tab_strip->tab_count(); ++i) {
|
| - Tab* tab = tab_strip->tab_at(i);
|
| - if (tab_strip->tab_at(i)->bounds().Contains(point))
|
| - return tab;
|
| - }
|
| - return NULL;
|
| -}
|
| -
|
| -const int kInitialTabOffset = 10;
|
| +const int64 kActivationDelayMS = 200;
|
| +const int64 kCancelImmersiveRevelDelayMS = 200;
|
| }
|
|
|
| // static
|
| @@ -39,32 +34,64 @@ TabScrubber* TabScrubber::GetInstance() {
|
| return instance;
|
| }
|
|
|
| +// static
|
| +gfx::Point TabScrubber::GetStartPoint(
|
| + TabStrip* tab_strip,
|
| + int index,
|
| + TabScrubber::Direction direction) {
|
| + int initial_tab_offset = Tab::GetMiniWidth() / 2;
|
| + gfx::Rect tab_bounds = tab_strip->tab_at(index)->bounds();
|
| + float x = direction == LEFT ?
|
| + tab_bounds.x() + initial_tab_offset :
|
| + tab_bounds.right() - initial_tab_offset;
|
| + return gfx::Point(x, tab_bounds.CenterPoint().y());
|
| +}
|
| +
|
| +bool TabScrubber::IsActivationPending() {
|
| + return activate_timer_.IsRunning();
|
| +}
|
| +
|
| TabScrubber::TabScrubber()
|
| : scrubbing_(false),
|
| browser_(NULL),
|
| - scroll_x_(-1),
|
| - scroll_y_(-1) {
|
| + swipe_x_(-1),
|
| + swipe_y_(-1),
|
| + swipe_direction_(LEFT),
|
| + highlighted_tab_(-1),
|
| + activate_timer_(true, false),
|
| + activation_delay_(base::TimeDelta::FromMilliseconds(kActivationDelayMS)),
|
| + should_cancel_immersive_reveal_(false),
|
| + cancel_immersive_reveal_timer_(true, false),
|
| + weak_ptr_factory_(this) {
|
| ash::Shell::GetInstance()->AddPreTargetHandler(this);
|
| + registrar_.Add(
|
| + this,
|
| + chrome::NOTIFICATION_BROWSER_CLOSING,
|
| + content::NotificationService::AllSources());
|
| }
|
|
|
| TabScrubber::~TabScrubber() {
|
| + // Note: The weak_ptr_factory_ should invalidate its weak pointers before
|
| + // any other members are destroyed.
|
| + weak_ptr_factory_.InvalidateWeakPtrs();
|
| }
|
|
|
| void TabScrubber::OnScrollEvent(ui::ScrollEvent* event) {
|
| - if (event->type() == ui::ET_SCROLL_FLING_CANCEL) {
|
| - if (scrubbing_)
|
| - StopScrubbing();
|
| + if (event->type() == ui::ET_SCROLL_FLING_CANCEL ||
|
| + event->type() == ui::ET_SCROLL_FLING_START) {
|
| + FinishScrub(true);
|
| + CancelImmersiveReveal();
|
| return;
|
| }
|
|
|
| - if (event->finger_count() != 3 ||
|
| - event->type() != ui::ET_SCROLL)
|
| + if (event->finger_count() != 3)
|
| return;
|
|
|
| Browser* browser = GetActiveBrowser();
|
| - if (!browser || (browser_ && browser != browser_)) {
|
| - if (scrubbing_)
|
| - StopScrubbing();
|
| + if (!browser || (scrubbing_ && browser_ && browser != browser_) ||
|
| + (highlighted_tab_ != -1 &&
|
| + highlighted_tab_ >= browser->tab_strip_model()->count())) {
|
| + FinishScrub(false);
|
| return;
|
| }
|
|
|
| @@ -73,49 +100,142 @@ void TabScrubber::OnScrollEvent(ui::ScrollEvent* event) {
|
| browser->window()->GetNativeWindow());
|
| TabStrip* tab_strip = browser_view->tabstrip();
|
|
|
| - float x_offset = -event->x_offset();
|
| + if (tab_strip->IsAnimating()) {
|
| + FinishScrub(false);
|
| + return;
|
| + }
|
| +
|
| + // We are handling the event.
|
| + event->StopPropagation();
|
| +
|
| + float x_offset = event->x_offset();
|
| + if (!ui::IsNaturalScrollEnabled())
|
| + x_offset = -x_offset;
|
| + int last_tab_index = highlighted_tab_ == -1 ?
|
| + browser->tab_strip_model()->active_index() : highlighted_tab_;
|
| if (!scrubbing_) {
|
| - scrubbing_ = true;
|
| + swipe_direction_ = (x_offset < 0) ? LEFT : RIGHT;
|
| + const gfx::Point start_point =
|
| + GetStartPoint(tab_strip,
|
| + browser->tab_strip_model()->active_index(),
|
| + swipe_direction_);
|
| browser_ = browser;
|
| - Tab* initial_tab =
|
| - tab_strip->tab_at(browser_->tab_strip_model()->active_index());
|
| - scroll_x_ = initial_tab->x();
|
| - scroll_x_ += (x_offset < 0) ?
|
| - kInitialTabOffset : initial_tab->width() - kInitialTabOffset;
|
| - scroll_y_ = initial_tab->height() / 2;
|
| - registrar_.Add(
|
| - this,
|
| - chrome::NOTIFICATION_BROWSER_CLOSING,
|
| - content::Source<Browser>(browser_));
|
| + scrubbing_ = true;
|
| +
|
| + swipe_x_ = start_point.x();
|
| + swipe_y_ = start_point.y();
|
| + ImmersiveModeController* immersive_controller =
|
| + browser_view->immersive_mode_controller();
|
| + CancelImmersiveReveal();
|
| + if (immersive_controller->enabled() &&
|
| + !immersive_controller->IsRevealed()) {
|
| + immersive_controller->MaybeStartReveal();
|
| + should_cancel_immersive_reveal_ = true;
|
| + }
|
| + tab_strip->AddObserver(this);
|
| + } else if (highlighted_tab_ == -1) {
|
| + Direction direction = (x_offset < 0) ? LEFT : RIGHT;
|
| + if (direction != swipe_direction_) {
|
| + const gfx::Point start_point =
|
| + GetStartPoint(tab_strip,
|
| + browser->tab_strip_model()->active_index(),
|
| + direction);
|
| + swipe_x_ = start_point.x();
|
| + swipe_y_ = start_point.y();
|
| + swipe_direction_ = direction;
|
| + }
|
| }
|
|
|
| - if (ui::IsNaturalScrollEnabled())
|
| - scroll_x_ += event->x_offset();
|
| - else
|
| - scroll_x_ -= event->x_offset();
|
| + swipe_x_ += x_offset;
|
| Tab* first_tab = tab_strip->tab_at(0);
|
| + int first_tab_center = first_tab->bounds().CenterPoint().x();
|
| Tab* last_tab = tab_strip->tab_at(tab_strip->tab_count() - 1);
|
| - if (scroll_x_ < first_tab->x())
|
| - scroll_x_ = first_tab->x();
|
| - if (scroll_x_ > last_tab->bounds().right())
|
| - scroll_x_ = last_tab->bounds().right();
|
| -
|
| - gfx::Point tab_point(scroll_x_, scroll_y_);
|
| - Tab* new_tab = GetTabAt(tab_strip, tab_point);
|
| - if (new_tab && !new_tab->IsActive()) {
|
| - int new_index = tab_strip->GetModelIndexOfTab(new_tab);
|
| - browser->tab_strip_model()->ActivateTabAt(new_index, true);
|
| - }
|
| + int last_tab_tab_center = last_tab->bounds().CenterPoint().x();
|
| + if (swipe_x_ < first_tab_center)
|
| + swipe_x_ = first_tab_center;
|
| + if (swipe_x_ > last_tab_tab_center)
|
| + swipe_x_ = last_tab_tab_center;
|
|
|
| - event->StopPropagation();
|
| + Tab* initial_tab = tab_strip->tab_at(last_tab_index);
|
| + gfx::Point tab_point(swipe_x_, swipe_y_);
|
| + views::View::ConvertPointToTarget(tab_strip, initial_tab, &tab_point);
|
| + Tab* new_tab = tab_strip->GetTabAt(initial_tab, tab_point);
|
| + if (!new_tab)
|
| + return;
|
| +
|
| + int new_index = tab_strip->GetModelIndexOfTab(new_tab);
|
| + if (new_index != highlighted_tab_) {
|
| + if (activate_timer_.IsRunning()) {
|
| + activate_timer_.Reset();
|
| + } else {
|
| + activate_timer_.Start(FROM_HERE,
|
| + activation_delay_,
|
| + base::Bind(&TabScrubber::FinishScrub,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + true));
|
| + }
|
| + if (highlighted_tab_ != -1) {
|
| + Tab* tab = tab_strip->tab_at(highlighted_tab_);
|
| + tab->hover_controller()->HideImmediately();
|
| + }
|
| + if (new_index == browser->tab_strip_model()->active_index()) {
|
| + highlighted_tab_ = -1;
|
| + } else {
|
| + highlighted_tab_ = new_index;
|
| + new_tab->hover_controller()->Show(views::GlowHoverController::PRONOUNCED);
|
| + }
|
| + }
|
| + if (highlighted_tab_ != -1) {
|
| + gfx::Point hover_point(swipe_x_, swipe_y_);
|
| + views::View::ConvertPointToTarget(tab_strip, new_tab, &hover_point);
|
| + new_tab->hover_controller()->SetLocation(hover_point);
|
| + }
|
| }
|
|
|
| void TabScrubber::Observe(int type,
|
| const content::NotificationSource& source,
|
| const content::NotificationDetails& details) {
|
| - DCHECK(type == chrome::NOTIFICATION_BROWSER_CLOSING &&
|
| - content::Source<Browser>(source).ptr() == browser_);
|
| - StopScrubbing();
|
| + if (content::Source<Browser>(source).ptr() == browser_)
|
| + FinishScrub(false);
|
| + browser_ = NULL;
|
| +}
|
| +
|
| +void TabScrubber::TabStripAddedTabAt(TabStrip* tab_strip, int index) {
|
| + if (highlighted_tab_ == -1)
|
| + return;
|
| +
|
| + if (index < highlighted_tab_)
|
| + ++highlighted_tab_;
|
| +}
|
| +
|
| +void TabScrubber::TabStripMovedTab(TabStrip* tab_strip,
|
| + int from_index,
|
| + int to_index) {
|
| + if (highlighted_tab_ == -1)
|
| + return;
|
| +
|
| + if (from_index == highlighted_tab_)
|
| + highlighted_tab_ = to_index;
|
| + else if (from_index < highlighted_tab_&& highlighted_tab_<= to_index)
|
| + --highlighted_tab_;
|
| + else if (from_index > highlighted_tab_ && highlighted_tab_ >= to_index)
|
| + ++highlighted_tab_;
|
| +}
|
| +
|
| +void TabScrubber::TabStripRemovedTabAt(TabStrip* tab_strip, int index) {
|
| + if (highlighted_tab_ == -1)
|
| + return;
|
| + if (index == highlighted_tab_) {
|
| + FinishScrub(false);
|
| + return;
|
| + }
|
| + if (index < highlighted_tab_)
|
| + --highlighted_tab_;
|
| +}
|
| +
|
| +void TabScrubber::TabStripDeleted(TabStrip* tab_strip) {
|
| + if (highlighted_tab_ == -1)
|
| + return;
|
| }
|
|
|
| Browser* TabScrubber::GetActiveBrowser() {
|
| @@ -130,14 +250,42 @@ Browser* TabScrubber::GetActiveBrowser() {
|
| return browser;
|
| }
|
|
|
| -void TabScrubber::StopScrubbing() {
|
| - if (!scrubbing_)
|
| - return;
|
| +void TabScrubber::FinishScrub(bool activate) {
|
| + activate_timer_.Stop();
|
|
|
| - registrar_.Remove(
|
| - this,
|
| - chrome::NOTIFICATION_BROWSER_CLOSING,
|
| - content::Source<Browser>(browser_));
|
| + if (browser_) {
|
| + BrowserView* browser_view =
|
| + BrowserView::GetBrowserViewForNativeWindow(
|
| + browser_->window()->GetNativeWindow());
|
| + TabStrip* tab_strip = browser_view->tabstrip();
|
| + if (activate && highlighted_tab_ != -1) {
|
| + Tab* tab = tab_strip->tab_at(highlighted_tab_);
|
| + tab->hover_controller()->HideImmediately();
|
| + browser_->tab_strip_model()->ActivateTabAt(highlighted_tab_, true);
|
| + }
|
| + tab_strip->RemoveObserver(this);
|
| + if (!cancel_immersive_reveal_timer_.IsRunning() &&
|
| + should_cancel_immersive_reveal_) {
|
| + cancel_immersive_reveal_timer_.Start(
|
| + FROM_HERE,
|
| + base::TimeDelta::FromMilliseconds(kCancelImmersiveRevelDelayMS),
|
| + base:: Bind(&TabScrubber::CancelImmersiveReveal,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + }
|
| + }
|
| + swipe_x_ = -1;
|
| + swipe_y_ = -1;
|
| scrubbing_ = false;
|
| - browser_ = NULL;
|
| + highlighted_tab_ = -1;
|
| +}
|
| +
|
| +void TabScrubber::CancelImmersiveReveal() {
|
| + cancel_immersive_reveal_timer_.Stop();
|
| + if (browser_ && should_cancel_immersive_reveal_) {
|
| + BrowserView* browser_view =
|
| + BrowserView::GetBrowserViewForNativeWindow(
|
| + browser_->window()->GetNativeWindow());
|
| + browser_view->immersive_mode_controller()->CancelReveal();
|
| + }
|
| + should_cancel_immersive_reveal_ = false;
|
| }
|
|
|