Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ash / wm / overview / window_selector_item.cc
blobb06eb86a296a22b644f280a0a343f5bb0a040224
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 "ash/screen_util.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/overview/transparent_activate_window_button.h"
12 #include "base/auto_reset.h"
13 #include "grit/ash_resources.h"
14 #include "ui/aura/window.h"
15 #include "ui/base/resource/resource_bundle.h"
16 #include "ui/compositor/scoped_layer_animation_settings.h"
17 #include "ui/views/controls/button/image_button.h"
18 #include "ui/views/controls/label.h"
19 #include "ui/views/layout/box_layout.h"
20 #include "ui/views/widget/widget.h"
22 namespace ash {
24 namespace {
26 views::Widget* CreateCloseWindowButton(aura::Window* root_window,
27 views::ButtonListener* listener) {
28 views::Widget* widget = new views::Widget;
29 views::Widget::InitParams params;
30 params.type = views::Widget::InitParams::TYPE_POPUP;
31 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
32 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
33 params.parent =
34 Shell::GetContainer(root_window, ash::kShellWindowId_OverlayContainer);
35 widget->set_focus_on_creation(false);
36 widget->Init(params);
37 views::ImageButton* button = new views::ImageButton(listener);
38 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
39 button->SetImage(views::CustomButton::STATE_NORMAL,
40 rb.GetImageSkiaNamed(IDR_AURA_WINDOW_OVERVIEW_CLOSE));
41 button->SetImage(views::CustomButton::STATE_HOVERED,
42 rb.GetImageSkiaNamed(IDR_AURA_WINDOW_OVERVIEW_CLOSE_H));
43 button->SetImage(views::CustomButton::STATE_PRESSED,
44 rb.GetImageSkiaNamed(IDR_AURA_WINDOW_OVERVIEW_CLOSE_P));
45 widget->SetContentsView(button);
46 widget->SetSize(rb.GetImageSkiaNamed(IDR_AURA_WINDOW_OVERVIEW_CLOSE)->size());
47 widget->Show();
48 return widget;
51 } // namespace
53 // In the conceptual overview table, the window margin is the space reserved
54 // around the window within the cell. This margin does not overlap so the
55 // closest distance between adjacent windows will be twice this amount.
56 static const int kWindowMargin = 30;
58 // Foreground label color.
59 static const SkColor kLabelColor = SK_ColorWHITE;
61 // Background label color.
62 static const SkColor kLabelBackground = SK_ColorTRANSPARENT;
64 // Label shadow color.
65 static const SkColor kLabelShadow = 0xB0000000;
67 // Vertical padding for the label, both over and beneath it.
68 static const int kVerticalLabelPadding = 20;
70 // Solid shadow length from the label
71 static const int kVerticalShadowOffset = 1;
73 // Amount of blur applied to the label shadow
74 static const int kShadowBlur = 10;
76 const int WindowSelectorItem::kFadeInMilliseconds = 80;
78 // Opacity for dimmed items.
79 static const float kDimmedItemOpacity = 0.5f;
81 WindowSelectorItem::WindowSelectorItem()
82 : dimmed_(false),
83 root_window_(NULL),
84 in_bounds_update_(false),
85 window_label_view_(NULL) {
88 WindowSelectorItem::~WindowSelectorItem() {
91 void WindowSelectorItem::RemoveWindow(const aura::Window* window) {
92 // If empty WindowSelectorItem will be destroyed immediately after this by
93 // its owner.
94 if (empty())
95 return;
96 window_label_.reset();
97 UpdateWindowLabels(target_bounds_, root_window_, false);
98 UpdateCloseButtonBounds(root_window_, false);
101 void WindowSelectorItem::SetBounds(aura::Window* root_window,
102 const gfx::Rect& target_bounds,
103 bool animate) {
104 if (in_bounds_update_)
105 return;
106 base::AutoReset<bool> auto_reset_in_bounds_update(&in_bounds_update_, true);
107 root_window_ = root_window;
108 target_bounds_ = target_bounds;
110 // Set the bounds of the transparent window handler to cover the entire
111 // bounding box area.
112 if (!activate_window_button_) {
113 activate_window_button_.reset(
114 new TransparentActivateWindowButton(SelectionWindow()));
116 activate_window_button_->SetBounds(target_bounds);
118 UpdateWindowLabels(target_bounds, root_window, animate);
120 gfx::Rect inset_bounds(target_bounds);
121 inset_bounds.Inset(kWindowMargin, kWindowMargin);
122 SetItemBounds(root_window, inset_bounds, animate);
123 UpdateCloseButtonBounds(root_window, animate);
126 void WindowSelectorItem::RecomputeWindowTransforms() {
127 if (in_bounds_update_ || target_bounds_.IsEmpty())
128 return;
129 DCHECK(root_window_);
130 base::AutoReset<bool> auto_reset_in_bounds_update(&in_bounds_update_, true);
131 gfx::Rect inset_bounds(target_bounds_);
132 inset_bounds.Inset(kWindowMargin, kWindowMargin);
133 SetItemBounds(root_window_, inset_bounds, false);
134 UpdateCloseButtonBounds(root_window_, false);
137 void WindowSelectorItem::SendFocusAlert() const {
138 activate_window_button_->SendFocusAlert();
141 void WindowSelectorItem::SetDimmed(bool dimmed) {
142 dimmed_ = dimmed;
143 SetOpacity(dimmed ? kDimmedItemOpacity : 1.0f);
146 void WindowSelectorItem::ButtonPressed(views::Button* sender,
147 const ui::Event& event) {
148 views::Widget::GetWidgetForNativeView(SelectionWindow())->Close();
151 void WindowSelectorItem::OnWindowTitleChanged(aura::Window* window) {
152 // TODO(flackr): Maybe add the new title to a vector of titles so that we can
153 // filter any of the titles the window had while in the overview session.
154 if (window == SelectionWindow())
155 window_label_view_->SetText(window->title());
158 void WindowSelectorItem::UpdateCloseButtonBounds(aura::Window* root_window,
159 bool animate) {
160 gfx::RectF align_bounds(SelectionWindow()->layer()->bounds());
161 gfx::Transform window_transform;
162 window_transform.Translate(align_bounds.x(), align_bounds.y());
163 window_transform.PreconcatTransform(SelectionWindow()->layer()->
164 GetTargetTransform());
165 window_transform.Translate(-align_bounds.x(), -align_bounds.y());
166 window_transform.TransformRect(&align_bounds);
167 gfx::Rect target_bounds = ToEnclosingRect(align_bounds);
169 gfx::Transform close_button_transform;
170 close_button_transform.Translate(target_bounds.right(), target_bounds.y());
172 // If the root window has changed, force the close button to be recreated
173 // and faded in on the new root window.
174 if (close_button_ &&
175 close_button_->GetNativeWindow()->GetRootWindow() != root_window) {
176 close_button_.reset();
179 if (!close_button_) {
180 close_button_.reset(CreateCloseWindowButton(root_window, this));
181 gfx::Rect close_button_rect(close_button_->GetNativeWindow()->bounds());
182 // Align the center of the button with position (0, 0) so that the
183 // translate transform does not need to take the button dimensions into
184 // account.
185 close_button_rect.set_x(-close_button_rect.width() / 2);
186 close_button_rect.set_y(-close_button_rect.height() / 2);
187 close_button_->GetNativeWindow()->SetBounds(close_button_rect);
188 close_button_->GetNativeWindow()->SetTransform(close_button_transform);
189 // The close button is initialized when entering overview, fade the button
190 // in after the window should be in place.
191 ui::Layer* layer = close_button_->GetNativeWindow()->layer();
192 layer->SetOpacity(0);
193 layer->GetAnimator()->StopAnimating();
194 layer->GetAnimator()->SchedulePauseForProperties(
195 base::TimeDelta::FromMilliseconds(
196 ScopedTransformOverviewWindow::kTransitionMilliseconds),
197 ui::LayerAnimationElement::OPACITY);
199 ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
200 settings.SetPreemptionStrategy(
201 ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
202 settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
203 WindowSelectorItem::kFadeInMilliseconds));
204 layer->SetOpacity(1);
206 } else {
207 if (animate) {
208 ui::ScopedLayerAnimationSettings settings(
209 close_button_->GetNativeWindow()->layer()->GetAnimator());
210 settings.SetPreemptionStrategy(
211 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
212 settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
213 ScopedTransformOverviewWindow::kTransitionMilliseconds));
214 close_button_->GetNativeWindow()->SetTransform(close_button_transform);
215 } else {
216 close_button_->GetNativeWindow()->SetTransform(close_button_transform);
221 void WindowSelectorItem::SetOpacity(float opacity) {
222 window_label_->GetNativeWindow()->layer()->SetOpacity(opacity);
223 close_button_->GetNativeWindow()->layer()->SetOpacity(opacity);
226 void WindowSelectorItem::UpdateWindowLabels(const gfx::Rect& window_bounds,
227 aura::Window* root_window,
228 bool animate) {
229 gfx::Rect converted_bounds = ScreenUtil::ConvertRectFromScreen(root_window,
230 window_bounds);
231 gfx::Rect label_bounds(converted_bounds.x(),
232 converted_bounds.bottom(),
233 converted_bounds.width(),
236 // If the root window has changed, force the window label to be recreated
237 // and faded in on the new root window.
238 if (window_label_ &&
239 window_label_->GetNativeWindow()->GetRootWindow() != root_window) {
240 window_label_.reset();
243 if (!window_label_) {
244 CreateWindowLabel(SelectionWindow()->title());
245 label_bounds.set_height(window_label_view_->GetPreferredSize().height());
246 label_bounds.set_y(label_bounds.y() - window_label_view_->
247 GetPreferredSize().height());
248 window_label_->GetNativeWindow()->SetBounds(label_bounds);
249 ui::Layer* layer = window_label_->GetNativeWindow()->layer();
251 layer->SetOpacity(0);
252 layer->GetAnimator()->StopAnimating();
254 layer->GetAnimator()->SchedulePauseForProperties(
255 base::TimeDelta::FromMilliseconds(
256 ScopedTransformOverviewWindow::kTransitionMilliseconds),
257 ui::LayerAnimationElement::OPACITY);
259 ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
260 settings.SetPreemptionStrategy(
261 ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
262 settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
263 kFadeInMilliseconds));
264 layer->SetOpacity(1);
265 } else {
266 label_bounds.set_height(window_label_->
267 GetContentsView()->GetPreferredSize().height());
268 label_bounds.set_y(label_bounds.y() - window_label_->
269 GetContentsView()->GetPreferredSize().height());
270 if (animate) {
271 ui::ScopedLayerAnimationSettings settings(
272 window_label_->GetNativeWindow()->layer()->GetAnimator());
273 settings.SetPreemptionStrategy(
274 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
275 settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
276 ScopedTransformOverviewWindow::kTransitionMilliseconds));
277 window_label_->GetNativeWindow()->SetBounds(label_bounds);
278 } else {
279 window_label_->GetNativeWindow()->SetBounds(label_bounds);
284 void WindowSelectorItem::CreateWindowLabel(const base::string16& title) {
285 window_label_.reset(new views::Widget);
286 views::Widget::InitParams params;
287 params.type = views::Widget::InitParams::TYPE_POPUP;
288 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
289 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
290 params.parent =
291 Shell::GetContainer(root_window_, ash::kShellWindowId_OverlayContainer);
292 params.accept_events = false;
293 params.visible_on_all_workspaces = true;
294 window_label_->set_focus_on_creation(false);
295 window_label_->Init(params);
296 window_label_view_ = new views::Label;
297 window_label_view_->SetEnabledColor(kLabelColor);
298 window_label_view_->SetBackgroundColor(kLabelBackground);
299 window_label_view_->SetShadows(gfx::ShadowValues(
301 gfx::ShadowValue(
302 gfx::Point(0, kVerticalShadowOffset), kShadowBlur, kLabelShadow)));
303 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
304 window_label_view_->SetFontList(
305 bundle.GetFontList(ui::ResourceBundle::BoldFont));
306 window_label_view_->SetText(title);
307 views::BoxLayout* layout = new views::BoxLayout(views::BoxLayout::kVertical,
309 kVerticalLabelPadding,
311 window_label_view_->SetLayoutManager(layout);
312 window_label_->SetContentsView(window_label_view_);
313 window_label_->Show();
316 } // namespace ash