Chromium Code Reviews| Index: athena/wm/split_view_controller.cc |
| diff --git a/athena/wm/split_view_controller.cc b/athena/wm/split_view_controller.cc |
| index 7da36755f7e76433545753ba21a2e4c1f89f3b02..290b60380e93f90c386a56bfa58793e9651ae77b 100644 |
| --- a/athena/wm/split_view_controller.cc |
| +++ b/athena/wm/split_view_controller.cc |
| @@ -4,29 +4,256 @@ |
| #include "athena/wm/split_view_controller.h" |
| +#include "athena/wm/public/window_manager.h" |
| +#include "base/bind.h" |
| #include "ui/aura/window.h" |
| +#include "ui/compositor/layer_animation_observer.h" |
| +#include "ui/compositor/scoped_layer_animation_settings.h" |
| #include "ui/events/event_handler.h" |
| +#include "ui/gfx/display.h" |
| +#include "ui/gfx/screen.h" |
| +#include "ui/wm/core/window_list_provider.h" |
| namespace athena { |
| +namespace { |
| -SplitViewController::SplitViewController() { |
| +// An animation observer that runs a callback at the end of the animation, and |
| +// destroys itself. |
| +class CallbackAnimationObserver : public ui::ImplicitAnimationObserver { |
| + public: |
| + CallbackAnimationObserver(const base::Closure& closure) |
|
oshima
2014/08/06 21:54:09
explicit
mfomitchev
2014/08/08 16:03:22
Done.
|
| + : closure_(closure) { |
| + } |
| + |
| + virtual ~CallbackAnimationObserver() {} |
| + |
| + private: |
| + // Overridden from ui::ImplicitAnimationObserver: |
| + virtual void OnImplicitAnimationsCompleted() OVERRIDE { |
| + if (!closure_.is_null()) |
| + closure_.Run(); |
| + delete this; |
| + } |
| + |
| + const base::Closure closure_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(CallbackAnimationObserver); |
| +}; |
| + |
| +} // namespace |
| + |
| +SplitViewController::SplitViewController( |
| + aura::Window* container, |
| + wm::WindowListProvider* window_list_provider, |
| + WindowManager* window_manager) |
| + : weak_factory_(this), |
| + state_(INACTIVE), |
| + container_(container), |
| + window_manager_(window_manager), |
| + window_list_provider_(window_list_provider), |
| + current_window_(NULL), |
| + left_window_(NULL), |
| + right_window_(NULL), |
| + separator_position_(0) { |
| + window_manager->AddObserver(this); |
| } |
| SplitViewController::~SplitViewController() { |
| } |
| +bool SplitViewController::IsSplitViewModeActive() { |
| + return state_ == ACTIVE; |
| +} |
| + |
| +void SplitViewController::Layout(bool animate) { |
| + if (left_window_) { |
| + CHECK(right_window_); |
| + gfx::Transform left_transform; |
| + gfx::Transform right_transform; |
| + int container_width = container_->GetBoundsInScreen().width(); |
|
oshima
2014/08/06 21:54:09
This should be work area. (there is a small area a
mfomitchev
2014/08/08 16:03:22
Wouldn't the activities' container already set to
oshima
2014/08/08 16:45:34
Container is the same size of the root window. You
mfomitchev
2014/08/08 17:40:50
Ok. How can I get the size of the "work area"? I'd
oshima
2014/08/08 18:00:40
Yes, that's a bug that we need to fix. I'll addres
|
| + if (state_ == ACTIVE) { |
| + left_transform.Scale(.5, 1); |
| + right_transform.Scale(.5, 1); |
|
oshima
2014/08/06 21:54:09
doesn't this make window stretched vertically?
mfomitchev
2014/08/08 16:03:22
Yes, but that will be fixed in OnAnimationCOmplete
|
| + right_transform.Translate(container_width, 0); |
| + } else { |
| + left_transform.Translate(separator_position_ - container_width, 0); |
| + right_transform.Translate(separator_position_, 0); |
| + } |
| + left_window_->Show(); |
| + right_window_->Show(); |
| + SetWindowTransform(left_window_, left_transform, animate); |
| + SetWindowTransform(right_window_, right_transform, animate); |
| + } |
| +} |
| + |
| +void SplitViewController::SetWindowTransform( |
| + aura::Window* window, const gfx::Transform& transform, bool animate) { |
| + if (animate) { |
| + scoped_refptr<ui::LayerAnimator> animator = |
| + window->layer()->GetAnimator(); |
| + ui::ScopedLayerAnimationSettings settings(animator); |
| + settings.SetPreemptionStrategy( |
| + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
| + settings.AddObserver(new CallbackAnimationObserver( |
| + base::Bind(&SplitViewController::AnimationCompleted, |
| + weak_factory_.GetWeakPtr()))); |
| + //settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(250)); |
| + window->SetTransform(transform); |
| + |
| + // TODO: In the end of the animation we need to hide the window that's off |
| + // screen and also set transforms for all windows to gfx::Transform |
| + // (for the case where one window is animated off screen). |
| + } else { |
| + window->SetTransform(transform); |
| + } |
| +} |
| + |
| +void SplitViewController::AnimationCompleted() { |
| + if (state_ == ACTIVE) { |
| + gfx::Rect bounds_size = gfx::Rect(container_->GetBoundsInScreen().size()); |
| + int container_width = bounds_size.width(); |
| + bounds_size.set_width(container_width / 2); |
| + left_window_->SetBounds(bounds_size); |
| + left_window_->SetTransform(gfx::Transform()); |
| + right_window_->SetBounds(bounds_size); |
| + gfx::Transform right_transform; |
| + right_transform.Translate(container_width / 2, 0); |
| + right_window_->SetTransform(right_transform); |
| + } else { |
| + int container_width = container_->GetBoundsInScreen().width(); |
| + left_window_->SetTransform(gfx::Transform()); |
| + right_window_->SetTransform(gfx::Transform()); |
| + if (separator_position_ == 0) |
| + left_window_->Hide(); |
| + else if (separator_position_ == container_width) |
| + right_window_->Hide(); |
| + } |
| +} |
| + |
| +void SplitViewController::UpdateSeparatorPositionFromScrollDelta(float delta) { |
| + gfx::Screen* screen = gfx::Screen::GetScreenFor(container_); |
| + const gfx::Rect& display_bounds = |
| + screen->GetDisplayNearestWindow(container_).bounds(); |
| + gfx::Rect container_bounds = container_->GetBoundsInScreen(); |
| + separator_position_ = delta > 0 ? |
| + ((int) delta) + display_bounds.x() - container_bounds.x() : |
| + display_bounds.right() - container_bounds.x() + delta; |
| +} |
| + |
| +aura::Window* SplitViewController::GetCurrentWindow() { |
| + if (!current_window_) { |
| + aura::Window::Windows windows = window_list_provider_->GetWindowList(); |
| + if (windows.empty()) |
| + return NULL; |
| + current_window_ = windows.back(); |
| + } |
| + return current_window_; |
| +} |
| + |
| +/////////////////////////////////////////////////////////////////////////////// |
| +// Begin BezelController::ScrollDelegate overrides. |
| void SplitViewController::ScrollBegin(BezelController::Bezel bezel, |
| float delta) { |
| + if (!CanScroll()) |
| + return; |
| + state_ = SCROLLING; |
| + aura::Window* current_window = GetCurrentWindow(); |
| + CHECK(current_window); |
| + |
| + aura::Window::Windows windows = window_list_provider_->GetWindowList(); |
| + CHECK(windows.size() >= 2); |
| + aura::Window::Windows::const_iterator it = std::find( |
| + windows.begin(), windows.end(), current_window); |
| + CHECK(it != windows.end()); |
| + |
| + if (delta > 0) { |
| + right_window_ = current_window; |
| + // reverse iterator points to the position before normal iterator |it| |
| + aura::Window::Windows::const_reverse_iterator rev_it(it); |
| + // circle to end if needed. |
| + left_window_ = rev_it == windows.rend() ? windows.back() : *(rev_it); |
| + } else { |
| + left_window_ = current_window; |
| + ++it; |
| + // circle to front if needed. |
| + right_window_ = it == windows.end() ? windows.front() : *it; |
| + } |
| + |
| + CHECK(left_window_); |
| + CHECK(right_window_); |
| + |
| + // TODO (mfomitchev): |
| + // HACK until we are properly hiding off-screen windows in window manager |
| + // Loop through all windows and hide them |
|
oshima
2014/08/06 21:54:09
add me on TODO and crbug.com/388362
mfomitchev
2014/08/08 16:03:22
Done.
|
| + for (it = windows.begin(); it != windows.end(); ++it) { |
| + if (*it != left_window_ && *it != right_window_) |
| + (*it)->Hide(); |
| + } |
| + // END HACK |
|
oshima
2014/08/06 21:54:09
remove HACK/END HACK (as it's obvious)
mfomitchev
2014/08/08 16:03:22
Done.
|
| + |
| + UpdateSeparatorPositionFromScrollDelta(delta); |
| + Layout(false); |
| } |
| +// Max distance from the scroll end position to the middle of the screen where |
| +// we would go into the split view mode. |
| +const int kMaxDistanceFromMiddle = 120; |
| void SplitViewController::ScrollEnd() { |
| + if (state_ != SCROLLING) |
| + return; |
| + |
| + int cont_width = container_->GetBoundsInScreen().width(); |
| + if (abs(cont_width / 2 - separator_position_) <= kMaxDistanceFromMiddle) { |
|
oshima
2014/08/06 21:54:09
std::abs
include <cmath>
mfomitchev
2014/08/08 16:03:22
Done.
|
| + state_ = ACTIVE; |
| + separator_position_ = cont_width / 2; |
| + } else if (separator_position_ < cont_width / 2) { |
| + separator_position_ = 0; |
| + current_window_ = right_window_; |
| + state_ = INACTIVE; |
| + } else { |
| + separator_position_ = cont_width; |
| + current_window_ = left_window_; |
| + state_ = INACTIVE; |
| + } |
| + Layout(true); |
| } |
| void SplitViewController::ScrollUpdate(float delta) { |
| + if (state_ != SCROLLING) |
| + return; |
| + UpdateSeparatorPositionFromScrollDelta(delta); |
| + Layout(false); |
| } |
| bool SplitViewController::CanScroll() { |
| - return false; |
| + // TODO (mfomitchev): return false in vertical orientation, in full screen. |
| + bool result = (!window_manager_->IsOverviewModeActive() && |
| + !IsSplitViewModeActive() && |
| + window_list_provider_->GetWindowList().size() >= 2); |
| + return result; |
| } |
| +/////////////////////////////////////////////////////////////////////////////// |
| +// WindowManagerObserver overrides |
| +void SplitViewController::OnOverviewModeEnter() { |
| + if (state_ == ACTIVE) { |
| + CHECK(left_window_); |
| + CHECK(right_window_); |
| + window_list_provider_->MoveToFront(right_window_); |
| + window_list_provider_->MoveToFront(left_window_); |
| + // TODO (mfomitchev): This shouldn't be done here, but the overview mode's |
| + // transition animation currently looks bad if the starting transform of |
| + // any window is not gfx::Transform(). |
| + right_window_->SetTransform(gfx::Transform()); |
| + } else if (current_window_) { |
| + window_list_provider_->MoveToFront(current_window_); |
| + } |
| + current_window_ = NULL; |
| + left_window_ = NULL; |
| + right_window_ = NULL; |
| + state_ = INACTIVE; |
| +} |
| + |
| +void SplitViewController::OnOverviewModeExit() {} |
| + |
| } // namespace athena |