Commit bb0d7560 authored by sail@chromium.org's avatar sail@chromium.org

Multi-Profiles: Change avatar menu to bubble view

BUG=
TEST=Ran on views and verified that things looked ok.

Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=96306

Review URL: http://codereview.chromium.org/7566050

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@96311 0039d316-1c4b-4281-b951-d872f2087c98
parent dee7ab58
......@@ -8375,6 +8375,15 @@ Keep your key file in a safe place. You will need it to create new versions of y
New User
</message>
</if>
<message name="IDS_PROFILES_CREATE_NEW_PROFILE_LINK" desc="Link in the avatar menu bubble view to create a new profile.">
New user
</message>
<message name="IDS_PROFILES_CUSTOMIZE_PROFILE_ACCESSIBLE_NAME" desc="Description of the customize profile button. This is used for accessibility.">
Customize user: <ph name="PROFILE_NAME">$1<ex>First user</ex></ph>
</message>
<message name="IDS_PROFILES_SWITCH_TO_PROFILE_ACCESSIBLE_NAME" desc="Description of the switch to profile button. This is used for accessibility.">
Switch to user: <ph name="PROFILE_NAME">$1<ex>First user</ex></ph>
</message>
<if expr="not pp_ifdef('use_titlecase')">
<message name="IDS_PROFILES_MENU" desc="The title of the profiles submenu in the wrench menu.">
Users
......
......@@ -232,6 +232,10 @@
<include name="IDR_PROFILE_AVATAR_23" file="profile_avatar_margarita.png" type="BINDATA" />
<include name="IDR_PROFILE_AVATAR_24" file="profile_avatar_note.png" type="BINDATA" />
<include name="IDR_PROFILE_AVATAR_25" file="profile_avatar_sun_cloud.png" type="BINDATA" />
<include name="IDR_PROFILE_EDIT" file="profile_edit.png" type="BINDATA" />
<include name="IDR_PROFILE_EDIT_HOVER" file="profile_edit_hover.png" type="BINDATA" />
<include name="IDR_PROFILE_EDIT_PRESSED" file="profile_edit_pressed.png" type="BINDATA" />
<include name="IDR_PROFILE_SELECTED" file="profile_selected.png" type="BINDATA" />
<include name="IDR_RESTORE_BUTTON_MASK" file="restore_button_mask.png" type="BINDATA" />
<include name="IDR_SAD_TAB" file="sadtab.png" type="BINDATA" />
<include name="IDR_SAFEBROWSING_WARNING" file="safebrowsing_warning.png" type="BINDATA" />
......
......@@ -70,7 +70,7 @@ AvatarMenuModel::Item::Item(size_t model_index, const gfx::Image& icon)
AvatarMenuModel::Item::~Item() {
}
void AvatarMenuModel::SwichToProfile(size_t index) {
void AvatarMenuModel::SwitchToProfile(size_t index) {
const Item& item = GetItemAt(index);
FilePath path = profile_info_->GetPathOfProfileAtIndex(item.model_index);
......@@ -119,7 +119,7 @@ void AvatarMenuModel::RebuildMenu() {
items_.push_back(item);
}
observer_->OnAvatarMenuModelChanged();
observer_->OnAvatarMenuModelChanged(this);
}
void AvatarMenuModel::ClearMenu() {
......
......@@ -59,7 +59,7 @@ class AvatarMenuModel : public NotificationObserver {
// model:
// Opens a Browser with the specified profile in response to the user
// selecting an item.
void SwichToProfile(size_t index);
void SwitchToProfile(size_t index);
// Opens the profile settings in response to clicking the edit button next to
// an item.
void EditProfile(size_t index);
......
......@@ -5,13 +5,15 @@
#ifndef CHROME_BROWSER_PROFILES_AVATAR_MENU_MODEL_OBSERVER_H_
#define CHROME_BROWSER_PROFILES_AVATAR_MENU_MODEL_OBSERVER_H_
class AvatarMenuModel;
// Delegate interface for objects that want to be notified when the
// AvatarMenuModel changes.
class AvatarMenuModelObserver {
public:
virtual ~AvatarMenuModelObserver() {}
virtual void OnAvatarMenuModelChanged() = 0;
virtual void OnAvatarMenuModelChanged(AvatarMenuModel* avatar_menu_model) = 0;
};
#endif // CHROME_BROWSER_PROFILES_AVATAR_MENU_MODEL_OBSERVER_H_
......@@ -57,7 +57,7 @@ class MockObserver : public AvatarMenuModelObserver {
MockObserver() : count_(0) {}
virtual ~MockObserver() {}
virtual void OnAvatarMenuModelChanged() {
virtual void OnAvatarMenuModelChanged(AvatarMenuModel* avatar_menu_model) {
++count_;
}
......
// 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.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/profile_menu_model.h"
#include "grit/chromium_strings.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/image/image.h"
#include "views/controls/button/image_button.h"
#include "views/controls/button/menu_button.h"
#include "views/controls/menu/menu_item_view.h"
#include "views/controls/menu/submenu_view.h"
#include "views/widget/widget.h"
namespace {
const int kCellWidth = 38;
const int kCellHeight = 31;
const int kCellPaddingX = 5;
const int kCellPaddingY = 5;
const int kGridMaxCol = 3;
static inline int Round(double x) {
return static_cast<int>(x + 0.5);
}
// This is an button that scales its image to fit its bounds.
class ScaledImageButton : public views::ImageButton {
public:
explicit ScaledImageButton(views::ButtonListener* listener);
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(ScaledImageButton);
};
// A view that displays avatar icons in a grid.
class AvatarIconGridView : public views::View, public views::ButtonListener {
public:
AvatarIconGridView(Profile* profile, views::MenuItemView* menu);
virtual ~AvatarIconGridView();
virtual void Layout() OVERRIDE;
virtual gfx::Size GetPreferredSize() OVERRIDE;
virtual void ButtonPressed(views::Button* sender,
const views::Event& event) OVERRIDE;
private:
// Sets the profile's avatar icon to the icon at the given index.
void SetAvatarIconToIndex(int icon_index);
typedef std::map<int, views::View*> IconIndexToButtonMap;
IconIndexToButtonMap icon_index_to_button_map_;
Profile* profile_;
views::MenuItemView* menu_;
DISALLOW_COPY_AND_ASSIGN(AvatarIconGridView);
};
ScaledImageButton::ScaledImageButton(views::ButtonListener* listener)
: views::ImageButton(listener) {
}
void ScaledImageButton::OnPaint(gfx::Canvas* canvas) {
if (state() == views::CustomButton::BS_HOT)
canvas->FillRectInt(SkColorSetARGB(20, 0, 0, 0), 0, 0, width(), height());
else if (state() == views::CustomButton::BS_PUSHED)
canvas->FillRectInt(SkColorSetARGB(40, 0, 0, 0), 0, 0, width(), height());
const SkBitmap& icon = GetImageToPaint();
if (icon.isNull())
return;
int dst_width;
int dst_height;
if (icon.width() > icon.height()) {
dst_width = std::min(width(), icon.width());
float scale = static_cast<float>(dst_width) /
static_cast<float>(icon.width());
dst_height = Round(icon.height() * scale);
} else {
dst_height = std::min(height(), icon.height());
float scale = static_cast<float>(dst_height) /
static_cast<float>(icon.height());
dst_width = Round(icon.width() * scale);
}
int dst_x = (width() - dst_width) / 2;
int dst_y = (height() - dst_height) / 2;
canvas->DrawBitmapInt(icon, 0, 0, icon.width(), icon.height(),
dst_x, dst_y, dst_width, dst_height, false);
}
AvatarIconGridView::AvatarIconGridView(Profile* profile,
views::MenuItemView* menu)
: profile_(profile),
menu_(menu) {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
for (size_t i = 0; i < ProfileInfoCache::GetDefaultAvatarIconCount(); ++i) {
int resource_id =
ProfileInfoCache::GetDefaultAvatarIconResourceIDAtIndex(i);
views::ImageButton* button = new ScaledImageButton(this);
button->SetImage(views::CustomButton::BS_NORMAL,
rb.GetImageNamed(resource_id));
button->SetAccessibleName(
l10n_util::GetStringFUTF16Int(IDS_NUMBERED_AVATAR_NAME,
static_cast<int>(i + 1)));
AddChildView(button);
icon_index_to_button_map_[i] = button;
}
}
AvatarIconGridView::~AvatarIconGridView() {
}
void AvatarIconGridView::Layout() {
for (IconIndexToButtonMap::const_iterator it =
icon_index_to_button_map_.begin();
it != icon_index_to_button_map_.end(); ++it) {
views::View* view = it->second;
int icon_index = it->first;
int col = icon_index % kGridMaxCol;
int row = icon_index / kGridMaxCol;
int x = col * kCellWidth + col * kCellPaddingX;
int y = row * kCellHeight + row * kCellPaddingY;
view->SetBounds(x, y, kCellWidth, kCellHeight);
}
}
gfx::Size AvatarIconGridView::GetPreferredSize() {
int cols = kGridMaxCol;
int rows = ProfileInfoCache::GetDefaultAvatarIconCount() / cols;
if (ProfileInfoCache::GetDefaultAvatarIconCount() % cols != 0)
rows++;
return gfx::Size(cols * kCellWidth + (cols - 1) * kCellPaddingX,
rows * kCellHeight + (rows - 1) * kCellPaddingY);
}
void AvatarIconGridView::ButtonPressed(views::Button* sender,
const views::Event& event) {
for (IconIndexToButtonMap::const_iterator it =
icon_index_to_button_map_.begin();
it != icon_index_to_button_map_.end(); ++it) {
if (it->second == sender) {
SetAvatarIconToIndex(it->first);
menu_->Cancel();
return;
}
}
NOTREACHED();
}
void AvatarIconGridView::SetAvatarIconToIndex(int icon_index) {
ProfileInfoCache& cache =
g_browser_process->profile_manager()->GetProfileInfoCache();
size_t profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath());
cache.SetAvatarIconOfProfileAtIndex(profile_index, icon_index);
}
} // namespace
AvatarMenu::AvatarMenu(ui::MenuModel* model, Profile* profile)
: MenuModelAdapter(model),
profile_(profile) {
root_.reset(new views::MenuItemView(this));
BuildMenu(root_.get());
views::MenuItemView* item =
root_->GetMenuItemByID(ProfileMenuModel::COMMAND_CHOOSE_AVATAR_ICON);
item->AddChildView(new AvatarIconGridView(profile_, root_.get()));
}
AvatarMenu::~AvatarMenu() {
}
void AvatarMenu::RunMenu(views::MenuButton* host) {
// Up the ref count while the menu is displaying. This way if the window is
// deleted while we're running we won't prematurely delete the menu.
// TODO(sky): fix this, the menu should really take ownership of the menu
// (57890).
scoped_refptr<AvatarMenu> dont_delete_while_running(this);
gfx::Point screen_loc;
views::View::ConvertPointToScreen(host, &screen_loc);
gfx::Rect bounds(screen_loc, host->size());
root_->RunMenuAt(host->GetWidget(), host, bounds,
views::MenuItemView::TOPLEFT, true);
}
// 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.
#ifndef CHROME_BROWSER_UI_VIEWS_AVATAR_MENU_H_
#define CHROME_BROWSER_UI_VIEWS_AVATAR_MENU_H_
#pragma once
#include <map>
#include <utility>
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "ui/base/models/menu_model.h"
#include "views/controls/menu/menu_model_adapter.h"
class Profile;
class AvatarMenu : public base::RefCounted<AvatarMenu>,
public views::MenuModelAdapter {
public:
AvatarMenu(ui::MenuModel* model, Profile* profile);
virtual ~AvatarMenu();
// Shows the menu relative to the specified view.
void RunMenu(views::MenuButton* host);
private:
// The views menu.
scoped_ptr<views::MenuItemView> root_;
// Profile the menu is being shown for.
Profile* profile_;
DISALLOW_COPY_AND_ASSIGN(AvatarMenu);
};
#endif // CHROME_BROWSER_UI_VIEWS_AVATAR_MENU_H_
// 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 "base/utf_string_conversions.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"
#include "views/controls/button/image_button.h"
namespace {
const int kBubbleViewMinWidth = 175;
const int kBubbleViewMaxWidth = 800;
const int kItemHeight = 32;
const int kItemMarginY = 8;
const int kIconWidth = 38;
const int kIconMarginX = 6;
const int kEditProfileButtonMarginX = 8;
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 ProfileItemView : public views::CustomButton {
public:
ProfileItemView(const AvatarMenuModel::Item& item,
views::ButtonListener* listener)
: views::CustomButton(listener),
item_(item) {
}
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
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, kIconWidth, 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.GetImageNamed(IDR_PROFILE_SELECTED);
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() + kIconMarginX;
canvas->DrawStringInt(item_.name, rb.GetFont(ResourceBundle::BaseFont),
GetNameColor(), name_x, 0, width() - name_x,
height());
}
virtual gfx::Size GetPreferredSize() OVERRIDE {
gfx::Font font = ResourceBundle::GetSharedInstance().GetFont(
ResourceBundle::BaseFont);
int title_width = font.GetStringWidth(item_.name);
return gfx::Size(kIconWidth + kIconMarginX + title_width, kItemHeight);
}
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);
return normal ? SkColorSetRGB(128, 128, 128) : SkColorSetRGB(64, 64, 64);
}
AvatarMenuModel::Item item_;
};
} // namespace
class EditProfileButton : public views::ImageButton {
public:
EditProfileButton(size_t profile_index, views::ButtonListener* listener)
: views::ImageButton(listener),
profile_index_(profile_index) {
}
size_t profile_index() {
return profile_index_;
}
private:
size_t profile_index_;
};
AvatarMenuBubbleView::AvatarMenuBubbleView(Browser* browser)
: add_profile_link_(NULL),
browser_(browser),
edit_profile_button_(NULL) {
avatar_menu_model_.reset(new AvatarMenuModel(
&g_browser_process->profile_manager()->GetProfileInfoCache(),
this, browser_));
}
AvatarMenuBubbleView::~AvatarMenuBubbleView() {
}
gfx::Size AvatarMenuBubbleView::GetPreferredSize() {
int max_width = 0;
int total_height = 0;
for (size_t i = 0; i < item_views_.size(); ++i) {
gfx::Size size = item_views_[i]->GetPreferredSize();
if (i == edit_profile_button_->profile_index()) {
size.set_width(size.width() +
edit_profile_button_->GetPreferredSize().width() +
kEditProfileButtonMarginX);
}
max_width = std::max(max_width, size.width());
total_height += size.height() + kItemMarginY;
}
gfx::Size add_profile_size = add_profile_link_->GetPreferredSize();
max_width = std::max(max_width,
add_profile_size.width() + kIconWidth + kIconMarginX);
total_height += add_profile_link_->GetPreferredSize().height();
int total_width = std::min(std::max(max_width, kBubbleViewMinWidth),
kBubbleViewMaxWidth);
return gfx::Size(total_width, total_height);
}
void AvatarMenuBubbleView::Layout() {
int y = 0;
for (size_t i = 0; i < item_views_.size(); ++i) {
views::CustomButton* item_view = item_views_[i];
int item_height = item_view->GetPreferredSize().height();
int item_width = width();
if (i == edit_profile_button_->profile_index()) {
gfx::Size edit_size = edit_profile_button_->GetPreferredSize();
edit_profile_button_->SetBounds(width() - edit_size.width(), y,
edit_size.width(), item_height);
item_width -= edit_size.width() + kEditProfileButtonMarginX;
}
item_view->SetBounds(0, y, item_width, item_height);
y += item_height + kItemMarginY;
}
add_profile_link_->SetBounds(kIconWidth + kIconMarginX, y, width(),
add_profile_link_->GetPreferredSize().height());
}
void AvatarMenuBubbleView::ButtonPressed(views::Button* sender,
const views::Event& event) {
if (sender == edit_profile_button_) {
avatar_menu_model_->EditProfile(edit_profile_button_->profile_index());
} else {
for (size_t i = 0; i < item_views_.size(); ++i) {
if (sender == item_views_[i]) {
avatar_menu_model_->SwitchToProfile(i);
break;
}
}
}
}
void AvatarMenuBubbleView::LinkClicked(views::Link* source, int event_flags) {
DCHECK_EQ(source, add_profile_link_);
avatar_menu_model_->AddNewProfile();
}
void AvatarMenuBubbleView::BubbleClosing(Bubble* bubble,
bool closed_by_escape) {
}
bool AvatarMenuBubbleView::CloseOnEscape() {
return true;
}
bool AvatarMenuBubbleView::FadeInOnShow() {
return false;
}
void AvatarMenuBubbleView::OnAvatarMenuModelChanged(
AvatarMenuModel* avatar_menu_model) {
// Unset all our child view references and call RemoveAllChildViews() which
// will actually delete them.
add_profile_link_ = NULL;
edit_profile_button_ = NULL;
item_views_.clear();
RemoveAllChildViews(true);
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);
item_view->SetAccessibleName(l10n_util::GetStringFUTF16(
IDS_PROFILES_SWITCH_TO_PROFILE_ACCESSIBLE_NAME, item.name));
AddChildView(item_view);
item_views_.push_back(item_view);
if (item.active) {
DCHECK(!edit_profile_button_);
edit_profile_button_ = new EditProfileButton(i, this);
edit_profile_button_->SetAccessibleName(l10n_util::GetStringFUTF16(
IDS_PROFILES_CUSTOMIZE_PROFILE_ACCESSIBLE_NAME, item.name));
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
edit_profile_button_->SetImage(views::CustomButton::BS_NORMAL,
rb.GetImageNamed(IDR_PROFILE_EDIT));
edit_profile_button_->SetImage(views::CustomButton::BS_HOT,
rb.GetImageNamed(IDR_PROFILE_EDIT_HOVER));
edit_profile_button_->SetImage(views::CustomButton::BS_PUSHED,
rb.GetImageNamed(IDR_PROFILE_EDIT_PRESSED));
edit_profile_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
views::ImageButton::ALIGN_MIDDLE);
AddChildView(edit_profile_button_);
}
}
add_profile_link_ = new views::Link(UTF16ToWide(
l10n_util::GetStringUTF16(IDS_PROFILES_CREATE_NEW_PROFILE_LINK)));
add_profile_link_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
add_profile_link_->SetNormalColor(SkColorSetRGB(0, 0x79, 0xda));
AddChildView(add_profile_link_);
PreferredSizeChanged();
}
// 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.
#ifndef CHROME_BROWSER_UI_VIEWS_AVATAR_MENU_BUBBLE_VIEW_H_
#define CHROME_BROWSER_UI_VIEWS_AVATAR_MENU_BUBBLE_VIEW_H_
#pragma once
#include <vector>
#include "chrome/browser/profiles/avatar_menu_model_observer.h"
#include "chrome/browser/ui/views/bubble/bubble.h"
#include "views/controls/button/custom_button.h"
#include "views/controls/link.h"
#include "views/controls/link_listener.h"
class AvatarMenuModel;
class Browser;
class EditProfileButton;
// This bubble view is displayed when the user clicks on the avatar button.
// It displays a list of profiles and allows users to switch between profiles.
class AvatarMenuBubbleView : public views::View,
public views::ButtonListener,
public views::LinkListener,
public BubbleDelegate,
public AvatarMenuModelObserver {
public:
explicit AvatarMenuBubbleView(Browser* browser);
~AvatarMenuBubbleView();
// views::View implementation.
virtual gfx::Size GetPreferredSize() OVERRIDE;
virtual void Layout() OVERRIDE;
// views::ButtonListener implementation.
virtual void ButtonPressed(views::Button* sender,
const views::Event& event) OVERRIDE;
// views::LinkListener implementation.
virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE;
// BubbleDelegate implementation.
virtual void BubbleClosing(Bubble* bubble, bool closed_by_escape) OVERRIDE;
virtual bool CloseOnEscape() OVERRIDE;
virtual bool FadeInOnShow() OVERRIDE;
// AvatarMenuModelObserver implementation.
virtual void OnAvatarMenuModelChanged(
AvatarMenuModel* avatar_menu_model) OVERRIDE;
private:
views::Link* add_profile_link_;
scoped_ptr<AvatarMenuModel> avatar_menu_model_;
Browser* browser_;
EditProfileButton* edit_profile_button_;
std::vector<views::CustomButton*> item_views_;
DISALLOW_COPY_AND_ASSIGN(AvatarMenuBubbleView);
};
#endif // CHROME_BROWSER_UI_VIEWS_AVATAR_MENU_BUBBLE_VIEW_H_
......@@ -6,7 +6,8 @@
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/profile_menu_model.h"
#include "chrome/browser/ui/views/avatar_menu.h"
#include "chrome/browser/ui/views/avatar_menu_bubble_view.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "ui/gfx/canvas_skia.h"
#include "views/widget/widget.h"
......@@ -62,9 +63,16 @@ void AvatarMenuButton::RunMenu(views::View* source, const gfx::Point& pt) {
if (!has_menu_)
return;
menu_model_.reset(new ProfileMenuModel(browser_));
// The avatar menu will automatically delete itself when done.
AvatarMenu* avatar_menu =
new AvatarMenu(menu_model_.get(), browser_->profile());
avatar_menu->RunMenu(this);
BrowserView* browser_view = BrowserView::GetBrowserViewForNativeWindow(
browser_->window()->GetNativeHandle());
gfx::Point origin;
views::View::ConvertPointToScreen(this, &origin);
gfx::Rect bounds(0, 0, width(), height());
bounds.set_origin(origin);
AvatarMenuBubbleView* bubble_view = new AvatarMenuBubbleView(browser_);
// Bubble::Show() takes ownership of the view.
Bubble::Show(browser_view->GetWidget(), bounds, BubbleBorder::TOP_LEFT,
bubble_view, bubble_view);
}
......@@ -3081,8 +3081,8 @@
'browser/ui/views/autocomplete/autocomplete_result_view_model.h',
'browser/ui/views/autocomplete/touch_autocomplete_popup_contents_view.cc',
'browser/ui/views/autocomplete/touch_autocomplete_popup_contents_view.h',
'browser/ui/views/avatar_menu.cc',
'browser/ui/views/avatar_menu.h',
'browser/ui/views/avatar_menu_bubble_view.cc',
'browser/ui/views/avatar_menu_bubble_view.h',
'browser/ui/views/avatar_menu_button.cc',
'browser/ui/views/avatar_menu_button.h',
'browser/ui/views/bookmarks/bookmark_bar_instructions_view.cc',
......@@ -4342,8 +4342,8 @@
['include', '^browser/ui/views/autocomplete/autocomplete_result_view_model.h'],
['include', '^browser/ui/views/autocomplete/touch_autocomplete_popup_contents_view.cc'],
['include', '^browser/ui/views/autocomplete/touch_autocomplete_popup_contents_view.h'],
['include', '^browser/ui/views/avatar_menu.cc'],
['include', '^browser/ui/views/avatar_menu.h'],
['include', '^browser/ui/views/avatar_menu_bubble_view.cc'],
['include', '^browser/ui/views/avatar_menu_bubble_view.h'],
['include', '^browser/ui/views/avatar_menu_button.cc'],
['include', '^browser/ui/views/avatar_menu_button.h'],
['include', '^browser/ui/views/bookmarks/bookmark_bar_instructions_view.cc'],
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment