Chromium Code Reviews| 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 |