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

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

Issue 316693002: Reland Window Control Animations for TouchView (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix and Unit Test Created 6 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
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ash/frame/caption_buttons/frame_caption_button_container_view.h" 5 #include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
6 6
7 #include <cmath> 7 #include <cmath>
8 #include <map>
8 9
9 #include "ash/ash_switches.h" 10 #include "ash/ash_switches.h"
10 #include "ash/frame/caption_buttons/frame_caption_button.h" 11 #include "ash/frame/caption_buttons/frame_caption_button.h"
11 #include "ash/frame/caption_buttons/frame_size_button.h" 12 #include "ash/frame/caption_buttons/frame_size_button.h"
12 #include "ash/metrics/user_metrics_recorder.h" 13 #include "ash/metrics/user_metrics_recorder.h"
13 #include "ash/shell.h" 14 #include "ash/shell.h"
14 #include "grit/ui_strings.h" // Accessibility names 15 #include "grit/ui_strings.h" // Accessibility names
15 #include "ui/base/hit_test.h" 16 #include "ui/base/hit_test.h"
16 #include "ui/base/l10n/l10n_util.h" 17 #include "ui/base/l10n/l10n_util.h"
18 #include "ui/compositor/layer.h"
17 #include "ui/compositor/scoped_animation_duration_scale_mode.h" 19 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
20 #include "ui/compositor/scoped_layer_animation_settings.h"
21 #include "ui/gfx/animation/tween.h"
18 #include "ui/gfx/canvas.h" 22 #include "ui/gfx/canvas.h"
19 #include "ui/gfx/insets.h" 23 #include "ui/gfx/insets.h"
20 #include "ui/gfx/point.h" 24 #include "ui/gfx/point.h"
21 #include "ui/views/widget/widget.h" 25 #include "ui/views/widget/widget.h"
22 #include "ui/views/widget/widget_delegate.h" 26 #include "ui/views/widget/widget_delegate.h"
23 27
24 namespace ash { 28 namespace ash {
25 29
26 namespace { 30 namespace {
27 31
32 // Visual design parameters for animating the transition to maximize mode.
33 // When the size button hides we delay sliding the minimize button into its
34 // location. Also used to delay showing the size button so that the minimize
35 // button slides out of that position.
36 const int kAnimationDelayMs = 100;
37 const int kMinimizeSlideDurationMs = 500;
38 const int kSizeFadeDurationMs = 250;
39
28 // Converts |point| from |src| to |dst| and hittests against |dst|. 40 // Converts |point| from |src| to |dst| and hittests against |dst|.
29 bool ConvertPointToViewAndHitTest(const views::View* src, 41 bool ConvertPointToViewAndHitTest(const views::View* src,
30 const views::View* dst, 42 const views::View* dst,
31 const gfx::Point& point) { 43 const gfx::Point& point) {
32 gfx::Point converted(point); 44 gfx::Point converted(point);
33 views::View::ConvertPointToTarget(src, dst, &converted); 45 views::View::ConvertPointToTarget(src, dst, &converted);
34 return dst->HitTestPoint(converted); 46 return dst->HitTestPoint(converted);
35 } 47 }
36 48
37 } // namespace 49 } // namespace
38 50
39 // static 51 // static
40 const char FrameCaptionButtonContainerView::kViewClassName[] = 52 const char FrameCaptionButtonContainerView::kViewClassName[] =
41 "FrameCaptionButtonContainerView"; 53 "FrameCaptionButtonContainerView";
42 54
43 FrameCaptionButtonContainerView::FrameCaptionButtonContainerView( 55 FrameCaptionButtonContainerView::FrameCaptionButtonContainerView(
44 views::Widget* frame, 56 views::Widget* frame,
45 MinimizeAllowed minimize_allowed) 57 MinimizeAllowed minimize_allowed)
46 : frame_(frame), 58 : frame_(frame),
47 minimize_button_(NULL), 59 minimize_button_(NULL),
48 size_button_(NULL), 60 size_button_(NULL),
49 close_button_(NULL) { 61 close_button_(NULL) {
62 SetPaintToLayer(true);
63 SetFillsBoundsOpaquely(false);
64 set_layer_owner_delegate(this);
65
50 // Insert the buttons left to right. 66 // Insert the buttons left to right.
51 minimize_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_MINIMIZE); 67 minimize_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_MINIMIZE);
52 minimize_button_->SetAccessibleName( 68 minimize_button_->SetAccessibleName(
53 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MINIMIZE)); 69 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MINIMIZE));
54 minimize_button_->SetVisible(minimize_allowed == MINIMIZE_ALLOWED); 70 minimize_button_->SetVisible(minimize_allowed == MINIMIZE_ALLOWED);
71 minimize_button_->SetPaintToLayer(true);
72 minimize_button_->SetFillsBoundsOpaquely(false);
73 minimize_button_->set_layer_owner_delegate(this);
55 AddChildView(minimize_button_); 74 AddChildView(minimize_button_);
56 75
57 size_button_ = new FrameSizeButton(this, frame, this); 76 size_button_ = new FrameSizeButton(this, frame, this);
58 size_button_->SetAccessibleName( 77 size_button_->SetAccessibleName(
59 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MAXIMIZE)); 78 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MAXIMIZE));
79 size_button_->SetPaintToLayer(true);
80 size_button_->SetFillsBoundsOpaquely(false);
81 size_button_->set_layer_owner_delegate(this);
60 UpdateSizeButtonVisibility(false); 82 UpdateSizeButtonVisibility(false);
61 AddChildView(size_button_); 83 AddChildView(size_button_);
62 84
63 close_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_CLOSE); 85 close_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_CLOSE);
64 close_button_->SetAccessibleName( 86 close_button_->SetAccessibleName(
65 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE)); 87 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE));
88 close_button_->SetPaintToLayer(true);
89 close_button_->SetFillsBoundsOpaquely(false);
90 close_button_->set_layer_owner_delegate(this);
66 AddChildView(close_button_); 91 AddChildView(close_button_);
67 } 92 }
68 93
69 FrameCaptionButtonContainerView::~FrameCaptionButtonContainerView() { 94 FrameCaptionButtonContainerView::~FrameCaptionButtonContainerView() {
70 } 95 }
71 96
72 void FrameCaptionButtonContainerView::SetButtonImages( 97 void FrameCaptionButtonContainerView::SetButtonImages(
73 CaptionButtonIcon icon, 98 CaptionButtonIcon icon,
74 int icon_image_id, 99 int icon_image_id,
75 int inactive_icon_image_id, 100 int inactive_icon_image_id,
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 } 145 }
121 146
122 void FrameCaptionButtonContainerView::UpdateSizeButtonVisibility( 147 void FrameCaptionButtonContainerView::UpdateSizeButtonVisibility(
123 bool force_hidden) { 148 bool force_hidden) {
124 // TODO(flackr): Refactor the Maximize Mode notifications. Currently 149 // TODO(flackr): Refactor the Maximize Mode notifications. Currently
125 // UpdateSizeButtonVisibilty requires a force_hidden parameter. This is 150 // UpdateSizeButtonVisibilty requires a force_hidden parameter. This is
126 // because Shell::IsMaximizeWindowManagerEnabled is still false at the 151 // because Shell::IsMaximizeWindowManagerEnabled is still false at the
127 // time when ShellObserver::OnMaximizeModeStarted is called. This prevents 152 // time when ShellObserver::OnMaximizeModeStarted is called. This prevents
128 // this method from performing that check, and instead relies on the calling 153 // this method from performing that check, and instead relies on the calling
129 // code to tell it to force being hidden. 154 // code to tell it to force being hidden.
130 size_button_->SetVisible( 155
131 !force_hidden && frame_->widget_delegate()->CanMaximize()); 156 bool visible = !force_hidden && frame_->widget_delegate()->CanMaximize();
157
158 // Turning visibility off prevents animations from rendering. Setting the
159 // size button visibility to false will occur after the animation.
160 if (visible) {
161 size_button_->SetVisible(true);
162 // Because we delay calling View::SetVisible(false) until the end of the
163 // animation, if SetVisible(true) is called mid-animation, the View still
164 // believes it is visible and will not update the target layer visibility.
165 size_button_->layer()->SetVisible(true);
166 }
167
168 ui::ScopedLayerAnimationSettings settings(
169 size_button_->layer()->GetAnimator());
170 settings.SetTransitionDuration(
171 base::TimeDelta::FromMilliseconds(kSizeFadeDurationMs));
172 settings.SetPreemptionStrategy(
173 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
174
175 if (visible) {
176 settings.SetTweenType(gfx::Tween::EASE_OUT);
177 // Delay fade in so that the minimize button has begun its sliding
178 // animation.
179 size_button_->layer()->GetAnimator()->SchedulePauseForProperties(
180 base::TimeDelta::FromMilliseconds(kAnimationDelayMs),
181 ui::LayerAnimationElement::OPACITY);
182 size_button_->layer()->SetOpacity(1.0f);
183 } else {
184 settings.SetTweenType(gfx::Tween::EASE_IN);
185 // Observer will call size_button_->SetVisible(false) upon completion of
186 // the animation.
187 // TODO(jonross): avoid the delayed SetVisible(false) call by acquring
188 // the size_button's layer before making it invisible. That layer can then
189 // be animated and deleted upon completion of the animation. See
190 // LayerOwner::RecreateLayer
191 settings.AddObserver(this);
192 size_button_->layer()->SetOpacity(0.0f);
193 size_button_->layer()->SetVisible(false);
194 }
132 } 195 }
133 196
134 gfx::Size FrameCaptionButtonContainerView::GetPreferredSize() const { 197 gfx::Size FrameCaptionButtonContainerView::GetPreferredSize() const {
135 int width = 0; 198 int width = 0;
136 for (int i = 0; i < child_count(); ++i) { 199 for (int i = 0; i < child_count(); ++i) {
137 const views::View* child = child_at(i); 200 const views::View* child = child_at(i);
138 if (child->visible()) 201 if (child->visible())
139 width += child_at(i)->GetPreferredSize().width(); 202 width += child_at(i)->GetPreferredSize().width();
140 } 203 }
141 return gfx::Size(width, close_button_->GetPreferredSize().height()); 204 return gfx::Size(width, close_button_->GetPreferredSize().height());
142 } 205 }
143 206
144 void FrameCaptionButtonContainerView::Layout() { 207 void FrameCaptionButtonContainerView::Layout() {
145 int x = 0; 208 int x = width();
146 for (int i = 0; i < child_count(); ++i) { 209 // Offsets the initial position of a child, so that buttons slide into the
210 // place as other buttons are added/removed.
211 int offset_x = 0;
212 for (int i = child_count() - 1; i >= 0; --i) {
147 views::View* child = child_at(i); 213 views::View* child = child_at(i);
148 if (!child->visible()) 214 ui::LayerAnimator* child_animator = child->layer()->GetAnimator();
215 bool child_animating = child_animator->is_animating();
216 // The actual property visibility is not being animated, otherwise the
217 // view does not render.
218 bool child_animating_opacity = child_animator->
219 IsAnimatingProperty(ui::LayerAnimationElement::OPACITY);
220 bool child_target_visibility = child->layer()->GetTargetVisibility();
221
222 if (child_animating_opacity) {
223 if (child_target_visibility)
224 offset_x += child->width();
225 else
226 offset_x -= child->width();
227 }
228
229 if (!child->visible() || !child_target_visibility)
149 continue; 230 continue;
150 231
232 scoped_ptr<ui::ScopedLayerAnimationSettings> animation;
151 gfx::Size size = child->GetPreferredSize(); 233 gfx::Size size = child->GetPreferredSize();
234 x -= size.width();
235
236 // Animate the button if a previous button is currently animating
237 // its visibility.
238 if (offset_x != 0) {
239 if (!child_animating)
240 child->SetBounds(x + offset_x, 0, size.width(), size.height());
241 if (offset_x < 0) {
242 // Delay sliding to where the previous button was located.
243 child_animator->SchedulePauseForProperties(
244 base::TimeDelta::FromMilliseconds(kAnimationDelayMs),
245 ui::LayerAnimationElement::BOUNDS);
246 }
247
248 ui::ScopedLayerAnimationSettings* settings =
249 new ui::ScopedLayerAnimationSettings(child_animator);
250 settings->SetTransitionDuration(
251 base::TimeDelta::FromMilliseconds(kMinimizeSlideDurationMs));
252 settings->SetPreemptionStrategy(
253 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
254 settings->SetTweenType(gfx::Tween::EASE_OUT);
255 animation.reset(settings);
256 }
152 child->SetBounds(x, 0, size.width(), size.height()); 257 child->SetBounds(x, 0, size.width(), size.height());
153 x += size.width();
154 } 258 }
155 } 259 }
156 260
157 const char* FrameCaptionButtonContainerView::GetClassName() const { 261 const char* FrameCaptionButtonContainerView::GetClassName() const {
158 return kViewClassName; 262 return kViewClassName;
159 } 263 }
160 264
161 void FrameCaptionButtonContainerView::SetButtonIcon(FrameCaptionButton* button, 265 void FrameCaptionButtonContainerView::SetButtonIcon(FrameCaptionButton* button,
162 CaptionButtonIcon icon, 266 CaptionButtonIcon icon,
163 Animate animate) { 267 Animate animate) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 } 299 }
196 300
197 // Abort any animations of the button icons. 301 // Abort any animations of the button icons.
198 SetButtonsToNormal(ANIMATE_NO); 302 SetButtonsToNormal(ANIMATE_NO);
199 303
200 ash::UserMetricsAction action = 304 ash::UserMetricsAction action =
201 ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MINIMIZE; 305 ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MINIMIZE;
202 if (sender == minimize_button_) { 306 if (sender == minimize_button_) {
203 frame_->Minimize(); 307 frame_->Minimize();
204 } else if (sender == size_button_) { 308 } else if (sender == size_button_) {
205 if (frame_->IsFullscreen()) { // Can be clicked in immersive fullscreen. 309 if (frame_->IsFullscreen()) { // Can be clicked in immersive fullscreen.
206 frame_->SetFullscreen(false); 310 frame_->SetFullscreen(false);
207 action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_EXIT_FULLSCREEN; 311 action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_EXIT_FULLSCREEN;
208 } else if (frame_->IsMaximized()) { 312 } else if (frame_->IsMaximized()) {
209 frame_->Restore(); 313 frame_->Restore();
210 action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_RESTORE; 314 action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_RESTORE;
211 } else { 315 } else {
212 frame_->Maximize(); 316 frame_->Maximize();
213 action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MAXIMIZE; 317 action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MAXIMIZE;
214 } 318 }
215 } else if(sender == close_button_) { 319 } else if (sender == close_button_) {
216 frame_->Close(); 320 frame_->Close();
217 action = ash::UMA_WINDOW_CLOSE_BUTTON_CLICK; 321 action = ash::UMA_WINDOW_CLOSE_BUTTON_CLICK;
218 } else { 322 } else {
219 return; 323 return;
220 } 324 }
221 ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction(action); 325 ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction(action);
222 } 326 }
223 327
224 bool FrameCaptionButtonContainerView::IsMinimizeButtonVisible() const { 328 bool FrameCaptionButtonContainerView::IsMinimizeButtonVisible() const {
225 return minimize_button_->visible(); 329 return minimize_button_->visible();
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
282 FrameCaptionButton* button = buttons[i]; 386 FrameCaptionButton* button = buttons[i];
283 views::Button::ButtonState new_state = views::Button::STATE_NORMAL; 387 views::Button::ButtonState new_state = views::Button::STATE_NORMAL;
284 if (button == to_hover) 388 if (button == to_hover)
285 new_state = views::Button::STATE_HOVERED; 389 new_state = views::Button::STATE_HOVERED;
286 else if (button == to_press) 390 else if (button == to_press)
287 new_state = views::Button::STATE_PRESSED; 391 new_state = views::Button::STATE_PRESSED;
288 button->SetState(new_state); 392 button->SetState(new_state);
289 } 393 }
290 } 394 }
291 395
396 void FrameCaptionButtonContainerView::OnImplicitAnimationsCompleted() {
397 // If there is another animation in the queue, the reverse animation was
398 // triggered before the completion of animating to invisible. Do not turn off
399 // the visibility so that the next animation may render.
400 if (!size_button_->layer()->GetAnimator()->is_animating() &&
401 !size_button_->layer()->GetTargetVisibility()) {
402 size_button_->SetVisible(false);
403 }
404 // TODO(jonross): currently we need to delay telling the parent about the
405 // size change from visibility. When the size changes this forces a relayout
406 // and we want to animate both the bounds of FrameCaptionButtonContainerView
407 // along with that of its children. However when the parent is currently
408 // having its bounds changed this leads to strange animations where this view
409 // renders outside of its parents. Create a more specific animation where
410 // height and y are immediately fixed, and where we only animate width and x.
411 PreferredSizeChanged();
412 }
413
414 void FrameCaptionButtonContainerView::OnLayerRecreated(ui::Layer* old_layer,
415 ui::Layer* new_layer) {
416 if (new_layer == layer())
417 GetWidget()->UpdateRootLayers();
418 if (new_layer == minimize_button_->layer());
419 minimize_button_->GetWidget()->UpdateRootLayers();
420 if (new_layer == size_button_->layer())
421 size_button_->GetWidget()->UpdateRootLayers();
422 if (new_layer == close_button_->layer())
423 close_button_->GetWidget()->UpdateRootLayers();
flackr 2014/06/04 22:41:44 I think it'd make more sense for FrameCaptionButto
jonross 2014/06/05 15:16:39 Done.
424 GetWidget()->UpdateRootLayers();
425 }
426
292 FrameCaptionButtonContainerView::ButtonIconIds::ButtonIconIds() 427 FrameCaptionButtonContainerView::ButtonIconIds::ButtonIconIds()
293 : icon_image_id(-1), 428 : icon_image_id(-1),
294 inactive_icon_image_id(-1), 429 inactive_icon_image_id(-1),
295 hovered_background_image_id(-1), 430 hovered_background_image_id(-1),
296 pressed_background_image_id(-1) { 431 pressed_background_image_id(-1) {
297 } 432 }
298 433
299 FrameCaptionButtonContainerView::ButtonIconIds::ButtonIconIds( 434 FrameCaptionButtonContainerView::ButtonIconIds::ButtonIconIds(
300 int icon_id, 435 int icon_id,
301 int inactive_icon_id, 436 int inactive_icon_id,
302 int hovered_background_id, 437 int hovered_background_id,
303 int pressed_background_id) 438 int pressed_background_id)
304 : icon_image_id(icon_id), 439 : icon_image_id(icon_id),
305 inactive_icon_image_id(inactive_icon_id), 440 inactive_icon_image_id(inactive_icon_id),
306 hovered_background_image_id(hovered_background_id), 441 hovered_background_image_id(hovered_background_id),
307 pressed_background_image_id(pressed_background_id) { 442 pressed_background_image_id(pressed_background_id) {
308 } 443 }
309 444
310 FrameCaptionButtonContainerView::ButtonIconIds::~ButtonIconIds() { 445 FrameCaptionButtonContainerView::ButtonIconIds::~ButtonIconIds() {
311 } 446 }
312 447
313 } // namespace ash 448 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698