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.
5 #ifndef CHROME_BROWSER_UI_VIEWS_TABS_TAB_H_
6 #define CHROME_BROWSER_UI_VIEWS_TABS_TAB_H_
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/geometry/point.h"
17 #include "ui/gfx/paint_throbber.h"
18 #include "ui/views/context_menu_controller.h"
19 #include "ui/views/controls/button/button.h"
20 #include "ui/views/controls/glow_hover_controller.h"
21 #include "ui/views/masked_targeter_delegate.h"
22 #include "ui/views/view.h"
24 class MediaIndicatorButton
;
29 class AnimationContainer
;
30 class LinearAnimation
;
39 ///////////////////////////////////////////////////////////////////////////////
41 // A View that renders a Tab in a TabStrip.
43 ///////////////////////////////////////////////////////////////////////////////
44 class Tab
: public gfx::AnimationDelegate
,
45 public views::ButtonListener
,
46 public views::ContextMenuController
,
47 public views::MaskedTargeterDelegate
,
50 // The Tab's class name.
51 static const char kViewClassName
[];
53 explicit Tab(TabController
* controller
);
56 TabController
* controller() const { return controller_
; }
58 // Used to set/check whether this Tab is being animated closed.
59 void set_closing(bool closing
) { closing_
= closing
; }
60 bool closing() const { return closing_
; }
62 // See description above field.
63 void set_dragging(bool dragging
) { dragging_
= dragging
; }
64 bool dragging() const { return dragging_
; }
66 // Used to mark the tab as having been detached. Once this has happened, the
67 // tab should be invisibly closed. This is irreversible.
68 void set_detached() { detached_
= true; }
69 bool detached() const { return detached_
; }
71 // Sets the container all animations run from.
72 void set_animation_container(gfx::AnimationContainer
* container
);
74 // Returns true if this tab is the active tab.
75 bool IsActive() const;
77 // Notifies the MediaIndicatorButton that the active state of this tab has
79 void ActiveStateChanged();
81 // Returns true if the tab is selected.
82 bool IsSelected() const;
84 // Sets the data this tabs displays. Invokes DataChanged. Should only be
85 // called after Tab is added to widget hierarchy.
86 void SetData(const TabRendererData
& data
);
87 const TabRendererData
& data() const { return data_
; }
89 // Sets the network state. If the network state changes NetworkStateChanged is
91 void UpdateLoadingAnimation(TabRendererData::NetworkState state
);
93 // Starts/Stops a pulse animation.
97 // Start/stop the pinned tab title animation.
98 void StartPinnedTabTitleAnimation();
99 void StopPinnedTabTitleAnimation();
101 // Set the background offset used to match the image in the inactive tab
102 // to the frame image.
103 void set_background_offset(const gfx::Point
& offset
) {
104 background_offset_
= offset
;
107 // Returns true if this tab became the active tab selected in
108 // response to the last ui::ET_TAP_DOWN gesture dispatched to
109 // this tab. Only used for collecting UMA metrics.
110 // See ash/touch/touch_uma.cc.
111 bool tab_activated_with_last_tap_down() const {
112 return tab_activated_with_last_tap_down_
;
115 views::GlowHoverController
* hover_controller() {
116 return &hover_controller_
;
119 // Returns the width of the largest part of the tab that is available for the
120 // user to click to select/activate the tab.
121 int GetWidthOfLargestSelectableRegion() const;
123 // Returns the inset within the first dragged tab to use when calculating the
124 // "drag insertion point". If we simply used the x-coordinate of the tab,
125 // we'd be calculating based on a point well before where the user considers
126 // the tab to "be". The value here is chosen to "feel good" based on the
127 // widths of the tab images and the tab overlap.
129 // Note that this must return a value smaller than the midpoint of any tab's
130 // width, or else the user won't be able to drag a tab to the left of the
131 // first tab in the strip.
132 static int leading_width_for_drag() { return 16; }
134 // Returns the minimum possible size of a single unselected Tab.
135 static gfx::Size
GetMinimumUnselectedSize();
136 // Returns the minimum possible size of a selected Tab. Selected tabs must
137 // always show a close button and have a larger minimum size than unselected
139 static gfx::Size
GetMinimumSelectedSize();
140 // Returns the preferred size of a single Tab, assuming space is
142 static gfx::Size
GetStandardSize();
144 // Returns the width for touch tabs.
145 static int GetTouchWidth();
147 // Returns the width for pinned tabs. Pinned tabs always have this width.
148 static int GetPinnedWidth();
150 // Returns the height for immersive mode tabs.
151 static int GetImmersiveHeight();
154 friend class TabTest
;
155 FRIEND_TEST_ALL_PREFIXES(TabTest
, CloseButtonLayout
);
157 friend class TabStripTest
;
158 FRIEND_TEST_ALL_PREFIXES(TabStripTest
, TabHitTestMaskWhenStacked
);
159 FRIEND_TEST_ALL_PREFIXES(TabStripTest
, TabCloseButtonVisibilityWhenStacked
);
161 // The animation object used to swap the favicon with the sad tab icon.
162 class FaviconCrashAnimation
;
163 class TabCloseButton
;
165 // Contains a cached image and the values used to generate it.
166 struct ImageCacheEntry
{
170 // ID of the resource used.
173 // Scale factor we're drawing it.
174 ui::ScaleFactor scale_factor
;
177 gfx::ImageSkia image
;
180 typedef std::list
<ImageCacheEntry
> ImageCache
;
182 // gfx::AnimationDelegate:
183 void AnimationProgressed(const gfx::Animation
* animation
) override
;
184 void AnimationCanceled(const gfx::Animation
* animation
) override
;
185 void AnimationEnded(const gfx::Animation
* animation
) override
;
187 // views::ButtonListener:
188 void ButtonPressed(views::Button
* sender
, const ui::Event
& event
) override
;
190 // views::ContextMenuController:
191 void ShowContextMenuForView(views::View
* source
,
192 const gfx::Point
& point
,
193 ui::MenuSourceType source_type
) override
;
195 // views::MaskedTargeterDelegate:
196 bool GetHitTestMask(gfx::Path
* mask
) const override
;
199 void OnPaint(gfx::Canvas
* canvas
) override
;
200 void Layout() override
;
201 void OnThemeChanged() override
;
202 const char* GetClassName() const override
;
203 bool GetTooltipText(const gfx::Point
& p
,
204 base::string16
* tooltip
) const override
;
205 bool GetTooltipTextOrigin(const gfx::Point
& p
,
206 gfx::Point
* origin
) const override
;
207 bool OnMousePressed(const ui::MouseEvent
& event
) override
;
208 bool OnMouseDragged(const ui::MouseEvent
& event
) override
;
209 void OnMouseReleased(const ui::MouseEvent
& event
) override
;
210 void OnMouseCaptureLost() override
;
211 void OnMouseEntered(const ui::MouseEvent
& event
) override
;
212 void OnMouseMoved(const ui::MouseEvent
& event
) override
;
213 void OnMouseExited(const ui::MouseEvent
& event
) override
;
214 void GetAccessibleState(ui::AXViewState
* state
) override
;
217 void OnGestureEvent(ui::GestureEvent
* event
) override
;
219 // Invoked from Layout to adjust the position of the favicon or media
220 // indicator for pinned tabs.
221 void MaybeAdjustLeftForPinnedTab(gfx::Rect
* bounds
) const;
223 // Invoked from SetData after |data_| has been updated to the new data.
224 void DataChanged(const TabRendererData
& old
);
226 // Paint with the normal tab style.
227 void PaintTab(gfx::Canvas
* canvas
);
229 // Paint with the "immersive mode" light-bar style.
230 void PaintImmersiveTab(gfx::Canvas
* canvas
);
232 // Paint various portions of the Tab
233 void PaintTabBackground(gfx::Canvas
* canvas
);
234 void PaintInactiveTabBackgroundWithTitleChange(gfx::Canvas
* canvas
);
235 void PaintInactiveTabBackground(gfx::Canvas
* canvas
);
236 void PaintInactiveTabBackgroundUsingResourceId(gfx::Canvas
* canvas
,
238 void PaintActiveTabBackground(gfx::Canvas
* canvas
);
240 // Paints the favicon, mirrored for RTL if needed.
241 void PaintIcon(gfx::Canvas
* canvas
);
243 // Invoked if data_.network_state changes, or the network_state is not none.
244 void AdvanceLoadingAnimation(TabRendererData::NetworkState old_state
,
245 TabRendererData::NetworkState state
);
247 // Returns the number of favicon-size elements that can fit in the tab's
249 int IconCapacity() const;
251 // Returns whether the Tab should display a favicon.
252 bool ShouldShowIcon() const;
254 // Returns whether the Tab should display the media indicator.
255 bool ShouldShowMediaIndicator() const;
257 // Returns whether the Tab should display a close button.
258 bool ShouldShowCloseBox() const;
260 // Gets the throb value for the tab. When a tab is not selected the
261 // active background is drawn at |GetThrobValue()|%. This is used for hover,
262 // mini tab title change and pulsing.
263 double GetThrobValue();
265 // Set the temporary offset for the favicon. This is used during the crash
267 void SetFaviconHidingOffset(int offset
);
269 void DisplayCrashedFavicon();
270 void ResetCrashedFavicon();
272 void StopCrashAnimation();
273 void StartCrashAnimation();
275 // Returns true if the crash animation is currently running.
276 bool IsPerformingCrashAnimation() const;
278 // Schedules repaint task for icon.
279 void ScheduleIconPaint();
281 // Returns the rectangle for the light bar in immersive mode.
282 gfx::Rect
GetImmersiveBarRect() const;
284 // Gets the tab id and frame id.
285 void GetTabIdAndFrameId(views::Widget
* widget
,
287 int* frame_id
) const;
289 // Returns |media_indicator_button_|, creating it on-demand.
290 MediaIndicatorButton
* GetMediaIndicatorButton();
292 // Performs a one-time initialization of static resources such as tab images.
293 static void InitTabResources();
295 // Returns the minimum possible size of a single unselected Tab, not
296 // including considering touch mode.
297 static gfx::Size
GetBasicMinimumUnselectedSize();
299 // Loads the images to be used for the tab background.
300 static void LoadTabImages();
302 // Returns the cached image for the specified arguments, or an empty image if
303 // there isn't one cached.
304 static gfx::ImageSkia
GetCachedImage(int resource_id
,
305 const gfx::Size
& size
,
306 ui::ScaleFactor scale_factor
);
308 // Caches the specified image.
309 static void SetCachedImage(int resource_id
,
310 ui::ScaleFactor scale_factor
,
311 const gfx::ImageSkia
& image
);
313 // The controller, never NULL.
314 TabController
* const controller_
;
316 TabRendererData data_
;
318 // True if the tab is being animated closed.
321 // True if the tab is being dragged.
324 // True if the tab has been detached.
327 // The offset used to animate the favicon location. This is used when the tab
329 int favicon_hiding_offset_
;
331 // The point in time when the tab icon was first painted in the waiting state.
332 base::TimeTicks waiting_start_time_
;
334 // The point in time when the tab icon was first painted in the loading state.
335 base::TimeTicks loading_start_time_
;
337 // Paint state for the throbber after the most recent waiting paint.
338 gfx::ThrobberWaitingState waiting_state_
;
340 // Step in the immersive loading progress indicator.
341 int immersive_loading_step_
;
343 bool should_display_crashed_favicon_
;
345 // Whole-tab throbbing "pulse" animation.
346 scoped_ptr
<gfx::ThrobAnimation
> pulse_animation_
;
348 scoped_ptr
<gfx::MultiAnimation
> pinned_title_change_animation_
;
350 // Crash icon animation (in place of favicon).
351 scoped_ptr
<gfx::LinearAnimation
> crash_icon_animation_
;
353 scoped_refptr
<gfx::AnimationContainer
> animation_container_
;
355 views::ImageButton
* close_button_
;
356 MediaIndicatorButton
* media_indicator_button_
; // NULL until first use.
357 views::Label
* title_
;
359 bool tab_activated_with_last_tap_down_
;
361 views::GlowHoverController hover_controller_
;
363 // The bounds of various sections of the display.
364 gfx::Rect favicon_bounds_
;
366 // The offset used to paint the inactive background image.
367 gfx::Point background_offset_
;
370 gfx::ImageSkia
* image_l
;
371 gfx::ImageSkia
* image_c
;
372 gfx::ImageSkia
* image_r
;
376 static TabImage tab_active_
;
377 static TabImage tab_inactive_
;
378 static TabImage tab_alpha_
;
380 // Whether we're showing the icon. It is cached so that we can detect when it
381 // changes and layout appropriately.
384 // Whether we're showing the media indicator. It is cached so that we can
385 // detect when it changes and layout appropriately.
386 bool showing_media_indicator_
;
388 // Whether we are showing the close button. It is cached so that we can
389 // detect when it changes and layout appropriately.
390 bool showing_close_button_
;
392 // The current color of the close button.
393 SkColor close_button_color_
;
395 // As the majority of the tabs are inactive, and painting tabs is slowish,
396 // we cache a handful of the inactive tab backgrounds here.
397 static ImageCache
* image_cache_
;
399 DISALLOW_COPY_AND_ASSIGN(Tab
);
402 #endif // CHROME_BROWSER_UI_VIEWS_TABS_TAB_H_