• 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/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"
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 
SetImageAlignment(HorizontalAlignment h_align,VerticalAlignment v_align)63 void ImageButton::SetImageAlignment(HorizontalAlignment h_align,
64                                     VerticalAlignment v_align) {
65   h_alignment_ = h_align;
66   v_alignment_ = v_align;
67   SchedulePaint();
68 }
69 
SetFocusPainter(scoped_ptr<Painter> focus_painter)70 void ImageButton::SetFocusPainter(scoped_ptr<Painter> focus_painter) {
71   focus_painter_ = focus_painter.Pass();
72 }
73 
74 ////////////////////////////////////////////////////////////////////////////////
75 // ImageButton, View overrides:
76 
GetPreferredSize() const77 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());
82   }
83 
84   gfx::Insets insets = GetInsets();
85   size.Enlarge(insets.width(), insets.height());
86   return size;
87 }
88 
GetClassName() const89 const char* ImageButton::GetClassName() const {
90   return kViewClassName;
91 }
92 
OnPaint(gfx::Canvas * canvas)93 void ImageButton::OnPaint(gfx::Canvas* canvas) {
94   // Call the base class first to paint any background/borders.
95   View::OnPaint(canvas);
96 
97   gfx::ImageSkia img = GetImageToPaint();
98 
99   if (!img.isNull()) {
100     gfx::ScopedCanvas scoped(canvas);
101     if (draw_image_mirrored_) {
102       canvas->Translate(gfx::Vector2d(width(), 0));
103       canvas->Scale(-1, 1);
104     }
105 
106     gfx::Point position = ComputeImagePaintPosition(img);
107     if (!background_image_.isNull())
108       canvas->DrawImageInt(background_image_, position.x(), position.y());
109 
110     canvas->DrawImageInt(img, position.x(), position.y());
111   }
112 
113   Painter::PaintFocusPainter(this, canvas, focus_painter());
114 }
115 
116 ////////////////////////////////////////////////////////////////////////////////
117 // ImageButton, protected:
118 
OnFocus()119 void ImageButton::OnFocus() {
120   View::OnFocus();
121   if (focus_painter_.get())
122     SchedulePaint();
123 }
124 
OnBlur()125 void ImageButton::OnBlur() {
126   View::OnBlur();
127   if (focus_painter_.get())
128     SchedulePaint();
129 }
130 
GetImageToPaint()131 gfx::ImageSkia ImageButton::GetImageToPaint() {
132   gfx::ImageSkia img;
133 
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());
137   } else {
138     img = images_[state_];
139   }
140 
141   return !img.isNull() ? img : images_[STATE_NORMAL];
142 }
143 
144 ////////////////////////////////////////////////////////////////////////////////
145 // ImageButton, private:
146 
ComputeImagePaintPosition(const gfx::ImageSkia & image)147 gfx::Point ImageButton::ComputeImagePaintPosition(const gfx::ImageSkia& image) {
148   int x = 0, y = 0;
149   gfx::Rect rect = GetContentsBounds();
150 
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;
157   }
158 
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();
163 
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();
168 
169   x += rect.x();
170   y += rect.y();
171 
172   return gfx::Point(x, y);
173 }
174 
175 ////////////////////////////////////////////////////////////////////////////////
176 // ToggleImageButton, public:
177 
ToggleImageButton(ButtonListener * listener)178 ToggleImageButton::ToggleImageButton(ButtonListener* listener)
179     : ImageButton(listener),
180       toggled_(false) {
181 }
182 
~ToggleImageButton()183 ToggleImageButton::~ToggleImageButton() {
184 }
185 
SetToggled(bool toggled)186 void ToggleImageButton::SetToggled(bool toggled) {
187   if (toggled == toggled_)
188     return;
189 
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;
194   }
195   toggled_ = toggled;
196   SchedulePaint();
197 
198   NotifyAccessibilityEvent(ui::AX_EVENT_VALUE_CHANGED, true);
199 }
200 
SetToggledImage(ButtonState state,const gfx::ImageSkia * image)201 void ToggleImageButton::SetToggledImage(ButtonState state,
202                                         const gfx::ImageSkia* image) {
203   if (toggled_) {
204     images_[state] = image ? *image : gfx::ImageSkia();
205     if (state_ == state)
206       SchedulePaint();
207   } else {
208     alternate_images_[state] = image ? *image : gfx::ImageSkia();
209   }
210 }
211 
SetToggledTooltipText(const base::string16 & tooltip)212 void ToggleImageButton::SetToggledTooltipText(const base::string16& tooltip) {
213   toggled_tooltip_text_ = tooltip;
214 }
215 
216 ////////////////////////////////////////////////////////////////////////////////
217 // ToggleImageButton, ImageButton overrides:
218 
GetImage(ButtonState state) const219 const gfx::ImageSkia& ToggleImageButton::GetImage(ButtonState state) const {
220   if (toggled_)
221     return alternate_images_[state];
222   return images_[state];
223 }
224 
SetImage(ButtonState state,const gfx::ImageSkia * image)225 void ToggleImageButton::SetImage(ButtonState state,
226                                  const gfx::ImageSkia* image) {
227   if (toggled_) {
228     alternate_images_[state] = image ? *image : gfx::ImageSkia();
229   } else {
230     images_[state] = image ? *image : gfx::ImageSkia();
231     if (state_ == state)
232       SchedulePaint();
233   }
234   PreferredSizeChanged();
235 }
236 
237 ////////////////////////////////////////////////////////////////////////////////
238 // ToggleImageButton, View overrides:
239 
GetTooltipText(const gfx::Point & p,base::string16 * tooltip) const240 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);
244 
245   *tooltip = toggled_tooltip_text_;
246   return true;
247 }
248 
GetAccessibleState(ui::AXViewState * state)249 void ToggleImageButton::GetAccessibleState(ui::AXViewState* state) {
250   ImageButton::GetAccessibleState(state);
251   GetTooltipText(gfx::Point(), &state->name);
252 }
253 
254 }  // namespace views
255