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