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

Side by Side Diff: ui/app_list/views/page_switcher.cc

Issue 2938563002: Vertically centered app list page switcher (Closed)
Patch Set: Created 3 years, 6 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
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 "ui/app_list/views/page_switcher.h"
6
7 #include <algorithm>
8
9 #include "base/macros.h"
10 #include "third_party/skia/include/core/SkPath.h"
11 #include "ui/app_list/app_list_constants.h"
12 #include "ui/app_list/pagination_model.h"
13 #include "ui/gfx/animation/throb_animation.h"
14 #include "ui/gfx/canvas.h"
15 #include "ui/gfx/geometry/insets.h"
16 #include "ui/gfx/skia_util.h"
17 #include "ui/views/controls/button/custom_button.h"
18 #include "ui/views/layout/box_layout.h"
19
20 namespace app_list {
21
22 namespace {
23
24 const int kPreferredHeight = 58;
25
26 const int kMaxButtonSpacing = 18;
27 const int kMinButtonSpacing = 4;
28 const int kMaxButtonWidth = 68;
29 const int kMinButtonWidth = 28;
30 const int kButtonHeight = 6;
31 const int kButtonCornerRadius = 2;
32 const int kButtonStripPadding = 20;
33
34 class PageSwitcherButton : public views::CustomButton {
35 public:
36 explicit PageSwitcherButton(views::ButtonListener* listener)
37 : views::CustomButton(listener),
38 button_width_(kMaxButtonWidth),
39 selected_range_(0) {
40 }
41 ~PageSwitcherButton() override {}
42
43 void SetSelectedRange(double selected_range) {
44 if (selected_range_ == selected_range)
45 return;
46
47 selected_range_ = selected_range;
48 SchedulePaint();
49 }
50
51 void set_button_width(int button_width) { button_width_ = button_width; }
52
53 // Overridden from views::View:
54 gfx::Size CalculatePreferredSize() const override {
55 return gfx::Size(button_width_, kButtonHeight);
56 }
57
58 void PaintButtonContents(gfx::Canvas* canvas) override {
59 if (state() == STATE_HOVERED)
60 PaintButton(canvas, kPagerHoverColor);
61 else
62 PaintButton(canvas, kPagerNormalColor);
63 }
64
65 void OnGestureEvent(ui::GestureEvent* event) override {
66 CustomButton::OnGestureEvent(event);
67
68 if (event->type() == ui::ET_GESTURE_TAP_DOWN)
69 SetState(views::CustomButton::STATE_HOVERED);
70 else if (event->type() == ui::ET_GESTURE_TAP_CANCEL ||
71 event->type() == ui::ET_GESTURE_TAP)
72 SetState(views::CustomButton::STATE_NORMAL);
73 SchedulePaint();
74 }
75
76 private:
77 // Paints a button that has two rounded corner at bottom.
78 void PaintButton(gfx::Canvas* canvas, SkColor base_color) {
79 gfx::Rect rect(GetContentsBounds());
80 rect.ClampToCenteredSize(gfx::Size(button_width_, kButtonHeight));
81
82 SkPath path;
83 path.addRoundRect(gfx::RectToSkRect(rect),
84 SkIntToScalar(kButtonCornerRadius),
85 SkIntToScalar(kButtonCornerRadius));
86
87 cc::PaintFlags flags;
88 flags.setAntiAlias(true);
89 flags.setStyle(cc::PaintFlags::kFill_Style);
90 flags.setColor(base_color);
91 canvas->DrawPath(path, flags);
92
93 int selected_start_x = 0;
94 int selected_width = 0;
95 if (selected_range_ > 0) {
96 selected_width = selected_range_ * rect.width();
97 } else if (selected_range_ < 0) {
98 selected_width = -selected_range_ * rect.width();
99 selected_start_x = rect.right() - selected_width;
100 }
101
102 if (selected_width) {
103 gfx::Rect selected_rect(rect);
104 selected_rect.set_x(selected_start_x);
105 selected_rect.set_width(selected_width);
106
107 SkPath selected_path;
108 selected_path.addRoundRect(gfx::RectToSkRect(selected_rect),
109 SkIntToScalar(kButtonCornerRadius),
110 SkIntToScalar(kButtonCornerRadius));
111 flags.setColor(kPagerSelectedColor);
112 canvas->DrawPath(selected_path, flags);
113 }
114 }
115
116 int button_width_;
117
118 // [-1, 1] range that represents the portion of the button that should be
119 // painted with kSelectedColor. Positive range starts from left side and
120 // negative range starts from the right side.
121 double selected_range_;
122
123 DISALLOW_COPY_AND_ASSIGN(PageSwitcherButton);
124 };
125
126 // Gets PageSwitcherButton at |index| in |buttons|.
127 PageSwitcherButton* GetButtonByIndex(views::View* buttons, int index) {
128 return static_cast<PageSwitcherButton*>(buttons->child_at(index));
129 }
130
131 } // namespace
132
133 PageSwitcher::PageSwitcher(PaginationModel* model)
134 : model_(model),
135 buttons_(new views::View) {
136 AddChildView(buttons_);
137
138 TotalPagesChanged();
139 SelectedPageChanged(-1, model->selected_page());
140 model_->AddObserver(this);
141 }
142
143 PageSwitcher::~PageSwitcher() {
144 model_->RemoveObserver(this);
145 }
146
147 int PageSwitcher::GetPageForPoint(const gfx::Point& point) const {
148 if (!buttons_->bounds().Contains(point))
149 return -1;
150
151 gfx::Point buttons_point(point);
152 views::View::ConvertPointToTarget(this, buttons_, &buttons_point);
153
154 for (int i = 0; i < buttons_->child_count(); ++i) {
155 const views::View* button = buttons_->child_at(i);
156 if (button->bounds().Contains(buttons_point))
157 return i;
158 }
159
160 return -1;
161 }
162
163 void PageSwitcher::UpdateUIForDragPoint(const gfx::Point& point) {
164 int page = GetPageForPoint(point);
165
166 const int button_count = buttons_->child_count();
167 if (page >= 0 && page < button_count) {
168 PageSwitcherButton* button =
169 static_cast<PageSwitcherButton*>(buttons_->child_at(page));
170 button->SetState(views::CustomButton::STATE_HOVERED);
171 return;
172 }
173
174 for (int i = 0; i < button_count; ++i) {
175 PageSwitcherButton* button =
176 static_cast<PageSwitcherButton*>(buttons_->child_at(i));
177 button->SetState(views::CustomButton::STATE_NORMAL);
178 }
179 }
180
181 gfx::Size PageSwitcher::CalculatePreferredSize() const {
182 // Always return a size with correct height so that container resize is not
183 // needed when more pages are added.
184 return gfx::Size(buttons_->GetPreferredSize().width(),
185 kPreferredHeight);
186 }
187
188 void PageSwitcher::Layout() {
189 gfx::Rect rect(GetContentsBounds());
190
191 CalculateButtonWidthAndSpacing(rect.width());
192
193 // Makes |buttons_| horizontally center and vertically fill.
194 gfx::Size buttons_size(buttons_->GetPreferredSize());
195 gfx::Rect buttons_bounds(rect.CenterPoint().x() - buttons_size.width() / 2,
196 rect.y(),
197 buttons_size.width(),
198 rect.height());
199 buttons_->SetBoundsRect(gfx::IntersectRects(rect, buttons_bounds));
200 }
201
202 void PageSwitcher::CalculateButtonWidthAndSpacing(int contents_width) {
203 const int button_count = buttons_->child_count();
204 if (!button_count)
205 return;
206
207 contents_width -= 2 * kButtonStripPadding;
208
209 int button_width = kMinButtonWidth;
210 int button_spacing = kMinButtonSpacing;
211 if (button_count > 1) {
212 button_spacing = (contents_width - button_width * button_count) /
213 (button_count - 1);
214 button_spacing = std::min(kMaxButtonSpacing,
215 std::max(kMinButtonSpacing, button_spacing));
216 }
217
218 button_width = (contents_width - (button_count - 1) * button_spacing) /
219 button_count;
220 button_width = std::min(kMaxButtonWidth,
221 std::max(kMinButtonWidth, button_width));
222
223 buttons_->SetLayoutManager(new views::BoxLayout(
224 views::BoxLayout::kHorizontal, gfx::Insets(0, kButtonStripPadding),
225 button_spacing));
226 for (int i = 0; i < button_count; ++i) {
227 PageSwitcherButton* button =
228 static_cast<PageSwitcherButton*>(buttons_->child_at(i));
229 button->set_button_width(button_width);
230 }
231 }
232
233 void PageSwitcher::ButtonPressed(views::Button* sender,
234 const ui::Event& event) {
235 for (int i = 0; i < buttons_->child_count(); ++i) {
236 if (sender == static_cast<views::Button*>(buttons_->child_at(i))) {
237 model_->SelectPage(i, true /* animate */);
238 break;
239 }
240 }
241 }
242
243 void PageSwitcher::TotalPagesChanged() {
244 buttons_->RemoveAllChildViews(true);
245 for (int i = 0; i < model_->total_pages(); ++i) {
246 PageSwitcherButton* button = new PageSwitcherButton(this);
247 button->SetSelectedRange(i == model_->selected_page() ? 1 : 0);
248 buttons_->AddChildView(button);
249 }
250 buttons_->SetVisible(model_->total_pages() > 1);
251 Layout();
252 }
253
254 void PageSwitcher::SelectedPageChanged(int old_selected, int new_selected) {
255 if (old_selected >= 0 && old_selected < buttons_->child_count())
256 GetButtonByIndex(buttons_, old_selected)->SetSelectedRange(0);
257 if (new_selected >= 0 && new_selected < buttons_->child_count())
258 GetButtonByIndex(buttons_, new_selected)->SetSelectedRange(1);
259 }
260
261 void PageSwitcher::TransitionStarted() {
262 }
263
264 void PageSwitcher::TransitionChanged() {
265 const int current_page = model_->selected_page();
266 const int target_page = model_->transition().target_page;
267
268 double progress = model_->transition().progress;
269 double remaining = progress - 1;
270
271 if (current_page > target_page) {
272 remaining = -remaining;
273 progress = -progress;
274 }
275
276 GetButtonByIndex(buttons_, current_page)->SetSelectedRange(remaining);
277 if (model_->is_valid_page(target_page))
278 GetButtonByIndex(buttons_, target_page)->SetSelectedRange(progress);
279 }
280
281 } // namespace app_list
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698