tray_user.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
1b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek// Copyright (c) 2012 The Chromium Authors. All rights reserved.
277349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek// Use of this source code is governed by a BSD-style license that can be
377349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek// found in the LICENSE file.
477349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek
577349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include "ash/system/user/tray_user.h"
677349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek
777349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include <algorithm>
877349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include <climits>
977349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include <vector>
10b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
11b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ash/ash_switches.h"
12b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ash/multi_profile_uma.h"
1377349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include "ash/popup_message.h"
1477349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include "ash/root_window_controller.h"
1577349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include "ash/session_state_delegate.h"
16d065d6080f0620bb80b933f3f5d52d37bb2ea770Ted Kremenek#include "ash/shelf/shelf_layout_manager.h"
17d065d6080f0620bb80b933f3f5d52d37bb2ea770Ted Kremenek#include "ash/shell.h"
18d065d6080f0620bb80b933f3f5d52d37bb2ea770Ted Kremenek#include "ash/shell_delegate.h"
1977349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include "ash/system/tray/system_tray.h"
20aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek#include "ash/system/tray/system_tray_delegate.h"
2199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek#include "ash/system/tray/system_tray_notifier.h"
2277349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include "ash/system/tray/tray_constants.h"
2377349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include "ash/system/tray/tray_item_view.h"
24b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ash/system/tray/tray_popup_label_button.h"
2577349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include "ash/system/tray/tray_popup_label_button_border.h"
2699c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek#include "ash/system/tray/tray_utils.h"
2799c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek#include "base/i18n/rtl.h"
28b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "base/logging.h"
29b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "base/memory/scoped_vector.h"
30b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "base/strings/string16.h"
31e5f4dcb6bd73a10df6eb6c3cfe057c88cb2362ccTed Kremenek#include "base/strings/string_util.h"
32b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "base/strings/utf_string_conversions.h"
33aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek#include "grit/ash_resources.h"
34b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "grit/ash_strings.h"
35b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "skia/ext/image_operations.h"
36f116bd654bcdb5d7c22656f224deeb7a67f7d0cdTed Kremenek#include "third_party/skia/include/core/SkCanvas.h"
37aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek#include "third_party/skia/include/core/SkPaint.h"
38aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek#include "third_party/skia/include/core/SkPath.h"
39aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek#include "ui/aura/window.h"
40330dddd19406f9cc227e59e0bb0a36ecdc52915eTed Kremenek#include "ui/base/l10n/l10n_util.h"
4199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek#include "ui/base/resource/resource_bundle.h"
4277349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include "ui/gfx/canvas.h"
43b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/gfx/font.h"
44b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/gfx/image/image.h"
45b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/gfx/image/image_skia_operations.h"
46b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/gfx/insets.h"
47b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/gfx/range/range.h"
48b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/gfx/rect.h"
49b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/gfx/render_text.h"
50b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/gfx/size.h"
51b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/gfx/skia_util.h"
52b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/gfx/text_elider.h"
53b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/views/border.h"
54b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/views/bubble/tray_bubble_view.h"
55b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/views/controls/button/button.h"
56b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/views/controls/button/custom_button.h"
57b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/views/controls/image_view.h"
58aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek#include "ui/views/controls/label.h"
59240f1f00dda1d481276ea872fe8f8851581a7e6bTed Kremenek#include "ui/views/controls/link.h"
60b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/views/controls/link_listener.h"
61b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/views/corewm/shadow_types.h"
62aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek#include "ui/views/layout/box_layout.h"
63b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/views/layout/fill_layout.h"
64b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/views/mouse_watcher.h"
65b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/views/painter.h"
66b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/views/view.h"
67b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "ui/views/widget/widget.h"
68b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
69b387a3f23e423d62c053be86294b703da1d1a222Ted Kremeneknamespace {
70b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
710d093d3005dd583675a45a85bd688063572cc8afTed Kremenekconst int kUserDetailsVerticalPadding = 5;
720d093d3005dd583675a45a85bd688063572cc8afTed Kremenekconst int kUserCardVerticalPadding = 10;
730d093d3005dd583675a45a85bd688063572cc8afTed Kremenekconst int kProfileRoundedCornerRadius = 2;
740d093d3005dd583675a45a85bd688063572cc8afTed Kremenekconst int kUserIconSize = 27;
75b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenekconst int kUserIconLargeSize = 32;
76b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenekconst int kUserIconLargeCornerRadius = 2;
7799c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenekconst int kUserLabelToIconPadding = 5;
7899c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// When using multi login, this spacing is added between user icons.
7999c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenekconst int kTrayLabelSpacing = 1;
8099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek
8199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// When a hover border is used, it is starting this many pixels before the icon
8299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// position.
83affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenekconst int kTrayUserTileHoverBorderInset = 10;
844a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek
854a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek// The border color of the user button.
86affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenekconst SkColor kBorderColor = 0xffdcdcdc;
875e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek
8823a4f917cd8d1090be7c96c4eda8643086f64d36Ted Kremenek// The invisible word joiner character, used as a marker to indicate the start
891e80aa49ec689d1937e54fb353d6626e0a58f0dbTed Kremenek// and end of the user's display name in the public account user card's text.
90affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenekconst char16 kDisplayNameMark[] = { 0x2060, 0 };
91affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenek
9202737ed29d7fff2206f7c7ee958cdf0665e35542Ted Kremenekconst int kPublicAccountLogoutButtonBorderImagesNormal[] = {
9302737ed29d7fff2206f7c7ee958cdf0665e35542Ted Kremenek    IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
948cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek    IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
9502737ed29d7fff2206f7c7ee958cdf0665e35542Ted Kremenek    IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
9602737ed29d7fff2206f7c7ee958cdf0665e35542Ted Kremenek    IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
9702737ed29d7fff2206f7c7ee958cdf0665e35542Ted Kremenek    IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
98b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
994a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek    IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
1004a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek    IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
1014a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek    IDR_AURA_TRAY_POPUP_LABEL_BUTTON_NORMAL_BACKGROUND,
102b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek};
1034a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek
1044a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenekconst int kPublicAccountLogoutButtonBorderImagesHovered[] = {
1054a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek    IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
1069dca062461a6244cf0f733346657fa3eee853f9bTed Kremenek    IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
107affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenek    IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
108affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenek    IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
109affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenek    IDR_AURA_TRAY_POPUP_LABEL_BUTTON_HOVER_BACKGROUND,
110affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenek    IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
111b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
11207d83aa220567bef263ef76cfc9b0159320bb640Ted Kremenek    IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
113b5339121f63f2754d4f26e8f3a092caf9f7d9290Ted Kremenek    IDR_AURA_TRAY_POPUP_PUBLIC_ACCOUNT_LOGOUT_BUTTON_BORDER,
11407d83aa220567bef263ef76cfc9b0159320bb640Ted Kremenek};
11507d83aa220567bef263ef76cfc9b0159320bb640Ted Kremenek
11607d83aa220567bef263ef76cfc9b0159320bb640Ted Kremenek// Offsetting the popup message relative to the tray menu.
117b5339121f63f2754d4f26e8f3a092caf9f7d9290Ted Kremenekconst int kPopupMessageOffset = 25;
11807d83aa220567bef263ef76cfc9b0159320bb640Ted Kremenek
11907d83aa220567bef263ef76cfc9b0159320bb640Ted Kremenek// Switch to a user with the given |user_index|.
1204a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenekvoid SwitchUser(ash::MultiProfileIndex user_index) {
1214a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  // Do not switch users when the log screen is presented.
12207d83aa220567bef263ef76cfc9b0159320bb640Ted Kremenek  if (ash::Shell::GetInstance()->session_state_delegate()->
1234d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek          IsUserSessionBlocked())
1244d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek    return;
1254d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek
1264d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  DCHECK(user_index > 0);
1274d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  ash::SessionStateDelegate* delegate =
1284d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek      ash::Shell::GetInstance()->session_state_delegate();
1294d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  ash::MultiProfileUMA::RecordSwitchActiveUser(
1304d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek      ash::MultiProfileUMA::SWITCH_ACTIVE_USER_BY_TRAY);
1314d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  delegate->SwitchActiveUser(delegate->GetUserID(user_index));
132b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek}
1338cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek
1348cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek}  // namespace
1358cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek
1368cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremeneknamespace ash {
1375e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremeneknamespace internal {
1385e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek
1395e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremeneknamespace tray {
1405e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek
14123a4f917cd8d1090be7c96c4eda8643086f64d36Ted Kremenek// A custom image view with rounded edges.
14223a4f917cd8d1090be7c96c4eda8643086f64d36Ted Kremenekclass RoundedImageView : public views::View {
14323a4f917cd8d1090be7c96c4eda8643086f64d36Ted Kremenek public:
14423a4f917cd8d1090be7c96c4eda8643086f64d36Ted Kremenek  // Constructs a new rounded image view with rounded corners of radius
1452ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek  // |corner_radius|. If |active_user| is set, the icon will be drawn in
1462ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek  // full colors - otherwise it will fade into the background.
1472ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek  RoundedImageView(int corner_radius, bool active_user);
1482ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek  virtual ~RoundedImageView();
14923a4f917cd8d1090be7c96c4eda8643086f64d36Ted Kremenek
15023a4f917cd8d1090be7c96c4eda8643086f64d36Ted Kremenek  // Set the image that should be displayed. The image contents is copied to the
15123a4f917cd8d1090be7c96c4eda8643086f64d36Ted Kremenek  // receiver's image.
15223a4f917cd8d1090be7c96c4eda8643086f64d36Ted Kremenek  void SetImage(const gfx::ImageSkia& img, const gfx::Size& size);
15323a4f917cd8d1090be7c96c4eda8643086f64d36Ted Kremenek
154b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // Set the radii of the corners independently.
155b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  void SetCornerRadii(int top_left,
1567cb15939e08ea31f0fadcd24c974dbc9e4b61c01Ted Kremenek                      int top_right,
1570d093d3005dd583675a45a85bd688063572cc8afTed Kremenek                      int bottom_right,
1580d093d3005dd583675a45a85bd688063572cc8afTed Kremenek                      int bottom_left);
1590d093d3005dd583675a45a85bd688063572cc8afTed Kremenek
1600d093d3005dd583675a45a85bd688063572cc8afTed Kremenek private:
1610d093d3005dd583675a45a85bd688063572cc8afTed Kremenek  // Overridden from views::View.
1620d093d3005dd583675a45a85bd688063572cc8afTed Kremenek  virtual gfx::Size GetPreferredSize() OVERRIDE;
163b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
164b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
165b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  gfx::ImageSkia image_;
166b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  gfx::ImageSkia resized_;
167b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  gfx::Size image_size_;
168b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  int corner_radius_[4];
169b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
170b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // True if the given user is the active user and the icon should get
171b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // painted as active.
172b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  bool active_user_;
173b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
174b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  DISALLOW_COPY_AND_ASSIGN(RoundedImageView);
175b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek};
176b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
177b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek// An inactive user view which can be clicked to make active. Note that this
178b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek// "button" does not show as a button any click or hover changes.
179e01c98767dfd7153c3c84637c36659e3bbe16ff7Ted Kremenekclass UserSwitcherView : public RoundedImageView {
180e01c98767dfd7153c3c84637c36659e3bbe16ff7Ted Kremenek public:
181ffe0f43806d4823271c2406c1fccc2373115c36aTed Kremenek  UserSwitcherView(int corner_radius, MultiProfileIndex user_index);
182e01c98767dfd7153c3c84637c36659e3bbe16ff7Ted Kremenek  virtual ~UserSwitcherView() {}
183493d7a26d5ea319770ba904b43f2740d43b820cbTed Kremenek
184493d7a26d5ea319770ba904b43f2740d43b820cbTed Kremenek  virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
185b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
186b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
187aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek private:
188b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // The user index to activate when the item was clicked. Note that this
18902737ed29d7fff2206f7c7ee958cdf0665e35542Ted Kremenek  // index refers to the LRU list of logged in users.
19002737ed29d7fff2206f7c7ee958cdf0665e35542Ted Kremenek  MultiProfileIndex user_index_;
19102737ed29d7fff2206f7c7ee958cdf0665e35542Ted Kremenek
19202737ed29d7fff2206f7c7ee958cdf0665e35542Ted Kremenek  DISALLOW_COPY_AND_ASSIGN(UserSwitcherView);
1934a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek};
1944a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek
195b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek// The user details shown in public account mode. This is essentially a label
196b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek// but with custom painting code as the text is styled with multiple colors and
1974a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek// contains a link.
1984a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenekclass PublicAccountUserDetails : public views::View,
1999dca062461a6244cf0f733346657fa3eee853f9bTed Kremenek                                 public views::LinkListener {
2009dca062461a6244cf0f733346657fa3eee853f9bTed Kremenek public:
201b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  PublicAccountUserDetails(SystemTrayItem* owner, int used_width);
202b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  virtual ~PublicAccountUserDetails();
203b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
204b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek private:
205b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // Overridden from views::View.
206b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  virtual void Layout() OVERRIDE;
207b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  virtual gfx::Size GetPreferredSize() OVERRIDE;
208b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
2094a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek
2104a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  // Overridden from views::LinkListener.
211b5339121f63f2754d4f26e8f3a092caf9f7d9290Ted Kremenek  virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE;
212b5339121f63f2754d4f26e8f3a092caf9f7d9290Ted Kremenek
2134d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  // Calculate a preferred size that ensures the label text and the following
2144d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  // link do not wrap over more than three lines in total for aesthetic reasons
2154d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  // if possible.
2164d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  void CalculatePreferredSize(SystemTrayItem* owner, int used_width);
2174d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek
2184d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  base::string16 text_;
219d763eb91aab5bdecd11825fadb35d6d8cc905f63Ted Kremenek  views::Link* learn_more_;
220d763eb91aab5bdecd11825fadb35d6d8cc905f63Ted Kremenek  gfx::Size preferred_size_;
221affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenek  ScopedVector<gfx::RenderText> lines_;
222affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenek
223affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenek  DISALLOW_COPY_AND_ASSIGN(PublicAccountUserDetails);
2248cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek};
2258cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek
2268cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek// The button which holds the user card in case of multi profile.
2278cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenekclass UserCard : public views::CustomButton {
2288cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek public:
2295e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek  UserCard(views::ButtonListener* listener, bool active_user);
2305e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek  virtual ~UserCard();
2315e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek
2325e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek  // Called when the border should remain even in the non highlighted state.
2332ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek  void ForceBorderVisible(bool show);
2341e80aa49ec689d1937e54fb353d6626e0a58f0dbTed Kremenek
235dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek  // Overridden from views::View
236dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek  virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE;
237dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek  virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE;
238dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek
239dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek  // Check if the item is hovered.
240dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek  bool is_hovered_for_test() {return button_hovered_; }
2412ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek
2422ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek private:
24302737ed29d7fff2206f7c7ee958cdf0665e35542Ted Kremenek  // Change the hover/active state of the "button" when the status changes.
24402737ed29d7fff2206f7c7ee958cdf0665e35542Ted Kremenek  void ShowActive();
24502737ed29d7fff2206f7c7ee958cdf0665e35542Ted Kremenek
24602737ed29d7fff2206f7c7ee958cdf0665e35542Ted Kremenek  // True if this is the active user.
2471b9df4c307b650526344ba0a28534268f6920745Ted Kremenek  bool is_active_user_;
2481b9df4c307b650526344ba0a28534268f6920745Ted Kremenek
2491b9df4c307b650526344ba0a28534268f6920745Ted Kremenek  // True if button is hovered.
2501b9df4c307b650526344ba0a28534268f6920745Ted Kremenek  bool button_hovered_;
251d87a321a3c3902f7acfc6539b8946a00da6e45ccTed Kremenek
252d87a321a3c3902f7acfc6539b8946a00da6e45ccTed Kremenek  // True if the border should be visible.
253d87a321a3c3902f7acfc6539b8946a00da6e45ccTed Kremenek  bool show_border_;
254d87a321a3c3902f7acfc6539b8946a00da6e45ccTed Kremenek
2554a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  DISALLOW_COPY_AND_ASSIGN(UserCard);
2564a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek};
2574a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek
258d87a321a3c3902f7acfc6539b8946a00da6e45ccTed Kremenekclass UserViewMouseWatcherHost : public views::MouseWatcherHost {
259d87a321a3c3902f7acfc6539b8946a00da6e45ccTed Kremenekpublic:
2604d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek explicit UserViewMouseWatcherHost(const gfx::Rect& screen_area)
2614d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek     : screen_area_(screen_area) {}
2624d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek virtual ~UserViewMouseWatcherHost() {}
2634d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek
2644d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek // Implementation of MouseWatcherHost.
2654d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek virtual bool Contains(const gfx::Point& screen_point,
2664d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek                       views::MouseWatcherHost::MouseEventType type) OVERRIDE {
2674d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek   return screen_area_.Contains(screen_point);
2684d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek }
2694d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek
2704d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenekprivate:
2714d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek gfx::Rect screen_area_;
2724d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek
2734d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek DISALLOW_COPY_AND_ASSIGN(UserViewMouseWatcherHost);
2744d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek};
2754d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek
276b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek// The view of a user item.
2778cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenekclass UserView : public views::View,
2788cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek                 public views::ButtonListener,
2798cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek                 public views::MouseWatcherListener {
2805e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek public:
2815e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek  UserView(SystemTrayItem* owner,
2825e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek           ash::user::LoginStatus login,
2835e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek           MultiProfileIndex index);
2848cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek  virtual ~UserView();
2852ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek
2862ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek  // Overridden from MouseWatcherListener:
2872ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek  virtual void MouseMovedOutOfHost() OVERRIDE;
2882ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek
289dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek  TrayUser::TestState GetStateForTest() const;
290dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek  gfx::Rect GetBoundsInScreenOfUserButtonForTest();
291dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek
292dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek private:
293dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek  // Overridden from views::View.
294dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek  virtual gfx::Size GetPreferredSize() OVERRIDE;
295dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek  virtual int GetHeightForWidth(int width) OVERRIDE;
296dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek  virtual void Layout() OVERRIDE;
297dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek
298dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek  // Overridden from views::ButtonListener.
299dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek  virtual void ButtonPressed(views::Button* sender,
300dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek                             const ui::Event& event) OVERRIDE;
301dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek
302dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek  void AddLogoutButton(user::LoginStatus login);
303dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek  void AddUserCard(SystemTrayItem* owner, user::LoginStatus login);
304dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek
305dbfe41acda3078f8fe566318c0097f7ae683c6bbTed Kremenek  // Create a user icon representation for the user card.
30699c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek  views::View* CreateIconForUserCard(user::LoginStatus login);
30799c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek
30899c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek  // Create the additional user card content for the retail logged in mode.
30999c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek  void AddLoggedInRetailModeUserCardContent();
31099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek
31199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek  // Create the additional user card content for the public mode.
31299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek  void AddLoggedInPublicModeUserCardContent(SystemTrayItem* owner);
31399c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek
31499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek  // Create the menu option to add another user. If |disabled| is set the user
31599c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek  // cannot actively click on the item.
31699c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek  void ToggleAddUserMenuOption();
31799c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek
31899c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek  // Returns true when multi profile is supported.
31999c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek  bool SupportsMultiProfile();
32099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek
32199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek  MultiProfileIndex multiprofile_index_;
32299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek  // The view of the user card.
32399c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek  views::View* user_card_view_;
32499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek
32599c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek  // This is the owner system tray item of this view.
326b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  SystemTrayItem* owner_;
3276a6719a3a11087b48d9f1a4eb08b3bd43cb05a65Ted Kremenek
328b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // True if |user_card_view_| is a |UserView| - otherwise it is only a
329b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // |views::View|.
3306a6719a3a11087b48d9f1a4eb08b3bd43cb05a65Ted Kremenek  bool is_user_card_;
3316a6719a3a11087b48d9f1a4eb08b3bd43cb05a65Ted Kremenek  views::View* logout_button_;
3326a6719a3a11087b48d9f1a4eb08b3bd43cb05a65Ted Kremenek  scoped_ptr<PopupMessage> popup_message_;
3336a6719a3a11087b48d9f1a4eb08b3bd43cb05a65Ted Kremenek  scoped_ptr<views::Widget> add_menu_option_;
3346a6719a3a11087b48d9f1a4eb08b3bd43cb05a65Ted Kremenek
335b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // True when the add user panel is visible but not activatable.
336b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  bool add_user_visible_but_disabled_;
337b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
338b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // The mouse watcher which takes care of out of window hover events.
339b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  scoped_ptr<views::MouseWatcher> mouse_watcher_;
340b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
341b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  DISALLOW_COPY_AND_ASSIGN(UserView);
342b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek};
343b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
344b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek// The menu item view which gets shown when the user clicks in multi profile
34505a2378c708688c8ef498a5cea40ed7f5db15fa5Ted Kremenek// mode onto the user item.
34605a2378c708688c8ef498a5cea40ed7f5db15fa5Ted Kremenekclass AddUserView : public views::CustomButton,
34700a3a5f024ac54088ab887712b292171188064f0Ted Kremenek                    public views::ButtonListener {
34800a3a5f024ac54088ab887712b292171188064f0Ted Kremenek public:
34900a3a5f024ac54088ab887712b292171188064f0Ted Kremenek  // The |owner| is the view for which this view gets created. The |listener|
35000a3a5f024ac54088ab887712b292171188064f0Ted Kremenek  // will get notified when this item gets clicked.
35100a3a5f024ac54088ab887712b292171188064f0Ted Kremenek  AddUserView(UserCard* owner, views::ButtonListener* listener);
35200a3a5f024ac54088ab887712b292171188064f0Ted Kremenek  virtual ~AddUserView();
35300a3a5f024ac54088ab887712b292171188064f0Ted Kremenek
35400a3a5f024ac54088ab887712b292171188064f0Ted Kremenek  // Get the anchor view for a message.
35500a3a5f024ac54088ab887712b292171188064f0Ted Kremenek  views::View* anchor() { return anchor_; }
35600a3a5f024ac54088ab887712b292171188064f0Ted Kremenek
35705a2378c708688c8ef498a5cea40ed7f5db15fa5Ted Kremenek  // Overridden from views::ButtonListener.
358b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  virtual void ButtonPressed(views::Button* sender,
3590d093d3005dd583675a45a85bd688063572cc8afTed Kremenek                             const ui::Event& event) OVERRIDE;
3600d093d3005dd583675a45a85bd688063572cc8afTed Kremenek
361512c913a6f93d225faacdb8e20308f5c4065c3ebTed Kremenek private:
362b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // Overridden from views::View.
363aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  virtual gfx::Size GetPreferredSize() OVERRIDE;
364b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  virtual int GetHeightForWidth(int width) OVERRIDE;
365aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  virtual void Layout() OVERRIDE;
366aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek
367b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // Create the additional client content for this item.
36805a2378c708688c8ef498a5cea40ed7f5db15fa5Ted Kremenek  void AddContent();
3690d093d3005dd583675a45a85bd688063572cc8afTed Kremenek
3700d093d3005dd583675a45a85bd688063572cc8afTed Kremenek  // This is the content we create and show.
3710d093d3005dd583675a45a85bd688063572cc8afTed Kremenek  views::View* add_user_;
372b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
3730d093d3005dd583675a45a85bd688063572cc8afTed Kremenek  // This listener will get informed when someone clicks on this button.
3740d093d3005dd583675a45a85bd688063572cc8afTed Kremenek  views::ButtonListener* listener_;
3750d093d3005dd583675a45a85bd688063572cc8afTed Kremenek
376b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // This is the owner view of this item.
377aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  UserCard* owner_;
378aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek
379b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // The anchor view for targetted bubble messages.
38005a2378c708688c8ef498a5cea40ed7f5db15fa5Ted Kremenek  views::View* anchor_;
381aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek
382aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  DISALLOW_COPY_AND_ASSIGN(AddUserView);
383b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek};
384b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
385aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted KremenekRoundedImageView::RoundedImageView(int corner_radius, bool active_user)
38605a2378c708688c8ef498a5cea40ed7f5db15fa5Ted Kremenek    : active_user_(active_user) {
38705a2378c708688c8ef498a5cea40ed7f5db15fa5Ted Kremenek  for (int i = 0; i < 4; ++i)
38877349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek    corner_radius_[i] = corner_radius;
389aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek}
390aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek
391b387a3f23e423d62c053be86294b703da1d1a222Ted KremenekRoundedImageView::~RoundedImageView() {}
392b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
393aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenekvoid RoundedImageView::SetImage(const gfx::ImageSkia& img,
394aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek                                const gfx::Size& size) {
395b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  image_ = img;
396b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  image_size_ = size;
397aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek
398240f1f00dda1d481276ea872fe8f8851581a7e6bTed Kremenek  // Try to get the best image quality for the avatar.
399b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  resized_ = gfx::ImageSkiaOperations::CreateResizedImage(image_,
400b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek      skia::ImageOperations::RESIZE_BEST, size);
401b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  if (GetWidget() && visible()) {
402b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    PreferredSizeChanged();
403aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek    SchedulePaint();
404aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  }
405aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek}
406aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek
407aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenekvoid RoundedImageView::SetCornerRadii(int top_left,
408aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek                                      int top_right,
409aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek                                      int bottom_right,
410aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek                                      int bottom_left) {
411aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  corner_radius_[0] = top_left;
412aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  corner_radius_[1] = top_right;
413b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  corner_radius_[2] = bottom_right;
414aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  corner_radius_[3] = bottom_left;
415b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek}
416b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
417aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenekgfx::Size RoundedImageView::GetPreferredSize() {
418aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  return gfx::Size(image_size_.width() + GetInsets().width(),
419aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek                   image_size_.height() + GetInsets().height());
420aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek}
421aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek
422b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenekvoid RoundedImageView::OnPaint(gfx::Canvas* canvas) {
423aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  View::OnPaint(canvas);
424aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  gfx::Rect image_bounds(size());
425b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  image_bounds.ClampToCenteredSize(GetPreferredSize());
426aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  image_bounds.Inset(GetInsets());
427aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  const SkScalar kRadius[8] = {
428b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    SkIntToScalar(corner_radius_[0]),
429aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek    SkIntToScalar(corner_radius_[0]),
430aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek    SkIntToScalar(corner_radius_[1]),
431b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    SkIntToScalar(corner_radius_[1]),
4320e561a3e6755c4f248a8bb05d49071ddf4f2ef7bTed Kremenek    SkIntToScalar(corner_radius_[2]),
4335c684c4be01fb98077a9b5e07ca1fdc01d8d97cbTed Kremenek    SkIntToScalar(corner_radius_[2]),
4340e561a3e6755c4f248a8bb05d49071ddf4f2ef7bTed Kremenek    SkIntToScalar(corner_radius_[3]),
4355c684c4be01fb98077a9b5e07ca1fdc01d8d97cbTed Kremenek    SkIntToScalar(corner_radius_[3])
436b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  };
4374a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  SkPath path;
4384a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  path.addRoundRect(gfx::RectToSkRect(image_bounds), kRadius);
4394a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  SkPaint paint;
4409dca062461a6244cf0f733346657fa3eee853f9bTed Kremenek  paint.setAntiAlias(true);
441b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  paint.setXfermodeMode(active_user_ ? SkXfermode::kSrcOver_Mode :
442b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek                                       SkXfermode::kLuminosity_Mode);
443b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  canvas->DrawImageInPath(resized_, image_bounds.x(), image_bounds.y(),
444b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek                          path, paint);
445ef44bfb9d0f15ba0391f8346c9f01355fb450a09Ted Kremenek}
446ef44bfb9d0f15ba0391f8346c9f01355fb450a09Ted Kremenek
447ef44bfb9d0f15ba0391f8346c9f01355fb450a09Ted KremenekUserSwitcherView::UserSwitcherView(int corner_radius,
448ef44bfb9d0f15ba0391f8346c9f01355fb450a09Ted Kremenek                                   MultiProfileIndex user_index)
449ef44bfb9d0f15ba0391f8346c9f01355fb450a09Ted Kremenek    : RoundedImageView(corner_radius, false),
450ef44bfb9d0f15ba0391f8346c9f01355fb450a09Ted Kremenek      user_index_(user_index) {
451ef44bfb9d0f15ba0391f8346c9f01355fb450a09Ted Kremenek  SetEnabled(true);
452ef44bfb9d0f15ba0391f8346c9f01355fb450a09Ted Kremenek}
453ef44bfb9d0f15ba0391f8346c9f01355fb450a09Ted Kremenek
454ef44bfb9d0f15ba0391f8346c9f01355fb450a09Ted Kremenekvoid UserSwitcherView::OnMouseEvent(ui::MouseEvent* event) {
455ef44bfb9d0f15ba0391f8346c9f01355fb450a09Ted Kremenek  if (event->type() == ui::ET_MOUSE_PRESSED) {
456ef44bfb9d0f15ba0391f8346c9f01355fb450a09Ted Kremenek    SwitchUser(user_index_);
457ef44bfb9d0f15ba0391f8346c9f01355fb450a09Ted Kremenek    event->SetHandled();
458b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  }
459b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek}
460b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
461aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenekvoid UserSwitcherView::OnTouchEvent(ui::TouchEvent* event) {
462b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  if (event->type() == ui::ET_TOUCH_PRESSED) {
463de43424560f1a744de6214dab6bbee28ad8437f5Ted Kremenek    SwitchUser(user_index_);
464de43424560f1a744de6214dab6bbee28ad8437f5Ted Kremenek    event->SetHandled();
465aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  }
466de43424560f1a744de6214dab6bbee28ad8437f5Ted Kremenek}
467de43424560f1a744de6214dab6bbee28ad8437f5Ted Kremenek
46855deb97341819080d6d127d29e25b9502e4f2e3cTed KremenekPublicAccountUserDetails::PublicAccountUserDetails(SystemTrayItem* owner,
46955deb97341819080d6d127d29e25b9502e4f2e3cTed Kremenek                                                   int used_width)
47055deb97341819080d6d127d29e25b9502e4f2e3cTed Kremenek    : learn_more_(NULL) {
471b9308372e0d40c85cb573c4982fdf5089d89ab6dTed Kremenek  const int inner_padding =
472b9308372e0d40c85cb573c4982fdf5089d89ab6dTed Kremenek      kTrayPopupPaddingHorizontal - kTrayPopupPaddingBetweenItems;
473b9308372e0d40c85cb573c4982fdf5089d89ab6dTed Kremenek  const bool rtl = base::i18n::IsRTL();
474b9308372e0d40c85cb573c4982fdf5089d89ab6dTed Kremenek  set_border(views::Border::CreateEmptyBorder(
475b9308372e0d40c85cb573c4982fdf5089d89ab6dTed Kremenek      kUserDetailsVerticalPadding, rtl ? 0 : inner_padding,
476b9308372e0d40c85cb573c4982fdf5089d89ab6dTed Kremenek      kUserDetailsVerticalPadding, rtl ? inner_padding : 0));
477b9308372e0d40c85cb573c4982fdf5089d89ab6dTed Kremenek
47855deb97341819080d6d127d29e25b9502e4f2e3cTed Kremenek  // Retrieve the user's display name and wrap it with markers.
479b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // Note that since this is a public account it always has to be the primary
480aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  // user.
481b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  base::string16 display_name =
482b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek      Shell::GetInstance()->session_state_delegate()->GetUserDisplayName(0);
483b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  RemoveChars(display_name, kDisplayNameMark, &display_name);
484b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  display_name = kDisplayNameMark[0] + display_name + kDisplayNameMark[0];
485b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // Retrieve the domain managing the device and wrap it with markers.
486b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  base::string16 domain = UTF8ToUTF16(
487b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek      Shell::GetInstance()->system_tray_delegate()->GetEnterpriseDomain());
488b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  RemoveChars(domain, kDisplayNameMark, &domain);
489aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  base::i18n::WrapStringWithLTRFormatting(&domain);
490b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // Retrieve the label text, inserting the display name and domain.
491b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  text_ = l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_PUBLIC_LABEL,
492b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek                                     display_name, domain);
493b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
49402737ed29d7fff2206f7c7ee958cdf0665e35542Ted Kremenek  learn_more_ = new views::Link(l10n_util::GetStringUTF16(IDS_ASH_LEARN_MORE));
49502737ed29d7fff2206f7c7ee958cdf0665e35542Ted Kremenek  learn_more_->SetUnderline(false);
49602737ed29d7fff2206f7c7ee958cdf0665e35542Ted Kremenek  learn_more_->set_listener(this);
497b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  AddChildView(learn_more_);
498aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek
499b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  CalculatePreferredSize(owner, used_width);
500b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek}
501aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek
502aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted KremenekPublicAccountUserDetails::~PublicAccountUserDetails() {}
503aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek
504b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenekvoid PublicAccountUserDetails::Layout() {
505b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  lines_.clear();
506b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  const gfx::Rect contents_area = GetContentsBounds();
507ffe0f43806d4823271c2406c1fccc2373115c36aTed Kremenek  if (contents_area.IsEmpty())
508ffe0f43806d4823271c2406c1fccc2373115c36aTed Kremenek    return;
509d8e9f0dc737133d4e8342f39389064620f5a7f8fTed Kremenek
5109ef1ec98a8fc17e7560e07641184bc4daee39b46Ted Kremenek  // Word-wrap the label text.
5114a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  const gfx::Font font;
5129ef1ec98a8fc17e7560e07641184bc4daee39b46Ted Kremenek  std::vector<base::string16> lines;
5139ef1ec98a8fc17e7560e07641184bc4daee39b46Ted Kremenek  gfx::ElideRectangleText(text_, font, contents_area.width(),
5149ef1ec98a8fc17e7560e07641184bc4daee39b46Ted Kremenek                          contents_area.height(), gfx::ELIDE_LONG_WORDS,
51500a3a5f024ac54088ab887712b292171188064f0Ted Kremenek                          &lines);
5169ef1ec98a8fc17e7560e07641184bc4daee39b46Ted Kremenek  // Loop through the lines, creating a renderer for each.
51700a3a5f024ac54088ab887712b292171188064f0Ted Kremenek  gfx::Point position = contents_area.origin();
518b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  gfx::Range display_name(gfx::Range::InvalidRange());
519b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  for (std::vector<base::string16>::const_iterator it = lines.begin();
520aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek       it != lines.end(); ++it) {
52100a3a5f024ac54088ab887712b292171188064f0Ted Kremenek    gfx::RenderText* line = gfx::RenderText::CreateInstance();
522b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    line->SetDirectionalityMode(gfx::DIRECTIONALITY_FROM_UI);
523b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    line->SetText(*it);
524aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek    const gfx::Size size(contents_area.width(), line->GetStringSize().height());
52500a3a5f024ac54088ab887712b292171188064f0Ted Kremenek    line->SetDisplayRect(gfx::Rect(position, size));
52690e420321f60860f4c4e7a68ca9f7567824b46ecTed Kremenek    position.set_y(position.y() + size.height());
52710c16657eec144def180ee53d1e0249c9ed2b3b5Ted Kremenek
528aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek    // Set the default text color for the line.
52900a3a5f024ac54088ab887712b292171188064f0Ted Kremenek    line->SetColor(kPublicAccountUserCardTextColor);
530b640b3b5dfccaf259967cb2cb6755c9aa20d4423Ted Kremenek
53150d0ac299c641bee9024f3fbae2ea0640898a040Ted Kremenek    // If a range of the line contains the user's display name, apply a custom
532c3055ab39ac3535ffd581d33e21b72133099a6ebTed Kremenek    // text color to it.
53300a3a5f024ac54088ab887712b292171188064f0Ted Kremenek    if (display_name.is_empty())
534c3055ab39ac3535ffd581d33e21b72133099a6ebTed Kremenek      display_name.set_start(it->find(kDisplayNameMark));
535c3055ab39ac3535ffd581d33e21b72133099a6ebTed Kremenek    if (!display_name.is_empty()) {
536aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek      display_name.set_end(
537692416c214a3b234236dedcf875735a9cc29e90bTed Kremenek          it->find(kDisplayNameMark, display_name.start() + 1));
5384a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek      gfx::Range line_range(0, it->size());
5394a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek      line->ApplyColor(kPublicAccountUserCardNameColor,
540692416c214a3b234236dedcf875735a9cc29e90bTed Kremenek                       display_name.Intersect(line_range));
541aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek      // Update the range for the next line.
542692416c214a3b234236dedcf875735a9cc29e90bTed Kremenek      if (display_name.end() >= line_range.end())
543aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek        display_name.set_start(0);
544aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek      else
545aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek        display_name = gfx::Range::InvalidRange();
54600a3a5f024ac54088ab887712b292171188064f0Ted Kremenek    }
547aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek
54800a3a5f024ac54088ab887712b292171188064f0Ted Kremenek    lines_.push_back(line);
549aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  }
550692416c214a3b234236dedcf875735a9cc29e90bTed Kremenek
5513f916501c91d3f6f37b1d43276c440343f9454f6Ted Kremenek  // Position the link after the label text, separated by a space. If it does
5523f916501c91d3f6f37b1d43276c440343f9454f6Ted Kremenek  // not fit onto the last line of the text, wrap the link onto its own line.
5533f916501c91d3f6f37b1d43276c440343f9454f6Ted Kremenek  const gfx::Size last_line_size = lines_.back()->GetStringSize();
5543f916501c91d3f6f37b1d43276c440343f9454f6Ted Kremenek  const int space_width = font.GetStringWidth(ASCIIToUTF16(" "));
5553f916501c91d3f6f37b1d43276c440343f9454f6Ted Kremenek  const gfx::Size link_size = learn_more_->GetPreferredSize();
5563f916501c91d3f6f37b1d43276c440343f9454f6Ted Kremenek  if (contents_area.width() - last_line_size.width() >=
5573f916501c91d3f6f37b1d43276c440343f9454f6Ted Kremenek      space_width + link_size.width()) {
55800a3a5f024ac54088ab887712b292171188064f0Ted Kremenek    position.set_x(position.x() + last_line_size.width() + space_width);
5593f916501c91d3f6f37b1d43276c440343f9454f6Ted Kremenek    position.set_y(position.y() - last_line_size.height());
5603f916501c91d3f6f37b1d43276c440343f9454f6Ted Kremenek  }
56100a3a5f024ac54088ab887712b292171188064f0Ted Kremenek  position.set_y(position.y() - learn_more_->GetInsets().top());
56250d0ac299c641bee9024f3fbae2ea0640898a040Ted Kremenek  gfx::Rect learn_more_bounds(position, link_size);
563de43424560f1a744de6214dab6bbee28ad8437f5Ted Kremenek  learn_more_bounds.Intersect(contents_area);
564330dddd19406f9cc227e59e0bb0a36ecdc52915eTed Kremenek  if (base::i18n::IsRTL()) {
565330dddd19406f9cc227e59e0bb0a36ecdc52915eTed Kremenek    const gfx::Insets insets = GetInsets();
56600a3a5f024ac54088ab887712b292171188064f0Ted Kremenek    learn_more_bounds.Offset(insets.right() - insets.left(), 0);
567de43424560f1a744de6214dab6bbee28ad8437f5Ted Kremenek  }
56805a2378c708688c8ef498a5cea40ed7f5db15fa5Ted Kremenek  learn_more_->SetBoundsRect(learn_more_bounds);
569aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek}
570b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
57172fc3b30d775a6b720dd0dd87aa853226f0625ddChris Lattnergfx::Size PublicAccountUserDetails::GetPreferredSize() {
57272fc3b30d775a6b720dd0dd87aa853226f0625ddChris Lattner  return preferred_size_;
573d065d6080f0620bb80b933f3f5d52d37bb2ea770Ted Kremenek}
574
575void PublicAccountUserDetails::OnPaint(gfx::Canvas* canvas) {
576  for (ScopedVector<gfx::RenderText>::const_iterator it = lines_.begin();
577       it != lines_.end(); ++it) {
578    (*it)->Draw(canvas);
579  }
580  views::View::OnPaint(canvas);
581}
582
583void PublicAccountUserDetails::LinkClicked(views::Link* source,
584                                           int event_flags) {
585  DCHECK_EQ(source, learn_more_);
586  Shell::GetInstance()->system_tray_delegate()->ShowPublicAccountInfo();
587}
588
589void PublicAccountUserDetails::CalculatePreferredSize(SystemTrayItem* owner,
590                                                      int used_width) {
591  const gfx::Font font;
592  const gfx::Size link_size = learn_more_->GetPreferredSize();
593  const int space_width = font.GetStringWidth(ASCIIToUTF16(" "));
594  const gfx::Insets insets = GetInsets();
595  views::TrayBubbleView* bubble_view =
596      owner->system_tray()->GetSystemBubble()->bubble_view();
597  int min_width = std::max(
598      link_size.width(),
599      bubble_view->GetPreferredSize().width() - (used_width + insets.width()));
600  int max_width = std::min(
601      font.GetStringWidth(text_) + space_width + link_size.width(),
602      bubble_view->GetMaximumSize().width() - (used_width + insets.width()));
603  // Do a binary search for the minimum width that ensures no more than three
604  // lines are needed. The lower bound is the minimum of the current bubble
605  // width and the width of the link (as no wrapping is permitted inside the
606  // link). The upper bound is the maximum of the largest allowed bubble width
607  // and the sum of the label text and link widths when put on a single line.
608  std::vector<base::string16> lines;
609  while (min_width < max_width) {
610    lines.clear();
611    const int width = (min_width + max_width) / 2;
612    const bool too_narrow = gfx::ElideRectangleText(
613        text_, font, width, INT_MAX, gfx::TRUNCATE_LONG_WORDS, &lines) != 0;
614    int line_count = lines.size();
615    if (!too_narrow && line_count == 3 &&
616            width - font.GetStringWidth(lines.back()) <=
617            space_width + link_size.width()) {
618      ++line_count;
619    }
620    if (too_narrow || line_count > 3)
621      min_width = width + 1;
622    else
623      max_width = width;
624  }
625
626  // Calculate the corresponding height and set the preferred size.
627  lines.clear();
628  gfx::ElideRectangleText(
629      text_, font, min_width, INT_MAX, gfx::TRUNCATE_LONG_WORDS, &lines);
630  int line_count = lines.size();
631  if (min_width - font.GetStringWidth(lines.back()) <=
632      space_width + link_size.width()) {
633    ++line_count;
634  }
635  const int line_height = font.GetHeight();
636  const int link_extra_height = std::max(
637      link_size.height() - learn_more_->GetInsets().top() - line_height, 0);
638  preferred_size_ = gfx::Size(
639      min_width + insets.width(),
640      line_count * line_height + link_extra_height + insets.height());
641
642  bubble_view->SetWidth(preferred_size_.width() + used_width);
643}
644
645UserCard::UserCard(views::ButtonListener* listener, bool active_user)
646    : CustomButton(listener),
647      is_active_user_(active_user),
648      button_hovered_(false),
649      show_border_(false) {
650  if (is_active_user_) {
651    set_background(
652        views::Background::CreateSolidBackground(kBackgroundColor));
653    ShowActive();
654  }
655}
656
657UserCard::~UserCard() {}
658
659void UserCard::ForceBorderVisible(bool show) {
660  show_border_ = show;
661  ShowActive();
662}
663
664void UserCard::OnMouseEntered(const ui::MouseEvent& event) {
665  if (is_active_user_) {
666    button_hovered_ = true;
667    background()->SetNativeControlColor(kHoverBackgroundColor);
668    ShowActive();
669  }
670}
671
672void UserCard::OnMouseExited(const ui::MouseEvent& event) {
673  if (is_active_user_) {
674    button_hovered_ = false;
675    background()->SetNativeControlColor(kBackgroundColor);
676    ShowActive();
677  }
678}
679
680void UserCard::ShowActive() {
681  int width = button_hovered_ || show_border_ ? 1 : 0;
682  set_border(views::Border::CreateSolidSidedBorder(width, width, width, 1,
683                                                   kBorderColor));
684  SchedulePaint();
685}
686
687UserView::UserView(SystemTrayItem* owner,
688                   user::LoginStatus login,
689                   MultiProfileIndex index)
690    : multiprofile_index_(index),
691      user_card_view_(NULL),
692      owner_(owner),
693      is_user_card_(false),
694      logout_button_(NULL),
695      add_user_visible_but_disabled_(false) {
696  CHECK_NE(user::LOGGED_IN_NONE, login);
697  if (!index) {
698    // Only the logged in user will have a background. All other users will have
699    // to allow the TrayPopupContainer highlighting the menu line.
700    set_background(views::Background::CreateSolidBackground(
701        login == user::LOGGED_IN_PUBLIC ? kPublicAccountBackgroundColor :
702                                          kBackgroundColor));
703  }
704  SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0,
705                                        kTrayPopupPaddingBetweenItems));
706  // The logout button must be added before the user card so that the user card
707  // can correctly calculate the remaining available width.
708  // Note that only the current multiprofile user gets a button.
709  if (!multiprofile_index_)
710    AddLogoutButton(login);
711  AddUserCard(owner, login);
712}
713
714UserView::~UserView() {}
715
716void UserView::MouseMovedOutOfHost() {
717  popup_message_.reset();
718  mouse_watcher_.reset();
719  add_menu_option_.reset();
720}
721
722TrayUser::TestState UserView::GetStateForTest() const {
723  if (add_menu_option_.get()) {
724    return add_user_visible_but_disabled_ ? TrayUser::ACTIVE_BUT_DISABLED :
725                                            TrayUser::ACTIVE;
726  }
727
728  if (!is_user_card_)
729    return TrayUser::SHOWN;
730
731  return static_cast<UserCard*>(user_card_view_)->is_hovered_for_test() ?
732      TrayUser::HOVERED : TrayUser::SHOWN;
733}
734
735gfx::Rect UserView::GetBoundsInScreenOfUserButtonForTest() {
736  DCHECK(user_card_view_);
737  return user_card_view_->GetBoundsInScreen();
738}
739
740gfx::Size UserView::GetPreferredSize() {
741  gfx::Size size = views::View::GetPreferredSize();
742  // Only the active user panel will be forced to a certain height.
743  if (!multiprofile_index_) {
744    size.set_height(std::max(size.height(),
745                             kTrayPopupItemHeight + GetInsets().height()));
746  }
747  return size;
748}
749
750int UserView::GetHeightForWidth(int width) {
751  return GetPreferredSize().height();
752}
753
754void UserView::Layout() {
755  gfx::Rect contents_area(GetContentsBounds());
756  if (user_card_view_ && logout_button_) {
757    // Give the logout button the space it requests.
758    gfx::Rect logout_area = contents_area;
759    logout_area.ClampToCenteredSize(logout_button_->GetPreferredSize());
760    logout_area.set_x(contents_area.right() - logout_area.width());
761
762    // Give the remaining space to the user card.
763    gfx::Rect user_card_area = contents_area;
764    int remaining_width = contents_area.width() - logout_area.width();
765    if (SupportsMultiProfile()) {
766      // In multiprofile case |user_card_view_| and |logout_button_| have to
767      // have the same height.
768      int y = std::min(user_card_area.y(), logout_area.y());
769      int height = std::max(user_card_area.height(), logout_area.height());
770      logout_area.set_y(y);
771      logout_area.set_height(height);
772      user_card_area.set_y(y);
773      user_card_area.set_height(height);
774
775      // In multiprofile mode we have also to increase the size of the card by
776      // the size of the border to make it overlap with the logout button.
777      user_card_area.set_width(std::max(0, remaining_width + 1));
778
779      // To make the logout button symmetrical with the user card we also make
780      // the button longer by the same size the hover area in front of the icon
781      // got inset.
782      logout_area.set_width(logout_area.width() +
783                            kTrayUserTileHoverBorderInset);
784    } else {
785      // In all other modes we have to make sure that there is enough spacing
786      // between the two.
787      remaining_width -= kTrayPopupPaddingBetweenItems;
788    }
789    user_card_area.set_width(remaining_width);
790    user_card_view_->SetBoundsRect(user_card_area);
791    logout_button_->SetBoundsRect(logout_area);
792  } else if (user_card_view_) {
793    user_card_view_->SetBoundsRect(contents_area);
794  } else if (logout_button_) {
795    logout_button_->SetBoundsRect(contents_area);
796  }
797}
798
799void UserView::ButtonPressed(views::Button* sender, const ui::Event& event) {
800  if (sender == logout_button_) {
801    Shell::GetInstance()->system_tray_delegate()->SignOut();
802  } else if (sender == user_card_view_ && SupportsMultiProfile()) {
803    if (!multiprofile_index_) {
804      ToggleAddUserMenuOption();
805    } else {
806      SwitchUser(multiprofile_index_);
807      // Since the user list is about to change the system menu should get
808      // closed.
809      owner_->system_tray()->CloseSystemBubble();
810    }
811  } else if (add_menu_option_.get() &&
812             sender == add_menu_option_->GetContentsView()) {
813    // Let the user add another account to the session.
814    MultiProfileUMA::RecordSigninUser(MultiProfileUMA::SIGNIN_USER_BY_TRAY);
815    Shell::GetInstance()->system_tray_delegate()->ShowUserLogin();
816  } else {
817    NOTREACHED();
818  }
819}
820
821void UserView::AddLogoutButton(user::LoginStatus login) {
822  const base::string16 title = user::GetLocalizedSignOutStringForStatus(login,
823                                                                        true);
824  TrayPopupLabelButton* logout_button = new TrayPopupLabelButton(this, title);
825  logout_button->SetAccessibleName(title);
826  logout_button_ = logout_button;
827  // In public account mode, the logout button border has a custom color.
828  if (login == user::LOGGED_IN_PUBLIC) {
829    TrayPopupLabelButtonBorder* border =
830        static_cast<TrayPopupLabelButtonBorder*>(logout_button_->border());
831    border->SetPainter(false, views::Button::STATE_NORMAL,
832                       views::Painter::CreateImageGridPainter(
833                           kPublicAccountLogoutButtonBorderImagesNormal));
834    border->SetPainter(false, views::Button::STATE_HOVERED,
835                       views::Painter::CreateImageGridPainter(
836                           kPublicAccountLogoutButtonBorderImagesHovered));
837    border->SetPainter(false, views::Button::STATE_PRESSED,
838                       views::Painter::CreateImageGridPainter(
839                           kPublicAccountLogoutButtonBorderImagesHovered));
840  }
841  AddChildView(logout_button_);
842}
843
844void UserView::AddUserCard(SystemTrayItem* owner, user::LoginStatus login) {
845  // Add padding around the panel.
846  set_border(views::Border::CreateEmptyBorder(
847      kUserCardVerticalPadding, kTrayPopupPaddingHorizontal,
848      kUserCardVerticalPadding, kTrayPopupPaddingHorizontal));
849
850  if (SupportsMultiProfile() && login != user::LOGGED_IN_RETAIL_MODE) {
851    user_card_view_ = new UserCard(this, multiprofile_index_ == 0);
852    is_user_card_ = true;
853  } else {
854    user_card_view_ = new views::View();
855    is_user_card_ = false;
856  }
857
858  user_card_view_->SetLayoutManager(new views::BoxLayout(
859      views::BoxLayout::kHorizontal, 0, 0 , kTrayPopupPaddingBetweenItems));
860  AddChildViewAt(user_card_view_, 0);
861
862  if (login == user::LOGGED_IN_RETAIL_MODE) {
863    AddLoggedInRetailModeUserCardContent();
864    return;
865  }
866
867  // The entire user card should trigger hover (the inner items get disabled).
868  user_card_view_->SetEnabled(true);
869  user_card_view_->set_notify_enter_exit_on_child(true);
870
871  if (login == user::LOGGED_IN_PUBLIC) {
872    AddLoggedInPublicModeUserCardContent(owner);
873    return;
874  }
875
876  views::View* icon = CreateIconForUserCard(login);
877  user_card_view_->AddChildView(icon);
878
879  // To allow the border to start before the icon, reduce the size before and
880  // add an inset to the icon to get the spacing.
881  if (multiprofile_index_ == 0 && SupportsMultiProfile()) {
882    icon->set_border(views::Border::CreateEmptyBorder(
883        0, kTrayUserTileHoverBorderInset, 0, 0));
884    set_border(views::Border::CreateEmptyBorder(
885        kUserCardVerticalPadding,
886        kTrayPopupPaddingHorizontal - kTrayUserTileHoverBorderInset,
887        kUserCardVerticalPadding,
888        kTrayPopupPaddingHorizontal));
889  }
890  SessionStateDelegate* delegate =
891      Shell::GetInstance()->session_state_delegate();
892  views::Label* username = NULL;
893  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
894  if (!multiprofile_index_) {
895    base::string16 user_name_string =
896        login == user::LOGGED_IN_GUEST ?
897            bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_GUEST_LABEL) :
898            delegate->GetUserDisplayName(multiprofile_index_);
899    if (!user_name_string.empty()) {
900      username = new views::Label(user_name_string);
901      username->SetHorizontalAlignment(gfx::ALIGN_LEFT);
902    }
903  }
904
905  views::Label* additional = NULL;
906  if (login != user::LOGGED_IN_GUEST) {
907    base::string16 user_email_string =
908        login == user::LOGGED_IN_LOCALLY_MANAGED ?
909            bundle.GetLocalizedString(
910                IDS_ASH_STATUS_TRAY_LOCALLY_MANAGED_LABEL) :
911            UTF8ToUTF16(delegate->GetUserEmail(multiprofile_index_));
912    if (!user_email_string.empty()) {
913      additional = new views::Label(user_email_string);
914      additional->SetFont(bundle.GetFont(ui::ResourceBundle::SmallFont));
915      additional->SetHorizontalAlignment(gfx::ALIGN_LEFT);
916    }
917  }
918
919  // Adjust text properties dependent on if it is an active or inactive user.
920  if (multiprofile_index_) {
921    // Fade the text of non active users to 50%.
922    SkColor text_color = additional->enabled_color();
923    text_color = SkColorSetA(text_color, SkColorGetA(text_color) / 2);
924    if (additional)
925      additional->SetDisabledColor(text_color);
926    if (username)
927      username->SetDisabledColor(text_color);
928  }
929
930  if (additional && username) {
931    views::View* details = new views::View;
932    details->SetLayoutManager(new views::BoxLayout(
933        views::BoxLayout::kVertical, 0, kUserDetailsVerticalPadding, 0));
934    details->AddChildView(username);
935    details->AddChildView(additional);
936    user_card_view_->AddChildView(details);
937  } else {
938    if (username)
939      user_card_view_->AddChildView(username);
940    if (additional)
941      user_card_view_->AddChildView(additional);
942  }
943}
944
945views::View* UserView::CreateIconForUserCard(user::LoginStatus login) {
946  RoundedImageView* icon = new RoundedImageView(kProfileRoundedCornerRadius,
947                                                multiprofile_index_ == 0);
948  icon->SetEnabled(false);
949  if (login == user::LOGGED_IN_GUEST) {
950    icon->SetImage(*ui::ResourceBundle::GetSharedInstance().
951        GetImageNamed(IDR_AURA_UBER_TRAY_GUEST_ICON).ToImageSkia(),
952        gfx::Size(kUserIconSize, kUserIconSize));
953  } else {
954    icon->SetImage(
955        Shell::GetInstance()->session_state_delegate()->
956            GetUserImage(multiprofile_index_),
957        gfx::Size(kUserIconSize, kUserIconSize));
958  }
959  return icon;
960}
961
962void UserView::AddLoggedInRetailModeUserCardContent() {
963  views::Label* details = new views::Label;
964  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
965  details->SetText(
966      bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_KIOSK_LABEL));
967  details->set_border(views::Border::CreateEmptyBorder(0, 4, 0, 1));
968  details->SetHorizontalAlignment(gfx::ALIGN_LEFT);
969  user_card_view_->AddChildView(details);
970}
971
972void UserView::AddLoggedInPublicModeUserCardContent(SystemTrayItem* owner) {
973  user_card_view_->AddChildView(CreateIconForUserCard(user::LOGGED_IN_PUBLIC));
974  user_card_view_->AddChildView(new PublicAccountUserDetails(
975      owner, GetPreferredSize().width() + kTrayPopupPaddingBetweenItems));
976}
977
978void UserView::ToggleAddUserMenuOption() {
979  if (add_menu_option_.get()) {
980    popup_message_.reset();
981    mouse_watcher_.reset();
982    add_menu_option_.reset();
983    return;
984  }
985
986  // Note: We do not need to install a global event handler to delete this
987  // item since it will destroyed automatically before the menu / user menu item
988  // gets destroyed..
989  const SessionStateDelegate* session_state_delegate =
990      Shell::GetInstance()->session_state_delegate();
991  add_user_visible_but_disabled_ =
992      session_state_delegate->NumberOfLoggedInUsers() >=
993          session_state_delegate->GetMaximumNumberOfLoggedInUsers();
994  add_menu_option_.reset(new views::Widget);
995  views::Widget::InitParams params;
996  params.type = views::Widget::InitParams::TYPE_TOOLTIP;
997  params.keep_on_top = true;
998  params.context = this->GetWidget()->GetNativeWindow();
999  params.accept_events = true;
1000  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1001  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
1002  add_menu_option_->Init(params);
1003  add_menu_option_->SetOpacity(0xFF);
1004  add_menu_option_->GetNativeWindow()->set_owned_by_parent(false);
1005  SetShadowType(add_menu_option_->GetNativeView(),
1006                views::corewm::SHADOW_TYPE_NONE);
1007
1008  // Position it below our user card.
1009  gfx::Rect bounds = user_card_view_->GetBoundsInScreen();
1010  bounds.set_y(bounds.y() + bounds.height());
1011  add_menu_option_->SetBounds(bounds);
1012
1013  // Show the content.
1014  AddUserView* add_user_view = new AddUserView(
1015      static_cast<UserCard*>(user_card_view_), this);
1016  add_menu_option_->SetContentsView(add_user_view);
1017  add_menu_option_->SetAlwaysOnTop(true);
1018  add_menu_option_->Show();
1019  if (add_user_visible_but_disabled_) {
1020    ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
1021    popup_message_.reset(new PopupMessage(
1022        bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_CAPTION_CANNOT_ADD_USER),
1023        bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_MESSAGE_CANNOT_ADD_USER),
1024        PopupMessage::ICON_WARNING,
1025        add_user_view->anchor(),
1026        views::BubbleBorder::TOP_LEFT,
1027        gfx::Size(parent()->bounds().width() - kPopupMessageOffset, 0),
1028        2 * kPopupMessageOffset));
1029  }
1030  // Find the screen area which encloses both elements and sets then a mouse
1031  // watcher which will close the "menu".
1032  gfx::Rect area = user_card_view_->GetBoundsInScreen();
1033  area.set_height(2 * area.height());
1034  mouse_watcher_.reset(new views::MouseWatcher(
1035      new UserViewMouseWatcherHost(area),
1036      this));
1037  mouse_watcher_->Start();
1038}
1039
1040bool UserView::SupportsMultiProfile() {
1041  // We do not want to see any multi profile additions to a user view when the
1042  // log in screen is shown.
1043  return Shell::GetInstance()->delegate()->IsMultiProfilesEnabled() &&
1044      !Shell::GetInstance()->session_state_delegate()->IsUserSessionBlocked();
1045}
1046
1047AddUserView::AddUserView(UserCard* owner, views::ButtonListener* listener)
1048    : CustomButton(listener_),
1049      add_user_(NULL),
1050      listener_(listener),
1051      owner_(owner),
1052      anchor_(NULL) {
1053  AddContent();
1054  owner_->ForceBorderVisible(true);
1055}
1056
1057AddUserView::~AddUserView() {
1058  owner_->ForceBorderVisible(false);
1059}
1060
1061gfx::Size AddUserView::GetPreferredSize() {
1062  return owner_->bounds().size();
1063}
1064
1065int AddUserView::GetHeightForWidth(int width) {
1066  return owner_->bounds().size().height();
1067}
1068
1069void AddUserView::Layout() {
1070  gfx::Rect contents_area(GetContentsBounds());
1071  add_user_->SetBoundsRect(contents_area);
1072}
1073
1074void AddUserView::ButtonPressed(views::Button* sender, const ui::Event& event) {
1075  if (add_user_ == sender)
1076    listener_->ButtonPressed(this, event);
1077  else
1078    NOTREACHED();
1079}
1080
1081void AddUserView::AddContent() {
1082  set_notify_enter_exit_on_child(true);
1083
1084  const SessionStateDelegate* delegate =
1085      Shell::GetInstance()->session_state_delegate();
1086  bool enable = delegate->NumberOfLoggedInUsers() <
1087                    delegate->GetMaximumNumberOfLoggedInUsers();
1088
1089  SetLayoutManager(new views::FillLayout());
1090  set_background(views::Background::CreateSolidBackground(kBackgroundColor));
1091
1092  // Add padding around the panel.
1093  set_border(views::Border::CreateSolidBorder(1, kBorderColor));
1094
1095  add_user_ = new UserCard(this, enable);
1096  add_user_->set_border(views::Border::CreateEmptyBorder(
1097      kUserCardVerticalPadding,
1098      kTrayPopupPaddingHorizontal- kTrayUserTileHoverBorderInset,
1099      kUserCardVerticalPadding,
1100      kTrayPopupPaddingHorizontal- kTrayUserTileHoverBorderInset));
1101
1102  add_user_->SetLayoutManager(new views::BoxLayout(
1103      views::BoxLayout::kHorizontal, 0, 0 , kTrayPopupPaddingBetweenItems));
1104  AddChildViewAt(add_user_, 0);
1105
1106  // Add the [+] icon which is also the anchor for messages.
1107  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
1108  RoundedImageView* icon = new RoundedImageView(kProfileRoundedCornerRadius,
1109                                                true);
1110  anchor_ = icon;
1111  icon->SetImage(*ui::ResourceBundle::GetSharedInstance().
1112      GetImageNamed(IDR_AURA_UBER_TRAY_ADD_MULTIPROFILE_USER).ToImageSkia(),
1113      gfx::Size(kUserIconSize, kUserIconSize));
1114  add_user_->AddChildView(icon);
1115
1116  // Add the command text.
1117  views::Label* command_label = new views::Label(
1118      bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_SIGN_IN_ANOTHER_ACCOUNT));
1119  command_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1120  add_user_->AddChildView(command_label);
1121}
1122
1123}  // namespace tray
1124
1125TrayUser::TrayUser(SystemTray* system_tray, MultiProfileIndex index)
1126    : SystemTrayItem(system_tray),
1127      multiprofile_index_(index),
1128      user_(NULL),
1129      layout_view_(NULL),
1130      avatar_(NULL),
1131      label_(NULL),
1132      separator_shown_(false) {
1133  Shell::GetInstance()->system_tray_notifier()->AddUserObserver(this);
1134}
1135
1136TrayUser::~TrayUser() {
1137  Shell::GetInstance()->system_tray_notifier()->RemoveUserObserver(this);
1138}
1139
1140TrayUser::TestState TrayUser::GetStateForTest() const {
1141  if (separator_shown_)
1142    return SEPARATOR;
1143  if (!user_)
1144    return HIDDEN;
1145  return user_->GetStateForTest();
1146}
1147
1148bool TrayUser::CanDropWindowHereToTransferToUser(
1149    const gfx::Point& point_in_screen) {
1150  // Check that this item is shown in the system tray (which means it must have
1151  // a view there) and that the user it represents is not the current user (in
1152  // which case |GetTrayIndex()| would return NULL).
1153  if (!layout_view_ || !GetTrayIndex())
1154    return false;
1155  return layout_view_->GetBoundsInScreen().Contains(point_in_screen);
1156}
1157
1158bool TrayUser::TransferWindowToUser(aura::Window* window) {
1159  SessionStateDelegate* session_state_delegate =
1160      ash::Shell::GetInstance()->session_state_delegate();
1161  return session_state_delegate->TransferWindowToDesktopOfUser(window,
1162                                                               GetTrayIndex());
1163}
1164
1165gfx::Rect TrayUser::GetUserPanelBoundsInScreenForTest() const {
1166  DCHECK(user_);
1167  return user_->GetBoundsInScreenOfUserButtonForTest();
1168}
1169
1170views::View* TrayUser::CreateTrayView(user::LoginStatus status) {
1171  CHECK(layout_view_ == NULL);
1172  // When the full multi profile mode is used, only the active user will be
1173  // shown in the system tray, otherwise all users which are logged in.
1174  if (GetTrayIndex() && switches::UseFullMultiProfileMode())
1175    return NULL;
1176
1177  layout_view_ = new views::View();
1178  layout_view_->SetLayoutManager(
1179      new views::BoxLayout(views::BoxLayout::kHorizontal,
1180                           0, 0, kUserLabelToIconPadding));
1181  UpdateAfterLoginStatusChange(status);
1182  return layout_view_;
1183}
1184
1185views::View* TrayUser::CreateDefaultView(user::LoginStatus status) {
1186  if (status == user::LOGGED_IN_NONE)
1187    return NULL;
1188  const SessionStateDelegate* session_state_delegate =
1189      Shell::GetInstance()->session_state_delegate();
1190
1191  // If the screen is locked show only the currently active user.
1192  if (multiprofile_index_ && session_state_delegate->IsUserSessionBlocked())
1193    return NULL;
1194
1195  CHECK(user_ == NULL);
1196
1197  int logged_in_users = session_state_delegate->NumberOfLoggedInUsers();
1198
1199  // If there are multiple users logged in, the users will be separated from the
1200  // rest of the menu by a separator.
1201  if (multiprofile_index_ ==
1202          session_state_delegate->GetMaximumNumberOfLoggedInUsers() &&
1203      logged_in_users > 1) {
1204    separator_shown_ = true;
1205    return new views::View();
1206  }
1207
1208  // Do not show more UserView's then there are logged in users.
1209  if (multiprofile_index_ >= logged_in_users)
1210    return NULL;
1211
1212  user_ = new tray::UserView(this, status, multiprofile_index_);
1213  return user_;
1214}
1215
1216views::View* TrayUser::CreateDetailedView(user::LoginStatus status) {
1217  return NULL;
1218}
1219
1220void TrayUser::DestroyTrayView() {
1221  layout_view_ = NULL;
1222  avatar_ = NULL;
1223  label_ = NULL;
1224  separator_shown_ = false;
1225}
1226
1227void TrayUser::DestroyDefaultView() {
1228  user_ = NULL;
1229}
1230
1231void TrayUser::DestroyDetailedView() {
1232}
1233
1234void TrayUser::UpdateAfterLoginStatusChange(user::LoginStatus status) {
1235  // Only the active user is represented in the tray.
1236  if (!layout_view_)
1237    return;
1238  bool need_label = false;
1239  bool need_avatar = false;
1240  switch (status) {
1241    case user::LOGGED_IN_LOCKED:
1242    case user::LOGGED_IN_USER:
1243    case user::LOGGED_IN_OWNER:
1244    case user::LOGGED_IN_PUBLIC:
1245      need_avatar = true;
1246      break;
1247    case user::LOGGED_IN_LOCALLY_MANAGED:
1248      need_avatar = true;
1249      need_label = true;
1250      break;
1251    case user::LOGGED_IN_GUEST:
1252      need_label = true;
1253      break;
1254    case user::LOGGED_IN_RETAIL_MODE:
1255    case user::LOGGED_IN_KIOSK_APP:
1256    case user::LOGGED_IN_NONE:
1257      break;
1258  }
1259
1260  if ((need_avatar != (avatar_ != NULL)) ||
1261      (need_label != (label_ != NULL))) {
1262    layout_view_->RemoveAllChildViews(true);
1263    if (need_label) {
1264      label_ = new views::Label;
1265      SetupLabelForTray(label_);
1266      layout_view_->AddChildView(label_);
1267    } else {
1268      label_ = NULL;
1269    }
1270    if (need_avatar) {
1271      MultiProfileIndex tray_index = GetTrayIndex();
1272      if (!tray_index) {
1273        // The active user (index #0) will always be the first.
1274        avatar_ = new tray::RoundedImageView(kProfileRoundedCornerRadius, true);
1275      } else {
1276        // All other users will be inactive users.
1277        avatar_ = new tray::UserSwitcherView(kProfileRoundedCornerRadius,
1278                                             tray_index);
1279      }
1280      layout_view_->AddChildView(avatar_);
1281    } else {
1282      avatar_ = NULL;
1283    }
1284  }
1285
1286  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
1287  if (status == user::LOGGED_IN_LOCALLY_MANAGED) {
1288    label_->SetText(
1289        bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_LOCALLY_MANAGED_LABEL));
1290  } else if (status == user::LOGGED_IN_GUEST) {
1291    label_->SetText(bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_GUEST_LABEL));
1292  }
1293
1294  if (avatar_ && switches::UseAlternateShelfLayout()) {
1295    int corner_radius = GetTrayItemRadius();
1296    avatar_->SetCornerRadii(0, corner_radius, corner_radius, 0);
1297    avatar_->set_border(NULL);
1298  }
1299  UpdateAvatarImage(status);
1300
1301  // Update layout after setting label_ and avatar_ with new login status.
1302  UpdateLayoutOfItem();
1303}
1304
1305void TrayUser::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
1306  // Inactive users won't have a layout.
1307  if (!layout_view_)
1308    return;
1309  int corner_radius = GetTrayItemRadius();
1310  if (alignment == SHELF_ALIGNMENT_BOTTOM ||
1311      alignment == SHELF_ALIGNMENT_TOP) {
1312    if (avatar_) {
1313      if (switches::UseAlternateShelfLayout()) {
1314        if (multiprofile_index_) {
1315          avatar_->set_border(
1316              views::Border::CreateEmptyBorder(0, kTrayLabelSpacing, 0, 0));
1317        } else {
1318          avatar_->set_border(NULL);
1319        }
1320        avatar_->SetCornerRadii(0, corner_radius, corner_radius, 0);
1321      } else {
1322        avatar_->set_border(views::Border::CreateEmptyBorder(
1323            0, kTrayImageItemHorizontalPaddingBottomAlignment + 2,
1324            0, kTrayImageItemHorizontalPaddingBottomAlignment));
1325      }
1326    }
1327    if (label_) {
1328      label_->set_border(views::Border::CreateEmptyBorder(
1329          0, kTrayLabelItemHorizontalPaddingBottomAlignment,
1330          0, kTrayLabelItemHorizontalPaddingBottomAlignment));
1331    }
1332    layout_view_->SetLayoutManager(
1333        new views::BoxLayout(views::BoxLayout::kHorizontal,
1334                             0, 0, kUserLabelToIconPadding));
1335  } else {
1336    if (avatar_) {
1337      if (switches::UseAlternateShelfLayout()) {
1338        if (multiprofile_index_) {
1339          avatar_->set_border(
1340              views::Border::CreateEmptyBorder(kTrayLabelSpacing, 0, 0, 0));
1341        } else {
1342          avatar_->set_border(NULL);
1343        }
1344        avatar_->SetCornerRadii(0, 0, corner_radius, corner_radius);
1345      } else {
1346        SetTrayImageItemBorder(avatar_, alignment);
1347      }
1348    }
1349    if (label_) {
1350      label_->set_border(views::Border::CreateEmptyBorder(
1351          kTrayLabelItemVerticalPaddingVerticalAlignment,
1352          kTrayLabelItemHorizontalPaddingBottomAlignment,
1353          kTrayLabelItemVerticalPaddingVerticalAlignment,
1354          kTrayLabelItemHorizontalPaddingBottomAlignment));
1355    }
1356    layout_view_->SetLayoutManager(
1357        new views::BoxLayout(views::BoxLayout::kVertical,
1358                             0, 0, kUserLabelToIconPadding));
1359  }
1360}
1361
1362void TrayUser::OnUserUpdate() {
1363  UpdateAvatarImage(Shell::GetInstance()->system_tray_delegate()->
1364      GetUserLoginStatus());
1365}
1366
1367void TrayUser::OnUserAddedToSession() {
1368  SessionStateDelegate* session_state_delegate =
1369      Shell::GetInstance()->session_state_delegate();
1370  // Only create views for user items which are logged in.
1371  if (GetTrayIndex() >= session_state_delegate->NumberOfLoggedInUsers())
1372    return;
1373
1374  // Enforce a layout change that newly added items become visible.
1375  UpdateLayoutOfItem();
1376
1377  // Update the user item.
1378  UpdateAvatarImage(
1379      Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus());
1380}
1381
1382void TrayUser::UpdateAvatarImage(user::LoginStatus status) {
1383  SessionStateDelegate* session_state_delegate =
1384      Shell::GetInstance()->session_state_delegate();
1385  if (!avatar_ ||
1386      GetTrayIndex() >= session_state_delegate->NumberOfLoggedInUsers())
1387    return;
1388
1389  int icon_size = switches::UseAlternateShelfLayout() ?
1390      kUserIconLargeSize : kUserIconSize;
1391
1392  avatar_->SetImage(
1393      Shell::GetInstance()->session_state_delegate()->GetUserImage(
1394          GetTrayIndex()),
1395      gfx::Size(icon_size, icon_size));
1396
1397  // Unit tests might come here with no images for some users.
1398  if (avatar_->size().IsEmpty())
1399    avatar_->SetSize(gfx::Size(icon_size, icon_size));
1400}
1401
1402MultiProfileIndex TrayUser::GetTrayIndex() {
1403  Shell* shell = Shell::GetInstance();
1404  // If multi profile is not enabled we can use the normal index.
1405  if (!shell->delegate()->IsMultiProfilesEnabled())
1406    return multiprofile_index_;
1407  // In case of multi profile we need to mirror the indices since the system
1408  // tray items are in the reverse order then the menu items.
1409  return shell->session_state_delegate()->GetMaximumNumberOfLoggedInUsers() -
1410             multiprofile_index_;
1411}
1412
1413int TrayUser::GetTrayItemRadius() {
1414  SessionStateDelegate* delegate =
1415      Shell::GetInstance()->session_state_delegate();
1416  bool is_last_item = GetTrayIndex() == (delegate->NumberOfLoggedInUsers() - 1);
1417  return is_last_item ? kUserIconLargeCornerRadius : 0;
1418}
1419
1420void TrayUser::UpdateLayoutOfItem() {
1421  internal::RootWindowController* controller =
1422      internal::GetRootWindowController(
1423          system_tray()->GetWidget()->GetNativeWindow()->GetRootWindow());
1424  if (controller && controller->shelf()) {
1425    UpdateAfterShelfAlignmentChange(
1426        controller->GetShelfLayoutManager()->GetAlignment());
1427  }
1428}
1429
1430}  // namespace internal
1431}  // namespace ash
1432