| // Copyright (c) 2012 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_STACKED_TAB_STRIP_LAYOUT_H_ |
| #define CHROME_BROWSER_UI_VIEWS_TABS_STACKED_TAB_STRIP_LAYOUT_H_ |
| |
| #include <algorithm> |
| |
| #include "ui/gfx/geometry/size.h" |
| #include "ui/views/view_model.h" |
| |
| class Tab; |
| |
| // StackedTabStripLayout is used by TabStrip in touch |
| // mode. StackedTabStripLayout is responsible for managing the bounds of the |
| // tabs. StackedTabStripLayout differs from the normal layout in that it stacks |
| // tabs. Stacked tabs are tabs placed nearly on top of each other, and if enough |
| // consecutive stacked tabs exist they are placed on top of each other. Normally |
| // stacked tabs are placed after pinned tabs, or at the end of the tabstrip, but |
| // during dragging tabs may be stacked before or after the active tab. |
| class StackedTabStripLayout { |
| public: |
| static const int kAddTypePinned = 1 << 0; |
| static const int kAddTypeActive = 1 << 1; |
| |
| // |size| is the size for tabs, |overlap| the overlap between consecutive |
| // tabs, |stacked_padding| the padding between stacked tabs, |
| // |max_stacked_count| the maximum number of consecutive tabs that can be |
| // stacked before they are placed on top of each other, |view_model| is the |
| // ViewModel the bounds of the tabs are placed in. |
| StackedTabStripLayout(const gfx::Size& size, |
| int overlap, |
| int stacked_padding, |
| int max_stacked_count, |
| views::ViewModelBase* view_model); |
| StackedTabStripLayout(const StackedTabStripLayout&) = delete; |
| StackedTabStripLayout& operator=(const StackedTabStripLayout&) = delete; |
| ~StackedTabStripLayout(); |
| |
| // Sets the x-coordinate the normal tabs start at as well as the pinned tab |
| // count. This is only useful if the pinned tab count or x-coordinate change. |
| void SetXAndPinnedCount(int x, int pinned_tab_count); |
| |
| // Sets the width available for sizing the tabs to. |
| void SetWidth(int width); |
| |
| // Sets the index of the active tab. |
| void SetActiveIndex(int index); |
| |
| // Drags the active tab. |
| void DragActiveTab(int delta); |
| |
| // Makes sure the tabs fill the available width. Used after a drag operation |
| // completes. |
| void SizeToFit(); |
| |
| // Adds a new tab at the specified index. |add_types| is a bitmask of |
| // kAddType*. |start_x| is the new x-coordinate non-pinned tabs start at. |
| void AddTab(int index, int add_types, int start_x); |
| |
| // Removes the tab at the specified index. |start_x| is the new x-coordinate |
| // normal tabs start at, and |old_x| the old x-coordinate of the tab. |
| // ViewModel should already have been updated before calling this. |
| void RemoveTab(int index, int start_x, int old_x); |
| |
| // Moves the tab from |from| to |to|. |new_active_index| is the index of the |
| // currently active tab. |
| void MoveTab(int from, |
| int to, |
| int new_active_index, |
| int start_x, |
| int pinned_tab_count); |
| |
| // Returns the active index as used by this class. The active index dictates |
| // stacking and what tabs are visible. As pinned tabs are never stacked, |
| // StackedTabStripLayout forces the active index to be in the normal tabs. |
| int active_index() const { |
| return active_index_ < pinned_tab_count_ ? pinned_tab_count_ |
| : active_index_; |
| } |
| |
| int pinned_tab_count() const { return pinned_tab_count_; } |
| |
| // Returns true if the tab at index is stacked. |
| bool IsStacked(int index) const; |
| |
| // Sets the X coordinate of the active tab as close to |x| as possible. |
| void SetActiveTabLocation(int x); |
| |
| #if !defined(NDEBUG) |
| std::string BoundsString() const; |
| #endif |
| |
| private: |
| friend class StackedTabStripLayoutTest; |
| |
| // Sets the x-coordinate normal tabs start at, width, pinned tab count, and |
| // active index. |
| void Reset(int x, int width, int pinned_tab_count, int active_index); |
| |
| // Resets to an ideal layout state. |
| void ResetToIdealState(); |
| |
| // Makes all tabs between the active tab and |index| (inclusive) visible. If |
| // this is not possible, then |index| is made visible and a stack forms |
| // immediately to the right of the active tab. This is used when a new tab is |
| // added that isn't active. |
| void MakeVisible(int index); |
| |
| // Returns the x-coordinate for the active tab constrained by the current tab |
| // count. |
| int ConstrainActiveX(int x) const; |
| |
| // Reset the bounds of the active tab (based on ConstrainActiveX()) and resets |
| // the bounds of the remaining tabs by way of LayoutUsingCurrent*. |
| void SetActiveBoundsAndLayoutFromActiveTab(); |
| |
| // Sets the bounds of the tabs after |index| relative to the position of the |
| // tab at |index|. Each tab is placed tab_offset() pixels after the previous |
| // tab, stacking as necessary. |
| void LayoutByTabOffsetAfter(int index); |
| |
| // Same as LayoutByTabOffsetAfter(), but iterates toward |
| // |pinned_tab_count_|. |
| void LayoutByTabOffsetBefore(int index); |
| |
| // Similar to LayoutByTabOffsetAfter(), but uses the current x-coordinate |
| // if possible. |
| void LayoutUsingCurrentAfter(int index); |
| void LayoutUsingCurrentBefore(int index); |
| |
| void PushTabsAfter(int index, int delta); |
| void PushTabsBefore(int index, int delta); |
| |
| // Does a layout for drag. Similar to LayoutUsingCurrentXXX() but does not |
| // contrain. Used when dragging the active tab. |
| void LayoutForDragAfter(int index); |
| void LayoutForDragBefore(int index); |
| |
| // Used when the tabs are stacked at one side. The remaining tabs are stacked |
| // against the |active_index()|. |delta| is the amount of space to resize the |
| // the tabs by. |
| void ExpandTabsBefore(int index, int delta); |
| void ExpandTabsAfter(int index, int delta); |
| |
| // Adjusts the stacked tabs so that if there are more than |
| // |max_stacked_count_| tabs, the set > max_stacked_count_ have an |
| // x-coordinate of |x_|. Similarly those at the end have the same x-coordinate |
| // and are pushed all the way to the right. |
| void AdjustStackedTabs(); |
| void AdjustLeadingStackedTabs(); |
| void AdjustTrailingStackedTabs(); |
| |
| // Sets the bounds of the tab at |index|. |
| void SetIdealBoundsAt(int index, int x); |
| |
| // Returns the min x-coordinate for the sepcified index. This is calculated |
| // assuming all the tabs before |index| are stacked. |
| int GetMinX(int index) const; |
| |
| // Returns the max x-coordinate for the speficifed index. This is calculated |
| // assuming all the tabs after |index| are stacked. |
| int GetMaxX(int index) const; |
| |
| // Used when dragging to get the min/max coodinate. |
| int GetMinDragX(int index) const; |
| int GetMaxDragX(int index) const; |
| |
| // Returns the min x-coordinate for the tab at |index|. This is relative |
| // to the |active_index()| and is only useful when the active tab is pushed |
| // against the left side. |
| int GetMinXCompressed(int index) const; |
| |
| // Width needed to display |count| tabs. |
| int width_for_count(int count) const { |
| return (count * size_.width()) - (std::max(count - 1, 0) * overlap_); |
| } |
| |
| // Padding needed for |count| stacked tabs. |
| int stacked_padding_for_count(int count) const { |
| return std::min(count, max_stacked_count_) * stacked_padding_; |
| } |
| |
| // Max stacked padding. |
| int max_stacked_width() const { |
| return stacked_padding_ * max_stacked_count_; |
| } |
| |
| int ideal_x(int index) const { return view_model_->ideal_bounds(index).x(); } |
| |
| // Returns true if some of the tabs need to be stacked. |
| bool requires_stacking() const { |
| return tab_count() != pinned_tab_count_ && |
| x_ + width_for_count(tab_count() - pinned_tab_count_) > width_; |
| } |
| |
| // Number of tabs. |
| int tab_count() const { return view_model_->view_size(); } |
| |
| // Number of normal (non-pinned) tabs. |
| int normal_tab_count() const { return tab_count() - pinned_tab_count_; } |
| |
| // Distance from the start of one tab to the next. |
| int tab_offset() const { return size_.width() - overlap_; } |
| |
| // Size of tabs. |
| const gfx::Size size_; |
| |
| // Overlap between tabs. |
| const int overlap_; |
| |
| // Padding between stacked tabs. |
| const int stacked_padding_; |
| |
| // Max number of stacked tabs. |
| const int max_stacked_count_; |
| |
| // Where bounds are placed. This is owned by TabStrip. |
| // (Note: This is a ViewModelBase, not a ViewModelT<Tab>, because the tests do |
| // not populate the model with Tab views.) |
| views::ViewModelBase* view_model_; |
| |
| // X coordinate of the first tab. |
| int first_tab_x_ = 0; |
| |
| // X coordinate normal tabs start at. If there are no pinned tabs, this is |
| // equal to |first_tab_x_|. |
| int x_ = 0; |
| |
| // Available width. |
| int width_ = 0; |
| |
| // Number of pinned tabs. |
| int pinned_tab_count_ = 0; |
| |
| // Distance from the last pinned tab to the first non-pinned tab. |
| int pinned_tab_to_non_pinned_tab_ = 0; |
| |
| // Index of the active tab. |
| int active_index_ = -1; |
| }; |
| |
| #endif // CHROME_BROWSER_UI_VIEWS_TABS_STACKED_TAB_STRIP_LAYOUT_H_ |