Home | History | Annotate | Download | only in button
      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 
     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 
     39 ImageButton::~ImageButton() {
     40 }
     41 
     42 const gfx::ImageSkia& ImageButton::GetImage(ButtonState state) const {
     43   return images_[state];
     44 }
     45 
     46 void ImageButton::SetImage(ButtonState state, const gfx::ImageSkia* image) {
     47   images_[state] = image ? *image : gfx::ImageSkia();
     48   PreferredSizeChanged();
     49 }
     50 
     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 
     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 
     70 void ImageButton::SetFocusPainter(scoped_ptr<Painter> focus_painter) {
     71   focus_painter_ = focus_painter.Pass();
     72 }
     73 
     74 ////////////////////////////////////////////////////////////////////////////////
     75 // ImageButton, View overrides:
     76 
     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());
     82   }
     83 
     84   gfx::Insets insets = GetInsets();
     85   size.Enlarge(insets.width(), insets.height());
     86   return size;
     87 }
     88 
     89 const char* ImageButton::GetClassName() const {
     90   return kViewClassName;
     91 }
     92 
     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 
    119 void ImageButton::OnFocus() {
    120   View::OnFocus();
    121   if (focus_painter_.get())
    122     SchedulePaint();
    123 }
    124 
    125 void ImageButton::OnBlur() {
    126   View::OnBlur();
    127   if (focus_painter_.get())
    128     SchedulePaint();
    129 }
    130 
    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 
    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 
    178 ToggleImageButton::ToggleImageButton(ButtonListener* listener)
    179     : ImageButton(listener),
    180       toggled_(false) {
    181 }
    182 
    183 ToggleImageButton::~ToggleImageButton() {
    184 }
    185 
    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 
    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 
    212 void ToggleImageButton::SetToggledTooltipText(const base::string16& tooltip) {
    213   toggled_tooltip_text_ = tooltip;
    214 }
    215 
    216 ////////////////////////////////////////////////////////////////////////////////
    217 // ToggleImageButton, ImageButton overrides:
    218 
    219 const gfx::ImageSkia& ToggleImageButton::GetImage(ButtonState state) const {
    220   if (toggled_)
    221     return alternate_images_[state];
    222   return images_[state];
    223 }
    224 
    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 
    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);
    244 
    245   *tooltip = toggled_tooltip_text_;
    246   return true;
    247 }
    248 
    249 void ToggleImageButton::GetAccessibleState(ui::AXViewState* state) {
    250   ImageButton::GetAccessibleState(state);
    251   GetTooltipText(gfx::Point(), &state->name);
    252 }
    253 
    254 }  // namespace views
    255