diff options
Diffstat (limited to 'athena/screen/modal_window_controller.cc')
-rw-r--r-- | athena/screen/modal_window_controller.cc | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/athena/screen/modal_window_controller.cc b/athena/screen/modal_window_controller.cc new file mode 100644 index 0000000000..90357e9ce4 --- /dev/null +++ b/athena/screen/modal_window_controller.cc @@ -0,0 +1,146 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "athena/screen/modal_window_controller.h" + +#include "athena/screen/public/screen_manager.h" +#include "base/message_loop/message_loop.h" +#include "ui/aura/window.h" +#include "ui/aura/window_property.h" +#include "ui/compositor/layer.h" +#include "ui/compositor/layer_animation_observer.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/wm/core/window_animations.h" + +namespace athena { +namespace { + +DEFINE_OWNED_WINDOW_PROPERTY_KEY(ModalWindowController, + kModalWindowControllerKey, + nullptr); + +} // namespace + +// static +ModalWindowController* ModalWindowController::Get(aura::Window* container) { + ModalWindowController* controller = + container->GetProperty(kModalWindowControllerKey); + CHECK(controller); + return controller; +} + +ModalWindowController::ModalWindowController(int priority) + : modal_container_(nullptr), + dimmer_window_(new aura::Window(nullptr)), + dimmed_(false) { + ScreenManager::ContainerParams params("ModalContainer", priority); + params.can_activate_children = true; + params.block_events = true; + modal_container_ = ScreenManager::Get()->CreateContainer(params); + modal_container_->SetProperty(kModalWindowControllerKey, this); + + dimmer_window_->SetType(ui::wm::WINDOW_TYPE_NORMAL); + dimmer_window_->Init(aura::WINDOW_LAYER_SOLID_COLOR); + dimmer_window_->layer()->SetColor(SK_ColorBLACK); + dimmer_window_->layer()->SetOpacity(0.0f); + dimmer_window_->Show(); + + modal_container_->AddChild(dimmer_window_); + modal_container_->AddObserver(this); + + UpdateDimmerWindowBounds(); +} + +ModalWindowController::~ModalWindowController() { + if (modal_container_) + modal_container_->RemoveObserver(this); +} + +void ModalWindowController::OnWindowAdded(aura::Window* child) { + DCHECK_NE(child, dimmer_window_); + if (IsChildWindow(child)) { + child->AddObserver(this); + UpdateDimming(nullptr); + } +} + +void ModalWindowController::OnWindowVisibilityChanged(aura::Window* window, + bool visible) { + if (IsChildWindow(window)) + UpdateDimming(nullptr); +} + +void ModalWindowController::OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) { + if (window == modal_container_) + UpdateDimmerWindowBounds(); +} + +void ModalWindowController::OnWindowDestroyed(aura::Window* window) { + UpdateDimming(window); +} + +bool ModalWindowController::IsChildWindow(aura::Window* child) const { + return child->parent() == modal_container_ && child != dimmer_window_; +} + +void ModalWindowController::UpdateDimmerWindowBounds() { + gfx::Rect bounds(modal_container_->bounds().size()); + dimmer_window_->SetBounds(bounds); +} + +void ModalWindowController::UpdateDimming(aura::Window* ignore) { + if (!modal_container_ || !dimmer_window_) + return; + bool should_delete = true; + for (aura::Window* window : modal_container_->children()) { + if (window == dimmer_window_ || window == ignore) + continue; + should_delete = false; + if (window->TargetVisibility()) { + SetDimmed(true); + return; + } + } + SetDimmed(false); + + if (should_delete) { + // Remove the container from root so that the container becomes + // invisible, but don't delete it until next event execution + // because the call stack may still have and use the pointer. + modal_container_->RemoveObserver(this); + modal_container_->parent()->RemoveChild(modal_container_); + base::MessageLoopForUI::current()->DeleteSoon(FROM_HERE, modal_container_); + modal_container_ = nullptr; + dimmer_window_ = nullptr; + } +} + +void ModalWindowController::SetDimmed(bool dimmed) { + const float kDimmedOpacity = 0.4f; + + if (!dimmer_window_ || dimmed_ == dimmed) + return; + dimmed_ = dimmed; + + const int kDimmAnimationDurationMs = 500; + if (dimmed) { + ui::ScopedLayerAnimationSettings settings( + dimmer_window_->layer()->GetAnimator()); + settings.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kDimmAnimationDurationMs)); + dimmer_window_->layer()->SetOpacity(kDimmedOpacity); + } else { + // ScopedHidingAnimationSettings will detach the animating and + // recreate layers for the container so that animation can continue + // even if the container is removed immediately. + wm::ScopedHidingAnimationSettings settings(modal_container_); + settings.layer_animation_settings()->SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kDimmAnimationDurationMs)); + modal_container_->layer()->SetOpacity(0.0f); + } +} + +} // namespace athena |