Index: athena/screen/modal_window_controller.cc |
diff --git a/athena/screen/modal_window_controller.cc b/athena/screen/modal_window_controller.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..71a19ff56500c26bed9cfcd778ddc5dc5d6df2ee |
--- /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, |
+ NULL); |
+ |
+} // namespace |
+ |
+// static |
+ModalWindowController* ModalWindowController::Get(aura::Window* container) { |
+ ModalWindowController* controller = |
+ container->GetProperty(kModalWindowControllerKey); |
+ CHECK(controller); |
+ return controller; |
+} |
+ |
+ModalWindowController::ModalWindowController(int priority) |
+ : modal_container_(NULL), |
+ dimmer_window_(new aura::Window(NULL)), |
+ 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(NULL); |
+ } |
+} |
+ |
+void ModalWindowController::OnWindowVisibilityChanged(aura::Window* window, |
+ bool visible) { |
+ if (IsChildWindow(window)) |
+ UpdateDimming(NULL); |
+} |
+ |
+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_ = NULL; |
+ dimmer_window_ = NULL; |
+ } |
+} |
+ |
+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 |