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