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
FrameCaptionButton(views::ButtonListener * listener,CaptionButtonIcon icon)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
~FrameCaptionButton()35 FrameCaptionButton::~FrameCaptionButton() {
36 }
37
SetIcon(CaptionButtonIcon icon,Animate animate)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
SetStyle(Style style)60 void FrameCaptionButton::SetStyle(Style style) {
61 if (style_ == style)
62 return;
63 animation_->Reset(1);
64 style_ = style;
65 UpdateImages();
66 }
67
GetClassName() const68 const char* FrameCaptionButton::GetClassName() const {
69 return kViewClassName;
70 }
71
OnPaint(gfx::Canvas * canvas)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
OnGestureEvent(ui::GestureEvent * event)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
StateChanged()115 void FrameCaptionButton::StateChanged() {
116 if (state_ == STATE_HOVERED || state_ == STATE_PRESSED)
117 animation_->Reset(1);
118 }
119
UpdateImages()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
SetImages(int normal_image_id,int hot_image_id,int pushed_image_id)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
AnimationProgressed(const gfx::Animation * animation)173 void FrameCaptionButton::AnimationProgressed(const gfx::Animation* animation) {
174 SchedulePaint();
175 }
176
177 } // namespace ash
178