Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/views/avatar_menu_bubble_view.h" | 5 #include "chrome/browser/ui/views/avatar_menu_bubble_view.h" |
| 6 | 6 |
| 7 #include "base/utf_string_conversions.h" | 7 #include "base/utf_string_conversions.h" |
| 8 #include "chrome/browser/browser_process.h" | 8 #include "chrome/browser/browser_process.h" |
| 9 #include "chrome/browser/ui/browser.h" | 9 #include "chrome/browser/ui/browser.h" |
| 10 #include "chrome/browser/profiles/avatar_menu_model.h" | 10 #include "chrome/browser/profiles/avatar_menu_model.h" |
| 11 #include "chrome/browser/profiles/profile_info_cache.h" | 11 #include "chrome/browser/profiles/profile_info_cache.h" |
| 12 #include "chrome/browser/profiles/profile_manager.h" | 12 #include "chrome/browser/profiles/profile_manager.h" |
| 13 #include "grit/generated_resources.h" | 13 #include "grit/generated_resources.h" |
| 14 #include "grit/theme_resources.h" | 14 #include "grit/theme_resources.h" |
| 15 #include "ui/base/l10n/l10n_util.h" | 15 #include "ui/base/l10n/l10n_util.h" |
| 16 #include "ui/base/resource/resource_bundle.h" | 16 #include "ui/base/resource/resource_bundle.h" |
| 17 #include "ui/gfx/canvas.h" | 17 #include "ui/gfx/canvas.h" |
| 18 #include "ui/gfx/canvas_skia.h" | |
| 18 #include "ui/gfx/font.h" | 19 #include "ui/gfx/font.h" |
| 19 #include "ui/gfx/image/image.h" | 20 #include "ui/gfx/image/image.h" |
| 20 #include "views/controls/button/image_button.h" | 21 #include "views/controls/button/image_button.h" |
| 22 #include "views/controls/image_view.h" | |
| 23 #include "views/controls/label.h" | |
| 21 | 24 |
| 22 namespace { | 25 namespace { |
| 23 | 26 |
| 24 const int kBubbleViewMinWidth = 175; | 27 const int kBubbleViewMinWidth = 175; |
|
Peter Kasting
2011/10/04 20:48:52
Nit: Personally I'd find it more readable if the c
sail
2011/10/04 22:09:20
Fixed. Moved all the constants that were only bein
| |
| 25 const int kBubbleViewMaxWidth = 800; | 28 const int kBubbleViewMaxWidth = 800; |
| 26 const int kItemHeight = 32; | 29 const int kItemHeight = 44; |
| 27 const int kItemMarginY = 8; | 30 const int kItemMarginY = 4; |
| 28 const int kIconWidth = 38; | 31 const int kIconWidth = 38; |
| 29 const int kIconMarginX = 6; | 32 const int kIconMarginX = 6; |
| 30 const int kEditProfileButtonMarginX = 8; | 33 const int kNameFontDelta = 1; |
| 34 const int kStateFontDelta = -1; | |
| 35 const int kNameStatePaddingY = 2; | |
| 36 const float kBadgeOverlapRatioX = 1.0f / 5.0f; | |
| 37 const float kBadgeOverlapRatioY = 1.0f / 3.0f; | |
| 38 const int kSeparatorPaddingY = 5; | |
| 31 | 39 |
| 32 inline int Round(double x) { | 40 inline int Round(double x) { |
| 33 return static_cast<int>(x + 0.5); | 41 return static_cast<int>(x + 0.5); |
| 34 } | 42 } |
| 35 | 43 |
| 36 gfx::Rect GetCenteredAndScaledRect(int src_width, int src_height, | 44 gfx::Rect GetCenteredAndScaledRect(int src_width, int src_height, |
| 37 int dst_x, int dst_y, | 45 int dst_x, int dst_y, |
| 38 int dst_width, int dst_height) { | 46 int dst_width, int dst_height) { |
| 39 int scaled_width; | 47 int scaled_width; |
| 40 int scaled_height; | 48 int scaled_height; |
| 41 if (src_width > src_height) { | 49 if (src_width > src_height) { |
| 42 scaled_width = std::min(src_width, dst_width); | 50 scaled_width = std::min(src_width, dst_width); |
| 43 float scale = static_cast<float>(scaled_width) / | 51 float scale = static_cast<float>(scaled_width) / |
| 44 static_cast<float>(src_width); | 52 static_cast<float>(src_width); |
| 45 scaled_height = Round(src_height * scale); | 53 scaled_height = Round(src_height * scale); |
| 46 } else { | 54 } else { |
| 47 scaled_height = std::min(src_height, dst_height); | 55 scaled_height = std::min(src_height, dst_height); |
| 48 float scale = static_cast<float>(scaled_height) / | 56 float scale = static_cast<float>(scaled_height) / |
| 49 static_cast<float>(src_height); | 57 static_cast<float>(src_height); |
| 50 scaled_width = Round(src_width * scale); | 58 scaled_width = Round(src_width * scale); |
| 51 } | 59 } |
| 52 int x = dst_x + (dst_width - scaled_width) / 2; | 60 int x = dst_x + (dst_width - scaled_width) / 2; |
| 53 int y = dst_y + (dst_height - scaled_height) / 2; | 61 int y = dst_y + (dst_height - scaled_height) / 2; |
| 54 return gfx::Rect(x, y, scaled_width, scaled_height); | 62 return gfx::Rect(x, y, scaled_width, scaled_height); |
| 55 } | 63 } |
| 56 | 64 |
| 57 class ProfileItemView : public views::CustomButton { | 65 // Delegate to callback when the highlight state of a control changes. |
| 66 class HighlightDelegate { | |
| 67 public: | |
| 68 virtual void OnHighlightStateChanged() = 0; | |
| 69 }; | |
| 70 | |
| 71 // A custom Link control that forwards highlight state changes. We need to do | |
| 72 // this to make sure that the ProfileItemView looks highlighted even when | |
| 73 // the mouse is over this link. | |
| 74 class EditProfileLink : public views::Link { | |
| 75 public: | |
| 76 explicit EditProfileLink(const string16& title, | |
| 77 HighlightDelegate* delegate) | |
| 78 : views::Link(UTF16ToWideHack(title)), | |
| 79 delegate_(delegate), | |
| 80 state_(views::CustomButton::BS_NORMAL) { | |
| 81 } | |
| 82 | |
| 83 virtual void OnMouseEntered(const views::MouseEvent& event) OVERRIDE { | |
| 84 views::Link::OnMouseEntered(event); | |
| 85 state_ = views::CustomButton::BS_HOT; | |
| 86 delegate_->OnHighlightStateChanged(); | |
| 87 } | |
| 88 | |
| 89 virtual void OnMouseExited(const views::MouseEvent& event) OVERRIDE { | |
| 90 views::Link::OnMouseExited(event); | |
| 91 state_ = views::CustomButton::BS_NORMAL; | |
| 92 delegate_->OnHighlightStateChanged(); | |
| 93 } | |
| 94 | |
| 95 views::CustomButton::ButtonState state() { return state_; } | |
| 96 | |
| 97 private: | |
| 98 HighlightDelegate* delegate_; | |
| 99 views::CustomButton::ButtonState state_; | |
| 100 }; | |
| 101 | |
| 102 // A custom image view that ignores mouse events so that the parent can receive | |
| 103 // them them instead. | |
| 104 class ProfileImageView : public views::ImageView { | |
| 105 public: | |
| 106 virtual bool HitTest(const gfx::Point& l) const OVERRIDE { | |
| 107 return false; | |
| 108 } | |
| 109 }; | |
| 110 | |
| 111 // Control that shows information about a single profile. | |
| 112 class ProfileItemView : public views::CustomButton, | |
| 113 public HighlightDelegate { | |
| 58 public: | 114 public: |
| 59 ProfileItemView(const AvatarMenuModel::Item& item, | 115 ProfileItemView(const AvatarMenuModel::Item& item, |
| 60 views::ButtonListener* listener) | 116 views::ButtonListener* switch_profile_listener, |
| 61 : views::CustomButton(listener), | 117 views::LinkListener* edit_profile_listener) |
| 118 : views::CustomButton(switch_profile_listener), | |
| 62 item_(item) { | 119 item_(item) { |
| 120 image_view_ = new ProfileImageView(); | |
| 121 SkBitmap profile_icon = item_.icon; | |
| 122 if (item_.active) { | |
| 123 SkBitmap badged_icon = GetBadgedIcon(profile_icon); | |
| 124 image_view_->SetImage(&badged_icon); | |
| 125 } else { | |
| 126 image_view_->SetImage(&profile_icon); | |
| 127 } | |
| 128 AddChildView(image_view_); | |
| 129 | |
| 130 // Add a label to show the profile name. | |
| 131 name_label_ = new views::Label(UTF16ToWideHack(item_.name)); | |
| 132 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 133 gfx::Font base_font = rb.GetFont(ResourceBundle::BaseFont); | |
| 134 int style = item_.active ? gfx::Font::BOLD : 0; | |
| 135 name_label_->SetFont(base_font.DeriveFont(kNameFontDelta, style)); | |
| 136 name_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); | |
| 137 AddChildView(name_label_); | |
| 138 | |
| 139 // Add a label to show the sync state. | |
| 140 sync_state_label_ = new views::Label(UTF16ToWideHack(item_.sync_state)); | |
| 141 sync_state_label_->SetFont(base_font.DeriveFont(kStateFontDelta)); | |
| 142 sync_state_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); | |
| 143 sync_state_label_->SetEnabled(false); | |
| 144 AddChildView(sync_state_label_); | |
| 145 | |
| 146 // Add an edit profile link. | |
| 147 edit_link_ = new EditProfileLink( | |
| 148 l10n_util::GetStringUTF16(IDS_PROFILES_EDIT_PROFILE_LINK), this); | |
| 149 edit_link_->set_listener(edit_profile_listener); | |
| 150 edit_link_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); | |
| 151 edit_link_->SetNormalColor(SkColorSetRGB(0, 0x79, 0xda)); | |
|
Peter Kasting
2011/10/04 20:48:52
This is dangerous. The background color could ver
sail
2011/10/04 22:09:20
I'd like to fix this separately as a part of bug 9
Peter Kasting
2011/10/04 22:12:48
That's fine.
| |
| 152 AddChildView(edit_link_); | |
| 153 | |
| 154 OnHighlightStateChanged(); | |
| 63 } | 155 } |
| 64 | 156 |
| 65 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { | 157 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { |
| 66 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 158 if (IsHighlighted()) { |
| 67 | 159 canvas->FillRectInt(SkColorSetRGB(227, 237, 246), 0, 0, |
|
Peter Kasting
2011/10/04 20:48:52
Nit: You used hex above and decimal here.
This is
sail
2011/10/04 22:09:20
Changed to hex. As above, I'm working on fixing th
| |
| 68 // Draw the profile icon on the left. | 160 width(), height()); |
| 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 } | 161 } |
| 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 } | 162 } |
| 95 | 163 |
| 96 virtual gfx::Size GetPreferredSize() OVERRIDE { | 164 virtual gfx::Size GetPreferredSize() OVERRIDE { |
| 97 gfx::Font font = ResourceBundle::GetSharedInstance().GetFont( | 165 int width = std::max(name_label_->GetPreferredSize().width(), |
| 98 ResourceBundle::BaseFont); | 166 sync_state_label_->GetPreferredSize().width()); |
| 99 int title_width = font.GetStringWidth(item_.name); | 167 width = std::max(edit_link_->GetPreferredSize().width(), |
| 100 return gfx::Size(kIconWidth + kIconMarginX + title_width, kItemHeight); | 168 width); |
| 169 return gfx::Size(kIconWidth + kIconMarginX + width, kItemHeight); | |
| 101 } | 170 } |
| 102 | 171 |
| 103 private: | 172 virtual void Layout() OVERRIDE { |
| 104 SkColor GetNameColor() { | 173 // Profile icon. |
| 105 bool normal = state() != views::CustomButton::BS_PUSHED && | 174 const SkBitmap& icon = image_view_->GetImage(); |
| 106 state() != views::CustomButton::BS_HOT; | 175 gfx::Rect icon_rect = GetCenteredAndScaledRect( |
| 107 if (item_.active) | 176 icon.width(), icon.height(), 0, 0, kIconWidth, height()); |
| 108 return normal ? SkColorSetRGB(30, 30, 30) : SkColorSetRGB(0, 0, 0); | 177 image_view_->SetBoundsRect(icon_rect); |
| 109 return normal ? SkColorSetRGB(128, 128, 128) : SkColorSetRGB(64, 64, 64); | 178 |
| 179 int label_x = icon_rect.right() + kIconMarginX; | |
| 180 int max_label_width = width() - label_x; | |
| 181 gfx::Size name_size = name_label_->GetPreferredSize(); | |
| 182 name_size.set_width(std::max(name_size.width(), max_label_width)); | |
|
Peter Kasting
2011/10/04 20:48:52
Do you mean std::min() in these three cases?
sail
2011/10/04 22:09:20
Ouch, good catch. Fixed.
| |
| 183 gfx::Size state_size = sync_state_label_->GetPreferredSize(); | |
| 184 state_size.set_width(std::max(state_size.width(), max_label_width)); | |
| 185 gfx::Size edit_size = edit_link_->GetPreferredSize(); | |
| 186 edit_size.set_width(std::max(edit_size.width(), max_label_width)); | |
| 187 | |
| 188 int labels_height = name_size.height() + edit_size.height() + | |
| 189 kNameStatePaddingY; | |
| 190 int y = (height() - labels_height) / 2; | |
| 191 name_label_->SetBounds(label_x, y, name_size.width(), name_size.height()); | |
| 192 | |
| 193 int bottom = y + name_size.height() + kNameStatePaddingY + | |
| 194 std::max(state_size.height(), edit_size.height()); | |
|
Peter Kasting
2011/10/04 20:48:52
If you're using max(state, edit) for the height he
sail
2011/10/04 22:09:20
Done. Good idea.
| |
| 195 sync_state_label_->SetBounds(label_x, bottom - state_size.height(), | |
| 196 state_size.width(), state_size.height()); | |
| 197 // The edit link overlaps the sync state label. | |
| 198 edit_link_->SetBounds(label_x, bottom - edit_size.height(), | |
| 199 edit_size.width(), edit_size.height()); | |
| 110 } | 200 } |
| 111 | 201 |
| 202 virtual void OnHighlightStateChanged() OVERRIDE { | |
| 203 bool show_edit = IsHighlighted() && item_.active; | |
| 204 sync_state_label_->SetVisible(!show_edit); | |
| 205 edit_link_->SetVisible(show_edit); | |
| 206 SchedulePaint(); | |
| 207 } | |
| 208 | |
| 209 virtual void OnMouseEntered(const views::MouseEvent& event) OVERRIDE { | |
| 210 views::CustomButton::OnMouseEntered(event); | |
| 211 OnHighlightStateChanged(); | |
| 212 } | |
| 213 | |
| 214 virtual void OnMouseExited(const views::MouseEvent& event) OVERRIDE { | |
| 215 views::CustomButton::OnMouseExited(event); | |
| 216 OnHighlightStateChanged(); | |
| 217 } | |
| 218 | |
| 219 EditProfileLink* edit_link() { return edit_link_; } | |
| 220 const AvatarMenuModel::Item& item() { return item_; } | |
| 221 | |
| 222 private: | |
| 223 bool IsHighlighted() { | |
| 224 return state() == views::CustomButton::BS_PUSHED || | |
| 225 state() == views::CustomButton::BS_HOT || | |
| 226 edit_link_->state() == views::CustomButton::BS_PUSHED || | |
| 227 edit_link_->state() == views::CustomButton::BS_HOT; | |
| 228 } | |
| 229 | |
| 230 SkBitmap GetBadgedIcon(const SkBitmap& icon) { | |
| 231 gfx::Rect icon_rect = GetCenteredAndScaledRect( | |
| 232 icon.width(), icon.height(), 0, 0, kIconWidth, kItemHeight); | |
| 233 | |
| 234 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 235 SkBitmap badge = rb.GetImageNamed(IDR_PROFILE_SELECTED); | |
| 236 int width = icon_rect.width() + badge.width() * kBadgeOverlapRatioX; | |
| 237 int height = icon_rect.height() + badge.height() * kBadgeOverlapRatioY; | |
| 238 | |
| 239 gfx::CanvasSkia canvas(width, height, false); | |
| 240 canvas.DrawBitmapInt(icon, 0, 0, icon.width(), icon.height(), 0, 0, | |
| 241 icon_rect.width(), icon_rect.height(), true); | |
| 242 canvas.DrawBitmapInt(badge, width - badge.width(), height - badge.height()); | |
| 243 return canvas.ExtractBitmap(); | |
| 244 } | |
| 245 | |
| 246 EditProfileLink* edit_link_; | |
| 247 views::ImageView* image_view_; | |
| 112 AvatarMenuModel::Item item_; | 248 AvatarMenuModel::Item item_; |
| 249 views::Label* name_label_; | |
| 250 views::Label* sync_state_label_; | |
| 113 }; | 251 }; |
| 114 | 252 |
| 115 } // namespace | 253 } // namespace |
| 116 | 254 |
| 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) | 255 AvatarMenuBubbleView::AvatarMenuBubbleView(Browser* browser) |
| 133 : add_profile_link_(NULL), | 256 : add_profile_link_(NULL), |
| 134 browser_(browser), | 257 browser_(browser) { |
| 135 edit_profile_button_(NULL) { | |
| 136 avatar_menu_model_.reset(new AvatarMenuModel( | 258 avatar_menu_model_.reset(new AvatarMenuModel( |
| 137 &g_browser_process->profile_manager()->GetProfileInfoCache(), | 259 &g_browser_process->profile_manager()->GetProfileInfoCache(), |
| 138 this, browser_)); | 260 this, browser_)); |
| 139 // Build the menu for the first time. | 261 // Build the menu for the first time. |
| 140 OnAvatarMenuModelChanged(avatar_menu_model_.get()); | 262 OnAvatarMenuModelChanged(avatar_menu_model_.get()); |
| 141 } | 263 } |
| 142 | 264 |
| 143 AvatarMenuBubbleView::~AvatarMenuBubbleView() { | 265 AvatarMenuBubbleView::~AvatarMenuBubbleView() { |
| 144 } | 266 } |
| 145 | 267 |
| 146 gfx::Size AvatarMenuBubbleView::GetPreferredSize() { | 268 gfx::Size AvatarMenuBubbleView::GetPreferredSize() { |
| 147 int max_width = 0; | 269 int max_width = 0; |
| 148 int total_height = 0; | 270 int total_height = 0; |
| 149 for (size_t i = 0; i < item_views_.size(); ++i) { | 271 for (size_t i = 0; i < item_views_.size(); ++i) { |
| 150 gfx::Size size = item_views_[i]->GetPreferredSize(); | 272 gfx::Size size = item_views_[i]->GetPreferredSize(); |
| 151 if (i == edit_profile_button_->profile_index()) { | |
| 152 size.set_width(size.width() + | |
| 153 edit_profile_button_->GetPreferredSize().width() + | |
| 154 kEditProfileButtonMarginX); | |
| 155 } | |
| 156 | |
| 157 max_width = std::max(max_width, size.width()); | 273 max_width = std::max(max_width, size.width()); |
| 158 total_height += size.height() + kItemMarginY; | 274 total_height += size.height() + kItemMarginY; |
| 159 } | 275 } |
| 160 | 276 |
| 277 total_height += kSeparatorPaddingY * 2 + | |
| 278 separator_->GetPreferredSize().height(); | |
| 279 | |
| 161 gfx::Size add_profile_size = add_profile_link_->GetPreferredSize(); | 280 gfx::Size add_profile_size = add_profile_link_->GetPreferredSize(); |
| 162 max_width = std::max(max_width, | 281 max_width = std::max(max_width, |
| 163 add_profile_size.width() + kIconWidth + kIconMarginX); | 282 add_profile_size.width() + kIconWidth + kIconMarginX); |
| 164 total_height += add_profile_link_->GetPreferredSize().height(); | 283 total_height += add_profile_link_->GetPreferredSize().height(); |
| 165 | 284 |
| 166 int total_width = std::min(std::max(max_width, kBubbleViewMinWidth), | 285 int total_width = std::min(std::max(max_width, kBubbleViewMinWidth), |
| 167 kBubbleViewMaxWidth); | 286 kBubbleViewMaxWidth); |
| 168 return gfx::Size(total_width, total_height); | 287 return gfx::Size(total_width, total_height); |
| 169 } | 288 } |
| 170 | 289 |
| 171 void AvatarMenuBubbleView::Layout() { | 290 void AvatarMenuBubbleView::Layout() { |
| 172 int y = 0; | 291 int y = 0; |
| 173 for (size_t i = 0; i < item_views_.size(); ++i) { | 292 for (size_t i = 0; i < item_views_.size(); ++i) { |
| 174 views::CustomButton* item_view = item_views_[i]; | 293 views::CustomButton* item_view = item_views_[i]; |
| 175 int item_height = item_view->GetPreferredSize().height(); | 294 int item_height = item_view->GetPreferredSize().height(); |
| 176 int item_width = width(); | 295 int item_width = width(); |
| 177 | |
| 178 if (i == edit_profile_button_->profile_index()) { | |
| 179 gfx::Size edit_size = edit_profile_button_->GetPreferredSize(); | |
| 180 edit_profile_button_->SetBounds(width() - edit_size.width(), y, | |
| 181 edit_size.width(), item_height); | |
| 182 item_width -= edit_size.width() + kEditProfileButtonMarginX; | |
| 183 } | |
| 184 | |
| 185 item_view->SetBounds(0, y, item_width, item_height); | 296 item_view->SetBounds(0, y, item_width, item_height); |
| 186 y += item_height + kItemMarginY; | 297 y += item_height + kItemMarginY; |
| 187 } | 298 } |
| 188 | 299 |
| 300 y += kSeparatorPaddingY; | |
| 301 int separator_height = separator_->GetPreferredSize().height(); | |
| 302 separator_->SetBounds(0, y, width(), separator_height); | |
| 303 y += kSeparatorPaddingY + separator_height; | |
| 304 | |
| 189 add_profile_link_->SetBounds(kIconWidth + kIconMarginX, y, width(), | 305 add_profile_link_->SetBounds(kIconWidth + kIconMarginX, y, width(), |
| 190 add_profile_link_->GetPreferredSize().height()); | 306 add_profile_link_->GetPreferredSize().height()); |
| 191 } | 307 } |
| 192 | 308 |
| 193 void AvatarMenuBubbleView::ButtonPressed(views::Button* sender, | 309 void AvatarMenuBubbleView::ButtonPressed(views::Button* sender, |
| 194 const views::Event& event) { | 310 const views::Event& event) { |
| 195 if (sender == edit_profile_button_) { | 311 for (size_t i = 0; i < item_views_.size(); ++i) { |
| 196 avatar_menu_model_->EditProfile(edit_profile_button_->profile_index()); | 312 ProfileItemView* item_view = static_cast<ProfileItemView*>(item_views_[i]); |
| 197 } else { | 313 if (sender == item_view) { |
| 198 for (size_t i = 0; i < item_views_.size(); ++i) { | 314 // Clicking on the active profile shouldn't do anything. |
| 199 if (sender == item_views_[i]) { | 315 if (!item_view->item().active) |
| 200 avatar_menu_model_->SwitchToProfile(i); | 316 avatar_menu_model_->SwitchToProfile(i); |
| 201 break; | 317 break; |
| 202 } | |
| 203 } | 318 } |
| 204 } | 319 } |
| 205 } | 320 } |
| 206 | 321 |
| 207 void AvatarMenuBubbleView::LinkClicked(views::Link* source, int event_flags) { | 322 void AvatarMenuBubbleView::LinkClicked(views::Link* source, int event_flags) { |
| 208 DCHECK_EQ(source, add_profile_link_); | 323 if (source == add_profile_link_) { |
| 209 avatar_menu_model_->AddNewProfile(); | 324 avatar_menu_model_->AddNewProfile(); |
| 325 return; | |
| 326 } | |
| 327 | |
| 328 for (size_t i = 0; i < item_views_.size(); ++i) { | |
| 329 ProfileItemView* item_view = static_cast<ProfileItemView*>(item_views_[i]); | |
| 330 if (source == item_view->edit_link()) { | |
| 331 avatar_menu_model_->EditProfile(i); | |
| 332 return; | |
| 333 } | |
| 334 } | |
| 210 } | 335 } |
| 211 | 336 |
| 212 void AvatarMenuBubbleView::BubbleClosing(Bubble* bubble, | 337 void AvatarMenuBubbleView::BubbleClosing(Bubble* bubble, |
| 213 bool closed_by_escape) { | 338 bool closed_by_escape) { |
| 214 } | 339 } |
| 215 | 340 |
| 216 bool AvatarMenuBubbleView::CloseOnEscape() { | 341 bool AvatarMenuBubbleView::CloseOnEscape() { |
| 217 return true; | 342 return true; |
| 218 } | 343 } |
| 219 | 344 |
| 220 bool AvatarMenuBubbleView::FadeInOnShow() { | 345 bool AvatarMenuBubbleView::FadeInOnShow() { |
| 221 return false; | 346 return false; |
| 222 } | 347 } |
| 223 | 348 |
| 224 void AvatarMenuBubbleView::OnAvatarMenuModelChanged( | 349 void AvatarMenuBubbleView::OnAvatarMenuModelChanged( |
| 225 AvatarMenuModel* avatar_menu_model) { | 350 AvatarMenuModel* avatar_menu_model) { |
| 226 // Unset all our child view references and call RemoveAllChildViews() which | 351 // Unset all our child view references and call RemoveAllChildViews() which |
| 227 // will actually delete them. | 352 // will actually delete them. |
| 228 add_profile_link_ = NULL; | 353 add_profile_link_ = NULL; |
| 229 edit_profile_button_ = NULL; | |
| 230 item_views_.clear(); | 354 item_views_.clear(); |
| 231 RemoveAllChildViews(true); | 355 RemoveAllChildViews(true); |
| 232 | 356 |
| 233 for (size_t i = 0; i < avatar_menu_model->GetNumberOfItems(); ++i) { | 357 for (size_t i = 0; i < avatar_menu_model->GetNumberOfItems(); ++i) { |
| 234 const AvatarMenuModel::Item& item = avatar_menu_model->GetItemAt(i); | 358 const AvatarMenuModel::Item& item = avatar_menu_model->GetItemAt(i); |
| 235 ProfileItemView* item_view = new ProfileItemView(item, this); | 359 ProfileItemView* item_view = new ProfileItemView(item, this, this); |
| 236 item_view->SetAccessibleName(l10n_util::GetStringFUTF16( | 360 item_view->SetAccessibleName(l10n_util::GetStringFUTF16( |
| 237 IDS_PROFILES_SWITCH_TO_PROFILE_ACCESSIBLE_NAME, item.name)); | 361 IDS_PROFILES_SWITCH_TO_PROFILE_ACCESSIBLE_NAME, item.name)); |
| 238 AddChildView(item_view); | 362 AddChildView(item_view); |
| 239 item_views_.push_back(item_view); | 363 item_views_.push_back(item_view); |
| 364 } | |
| 240 | 365 |
| 241 if (item.active) { | 366 separator_ = new views::Separator(); |
| 242 DCHECK(!edit_profile_button_); | 367 AddChildView(separator_); |
| 243 edit_profile_button_ = new EditProfileButton(i, this); | |
| 244 edit_profile_button_->SetAccessibleName(l10n_util::GetStringFUTF16( | |
| 245 IDS_PROFILES_CUSTOMIZE_PROFILE_ACCESSIBLE_NAME, item.name)); | |
| 246 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 247 edit_profile_button_->SetImage(views::CustomButton::BS_NORMAL, | |
| 248 rb.GetImageNamed(IDR_PROFILE_EDIT)); | |
| 249 edit_profile_button_->SetImage(views::CustomButton::BS_HOT, | |
| 250 rb.GetImageNamed(IDR_PROFILE_EDIT_HOVER)); | |
| 251 edit_profile_button_->SetImage(views::CustomButton::BS_PUSHED, | |
| 252 rb.GetImageNamed(IDR_PROFILE_EDIT_PRESSED)); | |
| 253 edit_profile_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER, | |
| 254 views::ImageButton::ALIGN_MIDDLE); | |
| 255 AddChildView(edit_profile_button_); | |
| 256 } | |
| 257 } | |
| 258 | 368 |
| 259 add_profile_link_ = new views::Link(UTF16ToWide( | 369 add_profile_link_ = new views::Link(UTF16ToWide( |
| 260 l10n_util::GetStringUTF16(IDS_PROFILES_CREATE_NEW_PROFILE_LINK))); | 370 l10n_util::GetStringUTF16(IDS_PROFILES_CREATE_NEW_PROFILE_LINK))); |
| 261 add_profile_link_->set_listener(this); | 371 add_profile_link_->set_listener(this); |
| 262 add_profile_link_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); | 372 add_profile_link_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); |
| 263 add_profile_link_->SetNormalColor(SkColorSetRGB(0, 0x79, 0xda)); | 373 add_profile_link_->SetNormalColor(SkColorSetRGB(0, 0x79, 0xda)); |
| 264 AddChildView(add_profile_link_); | 374 AddChildView(add_profile_link_); |
| 265 | 375 |
| 266 PreferredSizeChanged(); | 376 PreferredSizeChanged(); |
| 267 } | 377 } |
| OLD | NEW |