| Index: ash/system/user/tray_user.cc
|
| diff --git a/ash/system/user/tray_user.cc b/ash/system/user/tray_user.cc
|
| index d55ac7da0720eee2bd1c8d9748ae44d15430dd4f..1c0196692ada347b31bf451cb48b463c5d43f858 100644
|
| --- a/ash/system/user/tray_user.cc
|
| +++ b/ash/system/user/tray_user.cc
|
| @@ -4,36 +4,88 @@
|
|
|
| #include "ash/system/user/tray_user.h"
|
|
|
| +#include <algorithm>
|
| +#include <climits>
|
| +#include <vector>
|
| +
|
| #include "ash/shell.h"
|
| +#include "ash/system/tray/system_tray.h"
|
| #include "ash/system/tray/system_tray_delegate.h"
|
| #include "ash/system/tray/tray_constants.h"
|
| #include "ash/system/tray/tray_item_view.h"
|
| #include "ash/system/tray/tray_views.h"
|
| +#include "base/i18n/rtl.h"
|
| +#include "base/logging.h"
|
| +#include "base/memory/scoped_vector.h"
|
| +#include "base/string16.h"
|
| +#include "base/string_util.h"
|
| #include "base/utf_string_conversions.h"
|
| +#include "grit/ash_resources.h"
|
| #include "grit/ash_strings.h"
|
| #include "skia/ext/image_operations.h"
|
| #include "third_party/skia/include/core/SkCanvas.h"
|
| #include "third_party/skia/include/core/SkPaint.h"
|
| #include "third_party/skia/include/core/SkPath.h"
|
| +#include "ui/base/l10n/l10n_util.h"
|
| +#include "ui/base/range/range.h"
|
| #include "ui/base/resource/resource_bundle.h"
|
| +#include "ui/base/text/text_elider.h"
|
| #include "ui/gfx/canvas.h"
|
| +#include "ui/gfx/font.h"
|
| #include "ui/gfx/image/image.h"
|
| #include "ui/gfx/image/image_skia_operations.h"
|
| +#include "ui/gfx/insets.h"
|
| +#include "ui/gfx/rect.h"
|
| +#include "ui/gfx/render_text.h"
|
| #include "ui/gfx/size.h"
|
| #include "ui/gfx/skia_util.h"
|
| +#include "ui/views/border.h"
|
| +#include "ui/views/bubble/tray_bubble_view.h"
|
| +#include "ui/views/controls/button/border_images.h"
|
| #include "ui/views/controls/button/button.h"
|
| -#include "ui/views/controls/button/text_button.h"
|
| +#include "ui/views/controls/button/custom_button.h"
|
| #include "ui/views/controls/image_view.h"
|
| #include "ui/views/controls/label.h"
|
| +#include "ui/views/controls/link.h"
|
| +#include "ui/views/controls/link_listener.h"
|
| #include "ui/views/layout/box_layout.h"
|
| #include "ui/views/view.h"
|
| #include "ui/views/widget/widget.h"
|
|
|
| namespace {
|
|
|
| -const int kUserInfoVerticalPadding = 10;
|
| -const int kUserIconSize = 27;
|
| +const int kUserDetailsVerticalPadding = 5;
|
| +const int kUserCardVerticalPadding = 10;
|
| const int kProfileRoundedCornerRadius = 2;
|
| +const int kUserIconSize = 27;
|
| +
|
| +// The invisible word joiner character, used as a marker to indicate the start
|
| +// and end of the user's display name in the public account user card's text.
|
| +const char16 kDisplayNameMark[] = { 0x2060, 0 };
|
| +
|
| +const int kPublicAccountLogoutButtonBorderImagesNormal[] = {
|
| + IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
|
| + IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
|
| + IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
|
| + IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
|
| + IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
|
| + IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
|
| + IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
|
| + IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
|
| + IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
|
| +};
|
| +
|
| +const int kPublicAccountLogoutButtonBorderImagesHovered[] = {
|
| + IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
|
| + IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
|
| + IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
|
| + IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
|
| + IDR_AURA_TRAY_POPUP_LABEL_BUTTON_HOVER_BACKGROUND,
|
| + IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
|
| + IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
|
| + IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
|
| + IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
|
| +};
|
|
|
| } // namespace
|
|
|
| @@ -47,49 +99,18 @@ class RoundedImageView : public views::View {
|
| public:
|
| // Constructs a new rounded image view with rounded corners of radius
|
| // |corner_radius|.
|
| - explicit RoundedImageView(int corner_radius) : corner_radius_(corner_radius) {
|
| - }
|
| + explicit RoundedImageView(int corner_radius);
|
| + virtual ~RoundedImageView();
|
|
|
| - virtual ~RoundedImageView() {
|
| - }
|
| -
|
| - // Set the image that should be displayed from a pointer. The pointer
|
| - // contents is copied in the receiver's image.
|
| - void SetImage(const gfx::ImageSkia& img, const gfx::Size& size) {
|
| - image_ = img;
|
| - image_size_ = size;
|
| -
|
| - // Try to get the best image quality for the avatar.
|
| - resized_ = gfx::ImageSkiaOperations::CreateResizedImage(image_,
|
| - skia::ImageOperations::RESIZE_BEST, size);
|
| - if (GetWidget() && visible()) {
|
| - PreferredSizeChanged();
|
| - SchedulePaint();
|
| - }
|
| - }
|
| + // Set the image that should be displayed. The image contents is copied to the
|
| + // receiver's image.
|
| + void SetImage(const gfx::ImageSkia& img, const gfx::Size& size);
|
|
|
| + private:
|
| // Overridden from views::View.
|
| - virtual gfx::Size GetPreferredSize() OVERRIDE {
|
| - return gfx::Size(image_size_.width() + GetInsets().width(),
|
| - image_size_.height() + GetInsets().height());
|
| - }
|
| + virtual gfx::Size GetPreferredSize() OVERRIDE;
|
| + virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
|
|
|
| - virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
|
| - View::OnPaint(canvas);
|
| - gfx::Rect image_bounds(size());
|
| - image_bounds.ClampToCenteredSize(GetPreferredSize());
|
| - image_bounds.Inset(GetInsets());
|
| - const SkScalar kRadius = SkIntToScalar(corner_radius_);
|
| - SkPath path;
|
| - path.addRoundRect(gfx::RectToSkRect(image_bounds), kRadius, kRadius);
|
| - SkPaint paint;
|
| - paint.setAntiAlias(true);
|
| - paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
|
| - canvas->DrawImageInPath(resized_, image_bounds.x(), image_bounds.y(),
|
| - path, paint);
|
| - }
|
| -
|
| - private:
|
| gfx::ImageSkia image_;
|
| gfx::ImageSkia resized_;
|
| gfx::Size image_size_;
|
| @@ -98,146 +119,410 @@ class RoundedImageView : public views::View {
|
| DISALLOW_COPY_AND_ASSIGN(RoundedImageView);
|
| };
|
|
|
| +// The user details shown in public account mode. This is essentially a label
|
| +// but with custom painting code as the text is styled with multiple colors and
|
| +// contains a link.
|
| +class PublicAccountUserDetails : public views::View,
|
| + public views::LinkListener {
|
| + public:
|
| + PublicAccountUserDetails(SystemTrayItem* owner, int used_width);
|
| + virtual ~PublicAccountUserDetails();
|
| +
|
| + private:
|
| + // Overridden from views::View.
|
| + virtual void Layout() OVERRIDE;
|
| + virtual gfx::Size GetPreferredSize() OVERRIDE;
|
| + virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
|
| +
|
| + // Overridden from views::LinkListener.
|
| + virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE;
|
| +
|
| + // Calculate a preferred size that ensures the label text and the following
|
| + // link do not wrap over more than three lines in total for aesthetic reasons
|
| + // if possible.
|
| + void CalculatePreferredSize(SystemTrayItem* owner, int used_width);
|
| +
|
| + string16 text_;
|
| + views::Link* learn_more_;
|
| + gfx::Size preferred_size_;
|
| + ScopedVector<gfx::RenderText> lines_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(PublicAccountUserDetails);
|
| +};
|
| +
|
| class UserView : public views::View,
|
| public views::ButtonListener {
|
| public:
|
| - explicit UserView(ash::user::LoginStatus login)
|
| - : login_(login),
|
| - user_info_(NULL),
|
| - username_(NULL),
|
| - email_(NULL),
|
| - signout_(NULL) {
|
| - CHECK(login_ != ash::user::LOGGED_IN_NONE);
|
| -
|
| - bool public_account = login_ == ash::user::LOGGED_IN_PUBLIC;
|
| - bool guest = login_ == ash::user::LOGGED_IN_GUEST;
|
| - bool locked = login_ == ash::user::LOGGED_IN_LOCKED;
|
| -
|
| - set_background(views::Background::CreateSolidBackground(
|
| - public_account ? kPublicAccountBackgroundColor : kBackgroundColor));
|
| -
|
| - if (!guest)
|
| - AddUserInfo();
|
| -
|
| - // A user should not be able to modify logged in state when screen is
|
| - // locked.
|
| - if (!locked)
|
| - AddButtonContainer();
|
| - }
|
| + explicit UserView(SystemTrayItem* owner, ash::user::LoginStatus login);
|
| + virtual ~UserView();
|
| +
|
| + private:
|
| + // Overridden from views::View.
|
| + virtual gfx::Size GetPreferredSize() OVERRIDE;
|
| + virtual void Layout() OVERRIDE;
|
| +
|
| + // Overridden from views::ButtonListener.
|
| + virtual void ButtonPressed(views::Button* sender,
|
| + const ui::Event& event) OVERRIDE;
|
| +
|
| + void AddLogoutButton(ash::user::LoginStatus login);
|
| + void AddUserCard(SystemTrayItem* owner, ash::user::LoginStatus login);
|
| +
|
| + views::View* user_card_;
|
| + views::View* logout_button_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(UserView);
|
| +};
|
|
|
| - virtual ~UserView() {}
|
| +RoundedImageView::RoundedImageView(int corner_radius)
|
| + : corner_radius_(corner_radius) {}
|
|
|
| - // Create container for buttons.
|
| - void AddButtonContainer() {
|
| - const string16 title = ash::user::GetLocalizedSignOutStringForStatus(login_,
|
| - true);
|
| - TrayPopupLabelButton* button = new TrayPopupLabelButton(this, title);
|
| - button->SetAccessibleName(title);
|
| - AddChildView(button);
|
| - signout_ = button;
|
| +RoundedImageView::~RoundedImageView() {}
|
| +
|
| +void RoundedImageView::SetImage(const gfx::ImageSkia& img,
|
| + const gfx::Size& size) {
|
| + image_ = img;
|
| + image_size_ = size;
|
| +
|
| + // Try to get the best image quality for the avatar.
|
| + resized_ = gfx::ImageSkiaOperations::CreateResizedImage(image_,
|
| + skia::ImageOperations::RESIZE_BEST, size);
|
| + if (GetWidget() && visible()) {
|
| + PreferredSizeChanged();
|
| + SchedulePaint();
|
| }
|
| +}
|
|
|
| - private:
|
| - void AddUserInfo() {
|
| - user_info_ = new views::View;
|
| - user_info_->SetLayoutManager(new views::BoxLayout(
|
| - views::BoxLayout::kHorizontal, kTrayPopupPaddingHorizontal,
|
| - kUserInfoVerticalPadding, kTrayPopupPaddingBetweenItems));
|
| - AddChildView(user_info_);
|
| -
|
| - if (login_ == ash::user::LOGGED_IN_KIOSK) {
|
| - views::Label* label = new views::Label;
|
| - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
|
| - label->SetText(
|
| - bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_KIOSK_LABEL));
|
| - label->set_border(views::Border::CreateEmptyBorder(
|
| - 0, 4, 0, 1));
|
| - label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
|
| - user_info_->AddChildView(label);
|
| - return;
|
| +gfx::Size RoundedImageView::GetPreferredSize() {
|
| + return gfx::Size(image_size_.width() + GetInsets().width(),
|
| + image_size_.height() + GetInsets().height());
|
| +}
|
| +
|
| +void RoundedImageView::OnPaint(gfx::Canvas* canvas) {
|
| + View::OnPaint(canvas);
|
| + gfx::Rect image_bounds(size());
|
| + image_bounds.ClampToCenteredSize(GetPreferredSize());
|
| + image_bounds.Inset(GetInsets());
|
| + const SkScalar kRadius = SkIntToScalar(corner_radius_);
|
| + SkPath path;
|
| + path.addRoundRect(gfx::RectToSkRect(image_bounds), kRadius, kRadius);
|
| + SkPaint paint;
|
| + paint.setAntiAlias(true);
|
| + paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
|
| + canvas->DrawImageInPath(resized_, image_bounds.x(), image_bounds.y(),
|
| + path, paint);
|
| +}
|
| +
|
| +PublicAccountUserDetails::PublicAccountUserDetails(SystemTrayItem* owner,
|
| + int used_width)
|
| + : learn_more_(NULL) {
|
| + const int inner_padding =
|
| + kTrayPopupPaddingHorizontal - kTrayPopupPaddingBetweenItems;
|
| + const bool rtl = base::i18n::IsRTL();
|
| + set_border(views::Border::CreateEmptyBorder(
|
| + kUserDetailsVerticalPadding, rtl ? 0 : inner_padding,
|
| + kUserDetailsVerticalPadding, rtl ? inner_padding : 0));
|
| +
|
| + ash::SystemTrayDelegate* delegate =
|
| + ash::Shell::GetInstance()->tray_delegate();
|
| + // Retrieve the user's display name and wrap it with markers.
|
| + string16 display_name = delegate->GetUserDisplayName();
|
| + RemoveChars(display_name, kDisplayNameMark, &display_name);
|
| + display_name = kDisplayNameMark[0] + display_name + kDisplayNameMark[0];
|
| + // Retrieve the domain managing the device and wrap it with markers.
|
| + string16 domain = UTF8ToUTF16(delegate->GetEnterpriseDomain());
|
| + RemoveChars(domain, kDisplayNameMark, &domain);
|
| + base::i18n::WrapStringWithLTRFormatting(&domain);
|
| + // Retrieve the label text, inserting the display name and domain.
|
| + text_ = l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_PUBLIC_LABEL,
|
| + display_name, domain);
|
| +
|
| + learn_more_ = new views::Link(l10n_util::GetStringUTF16(IDS_ASH_LEARN_MORE));
|
| + learn_more_->SetUnderline(false);
|
| + learn_more_->set_listener(this);
|
| + AddChildView(learn_more_);
|
| +
|
| + CalculatePreferredSize(owner, used_width);
|
| +}
|
| +
|
| +PublicAccountUserDetails::~PublicAccountUserDetails() {}
|
| +
|
| +void PublicAccountUserDetails::Layout() {
|
| + lines_.clear();
|
| + const gfx::Rect contents_area = GetContentsBounds();
|
| + if (contents_area.IsEmpty())
|
| + return;
|
| +
|
| + // Word-wrap the label text.
|
| + const gfx::Font font;
|
| + std::vector<string16> lines;
|
| + ui::ElideRectangleText(text_, font, contents_area.width(),
|
| + contents_area.height(), ui::ELIDE_LONG_WORDS, &lines);
|
| + // Loop through the lines, creating a renderer for each.
|
| + gfx::Point position = contents_area.origin();
|
| + ui::Range display_name(ui::Range::InvalidRange());
|
| + for (std::vector<string16>::const_iterator it = lines.begin();
|
| + it != lines.end(); ++it) {
|
| + gfx::RenderText* line = gfx::RenderText::CreateInstance();
|
| + line->SetDirectionalityMode(gfx::DIRECTIONALITY_FROM_UI);
|
| + line->SetText(*it);
|
| + const gfx::Size size(contents_area.width(), line->GetStringSize().height());
|
| + line->SetDisplayRect(gfx::Rect(position, size));
|
| + position.set_y(position.y() + size.height());
|
| +
|
| + // Set the default text color for the line.
|
| + gfx::StyleRange default_style(line->default_style());
|
| + default_style.foreground = kPublicAccountUserCardTextColor;
|
| + line->set_default_style(default_style);
|
| + line->ApplyDefaultStyle();
|
| +
|
| + // If a range of the line contains the user's display name, apply a custom
|
| + // text color to it.
|
| + if (display_name.is_empty())
|
| + display_name.set_start(it->find(kDisplayNameMark));
|
| + if (!display_name.is_empty()) {
|
| + display_name.set_end(
|
| + it->find(kDisplayNameMark, display_name.start() + 1));
|
| + gfx::StyleRange display_name_style(line->default_style());
|
| + display_name_style.foreground = kPublicAccountUserCardNameColor;
|
| + ui::Range line_range(0, it->size());
|
| + display_name_style.range = display_name.Intersect(line_range);
|
| + line->ApplyStyleRange(display_name_style);
|
| + // Update the range for the next line.
|
| + if (display_name.end() >= line_range.end())
|
| + display_name.set_start(0);
|
| + else
|
| + display_name = ui::Range::InvalidRange();
|
| }
|
|
|
| - RoundedImageView* image = new RoundedImageView(kProfileRoundedCornerRadius);
|
| - image->SetImage(ash::Shell::GetInstance()->tray_delegate()->GetUserImage(),
|
| - gfx::Size(kUserIconSize, kUserIconSize));
|
| - user_info_->AddChildView(image);
|
| -
|
| - views::View* user = new views::View;
|
| - user->SetLayoutManager(new views::BoxLayout(
|
| - views::BoxLayout::kVertical, 0, 5, 0));
|
| - ash::SystemTrayDelegate* tray =
|
| - ash::Shell::GetInstance()->tray_delegate();
|
| - username_ = new views::Label(tray->GetUserDisplayName());
|
| - username_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
|
| - user->AddChildView(username_);
|
| -
|
| - email_ = new views::Label(UTF8ToUTF16(tray->GetUserEmail()));
|
| - email_->SetFont(username_->font().DeriveFont(-1));
|
| - email_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
|
| - email_->SetEnabled(false);
|
| - user->AddChildView(email_);
|
| -
|
| - user_info_->AddChildView(user);
|
| + lines_.push_back(line);
|
| }
|
|
|
| - // Overridden from views::ButtonListener.
|
| - virtual void ButtonPressed(views::Button* sender,
|
| - const ui::Event& event) OVERRIDE {
|
| - CHECK(sender == signout_);
|
| - ash::SystemTrayDelegate* tray = ash::Shell::GetInstance()->tray_delegate();
|
| - tray->SignOut();
|
| + // Position the link after the label text, separated by a space. If it does
|
| + // not fit onto the last line of the text, wrap the link onto its own line.
|
| + const gfx::Size last_line_size = lines_.back()->GetStringSize();
|
| + const int space_width = font.GetStringWidth(ASCIIToUTF16(" "));
|
| + const gfx::Size link_size = learn_more_->GetPreferredSize();
|
| + if (contents_area.width() - last_line_size.width() >=
|
| + space_width + link_size.width()) {
|
| + position.set_x(position.x() + last_line_size.width() + space_width);
|
| + position.set_y(position.y() - last_line_size.height());
|
| + }
|
| + position.set_y(position.y() - learn_more_->GetInsets().top());
|
| + gfx::Rect learn_more_bounds(position, link_size);
|
| + learn_more_bounds.Intersect(contents_area);
|
| + if (base::i18n::IsRTL()) {
|
| + const gfx::Insets insets = GetInsets();
|
| + learn_more_bounds.Offset(insets.right() - insets.left(), 0);
|
| }
|
| + learn_more_->SetBoundsRect(learn_more_bounds);
|
| +}
|
|
|
| - // Overridden from views::View.
|
| - virtual gfx::Size GetPreferredSize() OVERRIDE {
|
| - gfx::Size size;
|
| - if (user_info_)
|
| - size = user_info_->GetPreferredSize();
|
| - if (signout_) {
|
| - gfx::Size signout_size = signout_->GetPreferredSize();
|
| - // Make sure the user default view item at least as tall as the other
|
| - // tray popup items.
|
| - if (size.height() == 0)
|
| - size.set_height(kTrayPopupItemHeight);
|
| - size.set_height(std::max(size.height(), signout_size.height()));
|
| - size.set_width(size.width() + signout_size.width() +
|
| - kTrayPopupPaddingHorizontal * 2 + kTrayPopupPaddingBetweenItems);
|
| - }
|
| - return size;
|
| +gfx::Size PublicAccountUserDetails::GetPreferredSize() {
|
| + return preferred_size_;
|
| +}
|
| +
|
| +void PublicAccountUserDetails::OnPaint(gfx::Canvas* canvas) {
|
| + for (ScopedVector<gfx::RenderText>::const_iterator it = lines_.begin();
|
| + it != lines_.end(); ++it) {
|
| + (*it)->Draw(canvas);
|
| }
|
| + views::View::OnPaint(canvas);
|
| +}
|
| +
|
| +void PublicAccountUserDetails::LinkClicked(views::Link* source,
|
| + int event_flags) {
|
| + DCHECK_EQ(source, learn_more_);
|
| + ash::Shell::GetInstance()->tray_delegate()->ShowPublicAccountInfo();
|
| +}
|
|
|
| - virtual void Layout() OVERRIDE {
|
| - views::View::Layout();
|
| - if (bounds().IsEmpty())
|
| - return;
|
| -
|
| - if (signout_ && user_info_) {
|
| - gfx::Rect signout_bounds(bounds());
|
| - signout_bounds.ClampToCenteredSize(signout_->GetPreferredSize());
|
| - signout_bounds.set_x(width() - signout_bounds.width() -
|
| - kTrayPopupPaddingHorizontal);
|
| - signout_->SetBoundsRect(signout_bounds);
|
| -
|
| - gfx::Rect usercard_bounds(user_info_->GetPreferredSize());
|
| - usercard_bounds.set_width(signout_bounds.x());
|
| - user_info_->SetBoundsRect(usercard_bounds);
|
| - } else if (signout_) {
|
| - signout_->SetBoundsRect(gfx::Rect(size()));
|
| - } else if (user_info_) {
|
| - user_info_->SetBoundsRect(gfx::Rect(size()));
|
| +void PublicAccountUserDetails::CalculatePreferredSize(SystemTrayItem* owner,
|
| + int used_width) {
|
| + const gfx::Font font;
|
| + const gfx::Size link_size = learn_more_->GetPreferredSize();
|
| + const int space_width = font.GetStringWidth(ASCIIToUTF16(" "));
|
| + const gfx::Insets insets = GetInsets();
|
| + views::TrayBubbleView* bubble_view =
|
| + owner->system_tray()->GetSystemBubble()->bubble_view();
|
| + int min_width = std::max(
|
| + link_size.width(),
|
| + bubble_view->GetPreferredSize().width() - (used_width + insets.width()));
|
| + int max_width = std::min(
|
| + font.GetStringWidth(text_) + space_width + link_size.width(),
|
| + bubble_view->GetMaximumSize().width() - (used_width + insets.width()));
|
| + // Do a binary search for the minimum width that ensures no more than three
|
| + // lines are needed. The lower bound is the minimum of the current bubble
|
| + // width and the width of the link (as no wrapping is permitted inside the
|
| + // link). The upper bound is the maximum of the largest allowed bubble width
|
| + // and the sum of the label text and link widths when put on a single line.
|
| + std::vector<string16> lines;
|
| + while (min_width < max_width) {
|
| + lines.clear();
|
| + const int width = (min_width + max_width) / 2;
|
| + const bool too_narrow = ui::ElideRectangleText(
|
| + text_, font, width, INT_MAX, ui::TRUNCATE_LONG_WORDS, &lines) != 0;
|
| + int line_count = lines.size();
|
| + if (!too_narrow && line_count == 3 &&
|
| + width - font.GetStringWidth(lines.back()) <=
|
| + space_width + link_size.width()) {
|
| + ++line_count;
|
| }
|
| + if (too_narrow || line_count > 3)
|
| + min_width = width + 1;
|
| + else
|
| + max_width = width;
|
| }
|
|
|
| - user::LoginStatus login_;
|
| + // Calculate the corresponding height and set the preferred size.
|
| + lines.clear();
|
| + ui::ElideRectangleText(
|
| + text_, font, min_width, INT_MAX, ui::TRUNCATE_LONG_WORDS, &lines);
|
| + int line_count = lines.size();
|
| + if (min_width - font.GetStringWidth(lines.back()) <=
|
| + space_width + link_size.width()) {
|
| + ++line_count;
|
| + }
|
| + const int line_height = font.GetHeight();
|
| + const int link_extra_height = std::max(
|
| + link_size.height() - learn_more_->GetInsets().top() - line_height, 0);
|
| + preferred_size_ = gfx::Size(
|
| + min_width + insets.width(),
|
| + line_count * line_height + link_extra_height + insets.height());
|
| +
|
| + bubble_view->SetWidth(preferred_size_.width() + used_width);
|
| +}
|
|
|
| - views::View* user_info_;
|
| - views::Label* username_;
|
| - views::Label* email_;
|
| +UserView::UserView(SystemTrayItem* owner, ash::user::LoginStatus login)
|
| + : user_card_(NULL),
|
| + logout_button_(NULL) {
|
| + CHECK_NE(ash::user::LOGGED_IN_NONE, login);
|
| + set_background(views::Background::CreateSolidBackground(
|
| + login == ash::user::LOGGED_IN_PUBLIC ? kPublicAccountBackgroundColor :
|
| + kBackgroundColor));
|
| + SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0,
|
| + kTrayPopupPaddingBetweenItems));
|
| + // The logout button must be added before the user card so that the user card
|
| + // can correctly calculate the remaining available width.
|
| + AddLogoutButton(login);
|
| + AddUserCard(owner, login);
|
| +}
|
|
|
| - views::Button* signout_;
|
| +UserView::~UserView() {}
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(UserView);
|
| -};
|
| +gfx::Size UserView::GetPreferredSize() {
|
| + gfx::Size size = views::View::GetPreferredSize();
|
| + if (!user_card_) {
|
| + // Make sure the default user view item is at least as tall as the other
|
| + // items.
|
| + size.set_height(std::max(size.height(),
|
| + kTrayPopupItemHeight + GetInsets().height()));
|
| + }
|
| + return size;
|
| +}
|
| +
|
| +void UserView::Layout() {
|
| + gfx::Rect contents_area(GetContentsBounds());
|
| + if (user_card_ && logout_button_) {
|
| + // Give the logout button the space it requests.
|
| + gfx::Rect logout_area = contents_area;
|
| + logout_area.ClampToCenteredSize(logout_button_->GetPreferredSize());
|
| + logout_area.set_x(contents_area.right() - logout_area.width());
|
| + logout_button_->SetBoundsRect(logout_area);
|
| +
|
| + // Give the remaining space to the user card.
|
| + gfx::Rect user_card_area = contents_area;
|
| + user_card_area.set_width(contents_area.width() -
|
| + (logout_area.width() + kTrayPopupPaddingBetweenItems));
|
| + user_card_->SetBoundsRect(user_card_area);
|
| + } else if (user_card_) {
|
| + user_card_->SetBoundsRect(contents_area);
|
| + } else if (logout_button_) {
|
| + logout_button_->SetBoundsRect(contents_area);
|
| + }
|
| +}
|
| +
|
| +void UserView::ButtonPressed(views::Button* sender, const ui::Event& event) {
|
| + DCHECK_EQ(logout_button_, sender);
|
| + ash::Shell::GetInstance()->tray_delegate()->SignOut();
|
| +}
|
| +
|
| +void UserView::AddLogoutButton(ash::user::LoginStatus login) {
|
| + // A user should not be able to modify logged-in state when screen is
|
| + // locked.
|
| + if (login == ash::user::LOGGED_IN_LOCKED)
|
| + return;
|
| +
|
| + const string16 title = ash::user::GetLocalizedSignOutStringForStatus(login,
|
| + true);
|
| + TrayPopupLabelButton* logout_button = new TrayPopupLabelButton(this, title);
|
| + logout_button->SetAccessibleName(title);
|
| + logout_button_ = logout_button;
|
| + // In public account mode, the logout button border has a custom color.
|
| + if (login == ash::user::LOGGED_IN_PUBLIC) {
|
| + TrayPopupLabelButtonBorder* border =
|
| + static_cast<TrayPopupLabelButtonBorder*>(logout_button_->border());
|
| + border->SetImages(views::CustomButton::STATE_NORMAL, views::BorderImages(
|
| + kPublicAccountLogoutButtonBorderImagesNormal));
|
| + border->SetImages(views::CustomButton::STATE_HOVERED, views::BorderImages(
|
| + kPublicAccountLogoutButtonBorderImagesHovered));
|
| + border->SetImages(views::CustomButton::STATE_PRESSED, views::BorderImages(
|
| + kPublicAccountLogoutButtonBorderImagesHovered));
|
| + }
|
| + AddChildView(logout_button_);
|
| +}
|
| +
|
| +void UserView::AddUserCard(SystemTrayItem* owner,
|
| + ash::user::LoginStatus login) {
|
| + if (login == ash::user::LOGGED_IN_GUEST)
|
| + return;
|
| +
|
| + set_border(views::Border::CreateEmptyBorder(0, kTrayPopupPaddingHorizontal,
|
| + 0, kTrayPopupPaddingHorizontal));
|
| +
|
| + user_card_ = new views::View();
|
| + user_card_->SetLayoutManager(new views::BoxLayout(
|
| + views::BoxLayout::kHorizontal, 0, kUserCardVerticalPadding,
|
| + kTrayPopupPaddingBetweenItems));
|
| + AddChildViewAt(user_card_, 0);
|
| +
|
| + if (login == ash::user::LOGGED_IN_KIOSK) {
|
| + views::Label* details = new views::Label;
|
| + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
|
| + details->SetText(
|
| + bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_KIOSK_LABEL));
|
| + details->set_border(views::Border::CreateEmptyBorder(0, 4, 0, 1));
|
| + details->SetHorizontalAlignment(gfx::ALIGN_LEFT);
|
| + user_card_->AddChildView(details);
|
| + return;
|
| + }
|
| +
|
| + RoundedImageView* avatar = new RoundedImageView(kProfileRoundedCornerRadius);
|
| + avatar->SetImage(ash::Shell::GetInstance()->tray_delegate()->GetUserImage(),
|
| + gfx::Size(kUserIconSize, kUserIconSize));
|
| + user_card_->AddChildView(avatar);
|
| +
|
| + if (login == ash::user::LOGGED_IN_PUBLIC) {
|
| + user_card_->AddChildView(new PublicAccountUserDetails(
|
| + owner, GetPreferredSize().width() + kTrayPopupPaddingBetweenItems));
|
| + return;
|
| + }
|
| +
|
| + ash::SystemTrayDelegate* delegate =
|
| + ash::Shell::GetInstance()->tray_delegate();
|
| + views::View* details = new views::View;
|
| + details->SetLayoutManager(new views::BoxLayout(
|
| + views::BoxLayout::kVertical, 0, kUserDetailsVerticalPadding, 0));
|
| + views::Label* username = new views::Label(delegate->GetUserDisplayName());
|
| + username->SetHorizontalAlignment(gfx::ALIGN_LEFT);
|
| + details->AddChildView(username);
|
| +
|
| + views::Label* email = new views::Label(UTF8ToUTF16(delegate->GetUserEmail()));
|
| + email->SetFont(username->font().DeriveFont(-1));
|
| + email->SetHorizontalAlignment(gfx::ALIGN_LEFT);
|
| + email->SetEnabled(false);
|
| + details->AddChildView(email);
|
| + user_card_->AddChildView(details);
|
| +}
|
|
|
| } // namespace tray
|
|
|
| @@ -272,7 +557,7 @@ views::View* TrayUser::CreateDefaultView(user::LoginStatus status) {
|
| return NULL;
|
|
|
| CHECK(user_ == NULL);
|
| - user_ = new tray::UserView(status);
|
| + user_ = new tray::UserView(this, status);
|
| return user_;
|
| }
|
|
|
|
|