OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/views/tabs/tab_strip.h" | 5 #include "chrome/browser/views/tabs/tab_strip.h" |
6 | 6 |
7 #include "app/animation_container.h" | 7 #include "app/animation_container.h" |
8 #include "app/drag_drop_types.h" | 8 #include "app/drag_drop_types.h" |
9 #include "app/l10n_util.h" | 9 #include "app/l10n_util.h" |
10 #include "app/resource_bundle.h" | 10 #include "app/resource_bundle.h" |
11 #include "app/slide_animation.h" | 11 #include "app/slide_animation.h" |
12 #include "base/compiler_specific.h" | 12 #include "base/compiler_specific.h" |
13 #include "base/stl_util-inl.h" | 13 #include "base/stl_util-inl.h" |
14 #include "chrome/browser/browser.h" | 14 #include "chrome/browser/browser.h" |
15 #include "chrome/browser/browser_theme_provider.h" | 15 #include "chrome/browser/browser_theme_provider.h" |
16 #include "chrome/browser/defaults.h" | 16 #include "chrome/browser/defaults.h" |
17 #include "chrome/browser/view_ids.h" | 17 #include "chrome/browser/view_ids.h" |
18 #include "chrome/browser/views/tabs/dragged_tab_controller.h" | |
19 #include "chrome/browser/views/tabs/tab.h" | 18 #include "chrome/browser/views/tabs/tab.h" |
20 #include "chrome/browser/views/tabs/tab_strip_controller.h" | 19 #include "chrome/browser/views/tabs/tab_strip_controller.h" |
21 #include "chrome/common/pref_names.h" | 20 #include "chrome/common/pref_names.h" |
22 #include "gfx/canvas.h" | 21 #include "gfx/canvas.h" |
23 #include "gfx/path.h" | 22 #include "gfx/path.h" |
24 #include "gfx/size.h" | 23 #include "gfx/size.h" |
25 #include "grit/generated_resources.h" | 24 #include "grit/generated_resources.h" |
26 #include "grit/theme_resources.h" | 25 #include "grit/theme_resources.h" |
27 #include "views/controls/image_view.h" | 26 #include "views/controls/image_view.h" |
28 #include "views/widget/default_theme_provider.h" | 27 #include "views/widget/default_theme_provider.h" |
29 #include "views/widget/root_view.h" | |
30 #include "views/window/non_client_view.h" | 28 #include "views/window/non_client_view.h" |
31 #include "views/window/window.h" | 29 #include "views/window/window.h" |
32 | 30 |
33 #if defined(OS_WIN) | 31 #if defined(OS_WIN) |
34 #include "app/win_util.h" | 32 #include "app/win_util.h" |
35 #include "views/widget/widget_win.h" | 33 #include "views/widget/widget_win.h" |
36 #elif defined(OS_LINUX) | 34 #elif defined(OS_LINUX) |
37 #include "views/widget/widget_gtk.h" | 35 #include "views/widget/widget_gtk.h" |
38 #endif | 36 #endif |
39 | 37 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 Tab* tab_; | 103 Tab* tab_; |
106 | 104 |
107 DISALLOW_COPY_AND_ASSIGN(NewTabAlphaDelegate); | 105 DISALLOW_COPY_AND_ASSIGN(NewTabAlphaDelegate); |
108 }; | 106 }; |
109 | 107 |
110 // Animation delegate used when a dragged tab is released. When done sets the | 108 // Animation delegate used when a dragged tab is released. When done sets the |
111 // dragging state to false. | 109 // dragging state to false. |
112 class ResetDraggingStateDelegate | 110 class ResetDraggingStateDelegate |
113 : public views::BoundsAnimator::OwnedAnimationDelegate { | 111 : public views::BoundsAnimator::OwnedAnimationDelegate { |
114 public: | 112 public: |
115 explicit ResetDraggingStateDelegate(Tab* tab) : tab_(tab) { | 113 explicit ResetDraggingStateDelegate(BaseTabRenderer* tab) : tab_(tab) { |
116 } | 114 } |
117 | 115 |
118 virtual void AnimationEnded(const Animation* animation) { | 116 virtual void AnimationEnded(const Animation* animation) { |
119 tab_->set_dragging(false); | 117 tab_->set_dragging(false); |
120 } | 118 } |
121 | 119 |
122 virtual void AnimationCanceled(const Animation* animation) { | 120 virtual void AnimationCanceled(const Animation* animation) { |
123 tab_->set_dragging(false); | 121 tab_->set_dragging(false); |
124 } | 122 } |
125 | 123 |
126 private: | 124 private: |
127 Tab* tab_; | 125 BaseTabRenderer* tab_; |
128 | 126 |
129 DISALLOW_COPY_AND_ASSIGN(ResetDraggingStateDelegate); | 127 DISALLOW_COPY_AND_ASSIGN(ResetDraggingStateDelegate); |
130 }; | 128 }; |
131 | 129 |
132 /////////////////////////////////////////////////////////////////////////////// | 130 /////////////////////////////////////////////////////////////////////////////// |
133 // NewTabButton | 131 // NewTabButton |
134 // | 132 // |
135 // A subclass of button that hit-tests to the shape of the new tab button. | 133 // A subclass of button that hit-tests to the shape of the new tab button. |
136 | 134 |
137 class NewTabButton : public views::ImageButton { | 135 class NewTabButton : public views::ImageButton { |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
199 CompleteRemove(); | 197 CompleteRemove(); |
200 } | 198 } |
201 | 199 |
202 private: | 200 private: |
203 void CompleteRemove() { | 201 void CompleteRemove() { |
204 if (!tab_->closing()) { | 202 if (!tab_->closing()) { |
205 // The tab was added back yet we weren't canceled. This shouldn't happen. | 203 // The tab was added back yet we weren't canceled. This shouldn't happen. |
206 NOTREACHED(); | 204 NOTREACHED(); |
207 return; | 205 return; |
208 } | 206 } |
209 tabstrip_->RemoveTab(tab_); | 207 tabstrip_->RemoveAndDeleteTab(tab_); |
210 HighlightCloseButton(); | 208 HighlightCloseButton(); |
211 } | 209 } |
212 | 210 |
213 // When the animation completes, we send the Container a message to simulate | 211 // When the animation completes, we send the Container a message to simulate |
214 // a mouse moved event at the current mouse position. This tickles the Tab | 212 // a mouse moved event at the current mouse position. This tickles the Tab |
215 // the mouse is currently over to show the "hot" state of the close button. | 213 // the mouse is currently over to show the "hot" state of the close button. |
216 void HighlightCloseButton() { | 214 void HighlightCloseButton() { |
217 if (tabstrip_->available_width_for_tabs_ == -1 || | 215 if (tabstrip_->available_width_for_tabs_ == -1 || |
218 tabstrip_->IsDragSessionActive()) { | 216 tabstrip_->IsDragSessionActive()) { |
219 // This function is not required (and indeed may crash!) for removes | 217 // This function is not required (and indeed may crash!) for removes |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
251 /////////////////////////////////////////////////////////////////////////////// | 249 /////////////////////////////////////////////////////////////////////////////// |
252 // TabStrip, public: | 250 // TabStrip, public: |
253 | 251 |
254 // static | 252 // static |
255 const int TabStrip::mini_to_non_mini_gap_ = 3; | 253 const int TabStrip::mini_to_non_mini_gap_ = 3; |
256 | 254 |
257 // static | 255 // static |
258 const int TabStrip::extra_gap_for_nano_ = 10; | 256 const int TabStrip::extra_gap_for_nano_ = 10; |
259 | 257 |
260 TabStrip::TabStrip(TabStripController* controller) | 258 TabStrip::TabStrip(TabStripController* controller) |
261 : BaseTabStrip(controller), | 259 : BaseTabStrip(controller, BaseTabStrip::HORIZONTAL_TAB_STRIP), |
262 resize_layout_factory_(this), | 260 resize_layout_factory_(this), |
263 added_as_message_loop_observer_(false), | 261 added_as_message_loop_observer_(false), |
264 needs_resize_layout_(false), | 262 needs_resize_layout_(false), |
265 current_unselected_width_(Tab::GetStandardSize().width()), | 263 current_unselected_width_(Tab::GetStandardSize().width()), |
266 current_selected_width_(Tab::GetStandardSize().width()), | 264 current_selected_width_(Tab::GetStandardSize().width()), |
267 available_width_for_tabs_(-1), | 265 available_width_for_tabs_(-1), |
268 animation_container_(new AnimationContainer()), | 266 animation_container_(new AnimationContainer()), |
269 ALLOW_THIS_IN_INITIALIZER_LIST(bounds_animator_(this)), | 267 ALLOW_THIS_IN_INITIALIZER_LIST(bounds_animator_(this)), |
270 animation_type_(ANIMATION_DEFAULT), | 268 animation_type_(ANIMATION_DEFAULT), |
271 new_tab_button_enabled_(true), | 269 new_tab_button_enabled_(true), |
272 cancelling_animation_(false), | 270 cancelling_animation_(false) { |
273 attaching_dragged_tab_(false) { | |
274 Init(); | 271 Init(); |
275 } | 272 } |
276 | 273 |
277 TabStrip::~TabStrip() { | 274 TabStrip::~TabStrip() { |
278 // The animations may reference the tabs. Shut down the animation before we | 275 // The animations may reference the tabs. Shut down the animation before we |
279 // delete the tabs. | 276 // delete the tabs. |
280 StopAnimating(false); | 277 StopAnimating(false); |
281 | 278 |
282 // TODO(beng): remove this if it doesn't work to fix the TabSelectedAt bug. | 279 DestroyDragController(); |
283 drag_controller_.reset(NULL); | |
284 | 280 |
285 // Make sure we unhook ourselves as a message loop observer so that we don't | 281 // Make sure we unhook ourselves as a message loop observer so that we don't |
286 // crash in the case where the user closes the window after closing a tab | 282 // crash in the case where the user closes the window after closing a tab |
287 // but before moving the mouse. | 283 // but before moving the mouse. |
288 RemoveMessageLoopObserver(); | 284 RemoveMessageLoopObserver(); |
289 | 285 |
290 // The children (tabs) may callback to us from their destructor. Delete them | 286 // The children (tabs) may callback to us from their destructor. Delete them |
291 // so that if they call back we aren't in a weird state. | 287 // so that if they call back we aren't in a weird state. |
292 RemoveAllChildViews(true); | 288 RemoveAllChildViews(true); |
293 } | 289 } |
294 | 290 |
295 void TabStrip::DestroyDragController() { | |
296 if (IsDragSessionActive()) | |
297 drag_controller_.reset(NULL); | |
298 } | |
299 | |
300 gfx::Rect TabStrip::GetIdealBounds(int tab_data_index) { | |
301 DCHECK_GE(tab_data_index, 0); | |
302 DCHECK_LT(tab_data_index, GetTabCount()); | |
303 return tab_data_[tab_data_index].ideal_bounds; | |
304 } | |
305 | |
306 void TabStrip::InitTabStripButtons() { | 291 void TabStrip::InitTabStripButtons() { |
307 newtab_button_ = new NewTabButton(this); | 292 newtab_button_ = new NewTabButton(this); |
308 if (browser_defaults::kSizeTabButtonToTopOfTabStrip) { | 293 if (browser_defaults::kSizeTabButtonToTopOfTabStrip) { |
309 newtab_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT, | 294 newtab_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT, |
310 views::ImageButton::ALIGN_BOTTOM); | 295 views::ImageButton::ALIGN_BOTTOM); |
311 } | 296 } |
312 LoadNewTabButtonImage(); | 297 LoadNewTabButtonImage(); |
313 newtab_button_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_NEWTAB)); | 298 newtab_button_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_NEWTAB)); |
314 AddChildView(newtab_button_); | 299 AddChildView(newtab_button_); |
315 } | 300 } |
316 | 301 |
317 gfx::Rect TabStrip::GetNewTabButtonBounds() { | 302 gfx::Rect TabStrip::GetNewTabButtonBounds() { |
318 return newtab_button_->bounds(); | 303 return newtab_button_->bounds(); |
319 } | 304 } |
320 | 305 |
321 //////////////////////////////////////////////////////////////////////////////// | 306 //////////////////////////////////////////////////////////////////////////////// |
322 // TabStrip, BaseTabStrip implementation: | 307 // TabStrip, BaseTabStrip implementation: |
323 | 308 |
324 int TabStrip::GetPreferredHeight() { | 309 int TabStrip::GetPreferredHeight() { |
325 return GetPreferredSize().height(); | 310 return GetPreferredSize().height(); |
326 } | 311 } |
327 | 312 |
328 void TabStrip::SetBackgroundOffset(const gfx::Point& offset) { | 313 void TabStrip::SetBackgroundOffset(const gfx::Point& offset) { |
329 int tab_count = GetTabCount(); | 314 for (int i = 0; i < tab_count(); ++i) |
330 for (int i = 0; i < tab_count; ++i) | |
331 GetTabAtTabDataIndex(i)->SetBackgroundOffset(offset); | 315 GetTabAtTabDataIndex(i)->SetBackgroundOffset(offset); |
332 } | 316 } |
333 | 317 |
334 bool TabStrip::IsPositionInWindowCaption(const gfx::Point& point) { | 318 bool TabStrip::IsPositionInWindowCaption(const gfx::Point& point) { |
335 views::View* v = GetViewForPoint(point); | 319 views::View* v = GetViewForPoint(point); |
336 | 320 |
337 // If there is no control at this location, claim the hit was in the title | 321 // If there is no control at this location, claim the hit was in the title |
338 // bar to get a move action. | 322 // bar to get a move action. |
339 if (v == this) | 323 if (v == this) |
340 return true; | 324 return true; |
(...skipping 10 matching lines...) Expand all Loading... |
351 | 335 |
352 // All other regions, including the new Tab button, should be considered part | 336 // All other regions, including the new Tab button, should be considered part |
353 // of the containing Window's client area so that regular events can be | 337 // of the containing Window's client area so that regular events can be |
354 // processed for them. | 338 // processed for them. |
355 return false; | 339 return false; |
356 } | 340 } |
357 | 341 |
358 void TabStrip::SetDraggedTabBounds(int tab_index, const gfx::Rect& tab_bounds) { | 342 void TabStrip::SetDraggedTabBounds(int tab_index, const gfx::Rect& tab_bounds) { |
359 } | 343 } |
360 | 344 |
361 bool TabStrip::IsDragSessionActive() const { | |
362 return drag_controller_.get() != NULL; | |
363 } | |
364 | |
365 bool TabStrip::IsAnimating() const { | 345 bool TabStrip::IsAnimating() const { |
366 return bounds_animator_.IsAnimating() || new_tab_timer_.IsRunning(); | 346 return bounds_animator_.IsAnimating() || new_tab_timer_.IsRunning(); |
367 } | 347 } |
368 | 348 |
369 TabStrip* TabStrip::AsTabStrip() { | 349 TabStrip* TabStrip::AsTabStrip() { |
370 return this; | 350 return this; |
371 } | 351 } |
372 | 352 |
373 void TabStrip::AddTabAt(int model_index, | |
374 bool foreground, | |
375 const TabRendererData& data) { | |
376 Tab* tab = CreateTab(); | |
377 tab->SetAnimationContainer(animation_container_.get()); | |
378 tab->SetData(data); | |
379 | |
380 TabData d = { tab, gfx::Rect() }; | |
381 tab_data_.insert(tab_data_.begin() + | |
382 ModelIndexToTabDataIndex(model_index), d); | |
383 | |
384 AddChildView(tab); | |
385 | |
386 // Don't animate the first tab, it looks weird, and don't animate anything | |
387 // if the containing window isn't visible yet. | |
388 if (GetTabCount() > 1 && GetWindow() && GetWindow()->IsVisible()) { | |
389 if (!IsDragSessionActive() && !attaching_dragged_tab_ && | |
390 ShouldStartIntertTabAnimationAtEnd(model_index, foreground)) { | |
391 StartInsertTabAnimationAtEnd(); | |
392 } else { | |
393 StartInsertTabAnimation(model_index); | |
394 } | |
395 } else { | |
396 Layout(); | |
397 } | |
398 } | |
399 | |
400 void TabStrip::RemoveTabAt(int model_index, bool initiated_close) { | 353 void TabStrip::RemoveTabAt(int model_index, bool initiated_close) { |
401 if (initiated_close) { | 354 if (initiated_close) { |
402 int model_count = GetModelCount(); | 355 int model_count = GetModelCount(); |
403 if (model_index != model_count && model_count > 0) { | 356 if (model_index != model_count && model_count > 0) { |
404 Tab* last_tab = GetTabAtModelIndex(model_count - 1); | 357 Tab* last_tab = GetTabAtModelIndex(model_count - 1); |
405 // Limit the width available to the TabStrip for laying out Tabs, so that | 358 // Limit the width available to the TabStrip for laying out Tabs, so that |
406 // Tabs are not resized until a later time (when the mouse pointer leaves | 359 // Tabs are not resized until a later time (when the mouse pointer leaves |
407 // the TabStrip). | 360 // the TabStrip). |
408 available_width_for_tabs_ = GetAvailableWidthForTabs(last_tab); | 361 available_width_for_tabs_ = GetAvailableWidthForTabs(last_tab); |
409 needs_resize_layout_ = true; | 362 needs_resize_layout_ = true; |
410 AddMessageLoopObserver(); | 363 AddMessageLoopObserver(); |
411 } else if (model_count) { | 364 } else if (model_count) { |
412 Tab* last_tab = GetTabAtModelIndex(model_count); | 365 Tab* last_tab = GetTabAtModelIndex(model_count); |
413 // Limit the width available to the TabStrip for laying out Tabs, so that | 366 // Limit the width available to the TabStrip for laying out Tabs, so that |
414 // Tabs are not resized until a later time (when the mouse pointer leaves | 367 // Tabs are not resized until a later time (when the mouse pointer leaves |
415 // the TabStrip). | 368 // the TabStrip). |
416 available_width_for_tabs_ = GetAvailableWidthForTabs(last_tab); | 369 available_width_for_tabs_ = GetAvailableWidthForTabs(last_tab); |
417 needs_resize_layout_ = true; | 370 needs_resize_layout_ = true; |
418 AddMessageLoopObserver(); | 371 AddMessageLoopObserver(); |
419 } | 372 } |
420 } | 373 } |
421 | |
422 StartRemoveTabAnimation(model_index); | 374 StartRemoveTabAnimation(model_index); |
423 } | 375 } |
424 | 376 |
425 void TabStrip::SelectTabAt(int old_model_index, int new_model_index) { | 377 void TabStrip::SelectTabAt(int old_model_index, int new_model_index) { |
426 // We have "tiny tabs" if the tabs are so tiny that the unselected ones are | 378 // We have "tiny tabs" if the tabs are so tiny that the unselected ones are |
427 // a different size to the selected ones. | 379 // a different size to the selected ones. |
428 bool tiny_tabs = current_unselected_width_ != current_selected_width_; | 380 bool tiny_tabs = current_unselected_width_ != current_selected_width_; |
429 if (!IsAnimating() && (!needs_resize_layout_ || tiny_tabs)) { | 381 if (!IsAnimating() && (!needs_resize_layout_ || tiny_tabs)) { |
430 Layout(); | 382 Layout(); |
431 } else { | 383 } else { |
432 SchedulePaint(); | 384 SchedulePaint(); |
433 } | 385 } |
434 | 386 |
435 if (old_model_index >= 0) { | 387 if (old_model_index >= 0) { |
436 GetTabAtTabDataIndex(ModelIndexToTabDataIndex(old_model_index))-> | 388 GetTabAtTabDataIndex(ModelIndexToTabIndex(old_model_index))-> |
437 StopMiniTabTitleAnimation(); | 389 StopMiniTabTitleAnimation(); |
438 } | 390 } |
439 } | 391 } |
440 | 392 |
441 void TabStrip::MoveTab(int from_model_index, int to_model_index) { | |
442 StartMoveTabAnimation(from_model_index, to_model_index); | |
443 } | |
444 | |
445 void TabStrip::TabTitleChangedNotLoading(int model_index) { | 393 void TabStrip::TabTitleChangedNotLoading(int model_index) { |
446 Tab* tab = GetTabAtModelIndex(model_index); | 394 Tab* tab = GetTabAtModelIndex(model_index); |
447 if (tab->data().mini && !tab->IsSelected()) | 395 if (tab->data().mini && !tab->IsSelected()) |
448 tab->StartMiniTabTitleAnimation(); | 396 tab->StartMiniTabTitleAnimation(); |
449 } | 397 } |
450 | 398 |
451 void TabStrip::SetTabData(int model_index, const TabRendererData& data) { | 399 void TabStrip::SetTabData(int model_index, const TabRendererData& data) { |
452 Tab* tab = GetTabAtModelIndex(model_index); | 400 Tab* tab = GetTabAtModelIndex(model_index); |
453 bool mini_state_changed = tab->data().mini != data.mini; | 401 bool mini_state_changed = tab->data().mini != data.mini; |
454 tab->SetData(data); | 402 tab->SetData(data); |
455 tab->SchedulePaint(); | 403 tab->SchedulePaint(); |
456 | 404 |
457 if (mini_state_changed) { | 405 if (mini_state_changed) { |
458 if (GetWindow() && GetWindow()->IsVisible()) | 406 if (GetWindow() && GetWindow()->IsVisible()) |
459 StartMiniTabAnimation(); | 407 StartMiniTabAnimation(); |
460 else | 408 else |
461 Layout(); | 409 Layout(); |
462 } | 410 } |
463 } | 411 } |
464 | 412 |
465 void TabStrip::StartHighlight(int model_index) { | 413 void TabStrip::StartHighlight(int model_index) { |
466 GetTabAtModelIndex(model_index)->StartPulse(); | 414 GetTabAtModelIndex(model_index)->StartPulse(); |
467 } | 415 } |
468 | 416 |
469 void TabStrip::StopAllHighlighting() { | 417 void TabStrip::StopAllHighlighting() { |
470 for (int i = 0; i < GetTabCount(); ++i) | 418 for (int i = 0; i < tab_count(); ++i) |
471 GetTabAtTabDataIndex(i)->StopPulse(); | 419 GetTabAtTabDataIndex(i)->StopPulse(); |
472 } | 420 } |
473 | 421 |
474 BaseTabRenderer* TabStrip::GetBaseTabAtModelIndex(int model_index) const { | |
475 return GetTabAtModelIndex(model_index); | |
476 } | |
477 | |
478 BaseTabRenderer* TabStrip::GetBaseTabAtTabIndex(int tab_index) const { | |
479 return GetTabAtTabDataIndex(tab_index); | |
480 } | |
481 | |
482 int TabStrip::GetModelIndexOfBaseTab(const BaseTabRenderer* tab) const { | |
483 return GetModelIndexOfTab(static_cast<const Tab*>(tab)); | |
484 } | |
485 | |
486 BaseTabRenderer* TabStrip::CreateTabForDragging() { | 422 BaseTabRenderer* TabStrip::CreateTabForDragging() { |
487 Tab* tab = new Tab(NULL); | 423 Tab* tab = new Tab(NULL); |
488 // Make sure the dragged tab shares our theme provider. We need to explicitly | 424 // Make sure the dragged tab shares our theme provider. We need to explicitly |
489 // do this as during dragging there isn't a theme provider. | 425 // do this as during dragging there isn't a theme provider. |
490 tab->SetThemeProvider(GetThemeProvider()); | 426 tab->SetThemeProvider(GetThemeProvider()); |
491 return tab; | 427 return tab; |
492 } | 428 } |
493 | 429 |
494 /////////////////////////////////////////////////////////////////////////////// | 430 /////////////////////////////////////////////////////////////////////////////// |
495 // TabStrip, views::View overrides: | 431 // TabStrip, views::View overrides: |
496 | 432 |
497 void TabStrip::PaintChildren(gfx::Canvas* canvas) { | 433 void TabStrip::PaintChildren(gfx::Canvas* canvas) { |
498 // Tabs are painted in reverse order, so they stack to the left. | 434 // Tabs are painted in reverse order, so they stack to the left. |
499 int tab_count = GetTabCount(); | |
500 | |
501 // Phantom tabs appear behind all other tabs and are rendered first. To make | 435 // Phantom tabs appear behind all other tabs and are rendered first. To make |
502 // them slightly transparent we render them to a different layer. | 436 // them slightly transparent we render them to a different layer. |
503 if (HasPhantomTabs()) { | 437 if (HasPhantomTabs()) { |
504 SkRect bounds; | 438 SkRect bounds; |
505 bounds.set(0, 0, SkIntToScalar(width()), SkIntToScalar(height())); | 439 bounds.set(0, 0, SkIntToScalar(width()), SkIntToScalar(height())); |
506 canvas->saveLayerAlpha(&bounds, kPhantomTabAlpha, | 440 canvas->saveLayerAlpha(&bounds, kPhantomTabAlpha, |
507 SkCanvas::kARGB_ClipLayer_SaveFlag); | 441 SkCanvas::kARGB_ClipLayer_SaveFlag); |
508 canvas->drawARGB(0, 255, 255, 255, SkXfermode::kClear_Mode); | 442 canvas->drawARGB(0, 255, 255, 255, SkXfermode::kClear_Mode); |
509 for (int i = tab_count - 1; i >= 0; --i) { | 443 for (int i = tab_count() - 1; i >= 0; --i) { |
510 Tab* tab = GetTabAtTabDataIndex(i); | 444 Tab* tab = GetTabAtTabDataIndex(i); |
511 if (tab->data().phantom) | 445 if (tab->data().phantom) |
512 tab->ProcessPaint(canvas); | 446 tab->ProcessPaint(canvas); |
513 } | 447 } |
514 canvas->restore(); | 448 canvas->restore(); |
515 | 449 |
516 canvas->saveLayerAlpha(&bounds, kPhantomTabIconAlpha, | 450 canvas->saveLayerAlpha(&bounds, kPhantomTabIconAlpha, |
517 SkCanvas::kARGB_ClipLayer_SaveFlag); | 451 SkCanvas::kARGB_ClipLayer_SaveFlag); |
518 canvas->drawARGB(0, 255, 255, 255, SkXfermode::kClear_Mode); | 452 canvas->drawARGB(0, 255, 255, 255, SkXfermode::kClear_Mode); |
519 for (int i = tab_count - 1; i >= 0; --i) { | 453 for (int i = tab_count() - 1; i >= 0; --i) { |
520 Tab* tab = GetTabAtTabDataIndex(i); | 454 Tab* tab = GetTabAtTabDataIndex(i); |
521 if (tab->data().phantom) { | 455 if (tab->data().phantom) { |
522 canvas->save(); | 456 canvas->save(); |
523 canvas->ClipRectInt(tab->MirroredX(), tab->y(), tab->width(), | 457 canvas->ClipRectInt(tab->MirroredX(), tab->y(), tab->width(), |
524 tab->height()); | 458 tab->height()); |
525 canvas->TranslateInt(tab->MirroredX(), tab->y()); | 459 canvas->TranslateInt(tab->MirroredX(), tab->y()); |
526 tab->PaintIcon(canvas); | 460 tab->PaintIcon(canvas); |
527 canvas->restore(); | 461 canvas->restore(); |
528 } | 462 } |
529 } | 463 } |
530 canvas->restore(); | 464 canvas->restore(); |
531 } | 465 } |
532 | 466 |
533 Tab* selected_tab = NULL; | 467 Tab* selected_tab = NULL; |
534 | 468 |
535 Tab* dragging_tab = NULL; | 469 Tab* dragging_tab = NULL; |
536 | 470 |
537 int model_count = GetModelCount(); | 471 int model_count = GetModelCount(); |
538 | 472 |
539 for (int i = tab_count - 1; i >= 0; --i) { | 473 for (int i = tab_count() - 1; i >= 0; --i) { |
540 Tab* tab = GetTabAtTabDataIndex(i); | 474 Tab* tab = GetTabAtTabDataIndex(i); |
541 // We must ask the _Tab's_ model, not ourselves, because in some situations | 475 // We must ask the _Tab's_ model, not ourselves, because in some situations |
542 // the model will be different to this object, e.g. when a Tab is being | 476 // the model will be different to this object, e.g. when a Tab is being |
543 // removed after its TabContents has been destroyed. | 477 // removed after its TabContents has been destroyed. |
544 if (!tab->data().phantom) { | 478 if (!tab->data().phantom) { |
545 if (tab->dragging()) { | 479 if (tab->dragging()) { |
546 dragging_tab = tab; | 480 dragging_tab = tab; |
547 } else if (!tab->IsSelected()) { | 481 } else if (!tab->IsSelected()) { |
548 if (tab->render_unselected() && model_count > 1) { | 482 if (tab->render_unselected() && model_count > 1) { |
549 // See comment above kNetTabAnimationSelectedOffset as to why we do | 483 // See comment above kNetTabAnimationSelectedOffset as to why we do |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 newtab_button_->ProcessPaint(canvas); | 525 newtab_button_->ProcessPaint(canvas); |
592 } | 526 } |
593 | 527 |
594 // And the dragged tab. | 528 // And the dragged tab. |
595 if (dragging_tab) | 529 if (dragging_tab) |
596 dragging_tab->ProcessPaint(canvas); | 530 dragging_tab->ProcessPaint(canvas); |
597 } | 531 } |
598 | 532 |
599 // Overridden to support automation. See automation_proxy_uitest.cc. | 533 // Overridden to support automation. See automation_proxy_uitest.cc. |
600 views::View* TabStrip::GetViewByID(int view_id) const { | 534 views::View* TabStrip::GetViewByID(int view_id) const { |
601 if (GetTabCount() > 0) { | 535 if (tab_count() > 0) { |
602 if (view_id == VIEW_ID_TAB_LAST) { | 536 if (view_id == VIEW_ID_TAB_LAST) { |
603 return GetTabAtTabDataIndex(GetTabCount() - 1); | 537 return GetTabAtTabDataIndex(tab_count() - 1); |
604 } else if ((view_id >= VIEW_ID_TAB_0) && (view_id < VIEW_ID_TAB_LAST)) { | 538 } else if ((view_id >= VIEW_ID_TAB_0) && (view_id < VIEW_ID_TAB_LAST)) { |
605 int index = view_id - VIEW_ID_TAB_0; | 539 int index = view_id - VIEW_ID_TAB_0; |
606 if (index >= 0 && index < GetTabCount()) { | 540 if (index >= 0 && index < tab_count()) { |
607 return GetTabAtTabDataIndex(index); | 541 return GetTabAtTabDataIndex(index); |
608 } else { | 542 } else { |
609 return NULL; | 543 return NULL; |
610 } | 544 } |
611 } | 545 } |
612 } | 546 } |
613 | 547 |
614 return View::GetViewByID(view_id); | 548 return View::GetViewByID(view_id); |
615 } | 549 } |
616 | 550 |
617 void TabStrip::Layout() { | 551 void TabStrip::Layout() { |
618 // Called from: | 552 BaseTabStrip::Layout(); |
619 // - window resize | |
620 StopAnimating(false); | |
621 | |
622 GenerateIdealBounds(); | |
623 | |
624 for (int i = 0, tab_count = GetTabCount(); i < tab_count; ++i) | |
625 tab_data_[i].tab->SetBounds(tab_data_[i].ideal_bounds); | |
626 | 553 |
627 if (new_tab_button_enabled_) { | 554 if (new_tab_button_enabled_) { |
628 newtab_button_->SetBounds(newtab_button_bounds_); | 555 newtab_button_->SetBounds(newtab_button_bounds_); |
629 newtab_button_->SetVisible(true); | 556 newtab_button_->SetVisible(true); |
630 } else { | 557 } else { |
631 newtab_button_->SetVisible(false); | 558 newtab_button_->SetVisible(false); |
632 } | 559 } |
633 | |
634 SchedulePaint(); | |
635 } | 560 } |
636 | 561 |
637 gfx::Size TabStrip::GetPreferredSize() { | 562 gfx::Size TabStrip::GetPreferredSize() { |
638 return gfx::Size(0, Tab::GetMinimumUnselectedSize().height()); | 563 return gfx::Size(0, Tab::GetMinimumUnselectedSize().height()); |
639 } | 564 } |
640 | 565 |
641 void TabStrip::OnDragEntered(const DropTargetEvent& event) { | 566 void TabStrip::OnDragEntered(const DropTargetEvent& event) { |
642 // Force animations to stop, otherwise it makes the index calculation tricky. | 567 // Force animations to stop, otherwise it makes the index calculation tricky. |
643 StopAnimating(true); | 568 StopAnimating(true); |
644 | 569 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
685 // Return any view that isn't a Tab or this TabStrip immediately. We don't | 610 // Return any view that isn't a Tab or this TabStrip immediately. We don't |
686 // want to interfere. | 611 // want to interfere. |
687 views::View* v = View::GetViewForPoint(point); | 612 views::View* v = View::GetViewForPoint(point); |
688 if (v && v != this && v->GetClassName() != Tab::kTabClassName) | 613 if (v && v != this && v->GetClassName() != Tab::kTabClassName) |
689 return v; | 614 return v; |
690 | 615 |
691 // The display order doesn't necessarily match the child list order, so we | 616 // The display order doesn't necessarily match the child list order, so we |
692 // walk the display list hit-testing Tabs. Since the selected tab always | 617 // walk the display list hit-testing Tabs. Since the selected tab always |
693 // renders on top of adjacent tabs, it needs to be hit-tested before any | 618 // renders on top of adjacent tabs, it needs to be hit-tested before any |
694 // left-adjacent Tab, so we look ahead for it as we walk. | 619 // left-adjacent Tab, so we look ahead for it as we walk. |
695 int tab_count = GetTabCount(); | 620 for (int i = 0; i < tab_count(); ++i) { |
696 for (int i = 0; i < tab_count; ++i) { | 621 Tab* next_tab = i < (tab_count() - 1) ? GetTabAtTabDataIndex(i + 1) : NULL; |
697 Tab* next_tab = i < (tab_count - 1) ? GetTabAtTabDataIndex(i + 1) : NULL; | |
698 if (next_tab && next_tab->IsSelected() && IsPointInTab(next_tab, point)) | 622 if (next_tab && next_tab->IsSelected() && IsPointInTab(next_tab, point)) |
699 return next_tab; | 623 return next_tab; |
700 Tab* tab = GetTabAtTabDataIndex(i); | 624 Tab* tab = GetTabAtTabDataIndex(i); |
701 if (IsPointInTab(tab, point)) | 625 if (IsPointInTab(tab, point)) |
702 return tab; | 626 return tab; |
703 } | 627 } |
704 | 628 |
705 // No need to do any floating view stuff, we don't use them in the TabStrip. | 629 // No need to do any floating view stuff, we don't use them in the TabStrip. |
706 return this; | 630 return this; |
707 } | 631 } |
708 | 632 |
709 void TabStrip::ThemeChanged() { | 633 void TabStrip::ThemeChanged() { |
710 LoadNewTabButtonImage(); | 634 LoadNewTabButtonImage(); |
711 } | 635 } |
712 | 636 |
713 void TabStrip::OnBoundsAnimatorDone(views::BoundsAnimator* animator) { | 637 void TabStrip::OnBoundsAnimatorDone(views::BoundsAnimator* animator) { |
714 AnimationType last_type = animation_type_; | 638 AnimationType last_type = animation_type_; |
715 | 639 |
716 ResetAnimationState(false); | 640 ResetAnimationState(false); |
717 | 641 |
718 if (!cancelling_animation_ && last_type == ANIMATION_NEW_TAB_2) | 642 if (!cancelling_animation_ && last_type == ANIMATION_NEW_TAB_2) |
719 NewTabAnimation2Done(); | 643 NewTabAnimation2Done(); |
720 } | 644 } |
721 | 645 |
722 Tab* TabStrip::CreateTab() { | 646 Tab* TabStrip::CreateTab() { |
723 return new Tab(this); | 647 Tab* tab = new Tab(this); |
| 648 tab->SetAnimationContainer(animation_container_.get()); |
| 649 return tab; |
| 650 } |
| 651 |
| 652 void TabStrip::StartInsertTabAnimation(int model_index, bool foreground) { |
| 653 if (!IsDragSessionActive() && !attaching_dragged_tab() && |
| 654 ShouldStartIntertTabAnimationAtEnd(model_index, foreground)) { |
| 655 StartInsertTabAnimationAtEnd(); |
| 656 } else { |
| 657 StartInsertTabAnimationImpl(model_index); |
| 658 } |
| 659 } |
| 660 |
| 661 void TabStrip::StartMoveTabAnimation() { |
| 662 ResetAnimationState(true); |
| 663 |
| 664 GenerateIdealBounds(); |
| 665 AnimateToIdealBounds(); |
| 666 } |
| 667 |
| 668 void TabStrip::StartedDraggingTab(BaseTabRenderer* tab) { |
| 669 tab->set_dragging(true); |
| 670 |
| 671 // Stop any animations on the tab. |
| 672 bounds_animator_.StopAnimatingView(tab); |
| 673 |
| 674 // Move the tab to its ideal bounds. |
| 675 GenerateIdealBounds(); |
| 676 int tab_data_index = TabIndexOfTab(tab); |
| 677 DCHECK(tab_data_index != -1); |
| 678 tab->SetBounds(ideal_bounds(tab_data_index)); |
| 679 SchedulePaint(); |
| 680 } |
| 681 |
| 682 void TabStrip::StoppedDraggingTab(BaseTabRenderer* tab) { |
| 683 int tab_data_index = TabIndexOfTab(tab); |
| 684 if (tab_data_index == -1) { |
| 685 // The tab was removed before the drag completed. Don't do anything. |
| 686 return; |
| 687 } |
| 688 |
| 689 // Animate the view back to its correct position. |
| 690 ResetAnimationState(true); |
| 691 GenerateIdealBounds(); |
| 692 AnimateToIdealBounds(); |
| 693 bounds_animator_.AnimateViewTo(tab, ideal_bounds(TabIndexOfTab(tab))); |
| 694 |
| 695 // Install a delegate to reset the dragging state when done. We have to leave |
| 696 // dragging true for the tab otherwise it'll draw beneath the new tab button. |
| 697 bounds_animator_.SetAnimationDelegate(tab, |
| 698 new ResetDraggingStateDelegate(tab), |
| 699 true); |
724 } | 700 } |
725 | 701 |
726 void TabStrip::ViewHierarchyChanged(bool is_add, | 702 void TabStrip::ViewHierarchyChanged(bool is_add, |
727 views::View* parent, | 703 views::View* parent, |
728 views::View* child) { | 704 views::View* child) { |
729 if (is_add && child == this) | 705 if (is_add && child == this) |
730 InitTabStripButtons(); | 706 InitTabStripButtons(); |
731 } | 707 } |
732 | 708 |
733 bool TabStrip::OnMouseDragged(const views::MouseEvent& event) { | |
734 if (drag_controller_.get()) | |
735 drag_controller_->Drag(); | |
736 return true; | |
737 } | |
738 | |
739 void TabStrip::OnMouseReleased(const views::MouseEvent& event, | |
740 bool canceled) { | |
741 EndDrag(canceled); | |
742 } | |
743 | |
744 /////////////////////////////////////////////////////////////////////////////// | 709 /////////////////////////////////////////////////////////////////////////////// |
745 // TabStrip, Tab::Delegate implementation: | 710 // TabStrip, Tab::Delegate implementation: |
746 | 711 |
747 bool TabStrip::IsTabSelected(const BaseTabRenderer* btr) const { | 712 bool TabStrip::IsTabSelected(const BaseTabRenderer* btr) const { |
748 const Tab* tab = static_cast<const Tab*>(btr); | 713 const Tab* tab = static_cast<const Tab*>(btr); |
749 if (tab->closing() || tab->render_unselected()) | 714 if (tab->closing() || tab->render_unselected()) |
750 return false; | 715 return false; |
751 | 716 |
752 return BaseTabStrip::IsTabSelected(btr); | 717 return BaseTabStrip::IsTabSelected(btr); |
753 } | 718 } |
754 | 719 |
755 bool TabStrip::IsTabPinned(const BaseTabRenderer* btr) const { | |
756 const Tab* tab = static_cast<const Tab*>(btr); | |
757 if (tab->closing()) | |
758 return false; | |
759 | |
760 return BaseTabStrip::IsTabPinned(tab); | |
761 } | |
762 | |
763 void TabStrip::MaybeStartDrag(BaseTabRenderer* btr, | |
764 const views::MouseEvent& event) { | |
765 Tab* tab = static_cast<Tab*>(btr); | |
766 // Don't accidentally start any drag operations during animations if the | |
767 // mouse is down... during an animation tabs are being resized automatically, | |
768 // so the View system can misinterpret this easily if the mouse is down that | |
769 // the user is dragging. | |
770 if (IsAnimating() || tab->closing() || !HasAvailableDragActions()) | |
771 return; | |
772 int model_index = GetModelIndexOfTab(tab); | |
773 if (!IsValidModelIndex(model_index)) { | |
774 CHECK(false); | |
775 return; | |
776 } | |
777 drag_controller_.reset(new DraggedTabController(tab, this)); | |
778 drag_controller_->CaptureDragInfo(tab, event.location()); | |
779 } | |
780 | |
781 void TabStrip::ContinueDrag(const views::MouseEvent& event) { | |
782 // We can get called even if |MaybeStartDrag| wasn't called in the event of | |
783 // a TabStrip animation when the mouse button is down. In this case we should | |
784 // _not_ continue the drag because it can lead to weird bugs. | |
785 if (drag_controller_.get()) { | |
786 bool started_drag = drag_controller_->started_drag(); | |
787 drag_controller_->Drag(); | |
788 if (drag_controller_->started_drag() && !started_drag) { | |
789 // The drag just started. Redirect mouse events to us to that the tab that | |
790 // originated the drag can be safely deleted. | |
791 GetRootView()->SetMouseHandler(this); | |
792 } | |
793 } | |
794 } | |
795 | |
796 bool TabStrip::EndDrag(bool canceled) { | |
797 if (!drag_controller_.get()) | |
798 return false; | |
799 bool started_drag = drag_controller_->started_drag(); | |
800 drag_controller_->EndDrag(canceled); | |
801 return started_drag; | |
802 } | |
803 | |
804 bool TabStrip::HasAvailableDragActions() const { | |
805 return controller()->HasAvailableDragActions() != 0; | |
806 } | |
807 | |
808 /////////////////////////////////////////////////////////////////////////////// | 720 /////////////////////////////////////////////////////////////////////////////// |
809 // TabStrip, views::BaseButton::ButtonListener implementation: | 721 // TabStrip, views::BaseButton::ButtonListener implementation: |
810 | 722 |
811 void TabStrip::ButtonPressed(views::Button* sender, const views::Event& event) { | 723 void TabStrip::ButtonPressed(views::Button* sender, const views::Event& event) { |
812 if (sender == newtab_button_) | 724 if (sender == newtab_button_) |
813 controller()->CreateNewTab(); | 725 controller()->CreateNewTab(); |
814 } | 726 } |
815 | 727 |
816 /////////////////////////////////////////////////////////////////////////////// | 728 /////////////////////////////////////////////////////////////////////////////// |
817 // TabStrip, MessageLoop::Observer implementation: | 729 // TabStrip, MessageLoop::Observer implementation: |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
909 tp->GetBitmapNamed(IDR_NEWTAB_BUTTON_P)); | 821 tp->GetBitmapNamed(IDR_NEWTAB_BUTTON_P)); |
910 newtab_button_->SetImage(views::CustomButton::BS_HOT, | 822 newtab_button_->SetImage(views::CustomButton::BS_HOT, |
911 tp->GetBitmapNamed(IDR_NEWTAB_BUTTON_H)); | 823 tp->GetBitmapNamed(IDR_NEWTAB_BUTTON_H)); |
912 newtab_button_->SetBackground(color, background, | 824 newtab_button_->SetBackground(color, background, |
913 tp->GetBitmapNamed(IDR_NEWTAB_BUTTON_MASK)); | 825 tp->GetBitmapNamed(IDR_NEWTAB_BUTTON_MASK)); |
914 if (in_test) | 826 if (in_test) |
915 delete tp; | 827 delete tp; |
916 } | 828 } |
917 | 829 |
918 Tab* TabStrip::GetTabAtTabDataIndex(int tab_data_index) const { | 830 Tab* TabStrip::GetTabAtTabDataIndex(int tab_data_index) const { |
919 DCHECK_GE(tab_data_index, 0); | 831 return static_cast<Tab*>(base_tab_at_tab_index(tab_data_index)); |
920 DCHECK_LT(tab_data_index, GetTabCount()); | |
921 return tab_data_[tab_data_index].tab; | |
922 } | 832 } |
923 | 833 |
924 Tab* TabStrip::GetTabAtModelIndex(int model_index) const { | 834 Tab* TabStrip::GetTabAtModelIndex(int model_index) const { |
925 return GetTabAtTabDataIndex(ModelIndexToTabDataIndex(model_index)); | 835 return GetTabAtTabDataIndex(ModelIndexToTabIndex(model_index)); |
926 } | |
927 | |
928 int TabStrip::GetTabCount() const { | |
929 return static_cast<int>(tab_data_.size()); | |
930 } | 836 } |
931 | 837 |
932 void TabStrip::GetCurrentTabWidths(double* unselected_width, | 838 void TabStrip::GetCurrentTabWidths(double* unselected_width, |
933 double* selected_width) const { | 839 double* selected_width) const { |
934 *unselected_width = current_unselected_width_; | 840 *unselected_width = current_unselected_width_; |
935 *selected_width = current_selected_width_; | 841 *selected_width = current_selected_width_; |
936 } | 842 } |
937 | 843 |
938 void TabStrip::GetDesiredTabWidths(int tab_count, | 844 void TabStrip::GetDesiredTabWidths(int tab_count, |
939 int mini_tab_count, | 845 int mini_tab_count, |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1017 *selected_width = std::max(available_width - total_offset - | 923 *selected_width = std::max(available_width - total_offset - |
1018 (min_unselected_width * (tab_count - 1)), min_selected_width); | 924 (min_unselected_width * (tab_count - 1)), min_selected_width); |
1019 } | 925 } |
1020 } | 926 } |
1021 } | 927 } |
1022 | 928 |
1023 void TabStrip::ResizeLayoutTabs() { | 929 void TabStrip::ResizeLayoutTabs() { |
1024 // We've been called back after the TabStrip has been emptied out (probably | 930 // We've been called back after the TabStrip has been emptied out (probably |
1025 // just prior to the window being destroyed). We need to do nothing here or | 931 // just prior to the window being destroyed). We need to do nothing here or |
1026 // else GetTabAt below will crash. | 932 // else GetTabAt below will crash. |
1027 if (GetTabCount() == 0) | 933 if (tab_count() == 0) |
1028 return; | 934 return; |
1029 | 935 |
1030 resize_layout_factory_.RevokeAll(); | 936 resize_layout_factory_.RevokeAll(); |
1031 | 937 |
1032 // It is critically important that this is unhooked here, otherwise we will | 938 // It is critically important that this is unhooked here, otherwise we will |
1033 // keep spying on messages forever. | 939 // keep spying on messages forever. |
1034 RemoveMessageLoopObserver(); | 940 RemoveMessageLoopObserver(); |
1035 | 941 |
1036 available_width_for_tabs_ = -1; | 942 available_width_for_tabs_ = -1; |
1037 int mini_tab_count = GetMiniTabCount(); | 943 int mini_tab_count = GetMiniTabCount(); |
1038 if (mini_tab_count == GetTabCount()) { | 944 if (mini_tab_count == tab_count()) { |
1039 // Only mini-tabs, we know the tab widths won't have changed (all | 945 // Only mini-tabs, we know the tab widths won't have changed (all |
1040 // mini-tabs have the same width), so there is nothing to do. | 946 // mini-tabs have the same width), so there is nothing to do. |
1041 return; | 947 return; |
1042 } | 948 } |
1043 Tab* first_tab = GetTabAtTabDataIndex(mini_tab_count); | 949 Tab* first_tab = GetTabAtTabDataIndex(mini_tab_count); |
1044 double unselected, selected; | 950 double unselected, selected; |
1045 GetDesiredTabWidths(GetTabCount(), mini_tab_count, GetNanoTabCount(), | 951 GetDesiredTabWidths(tab_count(), mini_tab_count, GetNanoTabCount(), |
1046 &unselected, &selected); | 952 &unselected, &selected); |
1047 int w = Round(first_tab->IsSelected() ? selected : selected); | 953 int w = Round(first_tab->IsSelected() ? selected : selected); |
1048 | 954 |
1049 // We only want to run the animation if we're not already at the desired | 955 // We only want to run the animation if we're not already at the desired |
1050 // size. | 956 // size. |
1051 if (abs(first_tab->width() - w) > 1) | 957 if (abs(first_tab->width() - w) > 1) |
1052 StartResizeLayoutAnimation(); | 958 StartResizeLayoutAnimation(); |
1053 } | 959 } |
1054 | 960 |
1055 bool TabStrip::IsCursorInTabStripZone() const { | 961 bool TabStrip::IsCursorInTabStripZone() const { |
(...skipping 30 matching lines...) Expand all Loading... |
1086 MessageLoopForUI::current()->RemoveObserver(this); | 992 MessageLoopForUI::current()->RemoveObserver(this); |
1087 added_as_message_loop_observer_ = false; | 993 added_as_message_loop_observer_ = false; |
1088 } | 994 } |
1089 } | 995 } |
1090 | 996 |
1091 gfx::Rect TabStrip::GetDropBounds(int drop_index, | 997 gfx::Rect TabStrip::GetDropBounds(int drop_index, |
1092 bool drop_before, | 998 bool drop_before, |
1093 bool* is_beneath) { | 999 bool* is_beneath) { |
1094 DCHECK(drop_index != -1); | 1000 DCHECK(drop_index != -1); |
1095 int center_x; | 1001 int center_x; |
1096 if (drop_index < GetTabCount()) { | 1002 if (drop_index < tab_count()) { |
1097 Tab* tab = GetTabAtTabDataIndex(drop_index); | 1003 Tab* tab = GetTabAtTabDataIndex(drop_index); |
1098 if (drop_before) | 1004 if (drop_before) |
1099 center_x = tab->x() - (kTabHOffset / 2); | 1005 center_x = tab->x() - (kTabHOffset / 2); |
1100 else | 1006 else |
1101 center_x = tab->x() + (tab->width() / 2); | 1007 center_x = tab->x() + (tab->width() / 2); |
1102 } else { | 1008 } else { |
1103 Tab* last_tab = GetTabAtTabDataIndex(drop_index - 1); | 1009 Tab* last_tab = GetTabAtTabDataIndex(drop_index - 1); |
1104 center_x = last_tab->x() + last_tab->width() + (kTabHOffset / 2); | 1010 center_x = last_tab->x() + last_tab->width() + (kTabHOffset / 2); |
1105 } | 1011 } |
1106 | 1012 |
(...skipping 21 matching lines...) Expand all Loading... |
1128 | 1034 |
1129 return drop_bounds; | 1035 return drop_bounds; |
1130 } | 1036 } |
1131 | 1037 |
1132 void TabStrip::UpdateDropIndex(const DropTargetEvent& event) { | 1038 void TabStrip::UpdateDropIndex(const DropTargetEvent& event) { |
1133 // If the UI layout is right-to-left, we need to mirror the mouse | 1039 // If the UI layout is right-to-left, we need to mirror the mouse |
1134 // coordinates since we calculate the drop index based on the | 1040 // coordinates since we calculate the drop index based on the |
1135 // original (and therefore non-mirrored) positions of the tabs. | 1041 // original (and therefore non-mirrored) positions of the tabs. |
1136 const int x = MirroredXCoordinateInsideView(event.x()); | 1042 const int x = MirroredXCoordinateInsideView(event.x()); |
1137 // We don't allow replacing the urls of mini-tabs. | 1043 // We don't allow replacing the urls of mini-tabs. |
1138 for (int i = GetMiniTabCount(); i < GetTabCount(); ++i) { | 1044 for (int i = GetMiniTabCount(); i < tab_count(); ++i) { |
1139 Tab* tab = GetTabAtTabDataIndex(i); | 1045 Tab* tab = GetTabAtTabDataIndex(i); |
1140 const int tab_max_x = tab->x() + tab->width(); | 1046 const int tab_max_x = tab->x() + tab->width(); |
1141 const int hot_width = tab->width() / 3; | 1047 const int hot_width = tab->width() / 3; |
1142 if (x < tab_max_x) { | 1048 if (x < tab_max_x) { |
1143 if (x < tab->x() + hot_width) | 1049 if (x < tab->x() + hot_width) |
1144 SetDropIndex(i, true); | 1050 SetDropIndex(i, true); |
1145 else if (x >= tab_max_x - hot_width) | 1051 else if (x >= tab_max_x - hot_width) |
1146 SetDropIndex(i + 1, true); | 1052 SetDropIndex(i + 1, true); |
1147 else | 1053 else |
1148 SetDropIndex(i, false); | 1054 SetDropIndex(i, false); |
1149 return; | 1055 return; |
1150 } | 1056 } |
1151 } | 1057 } |
1152 | 1058 |
1153 // The drop isn't over a tab, add it to the end. | 1059 // The drop isn't over a tab, add it to the end. |
1154 SetDropIndex(GetTabCount(), true); | 1060 SetDropIndex(tab_count(), true); |
1155 } | 1061 } |
1156 | 1062 |
1157 void TabStrip::SetDropIndex(int tab_data_index, bool drop_before) { | 1063 void TabStrip::SetDropIndex(int tab_data_index, bool drop_before) { |
1158 if (tab_data_index == -1) { | 1064 if (tab_data_index == -1) { |
1159 if (drop_info_.get()) | 1065 if (drop_info_.get()) |
1160 drop_info_.reset(NULL); | 1066 drop_info_.reset(NULL); |
1161 return; | 1067 return; |
1162 } | 1068 } |
1163 | 1069 |
1164 if (drop_info_.get() && drop_info_->drop_index == tab_data_index && | 1070 if (drop_info_.get() && drop_info_->drop_index == tab_data_index && |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1242 arrow_window->Close(); | 1148 arrow_window->Close(); |
1243 } | 1149 } |
1244 | 1150 |
1245 /////////////////////////////////////////////////////////////////////////////// | 1151 /////////////////////////////////////////////////////////////////////////////// |
1246 | 1152 |
1247 // Called from: | 1153 // Called from: |
1248 // - BasicLayout | 1154 // - BasicLayout |
1249 // - Tab insertion/removal | 1155 // - Tab insertion/removal |
1250 // - Tab reorder | 1156 // - Tab reorder |
1251 void TabStrip::GenerateIdealBounds() { | 1157 void TabStrip::GenerateIdealBounds() { |
1252 int tab_count = GetTabCount(); | |
1253 int non_closing_tab_count = 0; | 1158 int non_closing_tab_count = 0; |
1254 int mini_tab_count = 0; | 1159 int mini_tab_count = 0; |
1255 int nano_tab_count = 0; | 1160 int nano_tab_count = 0; |
1256 for (int i = 0; i < tab_count; ++i) { | 1161 for (int i = 0; i < tab_count(); ++i) { |
1257 if (!tab_data_[i].tab->closing()) { | 1162 BaseTabRenderer* tab = base_tab_at_tab_index(i); |
| 1163 if (!tab->closing()) { |
1258 ++non_closing_tab_count; | 1164 ++non_closing_tab_count; |
1259 if (tab_data_[i].tab->data().mini) | 1165 if (tab->data().mini) |
1260 mini_tab_count++; | 1166 mini_tab_count++; |
1261 if (tab_data_[i].tab->data().app) | 1167 if (tab->data().app) |
1262 nano_tab_count++; | 1168 nano_tab_count++; |
1263 } | 1169 } |
1264 } | 1170 } |
1265 | 1171 |
1266 double unselected, selected; | 1172 double unselected, selected; |
1267 GetDesiredTabWidths(non_closing_tab_count, mini_tab_count, nano_tab_count, | 1173 GetDesiredTabWidths(non_closing_tab_count, mini_tab_count, nano_tab_count, |
1268 &unselected, &selected); | 1174 &unselected, &selected); |
1269 | 1175 |
1270 current_unselected_width_ = unselected; | 1176 current_unselected_width_ = unselected; |
1271 current_selected_width_ = selected; | 1177 current_selected_width_ = selected; |
1272 | 1178 |
1273 // NOTE: This currently assumes a tab's height doesn't differ based on | 1179 // NOTE: This currently assumes a tab's height doesn't differ based on |
1274 // selected state or the number of tabs in the strip! | 1180 // selected state or the number of tabs in the strip! |
1275 int tab_height = Tab::GetStandardSize().height(); | 1181 int tab_height = Tab::GetStandardSize().height(); |
1276 double tab_x = 0; | 1182 double tab_x = 0; |
1277 bool last_was_mini = false; | 1183 bool last_was_mini = false; |
1278 for (int i = 0; i < tab_count; ++i) { | 1184 for (int i = 0; i < tab_count(); ++i) { |
1279 if (!tab_data_[i].tab->closing()) { | |
1280 Tab* tab = GetTabAtTabDataIndex(i); | 1185 Tab* tab = GetTabAtTabDataIndex(i); |
| 1186 if (!tab->closing()) { |
1281 double tab_width = unselected; | 1187 double tab_width = unselected; |
1282 if (tab->data().mini) { | 1188 if (tab->data().mini) { |
1283 tab_width = Tab::GetMiniWidth(); | 1189 tab_width = Tab::GetMiniWidth(); |
1284 } else { | 1190 } else { |
1285 if (last_was_mini) { | 1191 if (last_was_mini) { |
1286 // Give a bigger gap between mini and non-mini tabs. | 1192 // Give a bigger gap between mini and non-mini tabs. |
1287 tab_x += mini_to_non_mini_gap_; | 1193 tab_x += mini_to_non_mini_gap_; |
1288 if (nano_tab_count > 0) | 1194 if (nano_tab_count > 0) |
1289 tab_x += extra_gap_for_nano_; | 1195 tab_x += extra_gap_for_nano_; |
1290 } | 1196 } |
1291 if (tab->IsSelected()) | 1197 if (tab->IsSelected()) |
1292 tab_width = selected; | 1198 tab_width = selected; |
1293 } | 1199 } |
1294 double end_of_tab = tab_x + tab_width; | 1200 double end_of_tab = tab_x + tab_width; |
1295 int rounded_tab_x = Round(tab_x); | 1201 int rounded_tab_x = Round(tab_x); |
1296 tab_data_[i].ideal_bounds = | 1202 set_ideal_bounds(i, |
1297 gfx::Rect(rounded_tab_x, 0, Round(end_of_tab) - rounded_tab_x, | 1203 gfx::Rect(rounded_tab_x, 0, Round(end_of_tab) - rounded_tab_x, |
1298 tab_height); | 1204 tab_height)); |
1299 tab_x = end_of_tab + kTabHOffset; | 1205 tab_x = end_of_tab + kTabHOffset; |
1300 last_was_mini = tab->data().mini; | 1206 last_was_mini = tab->data().mini; |
1301 } | 1207 } |
1302 } | 1208 } |
1303 | 1209 |
1304 // Update bounds of new tab button. | 1210 // Update bounds of new tab button. |
1305 int new_tab_x; | 1211 int new_tab_x; |
1306 int new_tab_y = browser_defaults::kSizeTabButtonToTopOfTabStrip ? | 1212 int new_tab_y = browser_defaults::kSizeTabButtonToTopOfTabStrip ? |
1307 0 : kNewTabButtonVOffset; | 1213 0 : kNewTabButtonVOffset; |
1308 if (abs(Round(unselected) - Tab::GetStandardSize().width()) > 1 && | 1214 if (abs(Round(unselected) - Tab::GetStandardSize().width()) > 1 && |
1309 available_width_for_tabs_ == -1) { | 1215 available_width_for_tabs_ == -1) { |
1310 // We're shrinking tabs, so we need to anchor the New Tab button to the | 1216 // We're shrinking tabs, so we need to anchor the New Tab button to the |
1311 // right edge of the TabStrip's bounds, rather than the right edge of the | 1217 // right edge of the TabStrip's bounds, rather than the right edge of the |
1312 // right-most Tab, otherwise it'll bounce when animating. | 1218 // right-most Tab, otherwise it'll bounce when animating. |
1313 new_tab_x = width() - newtab_button_bounds_.width(); | 1219 new_tab_x = width() - newtab_button_bounds_.width(); |
1314 } else { | 1220 } else { |
1315 new_tab_x = Round(tab_x - kTabHOffset) + kNewTabButtonHOffset; | 1221 new_tab_x = Round(tab_x - kTabHOffset) + kNewTabButtonHOffset; |
1316 } | 1222 } |
1317 newtab_button_bounds_.set_origin(gfx::Point(new_tab_x, new_tab_y)); | 1223 newtab_button_bounds_.set_origin(gfx::Point(new_tab_x, new_tab_y)); |
1318 } | 1224 } |
1319 | 1225 |
1320 void TabStrip::NewTabAnimation1Done() { | 1226 void TabStrip::NewTabAnimation1Done() { |
1321 int tab_data_index = static_cast<int>(tab_data_.size() - 1); | 1227 int tab_data_index = tab_count() - 1; |
1322 Tab* tab = GetTabAtTabDataIndex(tab_data_index); | 1228 Tab* tab = GetTabAtTabDataIndex(tab_data_index); |
1323 | 1229 |
1324 gfx::Rect old_tab_bounds = tab->bounds(); | 1230 gfx::Rect old_tab_bounds = tab->bounds(); |
1325 | 1231 |
1326 GenerateIdealBounds(); | 1232 GenerateIdealBounds(); |
1327 | 1233 |
1328 gfx::Rect& end_bounds = tab_data_[tab_data_index].ideal_bounds; | 1234 gfx::Rect end_bounds = ideal_bounds(tab_data_index); |
1329 end_bounds.Offset(kNewTabOvershoot, 0); | 1235 end_bounds.Offset(kNewTabOvershoot, 0); |
| 1236 set_ideal_bounds(tab_data_index, end_bounds); |
1330 | 1237 |
1331 int x = old_tab_bounds.right() - end_bounds.width(); | 1238 int x = old_tab_bounds.right() - end_bounds.width(); |
1332 int w = end_bounds.width(); | 1239 int w = end_bounds.width(); |
1333 if (x < 0) { | 1240 if (x < 0) { |
1334 w += x; | 1241 w += x; |
1335 x = 0; | 1242 x = 0; |
1336 } | 1243 } |
1337 tab->SetBounds(x, old_tab_bounds.y(), w, end_bounds.height()); | 1244 tab->SetBounds(x, old_tab_bounds.y(), w, end_bounds.height()); |
1338 | 1245 |
1339 AnimateToIdealBounds(); | 1246 AnimateToIdealBounds(); |
(...skipping 13 matching lines...) Expand all Loading... |
1353 | 1260 |
1354 GenerateIdealBounds(); | 1261 GenerateIdealBounds(); |
1355 | 1262 |
1356 AnimateToIdealBounds(); | 1263 AnimateToIdealBounds(); |
1357 | 1264 |
1358 SlideAnimation* animation = new SlideAnimation(NULL); | 1265 SlideAnimation* animation = new SlideAnimation(NULL); |
1359 animation->SetSlideDuration(kNewTab3DurationMs); | 1266 animation->SetSlideDuration(kNewTab3DurationMs); |
1360 animation->SetTweenType(Tween::EASE_IN_OUT); | 1267 animation->SetTweenType(Tween::EASE_IN_OUT); |
1361 | 1268 |
1362 // BoundsAnimator takes ownership of animation. | 1269 // BoundsAnimator takes ownership of animation. |
1363 bounds_animator_.SetAnimationForView(tab_data_.back().tab, animation); | 1270 bounds_animator_.SetAnimationForView( |
| 1271 GetTabAtTabDataIndex(tab_count() - 1), animation); |
1364 } | 1272 } |
1365 | 1273 |
1366 void TabStrip::AnimateToIdealBounds() { | 1274 void TabStrip::AnimateToIdealBounds() { |
1367 for (size_t i = 0; i < tab_data_.size(); ++i) { | 1275 for (int i = 0; i < tab_count(); ++i) { |
1368 if (!tab_data_[i].tab->closing() && !tab_data_[i].tab->dragging()) { | 1276 Tab* tab = GetTabAtTabDataIndex(i); |
1369 bounds_animator_.AnimateViewTo(tab_data_[i].tab, | 1277 if (!tab->closing() && !tab->dragging()) |
1370 tab_data_[i].ideal_bounds); | 1278 bounds_animator_.AnimateViewTo(tab, ideal_bounds(i)); |
1371 } | |
1372 } | 1279 } |
1373 | 1280 |
1374 if (animation_type_ != ANIMATION_NEW_TAB_3) { | 1281 if (animation_type_ != ANIMATION_NEW_TAB_3) { |
1375 bounds_animator_.AnimateViewTo(newtab_button_, newtab_button_bounds_); | 1282 bounds_animator_.AnimateViewTo(newtab_button_, newtab_button_bounds_); |
1376 } | 1283 } |
1377 } | 1284 } |
1378 | 1285 |
1379 bool TabStrip::ShouldStartIntertTabAnimationAtEnd(int model_index, | 1286 bool TabStrip::ShouldStartIntertTabAnimationAtEnd(int model_index, |
1380 bool foreground) { | 1287 bool foreground) { |
1381 return foreground && (model_index + 1 == GetModelCount()) && | 1288 return foreground && (model_index + 1 == GetModelCount()) && |
1382 controller()->IsNewTabPage(model_index); | 1289 controller()->IsNewTabPage(model_index); |
1383 } | 1290 } |
1384 | 1291 |
1385 void TabStrip::StartResizeLayoutAnimation() { | 1292 void TabStrip::StartResizeLayoutAnimation() { |
1386 ResetAnimationState(true); | 1293 ResetAnimationState(true); |
1387 GenerateIdealBounds(); | 1294 GenerateIdealBounds(); |
1388 AnimateToIdealBounds(); | 1295 AnimateToIdealBounds(); |
1389 } | 1296 } |
1390 | 1297 |
1391 void TabStrip::StartInsertTabAnimationAtEnd() { | 1298 void TabStrip::StartInsertTabAnimationAtEnd() { |
1392 ResetAnimationState(true); | 1299 ResetAnimationState(true); |
1393 | 1300 |
1394 // The TabStrip can now use its entire width to lay out Tabs. | 1301 // The TabStrip can now use its entire width to lay out Tabs. |
1395 available_width_for_tabs_ = -1; | 1302 available_width_for_tabs_ = -1; |
1396 | 1303 |
1397 animation_type_ = ANIMATION_NEW_TAB_1; | 1304 animation_type_ = ANIMATION_NEW_TAB_1; |
1398 | 1305 |
1399 GenerateIdealBounds(); | 1306 GenerateIdealBounds(); |
1400 | 1307 |
1401 int tab_data_index = ModelIndexToTabDataIndex(GetModelCount() - 1); | 1308 int tab_data_index = ModelIndexToTabIndex(GetModelCount() - 1); |
1402 Tab* tab = tab_data_[tab_data_index].tab; | 1309 Tab* tab = GetTabAtTabDataIndex(tab_data_index); |
1403 tab->SizeToNewTabButtonImages(); | 1310 tab->SizeToNewTabButtonImages(); |
1404 tab->SetBounds(newtab_button_->x() + | 1311 tab->SetBounds(newtab_button_->x() + |
1405 (newtab_button_->width() - tab->width()) / 2, | 1312 (newtab_button_->width() - tab->width()) / 2, |
1406 tab_data_[tab_data_index].ideal_bounds.y(), | 1313 ideal_bounds(tab_data_index).y(), |
1407 tab->width(), tab->height()); | 1314 tab->width(), tab->height()); |
1408 tab->set_render_as_new_tab(true); | 1315 tab->set_render_as_new_tab(true); |
1409 | 1316 |
1410 new_tab_timer_.Start(base::TimeDelta::FromMilliseconds(kNewTabDurationMs), | 1317 new_tab_timer_.Start(base::TimeDelta::FromMilliseconds(kNewTabDurationMs), |
1411 this, &TabStrip::NewTabAnimation1Done); | 1318 this, &TabStrip::NewTabAnimation1Done); |
1412 } | 1319 } |
1413 | 1320 |
1414 void TabStrip::StartInsertTabAnimation(int model_index) { | 1321 void TabStrip::StartInsertTabAnimationImpl(int model_index) { |
1415 ResetAnimationState(true); | 1322 ResetAnimationState(true); |
1416 | 1323 |
1417 // The TabStrip can now use its entire width to lay out Tabs. | 1324 // The TabStrip can now use its entire width to lay out Tabs. |
1418 available_width_for_tabs_ = -1; | 1325 available_width_for_tabs_ = -1; |
1419 | 1326 |
1420 GenerateIdealBounds(); | 1327 GenerateIdealBounds(); |
1421 | 1328 |
1422 int tab_data_index = ModelIndexToTabDataIndex(model_index); | 1329 int tab_data_index = ModelIndexToTabIndex(model_index); |
1423 Tab* tab = tab_data_[tab_data_index].tab; | 1330 BaseTabRenderer* tab = base_tab_at_tab_index(tab_data_index); |
1424 if (model_index == 0) { | 1331 if (model_index == 0) { |
1425 tab->SetBounds(0, tab_data_[tab_data_index].ideal_bounds.y(), 0, | 1332 tab->SetBounds(0, ideal_bounds(tab_data_index).y(), 0, |
1426 tab_data_[tab_data_index].ideal_bounds.height()); | 1333 ideal_bounds(tab_data_index).height()); |
1427 } else { | 1334 } else { |
1428 Tab* last_tab = tab_data_[tab_data_index - 1].tab; | 1335 BaseTabRenderer* last_tab = base_tab_at_tab_index(tab_data_index - 1); |
1429 tab->SetBounds(last_tab->bounds().right() + kTabHOffset, | 1336 tab->SetBounds(last_tab->bounds().right() + kTabHOffset, |
1430 tab_data_[tab_data_index].ideal_bounds.y(), 0, | 1337 ideal_bounds(tab_data_index).y(), 0, |
1431 tab_data_[tab_data_index].ideal_bounds.height()); | 1338 ideal_bounds(tab_data_index).height()); |
1432 } | 1339 } |
1433 | 1340 |
1434 AnimateToIdealBounds(); | 1341 AnimateToIdealBounds(); |
1435 } | 1342 } |
1436 | 1343 |
1437 void TabStrip::StartRemoveTabAnimation(int model_index) { | 1344 void TabStrip::StartRemoveTabAnimation(int model_index) { |
1438 ResetAnimationState(true); | 1345 ResetAnimationState(true); |
1439 | 1346 |
1440 // Mark the tab as closing. | 1347 // Mark the tab as closing. |
1441 int tab_data_index = ModelIndexToTabDataIndex(model_index); | 1348 Tab* tab = GetTabAtModelIndex(model_index); |
1442 Tab* tab = tab_data_[tab_data_index].tab; | |
1443 tab->set_closing(true); | 1349 tab->set_closing(true); |
1444 | 1350 |
1445 // Start an animation for the tabs. | 1351 // Start an animation for the tabs. |
1446 GenerateIdealBounds(); | 1352 GenerateIdealBounds(); |
1447 AnimateToIdealBounds(); | 1353 AnimateToIdealBounds(); |
1448 | 1354 |
1449 // Animate the tab being closed to 0x0. | 1355 // Animate the tab being closed to 0x0. |
1450 gfx::Rect tab_bounds = tab->bounds(); | 1356 gfx::Rect tab_bounds = tab->bounds(); |
1451 tab_bounds.set_width(0); | 1357 tab_bounds.set_width(0); |
1452 bounds_animator_.AnimateViewTo(tab, tab_bounds); | 1358 bounds_animator_.AnimateViewTo(tab, tab_bounds); |
1453 | 1359 |
1454 // Register delegate to do cleanup when done, BoundsAnimator takes | 1360 // Register delegate to do cleanup when done, BoundsAnimator takes |
1455 // ownership of RemoveTabDelegate. | 1361 // ownership of RemoveTabDelegate. |
1456 bounds_animator_.SetAnimationDelegate(tab, new RemoveTabDelegate(this, tab), | 1362 bounds_animator_.SetAnimationDelegate(tab, new RemoveTabDelegate(this, tab), |
1457 true); | 1363 true); |
1458 } | 1364 } |
1459 | 1365 |
1460 void TabStrip::StartMoveTabAnimation(int from_model_index, | |
1461 int to_model_index) { | |
1462 ResetAnimationState(true); | |
1463 | |
1464 int from_tab_data_index = ModelIndexToTabDataIndex(from_model_index); | |
1465 | |
1466 Tab* tab = tab_data_[from_tab_data_index].tab; | |
1467 tab_data_.erase(tab_data_.begin() + from_tab_data_index); | |
1468 | |
1469 TabData data = {tab, gfx::Rect()}; | |
1470 | |
1471 int to_tab_data_index = ModelIndexToTabDataIndex(to_model_index); | |
1472 | |
1473 tab_data_.insert(tab_data_.begin() + to_tab_data_index, data); | |
1474 | |
1475 GenerateIdealBounds(); | |
1476 AnimateToIdealBounds(); | |
1477 } | |
1478 | |
1479 void TabStrip::StartMiniTabAnimation() { | 1366 void TabStrip::StartMiniTabAnimation() { |
1480 ResetAnimationState(true); | 1367 ResetAnimationState(true); |
1481 | 1368 |
1482 GenerateIdealBounds(); | 1369 GenerateIdealBounds(); |
1483 AnimateToIdealBounds(); | 1370 AnimateToIdealBounds(); |
1484 } | 1371 } |
1485 | 1372 |
1486 void TabStrip::StopAnimating(bool layout) { | 1373 void TabStrip::StopAnimating(bool layout) { |
1487 if (!IsAnimating()) | 1374 if (!IsAnimating()) |
1488 return; | 1375 return; |
(...skipping 19 matching lines...) Expand all Loading... |
1508 void TabStrip::ResetAnimationState(bool stop_new_tab_timer) { | 1395 void TabStrip::ResetAnimationState(bool stop_new_tab_timer) { |
1509 if (animation_type_ == ANIMATION_NEW_TAB_2) | 1396 if (animation_type_ == ANIMATION_NEW_TAB_2) |
1510 newtab_button_->SchedulePaint(); | 1397 newtab_button_->SchedulePaint(); |
1511 | 1398 |
1512 if (stop_new_tab_timer) | 1399 if (stop_new_tab_timer) |
1513 new_tab_timer_.Stop(); | 1400 new_tab_timer_.Stop(); |
1514 | 1401 |
1515 animation_type_ = ANIMATION_DEFAULT; | 1402 animation_type_ = ANIMATION_DEFAULT; |
1516 | 1403 |
1517 // Reset the animation state of each tab. | 1404 // Reset the animation state of each tab. |
1518 for (int i = 0, count = GetTabCount(); i < count; ++i) { | 1405 for (int i = 0; i < tab_count(); ++i) { |
1519 Tab* tab = GetTabAtTabDataIndex(i); | 1406 Tab* tab = GetTabAtTabDataIndex(i); |
1520 tab->set_render_as_new_tab(false); | 1407 tab->set_render_as_new_tab(false); |
1521 tab->set_render_unselected(false); | 1408 tab->set_render_unselected(false); |
1522 tab->set_alpha(1); | 1409 tab->set_alpha(1); |
1523 } | 1410 } |
1524 } | 1411 } |
1525 | 1412 |
1526 int TabStrip::GetMiniTabCount() const { | 1413 int TabStrip::GetMiniTabCount() const { |
1527 int mini_count = 0; | 1414 int mini_count = 0; |
1528 for (size_t i = 0; i < tab_data_.size(); ++i) { | 1415 for (int i = 0; i < tab_count(); ++i) { |
1529 if (tab_data_[i].tab->data().mini) | 1416 if (base_tab_at_tab_index(i)->data().mini) |
1530 mini_count++; | 1417 mini_count++; |
1531 else | 1418 else |
1532 return mini_count; | 1419 return mini_count; |
1533 } | 1420 } |
1534 return mini_count; | 1421 return mini_count; |
1535 } | 1422 } |
1536 | 1423 |
1537 int TabStrip::GetNanoTabCount() const { | 1424 int TabStrip::GetNanoTabCount() const { |
1538 int nano_count = 0; | 1425 int nano_count = 0; |
1539 for (size_t i = 0; i < tab_data_.size(); ++i) { | 1426 for (int i = 0; i < tab_count(); ++i) { |
1540 if (tab_data_[i].tab->data().app) | 1427 if (base_tab_at_tab_index(i)->data().app) |
1541 nano_count++; | 1428 nano_count++; |
1542 else | 1429 else |
1543 return nano_count; | 1430 return nano_count; |
1544 } | 1431 } |
1545 return nano_count; | 1432 return nano_count; |
1546 } | 1433 } |
1547 | 1434 |
1548 int TabStrip::GetAvailableWidthForTabs(Tab* last_tab) const { | 1435 int TabStrip::GetAvailableWidthForTabs(Tab* last_tab) const { |
1549 return last_tab->x() + last_tab->width(); | 1436 return last_tab->x() + last_tab->width(); |
1550 } | 1437 } |
1551 | 1438 |
1552 bool TabStrip::IsPointInTab(Tab* tab, | 1439 bool TabStrip::IsPointInTab(Tab* tab, |
1553 const gfx::Point& point_in_tabstrip_coords) { | 1440 const gfx::Point& point_in_tabstrip_coords) { |
1554 gfx::Point point_in_tab_coords(point_in_tabstrip_coords); | 1441 gfx::Point point_in_tab_coords(point_in_tabstrip_coords); |
1555 View::ConvertPointToView(this, tab, &point_in_tab_coords); | 1442 View::ConvertPointToView(this, tab, &point_in_tab_coords); |
1556 return tab->HitTest(point_in_tab_coords); | 1443 return tab->HitTest(point_in_tab_coords); |
1557 } | 1444 } |
1558 | 1445 |
1559 void TabStrip::RemoveTab(Tab* tab) { | |
1560 int tab_data_index = TabDataIndexOfTab(tab); | |
1561 | |
1562 DCHECK(tab_data_index != -1); | |
1563 | |
1564 // Remove the Tab from the TabStrip's list... | |
1565 tab_data_.erase(tab_data_.begin() + tab_data_index); | |
1566 | |
1567 delete tab; | |
1568 } | |
1569 | |
1570 void TabStrip::HandleGlobalMouseMoveEvent() { | 1446 void TabStrip::HandleGlobalMouseMoveEvent() { |
1571 if (!IsCursorInTabStripZone()) { | 1447 if (!IsCursorInTabStripZone()) { |
1572 // Mouse moved outside the tab slop zone, start a timer to do a resize | 1448 // Mouse moved outside the tab slop zone, start a timer to do a resize |
1573 // layout after a short while... | 1449 // layout after a short while... |
1574 if (resize_layout_factory_.empty()) { | 1450 if (resize_layout_factory_.empty()) { |
1575 MessageLoop::current()->PostDelayedTask(FROM_HERE, | 1451 MessageLoop::current()->PostDelayedTask(FROM_HERE, |
1576 resize_layout_factory_.NewRunnableMethod( | 1452 resize_layout_factory_.NewRunnableMethod( |
1577 &TabStrip::ResizeLayoutTabs), | 1453 &TabStrip::ResizeLayoutTabs), |
1578 kResizeTabsTimeMs); | 1454 kResizeTabsTimeMs); |
1579 } | 1455 } |
1580 } else { | 1456 } else { |
1581 // Mouse moved quickly out of the tab strip and then into it again, so | 1457 // Mouse moved quickly out of the tab strip and then into it again, so |
1582 // cancel the timer so that the strip doesn't move when the mouse moves | 1458 // cancel the timer so that the strip doesn't move when the mouse moves |
1583 // back over it. | 1459 // back over it. |
1584 resize_layout_factory_.RevokeAll(); | 1460 resize_layout_factory_.RevokeAll(); |
1585 } | 1461 } |
1586 } | 1462 } |
1587 | 1463 |
1588 bool TabStrip::HasPhantomTabs() const { | 1464 bool TabStrip::HasPhantomTabs() const { |
1589 for (int i = 0; i < GetTabCount(); ++i) { | 1465 for (int i = 0; i < tab_count(); ++i) { |
1590 if (GetTabAtTabDataIndex(i)->data().phantom) | 1466 if (GetTabAtTabDataIndex(i)->data().phantom) |
1591 return true; | 1467 return true; |
1592 } | 1468 } |
1593 return false; | 1469 return false; |
1594 } | 1470 } |
1595 | |
1596 int TabStrip::GetModelIndexOfTab(const Tab* tab) const { | |
1597 for (int i = 0, model_index = 0; i < GetTabCount(); ++i) { | |
1598 Tab* current_tab = GetTabAtTabDataIndex(i); | |
1599 if (!current_tab->closing()) { | |
1600 if (current_tab == tab) | |
1601 return model_index; | |
1602 model_index++; | |
1603 } | |
1604 } | |
1605 return -1; | |
1606 } | |
1607 | |
1608 int TabStrip::ModelIndexToTabDataIndex(int model_index) const { | |
1609 int current_model_index = 0; | |
1610 for (size_t i = 0; i < tab_data_.size(); ++i) { | |
1611 if (!tab_data_[i].tab->closing()) { | |
1612 if (current_model_index == model_index) | |
1613 return i; | |
1614 current_model_index++; | |
1615 } | |
1616 } | |
1617 return tab_data_.size(); | |
1618 } | |
1619 | |
1620 int TabStrip::TabDataIndexOfTab(Tab* tab) const { | |
1621 for (size_t i = 0; i < tab_data_.size(); ++i) { | |
1622 if (tab_data_[i].tab == tab) | |
1623 return i; | |
1624 } | |
1625 return -1; | |
1626 } | |
1627 | |
1628 void TabStrip::StartedDraggingTab(Tab* tab) { | |
1629 tab->set_dragging(true); | |
1630 | |
1631 // Stop any animations on the tab. | |
1632 bounds_animator_.StopAnimatingView(tab); | |
1633 | |
1634 // Move the tab to its ideal bounds. | |
1635 GenerateIdealBounds(); | |
1636 int tab_data_index = TabDataIndexOfTab(tab); | |
1637 DCHECK(tab_data_index != -1); | |
1638 tab->SetBounds(tab_data_[tab_data_index].ideal_bounds); | |
1639 SchedulePaint(); | |
1640 } | |
1641 | |
1642 void TabStrip::StoppedDraggingTab(Tab* tab) { | |
1643 int tab_data_index = TabDataIndexOfTab(tab); | |
1644 if (tab_data_index == -1) { | |
1645 // The tab was removed before the drag completed. Don't do anything. | |
1646 return; | |
1647 } | |
1648 | |
1649 // Animate the view back to its correct position. | |
1650 ResetAnimationState(true); | |
1651 GenerateIdealBounds(); | |
1652 AnimateToIdealBounds(); | |
1653 bounds_animator_.AnimateViewTo( | |
1654 tab, | |
1655 tab_data_[TabDataIndexOfTab(tab)].ideal_bounds); | |
1656 | |
1657 // Install a delegate to reset the dragging state when done. We have to leave | |
1658 // dragging true for the tab otherwise it'll draw beneath the new tab button. | |
1659 bounds_animator_.SetAnimationDelegate(tab, | |
1660 new ResetDraggingStateDelegate(tab), | |
1661 true); | |
1662 } | |
OLD | NEW |