tab.h revision 116680a4aac90f2aa7413d9095a592090648e557
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_H_
6#define CHROME_BROWSER_UI_VIEWS_TABS_TAB_H_
7
8#include <list>
9#include <string>
10
11#include "base/memory/ref_counted.h"
12#include "base/memory/scoped_ptr.h"
13#include "chrome/browser/ui/views/tabs/tab_renderer_data.h"
14#include "ui/base/layout.h"
15#include "ui/gfx/animation/animation_delegate.h"
16#include "ui/gfx/point.h"
17#include "ui/views/context_menu_controller.h"
18#include "ui/views/controls/button/button.h"
19#include "ui/views/controls/glow_hover_controller.h"
20#include "ui/views/masked_targeter_delegate.h"
21#include "ui/views/view.h"
22
23class TabController;
24
25namespace gfx {
26class Animation;
27class AnimationContainer;
28class LinearAnimation;
29class MultiAnimation;
30class ThrobAnimation;
31}
32namespace views {
33class ImageButton;
34class Label;
35}
36
37///////////////////////////////////////////////////////////////////////////////
38//
39//  A View that renders a Tab in a TabStrip.
40//
41///////////////////////////////////////////////////////////////////////////////
42class Tab : public gfx::AnimationDelegate,
43            public views::ButtonListener,
44            public views::ContextMenuController,
45            public views::MaskedTargeterDelegate,
46            public views::View {
47 public:
48  // The menu button's class name.
49  static const char kViewClassName[];
50
51  explicit Tab(TabController* controller);
52  virtual ~Tab();
53
54  // Used to set/check whether this Tab is being animated closed.
55  void set_closing(bool closing) { closing_ = closing; }
56  bool closing() const { return closing_; }
57
58  // See description above field.
59  void set_dragging(bool dragging) { dragging_ = dragging; }
60  bool dragging() const { return dragging_; }
61
62  // Used to mark the tab as having been detached.  Once this has happened, the
63  // tab should be invisibly closed.  This is irreversible.
64  void set_detached() { detached_ = true; }
65  bool detached() const { return detached_; }
66
67  // Sets the container all animations run from.
68  void set_animation_container(gfx::AnimationContainer* container);
69
70  // Returns true if this tab is the active tab.
71  bool IsActive() const;
72
73  // Returns true if the tab is selected.
74  bool IsSelected() const;
75
76  // Sets the data this tabs displays. Invokes DataChanged.
77  void SetData(const TabRendererData& data);
78  const TabRendererData& data() const { return data_; }
79
80  // Sets the network state. If the network state changes NetworkStateChanged is
81  // invoked.
82  void UpdateLoadingAnimation(TabRendererData::NetworkState state);
83
84  // Starts/Stops a pulse animation.
85  void StartPulse();
86  void StopPulse();
87
88  // Start/stop the mini-tab title animation.
89  void StartMiniTabTitleAnimation();
90  void StopMiniTabTitleAnimation();
91
92  // Set the background offset used to match the image in the inactive tab
93  // to the frame image.
94  void set_background_offset(const gfx::Point& offset) {
95    background_offset_ = offset;
96  }
97
98  // Returns true if this tab became the active tab selected in
99  // response to the last ui::ET_GESTURE_BEGIN gesture dispatched to
100  // this tab. Only used for collecting UMA metrics.
101  // See ash/touch/touch_uma.cc.
102  bool tab_activated_with_last_gesture_begin() const {
103    return tab_activated_with_last_gesture_begin_;
104  }
105
106  views::GlowHoverController* hover_controller() {
107    return &hover_controller_;
108  }
109
110  // Returns the inset within the first dragged tab to use when calculating the
111  // "drag insertion point".  If we simply used the x-coordinate of the tab,
112  // we'd be calculating based on a point well before where the user considers
113  // the tab to "be".  The value here is chosen to "feel good" based on the
114  // widths of the tab images and the tab overlap.
115  //
116  // Note that this must return a value smaller than the midpoint of any tab's
117  // width, or else the user won't be able to drag a tab to the left of the
118  // first tab in the strip.
119  static int leading_width_for_drag() { return 16; }
120
121  // Returns the minimum possible size of a single unselected Tab.
122  static gfx::Size GetMinimumUnselectedSize();
123  // Returns the minimum possible size of a selected Tab. Selected tabs must
124  // always show a close button and have a larger minimum size than unselected
125  // tabs.
126  static gfx::Size GetMinimumSelectedSize();
127  // Returns the preferred size of a single Tab, assuming space is
128  // available.
129  static gfx::Size GetStandardSize();
130
131  // Returns the width for touch tabs.
132  static int GetTouchWidth();
133
134  // Returns the width for mini-tabs. Mini-tabs always have this width.
135  static int GetMiniWidth();
136
137  // Returns the height for immersive mode tabs.
138  static int GetImmersiveHeight();
139
140 private:
141  friend class TabTest;
142  FRIEND_TEST_ALL_PREFIXES(TabTest, CloseButtonLayout);
143
144  friend class TabStripTest;
145  FRIEND_TEST_ALL_PREFIXES(TabStripTest, TabHitTestMaskWhenStacked);
146  FRIEND_TEST_ALL_PREFIXES(TabStripTest, ClippedTabCloseButton);
147
148  // The animation object used to swap the favicon with the sad tab icon.
149  class FaviconCrashAnimation;
150  class TabCloseButton;
151
152  // Contains a cached image and the values used to generate it.
153  struct ImageCacheEntry {
154    ImageCacheEntry();
155    ~ImageCacheEntry();
156
157    // ID of the resource used.
158    int resource_id;
159
160    // Scale factor we're drawing it.
161    ui::ScaleFactor scale_factor;
162
163    // The image.
164    gfx::ImageSkia image;
165  };
166
167  typedef std::list<ImageCacheEntry> ImageCache;
168
169  // gfx::AnimationDelegate:
170  virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE;
171  virtual void AnimationCanceled(const gfx::Animation* animation) OVERRIDE;
172  virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE;
173
174  // views::ButtonListener:
175  virtual void ButtonPressed(views::Button* sender,
176                             const ui::Event& event) OVERRIDE;
177
178  // views::ContextMenuController:
179  virtual void ShowContextMenuForView(views::View* source,
180                                      const gfx::Point& point,
181                                      ui::MenuSourceType source_type) OVERRIDE;
182
183  // views::MaskedTargeterDelegate:
184  virtual bool GetHitTestMask(gfx::Path* mask) const OVERRIDE;
185
186  // views::View:
187  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
188  virtual void Layout() OVERRIDE;
189  virtual void OnThemeChanged() OVERRIDE;
190  virtual const char* GetClassName() const OVERRIDE;
191  virtual bool GetTooltipText(const gfx::Point& p,
192                              base::string16* tooltip) const OVERRIDE;
193  virtual bool GetTooltipTextOrigin(const gfx::Point& p,
194                                    gfx::Point* origin) const OVERRIDE;
195  virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
196  virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
197  virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
198  virtual void OnMouseCaptureLost() OVERRIDE;
199  virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE;
200  virtual void OnMouseMoved(const ui::MouseEvent& event) OVERRIDE;
201  virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE;
202  virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
203
204  // ui::EventHandler:
205  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
206
207  // Invoked from Layout to adjust the position of the favicon or media
208  // indicator for mini tabs.
209  void MaybeAdjustLeftForMiniTab(gfx::Rect* bounds) const;
210
211  // Invoked from SetData after |data_| has been updated to the new data.
212  void DataChanged(const TabRendererData& old);
213
214  // Paint with the normal tab style.
215  void PaintTab(gfx::Canvas* canvas);
216
217  // Paint with the "immersive mode" light-bar style.
218  void PaintImmersiveTab(gfx::Canvas* canvas);
219
220  // Paint various portions of the Tab
221  void PaintTabBackground(gfx::Canvas* canvas);
222  void PaintInactiveTabBackgroundWithTitleChange(gfx::Canvas* canvas);
223  void PaintInactiveTabBackground(gfx::Canvas* canvas);
224  void PaintInactiveTabBackgroundUsingResourceId(gfx::Canvas* canvas,
225                                                 int tab_id);
226  void PaintActiveTabBackground(gfx::Canvas* canvas);
227
228  // Paints the favicon and media indicator icon, mirrored for RTL if needed.
229  void PaintIcon(gfx::Canvas* canvas);
230  void PaintMediaIndicator(gfx::Canvas* canvas);
231
232  // Invoked if data_.network_state changes, or the network_state is not none.
233  void AdvanceLoadingAnimation(TabRendererData::NetworkState old_state,
234                               TabRendererData::NetworkState state);
235
236  // Returns the number of favicon-size elements that can fit in the tab's
237  // current size.
238  int IconCapacity() const;
239
240  // Returns whether the Tab should display a favicon.
241  bool ShouldShowIcon() const;
242
243  // Returns whether the Tab should display the media indicator.
244  bool ShouldShowMediaIndicator() const;
245
246  // Returns whether the Tab should display a close button.
247  bool ShouldShowCloseBox() const;
248
249  // Gets the throb value for the tab. When a tab is not selected the
250  // active background is drawn at |GetThrobValue()|%. This is used for hover,
251  // mini tab title change and pulsing.
252  double GetThrobValue();
253
254  // Set the temporary offset for the favicon. This is used during the crash
255  // animation.
256  void SetFaviconHidingOffset(int offset);
257
258  void DisplayCrashedFavicon();
259  void ResetCrashedFavicon();
260
261  void StopCrashAnimation();
262  void StartCrashAnimation();
263
264  // Returns true if the crash animation is currently running.
265  bool IsPerformingCrashAnimation() const;
266
267  // Starts the media indicator fade-in/out animation. There's no stop method
268  // because this is not a continuous animation.
269  void StartMediaIndicatorAnimation();
270
271  // Schedules repaint task for icon.
272  void ScheduleIconPaint();
273
274  // Returns the rectangle for the light bar in immersive mode.
275  gfx::Rect GetImmersiveBarRect() const;
276
277  // Gets the tab id and frame id.
278  void GetTabIdAndFrameId(views::Widget* widget,
279                          int* tab_id,
280                          int* frame_id) const;
281
282  // Performs a one-time initialization of static resources such as tab images.
283  static void InitTabResources();
284
285  // Returns the minimum possible size of a single unselected Tab, not
286  // including considering touch mode.
287  static gfx::Size GetBasicMinimumUnselectedSize();
288
289  // Loads the images to be used for the tab background.
290  static void LoadTabImages();
291
292  // Returns the cached image for the specified arguments, or an empty image if
293  // there isn't one cached.
294  static gfx::ImageSkia GetCachedImage(int resource_id,
295                                       const gfx::Size& size,
296                                       ui::ScaleFactor scale_factor);
297
298  // Caches the specified image.
299  static void SetCachedImage(int resource_id,
300                             ui::ScaleFactor scale_factor,
301                             const gfx::ImageSkia& image);
302
303  // The controller, never NULL.
304  TabController* controller_;
305
306  TabRendererData data_;
307
308  // True if the tab is being animated closed.
309  bool closing_;
310
311  // True if the tab is being dragged.
312  bool dragging_;
313
314  // True if the tab has been detached.
315  bool detached_;
316
317  // The offset used to animate the favicon location. This is used when the tab
318  // crashes.
319  int favicon_hiding_offset_;
320
321  // The current index of the loading animation. The range varies depending on
322  // whether the tab is loading or waiting, see AdvanceLoadingAnimation().
323  int loading_animation_frame_;
324
325  // Step in the immersive loading progress indicator.
326  int immersive_loading_step_;
327
328  bool should_display_crashed_favicon_;
329
330  // Whole-tab throbbing "pulse" animation.
331  scoped_ptr<gfx::ThrobAnimation> pulse_animation_;
332
333  scoped_ptr<gfx::MultiAnimation> mini_title_change_animation_;
334
335  // Crash icon animation (in place of favicon).
336  scoped_ptr<gfx::LinearAnimation> crash_icon_animation_;
337
338  // Media indicator fade-in/out animation (i.e., only on show/hide, not a
339  // continuous animation).
340  scoped_ptr<gfx::Animation> media_indicator_animation_;
341  TabMediaState animating_media_state_;
342
343  scoped_refptr<gfx::AnimationContainer> animation_container_;
344
345  views::ImageButton* close_button_;
346  views::Label* title_;
347
348  bool tab_activated_with_last_gesture_begin_;
349
350  views::GlowHoverController hover_controller_;
351
352  // The bounds of various sections of the display.
353  gfx::Rect favicon_bounds_;
354  gfx::Rect media_indicator_bounds_;
355
356  // The offset used to paint the inactive background image.
357  gfx::Point background_offset_;
358
359  struct TabImage {
360    gfx::ImageSkia* image_l;
361    gfx::ImageSkia* image_c;
362    gfx::ImageSkia* image_r;
363    int l_width;
364    int r_width;
365  };
366  static TabImage tab_active_;
367  static TabImage tab_inactive_;
368  static TabImage tab_alpha_;
369
370  // Whether we're showing the icon. It is cached so that we can detect when it
371  // changes and layout appropriately.
372  bool showing_icon_;
373
374  // Whether we're showing the media indicator. It is cached so that we can
375  // detect when it changes and layout appropriately.
376  bool showing_media_indicator_;
377
378  // Whether we are showing the close button. It is cached so that we can
379  // detect when it changes and layout appropriately.
380  bool showing_close_button_;
381
382  // The current color of the close button.
383  SkColor close_button_color_;
384
385  // As the majority of the tabs are inactive, and painting tabs is slowish,
386  // we cache a handful of the inactive tab backgrounds here.
387  static ImageCache* image_cache_;
388
389  DISALLOW_COPY_AND_ASSIGN(Tab);
390};
391
392#endif  // CHROME_BROWSER_UI_VIEWS_TABS_TAB_H_
393