| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_H_ |
| #define CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_H_ |
| #pragma once |
| |
| #include "base/memory/ref_counted.h" |
| #include "base/timer.h" |
| #include "chrome/browser/ui/views/tabs/base_tab_strip.h" |
| #include "ui/base/animation/animation_container.h" |
| #include "ui/gfx/point.h" |
| #include "ui/gfx/rect.h" |
| #include "views/controls/button/image_button.h" |
| #include "views/mouse_watcher.h" |
| |
| class Tab; |
| |
| namespace views { |
| class ImageView; |
| #if defined(OS_LINUX) |
| class WidgetGtk; |
| #elif defined(OS_WIN) |
| class WidgetWin; |
| #endif |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // TabStrip |
| // |
| // A View that represents the TabStripModel. The TabStrip has the |
| // following responsibilities: |
| // - It implements the TabStripModelObserver interface, and acts as a |
| // container for Tabs, and is also responsible for creating them. |
| // - It takes part in Tab Drag & Drop with Tab, TabDragHelper and |
| // DraggedTab, focusing on tasks that require reshuffling other tabs |
| // in response to dragged tabs. |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| class TabStrip : public BaseTabStrip, |
| public views::ButtonListener, |
| public views::MouseWatcherListener { |
| public: |
| explicit TabStrip(TabStripController* controller); |
| virtual ~TabStrip(); |
| |
| // Creates the new tab button. |
| void InitTabStripButtons(); |
| |
| // Returns the bounds of the new tab button. |
| gfx::Rect GetNewTabButtonBounds(); |
| |
| // MouseWatcherListener overrides: |
| virtual void MouseMovedOutOfView() OVERRIDE; |
| |
| // AbstractTabStripView implementation: |
| virtual bool IsPositionInWindowCaption(const gfx::Point& point) OVERRIDE; |
| virtual void SetBackgroundOffset(const gfx::Point& offset) OVERRIDE; |
| |
| // BaseTabStrip implementation: |
| virtual void PrepareForCloseAt(int model_index) OVERRIDE; |
| virtual void RemoveTabAt(int model_index) OVERRIDE; |
| virtual void SelectTabAt(int old_model_index, int new_model_index) OVERRIDE; |
| virtual void TabTitleChangedNotLoading(int model_index) OVERRIDE; |
| virtual void StartHighlight(int model_index) OVERRIDE; |
| virtual void StopAllHighlighting() OVERRIDE; |
| virtual BaseTab* CreateTabForDragging() OVERRIDE; |
| |
| // views::View overrides: |
| virtual void PaintChildren(gfx::Canvas* canvas) OVERRIDE; |
| virtual const views::View* GetViewByID(int id) const OVERRIDE; |
| virtual gfx::Size GetPreferredSize() OVERRIDE; |
| // NOTE: the drag and drop methods are invoked from FrameView. This is done |
| // to allow for a drop region that extends outside the bounds of the TabStrip. |
| virtual void OnDragEntered(const views::DropTargetEvent& event) OVERRIDE; |
| virtual int OnDragUpdated(const views::DropTargetEvent& event) OVERRIDE; |
| virtual void OnDragExited() OVERRIDE; |
| virtual int OnPerformDrop(const views::DropTargetEvent& event) OVERRIDE; |
| virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE; |
| virtual views::View* GetEventHandlerForPoint(const gfx::Point& point) |
| OVERRIDE; |
| virtual void OnThemeChanged() OVERRIDE; |
| |
| protected: |
| // BaseTabStrip overrides: |
| virtual BaseTab* CreateTab() OVERRIDE; |
| virtual void StartInsertTabAnimation(int model_index) OVERRIDE; |
| virtual void AnimateToIdealBounds() OVERRIDE; |
| virtual bool ShouldHighlightCloseButtonAfterRemove() OVERRIDE; |
| virtual void DoLayout() OVERRIDE; |
| virtual void LayoutDraggedTabsAt(const std::vector<BaseTab*>& tabs, |
| BaseTab* active_tab, |
| const gfx::Point& location, |
| bool initial_drag) OVERRIDE; |
| virtual void CalculateBoundsForDraggedTabs( |
| const std::vector<BaseTab*>& tabs, |
| std::vector<gfx::Rect>* bounds) OVERRIDE; |
| virtual int GetSizeNeededForTabs(const std::vector<BaseTab*>& tabs) OVERRIDE; |
| |
| // views::View implementation: |
| virtual void ViewHierarchyChanged(bool is_add, |
| views::View* parent, |
| views::View* child) OVERRIDE; |
| |
| // views::ButtonListener implementation: |
| virtual void ButtonPressed(views::Button* sender, const views::Event& event) |
| OVERRIDE; |
| |
| // Horizontal gap between mini and non-mini-tabs. |
| static const int mini_to_non_mini_gap_; |
| |
| private: |
| friend class DraggedTabController; |
| |
| // Used during a drop session of a url. Tracks the position of the drop as |
| // well as a window used to highlight where the drop occurs. |
| struct DropInfo { |
| DropInfo(int index, bool drop_before, bool paint_down); |
| ~DropInfo(); |
| |
| // Index of the tab to drop on. If drop_before is true, the drop should |
| // occur between the tab at drop_index - 1 and drop_index. |
| // WARNING: if drop_before is true it is possible this will == tab_count, |
| // which indicates the drop should create a new tab at the end of the tabs. |
| int drop_index; |
| bool drop_before; |
| |
| // Direction the arrow should point in. If true, the arrow is displayed |
| // above the tab and points down. If false, the arrow is displayed beneath |
| // the tab and points up. |
| bool point_down; |
| |
| // Renders the drop indicator. |
| views::Widget* arrow_window; |
| views::ImageView* arrow_view; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(DropInfo); |
| }; |
| |
| void Init(); |
| |
| // Set the images for the new tab button. |
| void LoadNewTabButtonImage(); |
| |
| // Retrieves the Tab at the specified index. Remember, the specified index |
| // is in terms of tab_data, *not* the model. |
| Tab* GetTabAtTabDataIndex(int tab_data_index) const; |
| |
| // Returns the tab at the specified index. If a remove animation is on going |
| // and the index is >= the index of the tab being removed, the index is |
| // incremented. While a remove operation is on going the indices of the model |
| // do not line up with the indices of the view. This method adjusts the index |
| // accordingly. |
| // |
| // Use this instead of GetTabAtTabDataIndex if the index comes from the model. |
| Tab* GetTabAtModelIndex(int model_index) const; |
| |
| // Returns the number of mini-tabs. |
| int GetMiniTabCount() const; |
| |
| // -- Tab Resize Layout ----------------------------------------------------- |
| |
| // Returns the exact (unrounded) current width of each tab. |
| void GetCurrentTabWidths(double* unselected_width, |
| double* selected_width) const; |
| |
| // Returns the exact (unrounded) desired width of each tab, based on the |
| // desired strip width and number of tabs. If |
| // |width_of_tabs_for_mouse_close_| is nonnegative we use that value in |
| // calculating the desired strip width; otherwise we use the current width. |
| // |mini_tab_count| gives the number of mini-tabs and |tab_count| the number |
| // of mini and non-mini-tabs. |
| void GetDesiredTabWidths(int tab_count, |
| int mini_tab_count, |
| double* unselected_width, |
| double* selected_width) const; |
| |
| // Perform an animated resize-relayout of the TabStrip immediately. |
| void ResizeLayoutTabs(); |
| |
| // Ensure that the message loop observer used for event spying is added and |
| // removed appropriately so we can tell when to resize layout the tab strip. |
| void AddMessageLoopObserver(); |
| void RemoveMessageLoopObserver(); |
| |
| // -- Link Drag & Drop ------------------------------------------------------ |
| |
| // Returns the bounds to render the drop at, in screen coordinates. Sets |
| // |is_beneath| to indicate whether the arrow is beneath the tab, or above |
| // it. |
| gfx::Rect GetDropBounds(int drop_index, bool drop_before, bool* is_beneath); |
| |
| // Updates the location of the drop based on the event. |
| void UpdateDropIndex(const views::DropTargetEvent& event); |
| |
| // Sets the location of the drop, repainting as necessary. |
| void SetDropIndex(int tab_data_index, bool drop_before); |
| |
| // Returns the drop effect for dropping a URL on the tab strip. This does |
| // not query the data in anyway, it only looks at the source operations. |
| int GetDropEffect(const views::DropTargetEvent& event); |
| |
| // Returns the image to use for indicating a drop on a tab. If is_down is |
| // true, this returns an arrow pointing down. |
| static SkBitmap* GetDropArrowImage(bool is_down); |
| |
| // -- Animations ------------------------------------------------------------ |
| |
| // Generates the ideal bounds of the TabStrip when all Tabs have finished |
| // animating to their desired position/bounds. This is used by the standard |
| // Layout method and other callers like the DraggedTabController that need |
| // stable representations of Tab positions. |
| virtual void GenerateIdealBounds(); |
| |
| // Starts various types of TabStrip animations. |
| void StartResizeLayoutAnimation(); |
| virtual void StartMiniTabAnimation(); |
| void StartMouseInitiatedRemoveTabAnimation(int model_index); |
| |
| // Calculates the available width for tabs, assuming a Tab is to be closed. |
| int GetAvailableWidthForTabs(Tab* last_tab) const; |
| |
| // Returns true if the specified point in TabStrip coords is within the |
| // hit-test region of the specified Tab. |
| bool IsPointInTab(Tab* tab, const gfx::Point& point_in_tabstrip_coords); |
| |
| // -- Member Variables ------------------------------------------------------ |
| |
| // The "New Tab" button. |
| views::ImageButton* newtab_button_; |
| |
| // Ideal bounds of the new tab button. |
| gfx::Rect newtab_button_bounds_; |
| |
| // The current widths of various types of tabs. We save these so that, as |
| // users close tabs while we're holding them at the same size, we can lay out |
| // tabs exactly and eliminate the "pixel jitter" we'd get from just leaving |
| // them all at their existing, rounded widths. |
| double current_unselected_width_; |
| double current_selected_width_; |
| |
| // If this value is nonnegative, it is used in GetDesiredTabWidths() to |
| // calculate how much space in the tab strip to use for tabs. Most of the |
| // time this will be -1, but while we're handling closing a tab via the mouse, |
| // we'll set this to the edge of the last tab before closing, so that if we |
| // are closing the last tab and need to resize immediately, we'll resize only |
| // back to this width, thus once again placing the last tab under the mouse |
| // cursor. |
| int available_width_for_tabs_; |
| |
| // True if PrepareForCloseAt has been invoked. When true remove animations |
| // preserve current tab bounds. |
| bool in_tab_close_; |
| |
| // The size of the new tab button must be hardcoded because we need to be |
| // able to lay it out before we are able to get its image from the |
| // ui::ThemeProvider. It also makes sense to do this, because the size of the |
| // new tab button should not need to be calculated dynamically. |
| static const int kNewTabButtonWidth = 28; |
| static const int kNewTabButtonHeight = 18; |
| |
| // Valid for the lifetime of a drag over us. |
| scoped_ptr<DropInfo> drop_info_; |
| |
| // To ensure all tabs pulse at the same time they share the same animation |
| // container. This is that animation container. |
| scoped_refptr<ui::AnimationContainer> animation_container_; |
| |
| // Used for stage 1 of new tab animation. |
| base::OneShotTimer<TabStrip> new_tab_timer_; |
| |
| scoped_ptr<views::MouseWatcher> mouse_watcher_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TabStrip); |
| }; |
| |
| #endif // CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_H_ |