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_STACKED_TAB_STRIP_LAYOUT_H_
6#define CHROME_BROWSER_UI_VIEWS_TABS_STACKED_TAB_STRIP_LAYOUT_H_
7
8#include <algorithm>
9
10#include "base/basictypes.h"
11#include "ui/gfx/size.h"
12#include "ui/views/view_model.h"
13
14namespace views {
15class ViewModel;
16}
17
18// StackedTabStripLayout is used by TabStrip in touch
19// mode. StackedTabStripLayout is responsible for managing the bounds of the
20// tabs. StackedTabStripLayout differs from the normal layout in that it stacks
21// tabs. Stacked tabs are tabs placed nearly on top of each other, and if enough
22// consecutive stacked tabs exist they are placed on top of each other. Normally
23// stacked tabs are placed after mini-tabs, or at the end of the tabstrip, but
24// during dragging tabs may be stacked before or after the active tab.
25class StackedTabStripLayout {
26 public:
27  static const int kAddTypeMini   = 1 << 0;
28  static const int kAddTypeActive = 1 << 1;
29
30  // |size| is the size for tabs, |padding| the padding between consecutive
31  // tabs, |stacked_padding| the padding between stacked tabs,
32  // |max_stacked_count| the maximum number of consecutive tabs that can be
33  // stacked before they are placed on top of each other, |view_model| is the
34  // ViewModel the bounds of the tabs are placed in.
35  StackedTabStripLayout(const gfx::Size& size,
36                        int padding,
37                        int stacked_padding,
38                        int max_stacked_count,
39                        views::ViewModel* view_model);
40  ~StackedTabStripLayout();
41
42  // Sets the x-coordinate the normal tabs start at as well as the mini-tab
43  // count. This is only useful if the mini-tab count or x-coordinate change.
44  void SetXAndMiniCount(int x, int mini_tab_count);
45
46  // Sets the width available for sizing the tabs to.
47  void SetWidth(int width);
48
49  int width() const { return width_; }
50
51  // Sets the index of the active tab.
52  void SetActiveIndex(int index);
53
54  // Drags the active tab.
55  void DragActiveTab(int delta);
56
57  // Makes sure the tabs fill the available width. Used after a drag operation
58  // completes.
59  void SizeToFit();
60
61  // Adds a new tab at the specified index. |add_types| is a bitmask of
62  // kAddType*. |start_x| is the new x-coordinate non-mini tabs start at.
63  void AddTab(int index, int add_types, int start_x);
64
65  // Removes the tab at the specified index. |start_x| is the new x-coordinate
66  // normal tabs start at, and |old_x| the old x-coordinate of the tab. It is
67  // expected that the ViewModel hash been updated at the time this is invoked.
68  void RemoveTab(int index, int start_x, int old_x);
69
70  // Moves the tab from |from| to |to|. |new_active_index| is the index of the
71  // currently active tab.
72  void MoveTab(int from,
73               int to,
74               int new_active_index,
75               int start_x,
76               int mini_tab_count);
77
78  // Returns the active index as used by this class. The active index dictates
79  // stacking and what tabs are visible. As mini-tabs are never stacked,
80  // StackedTabStripLayout forces the active index to be in the normal tabs.
81  int active_index() const {
82    return active_index_ < mini_tab_count_ ? mini_tab_count_ : active_index_;
83  }
84
85  int mini_tab_count() const { return mini_tab_count_; }
86
87  // Returns true if the tab at index is stacked.
88  bool IsStacked(int index) const;
89
90  // Sets the location of the active tab as close to |x| as possible.
91  void SetActiveTabLocation(int x);
92
93#if !defined(NDEBUG)
94  std::string BoundsString() const;
95#endif
96
97 private:
98  friend class StackedTabStripLayoutTest;
99
100  // Sets the x-coordinate normal tabs start at, width mini-tab count and
101  // active index at once.
102  void Reset(int x, int width, int mini_tab_count, int active_index);
103
104  // Resets to an ideal layout state.
105  void ResetToIdealState();
106
107  // Makes |index| visible. This is used when a new tab is added that isn't
108  // active.
109  void MakeVisible(int index);
110
111  // Returns the x-coordinate for the active tab constrained by the current tab
112  // counts.
113  int ConstrainActiveX(int x) const;
114
115  // Reset the bounds of the active tab (based on ConstrainActiveX()) and resets
116  // the bounds of the remaining tabs by way of LayoutUsingCurrent*.
117  void SetActiveBoundsAndLayoutFromActiveTab();
118
119  // Sets the bounds of the tabs after |index| relative to the position of the
120  // tab at |index|. Each tab is placed |tab_offset()| pixels after the previous
121  // tab, stacking as necessary.
122  void LayoutByTabOffsetAfter(int index);
123
124  // Same as LayoutByTabOffsetAfter(), but iterates toward
125  // |mini_tab_count_|.
126  void LayoutByTabOffsetBefore(int index);
127
128  // Similar to LayoutByTabOffsetAfter(), but uses the current x-coordinate
129  // if possible.
130  void LayoutUsingCurrentAfter(int index);
131  void LayoutUsingCurrentBefore(int index);
132
133  void PushTabsAfter(int index, int delta);
134  void PushTabsBefore(int index, int delta);
135
136  // Does a layout for drag. Similar to LayoutUsingCurrentXXX() but does not
137  // contrain. Used when dragging the active tab.
138  void LayoutForDragAfter(int index);
139  void LayoutForDragBefore(int index);
140
141  // Used when the tabs are stacked at one side. The remaining tabs are stacked
142  // against the |active_index()|. |delta| is the amount of space to resize the
143  // the tabs by.
144  void ExpandTabsBefore(int index, int delta);
145  void ExpandTabsAfter(int index, int delta);
146
147  // Adjusts the stacked tabs so that if there are more than
148  // |max_stacked_count_| tabs, the set > max_stacked_count_ have an
149  // x-coordinate of |x_|. Similarly those at the end have the same x-coordinate
150  // and are pushed all the way to the right.
151  void AdjustStackedTabs();
152  void AdjustLeadingStackedTabs();
153  void AdjustTrailingStackedTabs();
154
155  // Sets the bounds of the tab at |index|.
156  void SetIdealBoundsAt(int index, int x);
157
158  // Returns the min x-coordinate for the sepcified index. This is calculated
159  // assuming all the tabs before |index| are stacked.
160  int GetMinX(int index) const;
161
162  // Returns the max x-coordinate for the speficifed index. This is calculated
163  // assuming all the tabs after |index| are stacked.
164  int GetMaxX(int index) const;
165
166  // Used when dragging to get the min/max coodinate.
167  int GetMinDragX(int index) const;
168  int GetMaxDragX(int index) const;
169
170  // Returns the min x-coordinate for the tab at |index|. This is relative
171  // to the |active_index()| and is only useful when the active tab is pushed
172  // against the left side.
173  int GetMinXCompressed(int index) const;
174
175  // Width needed to display |count| tabs.
176  int width_for_count(int count) const {
177    return (count * size_.width()) + (std::max(count - 1, 0) * padding_);
178  }
179
180  // Padding needed for |count| stacked tabs.
181  int stacked_padding_for_count(int count) const {
182    return std::min(count, max_stacked_count_) * stacked_padding_;
183  }
184
185  // Max stacked padding.
186  int max_stacked_width() const {
187    return stacked_padding_ * max_stacked_count_;
188  }
189
190  int ideal_x(int index) const { return view_model_->ideal_bounds(index).x(); }
191
192  // Returns true if some of the tabs need to be stacked.
193  bool requires_stacking() const {
194    return tab_count() != mini_tab_count_ &&
195        x_ + width_for_count(tab_count() - mini_tab_count_) > width_;
196  }
197
198  // Number of tabs.
199  int tab_count() const { return view_model_->view_size(); }
200
201  // Number of normal (non-mini) tabs.
202  int normal_tab_count() const { return tab_count() - mini_tab_count_; }
203
204  // Distance between one tab to the next.
205  int tab_offset() const { return size_.width() + padding_; }
206
207  // Size of tabs.
208  const gfx::Size size_;
209
210  // Padding between tabs.
211  const int padding_;
212
213  // Padding between stacked tabs.
214  const int stacked_padding_;
215
216  // Max number of stacked tabs.
217  const int max_stacked_count_;
218
219  // Where bounds are placed. This is owned by TabStrip.
220  views::ViewModel* view_model_;
221
222  // x-coordinate normal tabs start at.
223  int x_;
224
225  // Available width.
226  int width_;
227
228  // Number of mini-tabs.
229  int mini_tab_count_;
230
231  // Distance from the last mini-tab to the first non-mini-tab.
232  int mini_tab_to_non_mini_tab_;
233
234  // Index of the active tab.
235  int active_index_;
236
237  // X-coordinate of the first tab. This is either |x_| if there are no
238  // mini-tabs, or the x-coordinate of the first mini-tab.
239  int first_tab_x_;
240
241  DISALLOW_COPY_AND_ASSIGN(StackedTabStripLayout);
242};
243
244#endif  // CHROME_BROWSER_UI_VIEWS_TABS_STACKED_TAB_STRIP_LAYOUT_H_
245