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.
5 #include "ash/wm/overview/window_selector_panels.h"
7 #include "ash/screen_util.h"
9 #include "ash/shell_window_ids.h"
10 #include "ash/wm/overview/scoped_transform_overview_window.h"
11 #include "ash/wm/overview/transparent_activate_window_button.h"
12 #include "ash/wm/panels/panel_layout_manager.h"
13 #include "ash/wm/window_util.h"
14 #include "ui/aura/window.h"
15 #include "ui/compositor/layer.h"
16 #include "ui/compositor/layer_animation_observer.h"
17 #include "ui/compositor/layer_animation_sequence.h"
18 #include "ui/views/controls/button/button.h"
24 // This class extends ScopedTransformOverviewMode to hide and show the callout
25 // widget for a panel window when entering / leaving overview mode, as well as
26 // to add a transparent button for each panel window.
27 class ScopedTransformPanelWindow
: public ScopedTransformOverviewWindow
{
29 explicit ScopedTransformPanelWindow(aura::Window
* window
);
30 ~ScopedTransformPanelWindow() override
;
32 // ScopedTransformOverviewWindow overrides:
33 void PrepareForOverview() override
;
35 void SetTransform(aura::Window
* root_window
,
36 const gfx::Transform
& transform
,
37 bool animate
) override
;
40 // Returns the panel window bounds after the transformation.
41 gfx::Rect
GetTransformedBounds();
43 scoped_ptr
<TransparentActivateWindowButton
> window_button_
;
45 DISALLOW_COPY_AND_ASSIGN(ScopedTransformPanelWindow
);
48 ScopedTransformPanelWindow::ScopedTransformPanelWindow(aura::Window
* window
)
49 : ScopedTransformOverviewWindow(window
) {
52 ScopedTransformPanelWindow::~ScopedTransformPanelWindow() {
55 void ScopedTransformPanelWindow::PrepareForOverview() {
56 ScopedTransformOverviewWindow::PrepareForOverview();
57 window_button_
.reset(new TransparentActivateWindowButton(window()));
60 void ScopedTransformPanelWindow::SetTransform(
61 aura::Window
* root_window
,
62 const gfx::Transform
& transform
,
64 ScopedTransformOverviewWindow::SetTransform(root_window
, transform
, animate
);
65 window_button_
->SetBounds(GetTransformedBounds());
68 gfx::Rect
ScopedTransformPanelWindow::GetTransformedBounds() {
69 gfx::RectF
bounds(ScreenUtil::ConvertRectToScreen(
70 window()->GetRootWindow(), window()->layer()->bounds()));
71 gfx::Transform new_transform
;
72 new_transform
.Translate(bounds
.x(),
74 new_transform
.PreconcatTransform(window()->layer()->GetTargetTransform());
75 new_transform
.Translate(-bounds
.x(),
77 new_transform
.TransformRect(&bounds
);
78 return ToEnclosingRect(bounds
);
83 WindowSelectorPanels::WindowSelectorPanels(aura::Window
* panels_root_window
)
84 : panels_root_window_(panels_root_window
) {
85 static_cast<PanelLayoutManager
*>(
86 Shell::GetContainer(panels_root_window_
, kShellWindowId_PanelContainer
)->
87 layout_manager())->SetShowCalloutWidgets(false);
90 WindowSelectorPanels::~WindowSelectorPanels() {
91 static_cast<PanelLayoutManager
*>(
92 Shell::GetContainer(panels_root_window_
, kShellWindowId_PanelContainer
)->
93 layout_manager())->SetShowCalloutWidgets(true);
94 for (WindowList::iterator iter
= transform_windows_
.begin();
95 iter
!= transform_windows_
.end(); iter
++) {
96 (*iter
)->window()->RemoveObserver(this);
100 void WindowSelectorPanels::AddWindow(aura::Window
* window
) {
101 DCHECK(window
->GetRootWindow() == panels_root_window_
);
102 window
->AddObserver(this);
103 transform_windows_
.push_back(new ScopedTransformPanelWindow(window
));
106 aura::Window
* WindowSelectorPanels::GetRootWindow() {
107 return transform_windows_
.front()->window()->GetRootWindow();
110 bool WindowSelectorPanels::HasSelectableWindow(const aura::Window
* window
) {
111 for (WindowList::const_iterator iter
= transform_windows_
.begin();
112 iter
!= transform_windows_
.end(); ++iter
) {
113 if ((*iter
)->window() == window
)
119 bool WindowSelectorPanels::Contains(const aura::Window
* target
) {
120 for (WindowList::const_iterator iter
= transform_windows_
.begin();
121 iter
!= transform_windows_
.end(); ++iter
) {
122 if ((*iter
)->Contains(target
))
128 void WindowSelectorPanels::RestoreWindowOnExit(aura::Window
* window
) {
129 for (WindowList::iterator iter
= transform_windows_
.begin();
130 iter
!= transform_windows_
.end(); ++iter
) {
131 if ((*iter
)->Contains(window
)) {
132 (*iter
)->RestoreWindowOnExit();
138 aura::Window
* WindowSelectorPanels::SelectionWindow() {
139 return transform_windows_
.front()->window();
142 void WindowSelectorPanels::RemoveWindow(const aura::Window
* window
) {
143 for (WindowList::iterator iter
= transform_windows_
.begin();
144 iter
!= transform_windows_
.end(); ++iter
) {
145 if ((*iter
)->window() == window
) {
146 (*iter
)->window()->RemoveObserver(this);
147 (*iter
)->OnWindowDestroyed();
148 transform_windows_
.erase(iter
);
152 WindowSelectorItem::RemoveWindow(window
);
155 bool WindowSelectorPanels::empty() const {
156 return transform_windows_
.empty();
159 void WindowSelectorPanels::PrepareForOverview() {
160 // |panel_windows| will hold all the windows in the panel container, sorted
161 // according to their stacking order.
162 const aura::Window::Windows panels
=
163 transform_windows_
.front()->window()->parent()->children();
165 // Call PrepareForOverview() in the reverse stacking order so that the
166 // transparent windows that handle the events are in the correct stacking
168 size_t transformed_windows
= 0;
169 for (aura::Window::Windows::const_reverse_iterator iter
= panels
.rbegin();
170 iter
!= panels
.rend(); iter
++) {
171 for (size_t j
= 0; j
< transform_windows_
.size(); ++j
) {
172 if (transform_windows_
[j
]->window() == (*iter
)) {
173 transform_windows_
[j
]->PrepareForOverview();
174 transformed_windows
++;
178 DCHECK(transformed_windows
== transform_windows_
.size());
181 void WindowSelectorPanels::SetItemBounds(aura::Window
* root_window
,
182 const gfx::Rect
& target_bounds
,
184 gfx::Rect bounding_rect
;
185 for (WindowList::iterator iter
= transform_windows_
.begin();
186 iter
!= transform_windows_
.end(); ++iter
) {
187 bounding_rect
.Union((*iter
)->GetBoundsInScreen());
189 set_bounds(ScopedTransformOverviewWindow::
190 ShrinkRectToFitPreservingAspectRatio(bounding_rect
, target_bounds
));
191 gfx::Transform bounding_transform
=
192 ScopedTransformOverviewWindow::GetTransformForRect(bounding_rect
,
194 for (WindowList::iterator iter
= transform_windows_
.begin();
195 iter
!= transform_windows_
.end(); ++iter
) {
196 gfx::Transform transform
;
197 gfx::Rect bounds
= (*iter
)->GetBoundsInScreen();
198 transform
.Translate(bounding_rect
.x() - bounds
.x(),
199 bounding_rect
.y() - bounds
.y());
200 transform
.PreconcatTransform(bounding_transform
);
201 transform
.Translate(bounds
.x() - bounding_rect
.x(),
202 bounds
.y() - bounding_rect
.y());
203 (*iter
)->SetTransform(root_window
, transform
, animate
);
207 void WindowSelectorPanels::SetOpacity(float opacity
) {
208 // TODO(flackr): find a way to make panels that are hidden behind other panels
210 for (WindowList::iterator iter
= transform_windows_
.begin();
211 iter
!= transform_windows_
.end(); iter
++) {
212 (*iter
)->window()->layer()->SetOpacity(opacity
);
214 WindowSelectorItem::SetOpacity(opacity
);