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