ui: Move RenderText tests into gfx_unittests target.
[chromium-blink-merge.git] / ui / views / controls / button / text_button.cc
blobbf12f8e086dc1d211abf88fa2d1383447d69908e
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.
5 #include "ui/views/controls/button/text_button.h"
7 #include <algorithm>
9 #include "base/logging.h"
10 #include "grit/ui_resources.h"
11 #include "ui/base/resource/resource_bundle.h"
12 #include "ui/gfx/animation/throb_animation.h"
13 #include "ui/gfx/canvas.h"
14 #include "ui/gfx/image/image.h"
15 #include "ui/views/controls/button/button.h"
16 #include "ui/views/painter.h"
17 #include "ui/views/widget/widget.h"
19 #if defined(OS_WIN)
20 #include "skia/ext/skia_utils_win.h"
21 #include "ui/gfx/platform_font_win.h"
22 #include "ui/native_theme/native_theme_win.h"
23 #endif
25 namespace views {
27 namespace {
29 // Default space between the icon and text.
30 const int kDefaultIconTextSpacing = 5;
32 // Preferred padding between text and edge.
33 const int kPreferredPaddingHorizontal = 6;
34 const int kPreferredPaddingVertical = 5;
36 // Preferred padding between text and edge for NativeTheme border.
37 const int kPreferredNativeThemePaddingHorizontal = 12;
38 const int kPreferredNativeThemePaddingVertical = 5;
40 // By default the focus rect is drawn at the border of the view. For a button,
41 // we inset the focus rect by 3 pixels so that it doesn't draw on top of the
42 // button's border. This roughly matches how the Windows native focus rect for
43 // buttons looks. A subclass that draws a button with different padding may need
44 // to provide a different focus painter and do something different.
45 const int kFocusRectInset = 3;
47 // How long the hover fade animation should last.
48 const int kHoverAnimationDurationMs = 170;
50 #if defined(OS_WIN)
51 // These sizes are from http://msdn.microsoft.com/en-us/library/aa511279.aspx
52 const int kMinWidthDLUs = 50;
53 const int kMinHeightDLUs = 14;
54 #endif
56 // The default hot and pushed button image IDs; normal has none by default.
57 const int kHotImages[] = IMAGE_GRID(IDR_TEXTBUTTON_HOVER);
58 const int kPushedImages[] = IMAGE_GRID(IDR_TEXTBUTTON_PRESSED);
60 } // namespace
62 // static
63 const char TextButtonBase::kViewClassName[] = "TextButtonBase";
64 // static
65 const char TextButton::kViewClassName[] = "TextButton";
68 // TextButtonBorder -----------------------------------------------------------
70 TextButtonBorder::TextButtonBorder() {
73 TextButtonBorder::~TextButtonBorder() {
76 void TextButtonBorder::Paint(const View& view, gfx::Canvas* canvas) {
79 gfx::Insets TextButtonBorder::GetInsets() const {
80 return insets_;
83 gfx::Size TextButtonBorder::GetMinimumSize() const {
84 return gfx::Size();
87 void TextButtonBorder::SetInsets(const gfx::Insets& insets) {
88 insets_ = insets;
92 // TextButtonDefaultBorder ----------------------------------------------------
94 TextButtonDefaultBorder::TextButtonDefaultBorder()
95 : vertical_padding_(kPreferredPaddingVertical) {
96 set_hot_painter(Painter::CreateImageGridPainter(kHotImages));
97 set_pushed_painter(Painter::CreateImageGridPainter(kPushedImages));
98 SetInsets(gfx::Insets(vertical_padding_, kPreferredPaddingHorizontal,
99 vertical_padding_, kPreferredPaddingHorizontal));
102 TextButtonDefaultBorder::~TextButtonDefaultBorder() {
105 void TextButtonDefaultBorder::Paint(const View& view, gfx::Canvas* canvas) {
106 const TextButton* button = static_cast<const TextButton*>(&view);
107 int state = button->state();
108 bool animating = button->GetAnimation()->is_animating();
110 Painter* painter = normal_painter_.get();
111 // Use the hot painter when we're hovered. Also use the hot painter when we're
112 // STATE_NORMAL and |animating| so that we show throb animations started from
113 // CustomButton::StartThrobbing which should start throbbing the button
114 // regardless of whether it is hovered.
115 if (button->show_multiple_icon_states() &&
116 ((state == TextButton::STATE_HOVERED) ||
117 (state == TextButton::STATE_PRESSED) ||
118 ((state == TextButton::STATE_NORMAL) && animating))) {
119 painter = (state == TextButton::STATE_PRESSED) ?
120 pushed_painter_.get() : hot_painter_.get();
122 if (painter) {
123 if (animating) {
124 // TODO(pkasting): Really this should crossfade between states so it could
125 // handle the case of having a non-NULL |normal_painter_|.
126 canvas->SaveLayerAlpha(static_cast<uint8>(
127 button->GetAnimation()->CurrentValueBetween(0, 255)));
128 painter->Paint(canvas, view.size());
129 canvas->Restore();
130 } else {
131 painter->Paint(canvas, view.size());
136 gfx::Size TextButtonDefaultBorder::GetMinimumSize() const {
137 gfx::Size size;
138 if (normal_painter_)
139 size.SetToMax(normal_painter_->GetMinimumSize());
140 if (hot_painter_)
141 size.SetToMax(hot_painter_->GetMinimumSize());
142 if (pushed_painter_)
143 size.SetToMax(pushed_painter_->GetMinimumSize());
144 return size;
148 // TextButtonNativeThemeBorder ------------------------------------------------
150 TextButtonNativeThemeBorder::TextButtonNativeThemeBorder(
151 NativeThemeDelegate* delegate)
152 : delegate_(delegate) {
153 SetInsets(gfx::Insets(kPreferredNativeThemePaddingVertical,
154 kPreferredNativeThemePaddingHorizontal,
155 kPreferredNativeThemePaddingVertical,
156 kPreferredNativeThemePaddingHorizontal));
159 TextButtonNativeThemeBorder::~TextButtonNativeThemeBorder() {
162 void TextButtonNativeThemeBorder::Paint(const View& view, gfx::Canvas* canvas) {
163 const ui::NativeTheme* theme = view.GetNativeTheme();
164 const TextButtonBase* tb = static_cast<const TextButton*>(&view);
165 ui::NativeTheme::Part part = delegate_->GetThemePart();
166 gfx::Rect rect(delegate_->GetThemePaintRect());
168 if (tb->show_multiple_icon_states() &&
169 delegate_->GetThemeAnimation() != NULL &&
170 delegate_->GetThemeAnimation()->is_animating()) {
171 // Paint background state.
172 ui::NativeTheme::ExtraParams prev_extra;
173 ui::NativeTheme::State prev_state =
174 delegate_->GetBackgroundThemeState(&prev_extra);
175 theme->Paint(canvas->sk_canvas(), part, prev_state, rect, prev_extra);
177 // Composite foreground state above it.
178 ui::NativeTheme::ExtraParams extra;
179 ui::NativeTheme::State state = delegate_->GetForegroundThemeState(&extra);
180 int alpha = delegate_->GetThemeAnimation()->CurrentValueBetween(0, 255);
181 canvas->SaveLayerAlpha(static_cast<uint8>(alpha));
182 theme->Paint(canvas->sk_canvas(), part, state, rect, extra);
183 canvas->Restore();
184 } else {
185 ui::NativeTheme::ExtraParams extra;
186 ui::NativeTheme::State state = delegate_->GetThemeState(&extra);
187 theme->Paint(canvas->sk_canvas(), part, state, rect, extra);
192 // TextButtonBase -------------------------------------------------------------
194 TextButtonBase::TextButtonBase(ButtonListener* listener,
195 const base::string16& text)
196 : CustomButton(listener),
197 alignment_(ALIGN_LEFT),
198 min_width_(0),
199 min_height_(0),
200 max_width_(0),
201 show_multiple_icon_states_(true),
202 is_default_(false),
203 multi_line_(false),
204 use_enabled_color_from_theme_(true),
205 use_disabled_color_from_theme_(true),
206 use_highlight_color_from_theme_(true),
207 use_hover_color_from_theme_(true),
208 focus_painter_(Painter::CreateDashedFocusPainter()) {
209 SetText(text);
210 SetAnimationDuration(kHoverAnimationDurationMs);
213 TextButtonBase::~TextButtonBase() {
216 void TextButtonBase::SetIsDefault(bool is_default) {
217 if (is_default == is_default_)
218 return;
219 is_default_ = is_default;
220 if (is_default_)
221 AddAccelerator(ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE));
222 else
223 RemoveAccelerator(ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE));
224 SchedulePaint();
227 void TextButtonBase::SetText(const base::string16& text) {
228 if (text == text_)
229 return;
230 text_ = text;
231 SetAccessibleName(text);
232 UpdateTextSize();
235 void TextButtonBase::SetFontList(const gfx::FontList& font_list) {
236 font_list_ = font_list;
237 UpdateTextSize();
240 void TextButtonBase::SetEnabledColor(SkColor color) {
241 color_enabled_ = color;
242 use_enabled_color_from_theme_ = false;
243 UpdateColor();
246 void TextButtonBase::SetDisabledColor(SkColor color) {
247 color_disabled_ = color;
248 use_disabled_color_from_theme_ = false;
249 UpdateColor();
252 void TextButtonBase::SetHighlightColor(SkColor color) {
253 color_highlight_ = color;
254 use_highlight_color_from_theme_ = false;
257 void TextButtonBase::SetHoverColor(SkColor color) {
258 color_hover_ = color;
259 use_hover_color_from_theme_ = false;
262 void TextButtonBase::ClearMaxTextSize() {
263 max_text_size_ = text_size_;
266 void TextButtonBase::SetShowMultipleIconStates(bool show_multiple_icon_states) {
267 show_multiple_icon_states_ = show_multiple_icon_states;
270 void TextButtonBase::SetMultiLine(bool multi_line) {
271 if (multi_line != multi_line_) {
272 multi_line_ = multi_line;
273 max_text_size_.SetSize(0, 0);
274 UpdateTextSize();
275 SchedulePaint();
279 gfx::Size TextButtonBase::GetPreferredSize() const {
280 gfx::Insets insets = GetInsets();
282 // Use the max size to set the button boundaries.
283 // In multiline mode max size can be undefined while
284 // width() is 0, so max it out with current text size.
285 gfx::Size prefsize(std::max(max_text_size_.width(),
286 text_size_.width()) + insets.width(),
287 std::max(max_text_size_.height(),
288 text_size_.height()) + insets.height());
290 if (max_width_ > 0)
291 prefsize.set_width(std::min(max_width_, prefsize.width()));
293 prefsize.set_width(std::max(prefsize.width(), min_width_));
294 prefsize.set_height(std::max(prefsize.height(), min_height_));
296 return prefsize;
299 int TextButtonBase::GetHeightForWidth(int w) const {
300 if (!multi_line_)
301 return View::GetHeightForWidth(w);
303 if (max_width_ > 0)
304 w = std::min(max_width_, w);
306 gfx::Size text_size;
307 CalculateTextSize(&text_size, w);
308 int height = text_size.height() + GetInsets().height();
310 return std::max(height, min_height_);
313 void TextButtonBase::OnPaint(gfx::Canvas* canvas) {
314 PaintButton(canvas, PB_NORMAL);
317 void TextButtonBase::OnBoundsChanged(const gfx::Rect& previous_bounds) {
318 if (multi_line_)
319 UpdateTextSize();
322 const gfx::Animation* TextButtonBase::GetAnimation() const {
323 return hover_animation_.get();
326 void TextButtonBase::UpdateColor() {
327 color_ = enabled() ? color_enabled_ : color_disabled_;
330 void TextButtonBase::UpdateTextSize() {
331 int text_width = width();
332 // If width is defined, use GetTextBounds.width() for maximum text width,
333 // as it will take size of checkbox/radiobutton into account.
334 if (text_width != 0) {
335 gfx::Rect text_bounds = GetTextBounds();
336 text_width = text_bounds.width();
338 CalculateTextSize(&text_size_, text_width);
339 // Before layout width() is 0, and multiline text will be treated as one line.
340 // Do not store max_text_size in this case. UpdateTextSize will be called
341 // again once width() changes.
342 if (!multi_line_ || text_width != 0) {
343 max_text_size_.SetSize(std::max(max_text_size_.width(), text_size_.width()),
344 std::max(max_text_size_.height(),
345 text_size_.height()));
346 PreferredSizeChanged();
350 void TextButtonBase::CalculateTextSize(gfx::Size* text_size,
351 int max_width) const {
352 int h = font_list_.GetHeight();
353 int w = multi_line_ ? max_width : 0;
354 int flags = ComputeCanvasStringFlags();
355 if (!multi_line_)
356 flags |= gfx::Canvas::NO_ELLIPSIS;
358 gfx::Canvas::SizeStringInt(text_, font_list_, &w, &h, 0, flags);
359 text_size->SetSize(w, h);
362 void TextButtonBase::OnPaintText(gfx::Canvas* canvas, PaintButtonMode mode) {
363 gfx::Rect text_bounds(GetTextBounds());
364 if (text_bounds.width() > 0) {
365 // Because the text button can (at times) draw multiple elements on the
366 // canvas, we can not mirror the button by simply flipping the canvas as
367 // doing this will mirror the text itself. Flipping the canvas will also
368 // make the icons look wrong because icons are almost always represented as
369 // direction-insensitive images and such images should never be flipped
370 // horizontally.
372 // Due to the above, we must perform the flipping manually for RTL UIs.
373 text_bounds.set_x(GetMirroredXForRect(text_bounds));
375 SkColor text_color = (show_multiple_icon_states_ &&
376 (state() == STATE_HOVERED || state() == STATE_PRESSED)) ?
377 color_hover_ : color_;
379 int draw_string_flags = gfx::Canvas::DefaultCanvasTextAlignment() |
380 ComputeCanvasStringFlags();
382 if (mode == PB_FOR_DRAG) {
383 // Disable sub-pixel rendering as background is transparent.
384 draw_string_flags |= gfx::Canvas::NO_SUBPIXEL_RENDERING;
385 canvas->DrawStringRectWithHalo(text_, font_list_,
386 SK_ColorBLACK, SK_ColorWHITE,
387 text_bounds, draw_string_flags);
388 } else {
389 canvas->DrawStringRectWithFlags(text_, font_list_, text_color,
390 text_bounds, draw_string_flags);
395 int TextButtonBase::ComputeCanvasStringFlags() const {
396 if (!multi_line_)
397 return 0;
399 int flags = gfx::Canvas::MULTI_LINE;
400 switch (alignment_) {
401 case ALIGN_LEFT:
402 flags |= gfx::Canvas::TEXT_ALIGN_LEFT;
403 break;
404 case ALIGN_RIGHT:
405 flags |= gfx::Canvas::TEXT_ALIGN_RIGHT;
406 break;
407 case ALIGN_CENTER:
408 flags |= gfx::Canvas::TEXT_ALIGN_CENTER;
409 break;
411 return flags;
414 void TextButtonBase::OnFocus() {
415 View::OnFocus();
416 if (focus_painter_)
417 SchedulePaint();
420 void TextButtonBase::OnBlur() {
421 View::OnBlur();
422 if (focus_painter_)
423 SchedulePaint();
426 void TextButtonBase::GetExtraParams(
427 ui::NativeTheme::ExtraParams* params) const {
428 params->button.checked = false;
429 params->button.indeterminate = false;
430 params->button.is_default = false;
431 params->button.is_focused = false;
432 params->button.has_border = false;
433 params->button.classic_state = 0;
434 params->button.background_color =
435 GetNativeTheme()->GetSystemColor(
436 ui::NativeTheme::kColorId_ButtonBackgroundColor);
439 gfx::Rect TextButtonBase::GetContentBounds(int extra_width) const {
440 gfx::Insets insets = GetInsets();
441 int available_width = width() - insets.width();
442 int content_width = text_size_.width() + extra_width;
443 int content_x = 0;
444 switch(alignment_) {
445 case ALIGN_LEFT:
446 content_x = insets.left();
447 break;
448 case ALIGN_RIGHT:
449 content_x = width() - insets.right() - content_width;
450 if (content_x < insets.left())
451 content_x = insets.left();
452 break;
453 case ALIGN_CENTER:
454 content_x = insets.left() + std::max(0,
455 (available_width - content_width) / 2);
456 break;
458 content_width = std::min(content_width,
459 width() - insets.right() - content_x);
460 int available_height = height() - insets.height();
461 int content_y = (available_height - text_size_.height()) / 2 + insets.top();
463 gfx::Rect bounds(content_x, content_y, content_width, text_size_.height());
464 return bounds;
467 gfx::Rect TextButtonBase::GetTextBounds() const {
468 return GetContentBounds(0);
471 void TextButtonBase::SetFocusPainter(scoped_ptr<Painter> focus_painter) {
472 focus_painter_ = focus_painter.Pass();
475 void TextButtonBase::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
476 if (mode == PB_NORMAL) {
477 OnPaintBackground(canvas);
478 OnPaintBorder(canvas);
479 Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
482 OnPaintText(canvas, mode);
485 gfx::Size TextButtonBase::GetMinimumSize() const {
486 return max_text_size_;
489 void TextButtonBase::OnEnabledChanged() {
490 // We should always call UpdateColor() since the state of the button might be
491 // changed by other functions like CustomButton::SetState().
492 UpdateColor();
493 CustomButton::OnEnabledChanged();
496 const char* TextButtonBase::GetClassName() const {
497 return kViewClassName;
500 void TextButtonBase::OnNativeThemeChanged(const ui::NativeTheme* theme) {
501 if (use_enabled_color_from_theme_) {
502 color_enabled_ = theme->GetSystemColor(
503 ui::NativeTheme::kColorId_ButtonEnabledColor);
505 if (use_disabled_color_from_theme_) {
506 color_disabled_ = theme->GetSystemColor(
507 ui::NativeTheme::kColorId_ButtonDisabledColor);
509 if (use_highlight_color_from_theme_) {
510 color_highlight_ = theme->GetSystemColor(
511 ui::NativeTheme::kColorId_ButtonHighlightColor);
513 if (use_hover_color_from_theme_) {
514 color_hover_ = theme->GetSystemColor(
515 ui::NativeTheme::kColorId_ButtonHoverColor);
517 UpdateColor();
520 gfx::Rect TextButtonBase::GetThemePaintRect() const {
521 return GetLocalBounds();
524 ui::NativeTheme::State TextButtonBase::GetThemeState(
525 ui::NativeTheme::ExtraParams* params) const {
526 GetExtraParams(params);
527 switch(state()) {
528 case STATE_DISABLED:
529 return ui::NativeTheme::kDisabled;
530 case STATE_NORMAL:
531 return ui::NativeTheme::kNormal;
532 case STATE_HOVERED:
533 return ui::NativeTheme::kHovered;
534 case STATE_PRESSED:
535 return ui::NativeTheme::kPressed;
536 default:
537 NOTREACHED() << "Unknown state: " << state();
538 return ui::NativeTheme::kNormal;
542 const gfx::Animation* TextButtonBase::GetThemeAnimation() const {
543 #if defined(OS_WIN)
544 if (GetNativeTheme() == ui::NativeThemeWin::instance()) {
545 return ui::NativeThemeWin::instance()->IsThemingActive() ?
546 hover_animation_.get() : NULL;
548 #endif
549 return hover_animation_.get();
552 ui::NativeTheme::State TextButtonBase::GetBackgroundThemeState(
553 ui::NativeTheme::ExtraParams* params) const {
554 GetExtraParams(params);
555 return ui::NativeTheme::kNormal;
558 ui::NativeTheme::State TextButtonBase::GetForegroundThemeState(
559 ui::NativeTheme::ExtraParams* params) const {
560 GetExtraParams(params);
561 return ui::NativeTheme::kHovered;
565 // TextButton -----------------------------------------------------------------
567 TextButton::TextButton(ButtonListener* listener, const base::string16& text)
568 : TextButtonBase(listener, text),
569 icon_placement_(ICON_ON_LEFT),
570 has_hover_icon_(false),
571 has_pushed_icon_(false),
572 icon_text_spacing_(kDefaultIconTextSpacing),
573 ignore_minimum_size_(true),
574 full_justification_(false) {
575 SetBorder(scoped_ptr<Border>(new TextButtonDefaultBorder));
576 SetFocusPainter(Painter::CreateDashedFocusPainterWithInsets(
577 gfx::Insets(kFocusRectInset, kFocusRectInset,
578 kFocusRectInset, kFocusRectInset)));
581 TextButton::~TextButton() {
584 void TextButton::SetIcon(const gfx::ImageSkia& icon) {
585 icon_ = icon;
586 SchedulePaint();
589 void TextButton::SetHoverIcon(const gfx::ImageSkia& icon) {
590 icon_hover_ = icon;
591 has_hover_icon_ = true;
592 SchedulePaint();
595 void TextButton::SetPushedIcon(const gfx::ImageSkia& icon) {
596 icon_pushed_ = icon;
597 has_pushed_icon_ = true;
598 SchedulePaint();
601 gfx::Size TextButton::GetPreferredSize() const {
602 gfx::Size prefsize(TextButtonBase::GetPreferredSize());
603 prefsize.Enlarge(icon_.width(), 0);
604 prefsize.set_height(std::max(prefsize.height(), icon_.height()));
606 // Use the max size to set the button boundaries.
607 if (icon_.width() > 0 && !text_.empty())
608 prefsize.Enlarge(icon_text_spacing_, 0);
610 if (max_width_ > 0)
611 prefsize.set_width(std::min(max_width_, prefsize.width()));
613 #if defined(OS_WIN)
614 // Clamp the size returned to at least the minimum size.
615 if (!ignore_minimum_size_) {
616 gfx::PlatformFontWin* platform_font = static_cast<gfx::PlatformFontWin*>(
617 font_list_.GetPrimaryFont().platform_font());
618 prefsize.set_width(std::max(
619 prefsize.width(),
620 platform_font->horizontal_dlus_to_pixels(kMinWidthDLUs)));
621 prefsize.set_height(std::max(
622 prefsize.height(),
623 platform_font->vertical_dlus_to_pixels(kMinHeightDLUs)));
625 #endif
627 prefsize.set_width(std::max(prefsize.width(), min_width_));
628 prefsize.set_height(std::max(prefsize.height(), min_height_));
630 return prefsize;
633 void TextButton::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
634 if (full_justification_ && icon_placement_ == ICON_ON_LEFT)
635 set_alignment(ALIGN_RIGHT);
637 TextButtonBase::PaintButton(canvas, mode);
638 OnPaintIcon(canvas, mode);
641 void TextButton::OnPaintIcon(gfx::Canvas* canvas, PaintButtonMode mode) {
642 const gfx::ImageSkia& icon = GetImageToPaint();
644 if (icon.width() > 0) {
645 gfx::Rect text_bounds = GetTextBounds();
646 int icon_x = 0;
647 int spacing = text_.empty() ? 0 : icon_text_spacing_;
648 gfx::Insets insets = GetInsets();
649 switch (icon_placement_) {
650 case ICON_ON_LEFT:
651 icon_x = full_justification_ ? insets.left()
652 : text_bounds.x() - icon.width() - spacing;
653 break;
654 case ICON_ON_RIGHT:
655 icon_x = full_justification_ ? width() - insets.right() - icon.width()
656 : text_bounds.right() + spacing;
657 break;
658 case ICON_CENTERED:
659 DCHECK(text_.empty());
660 icon_x = (width() - insets.width() - icon.width()) / 2 + insets.left();
661 break;
662 default:
663 NOTREACHED();
664 break;
667 int available_height = height() - insets.height();
668 int icon_y = (available_height - icon.height()) / 2 + insets.top();
670 // Mirroring the icon position if necessary.
671 gfx::Rect icon_bounds(icon_x, icon_y, icon.width(), icon.height());
672 icon_bounds.set_x(GetMirroredXForRect(icon_bounds));
673 canvas->DrawImageInt(icon, icon_bounds.x(), icon_bounds.y());
677 void TextButton::set_ignore_minimum_size(bool ignore_minimum_size) {
678 ignore_minimum_size_ = ignore_minimum_size;
681 void TextButton::set_full_justification(bool full_justification) {
682 full_justification_ = full_justification;
685 const char* TextButton::GetClassName() const {
686 return kViewClassName;
689 ui::NativeTheme::Part TextButton::GetThemePart() const {
690 return ui::NativeTheme::kPushButton;
693 void TextButton::GetExtraParams(ui::NativeTheme::ExtraParams* params) const {
694 TextButtonBase::GetExtraParams(params);
695 params->button.is_default = is_default_;
698 gfx::Rect TextButton::GetTextBounds() const {
699 int extra_width = 0;
701 const gfx::ImageSkia& icon = GetImageToPaint();
702 if (icon.width() > 0)
703 extra_width = icon.width() + (text_.empty() ? 0 : icon_text_spacing_);
705 gfx::Rect bounds(GetContentBounds(extra_width));
707 if (extra_width > 0) {
708 // Make sure the icon is always fully visible.
709 if (icon_placement_ == ICON_ON_LEFT) {
710 bounds.Inset(extra_width, 0, 0, 0);
711 } else if (icon_placement_ == ICON_ON_RIGHT) {
712 bounds.Inset(0, 0, extra_width, 0);
716 return bounds;
719 const gfx::ImageSkia& TextButton::GetImageToPaint() const {
720 if (show_multiple_icon_states_) {
721 if (has_hover_icon_ && (state() == STATE_HOVERED))
722 return icon_hover_;
723 if (has_pushed_icon_ && (state() == STATE_PRESSED))
724 return icon_pushed_;
726 return icon_;
729 } // namespace views