diff options
author | mirandac@chromium.org <mirandac@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-08 20:25:58 +0000 |
---|---|---|
committer | mirandac@chromium.org <mirandac@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-08 20:25:58 +0000 |
commit | 538d5e25ac26fd0ad8a9bd3c88713ef9de171ec1 (patch) | |
tree | 1329817add6c62c904b65505b3634034a721b373 | |
parent | 9958a32c22a0a5ae4ec33fbb96e3ce6f46cfc058 (diff) | |
download | chromium_src-538d5e25ac26fd0ad8a9bd3c88713ef9de171ec1.zip chromium_src-538d5e25ac26fd0ad8a9bd3c88713ef9de171ec1.tar.gz chromium_src-538d5e25ac26fd0ad8a9bd3c88713ef9de171ec1.tar.bz2 |
SUMMARY: Create dropdown menu button on Windows Aero frame to be displayed when the user is synced. This is the first step in the multi-profile UI implementation on Windows. The displayed tag consists of two parts:
1. A profile menu button with invisible border and background consisting of text and a dropdown arrow.
2. A tag image displayed on the browser frame beneath the profile menu button.
DETAILED CL DESCRIPTION:
1. Changes to the frame and view
* glass_browser_frame_view
adds the profile_menu button to the frame, along with methods for laying it out, and watching for user name changes.
2. New profile menu button
* profile_menu_button
sets up the actual menu button itself, and provides the method PaintProfileTag that draws the underlying tag image on the browser frame. a better way to do this might be to create a new kind of menu button that combines methods from ImageButton as well as TextButton -- but maybe that's overkill?
Review URL: http://codereview.chromium.org/6490022
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@77324 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/ui/views/frame/glass_browser_frame_view.cc | 94 | ||||
-rw-r--r-- | chrome/browser/ui/views/frame/glass_browser_frame_view.h | 40 | ||||
-rw-r--r-- | chrome/browser/ui/views/profile_menu_button.cc | 54 | ||||
-rw-r--r-- | chrome/browser/ui/views/profile_menu_button.h | 45 | ||||
-rw-r--r-- | chrome/browser/ui/views/profile_tag_view.cc | 92 | ||||
-rw-r--r-- | chrome/browser/ui/views/profile_tag_view.h | 65 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 4 |
7 files changed, 393 insertions, 1 deletions
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc index 98dc9e7..dc20ee8 100644 --- a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc +++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc @@ -4,13 +4,23 @@ #include "chrome/browser/ui/views/frame/glass_browser_frame_view.h" +#include "base/command_line.h" +#include "base/utf_string_conversions.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/app/chrome_dll_resource.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/themes/browser_theme_provider.h" #include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/profile_menu_button.h" +#include "chrome/browser/ui/views/profile_menu_model.h" +#include "chrome/browser/ui/views/profile_tag_view.h" #include "chrome/browser/ui/views/tabs/side_tab_strip.h" #include "chrome/browser/ui/views/tabs/tab.h" #include "chrome/browser/ui/views/tabs/tab_strip.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/pref_names.h" #include "grit/app_resources.h" #include "grit/theme_resources.h" #include "ui/base/resource/resource_bundle.h" @@ -54,6 +64,11 @@ const int kNewTabCaptionRestoredSpacing = 5; // similar vertical coordinates, we need to reserve a larger, 16 px gap to avoid // looking too cluttered. const int kNewTabCaptionMaximizedSpacing = 16; +// Menu should display below the profile button tag image on the frame. This +// offset size depends on whether the frame is in glass or opaque mode. +const int kMenuDisplayOffset = 7; +// Y position for profile button inside the frame. +const int kProfileButtonYPosition = 2; } /////////////////////////////////////////////////////////////////////////////// @@ -68,6 +83,20 @@ GlassBrowserFrameView::GlassBrowserFrameView(BrowserFrame* frame, throbber_frame_(0) { if (frame_->GetWindow()->window_delegate()->ShouldShowWindowIcon()) InitThrobberIcons(); + // If multi-profile is enabled set up profile button and login notifications. + const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); + if (browser_command_line.HasSwitch(switches::kMultiProfiles) && + !browser_view->ShouldShowOffTheRecordAvatar()) { + RegisterLoginNotifications(); + profile_button_.reset(new views::ProfileMenuButton(NULL, std::wstring(), + this)); + profile_button_->SetVisible(false); + profile_tag_.reset(new views::ProfileTagView(frame_, + profile_button_.get())); + profile_tag_->SetVisible(false); + AddChildView(profile_tag_.get()); + AddChildView(profile_button_.get()); + } } GlassBrowserFrameView::~GlassBrowserFrameView() { @@ -180,6 +209,11 @@ int GlassBrowserFrameView::NonClientHitTest(const gfx::Point& point) { if (frame_component != HTNOWHERE) return frame_component; + // See if the point is within the profile menu button. + if (show_profile_button() && profile_button_->IsVisible() && + profile_button_->GetMirroredBounds().Contains(point)) + return HTCLIENT; + int frame_border_thickness = FrameBorderThickness(); int window_component = GetHTComponentForFrame(point, frame_border_thickness, nonclient_border_thickness, frame_border_thickness, @@ -190,6 +224,16 @@ int GlassBrowserFrameView::NonClientHitTest(const gfx::Point& point) { } /////////////////////////////////////////////////////////////////////////////// +// GlassBrowserFrameView, views::ViewMenuDelegate implementation: +void GlassBrowserFrameView::RunMenu(views::View *source, const gfx::Point &pt) { + if (profile_menu_model_ == NULL) + profile_menu_model_.reset(new views::ProfileMenuModel); + gfx::Point menu_point(pt.x(), + pt.y() + kMenuDisplayOffset); + profile_menu_model_->RunMenuAt(menu_point); +} + +/////////////////////////////////////////////////////////////////////////////// // GlassBrowserFrameView, views::View overrides: void GlassBrowserFrameView::OnPaint(gfx::Canvas* canvas) { @@ -206,6 +250,7 @@ void GlassBrowserFrameView::OnPaint(gfx::Canvas* canvas) { void GlassBrowserFrameView::Layout() { LayoutOTRAvatar(); LayoutClientView(); + LayoutProfileTag(); } /////////////////////////////////////////////////////////////////////////////// @@ -440,6 +485,40 @@ void GlassBrowserFrameView::LayoutClientView() { client_view_bounds_ = CalculateClientAreaBounds(width(), height()); } +void GlassBrowserFrameView::LayoutProfileTag() { + if (!show_profile_button()) + return; + + string16 profile_name = ASCIIToUTF16(browser_view_->browser()->profile()-> + GetPrefs()->GetString(prefs::kGoogleServicesUsername)); + if (!profile_name.empty()) { + profile_button_->SetText(profile_name); + profile_button_->ClearMaxTextSize(); + profile_button_->SetVisible(true); + int x_tag = + // The x position of minimize button in the frame + frame_->GetMinimizeButtonOffset() - + // - the space between the minimize button and the profile button + views::ProfileMenuButton::kProfileTagHorizontalSpacing - + // - the width of the profile button + profile_button_->GetPreferredSize().width(); + profile_button_->SetBounds( + x_tag, + kProfileButtonYPosition, + profile_button_->GetPreferredSize().width(), + profile_button_->GetPreferredSize().height()); + profile_tag_->SetVisible(true); + profile_tag_->SetBounds( + x_tag, + 1, + profile_button_->GetPreferredSize().width(), + views::ProfileTagView::kProfileTagHeight); + } else { + profile_button_->SetVisible(false); + profile_tag_->SetVisible(false); + } +} + gfx::Rect GlassBrowserFrameView::CalculateClientAreaBounds(int width, int height) const { if (!browser_view_->IsTabStripVisible()) @@ -498,6 +577,21 @@ void GlassBrowserFrameView::DisplayNextThrobberFrame() { reinterpret_cast<LPARAM>(throbber_icons_[throbber_frame_])); } +void GlassBrowserFrameView::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + DCHECK_EQ(NotificationType::PREF_CHANGED, type.value); + std::string* name = Details<std::string>(details).ptr(); + if (prefs::kGoogleServicesUsername == *name) + LayoutProfileTag(); +} + +void GlassBrowserFrameView::RegisterLoginNotifications() { + PrefService* pref_service = browser_view_->browser()->profile()->GetPrefs(); + DCHECK(pref_service); + username_pref_.Init(prefs::kGoogleServicesUsername, pref_service, this); +} + // static void GlassBrowserFrameView::InitThrobberIcons() { static bool initialized = false; diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.h b/chrome/browser/ui/views/frame/glass_browser_frame_view.h index 331071e..937012d 100644 --- a/chrome/browser/ui/views/frame/glass_browser_frame_view.h +++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.h @@ -6,15 +6,26 @@ #define CHROME_BROWSER_UI_VIEWS_FRAME_GLASS_BROWSER_FRAME_VIEW_H_ #pragma once +#include "base/scoped_ptr.h" +#include "chrome/browser/prefs/pref_member.h" #include "chrome/browser/ui/views/frame/browser_frame_win.h" #include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h" #include "views/controls/button/button.h" +#include "views/controls/menu/view_menu_delegate.h" #include "views/window/non_client_view.h" class BrowserView; class SkBitmap; -class GlassBrowserFrameView : public BrowserNonClientFrameView { +namespace views { +class ProfileMenuButton; +class ProfileMenuModel; +class ProfileTagView; +} + +class GlassBrowserFrameView : public BrowserNonClientFrameView, + public NotificationObserver, + public views::ViewMenuDelegate { public: // Constructs a non-client view for an BrowserFrame. GlassBrowserFrameView(BrowserFrame* frame, BrowserView* browser_view); @@ -35,6 +46,9 @@ class GlassBrowserFrameView : public BrowserNonClientFrameView { virtual void EnableClose(bool enable) { } virtual void ResetWindowControls() { } + // views::ViewMenuDelegate implementation: + virtual void RunMenu(views::View* source, const gfx::Point& pt) OVERRIDE; + protected: // Overridden from views::View: virtual void OnPaint(gfx::Canvas* canvas); @@ -64,6 +78,7 @@ class GlassBrowserFrameView : public BrowserNonClientFrameView { // Layout various sub-components of this view. void LayoutOTRAvatar(); void LayoutClientView(); + void LayoutProfileTag(); // Returns the bounds of the client area for the specified view size. gfx::Rect CalculateClientAreaBounds(int width, int height) const; @@ -75,6 +90,17 @@ class GlassBrowserFrameView : public BrowserNonClientFrameView { // Displays the next throbber frame. void DisplayNextThrobberFrame(); + // NotificationObserver implementation: + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) OVERRIDE; + + // Receive notifications when the user's Google services user name changes. + void RegisterLoginNotifications(); + + // Returns true if the ProfileButton has been created. + bool show_profile_button() const { return profile_button_.get() != NULL; } + // The layout rect of the OTR avatar icon, if visible. gfx::Rect otr_avatar_bounds_; @@ -87,12 +113,24 @@ class GlassBrowserFrameView : public BrowserNonClientFrameView { // The bounds of the ClientView. gfx::Rect client_view_bounds_; + // Menu button that displays user's name and multi-profile menu. + scoped_ptr<views::ProfileMenuButton> profile_button_; + + // Image tag displayed on frame beneath profile_button_. + scoped_ptr<views::ProfileTagView> profile_tag_; + + // Multi-profile menu for profile_button_. + scoped_ptr<views::ProfileMenuModel> profile_menu_model_; + // Whether or not the window throbber is currently animating. bool throbber_running_; // The index of the current frame of the throbber animation. int throbber_frame_; + // The Google services user name associated with this BrowserView's profile. + StringPrefMember username_pref_; + static const int kThrobberIconCount = 24; static HICON throbber_icons_[kThrobberIconCount]; static void InitThrobberIcons(); diff --git a/chrome/browser/ui/views/profile_menu_button.cc b/chrome/browser/ui/views/profile_menu_button.cc new file mode 100644 index 0000000..7cf6340 --- /dev/null +++ b/chrome/browser/ui/views/profile_menu_button.cc @@ -0,0 +1,54 @@ +// 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/profile_menu_button.h" + +#include "ui/base/text/text_elider.h" +#include "ui/gfx/color_utils.h" +#include "views/controls/button/button.h" +#include "views/controls/menu/view_menu_delegate.h" + +namespace { + +// ActiveTextShadow is a darkened version of hsl_active_shift. +const SkColor kActiveTextShadow = 0xFF708DB3; +// InactiveTextShadow is slightly darker than grey-white inactive background. +const SkColor kInactiveTextShadow = SK_ColorLTGRAY; +// TextHover is slightly darker than enabled color, for a subtle hover shift. +const SkColor kTextHover = 0xFFDDDDDD; +const SkColor kTextEnabled = SK_ColorWHITE; +const SkColor kTextHighlighted = SK_ColorWHITE; + +// Horizontal padding beside profile menu button, to center it in the +// underlying tag image. +const int kProfileButtonBorderSpacing = 10; + +// Maximum width for name string in pixels. +const int kMaxTextWidth = 200; +} + +namespace views { + +ProfileMenuButton::ProfileMenuButton(ButtonListener* listener, + const std::wstring& text, + ViewMenuDelegate* menu_delegate) : + MenuButton(listener, text, menu_delegate, true) { + // Turn off hover highlighting and position button in the center of the + // underlying profile tag image. + set_border(views::Border::CreateEmptyBorder( + 0, kProfileButtonBorderSpacing, 0, kProfileButtonBorderSpacing)); + SetTextShadowColors(kActiveTextShadow, kInactiveTextShadow); + SetHoverColor(kTextHover); + SetEnabledColor(kTextEnabled); + SetHighlightColor(kTextHighlighted); +} + +ProfileMenuButton::~ProfileMenuButton() {} + +void ProfileMenuButton::SetText(const std::wstring& text) { + MenuButton::SetText(ui::ElideText(text, font(), kMaxTextWidth, false)); +} + +} // namespace views + diff --git a/chrome/browser/ui/views/profile_menu_button.h b/chrome/browser/ui/views/profile_menu_button.h new file mode 100644 index 0000000..e7fc4b6 --- /dev/null +++ b/chrome/browser/ui/views/profile_menu_button.h @@ -0,0 +1,45 @@ +// 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_PROFILE_MENU_BUTTON_H_ +#define CHROME_BROWSER_UI_VIEWS_PROFILE_MENU_BUTTON_H_ +#pragma once + +#include <string> + +#include "views/controls/button/menu_button.h" + +namespace gfx { +class Canvas; +} + +namespace views { + +// ProfileMenuButton +// +// Shows the button for the multiprofile menu with an image layered +// underneath that displays the profile tag. + +class ProfileMenuButton : public MenuButton { + public: + // Space between window controls and end of profile tag. + static const int kProfileTagHorizontalSpacing = 5; + + ProfileMenuButton(ButtonListener* listener, + const std::wstring& text, + ViewMenuDelegate* menu_delegate); + + virtual ~ProfileMenuButton(); + + // Override MenuButton to clamp text at kMaxTextWidth. + virtual void SetText(const std::wstring& text) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(ProfileMenuButton); +}; + +} // namespace views + +#endif // CHROME_BROWSER_UI_VIEWS_PROFILE_MENU_BUTTON_H_ + diff --git a/chrome/browser/ui/views/profile_tag_view.cc b/chrome/browser/ui/views/profile_tag_view.cc new file mode 100644 index 0000000..eab9e41 --- /dev/null +++ b/chrome/browser/ui/views/profile_tag_view.cc @@ -0,0 +1,92 @@ +// 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/profile_tag_view.h" + +#include "chrome/browser/ui/views/frame/browser_frame.h" +#include "chrome/browser/ui/views/profile_menu_button.h" +#include "grit/theme_resources.h" +#include "ui/base/theme_provider.h" +#include "ui/gfx/canvas_skia.h" +#include "ui/gfx/color_utils.h" +#include "ui/gfx/skbitmap_operations.h" +#include "views/widget/widget.h" + +namespace { +// Colors for primary profile. TODO(mirandac): add colors for multi-profile. +color_utils::HSL hsl_active_shift = { 0.594, 0.5, 0.5 }; +} + +namespace views { + +ProfileTagView::ProfileTagView(BrowserFrame* frame, + views::ProfileMenuButton* profile_menu_button) + : profile_tag_bitmaps_created_(false), + frame_(frame), + profile_menu_button_(profile_menu_button) { +} + +void ProfileTagView::OnPaint(gfx::Canvas* canvas) { + CreateProfileTagBitmaps(); + + // The tag image consists of a right and left edge, and a center section that + // scales to fit the length of the user's name. We can't just scale the whole + // image, or the left and right edges would be distorted. + int tag_width = profile_menu_button_->GetPreferredSize().width(); + int center_tag_width = tag_width - active_profile_tag_left_.width() - + active_profile_tag_right_.width(); + int tag_x = frame_->GetMinimizeButtonOffset() - tag_width - + views::ProfileMenuButton::kProfileTagHorizontalSpacing; + + bool is_active = GetWidget()->IsActive(); + SkBitmap* profile_tag_left = is_active ? &active_profile_tag_left_ : + &inactive_profile_tag_left_; + SkBitmap* profile_tag_center = is_active ? &active_profile_tag_center_ : + &inactive_profile_tag_center_; + SkBitmap* profile_tag_right = is_active ? &active_profile_tag_right_ : + &inactive_profile_tag_right_; + + canvas->DrawBitmapInt(*profile_tag_left, 0, 0); + canvas->DrawBitmapInt(*profile_tag_center, 0, 0, + profile_tag_center->width(), + profile_tag_center->height(), + profile_tag_left->width(), 0, + center_tag_width, + profile_tag_center->height(), true); + canvas->DrawBitmapInt(*profile_tag_right, + profile_tag_left->width() + center_tag_width, 0); +} + +void ProfileTagView::CreateProfileTagBitmaps() { + // Lazily create profile tag bitmaps on first display. + // TODO(mirandac): Cache these per profile, instead of creating every time. + if (profile_tag_bitmaps_created_) + return; + profile_tag_bitmaps_created_ = true; + + ui::ThemeProvider* theme_provider = frame_->GetThemeProviderForFrame(); + SkBitmap* profile_tag_center = theme_provider->GetBitmapNamed( + IDR_PROFILE_TAG_CENTER); + SkBitmap* profile_tag_left = theme_provider->GetBitmapNamed( + IDR_PROFILE_TAG_LEFT); + SkBitmap* profile_tag_right = theme_provider->GetBitmapNamed( + IDR_PROFILE_TAG_RIGHT); + inactive_profile_tag_center_ = *theme_provider->GetBitmapNamed( + IDR_PROFILE_TAG_INACTIVE_CENTER); + inactive_profile_tag_left_ = *theme_provider->GetBitmapNamed( + IDR_PROFILE_TAG_INACTIVE_LEFT); + inactive_profile_tag_right_ = *theme_provider->GetBitmapNamed( + IDR_PROFILE_TAG_INACTIVE_RIGHT); + + // Color active bitmap according to profile. TODO(mirandac): add theming + // and multi-profile color schemes. + active_profile_tag_center_ = SkBitmapOperations::CreateHSLShiftedBitmap( + *profile_tag_center, hsl_active_shift); + active_profile_tag_left_ = SkBitmapOperations::CreateHSLShiftedBitmap( + *profile_tag_left, hsl_active_shift); + active_profile_tag_right_ = SkBitmapOperations::CreateHSLShiftedBitmap( + *profile_tag_right, hsl_active_shift); +} + +} // namespace views diff --git a/chrome/browser/ui/views/profile_tag_view.h b/chrome/browser/ui/views/profile_tag_view.h new file mode 100644 index 0000000..a3652c3 --- /dev/null +++ b/chrome/browser/ui/views/profile_tag_view.h @@ -0,0 +1,65 @@ +// 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_PROFILE_TAG_VIEW_H_ +#define CHROME_BROWSER_UI_VIEWS_PROFILE_TAG_VIEW_H_ +#pragma once + +#include "third_party/skia/include/core/SkBitmap.h" +#include "views/view.h" + +class BrowserFrame; + +namespace gfx { +class Canvas; +} + +namespace views { + +class ProfileMenuButton; + +// ProfileTag +// +// Displays the tinted button image underneath the ProfileMenuButton. + +class ProfileTagView : public View { + public: + // Height of profile tag. + static const int kProfileTagHeight = 20; + + ProfileTagView(BrowserFrame* frame, + views::ProfileMenuButton* profile_menu_button); + ~ProfileTagView() {} + + // Paint the profile tag background image on the given canvas. + virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; + + private: + // Create the bitmaps to be displayed on the frame behind the profile button. + void CreateProfileTagBitmaps(); + + // True if the bitmaps to display the profile tag have been created. + bool profile_tag_bitmaps_created_; + + // Bitmaps for the profile tag in active and inactive states. + SkBitmap active_profile_tag_center_; + SkBitmap active_profile_tag_left_; + SkBitmap active_profile_tag_right_; + SkBitmap inactive_profile_tag_center_; + SkBitmap inactive_profile_tag_left_; + SkBitmap inactive_profile_tag_right_; + + // The frame that hosts this view. + BrowserFrame* frame_; + + // The button to be displayed above this view. + views::ProfileMenuButton* profile_menu_button_; + + DISALLOW_COPY_AND_ASSIGN(ProfileTagView); +}; + +} // namespace views + +#endif // CHROME_BROWSER_UI_VIEWS_PROFILE_TAG_VIEW_H_ + diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 7606938..3d26810 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -3108,8 +3108,12 @@ 'browser/ui/views/page_info_bubble_view.h', 'browser/ui/views/pinned_contents_info_bubble.cc', 'browser/ui/views/pinned_contents_info_bubble.h', + 'browser/ui/views/profile_menu_button.h', + 'browser/ui/views/profile_menu_button.cc', 'browser/ui/views/profile_menu_model.h', 'browser/ui/views/profile_menu_model.cc', + 'browser/ui/views/profile_tag_view.h', + 'browser/ui/views/profile_tag_view.cc', 'browser/ui/views/reload_button.cc', 'browser/ui/views/reload_button.h', 'browser/ui/views/repost_form_warning_view.cc', |