new_avatar_button.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
1// Copyright 2014 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 "chrome/browser/ui/views/profiles/new_avatar_button.h"
6
7#include "base/win/windows_version.h"
8#include "chrome/browser/browser_process.h"
9#include "chrome/browser/profiles/profile_manager.h"
10#include "chrome/browser/profiles/profiles_state.h"
11#include "chrome/browser/ui/browser.h"
12#include "chrome/browser/ui/views/profiles/profile_chooser_view.h"
13#include "grit/theme_resources.h"
14#include "ui/base/resource/resource_bundle.h"
15#include "ui/gfx/canvas.h"
16#include "ui/views/border.h"
17#include "ui/views/controls/button/label_button_border.h"
18#include "ui/views/painter.h"
19
20namespace {
21
22scoped_ptr<views::Border> CreateBorder(const int normal_image_set[],
23                                       const int hot_image_set[],
24                                       const int pushed_image_set[]) {
25  scoped_ptr<views::LabelButtonBorder> border(
26      new views::LabelButtonBorder(views::Button::STYLE_TEXTBUTTON));
27  border->SetPainter(false, views::Button::STATE_NORMAL,
28      views::Painter::CreateImageGridPainter(normal_image_set));
29  border->SetPainter(false, views::Button::STATE_HOVERED,
30      views::Painter::CreateImageGridPainter(hot_image_set));
31  border->SetPainter(false, views::Button::STATE_PRESSED,
32      views::Painter::CreateImageGridPainter(pushed_image_set));
33
34  const int kLeftRightInset = 10;
35  const int kTopInset = 0;
36  const int kBottomInset = 4;
37  border->set_insets(gfx::Insets(kTopInset, kLeftRightInset,
38                                 kBottomInset, kLeftRightInset));
39
40  return border.PassAs<views::Border>();
41}
42
43}  // namespace
44
45NewAvatarButton::NewAvatarButton(
46    views::ButtonListener* listener,
47    const base::string16& profile_name,
48    AvatarButtonStyle button_style,
49    Browser* browser)
50    : MenuButton(listener,
51                 profiles::GetAvatarButtonTextForProfile(browser->profile()),
52                 NULL,
53                 true),
54      browser_(browser),
55      suppress_mouse_released_action_(false) {
56  set_animate_on_state_change(false);
57  SetTextColor(views::Button::STATE_NORMAL, SK_ColorWHITE);
58  SetTextColor(views::Button::STATE_HOVERED, SK_ColorWHITE);
59  SetTextColor(views::Button::STATE_PRESSED, SK_ColorWHITE);
60  SetTextShadows(gfx::ShadowValues(10,
61      gfx::ShadowValue(gfx::Point(), 1.0f, SK_ColorDKGRAY)));
62  SetTextSubpixelRenderingEnabled(false);
63
64  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
65  if (button_style == THEMED_BUTTON) {
66    const int kNormalImageSet[] = IMAGE_GRID(IDR_AVATAR_THEMED_BUTTON_NORMAL);
67    const int kHotImageSet[] = IMAGE_GRID(IDR_AVATAR_THEMED_BUTTON_HOVER);
68    const int kPushedImageSet[] = IMAGE_GRID(IDR_AVATAR_THEMED_BUTTON_PRESSED);
69
70    SetBorder(CreateBorder(kNormalImageSet, kHotImageSet, kPushedImageSet));
71    set_menu_marker(
72        rb->GetImageNamed(IDR_AVATAR_THEMED_BUTTON_DROPARROW).ToImageSkia());
73#if defined(OS_WIN)
74  } else if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
75    const int kNormalImageSet[] = IMAGE_GRID(IDR_AVATAR_METRO_BUTTON_NORMAL);
76    const int kHotImageSet[] = IMAGE_GRID(IDR_AVATAR_METRO_BUTTON_HOVER);
77    const int kPushedImageSet[] = IMAGE_GRID(IDR_AVATAR_METRO_BUTTON_PRESSED);
78
79    SetBorder(CreateBorder(kNormalImageSet, kHotImageSet, kPushedImageSet));
80    set_menu_marker(
81        rb->GetImageNamed(IDR_AVATAR_METRO_BUTTON_DROPARROW).ToImageSkia());
82#endif
83  } else {
84    const int kNormalImageSet[] = IMAGE_GRID(IDR_AVATAR_GLASS_BUTTON_NORMAL);
85    const int kHotImageSet[] = IMAGE_GRID(IDR_AVATAR_GLASS_BUTTON_HOVER);
86    const int kPushedImageSet[] = IMAGE_GRID(IDR_AVATAR_GLASS_BUTTON_PRESSED);
87
88    SetBorder(CreateBorder(kNormalImageSet, kHotImageSet, kPushedImageSet));
89    set_menu_marker(
90        rb->GetImageNamed(IDR_AVATAR_GLASS_BUTTON_DROPARROW).ToImageSkia());
91  }
92
93  g_browser_process->profile_manager()->GetProfileInfoCache().AddObserver(this);
94
95  // Subscribe to authentication error changes so that the avatar button can
96  // update itself.  Note that guest mode profiles won't have a token service.
97  SigninErrorController* error =
98      profiles::GetSigninErrorController(browser_->profile());
99  if (error) {
100    error->AddObserver(this);
101    OnErrorChanged();
102  }
103
104  SchedulePaint();
105}
106
107NewAvatarButton::~NewAvatarButton() {
108  g_browser_process->profile_manager()->
109      GetProfileInfoCache().RemoveObserver(this);
110  SigninErrorController* error =
111      profiles::GetSigninErrorController(browser_->profile());
112  if (error)
113    error->RemoveObserver(this);
114}
115
116bool NewAvatarButton::OnMousePressed(const ui::MouseEvent& event) {
117  // Prevent the bubble from being re-shown if it's already showing.
118  suppress_mouse_released_action_ = ProfileChooserView::IsShowing();
119  return MenuButton::OnMousePressed(event);
120}
121
122void NewAvatarButton::OnMouseReleased(const ui::MouseEvent& event) {
123  if (suppress_mouse_released_action_)
124    suppress_mouse_released_action_ = false;
125  else
126    MenuButton::OnMouseReleased(event);
127}
128
129void NewAvatarButton::OnProfileAdded(const base::FilePath& profile_path) {
130  UpdateAvatarButtonAndRelayoutParent();
131}
132
133void NewAvatarButton::OnProfileWasRemoved(
134      const base::FilePath& profile_path,
135      const base::string16& profile_name) {
136  UpdateAvatarButtonAndRelayoutParent();
137}
138
139void NewAvatarButton::OnProfileNameChanged(
140      const base::FilePath& profile_path,
141      const base::string16& old_profile_name) {
142  UpdateAvatarButtonAndRelayoutParent();
143}
144
145void NewAvatarButton::OnProfileAvatarChanged(
146      const base::FilePath& profile_path) {
147  UpdateAvatarButtonAndRelayoutParent();
148}
149
150void NewAvatarButton::OnProfileSupervisedUserIdChanged(
151      const base::FilePath& profile_path) {
152  UpdateAvatarButtonAndRelayoutParent();
153}
154
155void NewAvatarButton::OnErrorChanged() {
156  gfx::ImageSkia icon;
157
158  // If there is an error, show an warning icon.
159  const SigninErrorController* error =
160      profiles::GetSigninErrorController(browser_->profile());
161  if (error && error->HasError()) {
162    icon = *ui::ResourceBundle::GetSharedInstance().GetImageNamed(
163        IDR_ICON_PROFILES_AVATAR_BUTTON_ERROR).ToImageSkia();
164  }
165
166  SetImage(views::Button::STATE_NORMAL, icon);
167  UpdateAvatarButtonAndRelayoutParent();
168}
169
170void NewAvatarButton::UpdateAvatarButtonAndRelayoutParent() {
171  // We want the button to resize if the new text is shorter.
172  SetText(profiles::GetAvatarButtonTextForProfile(browser_->profile()));
173  SetMinSize(gfx::Size());
174  InvalidateLayout();
175
176  // Because the width of the button might have changed, the parent browser
177  // frame needs to recalculate the button bounds and redraw it.
178  if (parent())
179    parent()->Layout();
180}
181