1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ash/wm/overview/window_selector_panels.h"
6
7#include "ash/screen_ash.h"
8#include "ash/shell.h"
9#include "ash/shell_window_ids.h"
10#include "ash/wm/overview/scoped_transform_overview_window.h"
11#include "ash/wm/panels/panel_layout_manager.h"
12#include "ui/aura/client/screen_position_client.h"
13#include "ui/aura/window.h"
14#include "ui/compositor/layer.h"
15#include "ui/compositor/layer_animation_observer.h"
16#include "ui/compositor/layer_animation_sequence.h"
17#include "ui/views/widget/widget.h"
18
19namespace ash {
20
21namespace {
22
23const int kPanelCalloutFadeInDurationMilliseconds = 50;
24
25// This class extends ScopedTransformOverviewMode to hide and show the callout
26// widget for a panel window when entering / leaving overview mode.
27class ScopedTransformPanelWindow : public ScopedTransformOverviewWindow {
28 public:
29  ScopedTransformPanelWindow(aura::Window* window);
30  virtual ~ScopedTransformPanelWindow();
31
32  // ScopedTransformOverviewWindow overrides:
33  virtual void PrepareForOverview() OVERRIDE;
34
35 private:
36  // Returns the callout widget for the transformed panel.
37  views::Widget* GetCalloutWidget();
38
39  // Restores the callout visibility.
40  void RestoreCallout();
41
42  // Trigger relayout
43  void Relayout();
44
45  bool callout_visible_;
46
47  DISALLOW_COPY_AND_ASSIGN(ScopedTransformPanelWindow);
48};
49
50ScopedTransformPanelWindow::ScopedTransformPanelWindow(aura::Window* window)
51    : ScopedTransformOverviewWindow(window) {
52}
53
54ScopedTransformPanelWindow::~ScopedTransformPanelWindow() {
55  // window() will be NULL if the window was destroyed.
56  if (window())
57    RestoreCallout();
58}
59
60void ScopedTransformPanelWindow::PrepareForOverview() {
61  ScopedTransformOverviewWindow::PrepareForOverview();
62  GetCalloutWidget()->GetLayer()->SetOpacity(0.0f);
63}
64
65views::Widget* ScopedTransformPanelWindow::GetCalloutWidget() {
66  DCHECK(window()->parent()->id() == internal::kShellWindowId_PanelContainer);
67  internal::PanelLayoutManager* panel_layout_manager =
68      static_cast<internal::PanelLayoutManager*>(
69          window()->parent()->layout_manager());
70  return panel_layout_manager->GetCalloutWidgetForPanel(window());
71}
72
73void ScopedTransformPanelWindow::RestoreCallout() {
74  scoped_ptr<ui::LayerAnimationSequence> sequence(
75      new ui::LayerAnimationSequence);
76  ui::LayerAnimationElement::AnimatableProperties paused_properties;
77  paused_properties.insert(ui::LayerAnimationElement::OPACITY);
78  sequence->AddElement(ui::LayerAnimationElement::CreatePauseElement(
79      paused_properties, base::TimeDelta::FromMilliseconds(
80          ScopedTransformOverviewWindow::kTransitionMilliseconds)));
81  sequence->AddElement(ui::LayerAnimationElement::CreateOpacityElement(1,
82      base::TimeDelta::FromMilliseconds(
83          kPanelCalloutFadeInDurationMilliseconds)));
84  GetCalloutWidget()->GetLayer()->GetAnimator()->StartAnimation(
85      sequence.release());
86}
87
88}  // namespace
89
90WindowSelectorPanels::WindowSelectorPanels() {
91}
92
93WindowSelectorPanels::~WindowSelectorPanels() {
94}
95
96void WindowSelectorPanels::AddWindow(aura::Window* window) {
97  transform_windows_.push_back(new ScopedTransformPanelWindow(window));
98}
99
100aura::Window* WindowSelectorPanels::GetRootWindow() {
101  return transform_windows_.front()->window()->GetRootWindow();
102}
103
104bool WindowSelectorPanels::HasSelectableWindow(const aura::Window* window) {
105  for (WindowList::const_iterator iter = transform_windows_.begin();
106       iter != transform_windows_.end(); ++iter) {
107    if ((*iter)->window() == window)
108      return true;
109  }
110  return false;
111}
112
113aura::Window* WindowSelectorPanels::TargetedWindow(const aura::Window* target) {
114  for (WindowList::const_iterator iter = transform_windows_.begin();
115       iter != transform_windows_.end(); ++iter) {
116    if ((*iter)->Contains(target))
117      return (*iter)->window();
118  }
119  return NULL;
120}
121
122void WindowSelectorPanels::RestoreWindowOnExit(aura::Window* window) {
123  for (WindowList::iterator iter = transform_windows_.begin();
124       iter != transform_windows_.end(); ++iter) {
125    if ((*iter)->Contains(window)) {
126      (*iter)->RestoreWindowOnExit();
127      break;
128    }
129  }
130}
131
132aura::Window* WindowSelectorPanels::SelectionWindow() {
133  return transform_windows_.front()->window();
134}
135
136void WindowSelectorPanels::RemoveWindow(const aura::Window* window) {
137  for (WindowList::iterator iter = transform_windows_.begin();
138       iter != transform_windows_.end(); ++iter) {
139    if ((*iter)->window() == window) {
140      (*iter)->OnWindowDestroyed();
141      transform_windows_.erase(iter);
142      break;
143    }
144  }
145}
146
147bool WindowSelectorPanels::empty() const {
148  return transform_windows_.empty();
149}
150
151void WindowSelectorPanels::PrepareForOverview() {
152  for (WindowList::iterator iter = transform_windows_.begin();
153       iter != transform_windows_.end(); ++iter) {
154    (*iter)->PrepareForOverview();
155  }
156}
157
158void WindowSelectorPanels::SetItemBounds(aura::Window* root_window,
159                                         const gfx::Rect& target_bounds,
160                                         bool animate) {
161  gfx::Rect bounding_rect;
162  for (WindowList::iterator iter = transform_windows_.begin();
163       iter != transform_windows_.end(); ++iter) {
164    bounding_rect.Union((*iter)->GetBoundsInScreen());
165  }
166  set_bounds(ScopedTransformOverviewWindow::
167      ShrinkRectToFitPreservingAspectRatio(bounding_rect, target_bounds));
168  gfx::Transform bounding_transform =
169      ScopedTransformOverviewWindow::GetTransformForRect(bounding_rect,
170                                                         bounds());
171  for (WindowList::iterator iter = transform_windows_.begin();
172       iter != transform_windows_.end(); ++iter) {
173    gfx::Transform transform;
174    gfx::Rect bounds = (*iter)->GetBoundsInScreen();
175    transform.Translate(bounding_rect.x() - bounds.x(),
176                        bounding_rect.y() - bounds.y());
177    transform.PreconcatTransform(bounding_transform);
178    transform.Translate(bounds.x() - bounding_rect.x(),
179                        bounds.y() - bounding_rect.y());
180    (*iter)->SetTransform(root_window, transform, animate);
181  }
182}
183
184}  // namespace ash
185