Chromium Code Reviews| Index: athena/wm/window_overview_mode.cc |
| diff --git a/athena/wm/window_overview_mode.cc b/athena/wm/window_overview_mode.cc |
| index a294cdec6e66df34328c89ec08afeb6d72ca16d6..68d8fe553eeb73efa92774dbfde425dc6704256d 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" |
| @@ -22,6 +23,7 @@ |
| #include "ui/events/gestures/fling_curve.h" |
| #include "ui/gfx/frame_time.h" |
| #include "ui/gfx/transform.h" |
| +#include "ui/gfx/transform_util.h" |
| #include "ui/wm/core/shadow.h" |
| namespace { |
| @@ -40,6 +42,28 @@ 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) {} |
|
Jun Mukai
2014/08/07 21:00:30
Can you add DCHECK(!closure.is_null()) here?
Your
sadrul
2014/08/07 21:15:36
Done.
|
| + private: |
| + virtual ~ClosureAnimationObserver() { |
| + } |
| + |
| + // ui::ImplicitAnimationObserver: |
| + virtual void OnImplicitAnimationsCompleted() OVERRIDE { |
| + if (!closure_.is_null()) |
| + closure_.Run(); |
| + delete this; |
| + } |
| + |
| + 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,98 @@ 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(); |
| + aura::Window::Windows::const_reverse_iterator find = |
| + std::find(list.rbegin(), list.rend(), dragged_window_); |
| + CHECK(list.rend() != find); |
| + float progress = (*find)->GetProperty(kWindowOverviewState)->progress; |
| + for (++find; find != list.rend(); ++find) { |
| + aura::Window* window = *find; |
| + ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator()); |
| + settings.SetPreemptionStrategy( |
| + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| + float next_progress = window->GetProperty(kWindowOverviewState)->progress; |
| + SetWindowProgress(window, progress); |
| + progress = next_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); |
|
Jun Mukai
2014/08/07 21:00:30
should reset dragged_window_ here?
sadrul
2014/08/07 21:15:36
Done.
|
| + } |
| + |
| // ui::EventHandler: |
| virtual void OnMouseEvent(ui::MouseEvent* mouse) OVERRIDE { |
| if (mouse->type() == ui::ET_MOUSE_PRESSED) { |
| @@ -336,17 +456,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 +511,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); |
| }; |