Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "ui/views/controls/menu/menu_item_view.h" | 5 #include "ui/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.h" | 8 #include "base/stl_util.h" |
| 9 #include "base/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
| 10 #include "grit/ui_strings.h" | 10 #include "grit/ui_strings.h" |
| 11 #include "ui/base/accessibility/accessible_view_state.h" | 11 #include "ui/base/accessibility/accessible_view_state.h" |
| 12 #include "ui/base/l10n/l10n_util.h" | 12 #include "ui/base/l10n/l10n_util.h" |
| 13 #include "ui/base/models/menu_model.h" | 13 #include "ui/base/models/menu_model.h" |
| 14 #include "ui/gfx/canvas.h" | 14 #include "ui/gfx/canvas.h" |
| 15 #include "ui/views/controls/button/menu_button.h" | 15 #include "ui/views/controls/button/menu_button.h" |
| 16 #include "ui/views/controls/image_view.h" | |
| 16 #include "ui/views/controls/menu/menu_config.h" | 17 #include "ui/views/controls/menu/menu_config.h" |
| 17 #include "ui/views/controls/menu/menu_controller.h" | 18 #include "ui/views/controls/menu/menu_controller.h" |
| 18 #include "ui/views/controls/menu/menu_separator.h" | 19 #include "ui/views/controls/menu/menu_separator.h" |
| 19 #include "ui/views/controls/menu/submenu_view.h" | 20 #include "ui/views/controls/menu/submenu_view.h" |
| 20 | 21 |
| 21 namespace views { | 22 namespace views { |
| 22 | 23 |
| 23 namespace { | 24 namespace { |
| 24 | 25 |
| 25 // EmptyMenuMenuItem --------------------------------------------------------- | 26 // EmptyMenuMenuItem --------------------------------------------------------- |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 56 // MenuItemView --------------------------------------------------------------- | 57 // MenuItemView --------------------------------------------------------------- |
| 57 | 58 |
| 58 // static | 59 // static |
| 59 const int MenuItemView::kMenuItemViewID = 1001; | 60 const int MenuItemView::kMenuItemViewID = 1001; |
| 60 | 61 |
| 61 // static | 62 // static |
| 62 const int MenuItemView::kEmptyMenuItemViewID = | 63 const int MenuItemView::kEmptyMenuItemViewID = |
| 63 MenuItemView::kMenuItemViewID + 1; | 64 MenuItemView::kMenuItemViewID + 1; |
| 64 | 65 |
| 65 // static | 66 // static |
| 67 int MenuItemView::icon_area_width_ = 0; | |
| 68 | |
| 69 // static | |
| 66 int MenuItemView::label_start_; | 70 int MenuItemView::label_start_; |
| 67 | 71 |
| 68 // static | 72 // static |
| 69 int MenuItemView::item_right_margin_; | 73 int MenuItemView::item_right_margin_; |
| 70 | 74 |
| 71 // static | 75 // static |
| 72 int MenuItemView::pref_menu_height_; | 76 int MenuItemView::pref_menu_height_; |
| 73 | 77 |
| 74 // static | 78 // static |
| 75 const char MenuItemView::kViewClassName[] = "views/MenuItemView"; | 79 const char MenuItemView::kViewClassName[] = "views/MenuItemView"; |
| 76 | 80 |
| 77 MenuItemView::MenuItemView(MenuDelegate* delegate) | 81 MenuItemView::MenuItemView(MenuDelegate* delegate) |
| 78 : delegate_(delegate), | 82 : delegate_(delegate), |
| 79 controller_(NULL), | 83 controller_(NULL), |
| 80 canceled_(false), | 84 canceled_(false), |
| 81 parent_menu_item_(NULL), | 85 parent_menu_item_(NULL), |
| 82 type_(SUBMENU), | 86 type_(SUBMENU), |
| 83 selected_(false), | 87 selected_(false), |
| 84 command_(0), | 88 command_(0), |
| 85 submenu_(NULL), | 89 submenu_(NULL), |
| 86 has_mnemonics_(false), | 90 has_mnemonics_(false), |
| 87 show_mnemonics_(false), | 91 show_mnemonics_(false), |
| 88 has_icons_(false), | 92 has_icons_(false), |
| 93 icon_view_(NULL), | |
| 89 top_margin_(-1), | 94 top_margin_(-1), |
| 90 bottom_margin_(-1), | 95 bottom_margin_(-1), |
| 91 requested_menu_position_(POSITION_BEST_FIT), | 96 requested_menu_position_(POSITION_BEST_FIT), |
| 92 actual_menu_position_(requested_menu_position_), | 97 actual_menu_position_(requested_menu_position_), |
| 93 use_right_margin_(true) { | 98 use_right_margin_(true) { |
| 94 // NOTE: don't check the delegate for NULL, UpdateMenuPartSizes supplies a | 99 // NOTE: don't check the delegate for NULL, UpdateMenuPartSizes supplies a |
| 95 // NULL delegate. | 100 // NULL delegate. |
| 96 Init(NULL, 0, SUBMENU, delegate); | 101 Init(NULL, 0, SUBMENU, delegate); |
| 97 } | 102 } |
| 98 | 103 |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 212 DCHECK_GE(submenu_->child_count(), index); | 217 DCHECK_GE(submenu_->child_count(), index); |
| 213 if (type == SEPARATOR) { | 218 if (type == SEPARATOR) { |
| 214 submenu_->AddChildViewAt(new MenuSeparator(), index); | 219 submenu_->AddChildViewAt(new MenuSeparator(), index); |
| 215 return NULL; | 220 return NULL; |
| 216 } | 221 } |
| 217 MenuItemView* item = new MenuItemView(this, item_id, type); | 222 MenuItemView* item = new MenuItemView(this, item_id, type); |
| 218 if (label.empty() && GetDelegate()) | 223 if (label.empty() && GetDelegate()) |
| 219 item->SetTitle(GetDelegate()->GetLabel(item_id)); | 224 item->SetTitle(GetDelegate()->GetLabel(item_id)); |
| 220 else | 225 else |
| 221 item->SetTitle(label); | 226 item->SetTitle(label); |
| 222 item->SetIcon(icon); | 227 if (!icon.empty()) |
| 228 item->SetIcon(icon); | |
| 223 if (type == SUBMENU) | 229 if (type == SUBMENU) |
| 224 item->CreateSubmenu(); | 230 item->CreateSubmenu(); |
| 225 submenu_->AddChildViewAt(item, index); | 231 submenu_->AddChildViewAt(item, index); |
| 226 return item; | 232 return item; |
| 227 } | 233 } |
| 228 | 234 |
| 229 void MenuItemView::RemoveMenuItemAt(int index) { | 235 void MenuItemView::RemoveMenuItemAt(int index) { |
| 230 DCHECK(submenu_); | 236 DCHECK(submenu_); |
| 231 DCHECK_LE(0, index); | 237 DCHECK_LE(0, index); |
| 232 DCHECK_GT(submenu_->child_count(), index); | 238 DCHECK_GT(submenu_->child_count(), index); |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 353 item->tooltip_ = tooltip; | 359 item->tooltip_ = tooltip; |
| 354 } | 360 } |
| 355 | 361 |
| 356 void MenuItemView::SetIcon(const gfx::ImageSkia& icon, int item_id) { | 362 void MenuItemView::SetIcon(const gfx::ImageSkia& icon, int item_id) { |
| 357 MenuItemView* item = GetMenuItemByID(item_id); | 363 MenuItemView* item = GetMenuItemByID(item_id); |
| 358 DCHECK(item); | 364 DCHECK(item); |
| 359 item->SetIcon(icon); | 365 item->SetIcon(icon); |
| 360 } | 366 } |
| 361 | 367 |
| 362 void MenuItemView::SetIcon(const gfx::ImageSkia& icon) { | 368 void MenuItemView::SetIcon(const gfx::ImageSkia& icon) { |
| 363 icon_ = icon; | 369 if (icon.empty()) { |
| 370 SetIconView(NULL); | |
| 371 return; | |
| 372 } | |
| 373 | |
| 374 ImageView* icon_view = new ImageView(); | |
| 375 icon_view->SetImage(&icon); | |
| 376 SetIconView(icon_view); | |
| 377 } | |
| 378 | |
| 379 void MenuItemView::SetIconView(View* icon_view) { | |
| 380 if (icon_view_) { | |
| 381 RemoveChildView(icon_view_); | |
| 382 delete icon_view_; | |
| 383 icon_view_ = NULL; | |
| 384 } | |
| 385 if (icon_view) { | |
| 386 AddChildView(icon_view); | |
| 387 icon_view_ = icon_view; | |
| 388 } | |
| 364 SchedulePaint(); | 389 SchedulePaint(); |
| 365 } | 390 } |
| 366 | 391 |
| 367 void MenuItemView::OnPaint(gfx::Canvas* canvas) { | 392 void MenuItemView::OnPaint(gfx::Canvas* canvas) { |
| 368 PaintButton(canvas, PB_NORMAL); | 393 PaintButton(canvas, PB_NORMAL); |
| 369 } | 394 } |
| 370 | 395 |
| 371 gfx::Size MenuItemView::GetPreferredSize() { | 396 gfx::Size MenuItemView::GetPreferredSize() { |
| 372 if (pref_size_.IsEmpty()) | 397 if (pref_size_.IsEmpty()) |
| 373 pref_size_ = CalculatePreferredSize(); | 398 pref_size_ = CalculatePreferredSize(); |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 474 if (IsContainer()) { | 499 if (IsContainer()) { |
| 475 View* child = child_at(0); | 500 View* child = child_at(0); |
| 476 gfx::Size size = child->GetPreferredSize(); | 501 gfx::Size size = child->GetPreferredSize(); |
| 477 child->SetBounds(0, GetTopMargin(), size.width(), size.height()); | 502 child->SetBounds(0, GetTopMargin(), size.width(), size.height()); |
| 478 } else { | 503 } else { |
| 479 // Child views are laid out right aligned and given the full height. To | 504 // Child views are laid out right aligned and given the full height. To |
| 480 // right align start with the last view and progress to the first. | 505 // right align start with the last view and progress to the first. |
| 481 int x = width() - (use_right_margin_ ? item_right_margin_ : 0); | 506 int x = width() - (use_right_margin_ ? item_right_margin_ : 0); |
| 482 for (int i = child_count() - 1; i >= 0; --i) { | 507 for (int i = child_count() - 1; i >= 0; --i) { |
| 483 View* child = child_at(i); | 508 View* child = child_at(i); |
| 509 if (icon_view_ && (icon_view_ == child)) | |
| 510 continue; | |
| 484 int width = child->GetPreferredSize().width(); | 511 int width = child->GetPreferredSize().width(); |
| 485 child->SetBounds(x - width, 0, width, height()); | 512 child->SetBounds(x - width, 0, width, height()); |
| 486 x -= width - kChildXPadding; | 513 x -= width - kChildXPadding; |
| 487 } | 514 } |
| 515 // Position icon_view | |
|
msw
2012/06/28 01:56:38
nit: vertical bars around "|icon_view|", add punct
yefimt
2012/06/28 16:53:34
Done.
| |
| 516 const MenuConfig& config = MenuConfig::instance(); | |
| 517 if (icon_view_) { | |
| 518 icon_view_->SizeToPreferredSize(); | |
| 519 gfx::Size size = icon_view_->GetPreferredSize(); | |
| 520 int x = config.item_left_margin + (icon_area_width_ - size.width()) / 2; | |
| 521 int y = (height() + GetTopMargin() - GetBottomMargin() - | |
|
msw
2012/06/28 01:56:38
nit: I'd move the entire value calculation to the
yefimt
2012/06/28 16:53:34
Done.
| |
| 522 size.height()) / 2; | |
| 523 icon_view_->SetPosition(gfx::Point(x, y)); | |
| 524 } | |
| 488 } | 525 } |
| 489 } | 526 } |
| 490 | 527 |
| 491 int MenuItemView::GetAcceleratorTextWidth() { | 528 int MenuItemView::GetAcceleratorTextWidth() { |
| 492 string16 text = GetAcceleratorText(); | 529 string16 text = GetAcceleratorText(); |
| 493 return text.empty() ? 0 : GetFont().GetStringWidth(text); | 530 return text.empty() ? 0 : GetFont().GetStringWidth(text); |
| 494 } | 531 } |
| 495 | 532 |
| 496 void MenuItemView::SetMargins(int top_margin, int bottom_margin) { | 533 void MenuItemView::SetMargins(int top_margin, int bottom_margin) { |
| 497 top_margin_ = top_margin; | 534 top_margin_ = top_margin; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 508 controller_(NULL), | 545 controller_(NULL), |
| 509 canceled_(false), | 546 canceled_(false), |
| 510 parent_menu_item_(parent), | 547 parent_menu_item_(parent), |
| 511 type_(type), | 548 type_(type), |
| 512 selected_(false), | 549 selected_(false), |
| 513 command_(command), | 550 command_(command), |
| 514 submenu_(NULL), | 551 submenu_(NULL), |
| 515 has_mnemonics_(false), | 552 has_mnemonics_(false), |
| 516 show_mnemonics_(false), | 553 show_mnemonics_(false), |
| 517 has_icons_(false), | 554 has_icons_(false), |
| 555 icon_view_(NULL), | |
| 518 top_margin_(-1), | 556 top_margin_(-1), |
| 519 bottom_margin_(-1), | 557 bottom_margin_(-1), |
| 520 requested_menu_position_(POSITION_BEST_FIT), | 558 requested_menu_position_(POSITION_BEST_FIT), |
| 521 actual_menu_position_(requested_menu_position_) { | 559 actual_menu_position_(requested_menu_position_) { |
| 522 Init(parent, command, type, NULL); | 560 Init(parent, command, type, NULL); |
| 523 } | 561 } |
| 524 | 562 |
| 525 MenuItemView::~MenuItemView() { | 563 MenuItemView::~MenuItemView() { |
| 526 delete submenu_; | 564 delete submenu_; |
| 527 STLDeleteElements(&removed_items_); | 565 STLDeleteElements(&removed_items_); |
| 528 } | 566 } |
| 529 | 567 |
| 530 std::string MenuItemView::GetClassName() const { | 568 std::string MenuItemView::GetClassName() const { |
| 531 return kViewClassName; | 569 return kViewClassName; |
| 532 } | 570 } |
| 533 | 571 |
| 534 // Calculates all sizes that we can from the OS. | 572 // Calculates all sizes that we can from the OS. |
| 535 // | 573 // |
| 536 // This is invoked prior to Running a menu. | 574 // This is invoked prior to Running a menu. |
| 537 void MenuItemView::UpdateMenuPartSizes(bool has_icons) { | 575 void MenuItemView::UpdateMenuPartSizes() { |
| 538 MenuConfig::Reset(); | 576 MenuConfig::Reset(); |
| 539 const MenuConfig& config = MenuConfig::instance(); | 577 const MenuConfig& config = MenuConfig::instance(); |
| 540 | 578 |
| 541 item_right_margin_ = config.label_to_arrow_padding + config.arrow_width + | 579 item_right_margin_ = config.label_to_arrow_padding + config.arrow_width + |
| 542 config.arrow_to_edge_padding; | 580 config.arrow_to_edge_padding; |
| 581 icon_area_width_ = config.check_width; | |
| 582 if (has_icons_) | |
| 583 icon_area_width_ = std::max(icon_area_width_, GetMaxIconViewWidth()); | |
| 543 | 584 |
| 544 if (config.always_use_icon_to_label_padding) | 585 if (config.always_use_icon_to_label_padding) |
| 545 label_start_ = config.item_left_margin + config.check_width + | 586 label_start_ = config.item_left_margin + icon_area_width_ + |
| 546 config.icon_to_label_padding; | 587 config.icon_to_label_padding; |
| 547 else | 588 else |
| 548 // If there are no icons don't pad by the icon to label padding. This | 589 // If there are no icons don't pad by the icon to label padding. This |
| 549 // makes us look close to system menus. | 590 // makes us look close to system menus. |
| 550 label_start_ = config.item_left_margin + config.check_width + | 591 label_start_ = config.item_left_margin + icon_area_width_ + |
| 551 (has_icons ? config.icon_to_label_padding : 0); | 592 (has_icons_ ? config.icon_to_label_padding : 0); |
| 552 | 593 |
| 553 if (config.render_gutter) | 594 if (config.render_gutter) |
| 554 label_start_ += config.gutter_width + config.gutter_to_label; | 595 label_start_ += config.gutter_width + config.gutter_to_label; |
| 555 | 596 |
| 556 MenuItemView menu_item(NULL); | 597 MenuItemView menu_item(NULL); |
| 557 menu_item.SetTitle(ASCIIToUTF16("blah")); // Text doesn't matter here. | 598 menu_item.SetTitle(ASCIIToUTF16("blah")); // Text doesn't matter here. |
| 558 pref_menu_height_ = menu_item.GetPreferredSize().height(); | 599 pref_menu_height_ = menu_item.GetPreferredSize().height(); |
| 559 } | 600 } |
| 560 | 601 |
| 561 void MenuItemView::Init(MenuItemView* parent, | 602 void MenuItemView::Init(MenuItemView* parent, |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 592 canceled_ = false; | 633 canceled_ = false; |
| 593 | 634 |
| 594 has_mnemonics_ = has_mnemonics; | 635 has_mnemonics_ = has_mnemonics; |
| 595 show_mnemonics_ = has_mnemonics && show_mnemonics; | 636 show_mnemonics_ = has_mnemonics && show_mnemonics; |
| 596 | 637 |
| 597 AddEmptyMenus(); | 638 AddEmptyMenus(); |
| 598 | 639 |
| 599 if (!MenuController::GetActiveInstance()) { | 640 if (!MenuController::GetActiveInstance()) { |
| 600 // Only update the menu size if there are no menus showing, otherwise | 641 // Only update the menu size if there are no menus showing, otherwise |
| 601 // things may shift around. | 642 // things may shift around. |
| 602 UpdateMenuPartSizes(has_icons_); | 643 UpdateMenuPartSizes(); |
| 603 } | 644 } |
| 604 } | 645 } |
| 605 | 646 |
| 606 int MenuItemView::GetDrawStringFlags() { | 647 int MenuItemView::GetDrawStringFlags() { |
| 607 int flags = 0; | 648 int flags = 0; |
| 608 if (base::i18n::IsRTL()) | 649 if (base::i18n::IsRTL()) |
| 609 flags |= gfx::Canvas::TEXT_ALIGN_RIGHT; | 650 flags |= gfx::Canvas::TEXT_ALIGN_RIGHT; |
| 610 else | 651 else |
| 611 flags |= gfx::Canvas::TEXT_ALIGN_LEFT; | 652 flags |= gfx::Canvas::TEXT_ALIGN_LEFT; |
| 612 | 653 |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 728 if (!has_children()) | 769 if (!has_children()) |
| 729 return gfx::Size(); | 770 return gfx::Size(); |
| 730 | 771 |
| 731 if (IsContainer()) { | 772 if (IsContainer()) { |
| 732 View* child = child_at(0); | 773 View* child = child_at(0); |
| 733 return child->GetPreferredSize(); | 774 return child->GetPreferredSize(); |
| 734 } | 775 } |
| 735 | 776 |
| 736 int width = 0; | 777 int width = 0; |
| 737 for (int i = 0; i < child_count(); ++i) { | 778 for (int i = 0; i < child_count(); ++i) { |
| 779 View* child = child_at(i); | |
| 780 if (icon_view_ && (icon_view_ == child)) | |
| 781 continue; | |
| 738 if (i) | 782 if (i) |
| 739 width += kChildXPadding; | 783 width += kChildXPadding; |
| 740 width += child_at(i)->GetPreferredSize().width(); | 784 width += child->GetPreferredSize().width(); |
| 741 } | 785 } |
| 742 // Return a height of 0 to indicate that we should use the title height | 786 int height = 0; |
| 743 // instead. | 787 if (icon_view_) |
| 744 return gfx::Size(width, 0); | 788 height = icon_view_->GetPreferredSize().height(); |
| 789 | |
| 790 // If there is no icon view it returns a height of 0 to indicate that | |
| 791 // we should use the title height instead. | |
| 792 return gfx::Size(width, height); | |
| 745 } | 793 } |
| 746 | 794 |
| 747 gfx::Size MenuItemView::CalculatePreferredSize() { | 795 gfx::Size MenuItemView::CalculatePreferredSize() { |
| 748 gfx::Size child_size = GetChildPreferredSize(); | 796 gfx::Size child_size = GetChildPreferredSize(); |
| 749 if (IsContainer()) { | 797 if (IsContainer()) { |
| 750 return gfx::Size( | 798 return gfx::Size( |
| 751 child_size.width(), | 799 child_size.width(), |
| 752 child_size.height() + GetBottomMargin() + GetTopMargin()); | 800 child_size.height() + GetBottomMargin() + GetTopMargin()); |
| 753 } | 801 } |
| 754 | 802 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 771 return string16(); | 819 return string16(); |
| 772 | 820 |
| 773 ui::Accelerator accelerator; | 821 ui::Accelerator accelerator; |
| 774 return (GetDelegate() && | 822 return (GetDelegate() && |
| 775 GetDelegate()->GetAccelerator(GetCommand(), &accelerator)) ? | 823 GetDelegate()->GetAccelerator(GetCommand(), &accelerator)) ? |
| 776 accelerator.GetShortcutText() : string16(); | 824 accelerator.GetShortcutText() : string16(); |
| 777 } | 825 } |
| 778 | 826 |
| 779 bool MenuItemView::IsContainer() const { | 827 bool MenuItemView::IsContainer() const { |
| 780 // Let the first child take over |this| when we only have one child and no | 828 // Let the first child take over |this| when we only have one child and no |
| 781 // title. Note that what child_count() returns is the number of children, | 829 // title. |
| 830 return NonIconChildViewsCount() == 1 && title_.empty(); | |
|
msw
2012/06/28 01:56:38
nit: add parens around the first conditional.
yefimt
2012/06/28 16:53:34
Done.
| |
| 831 } | |
| 832 | |
| 833 int MenuItemView::NonIconChildViewsCount() const { | |
| 834 // Note that what child_count() returns is the number of children, | |
| 782 // not the number of menu items. | 835 // not the number of menu items. |
| 783 return child_count() == 1 && title_.empty(); | 836 return child_count() - (icon_view_ ? 1 : 0); |
| 837 } | |
| 838 | |
| 839 int MenuItemView::GetMaxIconViewWidth() const { | |
| 840 int width = 0; | |
| 841 for (int i = 0; i < submenu_->GetMenuItemCount(); ++i) { | |
| 842 MenuItemView* menu_item = submenu_->GetMenuItemAt(i); | |
| 843 int temp_width = 0; | |
| 844 if (menu_item->HasSubmenu()) { | |
| 845 temp_width = menu_item->GetMaxIconViewWidth(); | |
| 846 } else if (menu_item->icon_view()) { | |
| 847 temp_width = menu_item->icon_view()->GetPreferredSize().width(); | |
| 848 } | |
| 849 width = std::max(width, temp_width); | |
| 850 } | |
| 851 return width; | |
| 784 } | 852 } |
| 785 | 853 |
| 786 } // namespace views | 854 } // namespace views |
| OLD | NEW |