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/ash/tab_scrubber.h" | 5 #include "chrome/browser/ui/views/ash/tab_scrubber.h" |
6 | 6 |
7 #include "ash/shell.h" | 7 #include "ash/shell.h" |
8 #include "ash/wm/window_util.h" | 8 #include "ash/wm/window_util.h" |
9 #include "chrome/browser/ui/browser.h" | 9 #include "chrome/browser/ui/browser.h" |
10 #include "chrome/browser/ui/browser_finder.h" | 10 #include "chrome/browser/ui/browser_finder.h" |
11 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 11 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
12 #include "chrome/browser/ui/views/frame/browser_view.h" | 12 #include "chrome/browser/ui/views/frame/browser_view.h" |
| 13 #include "chrome/browser/ui/views/immersive_mode_controller.h" |
13 #include "chrome/browser/ui/views/tabs/tab.h" | 14 #include "chrome/browser/ui/views/tabs/tab.h" |
14 #include "chrome/browser/ui/views/tabs/tab_strip.h" | 15 #include "chrome/browser/ui/views/tabs/tab_strip.h" |
15 #include "chrome/common/chrome_notification_types.h" | 16 #include "chrome/common/chrome_notification_types.h" |
| 17 #include "content/public/browser/notification_service.h" |
16 #include "content/public/browser/notification_source.h" | 18 #include "content/public/browser/notification_source.h" |
17 #include "ui/aura/window.h" | 19 #include "ui/aura/window.h" |
18 #include "ui/base/events/event.h" | 20 #include "ui/base/events/event.h" |
19 #include "ui/base/events/event_utils.h" | 21 #include "ui/base/events/event_utils.h" |
| 22 #include "ui/views/controls/glow_hover_controller.h" |
20 | 23 |
21 namespace { | 24 namespace { |
22 Tab* GetTabAt(TabStrip* tab_strip, gfx::Point point) { | 25 const int64 kActivationDelayMS = 200; |
23 for (int i = 0; i < tab_strip->tab_count(); ++i) { | 26 const int64 kCancelImmersiveRevelDelayMS = 200; |
24 Tab* tab = tab_strip->tab_at(i); | |
25 if (tab_strip->tab_at(i)->bounds().Contains(point)) | |
26 return tab; | |
27 } | |
28 return NULL; | |
29 } | |
30 | |
31 const int kInitialTabOffset = 10; | |
32 } | 27 } |
33 | 28 |
34 // static | 29 // static |
35 TabScrubber* TabScrubber::GetInstance() { | 30 TabScrubber* TabScrubber::GetInstance() { |
36 static TabScrubber* instance = NULL; | 31 static TabScrubber* instance = NULL; |
37 if (!instance) | 32 if (!instance) |
38 instance = new TabScrubber(); | 33 instance = new TabScrubber(); |
39 return instance; | 34 return instance; |
40 } | 35 } |
41 | 36 |
| 37 // static |
| 38 gfx::Point TabScrubber::GetStartPoint( |
| 39 TabStrip* tab_strip, |
| 40 int index, |
| 41 TabScrubber::Direction direction) { |
| 42 int initial_tab_offset = Tab::GetMiniWidth() / 2; |
| 43 gfx::Rect tab_bounds = tab_strip->tab_at(index)->bounds(); |
| 44 float x = direction == LEFT ? |
| 45 tab_bounds.x() + initial_tab_offset : |
| 46 tab_bounds.right() - initial_tab_offset; |
| 47 return gfx::Point(x, tab_bounds.CenterPoint().y()); |
| 48 } |
| 49 |
| 50 bool TabScrubber::IsActivationPending() { |
| 51 return activate_timer_.IsRunning(); |
| 52 } |
| 53 |
42 TabScrubber::TabScrubber() | 54 TabScrubber::TabScrubber() |
43 : scrubbing_(false), | 55 : scrubbing_(false), |
44 browser_(NULL), | 56 browser_(NULL), |
45 scroll_x_(-1), | 57 swipe_x_(-1), |
46 scroll_y_(-1) { | 58 swipe_y_(-1), |
| 59 swipe_direction_(LEFT), |
| 60 highlighted_tab_(-1), |
| 61 activate_timer_(true, false), |
| 62 activation_delay_(base::TimeDelta::FromMilliseconds(kActivationDelayMS)), |
| 63 should_cancel_immersive_reveal_(false), |
| 64 cancel_immersive_reveal_timer_(true, false), |
| 65 weak_ptr_factory_(this) { |
47 ash::Shell::GetInstance()->AddPreTargetHandler(this); | 66 ash::Shell::GetInstance()->AddPreTargetHandler(this); |
| 67 registrar_.Add( |
| 68 this, |
| 69 chrome::NOTIFICATION_BROWSER_CLOSING, |
| 70 content::NotificationService::AllSources()); |
48 } | 71 } |
49 | 72 |
50 TabScrubber::~TabScrubber() { | 73 TabScrubber::~TabScrubber() { |
| 74 // Note: The weak_ptr_factory_ should invalidate its weak pointers before |
| 75 // any other members are destroyed. |
| 76 weak_ptr_factory_.InvalidateWeakPtrs(); |
51 } | 77 } |
52 | 78 |
53 void TabScrubber::OnScrollEvent(ui::ScrollEvent* event) { | 79 void TabScrubber::OnScrollEvent(ui::ScrollEvent* event) { |
54 if (event->type() == ui::ET_SCROLL_FLING_CANCEL) { | 80 if (event->type() == ui::ET_SCROLL_FLING_CANCEL || |
55 if (scrubbing_) | 81 event->type() == ui::ET_SCROLL_FLING_START) { |
56 StopScrubbing(); | 82 FinishScrub(true); |
| 83 CancelImmersiveReveal(); |
57 return; | 84 return; |
58 } | 85 } |
59 | 86 |
60 if (event->finger_count() != 3 || | 87 if (event->finger_count() != 3) |
61 event->type() != ui::ET_SCROLL) | |
62 return; | 88 return; |
63 | 89 |
64 Browser* browser = GetActiveBrowser(); | 90 Browser* browser = GetActiveBrowser(); |
65 if (!browser || (browser_ && browser != browser_)) { | 91 if (!browser || (scrubbing_ && browser_ && browser != browser_) || |
66 if (scrubbing_) | 92 (highlighted_tab_ != -1 && |
67 StopScrubbing(); | 93 highlighted_tab_ >= browser->tab_strip_model()->count())) { |
| 94 FinishScrub(false); |
68 return; | 95 return; |
69 } | 96 } |
70 | 97 |
71 BrowserView* browser_view = | 98 BrowserView* browser_view = |
72 BrowserView::GetBrowserViewForNativeWindow( | 99 BrowserView::GetBrowserViewForNativeWindow( |
73 browser->window()->GetNativeWindow()); | 100 browser->window()->GetNativeWindow()); |
74 TabStrip* tab_strip = browser_view->tabstrip(); | 101 TabStrip* tab_strip = browser_view->tabstrip(); |
75 | 102 |
76 float x_offset = -event->x_offset(); | 103 if (tab_strip->IsAnimating()) { |
77 if (!scrubbing_) { | 104 FinishScrub(false); |
78 scrubbing_ = true; | 105 return; |
79 browser_ = browser; | |
80 Tab* initial_tab = | |
81 tab_strip->tab_at(browser_->tab_strip_model()->active_index()); | |
82 scroll_x_ = initial_tab->x(); | |
83 scroll_x_ += (x_offset < 0) ? | |
84 kInitialTabOffset : initial_tab->width() - kInitialTabOffset; | |
85 scroll_y_ = initial_tab->height() / 2; | |
86 registrar_.Add( | |
87 this, | |
88 chrome::NOTIFICATION_BROWSER_CLOSING, | |
89 content::Source<Browser>(browser_)); | |
90 } | 106 } |
91 | 107 |
92 if (ui::IsNaturalScrollEnabled()) | 108 // We are handling the event. |
93 scroll_x_ += event->x_offset(); | 109 event->StopPropagation(); |
94 else | |
95 scroll_x_ -= event->x_offset(); | |
96 Tab* first_tab = tab_strip->tab_at(0); | |
97 Tab* last_tab = tab_strip->tab_at(tab_strip->tab_count() - 1); | |
98 if (scroll_x_ < first_tab->x()) | |
99 scroll_x_ = first_tab->x(); | |
100 if (scroll_x_ > last_tab->bounds().right()) | |
101 scroll_x_ = last_tab->bounds().right(); | |
102 | 110 |
103 gfx::Point tab_point(scroll_x_, scroll_y_); | 111 float x_offset = event->x_offset(); |
104 Tab* new_tab = GetTabAt(tab_strip, tab_point); | 112 if (!ui::IsNaturalScrollEnabled()) |
105 if (new_tab && !new_tab->IsActive()) { | 113 x_offset = -x_offset; |
106 int new_index = tab_strip->GetModelIndexOfTab(new_tab); | 114 int last_tab_index = highlighted_tab_ == -1 ? |
107 browser->tab_strip_model()->ActivateTabAt(new_index, true); | 115 browser->tab_strip_model()->active_index() : highlighted_tab_; |
| 116 if (!scrubbing_) { |
| 117 swipe_direction_ = (x_offset < 0) ? LEFT : RIGHT; |
| 118 const gfx::Point start_point = |
| 119 GetStartPoint(tab_strip, |
| 120 browser->tab_strip_model()->active_index(), |
| 121 swipe_direction_); |
| 122 browser_ = browser; |
| 123 scrubbing_ = true; |
| 124 |
| 125 swipe_x_ = start_point.x(); |
| 126 swipe_y_ = start_point.y(); |
| 127 ImmersiveModeController* immersive_controller = |
| 128 browser_view->immersive_mode_controller(); |
| 129 CancelImmersiveReveal(); |
| 130 if (immersive_controller->enabled() && |
| 131 !immersive_controller->IsRevealed()) { |
| 132 immersive_controller->MaybeStartReveal(); |
| 133 should_cancel_immersive_reveal_ = true; |
| 134 } |
| 135 tab_strip->AddObserver(this); |
| 136 } else if (highlighted_tab_ == -1) { |
| 137 Direction direction = (x_offset < 0) ? LEFT : RIGHT; |
| 138 if (direction != swipe_direction_) { |
| 139 const gfx::Point start_point = |
| 140 GetStartPoint(tab_strip, |
| 141 browser->tab_strip_model()->active_index(), |
| 142 direction); |
| 143 swipe_x_ = start_point.x(); |
| 144 swipe_y_ = start_point.y(); |
| 145 swipe_direction_ = direction; |
| 146 } |
108 } | 147 } |
109 | 148 |
110 event->StopPropagation(); | 149 swipe_x_ += x_offset; |
| 150 Tab* first_tab = tab_strip->tab_at(0); |
| 151 int first_tab_center = first_tab->bounds().CenterPoint().x(); |
| 152 Tab* last_tab = tab_strip->tab_at(tab_strip->tab_count() - 1); |
| 153 int last_tab_tab_center = last_tab->bounds().CenterPoint().x(); |
| 154 if (swipe_x_ < first_tab_center) |
| 155 swipe_x_ = first_tab_center; |
| 156 if (swipe_x_ > last_tab_tab_center) |
| 157 swipe_x_ = last_tab_tab_center; |
| 158 |
| 159 Tab* initial_tab = tab_strip->tab_at(last_tab_index); |
| 160 gfx::Point tab_point(swipe_x_, swipe_y_); |
| 161 views::View::ConvertPointToTarget(tab_strip, initial_tab, &tab_point); |
| 162 Tab* new_tab = tab_strip->GetTabAt(initial_tab, tab_point); |
| 163 if (!new_tab) |
| 164 return; |
| 165 |
| 166 int new_index = tab_strip->GetModelIndexOfTab(new_tab); |
| 167 if (new_index != highlighted_tab_) { |
| 168 if (activate_timer_.IsRunning()) { |
| 169 activate_timer_.Reset(); |
| 170 } else { |
| 171 activate_timer_.Start(FROM_HERE, |
| 172 activation_delay_, |
| 173 base::Bind(&TabScrubber::FinishScrub, |
| 174 weak_ptr_factory_.GetWeakPtr(), |
| 175 true)); |
| 176 } |
| 177 if (highlighted_tab_ != -1) { |
| 178 Tab* tab = tab_strip->tab_at(highlighted_tab_); |
| 179 tab->hover_controller()->HideImmediately(); |
| 180 } |
| 181 if (new_index == browser->tab_strip_model()->active_index()) { |
| 182 highlighted_tab_ = -1; |
| 183 } else { |
| 184 highlighted_tab_ = new_index; |
| 185 new_tab->hover_controller()->Show(views::GlowHoverController::PRONOUNCED); |
| 186 } |
| 187 } |
| 188 if (highlighted_tab_ != -1) { |
| 189 gfx::Point hover_point(swipe_x_, swipe_y_); |
| 190 views::View::ConvertPointToTarget(tab_strip, new_tab, &hover_point); |
| 191 new_tab->hover_controller()->SetLocation(hover_point); |
| 192 } |
111 } | 193 } |
112 | 194 |
113 void TabScrubber::Observe(int type, | 195 void TabScrubber::Observe(int type, |
114 const content::NotificationSource& source, | 196 const content::NotificationSource& source, |
115 const content::NotificationDetails& details) { | 197 const content::NotificationDetails& details) { |
116 DCHECK(type == chrome::NOTIFICATION_BROWSER_CLOSING && | 198 if (content::Source<Browser>(source).ptr() == browser_) |
117 content::Source<Browser>(source).ptr() == browser_); | 199 FinishScrub(false); |
118 StopScrubbing(); | 200 browser_ = NULL; |
| 201 } |
| 202 |
| 203 void TabScrubber::TabStripAddedTabAt(TabStrip* tab_strip, int index) { |
| 204 if (highlighted_tab_ == -1) |
| 205 return; |
| 206 |
| 207 if (index < highlighted_tab_) |
| 208 ++highlighted_tab_; |
| 209 } |
| 210 |
| 211 void TabScrubber::TabStripMovedTab(TabStrip* tab_strip, |
| 212 int from_index, |
| 213 int to_index) { |
| 214 if (highlighted_tab_ == -1) |
| 215 return; |
| 216 |
| 217 if (from_index == highlighted_tab_) |
| 218 highlighted_tab_ = to_index; |
| 219 else if (from_index < highlighted_tab_&& highlighted_tab_<= to_index) |
| 220 --highlighted_tab_; |
| 221 else if (from_index > highlighted_tab_ && highlighted_tab_ >= to_index) |
| 222 ++highlighted_tab_; |
| 223 } |
| 224 |
| 225 void TabScrubber::TabStripRemovedTabAt(TabStrip* tab_strip, int index) { |
| 226 if (highlighted_tab_ == -1) |
| 227 return; |
| 228 if (index == highlighted_tab_) { |
| 229 FinishScrub(false); |
| 230 return; |
| 231 } |
| 232 if (index < highlighted_tab_) |
| 233 --highlighted_tab_; |
| 234 } |
| 235 |
| 236 void TabScrubber::TabStripDeleted(TabStrip* tab_strip) { |
| 237 if (highlighted_tab_ == -1) |
| 238 return; |
119 } | 239 } |
120 | 240 |
121 Browser* TabScrubber::GetActiveBrowser() { | 241 Browser* TabScrubber::GetActiveBrowser() { |
122 aura::Window* active_window = ash::wm::GetActiveWindow(); | 242 aura::Window* active_window = ash::wm::GetActiveWindow(); |
123 if (!active_window) | 243 if (!active_window) |
124 return NULL; | 244 return NULL; |
125 | 245 |
126 Browser* browser = chrome::FindBrowserWithWindow(active_window); | 246 Browser* browser = chrome::FindBrowserWithWindow(active_window); |
127 if (!browser || browser->type() != Browser::TYPE_TABBED) | 247 if (!browser || browser->type() != Browser::TYPE_TABBED) |
128 return NULL; | 248 return NULL; |
129 | 249 |
130 return browser; | 250 return browser; |
131 } | 251 } |
132 | 252 |
133 void TabScrubber::StopScrubbing() { | 253 void TabScrubber::FinishScrub(bool activate) { |
134 if (!scrubbing_) | 254 activate_timer_.Stop(); |
135 return; | |
136 | 255 |
137 registrar_.Remove( | 256 if (browser_) { |
138 this, | 257 BrowserView* browser_view = |
139 chrome::NOTIFICATION_BROWSER_CLOSING, | 258 BrowserView::GetBrowserViewForNativeWindow( |
140 content::Source<Browser>(browser_)); | 259 browser_->window()->GetNativeWindow()); |
| 260 TabStrip* tab_strip = browser_view->tabstrip(); |
| 261 if (activate && highlighted_tab_ != -1) { |
| 262 Tab* tab = tab_strip->tab_at(highlighted_tab_); |
| 263 tab->hover_controller()->HideImmediately(); |
| 264 browser_->tab_strip_model()->ActivateTabAt(highlighted_tab_, true); |
| 265 } |
| 266 tab_strip->RemoveObserver(this); |
| 267 if (!cancel_immersive_reveal_timer_.IsRunning() && |
| 268 should_cancel_immersive_reveal_) { |
| 269 cancel_immersive_reveal_timer_.Start( |
| 270 FROM_HERE, |
| 271 base::TimeDelta::FromMilliseconds(kCancelImmersiveRevelDelayMS), |
| 272 base:: Bind(&TabScrubber::CancelImmersiveReveal, |
| 273 weak_ptr_factory_.GetWeakPtr())); |
| 274 } |
| 275 } |
| 276 swipe_x_ = -1; |
| 277 swipe_y_ = -1; |
141 scrubbing_ = false; | 278 scrubbing_ = false; |
142 browser_ = NULL; | 279 highlighted_tab_ = -1; |
143 } | 280 } |
| 281 |
| 282 void TabScrubber::CancelImmersiveReveal() { |
| 283 cancel_immersive_reveal_timer_.Stop(); |
| 284 if (browser_ && should_cancel_immersive_reveal_) { |
| 285 BrowserView* browser_view = |
| 286 BrowserView::GetBrowserViewForNativeWindow( |
| 287 browser_->window()->GetNativeWindow()); |
| 288 browser_view->immersive_mode_controller()->CancelReveal(); |
| 289 } |
| 290 should_cancel_immersive_reveal_ = false; |
| 291 } |
OLD | NEW |