| OLD | NEW |
| (Empty) |
| 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 // Default button size if no image is set. This is ignored if there is an image, | |
| 19 // and exists for historical reasons (any number of clients could depend on this | |
| 20 // behaviour). | |
| 21 static const int kDefaultWidth = 16; | |
| 22 static const int kDefaultHeight = 14; | |
| 23 | |
| 24 const char ImageButton::kViewClassName[] = "ImageButton"; | |
| 25 | |
| 26 //////////////////////////////////////////////////////////////////////////////// | |
| 27 // ImageButton, public: | |
| 28 | |
| 29 ImageButton::ImageButton(ButtonListener* listener) | |
| 30 : CustomButton(listener), | |
| 31 h_alignment_(ALIGN_LEFT), | |
| 32 v_alignment_(ALIGN_TOP), | |
| 33 draw_image_mirrored_(false), | |
| 34 focus_painter_(Painter::CreateDashedFocusPainter()) { | |
| 35 // By default, we request that the gfx::Canvas passed to our View::OnPaint() | |
| 36 // implementation is flipped horizontally so that the button's images are | |
| 37 // mirrored when the UI directionality is right-to-left. | |
| 38 EnableCanvasFlippingForRTLUI(true); | |
| 39 } | |
| 40 | |
| 41 ImageButton::~ImageButton() { | |
| 42 } | |
| 43 | |
| 44 const gfx::ImageSkia& ImageButton::GetImage(ButtonState state) const { | |
| 45 return images_[state]; | |
| 46 } | |
| 47 | |
| 48 void ImageButton::SetImage(ButtonState state, const gfx::ImageSkia* image) { | |
| 49 images_[state] = image ? *image : gfx::ImageSkia(); | |
| 50 PreferredSizeChanged(); | |
| 51 } | |
| 52 | |
| 53 void ImageButton::SetBackground(SkColor color, | |
| 54 const gfx::ImageSkia* image, | |
| 55 const gfx::ImageSkia* mask) { | |
| 56 if (image == NULL || mask == NULL) { | |
| 57 background_image_ = gfx::ImageSkia(); | |
| 58 return; | |
| 59 } | |
| 60 | |
| 61 background_image_ = gfx::ImageSkiaOperations::CreateButtonBackground(color, | |
| 62 *image, *mask); | |
| 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 void ImageButton::SetFocusPainter(scoped_ptr<Painter> focus_painter) { | |
| 73 focus_painter_ = focus_painter.Pass(); | |
| 74 } | |
| 75 | |
| 76 void ImageButton::SetMinimumImageSize(const gfx::Size& size) { | |
| 77 if (minimum_image_size_ == size) | |
| 78 return; | |
| 79 | |
| 80 minimum_image_size_ = size; | |
| 81 PreferredSizeChanged(); | |
| 82 } | |
| 83 | |
| 84 //////////////////////////////////////////////////////////////////////////////// | |
| 85 // ImageButton, View overrides: | |
| 86 | |
| 87 gfx::Size ImageButton::GetPreferredSize() const { | |
| 88 gfx::Size size(kDefaultWidth, kDefaultHeight); | |
| 89 if (!images_[STATE_NORMAL].isNull()) { | |
| 90 size = gfx::Size(images_[STATE_NORMAL].width(), | |
| 91 images_[STATE_NORMAL].height()); | |
| 92 } | |
| 93 | |
| 94 size.SetToMax(minimum_image_size_); | |
| 95 | |
| 96 gfx::Insets insets = GetInsets(); | |
| 97 size.Enlarge(insets.width(), insets.height()); | |
| 98 return size; | |
| 99 } | |
| 100 | |
| 101 const char* ImageButton::GetClassName() const { | |
| 102 return kViewClassName; | |
| 103 } | |
| 104 | |
| 105 void ImageButton::OnPaint(gfx::Canvas* canvas) { | |
| 106 // Call the base class first to paint any background/borders. | |
| 107 View::OnPaint(canvas); | |
| 108 | |
| 109 gfx::ImageSkia img = GetImageToPaint(); | |
| 110 | |
| 111 if (!img.isNull()) { | |
| 112 gfx::ScopedCanvas scoped(canvas); | |
| 113 if (draw_image_mirrored_) { | |
| 114 canvas->Translate(gfx::Vector2d(width(), 0)); | |
| 115 canvas->Scale(-1, 1); | |
| 116 } | |
| 117 | |
| 118 gfx::Point position = ComputeImagePaintPosition(img); | |
| 119 if (!background_image_.isNull()) | |
| 120 canvas->DrawImageInt(background_image_, position.x(), position.y()); | |
| 121 | |
| 122 canvas->DrawImageInt(img, position.x(), position.y()); | |
| 123 } | |
| 124 | |
| 125 Painter::PaintFocusPainter(this, canvas, focus_painter()); | |
| 126 } | |
| 127 | |
| 128 //////////////////////////////////////////////////////////////////////////////// | |
| 129 // ImageButton, protected: | |
| 130 | |
| 131 void ImageButton::OnFocus() { | |
| 132 View::OnFocus(); | |
| 133 if (focus_painter_.get()) | |
| 134 SchedulePaint(); | |
| 135 } | |
| 136 | |
| 137 void ImageButton::OnBlur() { | |
| 138 View::OnBlur(); | |
| 139 if (focus_painter_.get()) | |
| 140 SchedulePaint(); | |
| 141 } | |
| 142 | |
| 143 gfx::ImageSkia ImageButton::GetImageToPaint() { | |
| 144 gfx::ImageSkia img; | |
| 145 | |
| 146 if (!images_[STATE_HOVERED].isNull() && hover_animation_->is_animating()) { | |
| 147 img = gfx::ImageSkiaOperations::CreateBlendedImage(images_[STATE_NORMAL], | |
| 148 images_[STATE_HOVERED], hover_animation_->GetCurrentValue()); | |
| 149 } else { | |
| 150 img = images_[state_]; | |
| 151 } | |
| 152 | |
| 153 return !img.isNull() ? img : images_[STATE_NORMAL]; | |
| 154 } | |
| 155 | |
| 156 //////////////////////////////////////////////////////////////////////////////// | |
| 157 // ImageButton, private: | |
| 158 | |
| 159 gfx::Point ImageButton::ComputeImagePaintPosition(const gfx::ImageSkia& image) { | |
| 160 int x = 0, y = 0; | |
| 161 gfx::Rect rect = GetContentsBounds(); | |
| 162 | |
| 163 HorizontalAlignment h_alignment = h_alignment_; | |
| 164 if (draw_image_mirrored_) { | |
| 165 if (h_alignment == ALIGN_RIGHT) | |
| 166 h_alignment = ALIGN_LEFT; | |
| 167 else if (h_alignment == ALIGN_LEFT) | |
| 168 h_alignment = ALIGN_RIGHT; | |
| 169 } | |
| 170 | |
| 171 if (h_alignment == ALIGN_CENTER) | |
| 172 x = (rect.width() - image.width()) / 2; | |
| 173 else if (h_alignment == ALIGN_RIGHT) | |
| 174 x = rect.width() - image.width(); | |
| 175 | |
| 176 if (v_alignment_ == ALIGN_MIDDLE) | |
| 177 y = (rect.height() - image.height()) / 2; | |
| 178 else if (v_alignment_ == ALIGN_BOTTOM) | |
| 179 y = rect.height() - image.height(); | |
| 180 | |
| 181 x += rect.x(); | |
| 182 y += rect.y(); | |
| 183 | |
| 184 return gfx::Point(x, y); | |
| 185 } | |
| 186 | |
| 187 //////////////////////////////////////////////////////////////////////////////// | |
| 188 // ToggleImageButton, public: | |
| 189 | |
| 190 ToggleImageButton::ToggleImageButton(ButtonListener* listener) | |
| 191 : ImageButton(listener), | |
| 192 toggled_(false) { | |
| 193 } | |
| 194 | |
| 195 ToggleImageButton::~ToggleImageButton() { | |
| 196 } | |
| 197 | |
| 198 void ToggleImageButton::SetToggled(bool toggled) { | |
| 199 if (toggled == toggled_) | |
| 200 return; | |
| 201 | |
| 202 for (int i = 0; i < STATE_COUNT; ++i) { | |
| 203 gfx::ImageSkia temp = images_[i]; | |
| 204 images_[i] = alternate_images_[i]; | |
| 205 alternate_images_[i] = temp; | |
| 206 } | |
| 207 toggled_ = toggled; | |
| 208 SchedulePaint(); | |
| 209 | |
| 210 NotifyAccessibilityEvent(ui::AX_EVENT_VALUE_CHANGED, true); | |
| 211 } | |
| 212 | |
| 213 void ToggleImageButton::SetToggledImage(ButtonState state, | |
| 214 const gfx::ImageSkia* image) { | |
| 215 if (toggled_) { | |
| 216 images_[state] = image ? *image : gfx::ImageSkia(); | |
| 217 if (state_ == state) | |
| 218 SchedulePaint(); | |
| 219 } else { | |
| 220 alternate_images_[state] = image ? *image : gfx::ImageSkia(); | |
| 221 } | |
| 222 } | |
| 223 | |
| 224 void ToggleImageButton::SetToggledTooltipText(const base::string16& tooltip) { | |
| 225 toggled_tooltip_text_ = tooltip; | |
| 226 } | |
| 227 | |
| 228 //////////////////////////////////////////////////////////////////////////////// | |
| 229 // ToggleImageButton, ImageButton overrides: | |
| 230 | |
| 231 const gfx::ImageSkia& ToggleImageButton::GetImage(ButtonState state) const { | |
| 232 if (toggled_) | |
| 233 return alternate_images_[state]; | |
| 234 return images_[state]; | |
| 235 } | |
| 236 | |
| 237 void ToggleImageButton::SetImage(ButtonState state, | |
| 238 const gfx::ImageSkia* image) { | |
| 239 if (toggled_) { | |
| 240 alternate_images_[state] = image ? *image : gfx::ImageSkia(); | |
| 241 } else { | |
| 242 images_[state] = image ? *image : gfx::ImageSkia(); | |
| 243 if (state_ == state) | |
| 244 SchedulePaint(); | |
| 245 } | |
| 246 PreferredSizeChanged(); | |
| 247 } | |
| 248 | |
| 249 //////////////////////////////////////////////////////////////////////////////// | |
| 250 // ToggleImageButton, View overrides: | |
| 251 | |
| 252 bool ToggleImageButton::GetTooltipText(const gfx::Point& p, | |
| 253 base::string16* tooltip) const { | |
| 254 if (!toggled_ || toggled_tooltip_text_.empty()) | |
| 255 return Button::GetTooltipText(p, tooltip); | |
| 256 | |
| 257 *tooltip = toggled_tooltip_text_; | |
| 258 return true; | |
| 259 } | |
| 260 | |
| 261 void ToggleImageButton::GetAccessibleState(ui::AXViewState* state) { | |
| 262 ImageButton::GetAccessibleState(state); | |
| 263 GetTooltipText(gfx::Point(), &state->name); | |
| 264 } | |
| 265 | |
| 266 } // namespace views | |
| OLD | NEW |