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_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 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
270 MenuItemView* MenuController::Run(Widget* parent, | 270 MenuItemView* MenuController::Run(Widget* parent, |
271 MenuButton* button, | 271 MenuButton* button, |
272 MenuItemView* root, | 272 MenuItemView* root, |
273 const gfx::Rect& bounds, | 273 const gfx::Rect& bounds, |
274 MenuItemView::AnchorPosition position, | 274 MenuItemView::AnchorPosition position, |
275 int* result_mouse_event_flags) { | 275 int* result_mouse_event_flags) { |
276 exit_type_ = EXIT_NONE; | 276 exit_type_ = EXIT_NONE; |
277 possible_drag_ = false; | 277 possible_drag_ = false; |
278 drag_in_progress_ = false; | 278 drag_in_progress_ = false; |
279 | 279 |
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_; | 280 bool nested_menu = showing_; |
286 if (showing_) { | 281 if (showing_) { |
287 // Only support nesting of blocking_run menus, nesting of | 282 // Only support nesting of blocking_run menus, nesting of |
288 // blocking/non-blocking shouldn't be needed. | 283 // blocking/non-blocking shouldn't be needed. |
289 DCHECK(blocking_run_); | 284 DCHECK(blocking_run_); |
290 | 285 |
291 // We're already showing, push the current state. | 286 // We're already showing, push the current state. |
292 menu_stack_.push_back(state_); | 287 menu_stack_.push_back(state_); |
293 | 288 |
294 // The context menu should be owned by the same parent. | 289 // The context menu should be owned by the same parent. |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
466 ShowSiblingMenu(source, event.location()); | 461 ShowSiblingMenu(source, event.location()); |
467 } | 462 } |
468 UpdateActiveMouseView(source, event, mouse_menu); | 463 UpdateActiveMouseView(source, event, mouse_menu); |
469 } | 464 } |
470 | 465 |
471 void MenuController::OnMouseReleased(SubmenuView* source, | 466 void MenuController::OnMouseReleased(SubmenuView* source, |
472 const MouseEvent& event) { | 467 const MouseEvent& event) { |
473 if (!blocking_run_) | 468 if (!blocking_run_) |
474 return; | 469 return; |
475 | 470 |
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); | 471 DCHECK(state_.item); |
489 possible_drag_ = false; | 472 possible_drag_ = false; |
490 DCHECK(blocking_run_); | 473 DCHECK(blocking_run_); |
491 MenuPart part = GetMenuPart(source, event.location()); | 474 MenuPart part = GetMenuPart(source, event.location()); |
492 if (event.IsRightMouseButton() && (part.type == MenuPart::MENU_ITEM && | 475 if (event.IsRightMouseButton() && (part.type == MenuPart::MENU_ITEM && |
493 part.menu)) { | 476 part.menu)) { |
494 if (ShowContextMenu(part.menu, source, event)) | 477 if (ShowContextMenu(part.menu, source, event)) |
495 return; | 478 return; |
496 } | 479 } |
497 | 480 |
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
785 menu_item->GetType() != MenuItemView::SUBMENU)) { | 768 menu_item->GetType() != MenuItemView::SUBMENU)) { |
786 menu_item->GetWidget()->NotifyAccessibilityEvent( | 769 menu_item->GetWidget()->NotifyAccessibilityEvent( |
787 menu_item, ui::AccessibilityTypes::EVENT_FOCUS, true); | 770 menu_item, ui::AccessibilityTypes::EVENT_FOCUS, true); |
788 } | 771 } |
789 } | 772 } |
790 | 773 |
791 void MenuController::SetSelectionOnPointerDown(SubmenuView* source, | 774 void MenuController::SetSelectionOnPointerDown(SubmenuView* source, |
792 const LocatedEvent& event) { | 775 const LocatedEvent& event) { |
793 if (!blocking_run_) | 776 if (!blocking_run_) |
794 return; | 777 return; |
795 drop_first_release_event_ = false; | |
796 | 778 |
797 DCHECK(!active_mouse_view_); | 779 DCHECK(!active_mouse_view_); |
798 | 780 |
799 MenuPart part = GetMenuPart(source, event.location()); | 781 MenuPart part = GetMenuPart(source, event.location()); |
800 if (part.is_scroll()) | 782 if (part.is_scroll()) |
801 return; // Ignore presses on scroll buttons. | 783 return; // Ignore presses on scroll buttons. |
802 | 784 |
803 // When this menu is opened through a touch event, a simulated right-click | 785 // When this menu is opened through a touch event, a simulated right-click |
804 // is sent before the menu appears. Ignore it. | 786 // is sent before the menu appears. Ignore it. |
805 if ((event.flags() & ui::EF_RIGHT_MOUSE_BUTTON) && | 787 if ((event.flags() & ui::EF_RIGHT_MOUSE_BUTTON) && |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1042 default: | 1024 default: |
1043 break; | 1025 break; |
1044 } | 1026 } |
1045 return true; | 1027 return true; |
1046 } | 1028 } |
1047 | 1029 |
1048 MenuController::MenuController(bool blocking, | 1030 MenuController::MenuController(bool blocking, |
1049 internal::MenuControllerDelegate* delegate) | 1031 internal::MenuControllerDelegate* delegate) |
1050 : blocking_run_(blocking), | 1032 : blocking_run_(blocking), |
1051 showing_(false), | 1033 showing_(false), |
1052 drop_first_release_event_(false), | |
1053 exit_type_(EXIT_NONE), | 1034 exit_type_(EXIT_NONE), |
1054 did_capture_(false), | 1035 did_capture_(false), |
1055 result_(NULL), | 1036 result_(NULL), |
1056 result_mouse_event_flags_(0), | 1037 result_mouse_event_flags_(0), |
1057 drop_target_(NULL), | 1038 drop_target_(NULL), |
1058 drop_position_(MenuDelegate::DROP_UNKNOWN), | 1039 drop_position_(MenuDelegate::DROP_UNKNOWN), |
1059 owner_(NULL), | 1040 owner_(NULL), |
1060 #if defined(USE_AURA) | 1041 #if defined(USE_AURA) |
1061 root_window_(NULL), | 1042 root_window_(NULL), |
1062 #endif | 1043 #endif |
(...skipping 485 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1548 bool prefer_leading, | 1529 bool prefer_leading, |
1549 bool* is_leading) { | 1530 bool* is_leading) { |
1550 DCHECK(item); | 1531 DCHECK(item); |
1551 | 1532 |
1552 SubmenuView* submenu = item->GetSubmenu(); | 1533 SubmenuView* submenu = item->GetSubmenu(); |
1553 DCHECK(submenu); | 1534 DCHECK(submenu); |
1554 | 1535 |
1555 gfx::Size pref = submenu->GetScrollViewContainer()->GetPreferredSize(); | 1536 gfx::Size pref = submenu->GetScrollViewContainer()->GetPreferredSize(); |
1556 | 1537 |
1557 // Don't let the menu go too wide. | 1538 // Don't let the menu go too wide. |
1558 if (item->actual_menu_position() != MenuItemView::POSITION_OVER_BOUNDS) | 1539 pref.set_width(std::min(pref.width() - |
1559 pref.set_width(std::min(pref.width(), | 1540 (2 * MenuConfig::instance().menu_border_offset_horizontal), |
sky
2012/08/07 03:41:53
I'm confused by the usage of this. Here menu_borde
Harry McCleave
2012/08/07 20:16:34
Done.
| |
1560 item->GetDelegate()->GetMaxWidthForMenu(item))); | 1541 item->GetDelegate()->GetMaxWidthForMenu(item))); |
1561 if (!state_.monitor_bounds.IsEmpty()) | 1542 if (!state_.monitor_bounds.IsEmpty()) |
1562 pref.set_width(std::min(pref.width(), state_.monitor_bounds.width())); | 1543 pref.set_width(std::min(pref.width(), state_.monitor_bounds.width())); |
1563 | 1544 |
1564 // Assume we can honor prefer_leading. | 1545 // Assume we can honor prefer_leading. |
1565 *is_leading = prefer_leading; | 1546 *is_leading = prefer_leading; |
1566 | 1547 |
1567 int x, y; | 1548 int x, y; |
1568 | 1549 |
1569 if (!item->GetParentMenuItem()) { | 1550 if (!item->GetParentMenuItem()) { |
1570 // First item, position relative to initial location. | 1551 // First item, position relative to initial location. |
1571 x = state_.initial_bounds.x(); | 1552 x = state_.initial_bounds.x() + |
1572 if (item->actual_menu_position() == MenuItemView::POSITION_OVER_BOUNDS) | 1553 MenuConfig::instance().menu_border_offset_horizontal; |
1573 y = state_.initial_bounds.y(); | 1554 y = state_.initial_bounds.bottom() + |
1574 else | 1555 MenuConfig::instance().menu_border_offset_vertical; |
1575 y = state_.initial_bounds.bottom(); | |
1576 if (state_.anchor == MenuItemView::TOPRIGHT) | 1556 if (state_.anchor == MenuItemView::TOPRIGHT) |
1577 x = x + state_.initial_bounds.width() - pref.width(); | 1557 x = x + state_.initial_bounds.width() - pref.width(); |
1578 | 1558 |
1579 if (!state_.monitor_bounds.IsEmpty() && | 1559 if (!state_.monitor_bounds.IsEmpty() && |
1580 pref.height() > state_.monitor_bounds.height() && | 1560 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 | 1561 // 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 | 1562 // position with respect to the bounds will be preserved if it has |
1590 // already been drawn. When the requested positioning is below the bounds | 1563 // already been drawn. When the requested positioning is below the bounds |
1591 // it will shrink the menu to make it fit below. | 1564 // 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 | 1565 // 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 | 1566 // 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 | 1567 // 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. | 1568 // moving it off the initial_bounds region to avoid overlap. |
1596 // In all other requested position styles it will be flipped above and | 1569 // In all other requested position styles it will be flipped above and |
1597 // the height will be shrunken to the usable height. | 1570 // the height will be shrunken to the usable height. |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1642 pref.set_height(std::min(pref.height(), | 1615 pref.set_height(std::min(pref.height(), |
1643 state_.initial_bounds.y() - state_.monitor_bounds.y())); | 1616 state_.initial_bounds.y() - state_.monitor_bounds.y())); |
1644 y = state_.initial_bounds.y() - pref.height(); | 1617 y = state_.initial_bounds.y() - pref.height(); |
1645 item->set_actual_menu_position(MenuItemView::POSITION_ABOVE_BOUNDS); | 1618 item->set_actual_menu_position(MenuItemView::POSITION_ABOVE_BOUNDS); |
1646 } | 1619 } |
1647 } else if (item->actual_menu_position() == | 1620 } else if (item->actual_menu_position() == |
1648 MenuItemView::POSITION_ABOVE_BOUNDS) { | 1621 MenuItemView::POSITION_ABOVE_BOUNDS) { |
1649 pref.set_height(std::min(pref.height(), | 1622 pref.set_height(std::min(pref.height(), |
1650 state_.initial_bounds.y() - state_.monitor_bounds.y())); | 1623 state_.initial_bounds.y() - state_.monitor_bounds.y())); |
1651 y = state_.initial_bounds.y() - pref.height(); | 1624 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 { | 1625 } else { |
1662 item->set_actual_menu_position(MenuItemView::POSITION_BELOW_BOUNDS); | 1626 item->set_actual_menu_position(MenuItemView::POSITION_BELOW_BOUNDS); |
1663 } | 1627 } |
1664 } else { | 1628 } else { |
1665 // Not the first menu; position it relative to the bounds of the menu | 1629 // Not the first menu; position it relative to the bounds of the menu |
1666 // item. | 1630 // item. |
1667 gfx::Point item_loc; | 1631 gfx::Point item_loc; |
1668 View::ConvertPointToScreen(item, &item_loc); | 1632 View::ConvertPointToScreen(item, &item_loc); |
1669 | 1633 |
1670 // We must make sure we take into account the UI layout. If the layout is | 1634 // We must make sure we take into account the UI layout. If the layout is |
(...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2140 | 2104 |
2141 #if defined(USE_AURA) | 2105 #if defined(USE_AURA) |
2142 void MenuController::OnWindowActivated(aura::Window* active, | 2106 void MenuController::OnWindowActivated(aura::Window* active, |
2143 aura::Window* old_active) { | 2107 aura::Window* old_active) { |
2144 if (!drag_in_progress_) | 2108 if (!drag_in_progress_) |
2145 Cancel(EXIT_ALL); | 2109 Cancel(EXIT_ALL); |
2146 } | 2110 } |
2147 #endif | 2111 #endif |
2148 | 2112 |
2149 } // namespace views | 2113 } // namespace views |
OLD | NEW |