Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(460)

Side by Side Diff: athena/wm/split_view_controller.cc

Issue 420603011: Split Screen mode implementation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@split_view
Patch Set: Fixing a rebase glitch Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 <cmath>
8
9 #include "athena/wm/public/window_list_provider.h"
10 #include "athena/wm/public/window_manager.h"
11 #include "base/bind.h"
7 #include "ui/aura/window.h" 12 #include "ui/aura/window.h"
13 #include "ui/compositor/layer_animation_observer.h"
14 #include "ui/compositor/scoped_layer_animation_settings.h"
8 #include "ui/events/event_handler.h" 15 #include "ui/events/event_handler.h"
16 #include "ui/gfx/display.h"
17 #include "ui/gfx/screen.h"
9 18
10 namespace athena { 19 namespace athena {
11 20 namespace {
12 SplitViewController::SplitViewController() { 21
22 // An animation observer that runs a callback at the end of the animation, and
23 // destroys itself.
24 class CallbackAnimationObserver : public ui::ImplicitAnimationObserver {
25 public:
26 explicit CallbackAnimationObserver(const base::Closure& closure)
27 : closure_(closure) {}
28
29 virtual ~CallbackAnimationObserver() {}
30
31 private:
32 // Overridden from ui::ImplicitAnimationObserver:
33 virtual void OnImplicitAnimationsCompleted() OVERRIDE {
34 if (!closure_.is_null())
35 closure_.Run();
36 delete this;
37 }
38
39 const base::Closure closure_;
40
41 DISALLOW_COPY_AND_ASSIGN(CallbackAnimationObserver);
42 };
43
44 } // namespace
45
46 SplitViewController::SplitViewController(
47 aura::Window* container,
48 WindowListProvider* window_list_provider,
49 WindowManager* window_manager)
50 : weak_factory_(this),
51 state_(INACTIVE),
52 container_(container),
53 window_manager_(window_manager),
54 window_list_provider_(window_list_provider),
55 current_activity_window_(NULL),
56 left_window_(NULL),
57 right_window_(NULL),
58 separator_position_(0) {
59 window_manager->AddObserver(this);
sadrul 2014/08/09 13:32:40 Should you RemoveObserver() in dtor?
mfomitchev 2014/08/09 18:29:56 Done.
13 } 60 }
14 61
15 SplitViewController::~SplitViewController() { 62 SplitViewController::~SplitViewController() {
16 } 63 }
17 64
65 bool SplitViewController::IsSplitViewModeActive() const {
66 return state_ == ACTIVE;
67 }
68
69 void SplitViewController::UpdateLayout(bool animate) {
70 if (left_window_) {
sadrul 2014/08/09 13:32:40 early return if !left_window_
mfomitchev 2014/08/09 18:29:56 Done.
71 CHECK(right_window_);
72 gfx::Transform left_transform;
73 gfx::Transform right_transform;
74 int container_width = container_->GetBoundsInScreen().width();
75 if (state_ == ACTIVE) {
76 // This method should only be called once in ACTIVE state when
77 // the left and rightwindows are still full screen and need to be resized.
78 CHECK_EQ(left_window_->bounds().width(), container_width);
79 CHECK_EQ(right_window_->bounds().width(), container_width);
80 // Windows should be resized via an animation when entering the ACTIVE
81 // state.
82 CHECK(animate);
83 // We scale the windows here, but when the animation finishes, we reset
84 // the scaling and update the window bounds to the proper size - see
85 // OnAnimationCompleted().
86 left_transform.Scale(.5, 1);
87 right_transform.Scale(.5, 1);
88 right_transform.Translate(container_width, 0);
89 } else {
90 left_transform.Translate(separator_position_ - container_width, 0);
91 right_transform.Translate(separator_position_, 0);
92 }
93 left_window_->Show();
94 right_window_->Show();
95 SetWindowTransform(left_window_, left_transform, animate);
96 SetWindowTransform(right_window_, right_transform, animate);
97 }
98 }
99
100 void SplitViewController::SetWindowTransform(aura::Window* window,
101 const gfx::Transform& transform,
102 bool animate) {
103 if (animate) {
104 scoped_refptr<ui::LayerAnimator> animator = window->layer()->GetAnimator();
105 ui::ScopedLayerAnimationSettings settings(animator);
106 settings.SetPreemptionStrategy(
107 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
108 settings.AddObserver(new CallbackAnimationObserver(
109 base::Bind(&SplitViewController::OnAnimationCompleted,
110 weak_factory_.GetWeakPtr(),
111 window)));
112 window->SetTransform(transform);
113 } else {
114 window->SetTransform(transform);
115 }
116 }
117
118 void SplitViewController::OnAnimationCompleted(aura::Window* window) {
119 DCHECK(window == left_window_ || window == right_window_);
120 if (state_ == ACTIVE) {
121 gfx::Rect bounds_size = gfx::Rect(container_->GetBoundsInScreen().size());
122 int container_width = bounds_size.width();
123 bounds_size.set_width(container_width / 2);
124 if (window == left_window_) {
125 left_window_->SetBounds(bounds_size);
126 left_window_->SetTransform(gfx::Transform());
127 } else {
128 right_window_->SetBounds(bounds_size);
129 gfx::Transform right_transform;
130 right_transform.Translate(container_width / 2, 0);
131 right_window_->SetTransform(right_transform);
sadrul 2014/08/09 13:32:40 You should set the identity-transform on the windo
mfomitchev 2014/08/09 18:29:56 Good point. Done.
132 }
133 } else {
134 int container_width = container_->GetBoundsInScreen().width();
135 if (window == left_window_) {
136 left_window_->SetTransform(gfx::Transform());
137 if (separator_position_ == 0)
138 left_window_->Hide();
139 if (state_ == INACTIVE)
140 left_window_ = NULL;
141 } else {
142 right_window_->SetTransform(gfx::Transform());
143 if (separator_position_ == container_width)
144 right_window_->Hide();
145 if (state_ == INACTIVE)
146 right_window_ = NULL;
147 }
148 }
149 }
150
151 void SplitViewController::UpdateSeparatorPositionFromScrollDelta(float delta) {
152 gfx::Screen* screen = gfx::Screen::GetScreenFor(container_);
153 const gfx::Rect& display_bounds =
154 screen->GetDisplayNearestWindow(container_).bounds();
155 gfx::Rect container_bounds = container_->GetBoundsInScreen();
156 separator_position_ =
157 delta > 0 ? ((int)delta) + display_bounds.x() - container_bounds.x()
158 : display_bounds.right() - container_bounds.x() + delta;
159 }
160
161 aura::Window* SplitViewController::GetCurrentActivityWindow() {
162 if (!current_activity_window_) {
163 aura::Window::Windows windows = window_list_provider_->GetWindowList();
164 if (windows.empty())
165 return NULL;
166 current_activity_window_ = windows.back();
167 }
168 return current_activity_window_;
169 }
170
171 ///////////////////////////////////////////////////////////////////////////////
172 // Begin BezelController::ScrollDelegate overrides.
18 void SplitViewController::ScrollBegin(BezelController::Bezel bezel, 173 void SplitViewController::ScrollBegin(BezelController::Bezel bezel,
19 float delta) { 174 float delta) {
20 } 175 if (!CanScroll())
21 176 return;
177 state_ = SCROLLING;
178 aura::Window* current_window = GetCurrentActivityWindow();
179 CHECK(current_window);
180
181 aura::Window::Windows windows = window_list_provider_->GetWindowList();
182 CHECK(windows.size() >= 2);
183 aura::Window::Windows::const_iterator it =
184 std::find(windows.begin(), windows.end(), current_window);
185 CHECK(it != windows.end());
186
187 if (delta > 0) {
188 right_window_ = current_window;
189 // reverse iterator points to the position before normal iterator |it|
190 aura::Window::Windows::const_reverse_iterator rev_it(it);
191 // circle to end if needed.
192 left_window_ = rev_it == windows.rend() ? windows.back() : *(rev_it);
193 } else {
194 left_window_ = current_window;
195 ++it;
196 // circle to front if needed.
197 right_window_ = it == windows.end() ? windows.front() : *it;
198 }
199
200 CHECK(left_window_);
201 CHECK(right_window_);
202
203 // TODO(oshima|mfomitchev): crbug.com/388362
204 // Until we are properly hiding off-screen windows in window manager:
205 // Loop through all windows and hide them
206 for (it = windows.begin(); it != windows.end(); ++it) {
207 if (*it != left_window_ && *it != right_window_)
208 (*it)->Hide();
209 }
210
211 UpdateSeparatorPositionFromScrollDelta(delta);
212 UpdateLayout(false);
213 }
214
215 // Max distance from the scroll end position to the middle of the screen where
216 // we would go into the split view mode.
217 const int kMaxDistanceFromMiddle = 120;
22 void SplitViewController::ScrollEnd() { 218 void SplitViewController::ScrollEnd() {
219 if (state_ != SCROLLING)
220 return;
221
222 int container_width = container_->GetBoundsInScreen().width();
223 if (std::abs(container_width / 2 - separator_position_) <=
224 kMaxDistanceFromMiddle) {
225 state_ = ACTIVE;
226 separator_position_ = container_width / 2;
227 } else if (separator_position_ < container_width / 2) {
228 separator_position_ = 0;
229 current_activity_window_ = right_window_;
230 state_ = INACTIVE;
231 } else {
232 separator_position_ = container_width;
233 current_activity_window_ = left_window_;
234 state_ = INACTIVE;
235 }
236 UpdateLayout(true);
23 } 237 }
24 238
25 void SplitViewController::ScrollUpdate(float delta) { 239 void SplitViewController::ScrollUpdate(float delta) {
240 if (state_ != SCROLLING)
241 return;
242 UpdateSeparatorPositionFromScrollDelta(delta);
243 UpdateLayout(false);
26 } 244 }
27 245
28 bool SplitViewController::CanScroll() { 246 bool SplitViewController::CanScroll() {
29 return false; 247 // TODO(mfomitchev): return false in vertical orientation, in full screen.
248 bool result = (!window_manager_->IsOverviewModeActive() &&
249 !IsSplitViewModeActive() &&
250 window_list_provider_->GetWindowList().size() >= 2);
251 return result;
252 }
253
254 ///////////////////////////////////////////////////////////////////////////////
255 // WindowManagerObserver overrides
256 void SplitViewController::OnOverviewModeEnter() {
257 if (state_ == ACTIVE) {
258 CHECK(left_window_);
259 CHECK(right_window_);
260 window_list_provider_->MoveToFront(right_window_);
261 window_list_provider_->MoveToFront(left_window_);
262 // TODO(mfomitchev): This shouldn't be done here, but the overview mode's
263 // transition animation currently looks bad if the starting transform of
264 // any window is not gfx::Transform().
265 right_window_->SetTransform(gfx::Transform());
266 } else if (current_activity_window_) {
267 window_list_provider_->MoveToFront(current_activity_window_);
268 }
269 state_ = INACTIVE;
270 left_window_ = NULL;
271 right_window_ = NULL;
272 current_activity_window_ = NULL;
273 }
274
275 void SplitViewController::OnOverviewModeExit() {
30 } 276 }
31 277
32 } // namespace athena 278 } // namespace athena
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698