1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_H_ 6 #define CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_H_ 7 8 #include <vector> 9 10 #include "base/compiler_specific.h" 11 #include "base/memory/ref_counted.h" 12 #include "base/timer/timer.h" 13 #include "chrome/browser/ui/views/tabs/tab.h" 14 #include "chrome/browser/ui/views/tabs/tab_controller.h" 15 #include "ui/gfx/animation/animation_container.h" 16 #include "ui/gfx/point.h" 17 #include "ui/gfx/rect.h" 18 #include "ui/views/animation/bounds_animator.h" 19 #include "ui/views/controls/button/image_button.h" 20 #include "ui/views/mouse_watcher.h" 21 #include "ui/views/view.h" 22 #include "ui/views/view_model.h" 23 24 class NewTabButton; 25 class StackedTabStripLayout; 26 class Tab; 27 class TabDragController; 28 class TabStripController; 29 class TabStripObserver; 30 31 namespace ui { 32 class ListSelectionModel; 33 } 34 35 namespace views { 36 class ImageView; 37 } 38 39 /////////////////////////////////////////////////////////////////////////////// 40 // 41 // TabStrip 42 // 43 // A View that represents the TabStripModel. The TabStrip has the 44 // following responsibilities: 45 // - It implements the TabStripModelObserver interface, and acts as a 46 // container for Tabs, and is also responsible for creating them. 47 // - It takes part in Tab Drag & Drop with Tab, TabDragHelper and 48 // DraggedTab, focusing on tasks that require reshuffling other tabs 49 // in response to dragged tabs. 50 // 51 /////////////////////////////////////////////////////////////////////////////// 52 class TabStrip : public views::View, 53 public views::ButtonListener, 54 public views::MouseWatcherListener, 55 public TabController { 56 public: 57 static const char kViewClassName[]; 58 59 // Horizontal offset for the new tab button to bring it closer to the 60 // rightmost tab. 61 static const int kNewTabButtonHorizontalOffset; 62 63 // The vertical offset of the tab strip button. This offset applies only to 64 // restored windows. 65 static const int kNewTabButtonVerticalOffset; 66 67 explicit TabStrip(TabStripController* controller); 68 virtual ~TabStrip(); 69 70 // Add and remove observers to changes within this TabStrip. 71 void AddObserver(TabStripObserver* observer); 72 void RemoveObserver(TabStripObserver* observer); 73 74 // If |adjust_layout| is true the stacked layout changes based on whether the 75 // user uses a mouse or a touch device with the tabstrip. 76 void set_adjust_layout(bool adjust_layout) { adjust_layout_ = adjust_layout; } 77 78 // |stacked_layout_| defines what should happen when the tabs won't fit at 79 // their ideal size. When |stacked_layout_| is true the tabs are always sized 80 // to their ideal size and stacked on top of each other so that only a certain 81 // set of tabs are visible. This is used when the user uses a touch device. 82 // When |stacked_layout_| is false the tabs shrink to accommodate the 83 // available space. This is the default. 84 bool stacked_layout() const { return stacked_layout_; } 85 86 // Sets |stacked_layout_| and animates if necessary. 87 void SetStackedLayout(bool stacked_layout); 88 89 // Returns the bounds of the new tab button. 90 gfx::Rect GetNewTabButtonBounds(); 91 92 // Returns true if the new tab button should be sized to the top of the tab 93 // strip. 94 bool SizeTabButtonToTopOfTabStrip(); 95 96 // Starts highlighting the tab at the specified index. 97 void StartHighlight(int model_index); 98 99 // Stops all tab higlighting. 100 void StopAllHighlighting(); 101 102 // Adds a tab at the specified index. 103 void AddTabAt(int model_index, const TabRendererData& data, bool is_active); 104 105 // Moves a tab. 106 void MoveTab(int from_model_index, 107 int to_model_index, 108 const TabRendererData& data); 109 110 // Removes a tab at the specified index. 111 void RemoveTabAt(int model_index); 112 113 // Sets the tab data at the specified model index. 114 void SetTabData(int model_index, const TabRendererData& data); 115 116 // Returns true if the tab is not partly or fully clipped (due to overflow), 117 // and the tab couldn't become partly clipped due to changing the selected tab 118 // (for example, if currently the strip has the last tab selected, and 119 // changing that to the first tab would cause |tab| to be pushed over enough 120 // to clip). 121 bool ShouldTabBeVisible(const Tab* tab) const; 122 123 // Invoked from the controller when the close initiates from the TabController 124 // (the user clicked the tab close button or middle clicked the tab). This is 125 // invoked from Close. Because of unload handlers Close is not always 126 // immediately followed by RemoveTabAt. 127 void PrepareForCloseAt(int model_index, CloseTabSource source); 128 129 // Invoked when the selection changes from |old_selection| to 130 // |new_selection|. 131 void SetSelection(const ui::ListSelectionModel& old_selection, 132 const ui::ListSelectionModel& new_selection); 133 134 // Invoked when the title of a tab changes and the tab isn't loading. 135 void TabTitleChangedNotLoading(int model_index); 136 137 // Retrieves the ideal bounds for the Tab at the specified index. 138 const gfx::Rect& ideal_bounds(int tab_data_index) { 139 return tabs_.ideal_bounds(tab_data_index); 140 } 141 142 // Returns the Tab at |index|. 143 Tab* tab_at(int index) const { 144 return static_cast<Tab*>(tabs_.view_at(index)); 145 } 146 147 // Returns the index of the specified tab in the model coordinate system, or 148 // -1 if tab is closing or not valid. 149 int GetModelIndexOfTab(const Tab* tab) const; 150 151 // Gets the number of Tabs in the tab strip. 152 int tab_count() const { return tabs_.view_size(); } 153 154 // Cover method for TabStripController::GetCount. 155 int GetModelCount() const; 156 157 // Cover method for TabStripController::IsValidIndex. 158 bool IsValidModelIndex(int model_index) const; 159 160 TabStripController* controller() const { return controller_.get(); } 161 162 // Returns true if a drag session is currently active. 163 bool IsDragSessionActive() const; 164 165 // Returns true if a tab is being dragged into this tab strip. 166 bool IsActiveDropTarget() const; 167 168 // Returns true if the tab strip is editable. Returns false if the tab strip 169 // is being dragged or animated to prevent extensions from messing things up 170 // while that's happening. 171 bool IsTabStripEditable() const; 172 173 // Returns false when there is a drag operation in progress so that the frame 174 // doesn't close. 175 bool IsTabStripCloseable() const; 176 177 // Updates the loading animations displayed by tabs in the tabstrip to the 178 // next frame. 179 void UpdateLoadingAnimations(); 180 181 // Returns true if the specified point (in TabStrip coordinates) is in the 182 // window caption area of the browser window. 183 bool IsPositionInWindowCaption(const gfx::Point& point); 184 185 // Returns true if the specified rect (in TabStrip coordinates) intersects 186 // the window caption area of the browser window. 187 bool IsRectInWindowCaption(const gfx::Rect& rect); 188 189 // Set the background offset used by inactive tabs to match the frame image. 190 void SetBackgroundOffset(const gfx::Point& offset); 191 192 // Sets a painting style with miniature "tab indicator" rectangles at the top. 193 void SetImmersiveStyle(bool enable); 194 195 // Returns true if Tabs in this TabStrip are currently changing size or 196 // position. 197 bool IsAnimating() const; 198 199 // Stops any ongoing animations. If |layout| is true and an animation is 200 // ongoing this does a layout. 201 void StopAnimating(bool layout); 202 203 // Called to indicate whether the given URL is a supported file. 204 void FileSupported(const GURL& url, bool supported); 205 206 // TabController overrides: 207 virtual const ui::ListSelectionModel& GetSelectionModel() OVERRIDE; 208 virtual bool SupportsMultipleSelection() OVERRIDE; 209 virtual void SelectTab(Tab* tab) OVERRIDE; 210 virtual void ExtendSelectionTo(Tab* tab) OVERRIDE; 211 virtual void ToggleSelected(Tab* tab) OVERRIDE; 212 virtual void AddSelectionFromAnchorTo(Tab* tab) OVERRIDE; 213 virtual void CloseTab(Tab* tab, CloseTabSource source) OVERRIDE; 214 virtual void ShowContextMenuForTab(Tab* tab, 215 const gfx::Point& p, 216 ui::MenuSourceType source_type) OVERRIDE; 217 virtual bool IsActiveTab(const Tab* tab) const OVERRIDE; 218 virtual bool IsTabSelected(const Tab* tab) const OVERRIDE; 219 virtual bool IsTabPinned(const Tab* tab) const OVERRIDE; 220 virtual void MaybeStartDrag( 221 Tab* tab, 222 const ui::LocatedEvent& event, 223 const ui::ListSelectionModel& original_selection) OVERRIDE; 224 virtual void ContinueDrag(views::View* view, 225 const ui::LocatedEvent& event) OVERRIDE; 226 virtual bool EndDrag(EndDragReason reason) OVERRIDE; 227 virtual Tab* GetTabAt(Tab* tab, 228 const gfx::Point& tab_in_tab_coordinates) OVERRIDE; 229 virtual void OnMouseEventInTab(views::View* source, 230 const ui::MouseEvent& event) OVERRIDE; 231 virtual bool ShouldPaintTab(const Tab* tab, gfx::Rect* clip) OVERRIDE; 232 virtual bool IsImmersiveStyle() const OVERRIDE; 233 234 // MouseWatcherListener overrides: 235 virtual void MouseMovedOutOfHost() OVERRIDE; 236 237 // views::View overrides: 238 virtual void Layout() OVERRIDE; 239 virtual void PaintChildren(gfx::Canvas* canvas, 240 const views::CullSet& cull_set) OVERRIDE; 241 virtual const char* GetClassName() const OVERRIDE; 242 virtual gfx::Size GetPreferredSize() const OVERRIDE; 243 // NOTE: the drag and drop methods are invoked from FrameView. This is done 244 // to allow for a drop region that extends outside the bounds of the TabStrip. 245 virtual void OnDragEntered(const ui::DropTargetEvent& event) OVERRIDE; 246 virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE; 247 virtual void OnDragExited() OVERRIDE; 248 virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE; 249 virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE; 250 virtual views::View* GetEventHandlerForRect(const gfx::Rect& rect) OVERRIDE; 251 virtual views::View* GetTooltipHandlerForPoint( 252 const gfx::Point& point) OVERRIDE; 253 254 // Returns preferred height in immersive style. 255 static int GetImmersiveHeight(); 256 257 private: 258 typedef std::vector<Tab*> Tabs; 259 typedef std::map<int, Tabs> TabsClosingMap; 260 typedef std::pair<TabsClosingMap::iterator, 261 Tabs::iterator> FindClosingTabResult; 262 263 class RemoveTabDelegate; 264 265 friend class TabDragController; 266 friend class TabDragControllerTest; 267 FRIEND_TEST_ALL_PREFIXES(TabDragControllerTest, GestureEndShouldEndDragTest); 268 friend class TabStripTest; 269 FRIEND_TEST_ALL_PREFIXES(TabStripTest, TabHitTestMaskWhenStacked); 270 FRIEND_TEST_ALL_PREFIXES(TabStripTest, ClippedTabCloseButton); 271 272 // Used during a drop session of a url. Tracks the position of the drop as 273 // well as a window used to highlight where the drop occurs. 274 struct DropInfo { 275 DropInfo(int drop_index, 276 bool drop_before, 277 bool point_down, 278 views::Widget* context); 279 ~DropInfo(); 280 281 // Index of the tab to drop on. If drop_before is true, the drop should 282 // occur between the tab at drop_index - 1 and drop_index. 283 // WARNING: if drop_before is true it is possible this will == tab_count, 284 // which indicates the drop should create a new tab at the end of the tabs. 285 int drop_index; 286 bool drop_before; 287 288 // Direction the arrow should point in. If true, the arrow is displayed 289 // above the tab and points down. If false, the arrow is displayed beneath 290 // the tab and points up. 291 bool point_down; 292 293 // Renders the drop indicator. 294 views::Widget* arrow_window; 295 views::ImageView* arrow_view; 296 297 // The URL for the drop event. 298 GURL url; 299 300 // Whether the MIME type of the file pointed to by |url| is supported. 301 bool file_supported; 302 303 private: 304 DISALLOW_COPY_AND_ASSIGN(DropInfo); 305 }; 306 307 // Horizontal gap between mini and non-mini-tabs. 308 static const int kMiniToNonMiniGap; 309 310 // The size of the new tab button must be hardcoded because we need to be 311 // able to lay it out before we are able to get its image from the 312 // ui::ThemeProvider. It also makes sense to do this, because the size of the 313 // new tab button should not need to be calculated dynamically. 314 static const int kNewTabButtonAssetWidth; 315 static const int kNewTabButtonAssetHeight; 316 317 void Init(); 318 319 // Creates and returns a new tab. The caller owners the returned tab. 320 Tab* CreateTab(); 321 322 // Invoked from |AddTabAt| after the newly created tab has been inserted. 323 void StartInsertTabAnimation(int model_index); 324 325 // Invoked from |MoveTab| after |tab_data_| has been updated to animate the 326 // move. 327 void StartMoveTabAnimation(); 328 329 // Starts the remove tab animation. 330 void StartRemoveTabAnimation(int model_index); 331 332 // Schedules the animations and bounds changes necessary for a remove tab 333 // animation. 334 void ScheduleRemoveTabAnimation(Tab* tab); 335 336 // Animates all the views to their ideal bounds. 337 // NOTE: this does *not* invoke GenerateIdealBounds, it uses the bounds 338 // currently set in ideal_bounds. 339 void AnimateToIdealBounds(); 340 341 // Returns whether the highlight button should be highlighted after a remove. 342 bool ShouldHighlightCloseButtonAfterRemove(); 343 344 // Invoked from Layout if the size changes or layout is really needed. 345 void DoLayout(); 346 347 // Sets the visibility state of all tabs based on ShouldTabBeVisible(). 348 void SetTabVisibility(); 349 350 // Drags the active tab by |delta|. |initial_positions| is the x-coordinates 351 // of the tabs when the drag started. 352 void DragActiveTab(const std::vector<int>& initial_positions, int delta); 353 354 // Sets the ideal bounds x-coordinates to |positions|. 355 void SetIdealBoundsFromPositions(const std::vector<int>& positions); 356 357 // Stacks the dragged tabs. This is used if the drag operation is 358 // MOVE_VISIBLE_TABS and the tabs don't fill the tabstrip. When this happens 359 // the active tab follows the mouse and the other tabs stack around it. 360 void StackDraggedTabs(int delta); 361 362 // Returns true if dragging has resulted in temporarily stacking the tabs. 363 bool IsStackingDraggedTabs() const; 364 365 // Invoked during drag to layout the tabs being dragged in |tabs| at 366 // |location|. If |initial_drag| is true, this is the initial layout after the 367 // user moved the mouse far enough to trigger a drag. 368 void LayoutDraggedTabsAt(const Tabs& tabs, 369 Tab* active_tab, 370 const gfx::Point& location, 371 bool initial_drag); 372 373 // Calculates the bounds needed for each of the tabs, placing the result in 374 // |bounds|. 375 void CalculateBoundsForDraggedTabs(const Tabs& tabs, 376 std::vector<gfx::Rect>* bounds); 377 378 // Returns the size needed for the specified tabs. This is invoked during drag 379 // and drop to calculate offsets and positioning. 380 int GetSizeNeededForTabs(const Tabs& tabs); 381 382 // Returns the number of mini-tabs. 383 int GetMiniTabCount() const; 384 385 // Returns the last tab in the strip that's actually visible. This will be 386 // the actual last tab unless the strip is in the overflow state. 387 const Tab* GetLastVisibleTab() const; 388 389 // Adds the tab at |index| to |tabs_closing_map_| and removes the tab from 390 // |tabs_|. 391 void RemoveTabFromViewModel(int index); 392 393 // Cleans up the Tab from the TabStrip. This is called from the tab animation 394 // code and is not a general-purpose method. 395 void RemoveAndDeleteTab(Tab* tab); 396 397 // Adjusts the indices of all tabs in |tabs_closing_map_| whose index is 398 // >= |index| to have a new index of |index + delta|. 399 void UpdateTabsClosingMap(int index, int delta); 400 401 // Used by TabDragController when the user starts or stops dragging tabs. 402 void StartedDraggingTabs(const Tabs& tabs); 403 404 // Invoked when TabDragController detaches a set of tabs. 405 void DraggedTabsDetached(); 406 407 // Used by TabDragController when the user stops dragging tabs. |move_only| is 408 // true if the move behavior is TabDragController::MOVE_VISIBILE_TABS. 409 // |completed| is true if the drag operation completed successfully, false if 410 // it was reverted. 411 void StoppedDraggingTabs(const Tabs& tabs, 412 const std::vector<int>& initial_positions, 413 bool move_only, 414 bool completed); 415 416 // Invoked from StoppedDraggingTabs to cleanup |tab|. If |tab| is known 417 // |is_first_tab| is set to true. 418 void StoppedDraggingTab(Tab* tab, bool* is_first_tab); 419 420 // Takes ownership of |controller|. 421 void OwnDragController(TabDragController* controller); 422 423 // Destroys the current TabDragController. This cancel the existing drag 424 // operation. 425 void DestroyDragController(); 426 427 // Releases ownership of the current TabDragController. 428 TabDragController* ReleaseDragController(); 429 430 // Finds |tab| in the |tab_closing_map_| and returns a pair of iterators 431 // indicating precisely where it is. 432 FindClosingTabResult FindClosingTab(const Tab* tab); 433 434 // Paints all the tabs in |tabs_closing_map_[index]|. 435 void PaintClosingTabs(gfx::Canvas* canvas, 436 int index, 437 const views::CullSet& cull_set); 438 439 // Invoked when a mouse event occurs over |source|. Potentially switches the 440 // |stacked_layout_|. 441 void UpdateStackedLayoutFromMouseEvent(views::View* source, 442 const ui::MouseEvent& event); 443 444 // -- Tab Resize Layout ----------------------------------------------------- 445 446 // Returns the exact (unrounded) current width of each tab. 447 void GetCurrentTabWidths(double* unselected_width, 448 double* selected_width) const; 449 450 // Returns the exact (unrounded) desired width of each tab, based on the 451 // desired strip width and number of tabs. If 452 // |width_of_tabs_for_mouse_close_| is nonnegative we use that value in 453 // calculating the desired strip width; otherwise we use the current width. 454 // |mini_tab_count| gives the number of mini-tabs and |tab_count| the number 455 // of mini and non-mini-tabs. 456 void GetDesiredTabWidths(int tab_count, 457 int mini_tab_count, 458 double* unselected_width, 459 double* selected_width) const; 460 461 // Perform an animated resize-relayout of the TabStrip immediately. 462 void ResizeLayoutTabs(); 463 464 // Invokes ResizeLayoutTabs() as long as we're not in a drag session. If we 465 // are in a drag session this restarts the timer. 466 void ResizeLayoutTabsFromTouch(); 467 468 // Restarts |resize_layout_timer_|. 469 void StartResizeLayoutTabsFromTouchTimer(); 470 471 // Sets the bounds of the tabs to |tab_bounds|. 472 void SetTabBoundsForDrag(const std::vector<gfx::Rect>& tab_bounds); 473 474 // Ensure that the message loop observer used for event spying is added and 475 // removed appropriately so we can tell when to resize layout the tab strip. 476 void AddMessageLoopObserver(); 477 void RemoveMessageLoopObserver(); 478 479 // -- Link Drag & Drop ------------------------------------------------------ 480 481 // Returns the bounds to render the drop at, in screen coordinates. Sets 482 // |is_beneath| to indicate whether the arrow is beneath the tab, or above 483 // it. 484 gfx::Rect GetDropBounds(int drop_index, bool drop_before, bool* is_beneath); 485 486 // Updates the location of the drop based on the event. 487 void UpdateDropIndex(const ui::DropTargetEvent& event); 488 489 // Sets the location of the drop, repainting as necessary. 490 void SetDropIndex(int tab_data_index, bool drop_before); 491 492 // Returns the drop effect for dropping a URL on the tab strip. This does 493 // not query the data in anyway, it only looks at the source operations. 494 int GetDropEffect(const ui::DropTargetEvent& event); 495 496 // Returns the image to use for indicating a drop on a tab. If is_down is 497 // true, this returns an arrow pointing down. 498 static gfx::ImageSkia* GetDropArrowImage(bool is_down); 499 500 // -- Animations ------------------------------------------------------------ 501 502 // Invoked prior to starting a new animation. 503 void PrepareForAnimation(); 504 505 // Generates the ideal bounds for each of the tabs as well as the new tab 506 // button. 507 void GenerateIdealBounds(); 508 509 // Generates the ideal bounds for the mini tabs. Returns the index to position 510 // the first non-mini tab and sets |first_non_mini_index| to the index of the 511 // first non-mini tab. 512 int GenerateIdealBoundsForMiniTabs(int* first_non_mini_index); 513 514 // Returns the width needed for the new tab button (and padding). 515 static int new_tab_button_width() { 516 return kNewTabButtonAssetWidth + kNewTabButtonHorizontalOffset; 517 } 518 519 // Returns the width of the area that contains tabs. This does not include 520 // the width of the new tab button. 521 int tab_area_width() const { return width() - new_tab_button_width(); } 522 523 // Starts various types of TabStrip animations. 524 void StartResizeLayoutAnimation(); 525 void StartMiniTabAnimation(); 526 void StartMouseInitiatedRemoveTabAnimation(int model_index); 527 528 // Returns true if the specified point in TabStrip coords is within the 529 // hit-test region of the specified Tab. 530 bool IsPointInTab(Tab* tab, const gfx::Point& point_in_tabstrip_coords); 531 532 // -- Touch Layout ---------------------------------------------------------- 533 534 // Returns the position normal tabs start at. 535 int GetStartXForNormalTabs() const; 536 537 // Returns the tab to use for event handling. This uses FindTabForEventFrom() 538 // to do the actual searching. 539 Tab* FindTabForEvent(const gfx::Point& point); 540 541 // Returns the tab to use for event handling starting at index |start| and 542 // iterating by |delta|. 543 Tab* FindTabForEventFrom(const gfx::Point& point, int start, int delta); 544 545 // For a given point, finds a tab that is hit by the point. If the point hits 546 // an area on which two tabs are overlapping, the tab is selected as follows: 547 // - If one of the tabs is active, select it. 548 // - Select the left one. 549 // If no tabs are hit, returns NULL. 550 views::View* FindTabHitByPoint(const gfx::Point& point); 551 552 // Returns the x-coordinates of the tabs. 553 std::vector<int> GetTabXCoordinates(); 554 555 // Creates/Destroys |touch_layout_| as necessary. 556 void SwapLayoutIfNecessary(); 557 558 // Returns true if |touch_layout_| is needed. 559 bool NeedsTouchLayout() const; 560 561 // Sets the value of |reset_to_shrink_on_exit_|. If true |mouse_watcher_| is 562 // used to track when the mouse truly exits the tabstrip and the stacked 563 // layout is reset. 564 void SetResetToShrinkOnExit(bool value); 565 566 // views::ButtonListener implementation: 567 virtual void ButtonPressed(views::Button* sender, 568 const ui::Event& event) OVERRIDE; 569 570 // View overrides. 571 virtual const views::View* GetViewByID(int id) const OVERRIDE; 572 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE; 573 virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE; 574 virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE; 575 virtual void OnMouseCaptureLost() OVERRIDE; 576 virtual void OnMouseMoved(const ui::MouseEvent& event) OVERRIDE; 577 virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE; 578 579 // ui::EventHandler overrides. 580 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE; 581 582 // -- Member Variables ------------------------------------------------------ 583 584 // There is a one-to-one mapping between each of the tabs in the 585 // TabStripController (TabStripModel) and |tabs_|. Because we animate tab 586 // removal there exists a period of time where a tab is displayed but not in 587 // the model. When this occurs the tab is removed from |tabs_| and placed in 588 // |tabs_closing_map_|. When the animation completes the tab is removed from 589 // |tabs_closing_map_|. The painting code ensures both sets of tabs are 590 // painted, and the event handling code ensures only tabs in |tabs_| are used. 591 views::ViewModel tabs_; 592 TabsClosingMap tabs_closing_map_; 593 594 scoped_ptr<TabStripController> controller_; 595 596 // The "New Tab" button. 597 NewTabButton* newtab_button_; 598 599 // Ideal bounds of the new tab button. 600 gfx::Rect newtab_button_bounds_; 601 602 // The current widths of various types of tabs. We save these so that, as 603 // users close tabs while we're holding them at the same size, we can lay out 604 // tabs exactly and eliminate the "pixel jitter" we'd get from just leaving 605 // them all at their existing, rounded widths. 606 double current_unselected_width_; 607 double current_selected_width_; 608 609 // If this value is nonnegative, it is used in GetDesiredTabWidths() to 610 // calculate how much space in the tab strip to use for tabs. Most of the 611 // time this will be -1, but while we're handling closing a tab via the mouse, 612 // we'll set this to the edge of the last tab before closing, so that if we 613 // are closing the last tab and need to resize immediately, we'll resize only 614 // back to this width, thus once again placing the last tab under the mouse 615 // cursor. 616 int available_width_for_tabs_; 617 618 // True if PrepareForCloseAt has been invoked. When true remove animations 619 // preserve current tab bounds. 620 bool in_tab_close_; 621 622 // Valid for the lifetime of a drag over us. 623 scoped_ptr<DropInfo> drop_info_; 624 625 // To ensure all tabs pulse at the same time they share the same animation 626 // container. This is that animation container. 627 scoped_refptr<gfx::AnimationContainer> animation_container_; 628 629 // MouseWatcher is used for two things: 630 // . When a tab is closed to reset the layout. 631 // . When a mouse is used and the layout dynamically adjusts and is currently 632 // stacked (|stacked_layout_| is true). 633 scoped_ptr<views::MouseWatcher> mouse_watcher_; 634 635 // The controller for a drag initiated from a Tab. Valid for the lifetime of 636 // the drag session. 637 scoped_ptr<TabDragController> drag_controller_; 638 639 views::BoundsAnimator bounds_animator_; 640 641 // Size we last layed out at. 642 gfx::Size last_layout_size_; 643 644 // See description above stacked_layout(). 645 bool stacked_layout_; 646 647 // Should the layout dynamically adjust? 648 bool adjust_layout_; 649 650 // Only used while in touch mode. 651 scoped_ptr<StackedTabStripLayout> touch_layout_; 652 653 // If true the |stacked_layout_| is set to false when the mouse exits the 654 // tabstrip (as determined using MouseWatcher). 655 bool reset_to_shrink_on_exit_; 656 657 // Location of the mouse at the time of the last move. 658 gfx::Point last_mouse_move_location_; 659 660 // Time of the last mouse move event. 661 base::TimeTicks last_mouse_move_time_; 662 663 // Number of mouse moves. 664 int mouse_move_count_; 665 666 // Timer used when a tab is closed and we need to relayout. Only used when a 667 // tab close comes from a touch device. 668 base::OneShotTimer<TabStrip> resize_layout_timer_; 669 670 // True if tabs are painted as rectangular light-bars. 671 bool immersive_style_; 672 673 // Our observers. 674 typedef ObserverList<TabStripObserver> TabStripObservers; 675 TabStripObservers observers_; 676 677 DISALLOW_COPY_AND_ASSIGN(TabStrip); 678 }; 679 680 #endif // CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_H_ 681