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