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 "chrome/browser/ui/views/avatar_menu_button.h" 6 7 #include "base/command_line.h" 8 #include "base/prefs/pref_service.h" 9 #include "chrome/browser/browser_process.h" 10 #include "chrome/browser/chrome_notification_types.h" 11 #include "chrome/browser/profiles/avatar_menu.h" 12 #include "chrome/browser/profiles/profile_info_util.h" 13 #include "chrome/browser/profiles/profile_metrics.h" 14 #include "chrome/browser/profiles/profiles_state.h" 15 #include "chrome/browser/ui/browser.h" 16 #include "chrome/browser/ui/views/avatar_menu_bubble_view.h" 17 #include "chrome/browser/ui/views/frame/browser_view.h" 18 #include "chrome/browser/ui/views/profile_chooser_view.h" 19 #include "chrome/common/pref_names.h" 20 #include "content/public/browser/notification_service.h" 21 #include "ui/gfx/canvas.h" 22 #include "ui/views/widget/widget.h" 23 24 static inline int Round(double x) { 25 return static_cast<int>(x + 0.5); 26 } 27 28 // static 29 const char AvatarMenuButton::kViewClassName[] = "AvatarMenuButton"; 30 31 AvatarMenuButton::AvatarMenuButton(Browser* browser, bool disabled) 32 : MenuButton(NULL, base::string16(), this, false), 33 browser_(browser), 34 disabled_(disabled), 35 is_rectangle_(false), 36 old_height_(0) { 37 // In RTL mode, the avatar icon should be looking the opposite direction. 38 EnableCanvasFlippingForRTLUI(true); 39 } 40 41 AvatarMenuButton::~AvatarMenuButton() { 42 } 43 44 const char* AvatarMenuButton::GetClassName() const { 45 return kViewClassName; 46 } 47 48 void AvatarMenuButton::OnPaint(gfx::Canvas* canvas) { 49 if (!icon_.get()) 50 return; 51 52 if (old_height_ != height() || button_icon_.isNull()) { 53 old_height_ = height(); 54 button_icon_ = *profiles::GetAvatarIconForTitleBar( 55 *icon_, is_rectangle_, width(), height()).ToImageSkia(); 56 } 57 58 // Scale the image to fit the width of the button. 59 int dst_width = std::min(button_icon_.width(), width()); 60 // Truncate rather than rounding, so that for odd widths we put the extra 61 // pixel on the left. 62 int dst_x = (width() - dst_width) / 2; 63 64 // Scale the height and maintain aspect ratio. This means that the 65 // icon may not fit in the view. That's ok, we just vertically center it. 66 float scale = 67 static_cast<float>(dst_width) / static_cast<float>(button_icon_.width()); 68 // Round here so that we minimize the aspect ratio drift. 69 int dst_height = Round(button_icon_.height() * scale); 70 // Round rather than truncating, so that for odd heights we select an extra 71 // pixel below the image center rather than above. This is because the 72 // incognito image has shadows at the top that make the apparent center below 73 // the real center. 74 int dst_y = Round((height() - dst_height) / 2.0); 75 canvas->DrawImageInt(button_icon_, 0, 0, button_icon_.width(), 76 button_icon_.height(), dst_x, dst_y, dst_width, dst_height, false); 77 } 78 79 bool AvatarMenuButton::HitTestRect(const gfx::Rect& rect) const { 80 if (disabled_) 81 return false; 82 return views::MenuButton::HitTestRect(rect); 83 } 84 85 void AvatarMenuButton::SetAvatarIcon(const gfx::Image& icon, 86 bool is_rectangle) { 87 icon_.reset(new gfx::Image(icon)); 88 button_icon_ = gfx::ImageSkia(); 89 is_rectangle_ = is_rectangle; 90 SchedulePaint(); 91 } 92 93 // views::MenuButtonListener implementation 94 void AvatarMenuButton::OnMenuButtonClicked(views::View* source, 95 const gfx::Point& point) { 96 if (disabled_) 97 return; 98 99 ShowAvatarBubble(); 100 } 101 102 void AvatarMenuButton::ShowAvatarBubble() { 103 gfx::Point origin; 104 views::View::ConvertPointToScreen(this, &origin); 105 gfx::Rect bounds(origin, size()); 106 views::BubbleBorder::Arrow arrow = button_on_right_ ? 107 views::BubbleBorder::TOP_RIGHT : views::BubbleBorder::TOP_LEFT; 108 if (profiles::IsNewProfileManagementEnabled()) { 109 ProfileChooserView::ShowBubble( 110 this, arrow, views::BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR, bounds, 111 browser_); 112 } else { 113 AvatarMenuBubbleView::ShowBubble( 114 this, arrow, views::BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR, bounds, 115 browser_); 116 } 117 118 ProfileMetrics::LogProfileOpenMethod(ProfileMetrics::ICON_AVATAR_BUBBLE); 119 } 120