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

Unified 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: Rebase 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 side-by-side diff with in-line comments
Download patch
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 5cb052984a11ef721a1826c3318c4fb0cca8e06f..643993e4ca03d70e1607d3b9f8761c8d29479cad 100644
--- a/ash/frame/caption_buttons/frame_caption_button_container_view.cc
+++ b/ash/frame/caption_buttons/frame_caption_button_container_view.cc
@@ -16,7 +16,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"
@@ -27,6 +30,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,
@@ -49,6 +60,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(
@@ -122,10 +137,47 @@ int FrameCaptionButtonContainerView::NonClientHitTest(
}
void FrameCaptionButtonContainerView::UpdateSizeButtonVisibility() {
- size_button_->SetVisible(
- !Shell::GetInstance()->maximize_mode_controller()->
+ bool visible = !Shell::GetInstance()->maximize_mode_controller()->
IsMaximizeModeWindowManagerEnabled() &&
- frame_->widget_delegate()->CanMaximize());
+ 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 {
@@ -139,15 +191,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();
}
}
@@ -286,6 +379,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),

Powered by Google App Engine
This is Rietveld 408576698