Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(428)

Side by Side Diff: chrome/browser/ui/views/tabs/touch_tab_strip_layout.cc

Issue 10213011: Attempt 3 at a better touch tabstrip. There is still a bunch to do, (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove Tab::GetTouchModeMinimumSize Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 #include "chrome/browser/ui/views/tabs/touch_tab_strip_layout.h"
6
7 #include <stdio.h>
8
9 #include "base/logging.h"
10 #include "base/string_number_conversions.h"
11
12 TouchTabStripLayout::TouchTabStripLayout(const gfx::Size& size,
13 int padding,
14 int stacked_padding,
15 int max_stacked_count,
16 views::ViewModel* view_model)
17 : size_(size),
18 padding_(padding),
19 stacked_padding_(stacked_padding),
20 max_stacked_count_(max_stacked_count),
21 view_model_(view_model),
22 x_(0),
23 width_(0),
24 mini_tab_count_(0),
25 active_index_(-1) {
26 }
27
28 TouchTabStripLayout::~TouchTabStripLayout() {
29 }
30
31 void TouchTabStripLayout::SetXAndMiniCount(int x, int mini_tab_count) {
32 x_ = x;
33 mini_tab_count_ = mini_tab_count;
34 SetIdealBoundsAt(active_index(), ConstrainActiveX(ideal_x(active_index())));
35 LayoutByTabOffsetAfter(active_index());
36 LayoutByTabOffsetBefore(active_index());
37 }
38
39 void TouchTabStripLayout::SetWidth(int width) {
40 if (width_ == width)
41 return;
42
43 width_ = width;
44 if (!requires_stacking()) {
45 ResetToIdealState();
46 return;
47 }
48 SetActiveBoundsAndLayoutFromActiveTab();
49 }
50
51 void TouchTabStripLayout::SetActiveIndex(int index) {
52 int old = active_index();
53 active_index_ = index;
54 if (old == active_index() || !requires_stacking())
55 return;
56 SetIdealBoundsAt(active_index(), ConstrainActiveX(ideal_x(active_index())));
57 LayoutByTabOffsetBefore(active_index());
58 LayoutByTabOffsetAfter(active_index());
59 AdjustStackedTabs();
60 }
61
62 void TouchTabStripLayout::DragActiveTab(int delta) {
63 if (delta == 0 && !requires_stacking())
64 return;
65 int initial_x = ideal_x(active_index());
66 // If we're at a particular edge and start dragging, reset to ideal state.
67 if ((delta > 0 && initial_x == GetMinX(active_index())) ||
68 (delta < 0 && initial_x == GetMaxX(active_index()))) {
69 ResetToIdealState();
70 }
71 int x = delta > 0 ?
72 std::min(initial_x + delta, GetMaxX(active_index())) :
73 std::max(initial_x + delta, GetMinX(active_index()));
74 if (x != initial_x) {
75 SetIdealBoundsAt(active_index(), x);
76 LayoutByTabOffsetAfter(active_index());
77 LayoutByTabOffsetBefore(active_index());
78 delta -= (x - initial_x);
79 }
80 if (delta > 0)
81 ExpandTabsBefore(active_index(), delta);
82 else if (delta < 0)
83 ExpandTabsAfter(active_index(), -delta);
84 AdjustStackedTabs();
85 }
86
87 void TouchTabStripLayout::AddTab(int index,
88 int add_types,
89 int start_x) {
90 if (add_types & kAddTypeActive)
91 active_index_ = index;
92 else if (active_index_ >= index)
93 active_index_++;
94 if (add_types & kAddTypeMini)
95 mini_tab_count_++;
96 x_ = start_x;
97 if (!requires_stacking() || normal_tab_count() <= 1) {
98 ResetToIdealState();
99 return;
100 }
101 int active_x = (index + 1 == tab_count()) ?
102 width_ - size_.width() : ideal_x(index + 1);
103 SetIdealBoundsAt(active_index(), ConstrainActiveX(active_x));
104 LayoutByTabOffsetAfter(active_index());
105 LayoutByTabOffsetBefore(active_index());
106 AdjustStackedTabs();
107 }
108
109 void TouchTabStripLayout::RemoveTab(int index, int start_x, int old_x) {
110 if (index == active_index_)
111 active_index_ = std::min(active_index_, tab_count() - 1);
112 else if (index > active_index_)
113 active_index_--;
114 bool removed_mini_tab = index < mini_tab_count_;
115 if (removed_mini_tab) {
116 mini_tab_count_--;
117 DCHECK_GE(mini_tab_count_, 0);
118 }
119 int delta = start_x - x_;
120 x_ = start_x;
121 if (!requires_stacking()) {
122 ResetToIdealState();
123 return;
124 }
125 if (removed_mini_tab) {
126 for (int i = mini_tab_count_; i < tab_count(); ++i)
127 SetIdealBoundsAt(i, ideal_x(i) + delta);
128 }
129 SetActiveBoundsAndLayoutFromActiveTab();
130 AdjustStackedTabs();
131 }
132
133 void TouchTabStripLayout::MoveTab(int from,
134 int to,
135 int new_active_index,
136 int start_x,
137 int mini_tab_count) {
138 x_ = start_x;
139 mini_tab_count_ = mini_tab_count;
140 active_index_ = new_active_index;
141 SetIdealBoundsAt(active_index(), ConstrainActiveX(ideal_x(active_index())));
142 LayoutByTabOffsetAfter(active_index());
143 LayoutByTabOffsetBefore(active_index());
144 AdjustStackedTabs();
145 }
146
147 void TouchTabStripLayout::Reset(int x,
148 int width,
149 int mini_tab_count,
150 int active_index) {
151 x_ = x;
152 width_ = width;
153 mini_tab_count_ = mini_tab_count;
154 active_index_ = active_index;
155 ResetToIdealState();
156 }
157
158 void TouchTabStripLayout::ResetToIdealState() {
159 if (tab_count() == mini_tab_count_)
160 return;
161
162 if (!requires_stacking()) {
163 SetIdealBoundsAt(mini_tab_count_, x_);
164 LayoutByTabOffsetAfter(mini_tab_count_);
165 return;
166 }
167
168 if (normal_tab_count() == 1) {
169 // TODO: might want to shrink the tab here.
170 SetIdealBoundsAt(mini_tab_count_, 0);
171 return;
172 }
173
174 int available_width = width_ - x_;
175 int leading_count = active_index() - mini_tab_count_;
176 int trailing_count = tab_count() - active_index();
177 if (width_for_count(leading_count + 1) + max_stacked_width() <
178 available_width) {
179 SetIdealBoundsAt(mini_tab_count_, x_);
180 LayoutByTabOffsetAfter(mini_tab_count_);
181 } else if (width_for_count(trailing_count) + max_stacked_width() <
182 available_width) {
183 SetIdealBoundsAt(tab_count() - 1, width_ - size_.width());
184 LayoutByTabOffsetBefore(tab_count() - 1);
185 } else {
186 int index = active_index();
187 do {
188 int stacked_padding = stacked_padding_for_count(index - mini_tab_count_);
189 SetIdealBoundsAt(index, x_ + stacked_padding);
190 LayoutByTabOffsetAfter(index);
191 LayoutByTabOffsetBefore(index);
192 index--;
193 } while (index >= mini_tab_count_ && ideal_x(mini_tab_count_) != x_ &&
194 ideal_x(tab_count() - 1) != width_ - size_.width());
195 }
196 AdjustStackedTabs();
197 }
198
199 int TouchTabStripLayout::ConstrainActiveX(int x) const {
200 return std::min(GetMaxX(active_index()),
201 std::max(GetMinX(active_index()), x));
202 }
203
204 void TouchTabStripLayout::SetActiveBoundsAndLayoutFromActiveTab() {
205 int x = ConstrainActiveX(ideal_x(active_index()));
206 SetIdealBoundsAt(active_index(), x);
207 LayoutUsingCurrentBefore(active_index());
208 LayoutUsingCurrentAfter(active_index());
209 AdjustStackedTabs();
210 }
211
212 void TouchTabStripLayout::LayoutByTabOffsetAfter(int index) {
213 for (int i = index + 1; i < tab_count(); ++i) {
214 int max_x = width_ - size_.width() -
215 stacked_padding_for_count(tab_count() - i - 1);
216 int x = std::min(max_x,
217 view_model_->ideal_bounds(i - 1).x() + tab_offset());
218 SetIdealBoundsAt(i, x);
219 }
220 }
221
222 void TouchTabStripLayout::LayoutByTabOffsetBefore(int index) {
223 for (int i = index - 1; i >= mini_tab_count_; --i) {
224 int min_x = x_ + stacked_padding_for_count(i - mini_tab_count_);
225 int x = std::max(min_x, ideal_x(i + 1) - (tab_offset()));
226 SetIdealBoundsAt(i, x);
227 }
228 }
229
230 void TouchTabStripLayout::LayoutUsingCurrentAfter(int index) {
231 for (int i = index + 1; i < tab_count(); ++i) {
232 int min_x = width_ - width_for_count(tab_count() - i);
233 int x = std::max(min_x,
234 std::min(ideal_x(i), ideal_x(i - 1) + tab_offset()));
235 x = std::min(GetMaxX(i), x);
236 SetIdealBoundsAt(i, x);
237 }
238 }
239
240 void TouchTabStripLayout::LayoutUsingCurrentBefore(int index) {
241 for (int i = index - 1; i >= mini_tab_count_; --i) {
242 int max_x = x_ + width_for_count(i - mini_tab_count_);
243 SetIdealBoundsAt(
244 i, std::min(max_x,
245 std::max(ideal_x(i), ideal_x(i + 1) - tab_offset())));
246 }
247 }
248
249 void TouchTabStripLayout::ExpandTabsBefore(int index, int delta) {
250 if (index == mini_tab_count_ + 1)
251 return; // Nothing to expand.
252
253 for (int i = index - 1; i > mini_tab_count_ && delta > 0; --i) {
254 int to_resize = std::min(delta, GetMaxXCompressed(i) - ideal_x(i));
255 if (to_resize <= 0)
256 continue;
257 SetIdealBoundsAt(i, ideal_x(i) + to_resize);
258 delta -= to_resize;
259 LayoutByTabOffsetBefore(i);
260 }
261 }
262
263 void TouchTabStripLayout::ExpandTabsAfter(int index, int delta) {
264 if (index == tab_count() - 1)
265 return; // Nothing to expand.
266
267 for (int i = index + 1; i < tab_count() - 1 && delta > 0; ++i) {
268 int to_resize = std::min(ideal_x(i) - GetMinXCompressed(i), delta);
269 if (to_resize <= 0)
270 continue;
271 SetIdealBoundsAt(i, ideal_x(i) - to_resize);
272 delta -= to_resize;
273 LayoutByTabOffsetAfter(i);
274 }
275 }
276
277 void TouchTabStripLayout::AdjustStackedTabs() {
278 if (!requires_stacking() || mini_tab_count_ == tab_count())
279 return;
280
281 AdjustLeadingStackedTabs();
282 AdjustTrailingStackedTabs();
283 }
284
285 void TouchTabStripLayout::AdjustLeadingStackedTabs() {
286 int index = mini_tab_count_ + 1;
287 while (index < active_index() &&
288 ideal_x(index) - ideal_x(index - 1) <= stacked_padding_ &&
289 ideal_x(index) <= x_ + max_stacked_width()) {
290 index++;
291 }
292 if (ideal_x(index) - ideal_x(index - 1) <= stacked_padding_ &&
293 ideal_x(index) <= x_ + max_stacked_width()) {
294 index++;
295 }
296 if (index <= mini_tab_count_ + max_stacked_count_ - 1)
297 return;
298 int max_stacked = index;
299 int x = x_;
300 index = mini_tab_count_;
301 for (; index < max_stacked - max_stacked_count_ - 1; ++index)
302 SetIdealBoundsAt(index, x);
303 for (; index < max_stacked; ++index, x += stacked_padding_)
304 SetIdealBoundsAt(index, x);
305 }
306
307 void TouchTabStripLayout::AdjustTrailingStackedTabs() {
308 int index = tab_count() - 1;
309 int max_stacked_x = width_ - size_.width() - max_stacked_width();
310 while (index > active_index() &&
311 ideal_x(index) - ideal_x(index - 1) <= stacked_padding_ &&
312 ideal_x(index - 1) >= max_stacked_x) {
313 index--;
314 }
315 if (ideal_x(index) - ideal_x(index - 1) <= stacked_padding_ &&
316 ideal_x(index - 1) >= max_stacked_x) {
317 index--;
318 }
319 if (index >= tab_count() - max_stacked_count_)
320 return;
321 int first_stacked = index;
322 int x = width_ - size_.width() -
323 std::min(tab_count() - first_stacked, max_stacked_count_) *
324 stacked_padding_;
325 for (; index < first_stacked + max_stacked_count_;
326 ++index, x += stacked_padding_) {
327 SetIdealBoundsAt(index, x);
328 }
329 for (; index < tab_count(); ++index)
330 SetIdealBoundsAt(index, x);
331 }
332
333 void TouchTabStripLayout::SetIdealBoundsAt(int index, int x) {
334 view_model_->set_ideal_bounds(index, gfx::Rect(gfx::Point(x, 0), size_));
335 }
336
337 int TouchTabStripLayout::GetMinX(int index) const {
338 int leading_count = index - mini_tab_count_;
339 int trailing_count = tab_count() - index;
340 return std::max(x_ + stacked_padding_for_count(leading_count),
341 width_ - width_for_count(trailing_count));
342 }
343
344 int TouchTabStripLayout::GetMaxX(int index) const {
345 int leading_count = index - mini_tab_count_;
346 int trailing_count = tab_count() - index - 1;
347 int trailing_offset = stacked_padding_for_count(trailing_count);
348 int leading_size = width_for_count(leading_count) + x_;
349 if (leading_count > 0)
350 leading_size += padding_;
351 return std::min(width_ - trailing_offset - size_.width(), leading_size);
352 }
353
354 int TouchTabStripLayout::GetMaxXCompressed(int index) const {
355 DCHECK_LT(index, active_index());
356 DCHECK_GT(index, mini_tab_count_);
357 int trailing = active_index() - index;
358 return std::min(
359 x_ + width_for_count(index - mini_tab_count_) + padding_,
360 ideal_x(active_index()) - stacked_padding_for_count(trailing));
361 }
362
363 int TouchTabStripLayout::GetMinXCompressed(int index) const {
364 DCHECK_GT(index, active_index());
365 return std::max(
366 width_ - width_for_count(tab_count() - index),
367 ideal_x(active_index()) +
368 stacked_padding_for_count(index - active_index()));
369
370 }
371
372 #if !defined(NDEBUG)
373 std::string TouchTabStripLayout::BoundsString() const {
374 std::string result;
375 for (int i = 0; i < view_model_->view_size(); ++i) {
376 if (!result.empty())
377 result += " ";
378 if (i == active_index())
379 result += "[";
380 result += base::IntToString(view_model_->ideal_bounds(i).x());
381 if (i == active_index())
382 result += "]";
383 }
384 return result;
385 }
386 #endif
OLDNEW
« no previous file with comments | « chrome/browser/ui/views/tabs/touch_tab_strip_layout.h ('k') | chrome/browser/ui/views/tabs/touch_tab_strip_layout_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698