Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ash/frame/caption_buttons/frame_caption_button_container_view.h" | 5 #include "ash/frame/caption_buttons/frame_caption_button_container_view.h" |
| 6 | 6 |
| 7 #include <cmath> | 7 #include <cmath> |
| 8 #include <map> | |
| 8 | 9 |
| 9 #include "ash/ash_switches.h" | 10 #include "ash/ash_switches.h" |
| 10 #include "ash/frame/caption_buttons/alternate_frame_size_button.h" | 11 #include "ash/frame/caption_buttons/alternate_frame_size_button.h" |
| 11 #include "ash/frame/caption_buttons/frame_caption_button.h" | 12 #include "ash/frame/caption_buttons/frame_caption_button.h" |
| 12 #include "ash/frame/caption_buttons/frame_maximize_button.h" | 13 #include "ash/frame/caption_buttons/frame_maximize_button.h" |
| 13 #include "ash/metrics/user_metrics_recorder.h" | 14 #include "ash/metrics/user_metrics_recorder.h" |
| 14 #include "ash/shell.h" | 15 #include "ash/shell.h" |
| 15 #include "grit/ui_strings.h" // Accessibility names | 16 #include "grit/ui_strings.h" // Accessibility names |
| 16 #include "ui/base/hit_test.h" | 17 #include "ui/base/hit_test.h" |
| 17 #include "ui/base/l10n/l10n_util.h" | 18 #include "ui/base/l10n/l10n_util.h" |
| 19 #include "ui/compositor/layer.h" | |
| 18 #include "ui/compositor/scoped_animation_duration_scale_mode.h" | 20 #include "ui/compositor/scoped_animation_duration_scale_mode.h" |
| 21 #include "ui/compositor/scoped_layer_animation_settings.h" | |
| 22 #include "ui/gfx/animation/tween.h" | |
| 19 #include "ui/gfx/canvas.h" | 23 #include "ui/gfx/canvas.h" |
| 20 #include "ui/gfx/insets.h" | 24 #include "ui/gfx/insets.h" |
| 21 #include "ui/gfx/point.h" | 25 #include "ui/gfx/point.h" |
| 22 #include "ui/views/widget/widget.h" | 26 #include "ui/views/widget/widget.h" |
| 23 #include "ui/views/widget/widget_delegate.h" | 27 #include "ui/views/widget/widget_delegate.h" |
| 24 | 28 |
| 25 namespace ash { | 29 namespace ash { |
| 26 | 30 |
| 27 namespace { | 31 namespace { |
| 28 | 32 |
| 33 // Visual design parameters for animating the transition to maximize mode. | |
| 34 // When the size button hides we delay sliding the minimize button into its | |
| 35 // location. Also used to delay showing the size button so that the minimize | |
| 36 // button slides out of that position. | |
| 37 const int kAnimationDelayMs = 100; | |
| 38 const int kMinimizeSlideDurationMs = 500; | |
| 39 const int kSizeFadeDurationMs = 250; | |
| 40 | |
| 29 // Converts |point| from |src| to |dst| and hittests against |dst|. | 41 // Converts |point| from |src| to |dst| and hittests against |dst|. |
| 30 bool ConvertPointToViewAndHitTest(const views::View* src, | 42 bool ConvertPointToViewAndHitTest(const views::View* src, |
| 31 const views::View* dst, | 43 const views::View* dst, |
| 32 const gfx::Point& point) { | 44 const gfx::Point& point) { |
| 33 gfx::Point converted(point); | 45 gfx::Point converted(point); |
| 34 views::View::ConvertPointToTarget(src, dst, &converted); | 46 views::View::ConvertPointToTarget(src, dst, &converted); |
| 35 return dst->HitTestPoint(converted); | 47 return dst->HitTestPoint(converted); |
| 36 } | 48 } |
| 37 | 49 |
| 38 } // namespace | 50 } // namespace |
| 39 | 51 |
| 40 // static | 52 // static |
| 41 const char FrameCaptionButtonContainerView::kViewClassName[] = | 53 const char FrameCaptionButtonContainerView::kViewClassName[] = |
| 42 "FrameCaptionButtonContainerView"; | 54 "FrameCaptionButtonContainerView"; |
| 43 | 55 |
| 44 FrameCaptionButtonContainerView::FrameCaptionButtonContainerView( | 56 FrameCaptionButtonContainerView::FrameCaptionButtonContainerView( |
| 45 views::Widget* frame, | 57 views::Widget* frame, |
| 46 MinimizeAllowed minimize_allowed) | 58 MinimizeAllowed minimize_allowed) |
| 47 : frame_(frame), | 59 : frame_(frame), |
| 48 minimize_button_(NULL), | 60 minimize_button_(NULL), |
| 49 size_button_(NULL), | 61 size_button_(NULL), |
| 50 close_button_(NULL) { | 62 close_button_(NULL) { |
| 51 bool alternate_style = switches::UseAlternateFrameCaptionButtonStyle(); | 63 bool alternate_style = switches::UseAlternateFrameCaptionButtonStyle(); |
| 52 | 64 |
| 65 SetPaintToLayer(true); | |
| 66 SetFillsBoundsOpaquely(false); | |
| 67 | |
| 53 // Insert the buttons left to right. | 68 // Insert the buttons left to right. |
| 54 minimize_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_MINIMIZE); | 69 minimize_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_MINIMIZE); |
| 55 minimize_button_->SetAccessibleName( | 70 minimize_button_->SetAccessibleName( |
| 56 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MINIMIZE)); | 71 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MINIMIZE)); |
| 57 // Hide |minimize_button_| when using the non-alternate button style because | 72 // Hide |minimize_button_| when using the non-alternate button style because |
| 58 // |size_button_| is capable of minimizing in this case. | 73 // |size_button_| is capable of minimizing in this case. |
| 59 minimize_button_->SetVisible( | 74 minimize_button_->SetVisible( |
| 60 minimize_allowed == MINIMIZE_ALLOWED && | 75 minimize_allowed == MINIMIZE_ALLOWED && |
| 61 (alternate_style || !frame_->widget_delegate()->CanMaximize())); | 76 (alternate_style || !frame_->widget_delegate()->CanMaximize())); |
| 77 minimize_button_->SetPaintToLayer(true); | |
| 78 minimize_button_->SetFillsBoundsOpaquely(false); | |
| 62 AddChildView(minimize_button_); | 79 AddChildView(minimize_button_); |
| 63 | 80 |
| 64 if (alternate_style) | 81 if (alternate_style) |
| 65 size_button_ = new AlternateFrameSizeButton(this, frame, this); | 82 size_button_ = new AlternateFrameSizeButton(this, frame, this); |
| 66 else | 83 else |
| 67 size_button_ = new FrameMaximizeButton(this, frame); | 84 size_button_ = new FrameMaximizeButton(this, frame); |
| 68 size_button_->SetAccessibleName( | 85 size_button_->SetAccessibleName( |
| 69 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MAXIMIZE)); | 86 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MAXIMIZE)); |
| 87 size_button_->SetPaintToLayer(true); | |
| 88 size_button_->SetFillsBoundsOpaquely(false); | |
| 70 UpdateSizeButtonVisibility(false); | 89 UpdateSizeButtonVisibility(false); |
| 71 AddChildView(size_button_); | 90 AddChildView(size_button_); |
| 72 | 91 |
| 73 close_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_CLOSE); | 92 close_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_CLOSE); |
| 74 close_button_->SetAccessibleName( | 93 close_button_->SetAccessibleName( |
| 75 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE)); | 94 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE)); |
| 95 close_button_->SetPaintToLayer(true); | |
| 96 close_button_->SetFillsBoundsOpaquely(false); | |
| 76 AddChildView(close_button_); | 97 AddChildView(close_button_); |
| 77 } | 98 } |
| 78 | 99 |
| 79 FrameCaptionButtonContainerView::~FrameCaptionButtonContainerView() { | 100 FrameCaptionButtonContainerView::~FrameCaptionButtonContainerView() { |
| 80 } | 101 } |
| 81 | 102 |
| 82 FrameMaximizeButton* | 103 FrameMaximizeButton* |
| 83 FrameCaptionButtonContainerView::GetOldStyleSizeButton() { | 104 FrameCaptionButtonContainerView::GetOldStyleSizeButton() { |
| 84 return switches::UseAlternateFrameCaptionButtonStyle() ? | 105 return switches::UseAlternateFrameCaptionButtonStyle() ? |
| 85 NULL : static_cast<FrameMaximizeButton*>(size_button_); | 106 NULL : static_cast<FrameMaximizeButton*>(size_button_); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 136 } | 157 } |
| 137 | 158 |
| 138 void FrameCaptionButtonContainerView::UpdateSizeButtonVisibility( | 159 void FrameCaptionButtonContainerView::UpdateSizeButtonVisibility( |
| 139 bool force_hidden) { | 160 bool force_hidden) { |
| 140 // TODO(flackr): Refactor the Maximize Mode notifications. Currently | 161 // TODO(flackr): Refactor the Maximize Mode notifications. Currently |
| 141 // UpdateSizeButtonVisibilty requires a force_hidden parameter. This is | 162 // UpdateSizeButtonVisibilty requires a force_hidden parameter. This is |
| 142 // because Shell::IsMaximizeWindowManagerEnabled is still false at the | 163 // because Shell::IsMaximizeWindowManagerEnabled is still false at the |
| 143 // time when ShellObserver::OnMaximizeModeStarted is called. This prevents | 164 // time when ShellObserver::OnMaximizeModeStarted is called. This prevents |
| 144 // this method from performing that check, and instead relies on the calling | 165 // this method from performing that check, and instead relies on the calling |
| 145 // code to tell it to force being hidden. | 166 // code to tell it to force being hidden. |
| 146 size_button_->SetVisible( | 167 |
| 147 !force_hidden && frame_->widget_delegate()->CanMaximize()); | 168 bool visible = !force_hidden && frame_->widget_delegate()->CanMaximize(); |
| 169 | |
| 170 // Turning visibility off prevents animations from rendering. Setting the | |
| 171 // size button visibility to false will occur after the animation. | |
| 172 if (visible) | |
| 173 size_button_->SetVisible(visible); | |
| 174 | |
| 175 ui::ScopedLayerAnimationSettings settings( | |
| 176 size_button_->layer()->GetAnimator()); | |
| 177 settings.SetTransitionDuration( | |
| 178 base::TimeDelta::FromMilliseconds(kSizeFadeDurationMs)); | |
| 179 settings.SetPreemptionStrategy( | |
| 180 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | |
| 181 | |
| 182 if (visible) { | |
| 183 settings.SetTweenType(gfx::Tween::EASE_OUT); | |
| 184 // Delay fade in so that the minimize button has begun its sliding | |
| 185 // animation. | |
| 186 size_button_->layer()->GetAnimator()->SchedulePauseForProperties( | |
| 187 base::TimeDelta::FromMilliseconds(kAnimationDelayMs), | |
| 188 ui::LayerAnimationElement::OPACITY); | |
| 189 size_button_->layer()->SetOpacity(1.0f); | |
| 190 } else { | |
| 191 settings.SetTweenType(gfx::Tween::EASE_IN); | |
| 192 // Observer will call size_button_->SetVisible(false) upon completion of | |
| 193 // the animation. | |
| 194 // TODO(jonross): avoid the delayed SetVisible(false) call by acquring | |
| 195 // the size_button's layer before making it invisible. That layer can then | |
| 196 // be animated and deleted upon completion of the animation. See | |
| 197 // LayerOwner::RecreateLayer | |
| 198 settings.AddObserver(this); | |
| 199 size_button_->layer()->SetOpacity(0.0f); | |
| 200 size_button_->layer()->SetVisible(false); | |
| 201 } | |
| 148 } | 202 } |
| 149 | 203 |
| 150 gfx::Size FrameCaptionButtonContainerView::GetPreferredSize() { | 204 gfx::Size FrameCaptionButtonContainerView::GetPreferredSize() { |
| 151 int width = 0; | 205 int width = 0; |
| 152 for (int i = 0; i < child_count(); ++i) { | 206 for (int i = 0; i < child_count(); ++i) { |
| 153 views::View* child = child_at(i); | 207 views::View* child = child_at(i); |
| 154 if (child->visible()) | 208 if (child->visible()) |
| 155 width += child_at(i)->GetPreferredSize().width(); | 209 width += child_at(i)->GetPreferredSize().width(); |
| 156 } | 210 } |
| 157 return gfx::Size(width, close_button_->GetPreferredSize().height()); | 211 return gfx::Size(width, close_button_->GetPreferredSize().height()); |
| 158 } | 212 } |
| 159 | 213 |
| 160 void FrameCaptionButtonContainerView::Layout() { | 214 void FrameCaptionButtonContainerView::Layout() { |
|
jonross
2014/05/09 18:41:10
Redone to not care which button is changing visibi
| |
| 161 int x = 0; | 215 scoped_ptr<ui::ScopedLayerAnimationSettings> animation; |
|
flackr
2014/05/09 18:57:58
nit: Scope this to it's use, i.e. in the loop body
jonross
2014/05/15 20:24:13
Done.
| |
| 162 for (int i = 0; i < child_count(); ++i) { | 216 bool previous_child_animating_visibility = false; |
| 217 bool previous_child_target_visibility = false; | |
| 218 int x = width(); | |
| 219 for (int i = child_count() - 1; i >= 0; --i) { | |
| 163 views::View* child = child_at(i); | 220 views::View* child = child_at(i); |
| 164 if (!child->visible()) | 221 ui::LayerAnimator* child_animator = child->layer()->GetAnimator(); |
| 222 bool child_animating = child_animator->is_animating(); | |
| 223 // The actual property visibility is not being animated, otherwise the | |
| 224 // view does not render. | |
| 225 bool child_animating_visibility = child_animator-> | |
| 226 IsAnimatingProperty(ui::LayerAnimationElement::OPACITY); | |
|
flackr
2014/05/09 18:57:58
Instead of checking if it's animating opacity, che
jonross
2014/05/09 19:03:34
Issue with that is that layout is called 7+ times
| |
| 227 bool child_target_visibility = child->layer()->GetTargetVisibility(); | |
| 228 | |
| 229 | |
| 230 if (!child->visible() || | |
| 231 (child_animating_visibility && !child_target_visibility)) { | |
| 232 previous_child_animating_visibility = child_animating_visibility; | |
| 233 previous_child_target_visibility = child_target_visibility; | |
|
flackr
2014/05/09 18:57:58
This really needs to be an offset width. The butto
jonross
2014/05/15 20:24:13
Done.
| |
| 165 continue; | 234 continue; |
| 235 } | |
| 166 | 236 |
| 167 gfx::Size size = child->GetPreferredSize(); | 237 gfx::Size size = child->GetPreferredSize(); |
| 238 // Animate the button if the previous button is currently animating | |
| 239 // its visibility. | |
| 240 if (previous_child_animating_visibility) { | |
| 241 if (previous_child_target_visibility) { | |
| 242 if (!child_animating) | |
| 243 child->SetBounds(x, 0, size.width(), size.height()); | |
| 244 } else { | |
| 245 // Delay sliding to where the previous button was located. | |
| 246 child_animator->SchedulePauseForProperties( | |
| 247 base::TimeDelta::FromMilliseconds(kAnimationDelayMs), | |
| 248 ui::LayerAnimationElement::BOUNDS); | |
| 249 } | |
| 250 ui::ScopedLayerAnimationSettings* settings = | |
| 251 new ui::ScopedLayerAnimationSettings(child_animator); | |
| 252 settings->SetTransitionDuration( | |
| 253 base::TimeDelta::FromMilliseconds(kMinimizeSlideDurationMs)); | |
| 254 settings->SetPreemptionStrategy( | |
| 255 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | |
| 256 settings->SetTweenType(gfx::Tween::EASE_OUT); | |
| 257 animation.reset(settings); | |
| 258 } | |
| 259 x -= size.width(); | |
| 168 child->SetBounds(x, 0, size.width(), size.height()); | 260 child->SetBounds(x, 0, size.width(), size.height()); |
| 169 x += size.width(); | 261 |
| 262 if (child_animating_visibility) { | |
| 263 previous_child_animating_visibility = child_animating_visibility; | |
| 264 previous_child_target_visibility = child_target_visibility; | |
| 265 } | |
| 170 } | 266 } |
| 171 } | 267 } |
| 172 | 268 |
| 173 const char* FrameCaptionButtonContainerView::GetClassName() const { | 269 const char* FrameCaptionButtonContainerView::GetClassName() const { |
| 174 return kViewClassName; | 270 return kViewClassName; |
| 175 } | 271 } |
| 176 | 272 |
| 177 void FrameCaptionButtonContainerView::SetButtonIcon(FrameCaptionButton* button, | 273 void FrameCaptionButtonContainerView::SetButtonIcon(FrameCaptionButton* button, |
| 178 CaptionButtonIcon icon, | 274 CaptionButtonIcon icon, |
| 179 Animate animate) { | 275 Animate animate) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 211 } | 307 } |
| 212 | 308 |
| 213 // Abort any animations of the button icons. | 309 // Abort any animations of the button icons. |
| 214 SetButtonsToNormal(ANIMATE_NO); | 310 SetButtonsToNormal(ANIMATE_NO); |
| 215 | 311 |
| 216 ash::UserMetricsAction action = | 312 ash::UserMetricsAction action = |
| 217 ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MINIMIZE; | 313 ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MINIMIZE; |
| 218 if (sender == minimize_button_) { | 314 if (sender == minimize_button_) { |
| 219 frame_->Minimize(); | 315 frame_->Minimize(); |
| 220 } else if (sender == size_button_) { | 316 } else if (sender == size_button_) { |
| 221 if (frame_->IsFullscreen()) { // Can be clicked in immersive fullscreen. | 317 if (frame_->IsFullscreen()) { // Can be clicked in immersive fullscreen. |
| 222 frame_->SetFullscreen(false); | 318 frame_->SetFullscreen(false); |
| 223 action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_EXIT_FULLSCREEN; | 319 action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_EXIT_FULLSCREEN; |
| 224 } else if (frame_->IsMaximized()) { | 320 } else if (frame_->IsMaximized()) { |
| 225 frame_->Restore(); | 321 frame_->Restore(); |
| 226 action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_RESTORE; | 322 action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_RESTORE; |
| 227 } else { | 323 } else { |
| 228 frame_->Maximize(); | 324 frame_->Maximize(); |
| 229 action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MAXIMIZE; | 325 action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MAXIMIZE; |
| 230 } | 326 } |
| 231 } else if(sender == close_button_) { | 327 } else if (sender == close_button_) { |
| 232 frame_->Close(); | 328 frame_->Close(); |
| 233 action = ash::UMA_WINDOW_CLOSE_BUTTON_CLICK; | 329 action = ash::UMA_WINDOW_CLOSE_BUTTON_CLICK; |
| 234 } else { | 330 } else { |
| 235 return; | 331 return; |
| 236 } | 332 } |
| 237 ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction(action); | 333 ash::Shell::GetInstance()->metrics()->RecordUserMetricsAction(action); |
| 238 } | 334 } |
| 239 | 335 |
| 240 bool FrameCaptionButtonContainerView::IsMinimizeButtonVisible() const { | 336 bool FrameCaptionButtonContainerView::IsMinimizeButtonVisible() const { |
| 241 return minimize_button_->visible(); | 337 return minimize_button_->visible(); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 298 FrameCaptionButton* button = buttons[i]; | 394 FrameCaptionButton* button = buttons[i]; |
| 299 views::Button::ButtonState new_state = views::Button::STATE_NORMAL; | 395 views::Button::ButtonState new_state = views::Button::STATE_NORMAL; |
| 300 if (button == to_hover) | 396 if (button == to_hover) |
| 301 new_state = views::Button::STATE_HOVERED; | 397 new_state = views::Button::STATE_HOVERED; |
| 302 else if (button == to_press) | 398 else if (button == to_press) |
| 303 new_state = views::Button::STATE_PRESSED; | 399 new_state = views::Button::STATE_PRESSED; |
| 304 button->SetState(new_state); | 400 button->SetState(new_state); |
| 305 } | 401 } |
| 306 } | 402 } |
| 307 | 403 |
| 404 void FrameCaptionButtonContainerView::OnImplicitAnimationsCompleted() { | |
| 405 DCHECK(!size_button_->layer()->GetTargetVisibility()); | |
| 406 size_button_->SetVisible(false); | |
| 407 // TODO(jonross): currently we need to delay telling the parent about the | |
| 408 // size change from visibility. When the size changes this forces a relayout | |
| 409 // and we want to animate both the bounds of FrameCaptionButtonContainerView | |
| 410 // along with that of its children. However when the parent is currently | |
| 411 // having its bounds changed this leads to strange animations where this view | |
| 412 // renders outside of its parents. Create a more specific animation where | |
| 413 // height and y are immediately fixed, and where we only animate width and x. | |
| 414 PreferredSizeChanged(); | |
| 415 } | |
| 416 | |
| 308 FrameCaptionButtonContainerView::ButtonIconIds::ButtonIconIds() | 417 FrameCaptionButtonContainerView::ButtonIconIds::ButtonIconIds() |
| 309 : icon_image_id(-1), | 418 : icon_image_id(-1), |
| 310 inactive_icon_image_id(-1), | 419 inactive_icon_image_id(-1), |
| 311 hovered_background_image_id(-1), | 420 hovered_background_image_id(-1), |
| 312 pressed_background_image_id(-1) { | 421 pressed_background_image_id(-1) { |
| 313 } | 422 } |
| 314 | 423 |
| 315 FrameCaptionButtonContainerView::ButtonIconIds::ButtonIconIds( | 424 FrameCaptionButtonContainerView::ButtonIconIds::ButtonIconIds( |
| 316 int icon_id, | 425 int icon_id, |
| 317 int inactive_icon_id, | 426 int inactive_icon_id, |
| 318 int hovered_background_id, | 427 int hovered_background_id, |
| 319 int pressed_background_id) | 428 int pressed_background_id) |
| 320 : icon_image_id(icon_id), | 429 : icon_image_id(icon_id), |
| 321 inactive_icon_image_id(inactive_icon_id), | 430 inactive_icon_image_id(inactive_icon_id), |
| 322 hovered_background_image_id(hovered_background_id), | 431 hovered_background_image_id(hovered_background_id), |
| 323 pressed_background_image_id(pressed_background_id) { | 432 pressed_background_image_id(pressed_background_id) { |
| 324 } | 433 } |
| 325 | 434 |
| 326 FrameCaptionButtonContainerView::ButtonIconIds::~ButtonIconIds() { | 435 FrameCaptionButtonContainerView::ButtonIconIds::~ButtonIconIds() { |
| 327 } | 436 } |
| 328 | 437 |
| 329 } // namespace ash | 438 } // namespace ash |
| OLD | NEW |