| Index: ash/frame/caption_buttons/frame_caption_button_container_view.cc
|
| diff --git a/ash/frame/caption_buttons/frame_caption_button_container_view.cc b/ash/frame/caption_buttons/frame_caption_button_container_view.cc
|
| index 12bbb71a35cadd9e0fa774f31add9541abfec4ba..2a0e79f2641d14491765c308cef9b0b9521d22fb 100644
|
| --- a/ash/frame/caption_buttons/frame_caption_button_container_view.cc
|
| +++ b/ash/frame/caption_buttons/frame_caption_button_container_view.cc
|
| @@ -5,6 +5,7 @@
|
| #include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
|
|
|
| #include <cmath>
|
| +#include <map>
|
|
|
| #include "ash/ash_switches.h"
|
| #include "ash/frame/caption_buttons/frame_caption_button.h"
|
| @@ -14,7 +15,10 @@
|
| #include "grit/ui_strings.h" // Accessibility names
|
| #include "ui/base/hit_test.h"
|
| #include "ui/base/l10n/l10n_util.h"
|
| +#include "ui/compositor/layer.h"
|
| #include "ui/compositor/scoped_animation_duration_scale_mode.h"
|
| +#include "ui/compositor/scoped_layer_animation_settings.h"
|
| +#include "ui/gfx/animation/tween.h"
|
| #include "ui/gfx/canvas.h"
|
| #include "ui/gfx/insets.h"
|
| #include "ui/gfx/point.h"
|
| @@ -25,6 +29,14 @@ namespace ash {
|
|
|
| namespace {
|
|
|
| +// Visual design parameters for animating the transition to maximize mode.
|
| +// When the size button hides we delay sliding the minimize button into its
|
| +// location. Also used to delay showing the size button so that the minimize
|
| +// button slides out of that position.
|
| +const int kAnimationDelayMs = 100;
|
| +const int kMinimizeSlideDurationMs = 500;
|
| +const int kSizeFadeDurationMs = 250;
|
| +
|
| // Converts |point| from |src| to |dst| and hittests against |dst|.
|
| bool ConvertPointToViewAndHitTest(const views::View* src,
|
| const views::View* dst,
|
| @@ -47,6 +59,10 @@ FrameCaptionButtonContainerView::FrameCaptionButtonContainerView(
|
| minimize_button_(NULL),
|
| size_button_(NULL),
|
| close_button_(NULL) {
|
| + SetPaintToLayer(true);
|
| + SetFillsBoundsOpaquely(false);
|
| + set_layer_owner_delegate(this);
|
| +
|
| // Insert the buttons left to right.
|
| minimize_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_MINIMIZE);
|
| minimize_button_->SetAccessibleName(
|
| @@ -127,8 +143,46 @@ void FrameCaptionButtonContainerView::UpdateSizeButtonVisibility(
|
| // time when ShellObserver::OnMaximizeModeStarted is called. This prevents
|
| // this method from performing that check, and instead relies on the calling
|
| // code to tell it to force being hidden.
|
| - size_button_->SetVisible(
|
| - !force_hidden && frame_->widget_delegate()->CanMaximize());
|
| +
|
| + bool visible = !force_hidden && frame_->widget_delegate()->CanMaximize();
|
| +
|
| + // Turning visibility off prevents animations from rendering. Setting the
|
| + // size button visibility to false will occur after the animation.
|
| + if (visible) {
|
| + size_button_->SetVisible(true);
|
| + // Because we delay calling View::SetVisible(false) until the end of the
|
| + // animation, if SetVisible(true) is called mid-animation, the View still
|
| + // believes it is visible and will not update the target layer visibility.
|
| + size_button_->layer()->SetVisible(true);
|
| + }
|
| +
|
| + ui::ScopedLayerAnimationSettings settings(
|
| + size_button_->layer()->GetAnimator());
|
| + settings.SetTransitionDuration(
|
| + base::TimeDelta::FromMilliseconds(kSizeFadeDurationMs));
|
| + settings.SetPreemptionStrategy(
|
| + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
|
| +
|
| + if (visible) {
|
| + settings.SetTweenType(gfx::Tween::EASE_OUT);
|
| + // Delay fade in so that the minimize button has begun its sliding
|
| + // animation.
|
| + size_button_->layer()->GetAnimator()->SchedulePauseForProperties(
|
| + base::TimeDelta::FromMilliseconds(kAnimationDelayMs),
|
| + ui::LayerAnimationElement::OPACITY);
|
| + size_button_->layer()->SetOpacity(1.0f);
|
| + } else {
|
| + settings.SetTweenType(gfx::Tween::EASE_IN);
|
| + // Observer will call size_button_->SetVisible(false) upon completion of
|
| + // the animation.
|
| + // TODO(jonross): avoid the delayed SetVisible(false) call by acquring
|
| + // the size_button's layer before making it invisible. That layer can then
|
| + // be animated and deleted upon completion of the animation. See
|
| + // LayerOwner::RecreateLayer
|
| + settings.AddObserver(this);
|
| + size_button_->layer()->SetOpacity(0.0f);
|
| + size_button_->layer()->SetVisible(false);
|
| + }
|
| }
|
|
|
| gfx::Size FrameCaptionButtonContainerView::GetPreferredSize() const {
|
| @@ -142,15 +196,56 @@ gfx::Size FrameCaptionButtonContainerView::GetPreferredSize() const {
|
| }
|
|
|
| void FrameCaptionButtonContainerView::Layout() {
|
| - int x = 0;
|
| - for (int i = 0; i < child_count(); ++i) {
|
| + int x = width();
|
| + // Offsets the initial position of a child, so that buttons slide into the
|
| + // place as other buttons are added/removed.
|
| + int offset_x = 0;
|
| + for (int i = child_count() - 1; i >= 0; --i) {
|
| views::View* child = child_at(i);
|
| - if (!child->visible())
|
| + ui::LayerAnimator* child_animator = child->layer()->GetAnimator();
|
| + bool child_animating = child_animator->is_animating();
|
| + // The actual property visibility is not being animated, otherwise the
|
| + // view does not render.
|
| + bool child_animating_opacity = child_animator->
|
| + IsAnimatingProperty(ui::LayerAnimationElement::OPACITY);
|
| + bool child_target_visibility = child->layer()->GetTargetVisibility();
|
| +
|
| + if (child_animating_opacity) {
|
| + if (child_target_visibility)
|
| + offset_x += child->width();
|
| + else
|
| + offset_x -= child->width();
|
| + }
|
| +
|
| + if (!child->visible() || !child_target_visibility)
|
| continue;
|
|
|
| + scoped_ptr<ui::ScopedLayerAnimationSettings> animation;
|
| gfx::Size size = child->GetPreferredSize();
|
| + x -= size.width();
|
| +
|
| + // Animate the button if a previous button is currently animating
|
| + // its visibility.
|
| + if (offset_x != 0) {
|
| + if (!child_animating)
|
| + child->SetBounds(x + offset_x, 0, size.width(), size.height());
|
| + if (offset_x < 0) {
|
| + // Delay sliding to where the previous button was located.
|
| + child_animator->SchedulePauseForProperties(
|
| + base::TimeDelta::FromMilliseconds(kAnimationDelayMs),
|
| + ui::LayerAnimationElement::BOUNDS);
|
| + }
|
| +
|
| + ui::ScopedLayerAnimationSettings* settings =
|
| + new ui::ScopedLayerAnimationSettings(child_animator);
|
| + settings->SetTransitionDuration(
|
| + base::TimeDelta::FromMilliseconds(kMinimizeSlideDurationMs));
|
| + settings->SetPreemptionStrategy(
|
| + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
|
| + settings->SetTweenType(gfx::Tween::EASE_OUT);
|
| + animation.reset(settings);
|
| + }
|
| child->SetBounds(x, 0, size.width(), size.height());
|
| - x += size.width();
|
| }
|
| }
|
|
|
| @@ -202,7 +297,7 @@ void FrameCaptionButtonContainerView::ButtonPressed(views::Button* sender,
|
| if (sender == minimize_button_) {
|
| frame_->Minimize();
|
| } else if (sender == size_button_) {
|
| - if (frame_->IsFullscreen()) { // Can be clicked in immersive fullscreen.
|
| + if (frame_->IsFullscreen()) { // Can be clicked in immersive fullscreen.
|
| frame_->SetFullscreen(false);
|
| action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_EXIT_FULLSCREEN;
|
| } else if (frame_->IsMaximized()) {
|
| @@ -212,7 +307,7 @@ void FrameCaptionButtonContainerView::ButtonPressed(views::Button* sender,
|
| frame_->Maximize();
|
| action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MAXIMIZE;
|
| }
|
| - } else if(sender == close_button_) {
|
| + } else if (sender == close_button_) {
|
| frame_->Close();
|
| action = ash::UMA_WINDOW_CLOSE_BUTTON_CLICK;
|
| } else {
|
| @@ -289,6 +384,29 @@ void FrameCaptionButtonContainerView::SetHoveredAndPressedButtons(
|
| }
|
| }
|
|
|
| +void FrameCaptionButtonContainerView::OnImplicitAnimationsCompleted() {
|
| + // If there is another animation in the queue, the reverse animation was
|
| + // triggered before the completion of animating to invisible. Do not turn off
|
| + // the visibility so that the next animation may render.
|
| + if (!size_button_->layer()->GetAnimator()->is_animating() &&
|
| + !size_button_->layer()->GetTargetVisibility()) {
|
| + size_button_->SetVisible(false);
|
| + }
|
| + // TODO(jonross): currently we need to delay telling the parent about the
|
| + // size change from visibility. When the size changes this forces a relayout
|
| + // and we want to animate both the bounds of FrameCaptionButtonContainerView
|
| + // along with that of its children. However when the parent is currently
|
| + // having its bounds changed this leads to strange animations where this view
|
| + // renders outside of its parents. Create a more specific animation where
|
| + // height and y are immediately fixed, and where we only animate width and x.
|
| + PreferredSizeChanged();
|
| +}
|
| +
|
| +void FrameCaptionButtonContainerView::OnLayerRecreated(ui::Layer* old_layer,
|
| + ui::Layer* new_layer) {
|
| + GetWidget()->UpdateRootLayers();
|
| +}
|
| +
|
| FrameCaptionButtonContainerView::ButtonIconIds::ButtonIconIds()
|
| : icon_image_id(-1),
|
| inactive_icon_image_id(-1),
|
|
|