1// Copyright (c) 2012 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/resize_shadow.h"
6
7#include "base/time/time.h"
8#include "grit/ash_resources.h"
9#include "ui/aura/window.h"
10#include "ui/base/hit_test.h"
11#include "ui/base/resource/resource_bundle.h"
12#include "ui/compositor/layer.h"
13#include "ui/compositor/scoped_layer_animation_settings.h"
14#include "ui/wm/core/image_grid.h"
15
16namespace {
17
18// Final opacity for resize effect.
19const float kShadowTargetOpacity = 0.25f;
20// Animation time for resize effect in milliseconds.
21const int kShadowAnimationDurationMs = 100;
22
23// Sets up a layer as invisible and fully transparent, without animating.
24void InitLayer(ui::Layer* layer) {
25  layer->SetVisible(false);
26  layer->SetOpacity(0.f);
27}
28
29// Triggers an opacity animation that will make |layer| become |visible|.
30void ShowLayer(ui::Layer* layer, bool visible) {
31  ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
32  settings.SetTransitionDuration(
33      base::TimeDelta::FromMilliseconds(kShadowAnimationDurationMs));
34  layer->SetOpacity(visible ? kShadowTargetOpacity : 0.f);
35  // Sets the layer visibility after a delay, which will be identical to the
36  // opacity animation duration.
37  layer->SetVisible(visible);
38}
39
40}  // namespace
41
42namespace ash {
43
44ResizeShadow::ResizeShadow() : last_hit_test_(HTNOWHERE) {}
45
46ResizeShadow::~ResizeShadow() {}
47
48void ResizeShadow::Init(aura::Window* window) {
49  // Set up our image grid and images.
50  ResourceBundle& res = ResourceBundle::GetSharedInstance();
51  image_grid_.reset(new ::wm::ImageGrid);
52  image_grid_->SetImages(
53      &res.GetImageNamed(IDR_AURA_RESIZE_SHADOW_TOP_LEFT),
54      &res.GetImageNamed(IDR_AURA_RESIZE_SHADOW_TOP),
55      &res.GetImageNamed(IDR_AURA_RESIZE_SHADOW_TOP_RIGHT),
56      &res.GetImageNamed(IDR_AURA_RESIZE_SHADOW_LEFT),
57      NULL,
58      &res.GetImageNamed(IDR_AURA_RESIZE_SHADOW_RIGHT),
59      &res.GetImageNamed(IDR_AURA_RESIZE_SHADOW_BOTTOM_LEFT),
60      &res.GetImageNamed(IDR_AURA_RESIZE_SHADOW_BOTTOM),
61      &res.GetImageNamed(IDR_AURA_RESIZE_SHADOW_BOTTOM_RIGHT));
62  // Initialize all layers to invisible/transparent.
63  InitLayer(image_grid_->top_left_layer());
64  InitLayer(image_grid_->top_layer());
65  InitLayer(image_grid_->top_right_layer());
66  InitLayer(image_grid_->left_layer());
67  InitLayer(image_grid_->right_layer());
68  InitLayer(image_grid_->bottom_left_layer());
69  InitLayer(image_grid_->bottom_layer());
70  InitLayer(image_grid_->bottom_right_layer());
71  // Add image grid as a child of the window's layer so it follows the window
72  // as it moves.
73  window->layer()->Add(image_grid_->layer());
74}
75
76void ResizeShadow::ShowForHitTest(int hit) {
77  // Don't start animations unless something changed.
78  if (hit == last_hit_test_)
79    return;
80  last_hit_test_ = hit;
81
82  // Show affected corners.
83  ShowLayer(image_grid_->top_left_layer(), hit == HTTOPLEFT);
84  ShowLayer(image_grid_->top_right_layer(), hit == HTTOPRIGHT);
85  ShowLayer(image_grid_->bottom_left_layer(), hit == HTBOTTOMLEFT);
86  ShowLayer(image_grid_->bottom_right_layer(), hit == HTBOTTOMRIGHT);
87
88  // Show affected edges.
89  ShowLayer(image_grid_->top_layer(),
90            hit == HTTOPLEFT || hit == HTTOP || hit == HTTOPRIGHT);
91  ShowLayer(image_grid_->left_layer(),
92            hit == HTTOPLEFT || hit == HTLEFT || hit == HTBOTTOMLEFT);
93  ShowLayer(image_grid_->right_layer(),
94            hit == HTTOPRIGHT || hit == HTRIGHT || hit == HTBOTTOMRIGHT);
95  ShowLayer(image_grid_->bottom_layer(),
96            hit == HTBOTTOMLEFT || hit == HTBOTTOM || hit == HTBOTTOMRIGHT);
97}
98
99void ResizeShadow::Hide() {
100  ShowForHitTest(HTNOWHERE);
101}
102
103void ResizeShadow::Layout(const gfx::Rect& content_bounds) {
104  gfx::Rect local_bounds(content_bounds.size());
105  image_grid_->SetContentBounds(local_bounds);
106}
107
108}  // namespace ash
109