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