Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(56)

Side by Side Diff: ui/views/controls/menu/menu_controller.cc

Issue 10829176: Update drop down menu look & feel (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Delete POSITION_OVER_BOUNDS related code Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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_controller.h" 5 #include "ui/views/controls/menu/menu_controller.h"
6 6
7 #include "base/i18n/case_conversion.h" 7 #include "base/i18n/case_conversion.h"
8 #include "base/i18n/rtl.h" 8 #include "base/i18n/rtl.h"
9 #include "base/run_loop.h" 9 #include "base/run_loop.h"
10 #include "base/time.h" 10 #include "base/time.h"
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 // Period of the scroll timer (in milliseconds). 43 // Period of the scroll timer (in milliseconds).
44 static const int kScrollTimerMS = 30; 44 static const int kScrollTimerMS = 30;
45 45
46 // Delay, in ms, between when menus are selected are moused over and the menu 46 // Delay, in ms, between when menus are selected are moused over and the menu
47 // appears. 47 // appears.
48 static const int kShowDelay = 400; 48 static const int kShowDelay = 400;
49 49
50 // Amount of time from when the drop exits the menu and the menu is hidden. 50 // Amount of time from when the drop exits the menu and the menu is hidden.
51 static const int kCloseOnExitTime = 1200; 51 static const int kCloseOnExitTime = 1200;
52 52
53 // Border width of the menu shadow (used to align drop down position/bounds)
54 static const int kMenuBorderOffsetY = 2;
sky 2012/08/07 00:31:57 This should be moved into menu_config and you'll w
Harry McCleave 2012/08/07 01:26:36 Done.
55 static const int kMenuBorderOffsetX = 1;
56
53 namespace views { 57 namespace views {
54 58
55 namespace { 59 namespace {
56 60
57 // Returns true if the mnemonic of |menu| matches key. 61 // Returns true if the mnemonic of |menu| matches key.
58 bool MatchesMnemonic(MenuItemView* menu, char16 key) { 62 bool MatchesMnemonic(MenuItemView* menu, char16 key) {
59 return menu->GetMnemonic() == key; 63 return menu->GetMnemonic() == key;
60 } 64 }
61 65
62 // Returns true if |menu| doesn't have a mnemonic and first character of the its 66 // Returns true if |menu| doesn't have a mnemonic and first character of the its
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
270 MenuItemView* MenuController::Run(Widget* parent, 274 MenuItemView* MenuController::Run(Widget* parent,
271 MenuButton* button, 275 MenuButton* button,
272 MenuItemView* root, 276 MenuItemView* root,
273 const gfx::Rect& bounds, 277 const gfx::Rect& bounds,
274 MenuItemView::AnchorPosition position, 278 MenuItemView::AnchorPosition position,
275 int* result_mouse_event_flags) { 279 int* result_mouse_event_flags) {
276 exit_type_ = EXIT_NONE; 280 exit_type_ = EXIT_NONE;
277 possible_drag_ = false; 281 possible_drag_ = false;
278 drag_in_progress_ = false; 282 drag_in_progress_ = false;
279 283
280 // We need to drop the first mouse release event when the menu has been
281 // layed out over the bounds.
282 drop_first_release_event_ =
283 root->GetRequestedMenuPosition() == MenuItemView::POSITION_OVER_BOUNDS;
284
285 bool nested_menu = showing_; 284 bool nested_menu = showing_;
286 if (showing_) { 285 if (showing_) {
287 // Only support nesting of blocking_run menus, nesting of 286 // Only support nesting of blocking_run menus, nesting of
288 // blocking/non-blocking shouldn't be needed. 287 // blocking/non-blocking shouldn't be needed.
289 DCHECK(blocking_run_); 288 DCHECK(blocking_run_);
290 289
291 // We're already showing, push the current state. 290 // We're already showing, push the current state.
292 menu_stack_.push_back(state_); 291 menu_stack_.push_back(state_);
293 292
294 // The context menu should be owned by the same parent. 293 // The context menu should be owned by the same parent.
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
466 ShowSiblingMenu(source, event.location()); 465 ShowSiblingMenu(source, event.location());
467 } 466 }
468 UpdateActiveMouseView(source, event, mouse_menu); 467 UpdateActiveMouseView(source, event, mouse_menu);
469 } 468 }
470 469
471 void MenuController::OnMouseReleased(SubmenuView* source, 470 void MenuController::OnMouseReleased(SubmenuView* source,
472 const MouseEvent& event) { 471 const MouseEvent& event) {
473 if (!blocking_run_) 472 if (!blocking_run_)
474 return; 473 return;
475 474
476 // We must ignore the first release event when it occured within the original
477 // bounds.
478 if (drop_first_release_event_ && (event.flags() & ui::EF_LEFT_MOUSE_BUTTON)) {
479 drop_first_release_event_ = false;
480 gfx::Point loc(event.location());
481 View::ConvertPointToScreen(source->GetScrollViewContainer(), &loc);
482 DCHECK(!state_.initial_bounds.IsEmpty());
483 if (state_.initial_bounds.Contains(loc))
484 return;
485 }
486 drop_first_release_event_ = false;
487
488 DCHECK(state_.item); 475 DCHECK(state_.item);
489 possible_drag_ = false; 476 possible_drag_ = false;
490 DCHECK(blocking_run_); 477 DCHECK(blocking_run_);
491 MenuPart part = GetMenuPart(source, event.location()); 478 MenuPart part = GetMenuPart(source, event.location());
492 if (event.IsRightMouseButton() && (part.type == MenuPart::MENU_ITEM && 479 if (event.IsRightMouseButton() && (part.type == MenuPart::MENU_ITEM &&
493 part.menu)) { 480 part.menu)) {
494 if (ShowContextMenu(part.menu, source, event)) 481 if (ShowContextMenu(part.menu, source, event))
495 return; 482 return;
496 } 483 }
497 484
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after
785 menu_item->GetType() != MenuItemView::SUBMENU)) { 772 menu_item->GetType() != MenuItemView::SUBMENU)) {
786 menu_item->GetWidget()->NotifyAccessibilityEvent( 773 menu_item->GetWidget()->NotifyAccessibilityEvent(
787 menu_item, ui::AccessibilityTypes::EVENT_FOCUS, true); 774 menu_item, ui::AccessibilityTypes::EVENT_FOCUS, true);
788 } 775 }
789 } 776 }
790 777
791 void MenuController::SetSelectionOnPointerDown(SubmenuView* source, 778 void MenuController::SetSelectionOnPointerDown(SubmenuView* source,
792 const LocatedEvent& event) { 779 const LocatedEvent& event) {
793 if (!blocking_run_) 780 if (!blocking_run_)
794 return; 781 return;
795 drop_first_release_event_ = false;
796 782
797 DCHECK(!active_mouse_view_); 783 DCHECK(!active_mouse_view_);
798 784
799 MenuPart part = GetMenuPart(source, event.location()); 785 MenuPart part = GetMenuPart(source, event.location());
800 if (part.is_scroll()) 786 if (part.is_scroll())
801 return; // Ignore presses on scroll buttons. 787 return; // Ignore presses on scroll buttons.
802 788
803 // When this menu is opened through a touch event, a simulated right-click 789 // When this menu is opened through a touch event, a simulated right-click
804 // is sent before the menu appears. Ignore it. 790 // is sent before the menu appears. Ignore it.
805 if ((event.flags() & ui::EF_RIGHT_MOUSE_BUTTON) && 791 if ((event.flags() & ui::EF_RIGHT_MOUSE_BUTTON) &&
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after
1042 default: 1028 default:
1043 break; 1029 break;
1044 } 1030 }
1045 return true; 1031 return true;
1046 } 1032 }
1047 1033
1048 MenuController::MenuController(bool blocking, 1034 MenuController::MenuController(bool blocking,
1049 internal::MenuControllerDelegate* delegate) 1035 internal::MenuControllerDelegate* delegate)
1050 : blocking_run_(blocking), 1036 : blocking_run_(blocking),
1051 showing_(false), 1037 showing_(false),
1052 drop_first_release_event_(false),
1053 exit_type_(EXIT_NONE), 1038 exit_type_(EXIT_NONE),
1054 did_capture_(false), 1039 did_capture_(false),
1055 result_(NULL), 1040 result_(NULL),
1056 result_mouse_event_flags_(0), 1041 result_mouse_event_flags_(0),
1057 drop_target_(NULL), 1042 drop_target_(NULL),
1058 drop_position_(MenuDelegate::DROP_UNKNOWN), 1043 drop_position_(MenuDelegate::DROP_UNKNOWN),
1059 owner_(NULL), 1044 owner_(NULL),
1060 #if defined(USE_AURA) 1045 #if defined(USE_AURA)
1061 root_window_(NULL), 1046 root_window_(NULL),
1062 #endif 1047 #endif
(...skipping 484 matching lines...) Expand 10 before | Expand all | Expand 10 after
1547 gfx::Rect MenuController::CalculateMenuBounds(MenuItemView* item, 1532 gfx::Rect MenuController::CalculateMenuBounds(MenuItemView* item,
1548 bool prefer_leading, 1533 bool prefer_leading,
1549 bool* is_leading) { 1534 bool* is_leading) {
1550 DCHECK(item); 1535 DCHECK(item);
1551 1536
1552 SubmenuView* submenu = item->GetSubmenu(); 1537 SubmenuView* submenu = item->GetSubmenu();
1553 DCHECK(submenu); 1538 DCHECK(submenu);
1554 1539
1555 gfx::Size pref = submenu->GetScrollViewContainer()->GetPreferredSize(); 1540 gfx::Size pref = submenu->GetScrollViewContainer()->GetPreferredSize();
1556 1541
1542 pref.set_width(pref.width() - (2 * kMenuBorderOffsetX));
sky 2012/08/07 00:31:57 Move this into 1545.
Harry McCleave 2012/08/07 01:26:36 Done.
1543
1557 // Don't let the menu go too wide. 1544 // Don't let the menu go too wide.
1558 if (item->actual_menu_position() != MenuItemView::POSITION_OVER_BOUNDS) 1545 pref.set_width(std::min(pref.width(),
1559 pref.set_width(std::min(pref.width(),
1560 item->GetDelegate()->GetMaxWidthForMenu(item))); 1546 item->GetDelegate()->GetMaxWidthForMenu(item)));
1561 if (!state_.monitor_bounds.IsEmpty()) 1547 if (!state_.monitor_bounds.IsEmpty())
1562 pref.set_width(std::min(pref.width(), state_.monitor_bounds.width())); 1548 pref.set_width(std::min(pref.width(), state_.monitor_bounds.width()));
1563 1549
1564 // Assume we can honor prefer_leading. 1550 // Assume we can honor prefer_leading.
1565 *is_leading = prefer_leading; 1551 *is_leading = prefer_leading;
1566 1552
1567 int x, y; 1553 int x, y;
1568 1554
1569 if (!item->GetParentMenuItem()) { 1555 if (!item->GetParentMenuItem()) {
1570 // First item, position relative to initial location. 1556 // First item, position relative to initial location.
1571 x = state_.initial_bounds.x(); 1557 x = state_.initial_bounds.x() + kMenuBorderOffsetX;
1572 if (item->actual_menu_position() == MenuItemView::POSITION_OVER_BOUNDS) 1558 y = state_.initial_bounds.bottom() + kMenuBorderOffsetY;
1573 y = state_.initial_bounds.y();
1574 else
1575 y = state_.initial_bounds.bottom();
1576 if (state_.anchor == MenuItemView::TOPRIGHT) 1559 if (state_.anchor == MenuItemView::TOPRIGHT)
1577 x = x + state_.initial_bounds.width() - pref.width(); 1560 x = x + state_.initial_bounds.width() - pref.width();
1578 1561
1579 if (!state_.monitor_bounds.IsEmpty() && 1562 if (!state_.monitor_bounds.IsEmpty() &&
1580 pref.height() > state_.monitor_bounds.height() && 1563 y + pref.height() > state_.monitor_bounds.bottom()) {
1581 item->actual_menu_position() == MenuItemView::POSITION_OVER_BOUNDS) {
1582 // Handle very tall menus.
1583 pref.set_height(state_.monitor_bounds.height());
1584 y = state_.monitor_bounds.y();
1585 } else if (!state_.monitor_bounds.IsEmpty() &&
1586 y + pref.height() > state_.monitor_bounds.bottom() &&
1587 item->actual_menu_position() != MenuItemView::POSITION_OVER_BOUNDS) {
1588 // The menu doesn't fit fully below the button on the screen. The menu 1564 // The menu doesn't fit fully below the button on the screen. The menu
1589 // position with respect to the bounds will be preserved if it has 1565 // position with respect to the bounds will be preserved if it has
1590 // already been drawn. When the requested positioning is below the bounds 1566 // already been drawn. When the requested positioning is below the bounds
1591 // it will shrink the menu to make it fit below. 1567 // it will shrink the menu to make it fit below.
1592 // If the requested positioning is best fit, it will first try to fit the 1568 // If the requested positioning is best fit, it will first try to fit the
1593 // menu below. If that does not fit it will try to place it above. If 1569 // menu below. If that does not fit it will try to place it above. If
1594 // that will not fit it will place it at the bottom of the work area and 1570 // that will not fit it will place it at the bottom of the work area and
1595 // moving it off the initial_bounds region to avoid overlap. 1571 // moving it off the initial_bounds region to avoid overlap.
1596 // In all other requested position styles it will be flipped above and 1572 // In all other requested position styles it will be flipped above and
1597 // the height will be shrunken to the usable height. 1573 // the height will be shrunken to the usable height.
1598 if (item->actual_menu_position() == MenuItemView::POSITION_BELOW_BOUNDS) { 1574 if (item->menu_position() == MenuItemView::POSITION_BELOW_BOUNDS) {
1599 pref.set_height(std::min(pref.height(), 1575 pref.set_height(std::min(pref.height(),
1600 state_.monitor_bounds.bottom() - y)); 1576 state_.monitor_bounds.bottom() - y));
1601 } else if (item->actual_menu_position() == 1577 } else if (item->menu_position() ==
1602 MenuItemView::POSITION_BEST_FIT) { 1578 MenuItemView::POSITION_BEST_FIT) {
1603 MenuItemView::MenuPosition orientation = 1579 MenuItemView::MenuPosition orientation =
1604 MenuItemView::POSITION_BELOW_BOUNDS; 1580 MenuItemView::POSITION_BELOW_BOUNDS;
1605 if (state_.monitor_bounds.height() < pref.height()) { 1581 if (state_.monitor_bounds.height() < pref.height()) {
1606 // Handle very tall menus. 1582 // Handle very tall menus.
1607 pref.set_height(state_.monitor_bounds.height()); 1583 pref.set_height(state_.monitor_bounds.height());
1608 y = state_.monitor_bounds.y(); 1584 y = state_.monitor_bounds.y();
1609 } else if (state_.monitor_bounds.y() + pref.height() < 1585 } else if (state_.monitor_bounds.y() + pref.height() <
1610 state_.initial_bounds.y()) { 1586 state_.initial_bounds.y()) {
1611 // Flipping upwards if there is enough space. 1587 // Flipping upwards if there is enough space.
(...skipping 18 matching lines...) Expand all
1630 } else { 1606 } else {
1631 // The menu should end with the same x coordinate as the owning 1607 // The menu should end with the same x coordinate as the owning
1632 // button. 1608 // button.
1633 if (state_.monitor_bounds.x() > 1609 if (state_.monitor_bounds.x() >
1634 state_.initial_bounds.x() - pref.width()) 1610 state_.initial_bounds.x() - pref.width())
1635 x = state_.initial_bounds.right(); // Move right of the button. 1611 x = state_.initial_bounds.right(); // Move right of the button.
1636 else 1612 else
1637 x = state_.initial_bounds.x() - pref.width(); // Move left. 1613 x = state_.initial_bounds.x() - pref.width(); // Move left.
1638 } 1614 }
1639 } 1615 }
1640 item->set_actual_menu_position(orientation); 1616 item->set_menu_position(orientation);
1641 } else { 1617 } else {
1642 pref.set_height(std::min(pref.height(), 1618 pref.set_height(std::min(pref.height(),
1643 state_.initial_bounds.y() - state_.monitor_bounds.y())); 1619 state_.initial_bounds.y() - state_.monitor_bounds.y()));
1644 y = state_.initial_bounds.y() - pref.height(); 1620 y = state_.initial_bounds.y() - pref.height();
1645 item->set_actual_menu_position(MenuItemView::POSITION_ABOVE_BOUNDS); 1621 item->set_menu_position(MenuItemView::POSITION_ABOVE_BOUNDS);
1646 } 1622 }
1647 } else if (item->actual_menu_position() == 1623 } else if (item->menu_position() ==
1648 MenuItemView::POSITION_ABOVE_BOUNDS) { 1624 MenuItemView::POSITION_ABOVE_BOUNDS) {
1649 pref.set_height(std::min(pref.height(), 1625 pref.set_height(std::min(pref.height(),
1650 state_.initial_bounds.y() - state_.monitor_bounds.y())); 1626 state_.initial_bounds.y() - state_.monitor_bounds.y()));
1651 y = state_.initial_bounds.y() - pref.height(); 1627 y = state_.initial_bounds.y() - pref.height();
1652 } else if (item->actual_menu_position() ==
1653 MenuItemView::POSITION_OVER_BOUNDS) {
1654 // Center vertically assuming all items have the same height.
1655 int middle = state_.initial_bounds.y() - pref.height() / 2;
1656 if (submenu->GetMenuItemCount() > 0)
1657 middle += submenu->GetMenuItemAt(0)->GetPreferredSize().height() / 2;
1658 y = std::max(state_.monitor_bounds.y(), middle);
1659 if (y + pref.height() > state_.monitor_bounds.bottom())
1660 y = state_.monitor_bounds.bottom() - pref.height();
1661 } else { 1628 } else {
1662 item->set_actual_menu_position(MenuItemView::POSITION_BELOW_BOUNDS); 1629 item->set_menu_position(MenuItemView::POSITION_BELOW_BOUNDS);
1663 } 1630 }
1664 } else { 1631 } else {
1665 // Not the first menu; position it relative to the bounds of the menu 1632 // Not the first menu; position it relative to the bounds of the menu
1666 // item. 1633 // item.
1667 gfx::Point item_loc; 1634 gfx::Point item_loc;
1668 View::ConvertPointToScreen(item, &item_loc); 1635 View::ConvertPointToScreen(item, &item_loc);
1669 1636
1670 // We must make sure we take into account the UI layout. If the layout is 1637 // We must make sure we take into account the UI layout. If the layout is
1671 // RTL, then a 'leading' menu is positioned to the left of the parent menu 1638 // RTL, then a 'leading' menu is positioned to the left of the parent menu
1672 // item and not to the right. 1639 // item and not to the right.
(...skipping 467 matching lines...) Expand 10 before | Expand all | Expand 10 after
2140 2107
2141 #if defined(USE_AURA) 2108 #if defined(USE_AURA)
2142 void MenuController::OnWindowActivated(aura::Window* active, 2109 void MenuController::OnWindowActivated(aura::Window* active,
2143 aura::Window* old_active) { 2110 aura::Window* old_active) {
2144 if (!drag_in_progress_) 2111 if (!drag_in_progress_)
2145 Cancel(EXIT_ALL); 2112 Cancel(EXIT_ALL);
2146 } 2113 }
2147 #endif 2114 #endif
2148 2115
2149 } // namespace views 2116 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698