Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "athena/wm/split_view_controller.h" | 5 #include "athena/wm/split_view_controller.h" |
| 6 | 6 |
| 7 #include "athena/common/drag_handle.h" | |
| 8 #include "athena/wm/public/window_manager.h" | |
| 9 #include "athena/wm/window_stack_provider.h" | |
| 10 #include "base/bind.h" | |
| 7 #include "ui/aura/window.h" | 11 #include "ui/aura/window.h" |
| 12 #include "ui/compositor/layer_animation_observer.h" | |
| 13 #include "ui/compositor/scoped_layer_animation_settings.h" | |
| 8 #include "ui/events/event_handler.h" | 14 #include "ui/events/event_handler.h" |
| 9 | 15 |
| 10 namespace athena { | 16 namespace athena { |
| 11 | 17 namespace { |
| 12 SplitViewController::SplitViewController() { | 18 |
| 19 // An animation observer that runs a callback at the end of the animation, and | |
| 20 // destroys itself. | |
| 21 class CallbackAnimationObserver : public ui::ImplicitAnimationObserver { | |
| 22 public: | |
| 23 CallbackAnimationObserver(const base::Closure& closure) | |
| 24 : closure_(closure) { | |
| 25 } | |
| 26 | |
| 27 virtual ~CallbackAnimationObserver() {} | |
| 28 | |
| 29 private: | |
| 30 // Overridden from ui::ImplicitAnimationObserver: | |
| 31 virtual void OnImplicitAnimationsCompleted() OVERRIDE { | |
| 32 if (!closure_.is_null()) | |
| 33 closure_.Run(); | |
| 34 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
| |
| 35 } | |
| 36 | |
| 37 const base::Closure closure_; | |
| 38 | |
| 39 DISALLOW_COPY_AND_ASSIGN(CallbackAnimationObserver); | |
| 40 }; | |
| 41 | |
| 42 } // namespace | |
| 43 | |
| 44 SplitViewController::SplitViewController( | |
| 45 aura::Window* container, | |
| 46 WindowStackProvider* window_stack_provider, | |
| 47 WindowManager* window_manager) | |
| 48 : weak_factory_(this), | |
| 49 state_(INACTIVE), | |
| 50 container_(container), | |
| 51 window_manager_(window_manager), | |
| 52 window_stack_provider_(window_stack_provider), | |
| 53 current_window_(NULL), | |
| 54 left_window_(NULL), | |
| 55 right_window_(NULL), | |
| 56 separator_position_(0) { | |
| 57 window_manager->AddObserver(this); | |
| 13 } | 58 } |
| 14 | 59 |
| 15 SplitViewController::~SplitViewController() { | 60 SplitViewController::~SplitViewController() { |
| 16 } | 61 } |
| 17 | 62 |
| 63 bool SplitViewController::IsSplitViewModeActive() { | |
| 64 return state_ == ACTIVE; | |
| 65 } | |
| 66 | |
| 67 void SplitViewController::Layout(bool animate) { | |
| 68 if (left_window_) { | |
| 69 CHECK(right_window_); | |
| 70 gfx::Transform left_transform; | |
| 71 gfx::Transform right_transform; | |
| 72 int container_width = container_->GetBoundsInScreen().width(); | |
| 73 if (state_ == ACTIVE) { | |
| 74 left_transform.Scale(.5, 1); | |
| 75 right_transform.Scale(.5, 1); | |
| 76 right_transform.Translate(container_width, 0); | |
| 77 } else { | |
| 78 left_transform.Translate(separator_position_ - container_width, 0); | |
| 79 right_transform.Translate(separator_position_, 0); | |
| 80 } | |
| 81 left_window_->Show(); | |
| 82 right_window_->Show(); | |
| 83 SetWindowTransform(left_window_, left_transform, animate); | |
| 84 SetWindowTransform(right_window_, right_transform, animate); | |
| 85 } | |
| 86 } | |
| 87 | |
| 88 void SplitViewController::SetWindowTransform( | |
| 89 aura::Window* window, const gfx::Transform& transform, bool animate) { | |
| 90 if (animate) { | |
| 91 scoped_refptr<ui::LayerAnimator> animator = | |
| 92 window->layer()->GetAnimator(); | |
| 93 ui::ScopedLayerAnimationSettings settings(animator); | |
| 94 settings.SetPreemptionStrategy( | |
| 95 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | |
| 96 settings.AddObserver(new CallbackAnimationObserver( | |
| 97 base::Bind(&SplitViewController::AnimationCompleted, | |
| 98 weak_factory_.GetWeakPtr()))); | |
| 99 //settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(250)); | |
| 100 window->SetTransform(transform); | |
| 101 | |
| 102 // TODO: In the end of the animation we need to hide the window that's off | |
| 103 // screen and also set transforms for all windows to gfx::Transform | |
| 104 // (for the case where one window is animated off screen). | |
| 105 } else { | |
| 106 window->SetTransform(transform); | |
| 107 } | |
| 108 } | |
| 109 | |
| 110 void SplitViewController::AnimationCompleted() { | |
| 111 LOG(ERROR) << "AnimationCompleted"; | |
| 112 if (state_ == ACTIVE) { | |
| 113 gfx::Rect bounds_size = gfx::Rect(container_->GetBoundsInScreen().size()); | |
| 114 int container_width = bounds_size.width(); | |
| 115 bounds_size.set_width(container_width / 2); | |
| 116 left_window_->SetBounds(bounds_size); | |
| 117 left_window_->SetTransform(gfx::Transform()); | |
| 118 right_window_->SetBounds(bounds_size); | |
| 119 gfx::Transform right_transform; | |
| 120 right_transform.Translate(container_width / 2, 0); | |
| 121 right_window_->SetTransform(right_transform); | |
| 122 } else { | |
| 123 int container_width = container_->GetBoundsInScreen().width(); | |
| 124 left_window_->SetTransform(gfx::Transform()); | |
| 125 right_window_->SetTransform(gfx::Transform()); | |
| 126 if (separator_position_ == 0) | |
| 127 left_window_->Hide(); | |
| 128 else if (separator_position_ == container_width) | |
| 129 right_window_->Hide(); | |
| 130 } | |
| 131 } | |
| 132 | |
| 133 void SplitViewController::UpdateSeparatorPositionFromScrollDelta(float delta) { | |
| 134 int container_width = container_->GetBoundsInScreen().width(); | |
| 135 separator_position_ = delta > 0 ? (int) delta : container_width + delta; | |
| 136 } | |
| 137 | |
| 138 aura::Window* SplitViewController::GetCurrentWindow() { | |
| 139 const aura::Window::Windows& windows = | |
| 140 window_stack_provider_->GetWindowStack(); | |
| 141 | |
| 142 LOG(ERROR) << "GetCurrentWindow: current_window_=" << current_window_; | |
| 143 LOG(ERROR) << "All Windows:"; | |
| 144 int i = 0; | |
| 145 aura::Window::Windows::const_iterator it; | |
| 146 for (it = windows.begin(); it != windows.end(); ++it) { | |
| 147 LOG(ERROR) << " Window " << i << ": " << *it; | |
| 148 ++i; | |
| 149 } | |
| 150 | |
| 151 if (windows.empty()) | |
| 152 return NULL; | |
| 153 if (!current_window_) | |
| 154 current_window_ = windows.back(); | |
| 155 return current_window_; | |
| 156 } | |
| 157 | |
| 158 /////////////////////////////////////////////////////////////////////////////// | |
| 159 // Begin BezelController::ScrollDelegate overrides. | |
| 18 void SplitViewController::ScrollBegin(BezelController::Bezel bezel, | 160 void SplitViewController::ScrollBegin(BezelController::Bezel bezel, |
| 19 float delta) { | 161 float delta) { |
| 20 } | 162 LOG(ERROR) << "ScrollBegin"; |
| 21 | 163 if (!CanScroll()) |
| 164 return; | |
| 165 state_ = SCROLLING; | |
| 166 aura::Window* current_window = GetCurrentWindow(); | |
| 167 CHECK(current_window); | |
| 168 | |
| 169 const aura::Window::Windows& windows = | |
| 170 window_stack_provider_->GetWindowStack(); | |
| 171 CHECK(windows.size() >= 2); | |
| 172 aura::Window::Windows::const_iterator it = std::find( | |
| 173 windows.begin(), windows.end(), current_window); | |
| 174 CHECK(it != windows.end()); | |
| 175 | |
| 176 if (delta > 0) { | |
| 177 right_window_ = current_window; | |
| 178 // reverse iterator points to the position before normal iterator |it| | |
| 179 aura::Window::Windows::const_reverse_iterator rev_it(it); | |
| 180 // circle to end if needed. | |
| 181 left_window_ = rev_it == windows.rend() ? windows.back() : *(rev_it); | |
| 182 } else { | |
| 183 left_window_ = current_window; | |
| 184 ++it; | |
| 185 // circle to front if needed. | |
| 186 right_window_ = it == windows.end() ? windows.front() : *it; | |
| 187 } | |
| 188 | |
| 189 CHECK(left_window_); | |
| 190 CHECK(right_window_); | |
| 191 | |
| 192 // HACK until we are properly hiding windows in window manager | |
| 193 // Loop through all windows and hide them | |
| 194 for (it = windows.begin(); it != windows.end(); ++it) { | |
| 195 if (*it != left_window_ && *it != right_window_) | |
| 196 (*it)->Hide(); | |
| 197 } | |
| 198 | |
| 199 LOG(ERROR) << "left_window_=" << left_window_ | |
| 200 << ", right_window_=" << right_window_; | |
| 201 | |
| 202 // END HACK | |
| 203 /* | |
| 204 it = std::find(windows.begin(), windows.end(), left_window_); | |
| 205 size_t index_left = std::distance(windows.begin(), it); | |
| 206 it = std::find(windows.begin(), windows.end(), right_window_); | |
| 207 size_t index_right = std::distance(windows.begin(), it); | |
| 208 LOG(ERROR) << "IndexLeft=" << index_left | |
| 209 << ", IndexRight=" << index_right; | |
| 210 */ | |
| 211 | |
| 212 UpdateSeparatorPositionFromScrollDelta(delta); | |
| 213 Layout(false); | |
| 214 } | |
| 215 | |
| 216 // Max distance from the scroll end position to the middle of the screen where | |
| 217 // we would go into the split view mode. | |
| 218 const int kMaxDistanceFromMiddle = 120; | |
| 22 void SplitViewController::ScrollEnd() { | 219 void SplitViewController::ScrollEnd() { |
| 220 LOG(ERROR) << "ScrollEnd"; | |
| 221 if (state_ != SCROLLING) | |
| 222 return; | |
| 223 | |
| 224 int cont_width = container_->GetBoundsInScreen().width(); | |
| 225 if (abs(cont_width / 2 - separator_position_) <= kMaxDistanceFromMiddle) { | |
| 226 state_ = ACTIVE; | |
| 227 separator_position_ = cont_width / 2; | |
| 228 LOG(ERROR) << "Entering split view mode!"; | |
| 229 } else if (separator_position_ < cont_width / 2) { | |
| 230 separator_position_ = 0; | |
| 231 current_window_ = right_window_; | |
| 232 state_ = INACTIVE; | |
| 233 } else { | |
| 234 separator_position_ = cont_width; | |
| 235 current_window_ = left_window_; | |
| 236 state_ = INACTIVE; | |
| 237 } | |
| 238 Layout(true); | |
| 23 } | 239 } |
| 24 | 240 |
| 25 void SplitViewController::ScrollUpdate(float delta) { | 241 void SplitViewController::ScrollUpdate(float delta) { |
| 242 if (state_ != SCROLLING) | |
| 243 return; | |
| 244 UpdateSeparatorPositionFromScrollDelta(delta); | |
| 245 Layout(false); | |
| 26 } | 246 } |
| 27 | 247 |
| 28 bool SplitViewController::CanScroll() { | 248 bool SplitViewController::CanScroll() { |
| 29 return false; | 249 // TODO (mfomitchev): return false in vertical orientation, in full screen. |
| 250 bool result = (!window_manager_->IsOverviewModeActive() && | |
| 251 !IsSplitViewModeActive() && | |
| 252 window_stack_provider_->GetWindowStack().size() >= 2); | |
| 253 return result; | |
| 254 } | |
| 255 | |
| 256 /////////////////////////////////////////////////////////////////////////////// | |
| 257 // WindowManagerObserver overrides | |
| 258 void SplitViewController::OnOverviewModeEnter() { | |
| 259 if (state_ == ACTIVE) { | |
| 260 CHECK(left_window_); | |
| 261 CHECK(right_window_); | |
| 262 window_stack_provider_->MoveWindowToFront(right_window_); | |
| 263 window_stack_provider_->MoveWindowToFront(left_window_); | |
| 264 // TODO (mfomitchev): This shouldn't be done here, but the overview mode's | |
| 265 // transition animation currently looks bad if the starting transform of | |
| 266 // any window is not gfx::Transform(). | |
| 267 right_window_->SetTransform(gfx::Transform()); | |
| 268 } else if (current_window_) { | |
| 269 window_stack_provider_->MoveWindowToFront(current_window_); | |
| 270 } | |
| 271 current_window_ = NULL; | |
| 272 left_window_ = NULL; | |
| 273 right_window_ = NULL; | |
| 274 state_ = INACTIVE; | |
| 30 } | 275 } |
| 31 | 276 |
| 32 } // namespace athena | 277 } // namespace athena |
| OLD | NEW |