15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/button/label_button.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/ui_resources.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/animation/throb_animation.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/gfx/sys_color_change_listener.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/native_theme/native_theme.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/button/label_button_border.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/focus_border.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/views/window/dialog_delegate.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/native_theme/native_theme_win.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The spacing between the icon and text.
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kSpacing = 5;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The length of the hover fade animation.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kHoverAnimationDurationMs = 170;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Default text and shadow colors for STYLE_BUTTON.
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst SkColor kStyleButtonTextColor = SK_ColorBLACK;
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst SkColor kStyleButtonShadowColor = SK_ColorWHITE;
32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace views {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const char LabelButton::kViewClassName[] = "LabelButton";
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LabelButton::LabelButton(ButtonListener* listener, const string16& text)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : CustomButton(listener),
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      image_(new ImageView()),
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      label_(new Label()),
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      button_state_images_(),
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      button_state_colors_(),
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      explicitly_set_colors_(),
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      is_default_(false),
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      style_(STYLE_TEXTBUTTON) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetAnimationDuration(kHoverAnimationDurationMs);
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetText(text);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddChildView(image_);
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image_->set_interactive(false);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddChildView(label_);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  label_->SetAutoColorReadabilityEnabled(false);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Initialize the colors, border, and layout.
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetStyle(style_);
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetAccessibleName(text);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LabelButton::~LabelButton() {}
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const gfx::ImageSkia& LabelButton::GetImage(ButtonState for_state) {
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (for_state != STATE_NORMAL && button_state_images_[for_state].isNull())
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return button_state_images_[STATE_NORMAL];
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return button_state_images_[for_state];
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LabelButton::SetImage(ButtonState for_state, const gfx::ImageSkia& image) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  button_state_images_[for_state] = image;
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  UpdateImage();
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const string16& LabelButton::GetText() const {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return label_->text();
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LabelButton::SetText(const string16& text) {
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetAccessibleName(text);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  label_->SetText(text);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LabelButton::SetTextColor(ButtonState for_state, SkColor color) {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  button_state_colors_[for_state] = color;
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (for_state == STATE_DISABLED)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    label_->SetDisabledColor(color);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else if (for_state == state())
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    label_->SetEnabledColor(color);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicitly_set_colors_[for_state] = true;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool LabelButton::GetTextMultiLine() const {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return label_->is_multi_line();
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LabelButton::SetTextMultiLine(bool text_multi_line) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  label_->SetMultiLine(text_multi_line);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const gfx::Font& LabelButton::GetFont() const {
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return label_->font();
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LabelButton::SetFont(const gfx::Font& font) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  label_->SetFont(font);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::HorizontalAlignment LabelButton::GetHorizontalAlignment() const {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return label_->horizontal_alignment();
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LabelButton::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  label_->SetHorizontalAlignment(alignment);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InvalidateLayout();
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void LabelButton::SetIsDefault(bool is_default) {
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (is_default == is_default_)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  is_default_ = is_default;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::Accelerator accel(ui::VKEY_RETURN, ui::EF_NONE);
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  is_default_ ? AddAccelerator(accel) : RemoveAccelerator(accel);
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // STYLE_BUTTON uses bold text to indicate default buttons.
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (style_ == STYLE_BUTTON) {
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int style = label_->font().GetStyle();
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    style = is_default ? style | gfx::Font::BOLD : style & !gfx::Font::BOLD;
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    label_->SetFont(label_->font().DeriveFont(0, style));
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void LabelButton::SetStyle(ButtonStyle style) {
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Use the new button style instead of the native button style.
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // TODO(msw): Officialy deprecate and remove STYLE_NATIVE_TEXTBUTTON.
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (DialogDelegate::UseNewStyle() && style == STYLE_NATIVE_TEXTBUTTON)
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    style = STYLE_BUTTON;
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  style_ = style;
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  set_border(new LabelButtonBorder(style));
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Inset the button focus rect from the actual border; roughly match Windows.
145b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  set_focus_border(style == STYLE_BUTTON ?
146b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      NULL : FocusBorder::CreateDashedFocusBorder(3, 3, 3, 3));
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (style == STYLE_BUTTON || style == STYLE_NATIVE_TEXTBUTTON) {
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    label_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    set_focusable(true);
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (style == STYLE_BUTTON)
1527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    set_min_size(gfx::Size(70, 33));
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Invalidate the layout to pickup the new insets from the border.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InvalidateLayout();
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ResetColorsFromNativeTheme();
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Size LabelButton::GetPreferredSize() {
159a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Use a temporary label copy for sizing to avoid calculation side-effects.
1607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  gfx::Font font = GetFont();
1617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  Label label(GetText(), font);
162a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  label.SetMultiLine(GetTextMultiLine());
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (style() == STYLE_BUTTON) {
1657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // Some text appears wider when rendered normally than when rendered bold.
1667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // Accommodate the widest, as buttons may show bold and shouldn't resize.
1677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const int current_width = label.GetPreferredSize().width();
1687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    label.SetFont(font.DeriveFont(0, font.GetStyle() ^ gfx::Font::BOLD));
1697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (label.GetPreferredSize().width() < current_width)
1707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      label.SetFont(font);
1717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
1727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
173a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Resize multi-line labels given the current limited available width.
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const gfx::Size image_size(image_->GetPreferredSize());
175a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  const int image_width = image_size.width();
176a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (GetTextMultiLine() && (width() > image_width + kSpacing))
177a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    label.SizeToFit(width() - image_width - (image_width > 0 ? kSpacing : 0));
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Calculate the required size.
180a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  gfx::Size size(label.GetPreferredSize());
181a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (image_width > 0 && size.width() > 0)
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    size.Enlarge(kSpacing, 0);
183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  size.SetToMax(gfx::Size(0, image_size.height()));
184a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  const gfx::Insets insets(GetInsets());
185a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  size.Enlarge(image_size.width() + insets.width(), insets.height());
186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Increase the minimum size monotonically with the preferred size.
188868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  size.SetToMax(min_size_);
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  min_size_ = size;
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Return the largest known size clamped to the maximum size (if valid).
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (max_size_.width() > 0)
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    size.set_width(std::min(max_size_.width(), size.width()));
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (max_size_.height() > 0)
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    size.set_height(std::min(max_size_.height(), size.height()));
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return size;
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LabelButton::Layout() {
20090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  gfx::HorizontalAlignment adjusted_alignment = GetHorizontalAlignment();
20190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (base::i18n::IsRTL() && adjusted_alignment != gfx::ALIGN_CENTER)
20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    adjusted_alignment = (adjusted_alignment == gfx::ALIGN_LEFT) ?
20390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        gfx::ALIGN_RIGHT : gfx::ALIGN_LEFT;
20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect child_area(GetLocalBounds());
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  child_area.Inset(GetInsets());
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Size image_size(image_->GetPreferredSize());
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image_size.set_width(std::min(image_size.width(), child_area.width()));
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image_size.set_height(std::min(image_size.height(), child_area.height()));
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The label takes any remaining width after sizing the image, unless both
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // views are centered. In that case, using the tighter preferred label width
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // avoids wasted space within the label that would look like awkward padding.
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Size label_size(child_area.size());
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!image_size.IsEmpty() && !label_size.IsEmpty()) {
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    label_size.set_width(
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::max(child_area.width() - image_size.width() - kSpacing, 0));
21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (adjusted_alignment == gfx::ALIGN_CENTER) {
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Ensure multi-line labels paired with images use their available width.
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (GetTextMultiLine())
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        label_->SizeToFit(label_size.width());
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      label_size.set_width(
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          std::min(label_size.width(), label_->GetPreferredSize().width()));
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Point image_origin(child_area.origin());
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image_origin.Offset(0, (child_area.height() - image_size.height()) / 2);
23090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (adjusted_alignment == gfx::ALIGN_CENTER) {
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int total_width = image_size.width() + label_size.width() +
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ((image_size.width() > 0 && label_size.width() > 0) ? kSpacing : 0);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    image_origin.Offset((child_area.width() - total_width) / 2, 0);
23490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  } else if (adjusted_alignment == gfx::ALIGN_RIGHT) {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    image_origin.Offset(child_area.width() - image_size.width(), 0);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Point label_origin(child_area.origin());
23990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!image_size.IsEmpty() &&adjusted_alignment != gfx::ALIGN_RIGHT)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    label_origin.set_x(image_origin.x() + image_size.width() + kSpacing);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image_->SetBoundsRect(gfx::Rect(image_origin, image_size));
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  label_->SetBoundsRect(gfx::Rect(label_origin, label_size));
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const char* LabelButton::GetClassName() const {
24790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return kViewClassName;
24890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
24990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
25090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void LabelButton::GetExtraParams(ui::NativeTheme::ExtraParams* params) const {
25190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  params->button.checked = false;
25290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  params->button.indeterminate = false;
25390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  params->button.is_default = is_default_;
25490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  params->button.is_focused = HasFocus() && IsAccessibilityFocusable();
25590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  params->button.has_border = style() == STYLE_NATIVE_TEXTBUTTON;
25690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  params->button.classic_state = 0;
257eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  params->button.background_color = label()->background_color();
25890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
25990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
26090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void LabelButton::UpdateImage() {
26190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  image_->SetImage(GetImage(state()));
26290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
26390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
26490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void LabelButton::ResetColorsFromNativeTheme() {
26590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const ui::NativeTheme* theme = GetNativeTheme();
26690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SkColor colors[STATE_COUNT] = {
26790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonEnabledColor),
26890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonHoverColor),
26990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonHoverColor),
27090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonDisabledColor),
27190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  };
27290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
27390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Certain styles do not change text color when hovered or pressed.
274eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool constant_text_color = false;
27590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#if defined(OS_WIN)
27690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  constant_text_color |= (style() == STYLE_NATIVE_TEXTBUTTON &&
27790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                          theme == ui::NativeThemeWin::instance());
27890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif
279eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
280eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  label_->SetBackgroundColor(theme->GetSystemColor(
281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      ui::NativeTheme::kColorId_ButtonBackgroundColor));
282eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
283eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Use hardcoded colors for inverted color scheme support and STYLE_BUTTON.
284eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (gfx::IsInvertedColorScheme()) {
285eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    constant_text_color = true;
286eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    colors[STATE_NORMAL] = SK_ColorWHITE;
287eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    label_->SetBackgroundColor(SK_ColorBLACK);
288eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    label_->SetAutoColorReadabilityEnabled(true);
289eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    label_->ClearEmbellishing();
290eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  } else if (style() == STYLE_BUTTON) {
291eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    constant_text_color = true;
292eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    colors[STATE_NORMAL] = kStyleButtonTextColor;
293eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    label_->SetAutoColorReadabilityEnabled(false);
294eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    label_->SetShadowColors(kStyleButtonShadowColor, kStyleButtonShadowColor);
295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    label_->SetShadowOffset(0, 1);
296eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
297eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
29890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (constant_text_color)
29990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    colors[STATE_HOVERED] = colors[STATE_PRESSED] = colors[STATE_NORMAL];
30090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
30190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (size_t state = STATE_NORMAL; state < STATE_COUNT; ++state) {
30290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!explicitly_set_colors_[state]) {
30390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      SetTextColor(static_cast<ButtonState>(state), colors[state]);
30490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      explicitly_set_colors_[state] = false;
30590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
30690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
30790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
30890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
30990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void LabelButton::StateChanged() {
31090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const gfx::Size previous_image_size(image_->GetPreferredSize());
31190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  UpdateImage();
31290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const SkColor color = button_state_colors_[state()];
31390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (state() != STATE_DISABLED && label_->enabled_color() != color)
31490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    label_->SetEnabledColor(color);
31590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  label_->SetEnabled(state() != STATE_DISABLED);
31690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (image_->GetPreferredSize() != previous_image_size)
31790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    Layout();
31890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
31990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LabelButton::ChildPreferredSizeChanged(View* child) {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PreferredSizeChanged();
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LabelButton::OnNativeThemeChanged(const ui::NativeTheme* theme) {
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ResetColorsFromNativeTheme();
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ui::NativeTheme::Part LabelButton::GetThemePart() const {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ui::NativeTheme::kPushButton;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Rect LabelButton::GetThemePaintRect() const {
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetLocalBounds();
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ui::NativeTheme::State LabelButton::GetThemeState(
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ui::NativeTheme::ExtraParams* params) const {
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetExtraParams(params);
33990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  switch (state()) {
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_NORMAL:   return ui::NativeTheme::kNormal;
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_HOVERED:  return ui::NativeTheme::kHovered;
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_PRESSED:  return ui::NativeTheme::kPressed;
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_DISABLED: return ui::NativeTheme::kDisabled;
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_COUNT:    NOTREACHED() << "Unknown state: " << state();
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ui::NativeTheme::kNormal;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const ui::Animation* LabelButton::GetThemeAnimation() const {
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (style() == STYLE_NATIVE_TEXTBUTTON &&
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GetNativeTheme() == ui::NativeThemeWin::instance()) {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ui::NativeThemeWin::instance()->IsThemingActive() ?
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        hover_animation_.get() : NULL;
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hover_animation_.get();
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ui::NativeTheme::State LabelButton::GetBackgroundThemeState(
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ui::NativeTheme::ExtraParams* params) const {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetExtraParams(params);
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ui::NativeTheme::kNormal;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ui::NativeTheme::State LabelButton::GetForegroundThemeState(
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ui::NativeTheme::ExtraParams* params) const {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetExtraParams(params);
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ui::NativeTheme::kHovered;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace views
373