- add sources.
[platform/framework/web/crosswalk.git] / src / ui / views / corewm / shadow.cc
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 "ui/views/corewm/shadow.h"
6
7 #include "grit/ui_resources.h"
8 #include "ui/base/resource/resource_bundle.h"
9 #include "ui/compositor/scoped_layer_animation_settings.h"
10 #include "ui/views/corewm/image_grid.h"
11
12 namespace {
13
14 // Shadow opacity for different styles.
15 const float kActiveShadowOpacity = 1.0f;
16 const float kInactiveShadowOpacity = 0.2f;
17 const float kSmallShadowOpacity = 1.0f;
18
19 // Interior inset for different styles.
20 const int kActiveInteriorInset = 0;
21 const int kInactiveInteriorInset = 0;
22 const int kSmallInteriorInset = 5;
23
24 // Duration for opacity animation in milliseconds.
25 const int kShadowAnimationDurationMs = 100;
26
27 float GetOpacityForStyle(views::corewm::Shadow::Style style) {
28   switch (style) {
29     case views::corewm::Shadow::STYLE_ACTIVE:
30       return kActiveShadowOpacity;
31     case views::corewm::Shadow::STYLE_INACTIVE:
32       return kInactiveShadowOpacity;
33     case views::corewm::Shadow::STYLE_SMALL:
34       return kSmallShadowOpacity;
35   }
36   return 1.0f;
37 }
38
39 int GetInteriorInsetForStyle(views::corewm::Shadow::Style style) {
40   switch (style) {
41     case views::corewm::Shadow::STYLE_ACTIVE:
42       return kActiveInteriorInset;
43     case views::corewm::Shadow::STYLE_INACTIVE:
44       return kInactiveInteriorInset;
45     case views::corewm::Shadow::STYLE_SMALL:
46       return kSmallInteriorInset;
47   }
48   return 0;
49 }
50
51 }  // namespace
52
53 namespace views {
54 namespace corewm {
55
56 Shadow::Shadow() : style_(STYLE_ACTIVE), interior_inset_(0) {
57 }
58
59 Shadow::~Shadow() {
60 }
61
62 void Shadow::Init(Style style) {
63   style_ = style;
64   image_grid_.reset(new ImageGrid);
65   UpdateImagesForStyle();
66   image_grid_->layer()->set_name("Shadow");
67   image_grid_->layer()->SetOpacity(GetOpacityForStyle(style_));
68 }
69
70 void Shadow::SetContentBounds(const gfx::Rect& content_bounds) {
71   content_bounds_ = content_bounds;
72   UpdateImageGridBounds();
73 }
74
75 ui::Layer* Shadow::layer() const {
76   return image_grid_->layer();
77 }
78
79 void Shadow::SetStyle(Style style) {
80   if (style_ == style)
81     return;
82
83   Style old_style = style_;
84   style_ = style;
85
86   // Stop waiting for any as yet unfinished implicit animations.
87   StopObservingImplicitAnimations();
88
89   // If we're switching to or from the small style, don't bother with
90   // animations.
91   if (style == STYLE_SMALL || old_style == STYLE_SMALL) {
92     UpdateImagesForStyle();
93     image_grid_->layer()->SetOpacity(GetOpacityForStyle(style));
94     return;
95   }
96
97   // If we're becoming active, switch images now.  Because the inactive image
98   // has a very low opacity the switch isn't noticeable and this approach
99   // allows us to use only a single set of shadow images at a time.
100   if (style == STYLE_ACTIVE) {
101     UpdateImagesForStyle();
102     // Opacity was baked into inactive image, start opacity low to match.
103     image_grid_->layer()->SetOpacity(kInactiveShadowOpacity);
104   }
105
106   {
107     // Property sets within this scope will be implicitly animated.
108     ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator());
109     settings.AddObserver(this);
110     settings.SetTransitionDuration(
111         base::TimeDelta::FromMilliseconds(kShadowAnimationDurationMs));
112     switch (style_) {
113       case STYLE_ACTIVE:
114         image_grid_->layer()->SetOpacity(kActiveShadowOpacity);
115         break;
116       case STYLE_INACTIVE:
117         image_grid_->layer()->SetOpacity(kInactiveShadowOpacity);
118         break;
119       default:
120         NOTREACHED() << "Unhandled style " << style_;
121         break;
122     }
123   }
124 }
125
126 void Shadow::OnImplicitAnimationsCompleted() {
127   // If we just finished going inactive, switch images.  This doesn't cause
128   // a visual pop because the inactive image opacity is so low.
129   if (style_ == STYLE_INACTIVE) {
130     UpdateImagesForStyle();
131     // Opacity is baked into inactive image, so set fully opaque.
132     image_grid_->layer()->SetOpacity(1.0f);
133   }
134 }
135
136 void Shadow::UpdateImagesForStyle() {
137   ResourceBundle& res = ResourceBundle::GetSharedInstance();
138   switch (style_) {
139     case STYLE_ACTIVE:
140       image_grid_->SetImages(
141           &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_TOP_LEFT),
142           &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_TOP),
143           &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_TOP_RIGHT),
144           &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_LEFT),
145           NULL,
146           &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_RIGHT),
147           &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_BOTTOM_LEFT),
148           &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_BOTTOM),
149           &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_BOTTOM_RIGHT));
150       break;
151     case STYLE_INACTIVE:
152       image_grid_->SetImages(
153           &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_TOP_LEFT),
154           &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_TOP),
155           &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_TOP_RIGHT),
156           &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_LEFT),
157           NULL,
158           &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_RIGHT),
159           &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_BOTTOM_LEFT),
160           &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_BOTTOM),
161           &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_BOTTOM_RIGHT));
162       break;
163     case STYLE_SMALL:
164       image_grid_->SetImages(
165           &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_LEFT),
166           &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP),
167           &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_RIGHT),
168           &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_LEFT),
169           NULL,
170           &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_RIGHT),
171           &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_LEFT),
172           &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM),
173           &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_RIGHT));
174       break;
175     default:
176       NOTREACHED() << "Unhandled style " << style_;
177       break;
178   }
179
180   // Update interior inset for style.
181   interior_inset_ = GetInteriorInsetForStyle(style_);
182
183   // Image sizes may have changed.
184   UpdateImageGridBounds();
185 }
186
187 void Shadow::UpdateImageGridBounds() {
188   // Update bounds based on content bounds and image sizes.
189   gfx::Rect image_grid_bounds = content_bounds_;
190   image_grid_bounds.Inset(interior_inset_, interior_inset_);
191   image_grid_->SetContentBounds(image_grid_bounds);
192 }
193
194 }  // namespace corewm
195 }  // namespace views