image_button.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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.
4
5#include "ui/views/controls/button/image_button.h"
6
7#include "base/utf_string_conversions.h"
8#include "ui/base/animation/throb_animation.h"
9#include "ui/gfx/canvas.h"
10#include "ui/gfx/image/image_skia_operations.h"
11#include "ui/views/widget/widget.h"
12
13namespace views {
14
15static const int kDefaultWidth = 16;   // Default button width if no theme.
16static const int kDefaultHeight = 14;  // Default button height if no theme.
17
18////////////////////////////////////////////////////////////////////////////////
19// ImageButton, public:
20
21ImageButton::ImageButton(ButtonListener* listener)
22    : CustomButton(listener),
23      h_alignment_(ALIGN_LEFT),
24      v_alignment_(ALIGN_TOP),
25      preferred_size_(kDefaultWidth, kDefaultHeight) {
26  // By default, we request that the gfx::Canvas passed to our View::OnPaint()
27  // implementation is flipped horizontally so that the button's images are
28  // mirrored when the UI directionality is right-to-left.
29  EnableCanvasFlippingForRTLUI(true);
30}
31
32ImageButton::~ImageButton() {
33}
34
35void ImageButton::SetImage(ButtonState state, const gfx::ImageSkia* image) {
36  images_[state] = image ? *image : gfx::ImageSkia();
37  PreferredSizeChanged();
38}
39
40void ImageButton::SetBackground(SkColor color,
41                                const gfx::ImageSkia* image,
42                                const gfx::ImageSkia* mask) {
43  if (image == NULL || mask == NULL) {
44    background_image_ = gfx::ImageSkia();
45    return;
46  }
47
48  background_image_ = gfx::ImageSkiaOperations::CreateButtonBackground(color,
49     *image, *mask);
50}
51
52void ImageButton::SetOverlayImage(const gfx::ImageSkia* image) {
53  if (!image) {
54    overlay_image_ = gfx::ImageSkia();
55    return;
56  }
57  overlay_image_ = *image;
58}
59
60void ImageButton::SetImageAlignment(HorizontalAlignment h_align,
61                                    VerticalAlignment v_align) {
62  h_alignment_ = h_align;
63  v_alignment_ = v_align;
64  SchedulePaint();
65}
66
67////////////////////////////////////////////////////////////////////////////////
68// ImageButton, View overrides:
69
70gfx::Size ImageButton::GetPreferredSize() {
71  if (!images_[BS_NORMAL].isNull())
72    return gfx::Size(images_[BS_NORMAL].width(), images_[BS_NORMAL].height());
73  return preferred_size_;
74}
75
76void ImageButton::OnPaint(gfx::Canvas* canvas) {
77  // Call the base class first to paint any background/borders.
78  View::OnPaint(canvas);
79
80  gfx::ImageSkia img = GetImageToPaint();
81
82  if (!img.isNull()) {
83    gfx::Point position = ComputeImagePaintPosition(img);
84    if (!background_image_.isNull())
85      canvas->DrawImageInt(background_image_, position.x(), position.y());
86
87    canvas->DrawImageInt(img, position.x(), position.y());
88
89    if (!overlay_image_.isNull())
90      canvas->DrawImageInt(overlay_image_, position.x(), position.y());
91  }
92  OnPaintFocusBorder(canvas);
93}
94
95////////////////////////////////////////////////////////////////////////////////
96// ImageButton, protected:
97
98gfx::ImageSkia ImageButton::GetImageToPaint() {
99  gfx::ImageSkia img;
100
101  if (!images_[BS_HOT].isNull() && hover_animation_->is_animating()) {
102    img = gfx::ImageSkiaOperations::CreateBlendedImage(images_[BS_NORMAL],
103        images_[BS_HOT], hover_animation_->GetCurrentValue());
104  } else {
105    img = images_[state_];
106  }
107
108  return !img.isNull() ? img : images_[BS_NORMAL];
109}
110
111////////////////////////////////////////////////////////////////////////////////
112// ImageButton, private:
113
114gfx::Point ImageButton::ComputeImagePaintPosition(const gfx::ImageSkia& image) {
115  int x = 0, y = 0;
116  gfx::Rect rect = GetContentsBounds();
117
118  if (h_alignment_ == ALIGN_CENTER)
119    x = (rect.width() - image.width()) / 2;
120  else if (h_alignment_ == ALIGN_RIGHT)
121    x = rect.width() - image.width();
122
123  if (v_alignment_ == ALIGN_MIDDLE)
124    y = (rect.height() - image.height()) / 2;
125  else if (v_alignment_ == ALIGN_BOTTOM)
126    y = rect.height() - image.height();
127
128  x += rect.x();
129  y += rect.y();
130
131  return gfx::Point(x, y);
132}
133
134////////////////////////////////////////////////////////////////////////////////
135// ToggleImageButton, public:
136
137ToggleImageButton::ToggleImageButton(ButtonListener* listener)
138    : ImageButton(listener),
139      toggled_(false) {
140}
141
142ToggleImageButton::~ToggleImageButton() {
143}
144
145void ToggleImageButton::SetToggled(bool toggled) {
146  if (toggled == toggled_)
147    return;
148
149  for (int i = 0; i < BS_COUNT; ++i) {
150    gfx::ImageSkia temp = images_[i];
151    images_[i] = alternate_images_[i];
152    alternate_images_[i] = temp;
153  }
154  toggled_ = toggled;
155  SchedulePaint();
156}
157
158void ToggleImageButton::SetToggledImage(ButtonState state,
159                                        const gfx::ImageSkia* image) {
160  if (toggled_) {
161    images_[state] = image ? *image : gfx::ImageSkia();
162    if (state_ == state)
163      SchedulePaint();
164  } else {
165    alternate_images_[state] = image ? *image : gfx::ImageSkia();
166  }
167}
168
169void ToggleImageButton::SetToggledTooltipText(const string16& tooltip) {
170  toggled_tooltip_text_ = tooltip;
171}
172
173////////////////////////////////////////////////////////////////////////////////
174// ToggleImageButton, ImageButton overrides:
175
176void ToggleImageButton::SetImage(ButtonState state,
177                                 const gfx::ImageSkia* image) {
178  if (toggled_) {
179    alternate_images_[state] = image ? *image : gfx::ImageSkia();
180  } else {
181    images_[state] = image ? *image : gfx::ImageSkia();
182    if (state_ == state)
183      SchedulePaint();
184  }
185  PreferredSizeChanged();
186}
187
188////////////////////////////////////////////////////////////////////////////////
189// ToggleImageButton, View overrides:
190
191bool ToggleImageButton::GetTooltipText(const gfx::Point& p,
192                                       string16* tooltip) const {
193  if (!toggled_ || toggled_tooltip_text_.empty())
194    return Button::GetTooltipText(p, tooltip);
195
196  *tooltip = toggled_tooltip_text_;
197  return true;
198}
199
200}  // namespace views
201