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 "views/controls/menu/menu_item_view.h" | 5 #include "views/controls/menu/menu_item_view.h" |
6 | 6 |
7 #include "base/i18n/case_conversion.h" | 7 #include "base/i18n/case_conversion.h" |
| 8 #include "base/stl_util-inl.h" |
8 #include "base/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
9 #include "grit/app_strings.h" | 10 #include "grit/app_strings.h" |
10 #include "ui/base/accessibility/accessible_view_state.h" | 11 #include "ui/base/accessibility/accessible_view_state.h" |
11 #include "ui/base/l10n/l10n_util.h" | 12 #include "ui/base/l10n/l10n_util.h" |
12 #include "ui/base/models/menu_model.h" | 13 #include "ui/base/models/menu_model.h" |
13 #include "ui/gfx/canvas.h" | 14 #include "ui/gfx/canvas.h" |
14 #include "views/controls/button/text_button.h" | 15 #include "views/controls/button/text_button.h" |
15 #include "views/controls/button/menu_button.h" | 16 #include "views/controls/button/menu_button.h" |
16 #include "views/controls/menu/menu_config.h" | 17 #include "views/controls/menu/menu_config.h" |
17 #include "views/controls/menu/menu_controller.h" | 18 #include "views/controls/menu/menu_controller.h" |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
95 Init(NULL, 0, SUBMENU, delegate); | 96 Init(NULL, 0, SUBMENU, delegate); |
96 } | 97 } |
97 | 98 |
98 MenuItemView::~MenuItemView() { | 99 MenuItemView::~MenuItemView() { |
99 // TODO(sky): ownership is bit wrong now. In particular if a nested message | 100 // TODO(sky): ownership is bit wrong now. In particular if a nested message |
100 // loop is running deletion can't be done, otherwise the stack gets | 101 // loop is running deletion can't be done, otherwise the stack gets |
101 // thoroughly screwed. The destructor should be made private, and | 102 // thoroughly screwed. The destructor should be made private, and |
102 // MenuController should be the only place handling deletion of the menu. | 103 // MenuController should be the only place handling deletion of the menu. |
103 // (57890). | 104 // (57890). |
104 delete submenu_; | 105 delete submenu_; |
| 106 STLDeleteElements(&removed_items_); |
105 } | 107 } |
106 | 108 |
107 bool MenuItemView::GetTooltipText(const gfx::Point& p, std::wstring* tooltip) { | 109 bool MenuItemView::GetTooltipText(const gfx::Point& p, std::wstring* tooltip) { |
108 *tooltip = UTF16ToWideHack(tooltip_); | 110 *tooltip = UTF16ToWideHack(tooltip_); |
109 if (!tooltip->empty()) | 111 if (!tooltip->empty()) |
110 return true; | 112 return true; |
111 if (GetType() != SEPARATOR) { | 113 if (GetType() != SEPARATOR) { |
112 gfx::Point location(p); | 114 gfx::Point location(p); |
113 ConvertPointToScreen(this, &location); | 115 ConvertPointToScreen(this, &location); |
114 *tooltip = GetDelegate()->GetTooltipText(command_, location); | 116 *tooltip = GetDelegate()->GetTooltipText(command_, location); |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 controller_->Run(parent, NULL, this, bounds, anchor, NULL); | 246 controller_->Run(parent, NULL, this, bounds, anchor, NULL); |
245 } | 247 } |
246 | 248 |
247 void MenuItemView::Cancel() { | 249 void MenuItemView::Cancel() { |
248 if (controller_ && !canceled_) { | 250 if (controller_ && !canceled_) { |
249 canceled_ = true; | 251 canceled_ = true; |
250 controller_->Cancel(MenuController::EXIT_ALL); | 252 controller_->Cancel(MenuController::EXIT_ALL); |
251 } | 253 } |
252 } | 254 } |
253 | 255 |
| 256 MenuItemView* MenuItemView::AddMenuItemAt(int index, |
| 257 int item_id, |
| 258 const std::wstring& label, |
| 259 const SkBitmap& icon, |
| 260 Type type) { |
| 261 DCHECK_LE(0, index); |
| 262 if (!submenu_) |
| 263 CreateSubmenu(); |
| 264 DCHECK_GE(submenu_->child_count(), index); |
| 265 if (type == SEPARATOR) { |
| 266 submenu_->AddChildViewAt(new MenuSeparator(), index); |
| 267 return NULL; |
| 268 } |
| 269 MenuItemView* item = new MenuItemView(this, item_id, type); |
| 270 if (label.empty() && GetDelegate()) |
| 271 item->SetTitle(GetDelegate()->GetLabel(item_id)); |
| 272 else |
| 273 item->SetTitle(label); |
| 274 item->SetIcon(icon); |
| 275 if (type == SUBMENU) |
| 276 item->CreateSubmenu(); |
| 277 submenu_->AddChildViewAt(item, index); |
| 278 return item; |
| 279 } |
| 280 |
| 281 void MenuItemView::RemoveMenuItemAt(int index) { |
| 282 DCHECK(submenu_); |
| 283 DCHECK_LE(0, index); |
| 284 DCHECK_GT(submenu_->child_count(), index); |
| 285 |
| 286 View* item = submenu_->GetChildViewAt(index); |
| 287 DCHECK(item); |
| 288 submenu_->RemoveChildView(item); |
| 289 |
| 290 // RemoveChildView() does not delete the item, which is a good thing |
| 291 // in case a submenu is being displayed while items are being removed. |
| 292 // Deletion will be done by ChildrenChanged() or at destruction. |
| 293 removed_items_.push_back(item); |
| 294 } |
| 295 |
254 MenuItemView* MenuItemView::AppendMenuItemFromModel(ui::MenuModel* model, | 296 MenuItemView* MenuItemView::AppendMenuItemFromModel(ui::MenuModel* model, |
255 int index, | 297 int index, |
256 int id) { | 298 int id) { |
257 SkBitmap icon; | 299 SkBitmap icon; |
258 bool has_icon = false; | 300 bool has_icon = false; |
259 std::wstring label; | 301 std::wstring label; |
260 MenuItemView::Type type; | 302 MenuItemView::Type type; |
261 ui::MenuModel::ItemType menu_type = model->GetTypeAt(index); | 303 ui::MenuModel::ItemType menu_type = model->GetTypeAt(index); |
262 switch (menu_type) { | 304 switch (menu_type) { |
263 case ui::MenuModel::TYPE_COMMAND: | 305 case ui::MenuModel::TYPE_COMMAND: |
(...skipping 22 matching lines...) Expand all Loading... |
286 break; | 328 break; |
287 } | 329 } |
288 | 330 |
289 return AppendMenuItemImpl(id, label, has_icon ? icon : SkBitmap(), type); | 331 return AppendMenuItemImpl(id, label, has_icon ? icon : SkBitmap(), type); |
290 } | 332 } |
291 | 333 |
292 MenuItemView* MenuItemView::AppendMenuItemImpl(int item_id, | 334 MenuItemView* MenuItemView::AppendMenuItemImpl(int item_id, |
293 const std::wstring& label, | 335 const std::wstring& label, |
294 const SkBitmap& icon, | 336 const SkBitmap& icon, |
295 Type type) { | 337 Type type) { |
296 if (!submenu_) | 338 const int index = submenu_ ? submenu_->child_count() : 0; |
297 CreateSubmenu(); | 339 return AddMenuItemAt(index, item_id, label, icon, type); |
298 if (type == SEPARATOR) { | |
299 submenu_->AddChildView(new MenuSeparator()); | |
300 return NULL; | |
301 } | |
302 MenuItemView* item = new MenuItemView(this, item_id, type); | |
303 if (label.empty() && GetDelegate()) | |
304 item->SetTitle(GetDelegate()->GetLabel(item_id)); | |
305 else | |
306 item->SetTitle(label); | |
307 item->SetIcon(icon); | |
308 if (type == SUBMENU) | |
309 item->CreateSubmenu(); | |
310 submenu_->AddChildView(item); | |
311 return item; | |
312 } | 340 } |
313 | 341 |
314 SubmenuView* MenuItemView::CreateSubmenu() { | 342 SubmenuView* MenuItemView::CreateSubmenu() { |
315 if (!submenu_) | 343 if (!submenu_) |
316 submenu_ = new SubmenuView(this); | 344 submenu_ = new SubmenuView(this); |
317 return submenu_; | 345 return submenu_; |
318 } | 346 } |
319 | 347 |
320 bool MenuItemView::HasSubmenu() const { | 348 bool MenuItemView::HasSubmenu() const { |
321 return (submenu_ != NULL); | 349 return (submenu_ != NULL); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
418 GetMenuItemByID(id); | 446 GetMenuItemByID(id); |
419 if (result) | 447 if (result) |
420 return result; | 448 return result; |
421 } | 449 } |
422 } | 450 } |
423 return NULL; | 451 return NULL; |
424 } | 452 } |
425 | 453 |
426 void MenuItemView::ChildrenChanged() { | 454 void MenuItemView::ChildrenChanged() { |
427 MenuController* controller = GetMenuController(); | 455 MenuController* controller = GetMenuController(); |
428 if (!controller) | 456 if (controller) { |
429 return; // We're not showing, nothing to do. | 457 // Handles the case where we were empty and are no longer empty. |
| 458 RemoveEmptyMenus(); |
430 | 459 |
431 // Handles the case where we were empty and are no longer empty. | 460 // Handles the case where we were not empty, but now are. |
432 RemoveEmptyMenus(); | 461 AddEmptyMenus(); |
433 | 462 |
434 // Handles the case where we were not empty, but now are. | 463 controller->MenuChildrenChanged(this); |
435 AddEmptyMenus(); | |
436 | 464 |
437 controller->MenuChildrenChanged(this); | 465 if (submenu_) { |
| 466 // Force a paint and layout. This handles the case of the top |
| 467 // level window's size remaining the same, resulting in no |
| 468 // change to the submenu's size and no layout. |
| 469 submenu_->Layout(); |
| 470 submenu_->SchedulePaint(); |
| 471 } |
| 472 } |
438 | 473 |
439 if (submenu_) { | 474 STLDeleteElements(&removed_items_); |
440 // Force a paint and layout. This handles the case of the top level window's | |
441 // size remaining the same, resulting in no change to the submenu's size and | |
442 // no layout. | |
443 submenu_->Layout(); | |
444 submenu_->SchedulePaint(); | |
445 } | |
446 } | 475 } |
447 | 476 |
448 void MenuItemView::Layout() { | 477 void MenuItemView::Layout() { |
449 if (!has_children()) | 478 if (!has_children()) |
450 return; | 479 return; |
451 | 480 |
452 // Child views are laid out right aligned and given the full height. To right | 481 // Child views are laid out right aligned and given the full height. To right |
453 // align start with the last view and progress to the first. | 482 // align start with the last view and progress to the first. |
454 for (int i = child_count() - 1, x = width() - item_right_margin_; i >= 0; | 483 for (int i = child_count() - 1, x = width() - item_right_margin_; i >= 0; |
455 --i) { | 484 --i) { |
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
690 } | 719 } |
691 | 720 |
692 string16 MenuItemView::GetAcceleratorText() { | 721 string16 MenuItemView::GetAcceleratorText() { |
693 Accelerator accelerator; | 722 Accelerator accelerator; |
694 return (GetDelegate() && | 723 return (GetDelegate() && |
695 GetDelegate()->GetAccelerator(GetCommand(), &accelerator)) ? | 724 GetDelegate()->GetAccelerator(GetCommand(), &accelerator)) ? |
696 accelerator.GetShortcutText() : string16(); | 725 accelerator.GetShortcutText() : string16(); |
697 } | 726 } |
698 | 727 |
699 } // namespace views | 728 } // namespace views |
OLD | NEW |