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