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_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 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 246 // currently selected item whose mnemonic matches. This may remain -1 even | 246 // currently selected item whose mnemonic matches. This may remain -1 even |
| 247 // though there are matches. | 247 // though there are matches. |
| 248 int next_match; | 248 int next_match; |
| 249 }; | 249 }; |
| 250 | 250 |
| 251 // MenuController:State ------------------------------------------------------ | 251 // MenuController:State ------------------------------------------------------ |
| 252 | 252 |
| 253 MenuController::State::State() | 253 MenuController::State::State() |
| 254 : item(NULL), | 254 : item(NULL), |
| 255 submenu_open(false), | 255 submenu_open(false), |
| 256 anchor(views::MenuItemView::TOPLEFT) {} | 256 anchor(views::MenuItemView::TOPLEFT), |
| 257 context_menu(false) {} | |
| 257 | 258 |
| 258 MenuController::State::~State() {} | 259 MenuController::State::~State() {} |
| 259 | 260 |
| 260 // MenuController ------------------------------------------------------------ | 261 // MenuController ------------------------------------------------------------ |
| 261 | 262 |
| 262 // static | 263 // static |
| 263 MenuController* MenuController::active_instance_ = NULL; | 264 MenuController* MenuController::active_instance_ = NULL; |
| 264 | 265 |
| 265 // static | 266 // static |
| 266 MenuController* MenuController::GetActiveInstance() { | 267 MenuController* MenuController::GetActiveInstance() { |
| 267 return active_instance_; | 268 return active_instance_; |
| 268 } | 269 } |
| 269 | 270 |
| 270 MenuItemView* MenuController::Run(Widget* parent, | 271 MenuItemView* MenuController::Run(Widget* parent, |
| 271 MenuButton* button, | 272 MenuButton* button, |
| 272 MenuItemView* root, | 273 MenuItemView* root, |
| 273 const gfx::Rect& bounds, | 274 const gfx::Rect& bounds, |
| 274 MenuItemView::AnchorPosition position, | 275 MenuItemView::AnchorPosition position, |
| 276 bool context_menu, | |
| 275 int* result_mouse_event_flags) { | 277 int* result_mouse_event_flags) { |
| 276 exit_type_ = EXIT_NONE; | 278 exit_type_ = EXIT_NONE; |
| 277 possible_drag_ = false; | 279 possible_drag_ = false; |
| 278 drag_in_progress_ = false; | 280 drag_in_progress_ = false; |
| 279 | 281 |
| 280 bool nested_menu = showing_; | 282 bool nested_menu = showing_; |
| 281 if (showing_) { | 283 if (showing_) { |
| 282 // Only support nesting of blocking_run menus, nesting of | 284 // Only support nesting of blocking_run menus, nesting of |
| 283 // blocking/non-blocking shouldn't be needed. | 285 // blocking/non-blocking shouldn't be needed. |
| 284 DCHECK(blocking_run_); | 286 DCHECK(blocking_run_); |
| 285 | 287 |
| 286 // We're already showing, push the current state. | 288 // We're already showing, push the current state. |
| 287 menu_stack_.push_back(state_); | 289 menu_stack_.push_back(state_); |
| 288 | 290 |
| 289 // The context menu should be owned by the same parent. | 291 // The context menu should be owned by the same parent. |
| 290 DCHECK_EQ(owner_, parent); | 292 DCHECK_EQ(owner_, parent); |
| 291 } else { | 293 } else { |
| 292 showing_ = true; | 294 showing_ = true; |
| 293 } | 295 } |
| 294 | 296 |
| 295 // Reset current state. | 297 // Reset current state. |
| 296 pending_state_ = State(); | 298 pending_state_ = State(); |
| 297 state_ = State(); | 299 state_ = State(); |
| 298 UpdateInitialLocation(bounds, position); | 300 UpdateInitialLocation(bounds, position, context_menu); |
| 299 | 301 |
| 300 owner_ = parent; | 302 owner_ = parent; |
| 301 | 303 |
| 302 // Set the selection, which opens the initial menu. | 304 // Set the selection, which opens the initial menu. |
| 303 SetSelection(root, SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY); | 305 SetSelection(root, SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY); |
| 304 | 306 |
| 305 if (!blocking_run_) { | 307 if (!blocking_run_) { |
| 306 // Start the timer to hide the menu. This is needed as we get no | 308 // Start the timer to hide the menu. This is needed as we get no |
| 307 // notification when the drag has finished. | 309 // notification when the drag has finished. |
| 308 StartCancelAllTimer(); | 310 StartCancelAllTimer(); |
| (...skipping 764 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1073 if (hot_view->GetClassName() == CustomButton::kViewClassName) { | 1075 if (hot_view->GetClassName() == CustomButton::kViewClassName) { |
| 1074 CustomButton* button = static_cast<CustomButton*>(hot_view); | 1076 CustomButton* button = static_cast<CustomButton*>(hot_view); |
| 1075 button->SetHotTracked(true); | 1077 button->SetHotTracked(true); |
| 1076 } | 1078 } |
| 1077 return (exit_type_ == EXIT_NONE) ? | 1079 return (exit_type_ == EXIT_NONE) ? |
| 1078 ACCELERATOR_PROCESSED : ACCELERATOR_PROCESSED_EXIT; | 1080 ACCELERATOR_PROCESSED : ACCELERATOR_PROCESSED_EXIT; |
| 1079 } | 1081 } |
| 1080 | 1082 |
| 1081 void MenuController::UpdateInitialLocation( | 1083 void MenuController::UpdateInitialLocation( |
| 1082 const gfx::Rect& bounds, | 1084 const gfx::Rect& bounds, |
| 1083 MenuItemView::AnchorPosition position) { | 1085 MenuItemView::AnchorPosition position, |
| 1086 bool context_menu) { | |
| 1087 pending_state_.context_menu = context_menu; | |
| 1084 pending_state_.initial_bounds = bounds; | 1088 pending_state_.initial_bounds = bounds; |
| 1085 if (bounds.height() > 1) { | 1089 if (bounds.height() > 1) { |
| 1086 // Inset the bounds slightly, otherwise drag coordinates don't line up | 1090 // Inset the bounds slightly, otherwise drag coordinates don't line up |
| 1087 // nicely and menus close prematurely. | 1091 // nicely and menus close prematurely. |
| 1088 pending_state_.initial_bounds.Inset(0, 1); | 1092 pending_state_.initial_bounds.Inset(0, 1); |
| 1089 } | 1093 } |
| 1090 | 1094 |
| 1091 // Reverse anchor position for RTL languages. | 1095 // Reverse anchor position for RTL languages. |
| 1092 if (base::i18n::IsRTL()) { | 1096 if (base::i18n::IsRTL()) { |
| 1093 pending_state_.anchor = position == MenuItemView::TOPRIGHT ? | 1097 pending_state_.anchor = position == MenuItemView::TOPRIGHT ? |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1174 menu_button_->SchedulePaint(); | 1178 menu_button_->SchedulePaint(); |
| 1175 | 1179 |
| 1176 // Need to reset capture when we show the menu again, otherwise we aren't | 1180 // Need to reset capture when we show the menu again, otherwise we aren't |
| 1177 // going to get any events. | 1181 // going to get any events. |
| 1178 did_capture_ = false; | 1182 did_capture_ = false; |
| 1179 gfx::Point screen_menu_loc; | 1183 gfx::Point screen_menu_loc; |
| 1180 View::ConvertPointToScreen(button, &screen_menu_loc); | 1184 View::ConvertPointToScreen(button, &screen_menu_loc); |
| 1181 // Subtract 1 from the height to make the popup flush with the button border. | 1185 // Subtract 1 from the height to make the popup flush with the button border. |
| 1182 UpdateInitialLocation(gfx::Rect(screen_menu_loc.x(), screen_menu_loc.y(), | 1186 UpdateInitialLocation(gfx::Rect(screen_menu_loc.x(), screen_menu_loc.y(), |
| 1183 button->width(), button->height() - 1), | 1187 button->width(), button->height() - 1), |
| 1184 anchor); | 1188 anchor, state_.context_menu); |
| 1185 alt_menu->PrepareForRun( | 1189 alt_menu->PrepareForRun( |
| 1186 has_mnemonics, | 1190 has_mnemonics, source->GetMenuItem()->GetRootMenuItem()->show_mnemonics_); |
| 1187 source->GetMenuItem()->GetRootMenuItem()->show_mnemonics_); | |
| 1188 alt_menu->controller_ = this; | 1191 alt_menu->controller_ = this; |
| 1189 SetSelection(alt_menu, SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY); | 1192 SetSelection(alt_menu, SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY); |
| 1190 return true; | 1193 return true; |
| 1191 } | 1194 } |
| 1192 | 1195 |
| 1193 bool MenuController::ShowContextMenu(MenuItemView* menu_item, | 1196 bool MenuController::ShowContextMenu(MenuItemView* menu_item, |
| 1194 SubmenuView* source, | 1197 SubmenuView* source, |
| 1195 const ui::LocatedEvent& event) { | 1198 const ui::LocatedEvent& event) { |
| 1196 // Set the selection immediately, making sure the submenu is only open | 1199 // Set the selection immediately, making sure the submenu is only open |
| 1197 // if it already was. | 1200 // if it already was. |
| (...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1543 pref.set_width(std::min(pref.width(), state_.monitor_bounds.width())); | 1546 pref.set_width(std::min(pref.width(), state_.monitor_bounds.width())); |
| 1544 | 1547 |
| 1545 // Assume we can honor prefer_leading. | 1548 // Assume we can honor prefer_leading. |
| 1546 *is_leading = prefer_leading; | 1549 *is_leading = prefer_leading; |
| 1547 | 1550 |
| 1548 int x, y; | 1551 int x, y; |
| 1549 | 1552 |
| 1550 if (!item->GetParentMenuItem()) { | 1553 if (!item->GetParentMenuItem()) { |
| 1551 // First item, position relative to initial location. | 1554 // First item, position relative to initial location. |
| 1552 x = state_.initial_bounds.x(); | 1555 x = state_.initial_bounds.x(); |
| 1556 // Offsets for context menu prevent menu items being selected by | |
| 1557 // simply opening the menu (bug 142992) | |
|
sky
2012/08/21 15:40:43
End with a '.'.
Harry McCleave
2012/08/21 18:38:35
Done.
Harry McCleave
2012/08/21 18:38:35
Done.
| |
| 1558 if(state_.context_menu) | |
|
sky
2012/08/21 15:40:43
Do we really want to do this every where, or only
Harry McCleave
2012/08/21 18:38:35
Done.
| |
| 1559 x += 1; | |
| 1553 y = state_.initial_bounds.bottom(); | 1560 y = state_.initial_bounds.bottom(); |
| 1554 if (state_.anchor == MenuItemView::TOPRIGHT) | 1561 if (state_.anchor == MenuItemView::TOPRIGHT) { |
| 1555 x = x + state_.initial_bounds.width() - pref.width(); | 1562 x = x + state_.initial_bounds.width() - pref.width(); |
| 1563 if(state_.context_menu) | |
|
sky
2012/08/21 15:40:43
nit: spacing.
Harry McCleave
2012/08/21 18:38:35
Done.
| |
| 1564 x -= 1; | |
| 1565 } | |
| 1556 | 1566 |
| 1557 if (!state_.monitor_bounds.IsEmpty() && | 1567 if (!state_.monitor_bounds.IsEmpty() && |
| 1558 y + pref.height() > state_.monitor_bounds.bottom()) { | 1568 y + pref.height() > state_.monitor_bounds.bottom()) { |
| 1559 // The menu doesn't fit fully below the button on the screen. The menu | 1569 // The menu doesn't fit fully below the button on the screen. The menu |
| 1560 // position with respect to the bounds will be preserved if it has | 1570 // position with respect to the bounds will be preserved if it has |
| 1561 // already been drawn. When the requested positioning is below the bounds | 1571 // already been drawn. When the requested positioning is below the bounds |
| 1562 // it will shrink the menu to make it fit below. | 1572 // it will shrink the menu to make it fit below. |
| 1563 // If the requested positioning is best fit, it will first try to fit the | 1573 // If the requested positioning is best fit, it will first try to fit the |
| 1564 // menu below. If that does not fit it will try to place it above. If | 1574 // menu below. If that does not fit it will try to place it above. If |
| 1565 // that will not fit it will place it at the bottom of the work area and | 1575 // that will not fit it will place it at the bottom of the work area and |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1661 y = item_loc.y() - MenuConfig::instance().submenu_vertical_margin_size; | 1671 y = item_loc.y() - MenuConfig::instance().submenu_vertical_margin_size; |
| 1662 if (state_.monitor_bounds.width() != 0) { | 1672 if (state_.monitor_bounds.width() != 0) { |
| 1663 pref.set_height(std::min(pref.height(), state_.monitor_bounds.height())); | 1673 pref.set_height(std::min(pref.height(), state_.monitor_bounds.height())); |
| 1664 if (y + pref.height() > state_.monitor_bounds.bottom()) | 1674 if (y + pref.height() > state_.monitor_bounds.bottom()) |
| 1665 y = state_.monitor_bounds.bottom() - pref.height(); | 1675 y = state_.monitor_bounds.bottom() - pref.height(); |
| 1666 if (y < state_.monitor_bounds.y()) | 1676 if (y < state_.monitor_bounds.y()) |
| 1667 y = state_.monitor_bounds.y(); | 1677 y = state_.monitor_bounds.y(); |
| 1668 } | 1678 } |
| 1669 } | 1679 } |
| 1670 | 1680 |
| 1671 if (state_.monitor_bounds.width() != 0) { | 1681 if (state_.monitor_bounds.width() != 0) { |
|
sky
2012/08/21 15:40:43
I think this wholoe block should be moved inside t
Harry McCleave
2012/08/21 18:38:35
Done.
| |
| 1672 if (x + pref.width() > state_.monitor_bounds.right()) | 1682 if (x + pref.width() > state_.monitor_bounds.right()) { |
| 1673 x = state_.monitor_bounds.right() - pref.width(); | 1683 if(state_.context_menu && !item->GetParentMenuItem()) |
|
sky
2012/08/21 15:40:43
nit: spacing
Harry McCleave
2012/08/21 18:38:35
Done.
| |
| 1674 if (x < state_.monitor_bounds.x()) | 1684 x -= pref.width() + 1; |
| 1675 x = state_.monitor_bounds.x(); | 1685 else |
| 1686 x = state_.monitor_bounds.right() - pref.width(); | |
| 1687 } | |
| 1688 if (x < state_.monitor_bounds.x()) { | |
| 1689 int temp_loc = state_.initial_bounds.x() + 1; | |
| 1690 if(state_.context_menu && !item->GetParentMenuItem() && | |
| 1691 temp_loc >= state_.monitor_bounds.x() && | |
| 1692 temp_loc + pref.width() < state_.monitor_bounds.right()) | |
| 1693 x = temp_loc; | |
| 1694 else | |
| 1695 x = state_.monitor_bounds.x(); | |
| 1696 } | |
| 1676 } | 1697 } |
| 1677 return gfx::Rect(x, y, pref.width(), pref.height()); | 1698 return gfx::Rect(x, y, pref.width(), pref.height()); |
| 1678 } | 1699 } |
| 1679 | 1700 |
| 1680 // static | 1701 // static |
| 1681 int MenuController::MenuDepth(MenuItemView* item) { | 1702 int MenuController::MenuDepth(MenuItemView* item) { |
| 1682 return item ? (MenuDepth(item->GetParentMenuItem()) + 1) : 0; | 1703 return item ? (MenuDepth(item->GetParentMenuItem()) + 1) : 0; |
| 1683 } | 1704 } |
| 1684 | 1705 |
| 1685 void MenuController::IncrementSelection(int delta) { | 1706 void MenuController::IncrementSelection(int delta) { |
| (...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2105 | 2126 |
| 2106 #if defined(USE_AURA) | 2127 #if defined(USE_AURA) |
| 2107 void MenuController::OnWindowActivated(aura::Window* active, | 2128 void MenuController::OnWindowActivated(aura::Window* active, |
| 2108 aura::Window* old_active) { | 2129 aura::Window* old_active) { |
| 2109 if (!drag_in_progress_) | 2130 if (!drag_in_progress_) |
| 2110 Cancel(EXIT_ALL); | 2131 Cancel(EXIT_ALL); |
| 2111 } | 2132 } |
| 2112 #endif | 2133 #endif |
| 2113 | 2134 |
| 2114 } // namespace views | 2135 } // namespace views |
| OLD | NEW |