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.
5 #include "ui/views/controls/button/image_button.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "ui/accessibility/ax_view_state.h"
9 #include "ui/gfx/animation/throb_animation.h"
10 #include "ui/gfx/canvas.h"
11 #include "ui/gfx/image/image_skia_operations.h"
12 #include "ui/gfx/scoped_canvas.h"
13 #include "ui/views/painter.h"
14 #include "ui/views/widget/widget.h"
18 // Default button size if no image is set. This is ignored if there is an image,
19 // and exists for historical reasons (any number of clients could depend on this
21 static const int kDefaultWidth
= 16;
22 static const int kDefaultHeight
= 14;
24 const char ImageButton::kViewClassName
[] = "ImageButton";
26 ////////////////////////////////////////////////////////////////////////////////
27 // ImageButton, public:
29 ImageButton::ImageButton(ButtonListener
* listener
)
30 : CustomButton(listener
),
31 h_alignment_(ALIGN_LEFT
),
32 v_alignment_(ALIGN_TOP
),
33 draw_image_mirrored_(false),
34 focus_painter_(Painter::CreateDashedFocusPainter()) {
35 // By default, we request that the gfx::Canvas passed to our View::OnPaint()
36 // implementation is flipped horizontally so that the button's images are
37 // mirrored when the UI directionality is right-to-left.
38 EnableCanvasFlippingForRTLUI(true);
41 ImageButton::~ImageButton() {
44 const gfx::ImageSkia
& ImageButton::GetImage(ButtonState state
) const {
45 return images_
[state
];
48 void ImageButton::SetImage(ButtonState state
, const gfx::ImageSkia
* image
) {
49 images_
[state
] = image
? *image
: gfx::ImageSkia();
50 PreferredSizeChanged();
53 void ImageButton::SetBackground(SkColor color
,
54 const gfx::ImageSkia
* image
,
55 const gfx::ImageSkia
* mask
) {
56 if (image
== NULL
|| mask
== NULL
) {
57 background_image_
= gfx::ImageSkia();
61 background_image_
= gfx::ImageSkiaOperations::CreateButtonBackground(color
,
65 void ImageButton::SetImageAlignment(HorizontalAlignment h_align
,
66 VerticalAlignment v_align
) {
67 h_alignment_
= h_align
;
68 v_alignment_
= v_align
;
72 void ImageButton::SetFocusPainter(scoped_ptr
<Painter
> focus_painter
) {
73 focus_painter_
= focus_painter
.Pass();
76 void ImageButton::SetMinimumImageSize(const gfx::Size
& size
) {
77 if (minimum_image_size_
== size
)
80 minimum_image_size_
= size
;
81 PreferredSizeChanged();
84 ////////////////////////////////////////////////////////////////////////////////
85 // ImageButton, View overrides:
87 gfx::Size
ImageButton::GetPreferredSize() const {
88 gfx::Size
size(kDefaultWidth
, kDefaultHeight
);
89 if (!images_
[STATE_NORMAL
].isNull()) {
90 size
= gfx::Size(images_
[STATE_NORMAL
].width(),
91 images_
[STATE_NORMAL
].height());
94 size
.SetToMax(minimum_image_size_
);
96 gfx::Insets insets
= GetInsets();
97 size
.Enlarge(insets
.width(), insets
.height());
101 const char* ImageButton::GetClassName() const {
102 return kViewClassName
;
105 void ImageButton::OnPaint(gfx::Canvas
* canvas
) {
106 // Call the base class first to paint any background/borders.
107 View::OnPaint(canvas
);
109 gfx::ImageSkia img
= GetImageToPaint();
112 gfx::ScopedCanvas
scoped(canvas
);
113 if (draw_image_mirrored_
) {
114 canvas
->Translate(gfx::Vector2d(width(), 0));
115 canvas
->Scale(-1, 1);
118 gfx::Point position
= ComputeImagePaintPosition(img
);
119 if (!background_image_
.isNull())
120 canvas
->DrawImageInt(background_image_
, position
.x(), position
.y());
122 canvas
->DrawImageInt(img
, position
.x(), position
.y());
125 Painter::PaintFocusPainter(this, canvas
, focus_painter());
128 ////////////////////////////////////////////////////////////////////////////////
129 // ImageButton, protected:
131 void ImageButton::OnFocus() {
133 if (focus_painter_
.get())
137 void ImageButton::OnBlur() {
139 if (focus_painter_
.get())
143 gfx::ImageSkia
ImageButton::GetImageToPaint() {
146 if (!images_
[STATE_HOVERED
].isNull() && hover_animation_
->is_animating()) {
147 img
= gfx::ImageSkiaOperations::CreateBlendedImage(images_
[STATE_NORMAL
],
148 images_
[STATE_HOVERED
], hover_animation_
->GetCurrentValue());
150 img
= images_
[state_
];
153 return !img
.isNull() ? img
: images_
[STATE_NORMAL
];
156 ////////////////////////////////////////////////////////////////////////////////
157 // ImageButton, private:
159 gfx::Point
ImageButton::ComputeImagePaintPosition(const gfx::ImageSkia
& image
) {
161 gfx::Rect rect
= GetContentsBounds();
163 HorizontalAlignment h_alignment
= h_alignment_
;
164 if (draw_image_mirrored_
) {
165 if (h_alignment
== ALIGN_RIGHT
)
166 h_alignment
= ALIGN_LEFT
;
167 else if (h_alignment
== ALIGN_LEFT
)
168 h_alignment
= ALIGN_RIGHT
;
171 if (h_alignment
== ALIGN_CENTER
)
172 x
= (rect
.width() - image
.width()) / 2;
173 else if (h_alignment
== ALIGN_RIGHT
)
174 x
= rect
.width() - image
.width();
176 if (v_alignment_
== ALIGN_MIDDLE
)
177 y
= (rect
.height() - image
.height()) / 2;
178 else if (v_alignment_
== ALIGN_BOTTOM
)
179 y
= rect
.height() - image
.height();
184 return gfx::Point(x
, y
);
187 ////////////////////////////////////////////////////////////////////////////////
188 // ToggleImageButton, public:
190 ToggleImageButton::ToggleImageButton(ButtonListener
* listener
)
191 : ImageButton(listener
),
195 ToggleImageButton::~ToggleImageButton() {
198 void ToggleImageButton::SetToggled(bool toggled
) {
199 if (toggled
== toggled_
)
202 for (int i
= 0; i
< STATE_COUNT
; ++i
) {
203 gfx::ImageSkia temp
= images_
[i
];
204 images_
[i
] = alternate_images_
[i
];
205 alternate_images_
[i
] = temp
;
210 NotifyAccessibilityEvent(ui::AX_EVENT_VALUE_CHANGED
, true);
213 void ToggleImageButton::SetToggledImage(ButtonState state
,
214 const gfx::ImageSkia
* image
) {
216 images_
[state
] = image
? *image
: gfx::ImageSkia();
220 alternate_images_
[state
] = image
? *image
: gfx::ImageSkia();
224 void ToggleImageButton::SetToggledTooltipText(const base::string16
& tooltip
) {
225 toggled_tooltip_text_
= tooltip
;
228 ////////////////////////////////////////////////////////////////////////////////
229 // ToggleImageButton, ImageButton overrides:
231 const gfx::ImageSkia
& ToggleImageButton::GetImage(ButtonState state
) const {
233 return alternate_images_
[state
];
234 return images_
[state
];
237 void ToggleImageButton::SetImage(ButtonState state
,
238 const gfx::ImageSkia
* image
) {
240 alternate_images_
[state
] = image
? *image
: gfx::ImageSkia();
242 images_
[state
] = image
? *image
: gfx::ImageSkia();
246 PreferredSizeChanged();
249 ////////////////////////////////////////////////////////////////////////////////
250 // ToggleImageButton, View overrides:
252 bool ToggleImageButton::GetTooltipText(const gfx::Point
& p
,
253 base::string16
* tooltip
) const {
254 if (!toggled_
|| toggled_tooltip_text_
.empty())
255 return Button::GetTooltipText(p
, tooltip
);
257 *tooltip
= toggled_tooltip_text_
;
261 void ToggleImageButton::GetAccessibleState(ui::AXViewState
* state
) {
262 ImageButton::GetAccessibleState(state
);
263 GetTooltipText(gfx::Point(), &state
->name
);