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 3 // found in the LICENSE file. 4 5 #include "ash/wm/caption_buttons/frame_caption_button.h" 6 7 #include "grit/ash_resources.h" 8 #include "ui/base/resource/resource_bundle.h" 9 #include "ui/gfx/animation/slide_animation.h" 10 #include "ui/gfx/canvas.h" 11 12 namespace ash { 13 14 namespace { 15 16 // The duration of the crossfade animation when swapping the button's icon. 17 const int kCrossfadeDurationMs = 200; 18 19 } // namespace 20 21 // static 22 const char FrameCaptionButton::kViewClassName[] = "FrameCaptionButton"; 23 24 FrameCaptionButton::FrameCaptionButton(views::ButtonListener* listener, 25 CaptionButtonIcon icon) 26 : ImageButton(listener), 27 icon_(icon), 28 style_(STYLE_SHORT_RESTORED), 29 last_paint_scale_(1.0f), 30 animation_(new gfx::SlideAnimation(this)) { 31 animation_->Reset(1); 32 UpdateImages(); 33 } 34 35 FrameCaptionButton::~FrameCaptionButton() { 36 } 37 38 void FrameCaptionButton::SetIcon(CaptionButtonIcon icon, Animate animate) { 39 if (icon_ == icon) 40 return; 41 42 if (animate == ANIMATE_YES) { 43 gfx::Canvas canvas(size(), last_paint_scale_, false); 44 OnPaint(&canvas); 45 crossfade_image_ = gfx::ImageSkia(canvas.ExtractImageRep()); 46 47 icon_ = icon; 48 UpdateImages(); 49 50 animation_->Reset(0); 51 animation_->SetSlideDuration(kCrossfadeDurationMs); 52 animation_->Show(); 53 } else { 54 animation_->Reset(1); 55 icon_ = icon; 56 UpdateImages(); 57 } 58 } 59 60 void FrameCaptionButton::SetStyle(Style style) { 61 if (style_ == style) 62 return; 63 animation_->Reset(1); 64 style_ = style; 65 UpdateImages(); 66 } 67 68 const char* FrameCaptionButton::GetClassName() const { 69 return kViewClassName; 70 } 71 72 void FrameCaptionButton::OnPaint(gfx::Canvas* canvas) { 73 last_paint_scale_ = canvas->image_scale(); 74 int alpha = static_cast<int>(animation_->GetCurrentValue() * 255); 75 int crossfade_alpha = 255 - alpha; 76 if (crossfade_alpha > 0 && !crossfade_image_.isNull()) { 77 gfx::Canvas composed_canvas(size(), last_paint_scale_, false); 78 SkPaint paint; 79 paint.setAlpha(crossfade_alpha); 80 paint.setXfermodeMode(SkXfermode::kPlus_Mode); 81 composed_canvas.DrawImageInt(crossfade_image_, 0, 0, paint); 82 paint.setAlpha(alpha); 83 ImageButton::OnPaint(&composed_canvas); 84 85 canvas->DrawImageInt( 86 gfx::ImageSkia(composed_canvas.ExtractImageRep()), 0, 0); 87 } else { 88 ImageButton::OnPaint(canvas); 89 } 90 } 91 92 void FrameCaptionButton::OnGestureEvent(ui::GestureEvent* event) { 93 // ImageButton does not become pressed when the user drags off and then back 94 // onto the button. Make FrameCaptionButton pressed in this case because this 95 // behavior is more consistent with AlternateFrameSizeButton. 96 if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || 97 event->type() == ui::ET_GESTURE_SCROLL_UPDATE) { 98 if (HitTestPoint(event->location())) { 99 SetState(STATE_PRESSED); 100 RequestFocus(); 101 event->StopPropagation(); 102 } else { 103 SetState(STATE_NORMAL); 104 } 105 } else if (event->type() == ui::ET_GESTURE_SCROLL_END) { 106 if (HitTestPoint(event->location())) { 107 SetState(STATE_HOVERED); 108 NotifyClick(*event); 109 event->StopPropagation(); 110 } 111 } 112 ImageButton::OnGestureEvent(event); 113 } 114 115 void FrameCaptionButton::StateChanged() { 116 if (state_ == STATE_HOVERED || state_ == STATE_PRESSED) 117 animation_->Reset(1); 118 } 119 120 void FrameCaptionButton::UpdateImages() { 121 switch (icon_) { 122 case CAPTION_BUTTON_ICON_MINIMIZE: 123 SetImages(IDR_AURA_WINDOW_MINIMIZE_SHORT, 124 IDR_AURA_WINDOW_MINIMIZE_SHORT_H, 125 IDR_AURA_WINDOW_MINIMIZE_SHORT_P); 126 break; 127 case CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE: 128 case CAPTION_BUTTON_ICON_LEFT_SNAPPED: 129 case CAPTION_BUTTON_ICON_RIGHT_SNAPPED: 130 if (style_ == STYLE_SHORT_MAXIMIZED_OR_FULLSCREEN) { 131 SetImages(IDR_AURA_WINDOW_MAXIMIZED_RESTORE2, 132 IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_H, 133 IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_P); 134 } else if (style_ == STYLE_SHORT_RESTORED) { 135 SetImages(IDR_AURA_WINDOW_MAXIMIZED_RESTORE, 136 IDR_AURA_WINDOW_MAXIMIZED_RESTORE_H, 137 IDR_AURA_WINDOW_MAXIMIZED_RESTORE_P); 138 } else { 139 SetImages(IDR_AURA_WINDOW_MAXIMIZE, 140 IDR_AURA_WINDOW_MAXIMIZE_H, 141 IDR_AURA_WINDOW_MAXIMIZE_P); 142 } 143 break; 144 case CAPTION_BUTTON_ICON_CLOSE: 145 if (style_ == STYLE_SHORT_MAXIMIZED_OR_FULLSCREEN) { 146 SetImages(IDR_AURA_WINDOW_MAXIMIZED_CLOSE2, 147 IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_H, 148 IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_P); 149 } else if (style_ == STYLE_SHORT_RESTORED) { 150 SetImages(IDR_AURA_WINDOW_MAXIMIZED_CLOSE, 151 IDR_AURA_WINDOW_MAXIMIZED_CLOSE_H, 152 IDR_AURA_WINDOW_MAXIMIZED_CLOSE_P); 153 } else { 154 SetImages(IDR_AURA_WINDOW_CLOSE, 155 IDR_AURA_WINDOW_CLOSE_H, 156 IDR_AURA_WINDOW_CLOSE_P); 157 } 158 break; 159 } 160 161 SchedulePaint(); 162 } 163 164 void FrameCaptionButton::SetImages(int normal_image_id, 165 int hot_image_id, 166 int pushed_image_id) { 167 ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance(); 168 SetImage(STATE_NORMAL, resource_bundle.GetImageSkiaNamed(normal_image_id)); 169 SetImage(STATE_HOVERED, resource_bundle.GetImageSkiaNamed(hot_image_id)); 170 SetImage(STATE_PRESSED, resource_bundle.GetImageSkiaNamed(pushed_image_id)); 171 } 172 173 void FrameCaptionButton::AnimationProgressed(const gfx::Animation* animation) { 174 SchedulePaint(); 175 } 176 177 } // namespace ash 178