diff options
Diffstat (limited to 'chrome/browser/ui/views/tabs/tab_strip.h')
-rw-r--r-- | chrome/browser/ui/views/tabs/tab_strip.h | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h new file mode 100644 index 0000000..4978a5c --- /dev/null +++ b/chrome/browser/ui/views/tabs/tab_strip.h @@ -0,0 +1,287 @@ +// Copyright (c) 2010 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 "app/animation_container.h" +#include "base/ref_counted.h" +#include "base/timer.h" +#include "chrome/browser/views/tabs/base_tab_strip.h" +#include "gfx/point.h" +#include "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(); + + // BaseTabStrip implementation: + virtual int GetPreferredHeight(); + virtual void SetBackgroundOffset(const gfx::Point& offset); + virtual bool IsPositionInWindowCaption(const gfx::Point& point); + virtual void SetDraggedTabBounds(int tab_index, + const gfx::Rect& tab_bounds); + virtual TabStrip* AsTabStrip(); + virtual void PrepareForCloseAt(int model_index); + virtual void RemoveTabAt(int model_index); + virtual void SelectTabAt(int old_model_index, int new_model_index); + virtual void TabTitleChangedNotLoading(int model_index); + virtual void StartHighlight(int model_index); + virtual void StopAllHighlighting(); + virtual BaseTab* CreateTabForDragging(); + + // views::View overrides: + virtual void PaintChildren(gfx::Canvas* canvas); + virtual views::View* GetViewByID(int id) const; + virtual gfx::Size GetPreferredSize(); + // 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); + virtual int OnDragUpdated(const views::DropTargetEvent& event); + virtual void OnDragExited(); + virtual int OnPerformDrop(const views::DropTargetEvent& event); + virtual AccessibilityTypes::Role GetAccessibleRole(); + virtual views::View* GetViewForPoint(const gfx::Point& point); + virtual void OnThemeChanged(); + + protected: + // BaseTabStrip overrides: + virtual BaseTab* CreateTab(); + virtual void StartInsertTabAnimation(int model_index, bool foreground); + virtual void StartMoveTabAnimation(); + virtual void AnimateToIdealBounds(); + virtual bool ShouldHighlightCloseButtonAfterRemove(); + virtual void DoLayout(); + + // views::View implementation: + virtual void ViewHierarchyChanged(bool is_add, + views::View* parent, + views::View* child); + + // TabController overrides. + virtual bool IsTabSelected(const BaseTab* btr) const; + + // views::ButtonListener implementation: + virtual void ButtonPressed(views::Button* sender, const views::Event& event); + + // 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. + // TODO(beng): should be views::Widget. +#if defined(OS_WIN) + views::WidgetWin* arrow_window; +#else + views::WidgetGtk* arrow_window; +#endif + 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. + void GenerateIdealBounds(); + + // Starts various types of TabStrip animations. + void StartResizeLayoutAnimation(); + void StartMoveTabAnimation(int from_model_index, + int to_model_index); + void StartMiniTabAnimation(); + void StartMouseInitiatedRemoveTabAnimation(int model_index); + + // Stops any ongoing animations. If |layout| is true and an animation is + // ongoing this does a layout. + virtual void StopAnimating(bool layout); + + // 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 + // 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<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_ |