diff options
author | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-08 12:01:42 +0000 |
---|---|---|
committer | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-08 12:03:03 +0000 |
commit | 1899fa47c3fdc3a7867bb8d8e2a6e0b540446860 (patch) | |
tree | 1967eb10c518cd38cbbbdef3b0fd41f61ef79f49 /athena | |
parent | 7eb95f2ab22789ab500c8da17d21c7366f14d1fa (diff) | |
download | chromium_src-1899fa47c3fdc3a7867bb8d8e2a6e0b540446860.zip chromium_src-1899fa47c3fdc3a7867bb8d8e2a6e0b540446860.tar.gz chromium_src-1899fa47c3fdc3a7867bb8d8e2a6e0b540446860.tar.bz2 |
athena: Slide a window offscreen in overview mode to close it.
BUG=401526
R=mukai@chromium.org
Review URL: https://codereview.chromium.org/442263004
Cr-Commit-Position: refs/heads/master@{#288335}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288335 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'athena')
-rw-r--r-- | athena/wm/window_overview_mode.cc | 185 |
1 files changed, 172 insertions, 13 deletions
diff --git a/athena/wm/window_overview_mode.cc b/athena/wm/window_overview_mode.cc index a294cde..e04858a 100644 --- a/athena/wm/window_overview_mode.cc +++ b/athena/wm/window_overview_mode.cc @@ -8,6 +8,7 @@ #include <functional> #include <vector> +#include "base/bind.h" #include "base/macros.h" #include "ui/aura/scoped_window_targeter.h" #include "ui/aura/window.h" @@ -40,6 +41,29 @@ struct WindowOverviewState { scoped_ptr<wm::Shadow> shadow; }; +// Runs a callback at the end of the animation. This observe also destroys +// itself afterwards. +class ClosureAnimationObserver : public ui::ImplicitAnimationObserver { + public: + explicit ClosureAnimationObserver(const base::Closure& closure) + : closure_(closure) { + DCHECK(!closure_.is_null()); + } + private: + virtual ~ClosureAnimationObserver() { + } + + // ui::ImplicitAnimationObserver: + virtual void OnImplicitAnimationsCompleted() OVERRIDE { + closure_.Run(); + delete this; + } + + const base::Closure closure_; + + DISALLOW_COPY_AND_ASSIGN(ClosureAnimationObserver); +}; + } // namespace DECLARE_WINDOW_PROPERTY_TYPE(WindowOverviewState*) @@ -54,13 +78,18 @@ bool ShouldShowWindowInOverviewMode(aura::Window* window) { return window->type() == ui::wm::WINDOW_TYPE_NORMAL; } +// Gets the transform for the window in its current state. +gfx::Transform GetTransformForState(WindowOverviewState* state) { + return gfx::Tween::TransformValueBetween(state->progress, + state->top, + state->bottom); +} + // Sets the progress-state for the window in the overview mode. void SetWindowProgress(aura::Window* window, float progress) { WindowOverviewState* state = window->GetProperty(kWindowOverviewState); - gfx::Transform transform = - gfx::Tween::TransformValueBetween(progress, state->top, state->bottom); - window->SetTransform(transform); state->progress = progress; + window->SetTransform(GetTransformForState(state)); } // Resets the overview-related state for |window|. @@ -108,7 +137,8 @@ class WindowOverviewModeImpl : public WindowOverviewMode, scoped_targeter_(new aura::ScopedWindowTargeter( container, scoped_ptr<ui::EventTargeter>( - new StaticWindowTargeter(container)))) { + new StaticWindowTargeter(container)))), + dragged_window_(NULL) { container_->set_target_handler(this); // Prepare the desired transforms for all the windows, and set the initial @@ -143,8 +173,6 @@ class WindowOverviewModeImpl : public WindowOverviewMode, const int kGapBetweenWindowsBottom = 10; const int kGapBetweenWindowsTop = 5; - const float kMinScale = 0.6f; - const float kMaxScale = 0.95f; for (aura::Window::Windows::const_reverse_iterator iter = windows.rbegin(); iter != windows.rend(); @@ -311,6 +339,101 @@ class WindowOverviewModeImpl : public WindowOverviewMode, compositor->RemoveAnimationObserver(this); } + void DragWindow(const ui::GestureEvent& event) { + CHECK(dragged_window_); + CHECK_EQ(ui::ET_GESTURE_SCROLL_UPDATE, event.type()); + gfx::Vector2dF dragged_distance = + dragged_start_location_ - event.location(); + WindowOverviewState* dragged_state = + dragged_window_->GetProperty(kWindowOverviewState); + CHECK(dragged_state); + gfx::Transform transform = GetTransformForState(dragged_state); + transform.Translate(-dragged_distance.x(), 0); + dragged_window_->SetTransform(transform); + + float ratio = std::min( + 1.f, std::abs(dragged_distance.x()) / kMinDistanceForDismissal); + float opacity = + gfx::Tween::FloatValueBetween(ratio, kMaxOpacity, kMinOpacity); + dragged_window_->layer()->SetOpacity(opacity); + } + + bool ShouldCloseDragWindow(const ui::GestureEvent& event) const { + gfx::Vector2dF dragged_distance = + dragged_start_location_ - event.location(); + if (event.type() == ui::ET_GESTURE_SCROLL_END) + return std::abs(dragged_distance.x()) >= kMinDistanceForDismissal; + CHECK_EQ(ui::ET_SCROLL_FLING_START, event.type()); + const bool dragging_towards_right = dragged_distance.x() < 0; + const bool swipe_towards_right = event.details().velocity_x() > 0; + if (dragging_towards_right != swipe_towards_right) + return false; + const float kMinVelocityForDismissal = 500.f; + return std::abs(event.details().velocity_x()) > kMinVelocityForDismissal; + } + + void CloseDragWindow(const ui::GestureEvent& gesture) { + // Animate |dragged_window_| offscreen first, then destroy it. + ui::ScopedLayerAnimationSettings settings( + dragged_window_->layer()->GetAnimator()); + settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + settings.AddObserver(new ClosureAnimationObserver( + base::Bind(&base::DeletePointer<aura::Window>, dragged_window_))); + + WindowOverviewState* dragged_state = + dragged_window_->GetProperty(kWindowOverviewState); + CHECK(dragged_state); + gfx::Transform transform = dragged_window_->layer()->transform(); + gfx::RectF transformed_bounds = dragged_window_->bounds(); + transform.TransformRect(&transformed_bounds); + float transform_x = 0.f; + if (gesture.location().x() > dragged_start_location_.x()) + transform_x = container_->bounds().right() - transformed_bounds.x(); + else + transform_x = -(transformed_bounds.x() + transformed_bounds.width()); + float scale = gfx::Tween::FloatValueBetween( + dragged_state->progress, kMinScale, kMaxScale); + transform.Translate(transform_x / scale, 0); + dragged_window_->SetTransform(transform); + dragged_window_->layer()->SetOpacity(kMinOpacity); + + // Move the windows behind |dragged_window_| in the stack forward one step. + const aura::Window::Windows& list = container_->children(); + for (aura::Window::Windows::const_iterator iter = list.begin(); + iter != list.end() && *iter != dragged_window_; + ++iter) { + aura::Window* window = *iter; + ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator()); + settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + WindowOverviewState* state = window->GetProperty(kWindowOverviewState); + + aura::Window* next = *(iter + 1); + WindowOverviewState* next_state = next->GetProperty(kWindowOverviewState); + state->top = next_state->top; + state->bottom = next_state->bottom; + SetWindowProgress(window, next_state->progress); + } + + dragged_window_ = NULL; + } + + void RestoreDragWindow() { + CHECK(dragged_window_); + WindowOverviewState* dragged_state = + dragged_window_->GetProperty(kWindowOverviewState); + CHECK(dragged_state); + + ui::ScopedLayerAnimationSettings settings( + dragged_window_->layer()->GetAnimator()); + settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + dragged_window_->SetTransform(GetTransformForState(dragged_state)); + dragged_window_->layer()->SetOpacity(1.f); + dragged_window_ = NULL; + } + // ui::EventHandler: virtual void OnMouseEvent(ui::MouseEvent* mouse) OVERRIDE { if (mouse->type() == ui::ET_MOUSE_PRESSED) { @@ -336,17 +459,44 @@ class WindowOverviewModeImpl : public WindowOverviewMode, gesture->SetHandled(); delegate_->OnSelectWindow(select); } + } else if (gesture->type() == ui::ET_GESTURE_SCROLL_BEGIN) { + if (std::abs(gesture->details().scroll_x_hint()) > + std::abs(gesture->details().scroll_y_hint()) * 2) { + dragged_start_location_ = gesture->location(); + dragged_window_ = SelectWindowAt(gesture); + } } else if (gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) { - DoScroll(gesture->details().scroll_y()); + if (dragged_window_) + DragWindow(*gesture); + else + DoScroll(gesture->details().scroll_y()); gesture->SetHandled(); - } else if (gesture->type() == ui::ET_SCROLL_FLING_START) { - CreateFlingerFor(*gesture); - AddAnimationObserver(); + } else if (gesture->type() == ui::ET_GESTURE_SCROLL_END) { + if (dragged_window_) { + if (ShouldCloseDragWindow(*gesture)) + CloseDragWindow(*gesture); + else + RestoreDragWindow(); + } gesture->SetHandled(); - } else if (gesture->type() == ui::ET_GESTURE_TAP_DOWN && fling_) { - fling_.reset(); - RemoveAnimationObserver(); + } else if (gesture->type() == ui::ET_SCROLL_FLING_START) { + if (dragged_window_) { + if (ShouldCloseDragWindow(*gesture)) + CloseDragWindow(*gesture); + else + RestoreDragWindow(); + } else { + CreateFlingerFor(*gesture); + AddAnimationObserver(); + } gesture->SetHandled(); + } else if (gesture->type() == ui::ET_GESTURE_TAP_DOWN) { + if (fling_) { + fling_.reset(); + RemoveAnimationObserver(); + gesture->SetHandled(); + } + dragged_window_ = NULL; } } @@ -364,11 +514,20 @@ class WindowOverviewModeImpl : public WindowOverviewMode, } } + const int kMinDistanceForDismissal = 300; + const float kMinScale = 0.6f; + const float kMaxScale = 0.95f; + const float kMaxOpacity = 1.0f; + const float kMinOpacity = 0.2f; + aura::Window* container_; WindowOverviewModeDelegate* delegate_; scoped_ptr<aura::ScopedWindowTargeter> scoped_targeter_; scoped_ptr<ui::FlingCurve> fling_; + aura::Window* dragged_window_; + gfx::Point dragged_start_location_; + DISALLOW_COPY_AND_ASSIGN(WindowOverviewModeImpl); }; |