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..c35c233758edbc5bd900607f94128b76f04dd359 100644 |
--- a/athena/wm/split_view_controller.cc |
+++ b/athena/wm/split_view_controller.cc |
@@ -4,29 +4,274 @@ |
#include "athena/wm/split_view_controller.h" |
+#include "athena/common/drag_handle.h" |
+#include "athena/wm/public/window_manager.h" |
+#include "athena/wm/window_stack_provider.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" |
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) |
+ : closure_(closure) { |
+ } |
+ |
+ virtual ~CallbackAnimationObserver() {} |
+ |
+ private: |
+ // Overridden from ui::ImplicitAnimationObserver: |
+ virtual void OnImplicitAnimationsCompleted() OVERRIDE { |
+ if (!closure_.is_null()) |
+ closure_.Run(); |
+ base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); |
oshima
2014/07/25 21:41:10
can't you remove immediately?
mfomitchev
2014/08/05 19:56:57
Yup, looks like I can. I think this used to cause
|
+ } |
+ |
+ const base::Closure closure_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(CallbackAnimationObserver); |
+}; |
+ |
+} // namespace |
+ |
+SplitViewController::SplitViewController( |
+ aura::Window* container, |
+ WindowStackProvider* window_stack_provider, |
+ WindowManager* window_manager) |
+ : weak_factory_(this), |
+ state_(INACTIVE), |
+ container_(container), |
+ window_manager_(window_manager), |
+ window_stack_provider_(window_stack_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(); |
+ if (state_ == ACTIVE) { |
+ left_transform.Scale(.5, 1); |
+ right_transform.Scale(.5, 1); |
+ 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() { |
+ LOG(ERROR) << "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) { |
+ int container_width = container_->GetBoundsInScreen().width(); |
+ separator_position_ = delta > 0 ? (int) delta : container_width + delta; |
+} |
+ |
+aura::Window* SplitViewController::GetCurrentWindow() { |
+ const aura::Window::Windows& windows = |
+ window_stack_provider_->GetWindowStack(); |
+ |
+ LOG(ERROR) << "GetCurrentWindow: current_window_=" << current_window_; |
+ LOG(ERROR) << "All Windows:"; |
+ int i = 0; |
+ aura::Window::Windows::const_iterator it; |
+ for (it = windows.begin(); it != windows.end(); ++it) { |
+ LOG(ERROR) << " Window " << i << ": " << *it; |
+ ++i; |
+ } |
+ |
+ if (windows.empty()) |
+ return NULL; |
+ if (!current_window_) |
+ current_window_ = windows.back(); |
+ return current_window_; |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+// Begin BezelController::ScrollDelegate overrides. |
void SplitViewController::ScrollBegin(BezelController::Bezel bezel, |
float delta) { |
+ LOG(ERROR) << "ScrollBegin"; |
+ if (!CanScroll()) |
+ return; |
+ state_ = SCROLLING; |
+ aura::Window* current_window = GetCurrentWindow(); |
+ CHECK(current_window); |
+ |
+ const aura::Window::Windows& windows = |
+ window_stack_provider_->GetWindowStack(); |
+ 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_); |
+ |
+ // HACK until we are properly hiding windows in window manager |
+ // Loop through all windows and hide them |
+ for (it = windows.begin(); it != windows.end(); ++it) { |
+ if (*it != left_window_ && *it != right_window_) |
+ (*it)->Hide(); |
+ } |
+ |
+ LOG(ERROR) << "left_window_=" << left_window_ |
+ << ", right_window_=" << right_window_; |
+ |
+ // END HACK |
+/* |
+ it = std::find(windows.begin(), windows.end(), left_window_); |
+ size_t index_left = std::distance(windows.begin(), it); |
+ it = std::find(windows.begin(), windows.end(), right_window_); |
+ size_t index_right = std::distance(windows.begin(), it); |
+ LOG(ERROR) << "IndexLeft=" << index_left |
+ << ", IndexRight=" << index_right; |
+*/ |
+ |
+ 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() { |
+ LOG(ERROR) << "ScrollEnd"; |
+ if (state_ != SCROLLING) |
+ return; |
+ |
+ int cont_width = container_->GetBoundsInScreen().width(); |
+ if (abs(cont_width / 2 - separator_position_) <= kMaxDistanceFromMiddle) { |
+ state_ = ACTIVE; |
+ separator_position_ = cont_width / 2; |
+ LOG(ERROR) << "Entering split view mode!"; |
+ } 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_stack_provider_->GetWindowStack().size() >= 2); |
+ return result; |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+// WindowManagerObserver overrides |
+void SplitViewController::OnOverviewModeEnter() { |
+ if (state_ == ACTIVE) { |
+ CHECK(left_window_); |
+ CHECK(right_window_); |
+ window_stack_provider_->MoveWindowToFront(right_window_); |
+ window_stack_provider_->MoveWindowToFront(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_stack_provider_->MoveWindowToFront(current_window_); |
+ } |
+ current_window_ = NULL; |
+ left_window_ = NULL; |
+ right_window_ = NULL; |
+ state_ = INACTIVE; |
} |
} // namespace athena |