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

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

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

Powered by Google App Engine
This is Rietveld 408576698