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