Port Android relocation packer to chromium build
[chromium-blink-merge.git] / ash / wm / overview / window_selector_item.cc
blobf3e8eca205bca026b07c9777ddcd64abbde16c56
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_item.h"
7 #include <algorithm>
8 #include <vector>
10 #include "ash/screen_util.h"
11 #include "ash/shell.h"
12 #include "ash/shell_window_ids.h"
13 #include "ash/wm/overview/overview_animation_type.h"
14 #include "ash/wm/overview/scoped_overview_animation_settings.h"
15 #include "ash/wm/overview/scoped_transform_overview_window.h"
16 #include "ash/wm/overview/window_selector_controller.h"
17 #include "ash/wm/window_state.h"
18 #include "base/auto_reset.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/time/time.h"
22 #include "grit/ash_resources.h"
23 #include "grit/ash_strings.h"
24 #include "ui/aura/window.h"
25 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/base/resource/resource_bundle.h"
27 #include "ui/gfx/geometry/vector2d.h"
28 #include "ui/gfx/transform_util.h"
29 #include "ui/strings/grit/ui_strings.h"
30 #include "ui/views/border.h"
31 #include "ui/views/controls/button/image_button.h"
32 #include "ui/views/layout/box_layout.h"
33 #include "ui/views/widget/widget.h"
34 #include "ui/wm/core/window_util.h"
36 namespace ash {
38 namespace {
40 // In the conceptual overview table, the window margin is the space reserved
41 // around the window within the cell. This margin does not overlap so the
42 // closest distance between adjacent windows will be twice this amount.
43 static const int kWindowMargin = 30;
45 // Foreground label color.
46 static const SkColor kLabelColor = SK_ColorWHITE;
48 // Label shadow color.
49 static const SkColor kLabelShadow = 0xB0000000;
51 // Vertical padding for the label, on top of it.
52 static const int kVerticalLabelPadding = 20;
54 // Solid shadow length from the label
55 static const int kVerticalShadowOffset = 1;
57 // Amount of blur applied to the label shadow
58 static const int kShadowBlur = 10;
60 // Opacity for dimmed items.
61 static const float kDimmedItemOpacity = 0.5f;
63 // Calculates the |window| bounds after being transformed to the selector's
64 // space. The returned Rect is in virtual screen coordinates.
65 gfx::Rect GetTransformedBounds(aura::Window* window) {
66 gfx::RectF bounds(ScreenUtil::ConvertRectToScreen(window->GetRootWindow(),
67 window->layer()->GetTargetBounds()));
68 gfx::Transform new_transform = TransformAboutPivot(
69 gfx::Point(bounds.x(), bounds.y()),
70 window->layer()->GetTargetTransform());
71 new_transform.TransformRect(&bounds);
72 return ToEnclosingRect(bounds);
75 // Convenvience method to fade in a Window with predefined animation settings.
76 // Note: The fade in animation will occur after a delay where the delay is how
77 // long the lay out animations take.
78 void SetupFadeInAfterLayout(aura::Window* window) {
79 ui::Layer* layer = window->layer();
80 layer->SetOpacity(0.0f);
81 ScopedOverviewAnimationSettings animation_settings(
82 OverviewAnimationType::OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_IN,
83 window);
84 layer->SetOpacity(1.0f);
87 // An image button with a close window icon.
88 class OverviewCloseButton : public views::ImageButton {
89 public:
90 explicit OverviewCloseButton(views::ButtonListener* listener);
91 ~OverviewCloseButton() override;
93 private:
94 DISALLOW_COPY_AND_ASSIGN(OverviewCloseButton);
97 OverviewCloseButton::OverviewCloseButton(views::ButtonListener* listener)
98 : views::ImageButton(listener) {
99 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
100 SetImage(views::CustomButton::STATE_NORMAL,
101 rb.GetImageSkiaNamed(IDR_AURA_WINDOW_OVERVIEW_CLOSE));
102 SetImage(views::CustomButton::STATE_HOVERED,
103 rb.GetImageSkiaNamed(IDR_AURA_WINDOW_OVERVIEW_CLOSE_H));
104 SetImage(views::CustomButton::STATE_PRESSED,
105 rb.GetImageSkiaNamed(IDR_AURA_WINDOW_OVERVIEW_CLOSE_P));
108 OverviewCloseButton::~OverviewCloseButton() {
111 } // namespace
113 WindowSelectorItem::OverviewLabelButton::OverviewLabelButton(
114 views::ButtonListener* listener,
115 const base::string16& text)
116 : LabelButton(listener, text),
117 top_padding_(0) {
120 WindowSelectorItem::OverviewLabelButton::~OverviewLabelButton() {
123 gfx::Rect WindowSelectorItem::OverviewLabelButton::GetChildAreaBounds() {
124 gfx::Rect bounds = GetLocalBounds();
125 bounds.Inset(0, top_padding_, 0, 0);
126 return bounds;
129 WindowSelectorItem::WindowSelectorItem(aura::Window* window)
130 : dimmed_(false),
131 root_window_(window->GetRootWindow()),
132 transform_window_(window),
133 in_bounds_update_(false),
134 window_label_button_view_(nullptr),
135 close_button_(new OverviewCloseButton(this)) {
136 CreateWindowLabel(window->title());
137 views::Widget::InitParams params;
138 params.type = views::Widget::InitParams::TYPE_POPUP;
139 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
140 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
141 params.parent = Shell::GetContainer(root_window_,
142 kShellWindowId_OverlayContainer);
143 close_button_widget_.set_focus_on_creation(false);
144 close_button_widget_.Init(params);
145 close_button_->SetVisible(false);
146 close_button_widget_.SetContentsView(close_button_);
147 close_button_widget_.SetSize(close_button_->GetPreferredSize());
148 close_button_widget_.Show();
150 gfx::Rect close_button_rect(close_button_widget_.GetNativeWindow()->bounds());
151 // Align the center of the button with position (0, 0) so that the
152 // translate transform does not need to take the button dimensions into
153 // account.
154 close_button_rect.set_x(-close_button_rect.width() / 2);
155 close_button_rect.set_y(-close_button_rect.height() / 2);
156 close_button_widget_.GetNativeWindow()->SetBounds(close_button_rect);
158 GetWindow()->AddObserver(this);
161 WindowSelectorItem::~WindowSelectorItem() {
162 GetWindow()->RemoveObserver(this);
165 aura::Window* WindowSelectorItem::GetWindow() {
166 return transform_window_.window();
169 void WindowSelectorItem::RestoreWindow() {
170 transform_window_.RestoreWindow();
173 void WindowSelectorItem::ShowWindowOnExit() {
174 transform_window_.ShowWindowOnExit();
177 void WindowSelectorItem::PrepareForOverview() {
178 transform_window_.PrepareForOverview();
181 bool WindowSelectorItem::Contains(const aura::Window* target) const {
182 return transform_window_.Contains(target);
185 void WindowSelectorItem::SetBounds(const gfx::Rect& target_bounds,
186 OverviewAnimationType animation_type) {
187 if (in_bounds_update_)
188 return;
189 base::AutoReset<bool> auto_reset_in_bounds_update(&in_bounds_update_, true);
190 target_bounds_ = target_bounds;
192 gfx::Rect inset_bounds(target_bounds);
193 inset_bounds.Inset(kWindowMargin, kWindowMargin);
194 SetItemBounds(inset_bounds, animation_type);
196 // SetItemBounds is called before UpdateCloseButtonLayout so the close button
197 // can properly use the updated windows bounds.
198 UpdateCloseButtonLayout(animation_type);
199 UpdateWindowLabel(target_bounds, animation_type);
202 void WindowSelectorItem::RecomputeWindowTransforms() {
203 if (in_bounds_update_ || target_bounds_.IsEmpty())
204 return;
205 base::AutoReset<bool> auto_reset_in_bounds_update(&in_bounds_update_, true);
206 gfx::Rect inset_bounds(target_bounds_);
207 inset_bounds.Inset(kWindowMargin, kWindowMargin);
208 SetItemBounds(inset_bounds, OverviewAnimationType::OVERVIEW_ANIMATION_NONE);
209 UpdateCloseButtonLayout(OverviewAnimationType::OVERVIEW_ANIMATION_NONE);
212 void WindowSelectorItem::SendFocusAlert() const {
213 window_label_button_view_->NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true);
216 void WindowSelectorItem::SetDimmed(bool dimmed) {
217 dimmed_ = dimmed;
218 SetOpacity(dimmed ? kDimmedItemOpacity : 1.0f);
221 void WindowSelectorItem::ButtonPressed(views::Button* sender,
222 const ui::Event& event) {
223 if (sender == close_button_) {
224 transform_window_.Close();
225 return;
227 CHECK(sender == window_label_button_view_);
228 wm::GetWindowState(transform_window_.window())->Activate();
231 void WindowSelectorItem::OnWindowDestroying(aura::Window* window) {
232 window->RemoveObserver(this);
233 transform_window_.OnWindowDestroyed();
236 void WindowSelectorItem::OnWindowTitleChanged(aura::Window* window) {
237 // TODO(flackr): Maybe add the new title to a vector of titles so that we can
238 // filter any of the titles the window had while in the overview session.
239 window_label_button_view_->SetText(window->title());
240 UpdateCloseButtonAccessibilityName();
243 void WindowSelectorItem::SetItemBounds(const gfx::Rect& target_bounds,
244 OverviewAnimationType animation_type) {
245 DCHECK(root_window_ == GetWindow()->GetRootWindow());
246 gfx::Rect screen_bounds = transform_window_.GetTargetBoundsInScreen();
247 gfx::Rect selector_item_bounds =
248 ScopedTransformOverviewWindow::ShrinkRectToFitPreservingAspectRatio(
249 screen_bounds, target_bounds);
250 gfx::Transform transform =
251 ScopedTransformOverviewWindow::GetTransformForRect(screen_bounds,
252 selector_item_bounds);
253 ScopedTransformOverviewWindow::ScopedAnimationSettings animation_settings;
254 transform_window_.BeginScopedAnimation(animation_type, &animation_settings);
255 transform_window_.SetTransform(root_window_, transform);
256 transform_window_.set_overview_transform(transform);
259 void WindowSelectorItem::SetOpacity(float opacity) {
260 window_label_->GetNativeWindow()->layer()->SetOpacity(opacity);
261 close_button_widget_.GetNativeWindow()->layer()->SetOpacity(opacity);
263 transform_window_.SetOpacity(opacity);
266 void WindowSelectorItem::UpdateWindowLabel(
267 const gfx::Rect& window_bounds,
268 OverviewAnimationType animation_type) {
269 // If the root window has changed, force the window label to be recreated
270 // and faded in on the new root window.
271 DCHECK(!window_label_ ||
272 window_label_->GetNativeWindow()->GetRootWindow() == root_window_);
274 if (!window_label_->IsVisible()) {
275 window_label_->Show();
276 SetupFadeInAfterLayout(window_label_->GetNativeWindow());
279 gfx::Rect converted_bounds =
280 ScreenUtil::ConvertRectFromScreen(root_window_, window_bounds);
281 gfx::Rect label_bounds(converted_bounds.x(), converted_bounds.y(),
282 converted_bounds.width(), converted_bounds.height());
283 window_label_button_view_->set_top_padding(label_bounds.height() -
284 kVerticalLabelPadding);
285 ScopedOverviewAnimationSettings animation_settings(
286 animation_type, window_label_->GetNativeWindow());
288 window_label_->GetNativeWindow()->SetBounds(label_bounds);
291 void WindowSelectorItem::CreateWindowLabel(const base::string16& title) {
292 window_label_.reset(new views::Widget);
293 views::Widget::InitParams params;
294 params.type = views::Widget::InitParams::TYPE_POPUP;
295 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
296 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
297 params.parent =
298 Shell::GetContainer(root_window_, kShellWindowId_OverlayContainer);
299 params.visible_on_all_workspaces = true;
300 window_label_->set_focus_on_creation(false);
301 window_label_->Init(params);
302 window_label_button_view_ = new OverviewLabelButton(this, title);
303 window_label_button_view_->SetBorder(views::Border::NullBorder());
304 window_label_button_view_->SetTextColor(views::LabelButton::STATE_NORMAL,
305 kLabelColor);
306 window_label_button_view_->SetTextColor(views::LabelButton::STATE_HOVERED,
307 kLabelColor);
308 window_label_button_view_->SetTextColor(views::LabelButton::STATE_PRESSED,
309 kLabelColor);
310 window_label_button_view_->set_animate_on_state_change(false);
311 window_label_button_view_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
312 window_label_button_view_->SetTextShadows(gfx::ShadowValues(
313 1, gfx::ShadowValue(gfx::Vector2d(0, kVerticalShadowOffset), kShadowBlur,
314 kLabelShadow)));
315 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
316 window_label_button_view_->SetFontList(
317 bundle.GetFontList(ui::ResourceBundle::BoldFont));
318 window_label_->SetContentsView(window_label_button_view_);
321 void WindowSelectorItem::UpdateCloseButtonLayout(
322 OverviewAnimationType animation_type) {
323 if (!close_button_->visible()) {
324 close_button_->SetVisible(true);
325 SetupFadeInAfterLayout(close_button_widget_.GetNativeWindow());
327 ScopedOverviewAnimationSettings animation_settings(animation_type,
328 close_button_widget_.GetNativeWindow());
330 gfx::Rect transformed_window_bounds = ScreenUtil::ConvertRectFromScreen(
331 close_button_widget_.GetNativeWindow()->GetRootWindow(),
332 GetTransformedBounds(GetWindow()));
334 gfx::Transform close_button_transform;
335 close_button_transform.Translate(transformed_window_bounds.right(),
336 transformed_window_bounds.y());
337 close_button_widget_.GetNativeWindow()->SetTransform(
338 close_button_transform);
341 void WindowSelectorItem::UpdateCloseButtonAccessibilityName() {
342 close_button_->SetAccessibleName(l10n_util::GetStringFUTF16(
343 IDS_ASH_OVERVIEW_CLOSE_ITEM_BUTTON_ACCESSIBLE_NAME,
344 GetWindow()->title()));
347 } // namespace ash