OLD | NEW |
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 #include <map> |
9 | 9 |
10 #include "ash/ash_switches.h" | 10 #include "ash/ash_switches.h" |
11 #include "ash/frame/caption_buttons/frame_caption_button.h" | 11 #include "ash/frame/caption_buttons/frame_caption_button.h" |
12 #include "ash/frame/caption_buttons/frame_size_button.h" | 12 #include "ash/frame/caption_buttons/frame_size_button.h" |
13 #include "ash/metrics/user_metrics_recorder.h" | 13 #include "ash/metrics/user_metrics_recorder.h" |
14 #include "ash/shell.h" | 14 #include "ash/shell.h" |
15 #include "ash/wm/maximize_mode/maximize_mode_controller.h" | 15 #include "ash/wm/maximize_mode/maximize_mode_controller.h" |
16 #include "grit/ui_strings.h" // Accessibility names | 16 #include "grit/ui_strings.h" // Accessibility names |
17 #include "ui/base/hit_test.h" | 17 #include "ui/base/hit_test.h" |
18 #include "ui/base/l10n/l10n_util.h" | 18 #include "ui/base/l10n/l10n_util.h" |
19 #include "ui/compositor/layer.h" | |
20 #include "ui/compositor/scoped_animation_duration_scale_mode.h" | 19 #include "ui/compositor/scoped_animation_duration_scale_mode.h" |
21 #include "ui/compositor/scoped_layer_animation_settings.h" | |
22 #include "ui/gfx/animation/tween.h" | |
23 #include "ui/gfx/canvas.h" | 20 #include "ui/gfx/canvas.h" |
24 #include "ui/gfx/insets.h" | 21 #include "ui/gfx/insets.h" |
25 #include "ui/gfx/point.h" | 22 #include "ui/gfx/point.h" |
26 #include "ui/views/widget/widget.h" | 23 #include "ui/views/widget/widget.h" |
27 #include "ui/views/widget/widget_delegate.h" | 24 #include "ui/views/widget/widget_delegate.h" |
28 | 25 |
29 namespace ash { | 26 namespace ash { |
30 | 27 |
31 namespace { | 28 namespace { |
32 | 29 |
33 // Visual design parameters for animating the transition to maximize mode. | |
34 // When the size button hides we delay sliding the minimize button into its | |
35 // location. Also used to delay showing the size button so that the minimize | |
36 // button slides out of that position. | |
37 const int kAnimationDelayMs = 100; | |
38 const int kMinimizeSlideDurationMs = 500; | |
39 const int kSizeFadeDurationMs = 250; | |
40 | |
41 // Converts |point| from |src| to |dst| and hittests against |dst|. | 30 // Converts |point| from |src| to |dst| and hittests against |dst|. |
42 bool ConvertPointToViewAndHitTest(const views::View* src, | 31 bool ConvertPointToViewAndHitTest(const views::View* src, |
43 const views::View* dst, | 32 const views::View* dst, |
44 const gfx::Point& point) { | 33 const gfx::Point& point) { |
45 gfx::Point converted(point); | 34 gfx::Point converted(point); |
46 views::View::ConvertPointToTarget(src, dst, &converted); | 35 views::View::ConvertPointToTarget(src, dst, &converted); |
47 return dst->HitTestPoint(converted); | 36 return dst->HitTestPoint(converted); |
48 } | 37 } |
49 | 38 |
50 } // namespace | 39 } // namespace |
51 | 40 |
52 // static | 41 // static |
53 const char FrameCaptionButtonContainerView::kViewClassName[] = | 42 const char FrameCaptionButtonContainerView::kViewClassName[] = |
54 "FrameCaptionButtonContainerView"; | 43 "FrameCaptionButtonContainerView"; |
55 | 44 |
56 FrameCaptionButtonContainerView::FrameCaptionButtonContainerView( | 45 FrameCaptionButtonContainerView::FrameCaptionButtonContainerView( |
57 views::Widget* frame, | 46 views::Widget* frame, |
58 MinimizeAllowed minimize_allowed) | 47 MinimizeAllowed minimize_allowed) |
59 : frame_(frame), | 48 : frame_(frame), |
60 minimize_button_(NULL), | 49 minimize_button_(NULL), |
61 size_button_(NULL), | 50 size_button_(NULL), |
62 close_button_(NULL) { | 51 close_button_(NULL) { |
63 SetPaintToLayer(true); | |
64 SetFillsBoundsOpaquely(false); | |
65 set_layer_owner_delegate(this); | |
66 | |
67 // Insert the buttons left to right. | 52 // Insert the buttons left to right. |
68 minimize_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_MINIMIZE); | 53 minimize_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_MINIMIZE); |
69 minimize_button_->SetAccessibleName( | 54 minimize_button_->SetAccessibleName( |
70 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MINIMIZE)); | 55 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MINIMIZE)); |
71 minimize_button_->SetVisible(minimize_allowed == MINIMIZE_ALLOWED); | 56 minimize_button_->SetVisible(minimize_allowed == MINIMIZE_ALLOWED); |
72 AddChildView(minimize_button_); | 57 AddChildView(minimize_button_); |
73 | 58 |
74 size_button_ = new FrameSizeButton(this, frame, this); | 59 size_button_ = new FrameSizeButton(this, frame, this); |
75 size_button_->SetAccessibleName( | 60 size_button_->SetAccessibleName( |
76 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MAXIMIZE)); | 61 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MAXIMIZE)); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
130 ConvertPointToViewAndHitTest(this, size_button_, point)) { | 115 ConvertPointToViewAndHitTest(this, size_button_, point)) { |
131 return HTMAXBUTTON; | 116 return HTMAXBUTTON; |
132 } else if (minimize_button_->visible() && | 117 } else if (minimize_button_->visible() && |
133 ConvertPointToViewAndHitTest(this, minimize_button_, point)) { | 118 ConvertPointToViewAndHitTest(this, minimize_button_, point)) { |
134 return HTMINBUTTON; | 119 return HTMINBUTTON; |
135 } | 120 } |
136 return HTNOWHERE; | 121 return HTNOWHERE; |
137 } | 122 } |
138 | 123 |
139 void FrameCaptionButtonContainerView::UpdateSizeButtonVisibility() { | 124 void FrameCaptionButtonContainerView::UpdateSizeButtonVisibility() { |
140 bool visible = !Shell::GetInstance()->maximize_mode_controller()-> | 125 size_button_->SetVisible( |
| 126 !Shell::GetInstance()->maximize_mode_controller()-> |
141 IsMaximizeModeWindowManagerEnabled() && | 127 IsMaximizeModeWindowManagerEnabled() && |
142 frame_->widget_delegate()->CanMaximize(); | 128 frame_->widget_delegate()->CanMaximize()); |
143 | |
144 // Turning visibility off prevents animations from rendering. Setting the | |
145 // size button visibility to false will occur after the animation. | |
146 if (visible) { | |
147 size_button_->SetVisible(true); | |
148 // Because we delay calling View::SetVisible(false) until the end of the | |
149 // animation, if SetVisible(true) is called mid-animation, the View still | |
150 // believes it is visible and will not update the target layer visibility. | |
151 size_button_->layer()->SetVisible(true); | |
152 } | |
153 | |
154 ui::ScopedLayerAnimationSettings settings( | |
155 size_button_->layer()->GetAnimator()); | |
156 settings.SetTransitionDuration( | |
157 base::TimeDelta::FromMilliseconds(kSizeFadeDurationMs)); | |
158 settings.SetPreemptionStrategy( | |
159 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | |
160 | |
161 if (visible) { | |
162 settings.SetTweenType(gfx::Tween::EASE_OUT); | |
163 // Delay fade in so that the minimize button has begun its sliding | |
164 // animation. | |
165 size_button_->layer()->GetAnimator()->SchedulePauseForProperties( | |
166 base::TimeDelta::FromMilliseconds(kAnimationDelayMs), | |
167 ui::LayerAnimationElement::OPACITY); | |
168 size_button_->layer()->SetOpacity(1.0f); | |
169 } else { | |
170 settings.SetTweenType(gfx::Tween::EASE_IN); | |
171 // Observer will call size_button_->SetVisible(false) upon completion of | |
172 // the animation. | |
173 // TODO(jonross): avoid the delayed SetVisible(false) call by acquring | |
174 // the size_button's layer before making it invisible. That layer can then | |
175 // be animated and deleted upon completion of the animation. See | |
176 // LayerOwner::RecreateLayer | |
177 settings.AddObserver(this); | |
178 size_button_->layer()->SetOpacity(0.0f); | |
179 size_button_->layer()->SetVisible(false); | |
180 } | |
181 } | 129 } |
182 | 130 |
183 gfx::Size FrameCaptionButtonContainerView::GetPreferredSize() const { | 131 gfx::Size FrameCaptionButtonContainerView::GetPreferredSize() const { |
184 int width = 0; | 132 int width = 0; |
185 for (int i = 0; i < child_count(); ++i) { | 133 for (int i = 0; i < child_count(); ++i) { |
186 const views::View* child = child_at(i); | 134 const views::View* child = child_at(i); |
187 if (child->visible()) | 135 if (child->visible()) |
188 width += child_at(i)->GetPreferredSize().width(); | 136 width += child_at(i)->GetPreferredSize().width(); |
189 } | 137 } |
190 return gfx::Size(width, close_button_->GetPreferredSize().height()); | 138 return gfx::Size(width, close_button_->GetPreferredSize().height()); |
191 } | 139 } |
192 | 140 |
193 void FrameCaptionButtonContainerView::Layout() { | 141 void FrameCaptionButtonContainerView::Layout() { |
194 int x = width(); | 142 int x = 0; |
195 // Offsets the initial position of a child, so that buttons slide into the | 143 for (int i = 0; i < child_count(); ++i) { |
196 // place as other buttons are added/removed. | |
197 int offset_x = 0; | |
198 for (int i = child_count() - 1; i >= 0; --i) { | |
199 views::View* child = child_at(i); | 144 views::View* child = child_at(i); |
200 ui::LayerAnimator* child_animator = child->layer()->GetAnimator(); | 145 if (!child->visible()) |
201 bool child_animating = child_animator->is_animating(); | |
202 // The actual property visibility is not being animated, otherwise the | |
203 // view does not render. | |
204 bool child_animating_opacity = child_animator-> | |
205 IsAnimatingProperty(ui::LayerAnimationElement::OPACITY); | |
206 bool child_target_visibility = child->layer()->GetTargetVisibility(); | |
207 | |
208 if (child_animating_opacity) { | |
209 if (child_target_visibility) | |
210 offset_x += child->width(); | |
211 else | |
212 offset_x -= child->width(); | |
213 } | |
214 | |
215 if (!child->visible() || !child_target_visibility) | |
216 continue; | 146 continue; |
217 | 147 |
218 scoped_ptr<ui::ScopedLayerAnimationSettings> animation; | |
219 gfx::Size size = child->GetPreferredSize(); | 148 gfx::Size size = child->GetPreferredSize(); |
220 x -= size.width(); | |
221 | |
222 // Animate the button if a previous button is currently animating | |
223 // its visibility. | |
224 if (offset_x != 0) { | |
225 if (!child_animating) | |
226 child->SetBounds(x + offset_x, 0, size.width(), size.height()); | |
227 if (offset_x < 0) { | |
228 // Delay sliding to where the previous button was located. | |
229 child_animator->SchedulePauseForProperties( | |
230 base::TimeDelta::FromMilliseconds(kAnimationDelayMs), | |
231 ui::LayerAnimationElement::BOUNDS); | |
232 } | |
233 | |
234 ui::ScopedLayerAnimationSettings* settings = | |
235 new ui::ScopedLayerAnimationSettings(child_animator); | |
236 settings->SetTransitionDuration( | |
237 base::TimeDelta::FromMilliseconds(kMinimizeSlideDurationMs)); | |
238 settings->SetPreemptionStrategy( | |
239 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | |
240 settings->SetTweenType(gfx::Tween::EASE_OUT); | |
241 animation.reset(settings); | |
242 } | |
243 child->SetBounds(x, 0, size.width(), size.height()); | 149 child->SetBounds(x, 0, size.width(), size.height()); |
| 150 x += size.width(); |
244 } | 151 } |
245 } | 152 } |
246 | 153 |
247 const char* FrameCaptionButtonContainerView::GetClassName() const { | 154 const char* FrameCaptionButtonContainerView::GetClassName() const { |
248 return kViewClassName; | 155 return kViewClassName; |
249 } | 156 } |
250 | 157 |
251 void FrameCaptionButtonContainerView::SetButtonIcon(FrameCaptionButton* button, | 158 void FrameCaptionButtonContainerView::SetButtonIcon(FrameCaptionButton* button, |
252 CaptionButtonIcon icon, | 159 CaptionButtonIcon icon, |
253 Animate animate) { | 160 Animate animate) { |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
372 FrameCaptionButton* button = buttons[i]; | 279 FrameCaptionButton* button = buttons[i]; |
373 views::Button::ButtonState new_state = views::Button::STATE_NORMAL; | 280 views::Button::ButtonState new_state = views::Button::STATE_NORMAL; |
374 if (button == to_hover) | 281 if (button == to_hover) |
375 new_state = views::Button::STATE_HOVERED; | 282 new_state = views::Button::STATE_HOVERED; |
376 else if (button == to_press) | 283 else if (button == to_press) |
377 new_state = views::Button::STATE_PRESSED; | 284 new_state = views::Button::STATE_PRESSED; |
378 button->SetState(new_state); | 285 button->SetState(new_state); |
379 } | 286 } |
380 } | 287 } |
381 | 288 |
382 void FrameCaptionButtonContainerView::OnImplicitAnimationsCompleted() { | |
383 // If there is another animation in the queue, the reverse animation was | |
384 // triggered before the completion of animating to invisible. Do not turn off | |
385 // the visibility so that the next animation may render. | |
386 if (!size_button_->layer()->GetAnimator()->is_animating() && | |
387 !size_button_->layer()->GetTargetVisibility()) { | |
388 size_button_->SetVisible(false); | |
389 } | |
390 // TODO(jonross): currently we need to delay telling the parent about the | |
391 // size change from visibility. When the size changes this forces a relayout | |
392 // and we want to animate both the bounds of FrameCaptionButtonContainerView | |
393 // along with that of its children. However when the parent is currently | |
394 // having its bounds changed this leads to strange animations where this view | |
395 // renders outside of its parents. Create a more specific animation where | |
396 // height and y are immediately fixed, and where we only animate width and x. | |
397 PreferredSizeChanged(); | |
398 } | |
399 | |
400 void FrameCaptionButtonContainerView::OnLayerRecreated(ui::Layer* old_layer, | |
401 ui::Layer* new_layer) { | |
402 GetWidget()->UpdateRootLayers(); | |
403 } | |
404 | |
405 FrameCaptionButtonContainerView::ButtonIconIds::ButtonIconIds() | 289 FrameCaptionButtonContainerView::ButtonIconIds::ButtonIconIds() |
406 : icon_image_id(-1), | 290 : icon_image_id(-1), |
407 inactive_icon_image_id(-1), | 291 inactive_icon_image_id(-1), |
408 hovered_background_image_id(-1), | 292 hovered_background_image_id(-1), |
409 pressed_background_image_id(-1) { | 293 pressed_background_image_id(-1) { |
410 } | 294 } |
411 | 295 |
412 FrameCaptionButtonContainerView::ButtonIconIds::ButtonIconIds( | 296 FrameCaptionButtonContainerView::ButtonIconIds::ButtonIconIds( |
413 int icon_id, | 297 int icon_id, |
414 int inactive_icon_id, | 298 int inactive_icon_id, |
415 int hovered_background_id, | 299 int hovered_background_id, |
416 int pressed_background_id) | 300 int pressed_background_id) |
417 : icon_image_id(icon_id), | 301 : icon_image_id(icon_id), |
418 inactive_icon_image_id(inactive_icon_id), | 302 inactive_icon_image_id(inactive_icon_id), |
419 hovered_background_image_id(hovered_background_id), | 303 hovered_background_image_id(hovered_background_id), |
420 pressed_background_image_id(pressed_background_id) { | 304 pressed_background_image_id(pressed_background_id) { |
421 } | 305 } |
422 | 306 |
423 FrameCaptionButtonContainerView::ButtonIconIds::~ButtonIconIds() { | 307 FrameCaptionButtonContainerView::ButtonIconIds::~ButtonIconIds() { |
424 } | 308 } |
425 | 309 |
426 } // namespace ash | 310 } // namespace ash |
OLD | NEW |