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 |