• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/strings/utf_string_conversions.h"
8 #include "ui/base/accessibility/accessible_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"
15 
16 namespace views {
17 
18 static const int kDefaultWidth = 16;   // Default button width if no theme.
19 static const int kDefaultHeight = 14;  // Default button height if no theme.
20 
21 const char ImageButton::kViewClassName[] = "ImageButton";
22 
23 ////////////////////////////////////////////////////////////////////////////////
24 // ImageButton, public:
25 
ImageButton(ButtonListener * listener)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);
37 }
38 
~ImageButton()39 ImageButton::~ImageButton() {
40 }
41 
GetImage(ButtonState state) const42 const gfx::ImageSkia& ImageButton::GetImage(ButtonState state) const {
43   return images_[state];
44 }
45 
SetImage(ButtonState state,const gfx::ImageSkia * image)46 void ImageButton::SetImage(ButtonState state, const gfx::ImageSkia* image) {
47   images_[state] = image ? *image : gfx::ImageSkia();
48   PreferredSizeChanged();
49 }
50 
SetBackground(SkColor color,const gfx::ImageSkia * image,const gfx::ImageSkia * mask)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();
56     return;
57   }
58 
59   background_image_ = gfx::ImageSkiaOperations::CreateButtonBackground(color,
60      *image, *mask);
61 }
62 
SetOverlayImage(const gfx::ImageSkia * image)63 void ImageButton::SetOverlayImage(const gfx::ImageSkia* image) {
64   if (!image) {
65     overlay_image_ = gfx::ImageSkia();
66     return;
67   }
68   overlay_image_ = *image;
69 }
70 
SetImageAlignment(HorizontalAlignment h_align,VerticalAlignment v_align)71 void ImageButton::SetImageAlignment(HorizontalAlignment h_align,
72                                     VerticalAlignment v_align) {
73   h_alignment_ = h_align;
74   v_alignment_ = v_align;
75   SchedulePaint();
76 }
77 
SetFocusPainter(scoped_ptr<Painter> focus_painter)78 void ImageButton::SetFocusPainter(scoped_ptr<Painter> focus_painter) {
79   focus_painter_ = focus_painter.Pass();
80 }
81 
82 ////////////////////////////////////////////////////////////////////////////////
83 // ImageButton, View overrides:
84 
GetPreferredSize()85 gfx::Size ImageButton::GetPreferredSize() {
86   gfx::Size size = preferred_size_;
87   if (!images_[STATE_NORMAL].isNull()) {
88     size = gfx::Size(images_[STATE_NORMAL].width(),
89                      images_[STATE_NORMAL].height());
90   }
91 
92   gfx::Insets insets = GetInsets();
93   size.Enlarge(insets.width(), insets.height());
94   return size;
95 }
96 
GetClassName() const97 const char* ImageButton::GetClassName() const {
98   return kViewClassName;
99 }
100 
OnPaint(gfx::Canvas * canvas)101 void ImageButton::OnPaint(gfx::Canvas* canvas) {
102   // Call the base class first to paint any background/borders.
103   View::OnPaint(canvas);
104 
105   gfx::ImageSkia img = GetImageToPaint();
106 
107   if (!img.isNull()) {
108     gfx::ScopedCanvas scoped(canvas);
109     if (draw_image_mirrored_) {
110       canvas->Translate(gfx::Vector2d(width(), 0));
111       canvas->Scale(-1, 1);
112     }
113 
114     gfx::Point position = ComputeImagePaintPosition(img);
115     if (!background_image_.isNull())
116       canvas->DrawImageInt(background_image_, position.x(), position.y());
117 
118     canvas->DrawImageInt(img, position.x(), position.y());
119 
120     if (!overlay_image_.isNull())
121       canvas->DrawImageInt(overlay_image_, position.x(), position.y());
122   }
123 
124   Painter::PaintFocusPainter(this, canvas, focus_painter());
125 }
126 
127 ////////////////////////////////////////////////////////////////////////////////
128 // ImageButton, protected:
129 
OnFocus()130 void ImageButton::OnFocus() {
131   View::OnFocus();
132   if (focus_painter_.get())
133     SchedulePaint();
134 }
135 
OnBlur()136 void ImageButton::OnBlur() {
137   View::OnBlur();
138   if (focus_painter_.get())
139     SchedulePaint();
140 }
141 
GetImageToPaint()142 gfx::ImageSkia ImageButton::GetImageToPaint() {
143   gfx::ImageSkia img;
144 
145   if (!images_[STATE_HOVERED].isNull() && hover_animation_->is_animating()) {
146     img = gfx::ImageSkiaOperations::CreateBlendedImage(images_[STATE_NORMAL],
147         images_[STATE_HOVERED], hover_animation_->GetCurrentValue());
148   } else {
149     img = images_[state_];
150   }
151 
152   return !img.isNull() ? img : images_[STATE_NORMAL];
153 }
154 
155 ////////////////////////////////////////////////////////////////////////////////
156 // ImageButton, private:
157 
ComputeImagePaintPosition(const gfx::ImageSkia & image)158 gfx::Point ImageButton::ComputeImagePaintPosition(const gfx::ImageSkia& image) {
159   int x = 0, y = 0;
160   gfx::Rect rect = GetContentsBounds();
161 
162   HorizontalAlignment h_alignment = h_alignment_;
163   if (draw_image_mirrored_) {
164     if (h_alignment == ALIGN_RIGHT)
165       h_alignment = ALIGN_LEFT;
166     else if (h_alignment == ALIGN_LEFT)
167       h_alignment = ALIGN_RIGHT;
168   }
169 
170   if (h_alignment == ALIGN_CENTER)
171     x = (rect.width() - image.width()) / 2;
172   else if (h_alignment == ALIGN_RIGHT)
173     x = rect.width() - image.width();
174 
175   if (v_alignment_ == ALIGN_MIDDLE)
176     y = (rect.height() - image.height()) / 2;
177   else if (v_alignment_ == ALIGN_BOTTOM)
178     y = rect.height() - image.height();
179 
180   x += rect.x();
181   y += rect.y();
182 
183   return gfx::Point(x, y);
184 }
185 
186 ////////////////////////////////////////////////////////////////////////////////
187 // ToggleImageButton, public:
188 
ToggleImageButton(ButtonListener * listener)189 ToggleImageButton::ToggleImageButton(ButtonListener* listener)
190     : ImageButton(listener),
191       toggled_(false) {
192 }
193 
~ToggleImageButton()194 ToggleImageButton::~ToggleImageButton() {
195 }
196 
SetToggled(bool toggled)197 void ToggleImageButton::SetToggled(bool toggled) {
198   if (toggled == toggled_)
199     return;
200 
201   for (int i = 0; i < STATE_COUNT; ++i) {
202     gfx::ImageSkia temp = images_[i];
203     images_[i] = alternate_images_[i];
204     alternate_images_[i] = temp;
205   }
206   toggled_ = toggled;
207   SchedulePaint();
208 
209   NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_VALUE_CHANGED, true);
210 }
211 
SetToggledImage(ButtonState state,const gfx::ImageSkia * image)212 void ToggleImageButton::SetToggledImage(ButtonState state,
213                                         const gfx::ImageSkia* image) {
214   if (toggled_) {
215     images_[state] = image ? *image : gfx::ImageSkia();
216     if (state_ == state)
217       SchedulePaint();
218   } else {
219     alternate_images_[state] = image ? *image : gfx::ImageSkia();
220   }
221 }
222 
SetToggledTooltipText(const string16 & tooltip)223 void ToggleImageButton::SetToggledTooltipText(const string16& tooltip) {
224   toggled_tooltip_text_ = tooltip;
225 }
226 
227 ////////////////////////////////////////////////////////////////////////////////
228 // ToggleImageButton, ImageButton overrides:
229 
GetImage(ButtonState state) const230 const gfx::ImageSkia& ToggleImageButton::GetImage(ButtonState state) const {
231   if (toggled_)
232     return alternate_images_[state];
233   return images_[state];
234 }
235 
SetImage(ButtonState state,const gfx::ImageSkia * image)236 void ToggleImageButton::SetImage(ButtonState state,
237                                  const gfx::ImageSkia* image) {
238   if (toggled_) {
239     alternate_images_[state] = image ? *image : gfx::ImageSkia();
240   } else {
241     images_[state] = image ? *image : gfx::ImageSkia();
242     if (state_ == state)
243       SchedulePaint();
244   }
245   PreferredSizeChanged();
246 }
247 
248 ////////////////////////////////////////////////////////////////////////////////
249 // ToggleImageButton, View overrides:
250 
GetTooltipText(const gfx::Point & p,string16 * tooltip) const251 bool ToggleImageButton::GetTooltipText(const gfx::Point& p,
252                                        string16* tooltip) const {
253   if (!toggled_ || toggled_tooltip_text_.empty())
254     return Button::GetTooltipText(p, tooltip);
255 
256   *tooltip = toggled_tooltip_text_;
257   return true;
258 }
259 
GetAccessibleState(ui::AccessibleViewState * state)260 void ToggleImageButton::GetAccessibleState(ui::AccessibleViewState* state) {
261   ImageButton::GetAccessibleState(state);
262   GetTooltipText(gfx::Point(), &state->name);
263 }
264 
265 }  // namespace views
266