1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
// Copyright (c) 2012 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/workspace/phantom_window_controller.h"
#include <math.h>
#include "ash/shell.h"
#include "ash/shell_window_ids.h"
#include "ash/wm/coordinate_conversion.h"
#include "grit/ash_resources.h"
#include "ui/aura/window.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/views/background.h"
#include "ui/views/painter.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
namespace ash {
namespace {
// The duration of the show animation.
const int kAnimationDurationMs = 200;
// The size of the phantom window at the beginning of the show animation in
// relation to the size of the phantom window at the end of the animation.
const float kStartBoundsRatio = 0.85f;
// The amount of pixels that the phantom window's shadow should extend past
// the bounds passed into Show().
const int kShadowThickness = 15;
// The minimum size of a phantom window including the shadow. The minimum size
// is derived from the size of the IDR_AURA_PHANTOM_WINDOW image assets.
const int kMinSizeWithShadow = 100;
// Adjusts the phantom window's bounds so that the bounds:
// - Include the size of the shadow.
// - Have a size equal to or larger than the minimum phantom window size.
gfx::Rect GetAdjustedBounds(const gfx::Rect& bounds) {
int x_inset = std::max(
static_cast<int>(ceil((kMinSizeWithShadow - bounds.width()) / 2.0f)),
kShadowThickness);
int y_inset = std::max(
static_cast<int>(ceil((kMinSizeWithShadow - bounds.height()) / 2.0f)),
kShadowThickness);
gfx::Rect adjusted_bounds(bounds);
adjusted_bounds.Inset(-x_inset, -y_inset);
return adjusted_bounds;
}
// Starts an animation of |widget| to |new_bounds_in_screen|. No-op if |widget|
// is NULL.
void AnimateToBounds(views::Widget* widget,
const gfx::Rect& new_bounds_in_screen) {
if (!widget)
return;
ui::ScopedLayerAnimationSettings scoped_setter(
widget->GetNativeWindow()->layer()->GetAnimator());
scoped_setter.SetTweenType(gfx::Tween::EASE_IN);
scoped_setter.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
scoped_setter.SetTransitionDuration(
base::TimeDelta::FromMilliseconds(kAnimationDurationMs));
widget->SetBounds(new_bounds_in_screen);
}
} // namespace
// PhantomWindowController ----------------------------------------------------
PhantomWindowController::PhantomWindowController(aura::Window* window)
: window_(window) {
}
PhantomWindowController::~PhantomWindowController() {
}
void PhantomWindowController::Show(const gfx::Rect& bounds_in_screen) {
gfx::Rect adjusted_bounds_in_screen = GetAdjustedBounds(bounds_in_screen);
if (adjusted_bounds_in_screen == target_bounds_in_screen_)
return;
target_bounds_in_screen_ = adjusted_bounds_in_screen;
gfx::Rect start_bounds_in_screen = target_bounds_in_screen_;
int start_width = std::max(
kMinSizeWithShadow,
static_cast<int>(start_bounds_in_screen.width() * kStartBoundsRatio));
int start_height = std::max(
kMinSizeWithShadow,
static_cast<int>(start_bounds_in_screen.height() * kStartBoundsRatio));
start_bounds_in_screen.Inset(
floor((start_bounds_in_screen.width() - start_width) / 2.0f),
floor((start_bounds_in_screen.height() - start_height) / 2.0f));
phantom_widget_ = CreatePhantomWidget(
wm::GetRootWindowMatching(target_bounds_in_screen_),
start_bounds_in_screen);
AnimateToBounds(phantom_widget_.get(), target_bounds_in_screen_);
}
scoped_ptr<views::Widget> PhantomWindowController::CreatePhantomWidget(
aura::Window* root_window,
const gfx::Rect& bounds_in_screen) {
scoped_ptr<views::Widget> phantom_widget(new views::Widget);
views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
// PhantomWindowController is used by FrameMaximizeButton to highlight the
// launcher button. Put the phantom in the same window as the launcher so that
// the phantom is visible.
params.parent = Shell::GetContainer(root_window,
kShellWindowId_ShelfContainer);
params.keep_on_top = true;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
phantom_widget->set_focus_on_creation(false);
phantom_widget->Init(params);
phantom_widget->SetVisibilityChangedAnimationsEnabled(false);
phantom_widget->GetNativeWindow()->SetName("PhantomWindow");
phantom_widget->GetNativeWindow()->set_id(kShellWindowId_PhantomWindow);
phantom_widget->SetBounds(bounds_in_screen);
phantom_widget->StackAbove(window_);
const int kImages[] = IMAGE_GRID(IDR_AURA_PHANTOM_WINDOW);
views::Painter* background_painter =
views::Painter::CreateImageGridPainter(kImages);
views::View* content_view = new views::View;
content_view->set_background(
views::Background::CreateBackgroundPainter(true, background_painter));
phantom_widget->SetContentsView(content_view);
// Show the widget after all the setups.
phantom_widget->Show();
// Fade the window in.
ui::Layer* widget_layer = phantom_widget->GetNativeWindow()->layer();
widget_layer->SetOpacity(0);
ui::ScopedLayerAnimationSettings scoped_setter(widget_layer->GetAnimator());
scoped_setter.SetTransitionDuration(
base::TimeDelta::FromMilliseconds(kAnimationDurationMs));
widget_layer->SetOpacity(1);
return phantom_widget.Pass();
}
} // namespace ash
|