OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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. | |
4 | |
5 #include "chrome/browser/ui/views/avatar_menu_bubble_view.h" | |
6 | |
7 #include "base/utf_string_conversions.h" | |
8 #include "chrome/browser/browser_process.h" | |
9 #include "chrome/browser/ui/browser.h" | |
10 #include "chrome/browser/profiles/avatar_menu_model.h" | |
11 #include "chrome/browser/profiles/profile_info_cache.h" | |
12 #include "chrome/browser/profiles/profile_manager.h" | |
13 #include "grit/generated_resources.h" | |
14 #include "grit/theme_resources.h" | |
15 #include "ui/base/l10n/l10n_util.h" | |
16 #include "ui/base/resource/resource_bundle.h" | |
17 #include "ui/gfx/canvas.h" | |
18 #include "ui/gfx/font.h" | |
19 #include "ui/gfx/image/image.h" | |
20 #include "views/controls/button/image_button.h" | |
21 | |
22 namespace { | |
23 | |
24 const int kBubbleViewMinWidth = 175; | |
25 const int kBubbleViewMaxWidth = 800; | |
26 const int kItemHeight = 32; | |
27 const int kItemMarginY = 8; | |
28 const int kIconWidth = 38; | |
29 const int kIconMarginX = 6; | |
30 const int kEditProfileButtonMarginX = 8; | |
31 | |
32 inline int Round(double x) { | |
33 return static_cast<int>(x + 0.5); | |
34 } | |
35 | |
36 gfx::Rect GetCenteredAndScaledRect(int src_width, int src_height, | |
37 int dst_x, int dst_y, | |
38 int dst_width, int dst_height) { | |
39 int scaled_width; | |
40 int scaled_height; | |
41 if (src_width > src_height) { | |
42 scaled_width = std::min(src_width, dst_width); | |
43 float scale = static_cast<float>(scaled_width) / | |
44 static_cast<float>(src_width); | |
45 scaled_height = Round(src_height * scale); | |
46 } else { | |
47 scaled_height = std::min(src_height, dst_height); | |
48 float scale = static_cast<float>(scaled_height) / | |
49 static_cast<float>(src_height); | |
50 scaled_width = Round(src_width * scale); | |
51 } | |
52 int x = dst_x + (dst_width - scaled_width) / 2; | |
53 int y = dst_y + (dst_height - scaled_height) / 2; | |
54 return gfx::Rect(x, y, scaled_width, scaled_height); | |
55 } | |
56 | |
57 class ProfileItemView : public views::CustomButton { | |
58 public: | |
59 ProfileItemView(const AvatarMenuModel::Item& item, | |
60 views::ButtonListener* listener) | |
61 : views::CustomButton(listener), | |
62 item_(item) { | |
63 } | |
64 | |
65 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { | |
66 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
67 | |
68 // Draw the profile icon on the left. | |
69 SkBitmap profile_icon = item_.icon; | |
70 gfx::Rect profile_icon_rect = GetCenteredAndScaledRect( | |
71 profile_icon.width(), profile_icon.height(), | |
72 0, 0, kIconWidth, height()); | |
73 canvas->DrawBitmapInt(profile_icon, 0, 0, profile_icon.width(), | |
74 profile_icon.height(), profile_icon_rect.x(), | |
75 profile_icon_rect.y(), profile_icon_rect.width(), | |
76 profile_icon_rect.height(), false); | |
77 | |
78 // If this profile is selected then draw a check mark on the bottom right | |
79 // of the profile icon. | |
80 if (item_.active) { | |
81 SkBitmap check_icon = rb.GetImageNamed(IDR_PROFILE_SELECTED); | |
82 int y = profile_icon_rect.bottom() - check_icon.height(); | |
83 int x = profile_icon_rect.right() - check_icon.width() + 2; | |
84 canvas->DrawBitmapInt(check_icon, 0, 0, check_icon.width(), | |
85 check_icon.height(), x, y, check_icon.width(), | |
86 check_icon.height(), false); | |
87 } | |
88 | |
89 // Draw the profile name to the right of the profile icon. | |
90 int name_x = profile_icon_rect.right() + kIconMarginX; | |
91 canvas->DrawStringInt(item_.name, rb.GetFont(ResourceBundle::BaseFont), | |
92 GetNameColor(), name_x, 0, width() - name_x, | |
93 height()); | |
94 } | |
95 | |
96 virtual gfx::Size GetPreferredSize() OVERRIDE { | |
97 gfx::Font font = ResourceBundle::GetSharedInstance().GetFont( | |
98 ResourceBundle::BaseFont); | |
99 int title_width = font.GetStringWidth(item_.name); | |
100 return gfx::Size(kIconWidth + kIconMarginX + title_width, kItemHeight); | |
101 } | |
102 | |
103 private: | |
104 SkColor GetNameColor() { | |
105 bool normal = state() != views::CustomButton::BS_PUSHED && | |
106 state() != views::CustomButton::BS_HOT; | |
107 if (item_.active) | |
108 return normal ? SkColorSetRGB(30, 30, 30) : SkColorSetRGB(0, 0, 0); | |
109 return normal ? SkColorSetRGB(128, 128, 128) : SkColorSetRGB(64, 64, 64); | |
110 } | |
111 | |
112 AvatarMenuModel::Item item_; | |
113 }; | |
114 | |
115 } // namespace | |
116 | |
117 class EditProfileButton : public views::ImageButton { | |
118 public: | |
119 EditProfileButton(size_t profile_index, views::ButtonListener* listener) | |
120 : views::ImageButton(listener), | |
121 profile_index_(profile_index) { | |
122 } | |
123 | |
124 size_t profile_index() { | |
125 return profile_index_; | |
126 } | |
127 | |
128 private: | |
129 size_t profile_index_; | |
130 }; | |
131 | |
132 AvatarMenuBubbleView::AvatarMenuBubbleView(Browser* browser) | |
133 : add_profile_link_(NULL), | |
134 browser_(browser), | |
135 edit_profile_button_(NULL) { | |
136 avatar_menu_model_.reset(new AvatarMenuModel( | |
137 &g_browser_process->profile_manager()->GetProfileInfoCache(), | |
138 this, browser_)); | |
139 } | |
140 | |
141 AvatarMenuBubbleView::~AvatarMenuBubbleView() { | |
142 } | |
143 | |
144 gfx::Size AvatarMenuBubbleView::GetPreferredSize() { | |
145 int max_width = 0; | |
146 int total_height = 0; | |
147 for (size_t i = 0; i < item_views_.size(); ++i) { | |
148 gfx::Size size = item_views_[i]->GetPreferredSize(); | |
149 if (i == edit_profile_button_->profile_index()) { | |
150 size.set_width(size.width() + | |
151 edit_profile_button_->GetPreferredSize().width() + | |
152 kEditProfileButtonMarginX); | |
153 } | |
154 | |
155 max_width = std::max(max_width, size.width()); | |
156 total_height += size.height() + kItemMarginY; | |
157 } | |
158 | |
159 gfx::Size add_profile_size = add_profile_link_->GetPreferredSize(); | |
160 max_width = std::max(max_width, | |
161 add_profile_size.width() + kIconWidth + kIconMarginX); | |
162 total_height += add_profile_link_->GetPreferredSize().height(); | |
163 | |
164 int total_width = std::min(std::max(max_width, kBubbleViewMinWidth), | |
165 kBubbleViewMaxWidth); | |
166 return gfx::Size(total_width, total_height); | |
167 } | |
168 | |
169 void AvatarMenuBubbleView::Layout() { | |
170 int y = 0; | |
171 for (size_t i = 0; i < item_views_.size(); ++i) { | |
172 views::CustomButton* item_view = item_views_[i]; | |
173 int item_height = item_view->GetPreferredSize().height(); | |
174 int item_width = width(); | |
175 | |
176 if (i == edit_profile_button_->profile_index()) { | |
177 gfx::Size edit_size = edit_profile_button_->GetPreferredSize(); | |
178 edit_profile_button_->SetBounds(width() - edit_size.width(), y, | |
179 edit_size.width(), item_height); | |
180 item_width -= edit_size.width() + kEditProfileButtonMarginX; | |
181 } | |
182 | |
183 item_view->SetBounds(0, y, item_width, item_height); | |
184 y += item_height + kItemMarginY; | |
185 } | |
186 | |
187 add_profile_link_->SetBounds(kIconWidth + kIconMarginX, y, width(), | |
188 add_profile_link_->GetPreferredSize().height()); | |
189 } | |
190 | |
191 void AvatarMenuBubbleView::ButtonPressed(views::Button* sender, | |
192 const views::Event& event) { | |
193 if (sender == edit_profile_button_) { | |
194 avatar_menu_model_->EditProfile(edit_profile_button_->profile_index()); | |
195 } else { | |
196 for (size_t i = 0; i < item_views_.size(); ++i) { | |
197 if (sender == item_views_[i]) { | |
198 avatar_menu_model_->SwitchToProfile(i); | |
199 break; | |
200 } | |
201 } | |
202 } | |
203 } | |
204 | |
205 void AvatarMenuBubbleView::LinkClicked(views::Link* source, int event_flags) { | |
206 DCHECK_EQ(source, add_profile_link_); | |
207 avatar_menu_model_->AddNewProfile(); | |
208 } | |
209 | |
210 void AvatarMenuBubbleView::BubbleClosing(Bubble* bubble, | |
211 bool closed_by_escape) { | |
212 } | |
213 | |
214 bool AvatarMenuBubbleView::CloseOnEscape() { | |
215 return true; | |
216 } | |
217 | |
218 bool AvatarMenuBubbleView::FadeInOnShow() { | |
219 return false; | |
220 } | |
221 | |
222 void AvatarMenuBubbleView::OnAvatarMenuModelChanged( | |
223 AvatarMenuModel* avatar_menu_model) { | |
224 // Unset all our child view references and call RemoveAllChildViews() which | |
225 // will actually delete them. | |
226 add_profile_link_ = NULL; | |
227 edit_profile_button_ = NULL; | |
228 item_views_.clear(); | |
229 RemoveAllChildViews(true); | |
230 | |
231 for (size_t i = 0; i < avatar_menu_model->GetNumberOfItems(); ++i) { | |
232 const AvatarMenuModel::Item& item = avatar_menu_model->GetItemAt(i); | |
233 ProfileItemView* item_view = new ProfileItemView(item, this); | |
234 item_view->SetAccessibleName(l10n_util::GetStringFUTF16( | |
235 IDS_PROFILES_SWITCH_TO_PROFILE_ACCESSIBLE_NAME, item.name)); | |
236 AddChildView(item_view); | |
237 item_views_.push_back(item_view); | |
238 | |
239 if (item.active) { | |
240 DCHECK(!edit_profile_button_); | |
241 edit_profile_button_ = new EditProfileButton(i, this); | |
242 edit_profile_button_->SetAccessibleName(l10n_util::GetStringFUTF16( | |
243 IDS_PROFILES_CUSTOMIZE_PROFILE_ACCESSIBLE_NAME, item.name)); | |
244 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
245 edit_profile_button_->SetImage(views::CustomButton::BS_NORMAL, | |
246 rb.GetImageNamed(IDR_PROFILE_EDIT)); | |
247 edit_profile_button_->SetImage(views::CustomButton::BS_HOT, | |
248 rb.GetImageNamed(IDR_PROFILE_EDIT_HOVER)); | |
249 edit_profile_button_->SetImage(views::CustomButton::BS_PUSHED, | |
250 rb.GetImageNamed(IDR_PROFILE_EDIT_PRESSED)); | |
251 edit_profile_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER, | |
252 views::ImageButton::ALIGN_MIDDLE); | |
253 AddChildView(edit_profile_button_); | |
254 } | |
255 } | |
256 | |
257 add_profile_link_ = new views::Link(UTF16ToWide( | |
258 l10n_util::GetStringUTF16(IDS_PROFILES_CREATE_NEW_PROFILE_LINK))); | |
259 add_profile_link_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); | |
260 add_profile_link_->SetNormalColor(SkColorSetRGB(0, 0x79, 0xda)); | |
261 AddChildView(add_profile_link_); | |
262 | |
263 PreferredSizeChanged(); | |
264 } | |
OLD | NEW |