tab_strip.h revision 4a5e2dc747d50c653511c68ccb2cfbfb740bd5a7
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 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#pragma once 8 9#include "app/animation_container.h" 10#include "base/ref_counted.h" 11#include "base/timer.h" 12#include "chrome/browser/views/tabs/base_tab_strip.h" 13#include "gfx/point.h" 14#include "gfx/rect.h" 15#include "views/controls/button/image_button.h" 16#include "views/mouse_watcher.h" 17 18class Tab; 19 20namespace views { 21class ImageView; 22#if defined(OS_LINUX) 23class WidgetGtk; 24#elif defined(OS_WIN) 25class WidgetWin; 26#endif 27} 28 29/////////////////////////////////////////////////////////////////////////////// 30// 31// TabStrip 32// 33// A View that represents the TabStripModel. The TabStrip has the 34// following responsibilities: 35// - It implements the TabStripModelObserver interface, and acts as a 36// container for Tabs, and is also responsible for creating them. 37// - It takes part in Tab Drag & Drop with Tab, TabDragHelper and 38// DraggedTab, focusing on tasks that require reshuffling other tabs 39// in response to dragged tabs. 40// 41/////////////////////////////////////////////////////////////////////////////// 42class TabStrip : public BaseTabStrip, 43 public views::ButtonListener, 44 public views::MouseWatcherListener { 45 public: 46 explicit TabStrip(TabStripController* controller); 47 virtual ~TabStrip(); 48 49 // Creates the new tab button. 50 void InitTabStripButtons(); 51 52 // Returns the bounds of the new tab button. 53 gfx::Rect GetNewTabButtonBounds(); 54 55 // MouseWatcherListener overrides: 56 virtual void MouseMovedOutOfView(); 57 58 // BaseTabStrip implementation: 59 virtual int GetPreferredHeight(); 60 virtual void SetBackgroundOffset(const gfx::Point& offset); 61 virtual bool IsPositionInWindowCaption(const gfx::Point& point); 62 virtual void SetDraggedTabBounds(int tab_index, 63 const gfx::Rect& tab_bounds); 64 virtual TabStrip* AsTabStrip(); 65 virtual void PrepareForCloseAt(int model_index); 66 virtual void RemoveTabAt(int model_index); 67 virtual void SelectTabAt(int old_model_index, int new_model_index); 68 virtual void TabTitleChangedNotLoading(int model_index); 69 virtual void StartHighlight(int model_index); 70 virtual void StopAllHighlighting(); 71 virtual BaseTab* CreateTabForDragging(); 72 73 // views::View overrides: 74 virtual void PaintChildren(gfx::Canvas* canvas); 75 virtual views::View* GetViewByID(int id) const; 76 virtual gfx::Size GetPreferredSize(); 77 // NOTE: the drag and drop methods are invoked from FrameView. This is done to 78 // allow for a drop region that extends outside the bounds of the TabStrip. 79 virtual void OnDragEntered(const views::DropTargetEvent& event); 80 virtual int OnDragUpdated(const views::DropTargetEvent& event); 81 virtual void OnDragExited(); 82 virtual int OnPerformDrop(const views::DropTargetEvent& event); 83 virtual AccessibilityTypes::Role GetAccessibleRole(); 84 virtual views::View* GetViewForPoint(const gfx::Point& point); 85 virtual void OnThemeChanged(); 86 87 protected: 88 // BaseTabStrip overrides: 89 virtual BaseTab* CreateTab(); 90 virtual void StartInsertTabAnimation(int model_index, bool foreground); 91 virtual void StartMoveTabAnimation(); 92 virtual void AnimateToIdealBounds(); 93 virtual bool ShouldHighlightCloseButtonAfterRemove(); 94 virtual void DoLayout(); 95 96 // views::View implementation: 97 virtual void ViewHierarchyChanged(bool is_add, 98 views::View* parent, 99 views::View* child); 100 101 // TabController overrides. 102 virtual bool IsTabSelected(const BaseTab* btr) const; 103 104 // views::ButtonListener implementation: 105 virtual void ButtonPressed(views::Button* sender, const views::Event& event); 106 107 // Horizontal gap between mini and non-mini-tabs. 108 static const int mini_to_non_mini_gap_; 109 110 private: 111 friend class DraggedTabController; 112 113 // Used during a drop session of a url. Tracks the position of the drop as 114 // well as a window used to highlight where the drop occurs. 115 struct DropInfo { 116 DropInfo(int index, bool drop_before, bool paint_down); 117 ~DropInfo(); 118 119 // Index of the tab to drop on. If drop_before is true, the drop should 120 // occur between the tab at drop_index - 1 and drop_index. 121 // WARNING: if drop_before is true it is possible this will == tab_count, 122 // which indicates the drop should create a new tab at the end of the tabs. 123 int drop_index; 124 bool drop_before; 125 126 // Direction the arrow should point in. If true, the arrow is displayed 127 // above the tab and points down. If false, the arrow is displayed beneath 128 // the tab and points up. 129 bool point_down; 130 131 // Renders the drop indicator. 132 // TODO(beng): should be views::Widget. 133#if defined(OS_WIN) 134 views::WidgetWin* arrow_window; 135#else 136 views::WidgetGtk* arrow_window; 137#endif 138 views::ImageView* arrow_view; 139 140 private: 141 DISALLOW_COPY_AND_ASSIGN(DropInfo); 142 }; 143 144 void Init(); 145 146 // Set the images for the new tab button. 147 void LoadNewTabButtonImage(); 148 149 // Retrieves the Tab at the specified index. Remember, the specified index 150 // is in terms of tab_data, *not* the model. 151 Tab* GetTabAtTabDataIndex(int tab_data_index) const; 152 153 // Returns the tab at the specified index. If a remove animation is on going 154 // and the index is >= the index of the tab being removed, the index is 155 // incremented. While a remove operation is on going the indices of the model 156 // do not line up with the indices of the view. This method adjusts the index 157 // accordingly. 158 // 159 // Use this instead of GetTabAtTabDataIndex if the index comes from the model. 160 Tab* GetTabAtModelIndex(int model_index) const; 161 162 // Returns the number of mini-tabs. 163 int GetMiniTabCount() const; 164 165 // -- Tab Resize Layout ----------------------------------------------------- 166 167 // Returns the exact (unrounded) current width of each tab. 168 void GetCurrentTabWidths(double* unselected_width, 169 double* selected_width) const; 170 171 // Returns the exact (unrounded) desired width of each tab, based on the 172 // desired strip width and number of tabs. If 173 // |width_of_tabs_for_mouse_close_| is nonnegative we use that value in 174 // calculating the desired strip width; otherwise we use the current width. 175 // |mini_tab_count| gives the number of mini-tabs and |tab_count| the number 176 // of mini and non-mini-tabs. 177 void GetDesiredTabWidths(int tab_count, 178 int mini_tab_count, 179 double* unselected_width, 180 double* selected_width) const; 181 182 // Perform an animated resize-relayout of the TabStrip immediately. 183 void ResizeLayoutTabs(); 184 185 // Ensure that the message loop observer used for event spying is added and 186 // removed appropriately so we can tell when to resize layout the tab strip. 187 void AddMessageLoopObserver(); 188 void RemoveMessageLoopObserver(); 189 190 // -- Link Drag & Drop ------------------------------------------------------ 191 192 // Returns the bounds to render the drop at, in screen coordinates. Sets 193 // |is_beneath| to indicate whether the arrow is beneath the tab, or above 194 // it. 195 gfx::Rect GetDropBounds(int drop_index, bool drop_before, bool* is_beneath); 196 197 // Updates the location of the drop based on the event. 198 void UpdateDropIndex(const views::DropTargetEvent& event); 199 200 // Sets the location of the drop, repainting as necessary. 201 void SetDropIndex(int tab_data_index, bool drop_before); 202 203 // Returns the drop effect for dropping a URL on the tab strip. This does 204 // not query the data in anyway, it only looks at the source operations. 205 int GetDropEffect(const views::DropTargetEvent& event); 206 207 // Returns the image to use for indicating a drop on a tab. If is_down is 208 // true, this returns an arrow pointing down. 209 static SkBitmap* GetDropArrowImage(bool is_down); 210 211 // -- Animations ------------------------------------------------------------ 212 213 // Generates the ideal bounds of the TabStrip when all Tabs have finished 214 // animating to their desired position/bounds. This is used by the standard 215 // Layout method and other callers like the DraggedTabController that need 216 // stable representations of Tab positions. 217 void GenerateIdealBounds(); 218 219 // Starts various types of TabStrip animations. 220 void StartResizeLayoutAnimation(); 221 void StartMoveTabAnimation(int from_model_index, 222 int to_model_index); 223 void StartMiniTabAnimation(); 224 void StartMouseInitiatedRemoveTabAnimation(int model_index); 225 226 // Stops any ongoing animations. If |layout| is true and an animation is 227 // ongoing this does a layout. 228 virtual void StopAnimating(bool layout); 229 230 // Calculates the available width for tabs, assuming a Tab is to be closed. 231 int GetAvailableWidthForTabs(Tab* last_tab) const; 232 233 // Returns true if the specified point in TabStrip coords is within the 234 // hit-test region of the specified Tab. 235 bool IsPointInTab(Tab* tab, const gfx::Point& point_in_tabstrip_coords); 236 237 // -- Member Variables ------------------------------------------------------ 238 239 // The "New Tab" button. 240 views::ImageButton* newtab_button_; 241 242 // Ideal bounds of the new tab button. 243 gfx::Rect newtab_button_bounds_; 244 245 // The current widths of various types of tabs. We save these so that, as 246 // users close tabs while we're holding them at the same size, we can lay out 247 // tabs exactly and eliminate the "pixel jitter" we'd get from just leaving 248 // them all at their existing, rounded widths. 249 double current_unselected_width_; 250 double current_selected_width_; 251 252 // If this value is nonnegative, it is used in GetDesiredTabWidths() to 253 // calculate how much space in the tab strip to use for tabs. Most of the 254 // time this will be -1, but while we're handling closing a tab via the mouse, 255 // we'll set this to the edge of the last tab before closing, so that if we 256 // are closing the last tab and need to resize immediately, we'll resize only 257 // back to this width, thus once again placing the last tab under the mouse 258 // cursor. 259 int available_width_for_tabs_; 260 261 // True if PrepareForCloseAt has been invoked. When true remove animations 262 // preserve current tab bounds. 263 bool in_tab_close_; 264 265 // The size of the new tab button must be hardcoded because we need to be 266 // able to lay it out before we are able to get its image from the 267 // ThemeProvider. It also makes sense to do this, because the size of the 268 // new tab button should not need to be calculated dynamically. 269 static const int kNewTabButtonWidth = 28; 270 static const int kNewTabButtonHeight = 18; 271 272 // Valid for the lifetime of a drag over us. 273 scoped_ptr<DropInfo> drop_info_; 274 275 // To ensure all tabs pulse at the same time they share the same animation 276 // container. This is that animation container. 277 scoped_refptr<AnimationContainer> animation_container_; 278 279 // Used for stage 1 of new tab animation. 280 base::OneShotTimer<TabStrip> new_tab_timer_; 281 282 scoped_ptr<views::MouseWatcher> mouse_watcher_; 283 284 DISALLOW_COPY_AND_ASSIGN(TabStrip); 285}; 286 287#endif // CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_H_ 288