OLD | NEW |
| (Empty) |
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 | |
OLD | NEW |