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