Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ui / views / controls / button / image_button.cc
blob1079d5e209b3effa2f44cad0eab34d03e717b6c6
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"
16 namespace views {
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
20 // behaviour).
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();
58 return;
61 background_image_ = gfx::ImageSkiaOperations::CreateButtonBackground(color,
62 *image, *mask);
65 void ImageButton::SetImageAlignment(HorizontalAlignment h_align,
66 VerticalAlignment v_align) {
67 h_alignment_ = h_align;
68 v_alignment_ = v_align;
69 SchedulePaint();
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)
78 return;
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());
98 return size;
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();
111 if (!img.isNull()) {
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() {
132 View::OnFocus();
133 if (focus_painter_.get())
134 SchedulePaint();
137 void ImageButton::OnBlur() {
138 View::OnBlur();
139 if (focus_painter_.get())
140 SchedulePaint();
143 gfx::ImageSkia ImageButton::GetImageToPaint() {
144 gfx::ImageSkia img;
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());
149 } else {
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) {
160 int x = 0, y = 0;
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();
181 x += rect.x();
182 y += rect.y();
184 return gfx::Point(x, y);
187 ////////////////////////////////////////////////////////////////////////////////
188 // ToggleImageButton, public:
190 ToggleImageButton::ToggleImageButton(ButtonListener* listener)
191 : ImageButton(listener),
192 toggled_(false) {
195 ToggleImageButton::~ToggleImageButton() {
198 void ToggleImageButton::SetToggled(bool toggled) {
199 if (toggled == toggled_)
200 return;
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;
207 toggled_ = toggled;
208 SchedulePaint();
210 NotifyAccessibilityEvent(ui::AX_EVENT_VALUE_CHANGED, true);
213 void ToggleImageButton::SetToggledImage(ButtonState state,
214 const gfx::ImageSkia* image) {
215 if (toggled_) {
216 images_[state] = image ? *image : gfx::ImageSkia();
217 if (state_ == state)
218 SchedulePaint();
219 } else {
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 {
232 if (toggled_)
233 return alternate_images_[state];
234 return images_[state];
237 void ToggleImageButton::SetImage(ButtonState state,
238 const gfx::ImageSkia* image) {
239 if (toggled_) {
240 alternate_images_[state] = image ? *image : gfx::ImageSkia();
241 } else {
242 images_[state] = image ? *image : gfx::ImageSkia();
243 if (state_ == state)
244 SchedulePaint();
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_;
258 return true;
261 void ToggleImageButton::GetAccessibleState(ui::AXViewState* state) {
262 ImageButton::GetAccessibleState(state);
263 GetTooltipText(gfx::Point(), &state->name);
266 } // namespace views