| 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 |