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 <cmath> | 7 #include <cmath> |
8 | 8 |
9 #include "athena/screen/public/screen_manager.h" | 9 #include "athena/screen/public/screen_manager.h" |
10 #include "athena/wm/public/window_list_provider.h" | 10 #include "athena/wm/public/window_list_provider.h" |
11 #include "athena/wm/public/window_manager.h" | 11 #include "athena/wm/public/window_manager.h" |
12 #include "base/bind.h" | 12 #include "base/bind.h" |
13 #include "ui/aura/scoped_window_targeter.h" | |
13 #include "ui/aura/window.h" | 14 #include "ui/aura/window.h" |
15 #include "ui/aura/window_delegate.h" | |
16 #include "ui/aura/window_targeter.h" | |
17 #include "ui/base/cursor/cursor.h" | |
18 #include "ui/base/hit_test.h" | |
14 #include "ui/compositor/closure_animation_observer.h" | 19 #include "ui/compositor/closure_animation_observer.h" |
15 #include "ui/compositor/layer_animation_observer.h" | 20 #include "ui/compositor/layer.h" |
16 #include "ui/compositor/scoped_layer_animation_settings.h" | 21 #include "ui/compositor/scoped_layer_animation_settings.h" |
17 #include "ui/events/event_handler.h" | 22 #include "ui/events/event_handler.h" |
18 #include "ui/gfx/display.h" | 23 #include "ui/gfx/display.h" |
19 #include "ui/gfx/screen.h" | 24 #include "ui/gfx/screen.h" |
25 #include "ui/views/widget/root_view.h" | |
26 #include "ui/views/widget/root_view_targeter.h" | |
27 #include "ui/views/widget/widget.h" | |
20 #include "ui/wm/core/window_util.h" | 28 #include "ui/wm/core/window_util.h" |
29 #include "ui/wm/public/window_types.h" | |
21 | 30 |
22 namespace athena { | 31 namespace athena { |
23 | 32 |
24 namespace { | 33 namespace { |
25 | 34 |
26 // Returns a target transform which is suitable for animating a windows's | 35 const int kDragHandleWidth = 4; |
27 // bounds. | 36 const int kDragHandleHeight = 80; |
28 gfx::Transform GetTargetTransformForBoundsAnimation(const gfx::Rect& from, | 37 const int kDividerWidth = 6; |
29 const gfx::Rect& to) { | 38 |
39 // TODO(mfomitchev): Should this be moved to ui/views? | |
40 | |
41 // Always returns the same target. | |
42 class StaticViewTargeterDelegate : public views::ViewTargeterDelegate { | |
43 public: | |
44 explicit StaticViewTargeterDelegate(views::View* target) | |
45 : target_(target) {} | |
46 | |
47 virtual ~StaticViewTargeterDelegate() {} | |
48 | |
49 private: | |
50 // views::ViewTargeterDelegate | |
51 virtual views::View* TargetForRect( | |
52 views::View* root, const gfx::Rect& rect) OVERRIDE { | |
53 return target_; | |
54 } | |
55 | |
56 // Not owned. | |
57 views::View* target_; | |
58 | |
59 DISALLOW_COPY_AND_ASSIGN(StaticViewTargeterDelegate); | |
60 }; | |
61 | |
62 // TODO(mfomitchev): This is a copy of EmptyWindowDelegate in | |
63 // ash/root_window_controller.cc. Should we move this somewhere we can reuse in | |
64 // both ash and athena? It looks like mojo::DummyDelegate could use this as | |
65 // well. | |
66 // Perhaps we could have ui/aura/empty_window_delegate.h or | |
67 // aura::CreateEmptyWIndowDelegate() in ui/aura/window_delegate.h | |
68 | |
69 // A window delegate which does nothing. Used to create a window that | |
70 // is a event target, but do nothing. | |
71 class EmptyWindowDelegate : public aura::WindowDelegate { | |
72 public: | |
73 EmptyWindowDelegate() {} | |
74 virtual ~EmptyWindowDelegate() {} | |
75 | |
76 // aura::WindowDelegate overrides: | |
77 virtual gfx::Size GetMinimumSize() const OVERRIDE { | |
78 return gfx::Size(); | |
79 } | |
80 virtual gfx::Size GetMaximumSize() const OVERRIDE { | |
81 return gfx::Size(); | |
82 } | |
83 virtual void OnBoundsChanged(const gfx::Rect& old_bounds, | |
84 const gfx::Rect& new_bounds) OVERRIDE { | |
85 } | |
86 virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE { | |
87 return gfx::kNullCursor; | |
88 } | |
89 virtual int GetNonClientComponent( | |
90 const gfx::Point& point) const OVERRIDE { | |
91 return HTNOWHERE; | |
92 } | |
93 virtual bool ShouldDescendIntoChildForEventHandling( | |
94 aura::Window* child, | |
95 const gfx::Point& location) OVERRIDE { | |
96 return false; | |
97 } | |
98 virtual bool CanFocus() OVERRIDE { | |
99 return false; | |
100 } | |
101 virtual void OnCaptureLost() OVERRIDE { | |
102 } | |
103 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { | |
104 } | |
105 virtual void OnDeviceScaleFactorChanged( | |
106 float device_scale_factor) OVERRIDE { | |
107 } | |
108 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {} | |
sadrul
2014/09/15 14:32:29
Some have {} in the same line, some have these in
mfomitchev
2014/09/15 16:37:23
Done. All methods that don't do anything have {} o
| |
109 virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE { | |
110 delete this; | |
111 } | |
112 virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE { | |
113 } | |
114 virtual bool HasHitTestMask() const OVERRIDE { | |
115 return false; | |
116 } | |
117 virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE {} | |
118 | |
119 private: | |
120 DISALLOW_COPY_AND_ASSIGN(EmptyWindowDelegate); | |
121 | |
122 }; | |
123 | |
124 // Expands the effective target area of a window ensuring it is easy to touch. | |
125 // If the window is big enough to begin with, there should be no change from | |
126 // the default targeting behavior. | |
127 class PriorityWindowTargeter : public aura::WindowTargeter, | |
128 public aura::WindowObserver { | |
129 public: | |
130 explicit PriorityWindowTargeter(aura::Window* priority_window) | |
131 : priority_window_(priority_window) { | |
132 DCHECK(priority_window); | |
133 priority_window->AddObserver(this); | |
134 } | |
135 | |
136 virtual ~PriorityWindowTargeter() { | |
137 priority_window_->RemoveObserver(this); | |
138 } | |
139 | |
140 private: | |
141 bool ShouldProcessEvent(ui::EventType event_type) { | |
142 return event_type == ui::ET_TOUCH_PRESSED; | |
143 } | |
144 | |
145 // aura::WindowTargeter: | |
146 virtual ui::EventTarget* FindTargetForLocatedEvent( | |
147 ui::EventTarget* root, | |
148 ui::LocatedEvent* event) OVERRIDE { | |
149 if (!priority_window_ || (event->type() != ui::ET_TOUCH_PRESSED)) | |
150 return WindowTargeter::FindTargetForLocatedEvent(root, event); | |
151 | |
152 gfx::Rect window_bounds = priority_window_->GetBoundsInRootWindow(); | |
153 gfx::Transform window_transform = priority_window_->layer()->transform(); | |
154 gfx::RectF transformed_bounds_f = window_bounds; | |
155 window_transform.TransformRect(&transformed_bounds_f); | |
156 gfx::Rect transformed_bounds = gfx::Rect(transformed_bounds_f.x(), | |
157 transformed_bounds_f.y(), | |
158 transformed_bounds_f.width(), | |
159 transformed_bounds_f.height()); | |
160 | |
161 gfx::Point window_center = transformed_bounds.CenterPoint(); | |
162 gfx::Rect extension_rect = gfx::Rect( | |
163 window_center.x() - kMinTouchDimension / 2, | |
164 window_center.y() - kMinTouchDimension / 2, | |
165 kMinTouchDimension, | |
166 kMinTouchDimension); | |
167 gfx::Rect extended_bounds = | |
168 gfx::UnionRects(transformed_bounds, extension_rect); | |
169 if (extended_bounds.Contains(event->root_location().x(), | |
170 event->root_location().y())) { | |
171 root->ConvertEventToTarget(priority_window_, event); | |
172 return priority_window_; | |
173 } | |
174 | |
175 return WindowTargeter::FindTargetForLocatedEvent(root, event); | |
176 } | |
177 | |
178 // aura::WindowObserver: | |
179 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE { | |
180 DCHECK_EQ(window, priority_window_); | |
181 priority_window_->RemoveObserver(this); | |
182 priority_window_ = NULL; | |
183 } | |
184 | |
185 // Minimum dimension of a target to be comfortably touchable. | |
186 // The effective touch target area of |priority_window_| gets expanded so | |
187 // that it's width and height is ayt least |kMinTouchDimension|. | |
188 int const kMinTouchDimension = 26; | |
189 | |
190 aura::Window* priority_window_; | |
191 | |
192 DISALLOW_COPY_AND_ASSIGN(PriorityWindowTargeter); | |
193 }; | |
194 | |
195 // Returns a target transform required to transform |from| to |to|. | |
196 gfx::Transform GetTransformForBounds(const gfx::Rect& from, | |
197 const gfx::Rect& to) { | |
30 gfx::Transform transform; | 198 gfx::Transform transform; |
31 transform.Translate(to.x() - from.x(), to.y() - from.y()); | 199 transform.Translate(to.x() - from.x(), to.y() - from.y()); |
32 transform.Scale(to.width() / static_cast<float>(from.width()), | 200 transform.Scale(to.width() / static_cast<float>(from.width()), |
33 to.height() / static_cast<float>(from.height())); | 201 to.height() / static_cast<float>(from.height())); |
34 return transform; | 202 return transform; |
35 } | 203 } |
36 | 204 |
37 bool IsLandscapeOrientation(gfx::Display::Rotation rotation) { | 205 bool IsLandscapeOrientation(gfx::Display::Rotation rotation) { |
38 return rotation == gfx::Display::ROTATE_0 || | 206 return rotation == gfx::Display::ROTATE_0 || |
39 rotation == gfx::Display::ROTATE_180; | 207 rotation == gfx::Display::ROTATE_180; |
40 } | 208 } |
41 | 209 |
42 } // namespace | 210 } // namespace |
43 | 211 |
44 SplitViewController::SplitViewController( | 212 SplitViewController::SplitViewController( |
45 aura::Window* container, | 213 aura::Window* container, |
46 WindowListProvider* window_list_provider) | 214 WindowListProvider* window_list_provider) |
47 : state_(INACTIVE), | 215 : state_(INACTIVE), |
48 container_(container), | 216 container_(container), |
49 window_list_provider_(window_list_provider), | 217 window_list_provider_(window_list_provider), |
50 left_window_(NULL), | 218 left_window_(NULL), |
51 right_window_(NULL), | 219 right_window_(NULL), |
52 separator_position_(0), | 220 divider_position_(0), |
221 divider_widget_(NULL), | |
53 weak_factory_(this) { | 222 weak_factory_(this) { |
54 } | 223 } |
55 | 224 |
56 SplitViewController::~SplitViewController() { | 225 SplitViewController::~SplitViewController() { |
57 } | 226 } |
58 | 227 |
59 bool SplitViewController::IsSplitViewModeActive() const { | 228 bool SplitViewController::IsSplitViewModeActive() const { |
60 return state_ == ACTIVE; | 229 return state_ == ACTIVE; |
61 } | 230 } |
62 | 231 |
(...skipping 24 matching lines...) Expand all Loading... | |
87 | 256 |
88 if (!right && iter != windows.rend()) { | 257 if (!right && iter != windows.rend()) { |
89 right = *iter; | 258 right = *iter; |
90 iter++; | 259 iter++; |
91 if (right == left && iter != windows.rend()) { | 260 if (right == left && iter != windows.rend()) { |
92 right = *iter; | 261 right = *iter; |
93 iter++; | 262 iter++; |
94 } | 263 } |
95 } | 264 } |
96 | 265 |
266 int container_width = container_->GetBoundsInScreen().width(); | |
267 divider_position_ = container_width / 2; | |
97 SetState(ACTIVE); | 268 SetState(ACTIVE); |
98 if (right_window_ != right) { | 269 if (right_window_ != right) { |
99 right_window_ = right; | 270 right_window_ = right; |
100 container_->StackChildAtTop(right_window_); | 271 container_->StackChildAtTop(right_window_); |
101 } | 272 } |
102 if (left_window_ != left) { | 273 if (left_window_ != left) { |
103 left_window_ = left; | 274 left_window_ = left; |
104 container_->StackChildAtTop(left_window_); | 275 container_->StackChildAtTop(left_window_); |
105 } | 276 } |
277 | |
106 UpdateLayout(true); | 278 UpdateLayout(true); |
107 } | 279 } |
108 | 280 |
109 void SplitViewController::ReplaceWindow(aura::Window* window, | 281 void SplitViewController::ReplaceWindow(aura::Window* window, |
110 aura::Window* replace_with) { | 282 aura::Window* replace_with) { |
111 CHECK(IsSplitViewModeActive()); | 283 CHECK(IsSplitViewModeActive()); |
112 CHECK(replace_with); | 284 CHECK(replace_with); |
113 CHECK(window == left_window_ || window == right_window_); | 285 CHECK(window == left_window_ || window == right_window_); |
114 CHECK(replace_with != left_window_ && replace_with != right_window_); | 286 CHECK(replace_with != left_window_ && replace_with != right_window_); |
115 #if !defined(NDEBUG) | 287 #if !defined(NDEBUG) |
(...skipping 12 matching lines...) Expand all Loading... | |
128 window->Hide(); | 300 window->Hide(); |
129 } | 301 } |
130 | 302 |
131 void SplitViewController::DeactivateSplitMode() { | 303 void SplitViewController::DeactivateSplitMode() { |
132 CHECK_EQ(ACTIVE, state_); | 304 CHECK_EQ(ACTIVE, state_); |
133 SetState(INACTIVE); | 305 SetState(INACTIVE); |
134 UpdateLayout(false); | 306 UpdateLayout(false); |
135 left_window_ = right_window_ = NULL; | 307 left_window_ = right_window_ = NULL; |
136 } | 308 } |
137 | 309 |
138 gfx::Rect SplitViewController::GetLeftTargetBounds() { | 310 void SplitViewController::InitializeDivider() { |
139 gfx::Rect work_area = | 311 CHECK(!divider_widget_); |
140 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().work_area(); | 312 CHECK(!divider_window_); |
141 return gfx::Rect(0, 0, container_->bounds().width() / 2, work_area.height()); | 313 |
314 divider_window_.reset(new aura::Window(new EmptyWindowDelegate())); | |
sadrul
2014/09/15 14:32:29
What's the purpose of |divider_window_|?
mfomitchev
2014/09/15 16:37:23
It covers the empty space between two windows in s
sadrul
2014/09/15 16:53:31
You don't need a separate window for this. You sho
mfomitchev
2014/09/15 17:44:20
If we do that, we will steal the entire right edge
sadrul
2014/09/15 17:50:25
It still doesn't make sense to have to maintain tw
mfomitchev
2014/09/15 18:34:21
I guess we could do that..
- I guess PriorityWindo
| |
315 divider_window_->SetType(ui::wm::WINDOW_TYPE_CONTROL); | |
316 divider_window_->Init(aura::WINDOW_LAYER_SOLID_COLOR); | |
317 divider_window_->layer()->SetColor(SK_ColorBLACK); | |
318 int container_height = container_->bounds().height(); | |
319 divider_window_->SetBounds( | |
320 gfx::Rect(-kDividerWidth / 2, 0, kDividerWidth, container_height)); | |
321 container_->AddChild(divider_window_.get()); | |
322 container_->StackChildAtTop(divider_window_.get()); | |
323 | |
324 views::View* divider_view = CreateDragHandleView(DragHandle::HORIZONTAL, | |
325 this, | |
326 kDragHandleWidth, | |
327 kDragHandleHeight, | |
328 1); | |
329 divider_widget_ = new views::Widget(); | |
330 views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL); | |
331 params.parent = container_; | |
332 params.accept_events = true; | |
333 params.activatable = views::Widget::InitParams::ACTIVATABLE_YES; | |
sadrul
2014/09/15 14:32:29
Make this ACTIVATABLE_NO (it should still be able
mfomitchev
2014/09/15 16:37:24
Done. Thanks.
| |
334 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; | |
335 params.bounds = gfx::Rect(-kDragHandleWidth / 2, | |
336 container_height / 2 - kDragHandleHeight / 2, | |
337 kDragHandleWidth, | |
338 kDragHandleHeight); | |
339 divider_widget_->Init(params); | |
340 divider_widget_->SetContentsView(divider_view); | |
341 | |
342 // Install a static view targeter on the root view which always targets | |
343 // divider_view. | |
344 // TODO(mfomitchev,tdanderson): This may not be needed if/when the logic | |
345 // in ViewTargeterDelegate::TargetForRect is changed to work better for | |
346 // views that are narrow in one dimension and long in another dimension. | |
347 views::internal::RootView* root_view = | |
348 static_cast<views::internal::RootView*>(divider_widget_->GetRootView()); | |
349 views::View* target_view = divider_view; | |
350 views::ViewTargeter* targeter = new views::RootViewTargeter( | |
351 new StaticViewTargeterDelegate(target_view), | |
352 root_view); | |
353 divider_widget_->GetRootView()->SetEventTargeter( | |
354 scoped_ptr<views::ViewTargeter>(targeter)); | |
sadrul
2014/09/15 14:32:29
|divider_view| is the only view (other than the in
mfomitchev
2014/09/15 16:37:23
It doesn't work if I remove this view targeter. It
sadrul
2014/09/15 16:53:31
This is a pretty bad bug. You should file a crbug
mfomitchev
2014/09/15 17:44:20
Done.
| |
142 } | 355 } |
143 | 356 |
144 gfx::Rect SplitViewController::GetRightTargetBounds() { | 357 void SplitViewController::HideDivider() { |
145 gfx::Rect work_area = | 358 divider_widget_->Hide(); |
146 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().work_area(); | 359 divider_window_->Hide(); |
360 window_targeter_.reset(); | |
361 } | |
362 | |
363 void SplitViewController::ShowDivider() { | |
364 divider_widget_->Show(); | |
365 divider_window_->Show(); | |
366 if (!window_targeter_) { | |
367 scoped_ptr<ui::EventTargeter> window_targeter = | |
368 scoped_ptr<ui::EventTargeter>( | |
369 new PriorityWindowTargeter(divider_widget_->GetNativeWindow())); | |
370 window_targeter_.reset( | |
371 new aura::ScopedWindowTargeter(container_, window_targeter.Pass())); | |
372 } | |
373 } | |
374 | |
375 gfx::Rect SplitViewController::GetLeftAreaBounds() { | |
376 int container_height = container_->bounds().height(); | |
377 return gfx::Rect( | |
378 0, 0, divider_position_ - kDividerWidth / 2, container_height); | |
379 } | |
380 | |
381 gfx::Rect SplitViewController::GetRightAreaBounds() { | |
147 int container_width = container_->bounds().width(); | 382 int container_width = container_->bounds().width(); |
148 return gfx::Rect( | 383 int container_height = container_->bounds().height(); |
149 container_width / 2, 0, container_width / 2, work_area.height()); | 384 return gfx::Rect(divider_position_ + kDividerWidth / 2, |
385 0, | |
386 container_width - divider_position_ - kDividerWidth / 2, | |
387 container_height); | |
150 } | 388 } |
151 | 389 |
152 void SplitViewController::SetState(SplitViewController::State state) { | 390 void SplitViewController::SetState(SplitViewController::State state) { |
153 if (state_ == state) | 391 if (state_ == state) |
154 return; | 392 return; |
155 | 393 |
394 if (divider_widget_ == NULL) { | |
395 InitializeDivider(); | |
396 } | |
397 | |
156 state_ = state; | 398 state_ = state; |
399 | |
157 ScreenManager::Get()->SetRotationLocked(state_ != INACTIVE); | 400 ScreenManager::Get()->SetRotationLocked(state_ != INACTIVE); |
401 if (state == INACTIVE) | |
402 HideDivider(); | |
403 else | |
404 ShowDivider(); | |
158 } | 405 } |
159 | 406 |
160 void SplitViewController::UpdateLayout(bool animate) { | 407 void SplitViewController::UpdateLayout(bool animate) { |
161 CHECK(left_window_); | 408 CHECK(left_window_); |
162 CHECK(right_window_); | 409 CHECK(right_window_); |
163 | |
164 // Splitview can be activated from SplitViewController::ActivateSplitMode or | 410 // Splitview can be activated from SplitViewController::ActivateSplitMode or |
165 // SplitViewController::ScrollEnd. Additionally we don't want to rotate the | 411 // SplitViewController::ScrollEnd. Additionally we don't want to rotate the |
166 // screen while engaging splitview (i.e. state_ == SCROLLING). | 412 // screen while engaging splitview (i.e. state_ == SCROLLING). |
167 if (state_ == INACTIVE && !animate) { | 413 if (state_ == INACTIVE && !animate) { |
168 if (!wm::IsActiveWindow(left_window_)) | 414 aura::Window* active_window = window_list_provider_->GetWindowList().back(); |
415 if (active_window != left_window_) { | |
169 left_window_->Hide(); | 416 left_window_->Hide(); |
170 if (!wm::IsActiveWindow(right_window_)) | 417 right_window_->SetBounds(gfx::Rect(container_->bounds())); |
418 } | |
419 if (active_window != right_window_) { | |
420 left_window_->SetBounds(gfx::Rect(container_->bounds())); | |
171 right_window_->Hide(); | 421 right_window_->Hide(); |
172 SetWindowTransforms(gfx::Transform(), gfx::Transform(), false); | 422 } |
423 SetWindowTransforms( | |
424 gfx::Transform(), gfx::Transform(), gfx::Transform(), false); | |
173 return; | 425 return; |
174 } | 426 } |
175 | 427 |
176 left_window_->Show(); | 428 left_window_->Show(); |
177 right_window_->Show(); | 429 right_window_->Show(); |
430 gfx::Transform divider_transform; | |
431 divider_transform.Translate(divider_position_, 0); | |
178 if (state_ == ACTIVE) { | 432 if (state_ == ACTIVE) { |
179 if (animate) { | 433 if (animate) { |
180 gfx::Transform left_transform = GetTargetTransformForBoundsAnimation( | 434 gfx::Transform left_transform = |
181 left_window_->bounds(), GetLeftTargetBounds()); | 435 GetTransformForBounds(left_window_->bounds(), GetLeftAreaBounds()); |
182 gfx::Transform right_transform = GetTargetTransformForBoundsAnimation( | 436 gfx::Transform right_transform = |
183 right_window_->bounds(), GetRightTargetBounds()); | 437 GetTransformForBounds(right_window_->bounds(), GetRightAreaBounds()); |
184 SetWindowTransforms(left_transform, right_transform, true); | 438 SetWindowTransforms( |
439 left_transform, right_transform, divider_transform, true); | |
185 } else { | 440 } else { |
186 left_window_->SetBounds(GetLeftTargetBounds()); | 441 left_window_->SetBounds(GetLeftAreaBounds()); |
187 right_window_->SetBounds(GetRightTargetBounds()); | 442 right_window_->SetBounds(GetRightAreaBounds()); |
188 SetWindowTransforms(gfx::Transform(), gfx::Transform(), false); | 443 SetWindowTransforms( |
444 gfx::Transform(), gfx::Transform(), divider_transform, false); | |
189 } | 445 } |
190 } else { | 446 } else { |
191 gfx::Transform left_transform; | 447 gfx::Transform left_transform; |
192 left_transform.Translate(separator_position_ - container_->bounds().width(), | |
193 0); | |
194 gfx::Transform right_transform; | 448 gfx::Transform right_transform; |
195 right_transform.Translate(separator_position_, 0); | 449 gfx::Rect left_area_bounds = GetLeftAreaBounds(); |
196 SetWindowTransforms(left_transform, right_transform, animate); | 450 gfx::Rect right_area_bounds = GetRightAreaBounds(); |
451 // If the width of the window is greater than the width of the area which it | |
452 // is supposed to occupy - translate the window. Otherwise scale the window | |
453 // up to fill the target area. | |
454 if (left_window_->bounds().width() >= left_area_bounds.width()) { | |
455 left_transform.Translate( | |
456 left_area_bounds.right() - left_window_->bounds().right(), 0); | |
457 } else { | |
458 left_transform = | |
459 GetTransformForBounds(left_window_->bounds(), left_area_bounds); | |
460 } | |
461 if (right_window_->bounds().width() >= right_area_bounds.width()) { | |
462 right_transform.Translate( | |
463 right_area_bounds.x() - right_window_->bounds().x(), 0); | |
464 } else { | |
465 right_transform = | |
466 GetTransformForBounds(right_window_->bounds(), right_area_bounds); | |
467 } | |
468 SetWindowTransforms( | |
469 left_transform, right_transform, divider_transform, animate); | |
197 } | 470 } |
198 // Note: |left_window_| and |right_window_| may be NULL if calling | 471 // Note: |left_window_| and |right_window_| may be NULL if calling |
199 // SetWindowTransforms(): | 472 // SetWindowTransforms(): |
200 // - caused the in-progress animation to abort. | 473 // - caused the in-progress animation to abort. |
201 // - started a zero duration animation. | 474 // - started a zero duration animation. |
202 } | 475 } |
203 | 476 |
204 void SplitViewController::SetWindowTransforms( | 477 void SplitViewController::SetWindowTransforms( |
205 const gfx::Transform& left_transform, | 478 const gfx::Transform& left_transform, |
206 const gfx::Transform& right_transform, | 479 const gfx::Transform& right_transform, |
480 const gfx::Transform& divider_transform, | |
207 bool animate) { | 481 bool animate) { |
208 if (animate) { | 482 if (animate) { |
209 ui::ScopedLayerAnimationSettings left_settings( | 483 ui::ScopedLayerAnimationSettings left_settings( |
210 left_window_->layer()->GetAnimator()); | 484 left_window_->layer()->GetAnimator()); |
211 left_settings.SetPreemptionStrategy( | 485 left_settings.SetPreemptionStrategy( |
212 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | 486 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
213 left_window_->SetTransform(left_transform); | 487 left_window_->SetTransform(left_transform); |
214 | 488 |
489 ui::ScopedLayerAnimationSettings divider_widget_settings( | |
490 divider_widget_->GetNativeWindow()->layer()->GetAnimator()); | |
491 divider_widget_settings.SetPreemptionStrategy( | |
492 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | |
493 divider_widget_->GetNativeWindow()->SetTransform(divider_transform); | |
494 | |
495 ui::ScopedLayerAnimationSettings divider_layer_settings( | |
496 divider_window_->layer()->GetAnimator()); | |
497 divider_layer_settings.SetPreemptionStrategy( | |
498 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | |
499 divider_window_->SetTransform(divider_transform); | |
500 | |
215 ui::ScopedLayerAnimationSettings right_settings( | 501 ui::ScopedLayerAnimationSettings right_settings( |
216 right_window_->layer()->GetAnimator()); | 502 right_window_->layer()->GetAnimator()); |
217 right_settings.SetPreemptionStrategy( | 503 right_settings.SetPreemptionStrategy( |
218 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | 504 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
219 right_settings.AddObserver(new ui::ClosureAnimationObserver( | 505 right_settings.AddObserver(new ui::ClosureAnimationObserver( |
220 base::Bind(&SplitViewController::OnAnimationCompleted, | 506 base::Bind(&SplitViewController::OnAnimationCompleted, |
221 weak_factory_.GetWeakPtr()))); | 507 weak_factory_.GetWeakPtr()))); |
222 right_window_->SetTransform(right_transform); | 508 right_window_->SetTransform(right_transform); |
223 } else { | 509 } else { |
224 left_window_->SetTransform(left_transform); | 510 left_window_->SetTransform(left_transform); |
225 right_window_->SetTransform(right_transform); | 511 right_window_->SetTransform(right_transform); |
512 divider_widget_->GetNativeWindow()->SetTransform(divider_transform); | |
513 divider_window_->SetTransform(divider_transform); | |
226 } | 514 } |
227 } | 515 } |
228 | 516 |
229 void SplitViewController::OnAnimationCompleted() { | 517 void SplitViewController::OnAnimationCompleted() { |
230 // Animation can be cancelled when deactivated. | 518 // Animation can be cancelled when deactivated. |
231 if (left_window_ == NULL) | 519 if (left_window_ == NULL) |
232 return; | 520 return; |
233 UpdateLayout(false); | 521 UpdateLayout(false); |
234 | 522 |
235 if (state_ == INACTIVE) { | 523 if (state_ == INACTIVE) { |
236 left_window_ = NULL; | 524 left_window_ = NULL; |
237 right_window_ = NULL; | 525 right_window_ = NULL; |
238 } | 526 } |
239 } | 527 } |
240 | 528 |
241 void SplitViewController::UpdateSeparatorPositionFromScrollDelta(float delta) { | 529 void SplitViewController::UpdateSeparatorPositionFromScrollDelta(float delta) { |
242 gfx::Screen* screen = gfx::Screen::GetScreenFor(container_); | 530 gfx::Screen* screen = gfx::Screen::GetScreenFor(container_); |
243 const gfx::Rect& display_bounds = | 531 const gfx::Rect& display_bounds = |
244 screen->GetDisplayNearestWindow(container_).bounds(); | 532 screen->GetDisplayNearestWindow(container_).bounds(); |
245 gfx::Rect container_bounds = container_->GetBoundsInScreen(); | 533 gfx::Rect container_bounds = container_->GetBoundsInScreen(); |
246 separator_position_ = | 534 divider_position_ = |
247 delta > 0 ? ((int)delta) + display_bounds.x() - container_bounds.x() | 535 delta > 0 ? ((int)delta) + display_bounds.x() - container_bounds.x() |
248 : display_bounds.right() - container_bounds.x() + delta; | 536 : display_bounds.right() - container_bounds.x() + delta; |
249 } | 537 } |
250 | 538 |
251 /////////////////////////////////////////////////////////////////////////////// | 539 /////////////////////////////////////////////////////////////////////////////// |
252 // BezelController::ScrollDelegate: | 540 // BezelController::ScrollDelegate: |
253 | 541 |
254 void SplitViewController::ScrollBegin(BezelController::Bezel bezel, | 542 void SplitViewController::ScrollBegin(BezelController::Bezel bezel, |
255 float delta) { | 543 float delta) { |
256 if (!CanScroll()) | 544 if (!CanScroll()) |
257 return; | 545 return; |
546 | |
258 SetState(SCROLLING); | 547 SetState(SCROLLING); |
259 | 548 |
260 aura::Window::Windows windows = window_list_provider_->GetWindowList(); | 549 aura::Window::Windows windows = window_list_provider_->GetWindowList(); |
261 CHECK(windows.size() >= 2); | 550 CHECK(windows.size() >= 2); |
262 aura::Window::Windows::const_reverse_iterator iter = windows.rbegin(); | 551 aura::Window::Windows::const_reverse_iterator iter = windows.rbegin(); |
263 aura::Window* current_window = *(iter); | 552 aura::Window* current_window = *(iter); |
264 CHECK(wm::IsActiveWindow(current_window)); | |
265 | 553 |
266 if (delta > 0) { | 554 if (delta > 0) { |
267 right_window_ = current_window; | 555 right_window_ = current_window; |
268 left_window_ = *(iter + 1); | 556 left_window_ = *(iter + 1); |
269 } else { | 557 } else { |
270 left_window_ = current_window; | 558 left_window_ = current_window; |
271 right_window_ = *(iter + 1); | 559 right_window_ = *(iter + 1); |
272 } | 560 } |
273 | 561 |
274 CHECK(left_window_); | 562 CHECK(left_window_); |
275 CHECK(right_window_); | 563 CHECK(right_window_); |
276 | 564 |
277 UpdateSeparatorPositionFromScrollDelta(delta); | 565 UpdateSeparatorPositionFromScrollDelta(delta); |
278 UpdateLayout(false); | 566 UpdateLayout(false); |
279 } | 567 } |
280 | 568 |
281 void SplitViewController::ScrollEnd() { | 569 void SplitViewController::ScrollEnd() { |
282 if (state_ != SCROLLING) | 570 if (state_ != SCROLLING) |
283 return; | 571 return; |
284 | 572 |
285 // Max distance from the scroll end position to the middle of the screen where | 573 // Max distance from the scroll end position to the middle of the screen where |
286 // we would go into the split view mode. | 574 // we would go into the split view mode. |
287 const int kMaxDistanceFromMiddle = 120; | 575 const int kMaxDistanceFromMiddle = 120; |
288 int container_width = container_->GetBoundsInScreen().width(); | 576 int container_width = container_->GetBoundsInScreen().width(); |
289 if (std::abs(container_width / 2 - separator_position_) <= | 577 if (std::abs(container_width / 2 - divider_position_) <= |
290 kMaxDistanceFromMiddle) { | 578 kMaxDistanceFromMiddle) { |
579 divider_position_ = container_width / 2; | |
291 SetState(ACTIVE); | 580 SetState(ACTIVE); |
292 separator_position_ = container_width / 2; | 581 } else if (divider_position_ < container_width / 2) { |
293 } else if (separator_position_ < container_width / 2) { | 582 divider_position_ = 0; |
294 separator_position_ = 0; | |
295 SetState(INACTIVE); | 583 SetState(INACTIVE); |
296 wm::ActivateWindow(right_window_); | 584 wm::ActivateWindow(right_window_); |
297 } else { | 585 } else { |
298 separator_position_ = container_width; | 586 divider_position_ = container_width; |
299 SetState(INACTIVE); | 587 SetState(INACTIVE); |
300 wm::ActivateWindow(left_window_); | 588 wm::ActivateWindow(left_window_); |
301 } | 589 } |
302 UpdateLayout(true); | 590 UpdateLayout(true); |
303 } | 591 } |
304 | 592 |
305 void SplitViewController::ScrollUpdate(float delta) { | 593 void SplitViewController::ScrollUpdate(float delta) { |
306 if (state_ != SCROLLING) | 594 if (state_ != SCROLLING) |
307 return; | 595 return; |
308 UpdateSeparatorPositionFromScrollDelta(delta); | 596 UpdateSeparatorPositionFromScrollDelta(delta); |
309 UpdateLayout(false); | 597 UpdateLayout(false); |
310 } | 598 } |
311 | 599 |
312 bool SplitViewController::CanScroll() { | 600 bool SplitViewController::CanScroll() { |
313 // TODO(mfomitchev): return false in full screen. | 601 // TODO(mfomitchev): return false in full screen. |
314 bool result = (!IsSplitViewModeActive() && | 602 bool result = (!IsSplitViewModeActive() && |
315 window_list_provider_->GetWindowList().size() >= 2 && | 603 window_list_provider_->GetWindowList().size() >= 2 && |
316 IsLandscapeOrientation(gfx::Screen::GetNativeScreen()-> | 604 IsLandscapeOrientation(gfx::Screen::GetNativeScreen()-> |
317 GetDisplayNearestWindow(container_).rotation())); | 605 GetDisplayNearestWindow(container_).rotation())); |
318 return result; | 606 return result; |
319 } | 607 } |
320 | 608 |
609 /////////////////////////////////////////////////////////////////////////////// | |
610 // ScrollHandle::ScrollDelegate: | |
611 | |
612 void SplitViewController::HandleScrollBegin(float delta) { | |
613 CHECK(state_ == ACTIVE); | |
614 state_ = SCROLLING; | |
615 divider_position_ = delta + divider_position_; | |
616 UpdateLayout(false); | |
617 } | |
618 | |
619 void SplitViewController::HandleScrollEnd() { | |
620 ScrollEnd(); | |
621 } | |
622 | |
623 void SplitViewController::HandleScrollUpdate(float delta) { | |
624 if (state_ != SCROLLING) | |
625 return; | |
626 divider_position_ = delta + container_->GetBoundsInScreen().width() / 2; | |
627 UpdateLayout(false); | |
628 } | |
629 | |
630 bool SplitViewController::HandleCanScroll() { | |
631 CHECK(IsLandscapeOrientation(gfx::Screen::GetNativeScreen() | |
632 ->GetDisplayNearestWindow(container_) | |
633 .rotation())); | |
634 return true; | |
635 } | |
636 | |
637 /////////////////////////////////////////////////////////////////////////////// | |
638 // WindowManagerObserver: | |
639 | |
640 void SplitViewController::OnOverviewModeEnter() { | |
641 if (divider_widget_) { | |
sadrul
2014/09/15 14:32:29
Remove {}
mfomitchev
2014/09/15 16:37:24
Done.
| |
642 HideDivider(); | |
643 } | |
644 } | |
645 | |
646 void SplitViewController::OnOverviewModeExit() { | |
647 if (state_ != INACTIVE) { | |
sadrul
2014/09/15 14:32:29
ditto
mfomitchev
2014/09/15 16:37:24
Done.
| |
648 ShowDivider(); | |
649 } | |
650 } | |
651 | |
652 void SplitViewController::OnSplitViewModeEnter() { | |
653 } | |
654 | |
655 void SplitViewController::OnSplitViewModeExit() { | |
656 } | |
657 | |
321 } // namespace athena | 658 } // namespace athena |
OLD | NEW |