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