blob: ea3ee69e3eaed5984aa911711920efaaeab8acca [file] [log] [blame]
// Copyright 2013 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 "ash/wm/overview/window_selector_panels.h"
#include "ash/screen_ash.h"
#include "ash/shell.h"
#include "ash/shell_window_ids.h"
#include "ash/wm/overview/scoped_transform_overview_window.h"
#include "ash/wm/panels/panel_layout_manager.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/window.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/layer_animation_sequence.h"
#include "ui/views/widget/widget.h"
namespace ash {
namespace {
const int kPanelCalloutFadeInDurationMilliseconds = 50;
// This class extends ScopedTransformOverviewMode to hide and show the callout
// widget for a panel window when entering / leaving overview mode.
class ScopedTransformPanelWindow : public ScopedTransformOverviewWindow {
public:
ScopedTransformPanelWindow(aura::Window* window);
virtual ~ScopedTransformPanelWindow();
protected:
virtual void OnOverviewStarted() OVERRIDE;
private:
// Returns the callout widget for the transformed panel.
views::Widget* GetCalloutWidget();
// Restores the callout visibility.
void RestoreCallout();
// Trigger relayout
void Relayout();
bool callout_visible_;
DISALLOW_COPY_AND_ASSIGN(ScopedTransformPanelWindow);
};
ScopedTransformPanelWindow::ScopedTransformPanelWindow(aura::Window* window)
: ScopedTransformOverviewWindow(window) {
}
ScopedTransformPanelWindow::~ScopedTransformPanelWindow() {
// window() will be NULL if the window was destroyed.
if (window())
RestoreCallout();
}
void ScopedTransformPanelWindow::OnOverviewStarted() {
ScopedTransformOverviewWindow::OnOverviewStarted();
GetCalloutWidget()->GetLayer()->SetOpacity(0.0f);
}
views::Widget* ScopedTransformPanelWindow::GetCalloutWidget() {
DCHECK(window()->parent()->id() == internal::kShellWindowId_PanelContainer);
internal::PanelLayoutManager* panel_layout_manager =
static_cast<internal::PanelLayoutManager*>(
window()->parent()->layout_manager());
return panel_layout_manager->GetCalloutWidgetForPanel(window());
}
void ScopedTransformPanelWindow::RestoreCallout() {
scoped_ptr<ui::LayerAnimationSequence> sequence(
new ui::LayerAnimationSequence);
ui::LayerAnimationElement::AnimatableProperties paused_properties;
paused_properties.insert(ui::LayerAnimationElement::OPACITY);
sequence->AddElement(ui::LayerAnimationElement::CreatePauseElement(
paused_properties, base::TimeDelta::FromMilliseconds(
ScopedTransformOverviewWindow::kTransitionMilliseconds)));
sequence->AddElement(ui::LayerAnimationElement::CreateOpacityElement(1,
base::TimeDelta::FromMilliseconds(
kPanelCalloutFadeInDurationMilliseconds)));
GetCalloutWidget()->GetLayer()->GetAnimator()->StartAnimation(
sequence.release());
}
} // namespace
WindowSelectorPanels::WindowSelectorPanels() {
}
WindowSelectorPanels::~WindowSelectorPanels() {
}
void WindowSelectorPanels::AddWindow(aura::Window* window) {
transform_windows_.push_back(new ScopedTransformPanelWindow(window));
}
aura::RootWindow* WindowSelectorPanels::GetRootWindow() {
return transform_windows_.front()->window()->GetRootWindow();
}
aura::Window* WindowSelectorPanels::TargetedWindow(const aura::Window* target) {
for (WindowList::const_iterator iter = transform_windows_.begin();
iter != transform_windows_.end(); ++iter) {
if ((*iter)->Contains(target))
return (*iter)->window();
}
return NULL;
}
void WindowSelectorPanels::RestoreWindowOnExit(aura::Window* window) {
for (WindowList::iterator iter = transform_windows_.begin();
iter != transform_windows_.end(); ++iter) {
if ((*iter)->Contains(window)) {
(*iter)->RestoreWindowOnExit();
break;
}
}
}
aura::Window* WindowSelectorPanels::SelectionWindow() {
return transform_windows_.front()->window();
}
void WindowSelectorPanels::RemoveWindow(const aura::Window* window) {
for (WindowList::iterator iter = transform_windows_.begin();
iter != transform_windows_.end(); ++iter) {
if ((*iter)->Contains(window)) {
(*iter)->OnWindowDestroyed();
transform_windows_.erase(iter);
break;
}
}
}
bool WindowSelectorPanels::empty() const {
return transform_windows_.empty();
}
void WindowSelectorPanels::SetItemBounds(aura::RootWindow* root_window,
const gfx::Rect& target_bounds) {
// Panel windows affect the position of each other. Restore all panel windows
// first in order to have the correct layout.
for (WindowList::iterator iter = transform_windows_.begin();
iter != transform_windows_.end(); ++iter) {
(*iter)->RestoreWindow();
}
gfx::Rect bounding_rect;
for (WindowList::iterator iter = transform_windows_.begin();
iter != transform_windows_.end(); ++iter) {
aura::Window* panel = (*iter)->window();
gfx::Rect bounds = ScreenAsh::ConvertRectToScreen(
panel->parent(), panel->GetTargetBounds());
bounding_rect.Union(bounds);
}
gfx::Transform bounding_transform =
ScopedTransformOverviewWindow::GetTransformForRectPreservingAspectRatio(
bounding_rect, target_bounds);
for (WindowList::iterator iter = transform_windows_.begin();
iter != transform_windows_.end(); ++iter) {
gfx::Transform transform;
aura::Window* panel = (*iter)->window();
gfx::Rect bounds = ScreenAsh::ConvertRectToScreen(
panel->parent(), panel->GetTargetBounds());
transform.Translate(bounding_rect.x() - bounds.x(),
bounding_rect.y() - bounds.y());
transform.PreconcatTransform(bounding_transform);
transform.Translate(bounds.x() - bounding_rect.x(),
bounds.y() - bounding_rect.y());
(*iter)->SetTransform(root_window, transform);
}
}
} // namespace ash