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 static const int kDefaultWidth
= 16; // Default button width if no theme.
19 static const int kDefaultHeight
= 14; // Default button height if no theme.
21 const char ImageButton::kViewClassName
[] = "ImageButton";
23 ////////////////////////////////////////////////////////////////////////////////
24 // ImageButton, public:
26 ImageButton::ImageButton(ButtonListener
* listener
)
27 : CustomButton(listener
),
28 h_alignment_(ALIGN_LEFT
),
29 v_alignment_(ALIGN_TOP
),
30 preferred_size_(kDefaultWidth
, kDefaultHeight
),
31 draw_image_mirrored_(false),
32 focus_painter_(Painter::CreateDashedFocusPainter()) {
33 // By default, we request that the gfx::Canvas passed to our View::OnPaint()
34 // implementation is flipped horizontally so that the button's images are
35 // mirrored when the UI directionality is right-to-left.
36 EnableCanvasFlippingForRTLUI(true);
39 ImageButton::~ImageButton() {
42 const gfx::ImageSkia
& ImageButton::GetImage(ButtonState state
) const {
43 return images_
[state
];
46 void ImageButton::SetImage(ButtonState state
, const gfx::ImageSkia
* image
) {
47 images_
[state
] = image
? *image
: gfx::ImageSkia();
48 PreferredSizeChanged();
51 void ImageButton::SetBackground(SkColor color
,
52 const gfx::ImageSkia
* image
,
53 const gfx::ImageSkia
* mask
) {
54 if (image
== NULL
|| mask
== NULL
) {
55 background_image_
= gfx::ImageSkia();
59 background_image_
= gfx::ImageSkiaOperations::CreateButtonBackground(color
,
63 void ImageButton::SetImageAlignment(HorizontalAlignment h_align
,
64 VerticalAlignment v_align
) {
65 h_alignment_
= h_align
;
66 v_alignment_
= v_align
;
70 void ImageButton::SetFocusPainter(scoped_ptr
<Painter
> focus_painter
) {
71 focus_painter_
= focus_painter
.Pass();
74 ////////////////////////////////////////////////////////////////////////////////
75 // ImageButton, View overrides:
77 gfx::Size
ImageButton::GetPreferredSize() const {
78 gfx::Size size
= preferred_size_
;
79 if (!images_
[STATE_NORMAL
].isNull()) {
80 size
= gfx::Size(images_
[STATE_NORMAL
].width(),
81 images_
[STATE_NORMAL
].height());
84 gfx::Insets insets
= GetInsets();
85 size
.Enlarge(insets
.width(), insets
.height());
89 const char* ImageButton::GetClassName() const {
90 return kViewClassName
;
93 void ImageButton::OnPaint(gfx::Canvas
* canvas
) {
94 // Call the base class first to paint any background/borders.
95 View::OnPaint(canvas
);
97 gfx::ImageSkia img
= GetImageToPaint();
100 gfx::ScopedCanvas
scoped(canvas
);
101 if (draw_image_mirrored_
) {
102 canvas
->Translate(gfx::Vector2d(width(), 0));
103 canvas
->Scale(-1, 1);
106 gfx::Point position
= ComputeImagePaintPosition(img
);
107 if (!background_image_
.isNull())
108 canvas
->DrawImageInt(background_image_
, position
.x(), position
.y());
110 canvas
->DrawImageInt(img
, position
.x(), position
.y());
113 Painter::PaintFocusPainter(this, canvas
, focus_painter());
116 ////////////////////////////////////////////////////////////////////////////////
117 // ImageButton, protected:
119 void ImageButton::OnFocus() {
121 if (focus_painter_
.get())
125 void ImageButton::OnBlur() {
127 if (focus_painter_
.get())
131 gfx::ImageSkia
ImageButton::GetImageToPaint() {
134 if (!images_
[STATE_HOVERED
].isNull() && hover_animation_
->is_animating()) {
135 img
= gfx::ImageSkiaOperations::CreateBlendedImage(images_
[STATE_NORMAL
],
136 images_
[STATE_HOVERED
], hover_animation_
->GetCurrentValue());
138 img
= images_
[state_
];
141 return !img
.isNull() ? img
: images_
[STATE_NORMAL
];
144 ////////////////////////////////////////////////////////////////////////////////
145 // ImageButton, private:
147 gfx::Point
ImageButton::ComputeImagePaintPosition(const gfx::ImageSkia
& image
) {
149 gfx::Rect rect
= GetContentsBounds();
151 HorizontalAlignment h_alignment
= h_alignment_
;
152 if (draw_image_mirrored_
) {
153 if (h_alignment
== ALIGN_RIGHT
)
154 h_alignment
= ALIGN_LEFT
;
155 else if (h_alignment
== ALIGN_LEFT
)
156 h_alignment
= ALIGN_RIGHT
;
159 if (h_alignment
== ALIGN_CENTER
)
160 x
= (rect
.width() - image
.width()) / 2;
161 else if (h_alignment
== ALIGN_RIGHT
)
162 x
= rect
.width() - image
.width();
164 if (v_alignment_
== ALIGN_MIDDLE
)
165 y
= (rect
.height() - image
.height()) / 2;
166 else if (v_alignment_
== ALIGN_BOTTOM
)
167 y
= rect
.height() - image
.height();
172 return gfx::Point(x
, y
);
175 ////////////////////////////////////////////////////////////////////////////////
176 // ToggleImageButton, public:
178 ToggleImageButton::ToggleImageButton(ButtonListener
* listener
)
179 : ImageButton(listener
),
183 ToggleImageButton::~ToggleImageButton() {
186 void ToggleImageButton::SetToggled(bool toggled
) {
187 if (toggled
== toggled_
)
190 for (int i
= 0; i
< STATE_COUNT
; ++i
) {
191 gfx::ImageSkia temp
= images_
[i
];
192 images_
[i
] = alternate_images_
[i
];
193 alternate_images_
[i
] = temp
;
198 NotifyAccessibilityEvent(ui::AX_EVENT_VALUE_CHANGED
, true);
201 void ToggleImageButton::SetToggledImage(ButtonState state
,
202 const gfx::ImageSkia
* image
) {
204 images_
[state
] = image
? *image
: gfx::ImageSkia();
208 alternate_images_
[state
] = image
? *image
: gfx::ImageSkia();
212 void ToggleImageButton::SetToggledTooltipText(const base::string16
& tooltip
) {
213 toggled_tooltip_text_
= tooltip
;
216 ////////////////////////////////////////////////////////////////////////////////
217 // ToggleImageButton, ImageButton overrides:
219 const gfx::ImageSkia
& ToggleImageButton::GetImage(ButtonState state
) const {
221 return alternate_images_
[state
];
222 return images_
[state
];
225 void ToggleImageButton::SetImage(ButtonState state
,
226 const gfx::ImageSkia
* image
) {
228 alternate_images_
[state
] = image
? *image
: gfx::ImageSkia();
230 images_
[state
] = image
? *image
: gfx::ImageSkia();
234 PreferredSizeChanged();
237 ////////////////////////////////////////////////////////////////////////////////
238 // ToggleImageButton, View overrides:
240 bool ToggleImageButton::GetTooltipText(const gfx::Point
& p
,
241 base::string16
* tooltip
) const {
242 if (!toggled_
|| toggled_tooltip_text_
.empty())
243 return Button::GetTooltipText(p
, tooltip
);
245 *tooltip
= toggled_tooltip_text_
;
249 void ToggleImageButton::GetAccessibleState(ui::AXViewState
* state
) {
250 ImageButton::GetAccessibleState(state
);
251 GetTooltipText(gfx::Point(), &state
->name
);