1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/views/passwords/credentials_item_view.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h"
9 #include "chrome/grit/generated_resources.h"
10 #include "components/autofill/core/common/password_form.h"
11 #include "grit/theme_resources.h"
12 #include "ui/base/l10n/l10n_util.h"
13 #include "ui/base/resource/resource_bundle.h"
14 #include "ui/gfx/canvas.h"
15 #include "ui/gfx/image/image.h"
16 #include "ui/gfx/path.h"
17 #include "ui/views/border.h"
18 #include "ui/views/controls/image_view.h"
19 #include "ui/views/controls/label.h"
22 // The default spacing between the icon and text.
23 const int kSpacing
= 5;
25 gfx::Size
GetTextLabelsSize(const views::Label
* upper_label
,
26 const views::Label
* lower_label
) {
27 gfx::Size upper_label_size
= upper_label
? upper_label
->GetPreferredSize()
29 gfx::Size lower_label_size
= lower_label
? lower_label
->GetPreferredSize()
31 return gfx::Size(std::max(upper_label_size
.width(), lower_label_size
.width()),
32 upper_label_size
.height() + lower_label_size
.height());
35 class CircularImageView
: public views::ImageView
{
37 CircularImageView() = default;
41 void OnPaint(gfx::Canvas
* canvas
) override
;
43 DISALLOW_COPY_AND_ASSIGN(CircularImageView
);
46 void CircularImageView::OnPaint(gfx::Canvas
* canvas
) {
47 // Display the avatar picture as a circle.
48 gfx::Rect
bounds(GetImageBounds());
49 gfx::Path circular_mask
;
50 circular_mask
.addCircle(
51 SkIntToScalar(bounds
.x() + bounds
.right()) / 2,
52 SkIntToScalar(bounds
.y() + bounds
.bottom()) / 2,
53 SkIntToScalar(std::min(bounds
.height(), bounds
.width())) / 2);
54 canvas
->ClipPath(circular_mask
, true);
55 ImageView::OnPaint(canvas
);
60 CredentialsItemView::CredentialsItemView(
61 views::ButtonListener
* button_listener
,
62 const autofill::PasswordForm
* form
,
63 password_manager::CredentialType credential_type
,
64 const base::string16
& upper_text
,
65 const base::string16
& lower_text
,
66 net::URLRequestContextGetter
* request_context
)
67 : LabelButton(button_listener
, base::string16()),
69 credential_type_(credential_type
),
70 upper_label_(nullptr),
71 lower_label_(nullptr),
72 weak_ptr_factory_(this) {
73 set_notify_enter_exit_on_child(true);
74 // Create an image-view for the avatar. Make sure it ignores events so that
75 // the parent can receive the events instead.
76 image_view_
= new CircularImageView
;
77 image_view_
->set_interactive(false);
78 gfx::Image image
= ResourceBundle::GetSharedInstance().GetImageNamed(
79 IDR_PROFILE_AVATAR_PLACEHOLDER_LARGE
);
80 DCHECK(image
.Width() >= kAvatarImageSize
&&
81 image
.Height() >= kAvatarImageSize
);
82 UpdateAvatar(image
.AsImageSkia());
83 if (form_
->icon_url
.is_valid()) {
84 // Fetch the actual avatar.
85 AccountAvatarFetcher
* fetcher
= new AccountAvatarFetcher(
86 form_
->icon_url
, weak_ptr_factory_
.GetWeakPtr());
87 fetcher
->Start(request_context
);
89 AddChildView(image_view_
);
91 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
92 if (!upper_text
.empty()) {
93 upper_label_
= new views::Label(
94 upper_text
, rb
->GetFontList(ui::ResourceBundle::BoldFont
));
95 upper_label_
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
96 AddChildView(upper_label_
);
99 if (!lower_text
.empty()) {
100 lower_label_
= new views::Label(
101 lower_text
, rb
->GetFontList(ui::ResourceBundle::SmallFont
));
102 lower_label_
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
103 AddChildView(lower_label_
);
109 CredentialsItemView::~CredentialsItemView() = default;
111 gfx::Size
CredentialsItemView::GetPreferredSize() const {
112 gfx::Size labels_size
= GetTextLabelsSize(upper_label_
, lower_label_
);
113 gfx::Size size
= gfx::Size(kAvatarImageSize
+ labels_size
.width(),
114 std::max(kAvatarImageSize
, labels_size
.height()));
115 const gfx::Insets
insets(GetInsets());
116 size
.Enlarge(insets
.width(), insets
.height());
117 size
.Enlarge(kSpacing
, 0);
119 // Make the size at least as large as the minimum size needed by the border.
120 size
.SetToMax(border() ? border()->GetMinimumSize() : gfx::Size());
124 int CredentialsItemView::GetHeightForWidth(int w
) const {
125 return View::GetHeightForWidth(w
);
128 void CredentialsItemView::Layout() {
129 gfx::Rect
child_area(GetChildAreaBounds());
130 child_area
.Inset(GetInsets());
132 gfx::Size
image_size(image_view_
->GetPreferredSize());
133 image_size
.SetToMin(child_area
.size());
134 gfx::Point
image_origin(child_area
.origin());
135 image_origin
.Offset(0, (child_area
.height() - image_size
.height()) / 2);
136 image_view_
->SetBoundsRect(gfx::Rect(image_origin
, image_size
));
138 gfx::Size upper_size
=
139 upper_label_
? upper_label_
->GetPreferredSize() : gfx::Size();
140 gfx::Size lower_size
=
141 lower_label_
? lower_label_
->GetPreferredSize() : gfx::Size();
142 int y_offset
= (child_area
.height() -
143 (upper_size
.height() + lower_size
.height())) / 2;
144 gfx::Point
label_origin(image_origin
.x() + image_size
.width() + kSpacing
,
145 child_area
.origin().y() + y_offset
);
147 upper_label_
->SetBoundsRect(gfx::Rect(label_origin
, upper_size
));
149 label_origin
.Offset(0, upper_size
.height());
150 lower_label_
->SetBoundsRect(gfx::Rect(label_origin
, lower_size
));
154 void CredentialsItemView::UpdateAvatar(const gfx::ImageSkia
& image
) {
155 image_view_
->SetImage(ScaleImageForAccountAvatar(image
));