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