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 |