| 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 |