Chromium Code Reviews| Index: chrome/browser/ui/views/avatar_menu_bubble_view.cc |
| diff --git a/chrome/browser/ui/views/avatar_menu_bubble_view.cc b/chrome/browser/ui/views/avatar_menu_bubble_view.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..f94922a999f53fcfbbf45a1ad37ceb2fed76d3ab |
| --- /dev/null |
| +++ b/chrome/browser/ui/views/avatar_menu_bubble_view.cc |
| @@ -0,0 +1,234 @@ |
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/ui/views/avatar_menu_bubble_view.h" |
| + |
| +#include "chrome/browser/browser_process.h" |
| +#include "chrome/browser/ui/browser.h" |
| +#include "chrome/browser/profiles/avatar_menu_model.h" |
| +#include "chrome/browser/profiles/profile_info_cache.h" |
| +#include "chrome/browser/profiles/profile_manager.h" |
| +#include "grit/generated_resources.h" |
| +#include "grit/theme_resources.h" |
| +#include "ui/base/l10n/l10n_util.h" |
| +#include "ui/base/resource/resource_bundle.h" |
| +#include "ui/gfx/canvas.h" |
| +#include "ui/gfx/font.h" |
| +#include "ui/gfx/image/image.h" |
| + |
| +namespace { |
| + |
| +const int ITEM_WIDTH = 210; |
|
Robert Sesek
2011/08/05 00:44:03
Shouldn't constants be in kCamelCase? That's what
sail
2011/08/05 01:28:21
Done.
|
| +const int ITEM_HEIGHT = 32; |
| +const int ITEM_MARGIN_Y = 8; |
| +const int ICON_WIDTH = 38; |
| +const int ICON_MARGIN_X = 6; |
| +const int ADD_USER_BUTTON_HEIGHT = 20; |
| +const int EDIT_USER_BUTTON_WIDTH = 19; |
| +const int EDIT_USER_BUTTON_MARGIN_X = 3; |
| + |
| +inline int Round(double x) { |
| + return static_cast<int>(x + 0.5); |
| +} |
| + |
| +gfx::Rect GetCenteredAndScaledRect(int src_width, int src_height, |
| + int dst_x, int dst_y, |
| + int dst_width, int dst_height) { |
| + int scaled_width; |
| + int scaled_height; |
| + if (src_width > src_height) { |
| + scaled_width = std::min(src_width, dst_width); |
| + float scale = static_cast<float>(scaled_width) / |
| + static_cast<float>(src_width); |
| + scaled_height = Round(src_height * scale); |
| + } else { |
| + scaled_height = std::min(src_height, dst_height); |
| + float scale = static_cast<float>(scaled_height) / |
| + static_cast<float>(src_height); |
| + scaled_width = Round(src_width * scale); |
| + } |
| + int x = dst_x + (dst_width - scaled_width) / 2; |
| + int y = dst_y + (dst_height - scaled_height) / 2; |
| + return gfx::Rect(x, y, scaled_width, scaled_height); |
| +} |
| + |
| +class AddUserButton : public views::ImageButton { |
| + public: |
| + explicit AddUserButton(views::ButtonListener* listener) |
| + : views::ImageButton(listener) { |
|
Robert Sesek
2011/08/05 00:44:03
nit: indent 4
sail
2011/08/05 01:28:21
Done.
|
| + } |
| + |
| + virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { |
| + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| + int x = ICON_WIDTH + ICON_MARGIN_X; |
| + int w = width() - x; |
| + |
| + gfx::Font font(rb.GetFont(ResourceBundle::BaseFont)); |
| + font = font.DeriveFont(0, gfx::Font::UNDERLINED); |
| + |
| + canvas->DrawStringInt( |
| + l10n_util::GetStringUTF16(IDS_PROFILES_CREATE_NEW_PROFILE_LINK), font, |
| + SkColorSetRGB(0, 0x79, 0xda), x, 0, w, height()); |
| + } |
| +}; |
| + |
| +class ProfileItemView : public views::ImageButton { |
| + public: |
| + ProfileItemView(const AvatarMenuModel::Item& item, |
| + views::ButtonListener* listener) |
| + : views::ImageButton(listener), |
| + item_(item) { |
| + } |
| + |
| + void OnPaint(gfx::Canvas* canvas) { |
| + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| + |
| + // Draw the profile icon on the left. |
| + SkBitmap profile_icon = item_.icon; |
| + gfx::Rect profile_icon_rect = GetCenteredAndScaledRect( |
| + profile_icon.width(), profile_icon.height(), |
| + 0, 0, ICON_WIDTH, height()); |
| + canvas->DrawBitmapInt(profile_icon, 0, 0, profile_icon.width(), |
| + profile_icon.height(), profile_icon_rect.x(), |
| + profile_icon_rect.y(), profile_icon_rect.width(), |
| + profile_icon_rect.height(), false); |
| + |
| + // If this profile is selected then draw a check mark on the bottom right |
| + // of the profile icon. |
| + if (item_.active) { |
| + SkBitmap check_icon = *rb.GetBitmapNamed(IDR_PROFILE_SELECTED); |
|
Robert Sesek
2011/08/05 00:44:03
Use GetImageNamed()
sail
2011/08/05 01:28:21
Done.
|
| + int y = profile_icon_rect.bottom() - check_icon.height(); |
| + int x = profile_icon_rect.right() - check_icon.width() + 2; |
| + canvas->DrawBitmapInt(check_icon, 0, 0, check_icon.width(), |
| + check_icon.height(), x, y, check_icon.width(), |
| + check_icon.height(), false); |
| + } |
| + |
| + // Draw the profile name to the right of the profile icon. |
| + int name_x = profile_icon_rect.right() + ICON_MARGIN_X; |
| + canvas->DrawStringInt(item_.name, rb.GetFont(ResourceBundle::BaseFont), |
| + GetNameColor(), name_x, 0, width() - name_x, |
| + height()); |
| + } |
| + |
| + private: |
| + SkColor GetNameColor() { |
| + bool normal = state() != views::CustomButton::BS_PUSHED && |
| + state() != views::CustomButton::BS_HOT; |
| + if (item_.active) |
| + return normal ? SkColorSetRGB(30, 30, 30) : SkColorSetRGB(0, 0, 0); |
| + else |
| + return normal ? SkColorSetRGB(128, 128, 128) : SkColorSetRGB(64, 64, 64); |
| + } |
| + |
| + AvatarMenuModel::Item item_; |
| +}; |
| + |
| +} // namespace |
| + |
| +class EditUserButton : public views::ImageButton { |
| + public: |
| + EditUserButton(size_t profile_index, views::ButtonListener* listener) |
| + : views::ImageButton(listener), |
| + profile_index_(profile_index) { |
| + } |
| + |
| + size_t GetProfileIndex() { |
|
Robert Sesek
2011/08/05 00:44:03
profile_index()
sail
2011/08/05 01:28:21
Done.
|
| + return profile_index_; |
| + } |
| + |
| + private: |
| + size_t profile_index_; |
| +}; |
| + |
| +AvatarMenuBubbleView::AvatarMenuBubbleView(Browser* browser) |
| + : add_user_button_(NULL), |
| + browser_(browser), |
| + edit_user_button_(NULL) { |
| + avatar_menu_model_.reset(new AvatarMenuModel( |
| + &g_browser_process->profile_manager()->GetProfileInfoCache(), |
| + this, browser_)); |
| + |
| + size_t active_profile_index = 0; |
|
Robert Sesek
2011/08/05 00:44:03
Move this into OnAvatarMenuModelChanged(). That wi
sail
2011/08/05 01:28:21
Done.
sail
2011/08/05 01:28:21
Done.
|
| + for (size_t i = 0; i < avatar_menu_model_->GetNumberOfItems(); ++i) { |
| + const AvatarMenuModel::Item& item = avatar_menu_model_->GetItemAt(i); |
| + ProfileItemView* item_view = new ProfileItemView(item, this); |
| + AddChildView(item_view); |
| + item_views_.push_back(item_view); |
| + |
| + if (item.active) |
| + active_profile_index = i; |
| + } |
| + |
| + add_user_button_ = new AddUserButton(this); |
| + AddChildView(add_user_button_); |
| + |
| + edit_user_button_ = new EditUserButton(active_profile_index, this); |
| + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| + edit_user_button_->SetImage(views::CustomButton::BS_NORMAL, |
| + rb.GetBitmapNamed(IDR_PROFILE_EDIT)); |
|
Robert Sesek
2011/08/05 00:44:03
GetImageNamed() here and throughout
sail
2011/08/05 01:28:21
Done.
|
| + edit_user_button_->SetImage(views::CustomButton::BS_HOT, |
| + rb.GetBitmapNamed(IDR_PROFILE_EDIT_HOVER)); |
| + edit_user_button_->SetImage(views::CustomButton::BS_PUSHED, |
| + rb.GetBitmapNamed(IDR_PROFILE_EDIT_PRESSED)); |
| + edit_user_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER, |
| + views::ImageButton::ALIGN_MIDDLE); |
| + AddChildView(edit_user_button_); |
| +} |
| + |
| +AvatarMenuBubbleView::~AvatarMenuBubbleView() { |
| +} |
| + |
| +gfx::Size AvatarMenuBubbleView::GetPreferredSize() { |
| + return gfx::Size(ITEM_WIDTH, (ITEM_HEIGHT + ITEM_MARGIN_Y) * |
| + item_views_.size() + ADD_USER_BUTTON_HEIGHT); |
| +} |
| + |
| +void AvatarMenuBubbleView::Layout() { |
| + int item_width = width() - EDIT_USER_BUTTON_WIDTH - EDIT_USER_BUTTON_MARGIN_X; |
| + |
| + for (size_t i = 0; i < item_views_.size(); ++i) { |
| + views::ImageButton* item_view = item_views_[i]; |
| + int y = (ITEM_HEIGHT + ITEM_MARGIN_Y) * i; |
| + item_view->SetBounds(0, y, item_width, ITEM_HEIGHT); |
| + } |
| + |
| + int y = (ITEM_HEIGHT + ITEM_MARGIN_Y) * item_views_.size(); |
| + add_user_button_->SetBounds(0, y, width(), ADD_USER_BUTTON_HEIGHT); |
| + |
| + y = (ITEM_HEIGHT + ITEM_MARGIN_Y) * edit_user_button_->GetProfileIndex(); |
| + edit_user_button_->SetBounds(width() - EDIT_USER_BUTTON_WIDTH, y, |
| + EDIT_USER_BUTTON_WIDTH, ITEM_HEIGHT); |
| +} |
| + |
| +void AvatarMenuBubbleView::ButtonPressed(views::Button* sender, |
| + const views::Event& event) { |
| + if (sender == add_user_button_) { |
| + avatar_menu_model_->AddNewProfile(); |
| + } else if (sender == edit_user_button_) { |
| + avatar_menu_model_->EditProfile(edit_user_button_->GetProfileIndex()); |
| + } else { |
| + for (size_t i = 0; i < item_views_.size(); ++i) { |
| + if (sender == item_views_[i]) { |
| + avatar_menu_model_->SwitchToProfile(i); |
| + break; |
| + } |
| + } |
| + } |
| +} |
| + |
| +void AvatarMenuBubbleView::BubbleClosing(Bubble* bubble, |
| + bool closed_by_escape) { |
| +} |
| + |
| +bool AvatarMenuBubbleView::CloseOnEscape() { |
| + return true; |
| +} |
| + |
| +bool AvatarMenuBubbleView::FadeInOnShow() { |
| + return false; |
| +} |
| + |
| +void AvatarMenuBubbleView::OnAvatarMenuModelChanged() { |
| +} |