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

Side by Side Diff: ash/common/frame/caption_buttons/frame_caption_button_container_view.cc

Issue 2734653002: chromeos: Move files in //ash/common to //ash (Closed)
Patch Set: fix a11y tests, fix docs Created 3 years, 9 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 2013 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 "ash/common/frame/caption_buttons/frame_caption_button_container_view.h "
6
7 #include <cmath>
8 #include <map>
9
10 #include "ash/common/frame/caption_buttons/frame_caption_button.h"
11 #include "ash/common/frame/caption_buttons/frame_size_button.h"
12 #include "ash/common/wm/maximize_mode/maximize_mode_controller.h"
13 #include "ash/common/wm_shell.h"
14 #include "ui/base/hit_test.h"
15 #include "ui/base/l10n/l10n_util.h"
16 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
17 #include "ui/gfx/animation/slide_animation.h"
18 #include "ui/gfx/animation/tween.h"
19 #include "ui/gfx/canvas.h"
20 #include "ui/gfx/geometry/insets.h"
21 #include "ui/gfx/geometry/point.h"
22 #include "ui/gfx/vector_icon_types.h"
23 #include "ui/strings/grit/ui_strings.h" // Accessibility names
24 #include "ui/views/widget/widget.h"
25 #include "ui/views/widget/widget_delegate.h"
26
27 namespace ash {
28
29 namespace {
30
31 // Duration of the animation of the position of |minimize_button_|.
32 const int kPositionAnimationDurationMs = 500;
33
34 // Duration of the animation of the alpha of |size_button_|.
35 const int kAlphaAnimationDurationMs = 250;
36
37 // Delay during |maximize_mode_animation_| hide to wait before beginning to
38 // animate the position of |minimize_button_|.
39 const int kHidePositionDelayMs = 100;
40
41 // Duration of |maximize_mode_animation_| hiding.
42 // Hiding size button 250
43 // |------------------------|
44 // Delay 100 Slide minimize button 500
45 // |---------|-------------------------------------------------|
46 const int kHideAnimationDurationMs =
47 kHidePositionDelayMs + kPositionAnimationDurationMs;
48
49 // Delay during |maximize_mode_animation_| show to wait before beginning to
50 // animate the alpha of |size_button_|.
51 const int kShowAnimationAlphaDelayMs = 100;
52
53 // Duration of |maximize_mode_animation_| showing.
54 // Slide minimize button 500
55 // |-------------------------------------------------|
56 // Delay 100 Show size button 250
57 // |---------|-----------------------|
58 const int kShowAnimationDurationMs = kPositionAnimationDurationMs;
59
60 // Value of |maximize_mode_animation_| showing to begin animating alpha of
61 // |size_button_|.
62 float SizeButtonShowStartValue() {
63 return static_cast<float>(kShowAnimationAlphaDelayMs) /
64 kShowAnimationDurationMs;
65 }
66
67 // Amount of |maximize_mode_animation_| showing to animate the alpha of
68 // |size_button_|.
69 float SizeButtonShowDuration() {
70 return static_cast<float>(kAlphaAnimationDurationMs) /
71 kShowAnimationDurationMs;
72 }
73
74 // Amount of |maximize_mode_animation_| hiding to animate the alpha of
75 // |size_button_|.
76 float SizeButtonHideDuration() {
77 return static_cast<float>(kAlphaAnimationDurationMs) /
78 kHideAnimationDurationMs;
79 }
80
81 // Value of |maximize_mode_animation_| hiding to begin animating the position of
82 // |minimize_button_|.
83 float HidePositionStartValue() {
84 return 1.0f -
85 static_cast<float>(kHidePositionDelayMs) / kHideAnimationDurationMs;
86 }
87
88 // Converts |point| from |src| to |dst| and hittests against |dst|.
89 bool ConvertPointToViewAndHitTest(const views::View* src,
90 const views::View* dst,
91 const gfx::Point& point) {
92 gfx::Point converted(point);
93 views::View::ConvertPointToTarget(src, dst, &converted);
94 return dst->HitTestPoint(converted);
95 }
96
97 // Bounds animation values to the range 0.0 - 1.0. Allows for mapping of offset
98 // animations to the expected range so that gfx::Tween::CalculateValue() can be
99 // used.
100 double CapAnimationValue(double value) {
101 return std::min(1.0, std::max(0.0, value));
102 }
103
104 } // namespace
105
106 // static
107 const char FrameCaptionButtonContainerView::kViewClassName[] =
108 "FrameCaptionButtonContainerView";
109
110 FrameCaptionButtonContainerView::FrameCaptionButtonContainerView(
111 views::Widget* frame)
112 : frame_(frame),
113 minimize_button_(NULL),
114 size_button_(NULL),
115 close_button_(NULL) {
116 bool size_button_visibility = ShouldSizeButtonBeVisible();
117 maximize_mode_animation_.reset(new gfx::SlideAnimation(this));
118 maximize_mode_animation_->SetTweenType(gfx::Tween::LINEAR);
119
120 // Ensure animation tracks visibility of size button.
121 if (size_button_visibility)
122 maximize_mode_animation_->Reset(1.0f);
123
124 // Insert the buttons left to right.
125 minimize_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_MINIMIZE);
126 minimize_button_->SetAccessibleName(
127 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MINIMIZE));
128 minimize_button_->SetVisible(frame_->widget_delegate()->CanMinimize());
129 AddChildView(minimize_button_);
130
131 size_button_ = new FrameSizeButton(this, frame, this);
132 size_button_->SetAccessibleName(
133 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MAXIMIZE));
134 size_button_->SetVisible(size_button_visibility);
135 AddChildView(size_button_);
136
137 close_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_CLOSE);
138 close_button_->SetAccessibleName(
139 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE));
140 AddChildView(close_button_);
141 }
142
143 FrameCaptionButtonContainerView::~FrameCaptionButtonContainerView() {}
144
145 void FrameCaptionButtonContainerView::TestApi::EndAnimations() {
146 container_view_->maximize_mode_animation_->End();
147 }
148
149 void FrameCaptionButtonContainerView::SetButtonImage(
150 CaptionButtonIcon icon,
151 const gfx::VectorIcon& icon_definition) {
152 button_icon_map_[icon] = &icon_definition;
153
154 FrameCaptionButton* buttons[] = {minimize_button_, size_button_,
155 close_button_};
156 for (size_t i = 0; i < arraysize(buttons); ++i) {
157 if (buttons[i]->icon() == icon)
158 buttons[i]->SetImage(icon, FrameCaptionButton::ANIMATE_NO,
159 icon_definition);
160 }
161 }
162
163 void FrameCaptionButtonContainerView::SetPaintAsActive(bool paint_as_active) {
164 minimize_button_->set_paint_as_active(paint_as_active);
165 size_button_->set_paint_as_active(paint_as_active);
166 close_button_->set_paint_as_active(paint_as_active);
167 }
168
169 void FrameCaptionButtonContainerView::SetUseLightImages(bool light) {
170 minimize_button_->set_use_light_images(light);
171 size_button_->set_use_light_images(light);
172 close_button_->set_use_light_images(light);
173 }
174
175 void FrameCaptionButtonContainerView::ResetWindowControls() {
176 SetButtonsToNormal(ANIMATE_NO);
177 }
178
179 int FrameCaptionButtonContainerView::NonClientHitTest(
180 const gfx::Point& point) const {
181 if (close_button_->visible() &&
182 ConvertPointToViewAndHitTest(this, close_button_, point)) {
183 return HTCLOSE;
184 } else if (size_button_->visible() &&
185 ConvertPointToViewAndHitTest(this, size_button_, point)) {
186 return HTMAXBUTTON;
187 } else if (minimize_button_->visible() &&
188 ConvertPointToViewAndHitTest(this, minimize_button_, point)) {
189 return HTMINBUTTON;
190 }
191 return HTNOWHERE;
192 }
193
194 void FrameCaptionButtonContainerView::UpdateSizeButtonVisibility() {
195 bool visible = ShouldSizeButtonBeVisible();
196 if (visible) {
197 size_button_->SetVisible(true);
198 maximize_mode_animation_->SetSlideDuration(kShowAnimationDurationMs);
199 maximize_mode_animation_->Show();
200 } else {
201 maximize_mode_animation_->SetSlideDuration(kHideAnimationDurationMs);
202 maximize_mode_animation_->Hide();
203 }
204 }
205
206 void FrameCaptionButtonContainerView::SetButtonSize(const gfx::Size& size) {
207 minimize_button_->set_size(size);
208 size_button_->set_size(size);
209 close_button_->set_size(size);
210 }
211
212 gfx::Size FrameCaptionButtonContainerView::GetPreferredSize() const {
213 int width = 0;
214 for (int i = 0; i < child_count(); ++i) {
215 const views::View* child = child_at(i);
216 if (child->visible())
217 width += child_at(i)->GetPreferredSize().width();
218 }
219 return gfx::Size(width, close_button_->GetPreferredSize().height());
220 }
221
222 void FrameCaptionButtonContainerView::Layout() {
223 int x = 0;
224 for (int i = 0; i < child_count(); ++i) {
225 views::View* child = child_at(i);
226 if (!child->visible())
227 continue;
228
229 gfx::Size size = child->GetPreferredSize();
230 child->SetBounds(x, 0, size.width(), size.height());
231 x += size.width();
232 }
233 if (maximize_mode_animation_->is_animating()) {
234 AnimationProgressed(maximize_mode_animation_.get());
235 }
236 }
237
238 const char* FrameCaptionButtonContainerView::GetClassName() const {
239 return kViewClassName;
240 }
241
242 void FrameCaptionButtonContainerView::AnimationEnded(
243 const gfx::Animation* animation) {
244 // Ensure that position is calculated at least once.
245 AnimationProgressed(animation);
246
247 double current_value = maximize_mode_animation_->GetCurrentValue();
248 if (current_value == 0.0) {
249 size_button_->SetVisible(false);
250 PreferredSizeChanged();
251 }
252 }
253
254 void FrameCaptionButtonContainerView::AnimationProgressed(
255 const gfx::Animation* animation) {
256 double current_value = animation->GetCurrentValue();
257 int size_alpha = 0;
258 int minimize_x = 0;
259 if (maximize_mode_animation_->IsShowing()) {
260 double scaled_value =
261 CapAnimationValue((current_value - SizeButtonShowStartValue()) /
262 SizeButtonShowDuration());
263 double tweened_value_alpha =
264 gfx::Tween::CalculateValue(gfx::Tween::EASE_OUT, scaled_value);
265 size_alpha = gfx::Tween::LinearIntValueBetween(tweened_value_alpha, 0, 255);
266
267 double tweened_value_slide =
268 gfx::Tween::CalculateValue(gfx::Tween::EASE_OUT, current_value);
269 minimize_x = gfx::Tween::LinearIntValueBetween(tweened_value_slide,
270 size_button_->x(), 0);
271 } else {
272 double scaled_value_alpha =
273 CapAnimationValue((1.0f - current_value) / SizeButtonHideDuration());
274 double tweened_value_alpha =
275 gfx::Tween::CalculateValue(gfx::Tween::EASE_IN, scaled_value_alpha);
276 size_alpha = gfx::Tween::LinearIntValueBetween(tweened_value_alpha, 255, 0);
277
278 double scaled_value_position = CapAnimationValue(
279 (HidePositionStartValue() - current_value) / HidePositionStartValue());
280 double tweened_value_position =
281 gfx::Tween::CalculateValue(gfx::Tween::EASE_OUT, scaled_value_position);
282 minimize_x = gfx::Tween::LinearIntValueBetween(tweened_value_position, 0,
283 size_button_->x());
284 }
285 size_button_->SetAlpha(size_alpha);
286 minimize_button_->SetX(minimize_x);
287 }
288
289 void FrameCaptionButtonContainerView::SetButtonIcon(FrameCaptionButton* button,
290 CaptionButtonIcon icon,
291 Animate animate) {
292 // The early return is dependant on |animate| because callers use
293 // SetButtonIcon() with ANIMATE_NO to progress |button|'s crossfade animation
294 // to the end.
295 if (button->icon() == icon &&
296 (animate == ANIMATE_YES || !button->IsAnimatingImageSwap())) {
297 return;
298 }
299
300 FrameCaptionButton::Animate fcb_animate =
301 (animate == ANIMATE_YES) ? FrameCaptionButton::ANIMATE_YES
302 : FrameCaptionButton::ANIMATE_NO;
303 auto it = button_icon_map_.find(icon);
304 if (it != button_icon_map_.end())
305 button->SetImage(icon, fcb_animate, *it->second);
306 }
307
308 bool FrameCaptionButtonContainerView::ShouldSizeButtonBeVisible() const {
309 return !WmShell::Get()
310 ->maximize_mode_controller()
311 ->IsMaximizeModeWindowManagerEnabled() &&
312 frame_->widget_delegate()->CanMaximize();
313 }
314
315 void FrameCaptionButtonContainerView::ButtonPressed(views::Button* sender,
316 const ui::Event& event) {
317 // Abort any animations of the button icons.
318 SetButtonsToNormal(ANIMATE_NO);
319
320 UserMetricsAction action = UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MINIMIZE;
321 if (sender == minimize_button_) {
322 frame_->Minimize();
323 } else if (sender == size_button_) {
324 if (frame_->IsFullscreen()) { // Can be clicked in immersive fullscreen.
325 frame_->Restore();
326 action = UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_EXIT_FULLSCREEN;
327 } else if (frame_->IsMaximized()) {
328 frame_->Restore();
329 action = UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_RESTORE;
330 } else {
331 frame_->Maximize();
332 action = UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MAXIMIZE;
333 }
334
335 if (event.IsGestureEvent())
336 WmShell::Get()->RecordGestureAction(GESTURE_FRAMEMAXIMIZE_TAP);
337 } else if (sender == close_button_) {
338 frame_->Close();
339 action = UMA_WINDOW_CLOSE_BUTTON_CLICK;
340 } else {
341 return;
342 }
343 WmShell::Get()->RecordUserMetricsAction(action);
344 }
345
346 bool FrameCaptionButtonContainerView::IsMinimizeButtonVisible() const {
347 return minimize_button_->visible();
348 }
349
350 void FrameCaptionButtonContainerView::SetButtonsToNormal(Animate animate) {
351 SetButtonIcons(CAPTION_BUTTON_ICON_MINIMIZE, CAPTION_BUTTON_ICON_CLOSE,
352 animate);
353 minimize_button_->SetState(views::Button::STATE_NORMAL);
354 size_button_->SetState(views::Button::STATE_NORMAL);
355 close_button_->SetState(views::Button::STATE_NORMAL);
356 }
357
358 void FrameCaptionButtonContainerView::SetButtonIcons(
359 CaptionButtonIcon minimize_button_icon,
360 CaptionButtonIcon close_button_icon,
361 Animate animate) {
362 SetButtonIcon(minimize_button_, minimize_button_icon, animate);
363 SetButtonIcon(close_button_, close_button_icon, animate);
364 }
365
366 const FrameCaptionButton* FrameCaptionButtonContainerView::GetButtonClosestTo(
367 const gfx::Point& position_in_screen) const {
368 // Since the buttons all have the same size, the closest button is the button
369 // with the center point closest to |position_in_screen|.
370 // TODO(pkotwicz): Make the caption buttons not overlap.
371 gfx::Point position(position_in_screen);
372 views::View::ConvertPointFromScreen(this, &position);
373
374 FrameCaptionButton* buttons[] = {minimize_button_, size_button_,
375 close_button_};
376 int min_squared_distance = INT_MAX;
377 FrameCaptionButton* closest_button = NULL;
378 for (size_t i = 0; i < arraysize(buttons); ++i) {
379 FrameCaptionButton* button = buttons[i];
380 if (!button->visible())
381 continue;
382
383 gfx::Point center_point = button->GetLocalBounds().CenterPoint();
384 views::View::ConvertPointToTarget(button, this, &center_point);
385 int squared_distance = static_cast<int>(
386 pow(static_cast<double>(position.x() - center_point.x()), 2) +
387 pow(static_cast<double>(position.y() - center_point.y()), 2));
388 if (squared_distance < min_squared_distance) {
389 min_squared_distance = squared_distance;
390 closest_button = button;
391 }
392 }
393 return closest_button;
394 }
395
396 void FrameCaptionButtonContainerView::SetHoveredAndPressedButtons(
397 const FrameCaptionButton* to_hover,
398 const FrameCaptionButton* to_press) {
399 FrameCaptionButton* buttons[] = {minimize_button_, size_button_,
400 close_button_};
401 for (size_t i = 0; i < arraysize(buttons); ++i) {
402 FrameCaptionButton* button = buttons[i];
403 views::Button::ButtonState new_state = views::Button::STATE_NORMAL;
404 if (button == to_hover)
405 new_state = views::Button::STATE_HOVERED;
406 else if (button == to_press)
407 new_state = views::Button::STATE_PRESSED;
408 button->SetState(new_state);
409 }
410 }
411
412 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698