diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-28 17:54:01 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-28 17:54:01 +0000 |
commit | cb776d3949174aa836b10a6011067ed990da3c65 (patch) | |
tree | 4da3836d333f1eb472d9dad55b5f17b1362977e0 | |
parent | 22ccf8319f6384f73495aff20175f372c8f47817 (diff) | |
download | chromium_src-cb776d3949174aa836b10a6011067ed990da3c65.zip chromium_src-cb776d3949174aa836b10a6011067ed990da3c65.tar.gz chromium_src-cb776d3949174aa836b10a6011067ed990da3c65.tar.bz2 |
Adds an animation for switching workspaces.
BUG=none
TEST=none
R=ben@chromium.org
Review URL: https://chromiumcodereview.appspot.com/9476022
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@123994 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | ash/wm/window_animations.cc | 119 | ||||
-rw-r--r-- | ash/wm/window_animations.h | 14 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_manager.cc | 72 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_manager.h | 16 | ||||
-rw-r--r-- | ui/gfx/compositor/layer.cc | 4 | ||||
-rw-r--r-- | ui/gfx/compositor/scoped_layer_animation_settings.cc | 4 | ||||
-rw-r--r-- | ui/gfx/compositor/scoped_layer_animation_settings.h | 1 |
7 files changed, 202 insertions, 28 deletions
diff --git a/ash/wm/window_animations.cc b/ash/wm/window_animations.cc index adc2cda..e4e513e 100644 --- a/ash/wm/window_animations.cc +++ b/ash/wm/window_animations.cc @@ -16,12 +16,15 @@ #include "ui/aura/window_observer.h" #include "ui/aura/window_property.h" #include "ui/gfx/compositor/layer_animation_observer.h" +#include "ui/gfx/compositor/layer_animator.h" #include "ui/gfx/compositor/scoped_layer_animation_settings.h" DECLARE_WINDOW_PROPERTY_TYPE(int) DECLARE_WINDOW_PROPERTY_TYPE(ash::WindowVisibilityAnimationType) DECLARE_WINDOW_PROPERTY_TYPE(ash::WindowVisibilityAnimationTransition) +using base::TimeDelta; + namespace ash { namespace internal { namespace { @@ -58,7 +61,7 @@ void SetWindowVisibilityAnimationTransition( } void SetWindowVisibilityAnimationDuration(aura::Window* window, - const base::TimeDelta& duration) { + const TimeDelta& duration) { window->SetProperty(internal::kWindowVisibilityAnimationDurationKey, static_cast<int>(duration.ToInternalValue())); } @@ -81,6 +84,9 @@ const float kWindowAnimation_ScaleFactor = 1.05f; const float kWindowAnimation_Vertical_TranslateY = 15.f; +// Amount windows are scaled during workspace animations. +const float kWorkspaceScale = .95f; + // Gets/sets the WindowVisibilityAnimationType associated with a window. WindowVisibilityAnimationType GetWindowVisibilityAnimationType( aura::Window* window) { @@ -157,6 +163,32 @@ class HidingWindowAnimationObserver : public ui::ImplicitAnimationObserver, DISALLOW_COPY_AND_ASSIGN(HidingWindowAnimationObserver); }; +// ImplicitAnimationObserver used when switching workspaces. Resets the layer +// visibility to 'false' when done. This doesn't need the complexity of +// HidingWindowAnimationObserver as the window isn't closing, and if it does a +// HidingWindowAnimationObserver will be created. +class WorkspaceHidingWindowAnimationObserver : + public ui::ImplicitAnimationObserver { + public: + explicit WorkspaceHidingWindowAnimationObserver(aura::Window* window) + : layer_(window->layer()) { + } + virtual ~WorkspaceHidingWindowAnimationObserver() { + } + + private: + // Overridden from ui::ImplicitAnimationObserver: + virtual void OnImplicitAnimationsCompleted() OVERRIDE { + // Restore the correct visibility value (overridden for the duration of the + // animation in AnimateHideWindow()). + layer_->SetVisible(false); + } + + ui::Layer* layer_; + + DISALLOW_COPY_AND_ASSIGN(WorkspaceHidingWindowAnimationObserver); +}; + // Shows a window using an animation, animating its opacity from 0.f to 1.f, and // its transform from |start_transform| to |end_transform|. void AnimateShowWindowCommon(aura::Window* window, @@ -171,10 +203,8 @@ void AnimateShowWindowCommon(aura::Window* window, ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator()); int duration = window->GetProperty(internal::kWindowVisibilityAnimationDurationKey); - if (duration > 0) { - settings.SetTransitionDuration( - base::TimeDelta::FromInternalValue(duration)); - } + if (duration > 0) + settings.SetTransitionDuration(TimeDelta::FromInternalValue(duration)); window->layer()->SetTransform(end_transform); window->layer()->SetOpacity(kWindowAnimation_ShowOpacity); @@ -193,10 +223,8 @@ void AnimateHideWindowCommon(aura::Window* window, int duration = window->GetProperty(internal::kWindowVisibilityAnimationDurationKey); - if (duration > 0) { - settings.SetTransitionDuration( - base::TimeDelta::FromInternalValue(duration)); - } + if (duration > 0) + settings.SetTransitionDuration(TimeDelta::FromInternalValue(duration)); window->layer()->SetOpacity(kWindowAnimation_HideOpacity); window->layer()->SetTransform(end_transform); @@ -245,6 +273,73 @@ void AnimateHideWindow_Fade(aura::Window* window) { AnimateHideWindowCommon(window, ui::Transform()); } +// Builds the transform used when switching workspaces for the specified +// window. +ui::Transform BuildWorkspaceSwitchTransform(aura::Window* window) { + // Animations for transitioning workspaces scale all windows. To give the + // effect of scaling from the center of the screen the windows are translated. + gfx::Rect parent_bounds(window->parent()->bounds()); + float mid_x = static_cast<float>(parent_bounds.width()) / 2.0f; + float initial_x = + (static_cast<float>(window->bounds().x()) - mid_x) * kWorkspaceScale + + mid_x; + float mid_y = static_cast<float>(parent_bounds.height()) / 2.0f; + float initial_y = + (static_cast<float>(window->bounds().y()) - mid_y) * kWorkspaceScale + + mid_y; + + ui::Transform transform; + transform.ConcatTranslate( + initial_x - static_cast<float>(window->bounds().x()), + initial_y - static_cast<float>(window->bounds().y())); + transform.ConcatScale(kWorkspaceScale, kWorkspaceScale); + return transform; +} + +void AnimateShowWindow_Workspace(aura::Window* window) { + ui::Transform transform(BuildWorkspaceSwitchTransform(window)); + window->layer()->SetVisible(true); + window->layer()->SetOpacity(0.0f); + window->layer()->SetTransform(transform); + + { + // Property sets within this scope will be implicitly animated. + ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator()); + + window->layer()->SetTransform(ui::Transform()); + // Opacity animates only during the first half of the animation. + settings.SetTransitionDuration(settings.GetTransitionDuration() / 2); + window->layer()->SetOpacity(1.0f); + } +} + +void AnimateHideWindow_Workspace(aura::Window* window) { + ui::Transform transform(BuildWorkspaceSwitchTransform(window)); + window->layer()->SetOpacity(1.0f); + window->layer()->SetTransform(ui::Transform()); + + // Opacity animates from 1 to 0 only over the second half of the animation. To + // get this functionality two animations are schedule for opacity, the first + // from 1 to 1 (which effectively does nothing) the second from 1 to 0. + // Because we're scheduling two animations of the same property we need to + // change the preemption strategy. + ui::LayerAnimator* animator = window->layer()->GetAnimator(); + animator->set_preemption_strategy(ui::LayerAnimator::ENQUEUE_NEW_ANIMATION); + { + // Property sets within this scope will be implicitly animated. + ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator()); + // Add an observer that sets visibility of the layer to false once animation + // completes. + settings.AddObserver(new WorkspaceHidingWindowAnimationObserver(window)); + window->layer()->SetTransform(transform); + settings.SetTransitionDuration(settings.GetTransitionDuration() / 2); + window->layer()->SetOpacity(1.0f); + window->layer()->SetOpacity(0.0f); + } + animator->set_preemption_strategy( + ui::LayerAnimator::IMMEDIATELY_SET_NEW_TARGET); +} + bool AnimateShowWindow(aura::Window* window) { if (!HasWindowVisibilityAnimationTransition(window, ANIMATE_SHOW)) return false; @@ -259,6 +354,9 @@ bool AnimateShowWindow(aura::Window* window) { case WINDOW_VISIBILITY_ANIMATION_TYPE_FADE: AnimateShowWindow_Fade(window); return true; + case WINDOW_VISIBILITY_ANIMATION_TYPE_WORKSPACE_SHOW: + AnimateShowWindow_Workspace(window); + return true; default: NOTREACHED(); return false; @@ -279,6 +377,9 @@ bool AnimateHideWindow(aura::Window* window) { case WINDOW_VISIBILITY_ANIMATION_TYPE_FADE: AnimateHideWindow_Fade(window); return true; + case WINDOW_VISIBILITY_ANIMATION_TYPE_WORKSPACE_HIDE: + AnimateHideWindow_Workspace(window); + return true; default: NOTREACHED(); return false; diff --git a/ash/wm/window_animations.h b/ash/wm/window_animations.h index f15e484..70ea4ff 100644 --- a/ash/wm/window_animations.h +++ b/ash/wm/window_animations.h @@ -17,11 +17,15 @@ namespace ash { // A variety of canned animations for window transitions. enum WindowVisibilityAnimationType { - WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT = 0, // Default. Lets the system - // decide based on window type. - WINDOW_VISIBILITY_ANIMATION_TYPE_DROP, // Window shrinks in. - WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL, // Vertical Glenimation. - WINDOW_VISIBILITY_ANIMATION_TYPE_FADE // Fades in/out. + WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT = 0, // Default. Lets the system + // decide based on window + // type. + WINDOW_VISIBILITY_ANIMATION_TYPE_DROP, // Window shrinks in. + WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL, // Vertical Glenimation. + WINDOW_VISIBILITY_ANIMATION_TYPE_FADE, // Fades in/out. + WINDOW_VISIBILITY_ANIMATION_TYPE_WORKSPACE_SHOW, // Windows are scaled and + // fade in. + WINDOW_VISIBILITY_ANIMATION_TYPE_WORKSPACE_HIDE, // Inverse of SHOW. }; // Type of visibility change transition that a window should animate. diff --git a/ash/wm/workspace/workspace_manager.cc b/ash/wm/workspace/workspace_manager.cc index 59befcf..67862b0 100644 --- a/ash/wm/workspace/workspace_manager.cc +++ b/ash/wm/workspace/workspace_manager.cc @@ -9,6 +9,7 @@ #include "ash/shell.h" #include "ash/wm/property_util.h" #include "ash/wm/shelf_layout_manager.h" +#include "ash/wm/window_animations.h" #include "ash/wm/window_resizer.h" #include "ash/wm/window_util.h" #include "ash/wm/workspace/managed_workspace.h" @@ -36,17 +37,13 @@ const int kWorkspaceHorizontalMargin = 50; const float kMaxOverviewScale = 0.9f; const float kMinOverviewScale = 0.3f; -// Sets the visibility of the layer of each window in |windows| to |value|. We -// set the visibility of the layer rather than the Window so that views doesn't -// see the visibility change. -// TODO: revisit this. Ideally the Window would think it's still visibile after -// this. May be possible after Ben lands his changes. -void SetWindowLayerVisibility(const std::vector<aura::Window*>& windows, - bool value) { - for (size_t i = 0; i < windows.size(); ++i){ +// Returns a list of all the windows with layers in |result|. +void BuildWindowList(const std::vector<aura::Window*>& windows, + std::vector<aura::Window*>* result) { + for (size_t i = 0; i < windows.size(); ++i) { if (windows[i]->layer()) - windows[i]->layer()->SetVisible(value); - SetWindowLayerVisibility(windows[i]->transient_children(), value); + result->push_back(windows[i]); + BuildWindowList(windows[i]->transient_children(), result); } } @@ -107,8 +104,16 @@ bool WorkspaceManager::ShouldMaximize(aura::Window* window) const { void WorkspaceManager::AddWindow(aura::Window* window) { DCHECK(IsManagedWindow(window)); - if (FindBy(window)) - return; // Already know about this window. + Workspace* current_workspace = FindBy(window); + if (current_workspace) { + // Already know about this window. Make sure the workspace is active. + if (active_workspace_ != current_workspace) { + if (active_workspace_) + window->layer()->GetAnimator()->StopAnimating(); + current_workspace->Activate(); + } + return; + } if (!window_util::IsWindowMaximized(window) && !window_util::IsWindowFullscreen(window)) { @@ -262,6 +267,43 @@ void WorkspaceManager::UpdateShelfVisibility() { shelf_->SetVisible(!window_util::HasFullscreenWindow(windows)); } +void WorkspaceManager::SetVisibilityOfWorkspaceWindows( + ash::internal::Workspace* workspace, + AnimateChangeType change_type, + bool value) { + std::vector<aura::Window*> children; + BuildWindowList(workspace->windows(), &children); + SetWindowLayerVisibility(children, change_type, value); +} + +void WorkspaceManager::SetWindowLayerVisibility( + const std::vector<aura::Window*>& windows, + AnimateChangeType change_type, + bool value) { + for (size_t i = 0; i < windows.size(); ++i) { + ui::Layer* layer = windows[i]->layer(); + if (layer) { + windows[i]->SetProperty(aura::client::kAnimationsDisabledKey, + change_type == DONT_ANIMATE); + bool update_layer = true; + if (change_type == ANIMATE) { + ash::SetWindowVisibilityAnimationType( + windows[i], + value ? ash::WINDOW_VISIBILITY_ANIMATION_TYPE_WORKSPACE_SHOW : + ash::WINDOW_VISIBILITY_ANIMATION_TYPE_WORKSPACE_HIDE); + if (ash::internal::AnimateOnChildWindowVisibilityChanged( + windows[i], value)) + update_layer = false; + } + if (update_layer) + layer->SetVisible(value); + // Reset the animation type so it isn't used in a future hide/show. + ash::SetWindowVisibilityAnimationType( + windows[i], ash::WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT); + } + } +} + Workspace* WorkspaceManager::GetActiveWorkspace() const { return active_workspace_; } @@ -277,10 +319,12 @@ void WorkspaceManager::SetActiveWorkspace(Workspace* workspace) { DCHECK(std::find(workspaces_.begin(), workspaces_.end(), workspace) != workspaces_.end()); if (active_workspace_) - SetWindowLayerVisibility(active_workspace_->windows(), false); + SetVisibilityOfWorkspaceWindows(active_workspace_, ANIMATE, false); + Workspace* last_active = active_workspace_; active_workspace_ = workspace; if (active_workspace_) { - SetWindowLayerVisibility(active_workspace_->windows(), true); + SetVisibilityOfWorkspaceWindows(active_workspace_, + last_active ? ANIMATE : DONT_ANIMATE, true); UpdateShelfVisibility(); } diff --git a/ash/wm/workspace/workspace_manager.h b/ash/wm/workspace/workspace_manager.h index 2960287..8adf5b96 100644 --- a/ash/wm/workspace/workspace_manager.h +++ b/ash/wm/workspace/workspace_manager.h @@ -101,6 +101,12 @@ class ASH_EXPORT WorkspaceManager : public aura::WindowObserver{ intptr_t old) OVERRIDE; private: + // Enumeration of whether windows should animate or not. + enum AnimateChangeType { + ANIMATE, + DONT_ANIMATE + }; + friend class Workspace; friend class WorkspaceManagerTest; @@ -114,6 +120,16 @@ class ASH_EXPORT WorkspaceManager : public aura::WindowObserver{ void UpdateShelfVisibility(); + // Sets the visibility of the windows in |workspace|. + void SetVisibilityOfWorkspaceWindows(Workspace* workspace, + AnimateChangeType change_type, + bool value); + + // Implementation of SetVisibilityOfWorkspaceWindows(). + void SetWindowLayerVisibility(const std::vector<aura::Window*>& windows, + AnimateChangeType change_type, + bool value); + // Returns the active workspace. Workspace* GetActiveWorkspace() const; diff --git a/ui/gfx/compositor/layer.cc b/ui/gfx/compositor/layer.cc index e80b5d8..b49e642 100644 --- a/ui/gfx/compositor/layer.cc +++ b/ui/gfx/compositor/layer.cc @@ -65,6 +65,10 @@ Layer::Layer(LayerType type) } Layer::~Layer() { + // Destroying the animator may cause observers to use the layer (and + // indirectly the WebLayer). Destroy the animator first so that the WebLayer + // is still around. + animator_.reset(); if (compositor_) compositor_->SetRootLayer(NULL); if (parent_) diff --git a/ui/gfx/compositor/scoped_layer_animation_settings.cc b/ui/gfx/compositor/scoped_layer_animation_settings.cc index 7a7dbc1..78fb067 100644 --- a/ui/gfx/compositor/scoped_layer_animation_settings.cc +++ b/ui/gfx/compositor/scoped_layer_animation_settings.cc @@ -44,5 +44,9 @@ void ScopedLayerAnimationSettings::SetTransitionDuration( animator_->transition_duration_ = duration; } +base::TimeDelta ScopedLayerAnimationSettings::GetTransitionDuration() const { + return animator_->transition_duration_; +} + } // namespace ui diff --git a/ui/gfx/compositor/scoped_layer_animation_settings.h b/ui/gfx/compositor/scoped_layer_animation_settings.h index dce64ef..94e5a4e 100644 --- a/ui/gfx/compositor/scoped_layer_animation_settings.h +++ b/ui/gfx/compositor/scoped_layer_animation_settings.h @@ -29,6 +29,7 @@ class COMPOSITOR_EXPORT ScopedLayerAnimationSettings { void AddObserver(ImplicitAnimationObserver* observer); void SetTransitionDuration(base::TimeDelta duration); + base::TimeDelta GetTransitionDuration() const; private: LayerAnimator* animator_; |