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

Side by Side Diff: chrome/browser/ui/views/ash/tab_scrubber.cc

Issue 11881042: highlight intermediate tabs (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added support for tab changes while waiting to activate Created 7 years, 10 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 | Annotate | Revision Log
OLDNEW
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() {
51 } 74 }
52 75
53 void TabScrubber::OnScrollEvent(ui::ScrollEvent* event) { 76 void TabScrubber::OnScrollEvent(ui::ScrollEvent* event) {
54 if (event->type() == ui::ET_SCROLL_FLING_CANCEL) { 77 if (event->type() == ui::ET_SCROLL_FLING_CANCEL ||
55 if (scrubbing_) 78 event->type() == ui::ET_SCROLL_FLING_START) {
56 StopScrubbing(); 79 FinishScrub(true);
80 CancelImmersiveReveal();
57 return; 81 return;
58 } 82 }
59 83
60 if (event->finger_count() != 3 || 84 if (event->finger_count() != 3)
61 event->type() != ui::ET_SCROLL)
62 return; 85 return;
63 86
64 Browser* browser = GetActiveBrowser(); 87 Browser* browser = GetActiveBrowser();
65 if (!browser || (browser_ && browser != browser_)) { 88 if (!browser || (browser_ && browser != browser_) ||
66 if (scrubbing_) 89 (highlighted_tab_ != -1 &&
67 StopScrubbing(); 90 highlighted_tab_ >= browser->tab_strip_model()->count())) {
91 FinishScrub(false);
68 return; 92 return;
69 } 93 }
70 94
71 BrowserView* browser_view = 95 BrowserView* browser_view =
72 BrowserView::GetBrowserViewForNativeWindow( 96 BrowserView::GetBrowserViewForNativeWindow(
73 browser->window()->GetNativeWindow()); 97 browser->window()->GetNativeWindow());
74 TabStrip* tab_strip = browser_view->tabstrip(); 98 TabStrip* tab_strip = browser_view->tabstrip();
75 99
76 float x_offset = -event->x_offset(); 100 if (tab_strip->IsAnimating()) {
77 if (!scrubbing_) { 101 FinishScrub(false);
78 scrubbing_ = true; 102 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 } 103 }
91 104
92 if (ui::IsNaturalScrollEnabled()) 105 // We are handling the event.
93 scroll_x_ += event->x_offset(); 106 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 107
103 gfx::Point tab_point(scroll_x_, scroll_y_); 108 float x_offset = event->x_offset();
104 Tab* new_tab = GetTabAt(tab_strip, tab_point); 109 if (!ui::IsNaturalScrollEnabled())
105 if (new_tab && !new_tab->IsActive()) { 110 x_offset = -x_offset;
106 int new_index = tab_strip->GetModelIndexOfTab(new_tab); 111 int last_tab_index = highlighted_tab_ == -1 ?
107 browser->tab_strip_model()->ActivateTabAt(new_index, true); 112 browser->tab_strip_model()->active_index() : highlighted_tab_;
113 if (!scrubbing_) {
114 swipe_direction_ = (x_offset < 0) ? LEFT : RIGHT;
115 const gfx::Point start_point =
116 GetStartPoint(tab_strip,
117 browser->tab_strip_model()->active_index(),
118 swipe_direction_);
119 browser_ = browser;
120 scrubbing_ = true;
121
122 swipe_x_ = start_point.x();
123 swipe_y_ = start_point.y();
124 ImmersiveModeController* immersive_controller =
125 browser_view->immersive_mode_controller();
126 CancelImmersiveReveal();
127 if (immersive_controller->enabled() &&
128 !immersive_controller->IsRevealed()) {
129 immersive_controller->MaybeStartReveal();
130 should_cancel_immersive_reveal_ = true;
131 }
132 tab_strip->AddObserver(this);
133 } else if (highlighted_tab_ == -1) {
134 Direction direction = (x_offset < 0) ? LEFT : RIGHT;
135 if (direction != swipe_direction_) {
136 const gfx::Point start_point =
137 GetStartPoint(tab_strip,
138 browser->tab_strip_model()->active_index(),
139 swipe_direction_);
140 swipe_x_ = start_point.x();
141 swipe_y_ = start_point.y();
142 swipe_direction_ = direction;
143 }
108 } 144 }
109 145
110 event->StopPropagation(); 146 swipe_x_ += x_offset;
147 Tab* first_tab = tab_strip->tab_at(0);
148 int first_tab_center = first_tab->bounds().CenterPoint().x();
149 Tab* last_tab = tab_strip->tab_at(tab_strip->tab_count() - 1);
150 int last_tab_tab_center = last_tab->bounds().CenterPoint().x();
151 if (swipe_x_ < first_tab_center)
152 swipe_x_ = first_tab_center;
153 if (swipe_x_ > last_tab_tab_center)
154 swipe_x_ = last_tab_tab_center;
155
156 Tab* initial_tab = tab_strip->tab_at(last_tab_index);
157 gfx::Point tab_point(swipe_x_, swipe_y_);
158 views::View::ConvertPointToTarget(tab_strip, initial_tab, &tab_point);
159 Tab* new_tab = tab_strip->GetTabAt(initial_tab, tab_point);
160 if (!new_tab)
161 return;
162
163 int new_index = tab_strip->GetModelIndexOfTab(new_tab);
164 if (new_index != highlighted_tab_) {
165 if (activate_timer_.IsRunning()) {
166 activate_timer_.Reset();
167 } else {
168 activate_timer_.Start(FROM_HERE,
169 activation_delay_,
170 base::Bind(&TabScrubber::FinishScrub,
171 weak_ptr_factory_.GetWeakPtr(),
172 true));
173 }
174 if (highlighted_tab_ != -1) {
175 Tab* tab = tab_strip->tab_at(highlighted_tab_);
176 tab->hover_controller()->HideImmediately();
177 }
178 if (new_index == browser->tab_strip_model()->active_index()) {
179 highlighted_tab_ = -1;
180 } else {
181 highlighted_tab_ = new_index;
182 new_tab->hover_controller()->Show(views::GlowHoverController::PRONOUNCED);
183 }
184 }
185 if (highlighted_tab_ != -1) {
186 gfx::Point hover_point(swipe_x_, swipe_y_);
187 views::View::ConvertPointToTarget(tab_strip, new_tab, &hover_point);
188 new_tab->hover_controller()->SetLocation(hover_point);
189 }
111 } 190 }
112 191
113 void TabScrubber::Observe(int type, 192 void TabScrubber::Observe(int type,
114 const content::NotificationSource& source, 193 const content::NotificationSource& source,
115 const content::NotificationDetails& details) { 194 const content::NotificationDetails& details) {
116 DCHECK(type == chrome::NOTIFICATION_BROWSER_CLOSING && 195 if (content::Source<Browser>(source).ptr() == browser_)
117 content::Source<Browser>(source).ptr() == browser_); 196 FinishScrub(false);
118 StopScrubbing(); 197 browser_ = NULL;
198 }
199
200 void TabScrubber::TabStripAddedTabAt(TabStrip* tab_strip, int index) {
201 if (highlighted_tab_ == -1)
202 return;
203
204 if (index < highlighted_tab_)
205 ++highlighted_tab_;
206 }
207
208 void TabScrubber::TabStripMovedTab(TabStrip* tab_strip,
209 int from_index,
210 int to_index) {
211 if (highlighted_tab_ == -1)
212 return;
213
214 if (from_index == highlighted_tab_)
215 highlighted_tab_ = to_index;
216 else if (from_index < highlighted_tab_&& highlighted_tab_<= to_index)
217 --highlighted_tab_;
218 else if (from_index > highlighted_tab_ && highlighted_tab_ >= to_index)
219 ++highlighted_tab_;
220 }
221
222 void TabScrubber::TabStripRemovedTabAt(TabStrip* tab_strip, int index) {
223 if (highlighted_tab_ == -1)
224 return;
225 if (index == highlighted_tab_) {
226 FinishScrub(false);
227 return;
228 }
229 if (index < highlighted_tab_)
230 --highlighted_tab_;
231 }
232
233 void TabScrubber::TabStripDeleted(TabStrip* tab_strip) {
234 if (highlighted_tab_ == -1)
sky 2013/02/06 22:55:16 Do you really need this? Maybe you should nuke the
235 return;
119 } 236 }
120 237
121 Browser* TabScrubber::GetActiveBrowser() { 238 Browser* TabScrubber::GetActiveBrowser() {
122 aura::Window* active_window = ash::wm::GetActiveWindow(); 239 aura::Window* active_window = ash::wm::GetActiveWindow();
123 if (!active_window) 240 if (!active_window)
124 return NULL; 241 return NULL;
125 242
126 Browser* browser = chrome::FindBrowserWithWindow(active_window); 243 Browser* browser = chrome::FindBrowserWithWindow(active_window);
127 if (!browser || browser->type() != Browser::TYPE_TABBED) 244 if (!browser || browser->type() != Browser::TYPE_TABBED)
128 return NULL; 245 return NULL;
129 246
130 return browser; 247 return browser;
131 } 248 }
132 249
133 void TabScrubber::StopScrubbing() { 250 void TabScrubber::FinishScrub(bool activate) {
134 if (!scrubbing_) 251 activate_timer_.Stop();
135 return;
136 252
137 registrar_.Remove( 253 if (browser_) {
138 this, 254 BrowserView* browser_view =
139 chrome::NOTIFICATION_BROWSER_CLOSING, 255 BrowserView::GetBrowserViewForNativeWindow(
140 content::Source<Browser>(browser_)); 256 browser_->window()->GetNativeWindow());
257 TabStrip* tab_strip = browser_view->tabstrip();
258 if (activate && highlighted_tab_ != -1) {
259 Tab* tab = tab_strip->tab_at(highlighted_tab_);
260 tab->hover_controller()->HideImmediately();
261 browser_->tab_strip_model()->ActivateTabAt(highlighted_tab_, true);
262 }
263 tab_strip->RemoveObserver(this);
264 if (!cancel_immersive_reveal_timer_.IsRunning() &&
265 should_cancel_immersive_reveal_) {
266 cancel_immersive_reveal_timer_.Start(
267 FROM_HERE,
268 base::TimeDelta::FromMilliseconds(kCancelImmersiveRevelDelayMS),
269 base:: Bind(&TabScrubber::CancelImmersiveReveal,
270 weak_ptr_factory_.GetWeakPtr()));
271 }
272 }
273 swipe_x_ = -1;
274 swipe_y_ = -1;
141 scrubbing_ = false; 275 scrubbing_ = false;
142 browser_ = NULL; 276 highlighted_tab_ = -1;
143 } 277 }
278
279 void TabScrubber::CancelImmersiveReveal() {
280 cancel_immersive_reveal_timer_.Stop();
281 if (browser_ && should_cancel_immersive_reveal_) {
282 BrowserView* browser_view =
283 BrowserView::GetBrowserViewForNativeWindow(
284 browser_->window()->GetNativeWindow());
285 browser_view->immersive_mode_controller()->CancelReveal();
286 }
287 should_cancel_immersive_reveal_ = false;
288 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698