summaryrefslogtreecommitdiff
path: root/chromium/ui/views/controls/menu/menu_controller.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ui/views/controls/menu/menu_controller.cc')
-rw-r--r--chromium/ui/views/controls/menu/menu_controller.cc155
1 files changed, 98 insertions, 57 deletions
diff --git a/chromium/ui/views/controls/menu/menu_controller.cc b/chromium/ui/views/controls/menu/menu_controller.cc
index ca6146dd053..3beb5516e12 100644
--- a/chromium/ui/views/controls/menu/menu_controller.cc
+++ b/chromium/ui/views/controls/menu/menu_controller.cc
@@ -17,7 +17,8 @@
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "build/build_config.h"
-#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
+#include "build/chromeos_buildflags.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/display/screen.h"
#include "ui/events/event.h"
@@ -361,7 +362,7 @@ class MenuController::MenuScrollTask {
}
DCHECK(part.submenu);
SubmenuView* new_menu = part.submenu;
- bool new_is_up = (part.type == MenuController::MenuPart::SCROLL_UP);
+ bool new_is_up = (part.type == MenuController::MenuPart::Type::kScrollUp);
if (new_menu == submenu_ && is_scrolling_up_ == new_is_up)
return;
@@ -707,7 +708,7 @@ bool MenuController::OnMouseDragged(SubmenuView* source,
return true;
}
MenuItemView* mouse_menu = nullptr;
- if (part.type == MenuPart::MENU_ITEM) {
+ if (part.type == MenuPart::Type::kMenuItem) {
// If there is no menu target, but a submenu target, then we are interacting
// with an empty menu item within a submenu. These cannot become selection
// targets for mouse interaction, so do not attempt to update selection.
@@ -718,7 +719,7 @@ bool MenuController::OnMouseDragged(SubmenuView* source,
mouse_menu = part.menu;
SetSelection(part.menu ? part.menu : state_.item, SELECTION_OPEN_SUBMENU);
}
- } else if (part.type == MenuPart::NONE) {
+ } else if (part.type == MenuPart::Type::kNone) {
// If there is a sibling menu, show it. Otherwise, if the user has selected
// a menu item with no accompanying sibling menu or submenu, move selection
// back to the parent menu item.
@@ -761,7 +762,7 @@ void MenuController::OnMouseReleased(SubmenuView* source,
DCHECK(state_.item);
possible_drag_ = false;
MenuPart part = GetMenuPart(source, event.location());
- if (event.IsRightMouseButton() && part.type == MenuPart::MENU_ITEM) {
+ if (event.IsRightMouseButton() && part.type == MenuPart::Type::kMenuItem) {
MenuItemView* menu = part.menu;
// |menu| is null means this event is from an empty menu or a separator.
// If it is from an empty menu, use parent context menu instead of that.
@@ -817,7 +818,7 @@ void MenuController::OnMouseReleased(SubmenuView* source,
Accept(part.menu, event.flags());
return;
}
- } else if (part.type == MenuPart::MENU_ITEM) {
+ } else if (part.type == MenuPart::Type::kMenuItem) {
// User either clicked on empty space, or a menu that has children.
SetSelection(part.menu ? part.menu : state_.item,
SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
@@ -913,7 +914,7 @@ void MenuController::OnGestureEvent(SubmenuView* source,
SetSelectionOnPointerDown(source, event);
event->StopPropagation();
} else if (event->type() == ui::ET_GESTURE_LONG_PRESS) {
- if (part.type == MenuPart::MENU_ITEM && part.menu) {
+ if (part.type == MenuPart::Type::kMenuItem && part.menu) {
gfx::Point screen_location(event->location());
View::ConvertPointToScreen(source->GetScrollViewContainer(),
&screen_location);
@@ -928,14 +929,14 @@ void MenuController::OnGestureEvent(SubmenuView* source,
Accept(part.menu, event->flags());
}
event->StopPropagation();
- } else if (part.type == MenuPart::MENU_ITEM) {
+ } else if (part.type == MenuPart::Type::kMenuItem) {
// User either tapped on empty space, or a menu that has children.
SetSelection(part.menu ? part.menu : state_.item,
SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
event->StopPropagation();
}
} else if (event->type() == ui::ET_GESTURE_TAP_CANCEL && part.menu &&
- part.type == MenuPart::MENU_ITEM) {
+ part.type == MenuPart::Type::kMenuItem) {
// Move the selection to the parent menu so that the selection in the
// current menu is unset. Make sure the submenu remains open by sending the
// appropriate SetSelectionTypes flags.
@@ -959,7 +960,7 @@ void MenuController::OnTouchEvent(SubmenuView* source, ui::TouchEvent* event) {
if (event->type() == ui::ET_TOUCH_PRESSED) {
MenuPart part = GetMenuPart(source, event->location());
- if (part.type == MenuPart::NONE) {
+ if (part.type == MenuPart::Type::kNone) {
RepostEventAndCancel(source, event);
event->SetHandled();
}
@@ -1059,8 +1060,9 @@ int MenuController::OnDragUpdated(SubmenuView* source,
query_menu_item = menu_item->GetParentMenuItem();
drop_position = MenuDelegate::DropPosition::kOn;
}
- drop_operation = menu_item->GetDelegate()->GetDropOperation(
- query_menu_item, event, &drop_position);
+ drop_operation =
+ static_cast<int>(menu_item->GetDelegate()->GetDropOperation(
+ query_menu_item, event, &drop_position));
// If the menu has a submenu, schedule the submenu to open.
SetSelection(menu_item, menu_item->HasSubmenu() ? SELECTION_OPEN_SUBMENU
@@ -1086,8 +1088,9 @@ void MenuController::OnDragExited(SubmenuView* source) {
}
}
-int MenuController::OnPerformDrop(SubmenuView* source,
- const ui::DropTargetEvent& event) {
+ui::mojom::DragOperation MenuController::OnPerformDrop(
+ SubmenuView* source,
+ const ui::DropTargetEvent& event) {
DCHECK(drop_target_);
// NOTE: the delegate may delete us after invoking OnPerformDrop, as such
// we don't call cancel here.
@@ -1125,7 +1128,7 @@ int MenuController::OnPerformDrop(SubmenuView* source,
void MenuController::OnDragEnteredScrollButton(SubmenuView* source,
bool is_up) {
MenuPart part;
- part.type = is_up ? MenuPart::SCROLL_UP : MenuPart::SCROLL_DOWN;
+ part.type = is_up ? MenuPart::Type::kScrollUp : MenuPart::Type::kScrollDown;
part.submenu = source;
UpdateScrolling(part);
@@ -1431,8 +1434,8 @@ void MenuController::SetSelectionOnPointerDown(SubmenuView* source,
(event->flags() & ui::EF_FROM_TOUCH))
return;
- if (part.type == MenuPart::NONE ||
- (part.type == MenuPart::MENU_ITEM && part.menu &&
+ if (part.type == MenuPart::Type::kNone ||
+ (part.type == MenuPart::Type::kMenuItem && part.menu &&
part.menu->GetRootMenuItem() != state_.item->GetRootMenuItem())) {
// Remember the time stamp of the current (press down) event. The owner can
// then use this to figure out if this menu was finished with the same click
@@ -1478,7 +1481,8 @@ void MenuController::StartDrag(SubmenuView* source,
float raster_scale = ScaleFactorForDragFromWidget(source->GetWidget());
gfx::Canvas canvas(item->size(), raster_scale, false /* opaque */);
item->PaintButton(&canvas, MenuItemView::PaintButtonMode::kForDrag);
- gfx::ImageSkia image(gfx::ImageSkiaRep(canvas.GetBitmap(), raster_scale));
+ gfx::ImageSkia image =
+ gfx::ImageSkia::CreateFromBitmap(canvas.GetBitmap(), raster_scale);
std::unique_ptr<OSExchangeData> data(std::make_unique<OSExchangeData>());
item->GetDelegate()->WriteDragData(item, data.get());
@@ -1869,11 +1873,11 @@ bool MenuController::IsScrollButtonAt(SubmenuView* source,
scroll_view->GetEventHandlerForPoint(gfx::Point(x, y));
if (child_under_mouse && child_under_mouse->GetEnabled()) {
if (child_under_mouse == scroll_view->scroll_up_button()) {
- *part = MenuPart::SCROLL_UP;
+ *part = MenuPart::Type::kScrollUp;
return true;
}
if (child_under_mouse == scroll_view->scroll_down_button()) {
- *part = MenuPart::SCROLL_DOWN;
+ *part = MenuPart::Type::kScrollDown;
return true;
}
}
@@ -1928,7 +1932,7 @@ bool MenuController::GetMenuPartByScreenCoordinateImpl(
gfx::Point menu_loc = screen_loc;
View::ConvertPointFromScreen(menu, &menu_loc);
part->menu = GetMenuItemAt(menu, menu_loc.x(), menu_loc.y());
- part->type = MenuPart::MENU_ITEM;
+ part->type = MenuPart::Type::kMenuItem;
part->submenu = menu;
part->should_submenu_show =
part->submenu && part->menu &&
@@ -2124,7 +2128,7 @@ void MenuController::OpenMenuImpl(MenuItemView* item, bool show) {
View::ConvertPointFromScreen(item->submenu_->GetWidget()->GetRootView(),
&mouse_pos);
MenuPart part_under_mouse = GetMenuPart(item->submenu_, mouse_pos);
- if (part_under_mouse.type != MenuPart::NONE)
+ if (part_under_mouse.type != MenuPart::Type::kNone)
menu_open_mouse_loc_ = mouse_pos;
}
@@ -2378,7 +2382,7 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
bool* is_leading) {
DCHECK(item);
- // Assume we can honor prefer_leading.
+ // Assume we can honor `prefer_leading`.
*is_leading = prefer_leading;
SubmenuView* submenu = item->GetSubmenu();
@@ -2427,26 +2431,58 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
menu_size.set_width(std::min(
menu_size.width(), item->GetDelegate()->GetMaxWidthForMenu(item)));
- if (state_.anchor == MenuAnchorPosition::kBubbleAbove) {
- // Align the left edges of the menu and anchor, and the bottom of the menu
- // with the top of the anchor.
+ if (state_.anchor == MenuAnchorPosition::kBubbleAbove ||
+ state_.anchor == MenuAnchorPosition::kBubbleBelow) {
+ // Align the left edges of the menu and anchor.
x = std::max(monitor_bounds.x(),
anchor_bounds.x() - border_and_shadow_insets.left());
- y = anchor_bounds.y() - menu_size.height() +
- border_and_shadow_insets.bottom() -
- menu_config.touchable_anchor_offset;
-
- // Align the right of the menu with the right of the anchor.
if (x + menu_size.width() > monitor_bounds.right()) {
+ // Align the right of the menu with the right of the anchor.
x = anchor_bounds.right() - menu_size.width() +
border_and_shadow_insets.right();
}
- // Align the top of the menu with the bottom of the anchor.
- if (y < monitor_bounds.y()) {
- y = anchor_bounds.bottom() - border_and_shadow_insets.top() +
- menu_config.touchable_anchor_offset;
+
+ const int y_for_menu_below = anchor_bounds.bottom() -
+ border_and_shadow_insets.top() +
+ menu_config.touchable_anchor_offset;
+ const int y_for_menu_above = anchor_bounds.y() - menu_size.height() +
+ border_and_shadow_insets.bottom() -
+ menu_config.touchable_anchor_offset;
+ if (state_.anchor == MenuAnchorPosition::kBubbleAbove) {
+ y = y_for_menu_above;
+ item->set_actual_menu_position(MenuPosition::kAboveBounds);
+ if (y < monitor_bounds.y()) {
+ y = y_for_menu_below;
+ item->set_actual_menu_position(MenuPosition::kBelowBounds);
+ }
+ } else if (state_.anchor == MenuAnchorPosition::kBubbleBelow) {
+ // Respect the previous MenuPosition. The menu contents could change
+ // while the menu is shown, the menu position should not change.
+ const bool able_to_show_menu_below =
+ (y_for_menu_below + menu_size.height() <= monitor_bounds.bottom());
+ const bool able_to_show_menu_above =
+ y_for_menu_above >= monitor_bounds.y();
+ if (item->actual_menu_position() == MenuPosition::kBelowBounds &&
+ able_to_show_menu_below) {
+ y = y_for_menu_below;
+ } else if (item->actual_menu_position() == MenuPosition::kAboveBounds &&
+ able_to_show_menu_above) {
+ y = y_for_menu_above;
+ } else if (able_to_show_menu_below) {
+ y = y_for_menu_below;
+ item->set_actual_menu_position(MenuPosition::kBelowBounds);
+ } else if (able_to_show_menu_above) {
+ // No room below, but there is room above. Show above the anchor.
+ // Align the bottom of the menu with the bottom of the anchor.
+ y = y_for_menu_above;
+ item->set_actual_menu_position(MenuPosition::kAboveBounds);
+ } else {
+ // No room above or below. Show as low as possible. Align the bottom
+ // of the menu with the bottom of the screen.
+ y = monitor_bounds.bottom() - menu_size.height();
+ item->set_actual_menu_position(MenuPosition::kBestFit);
+ }
}
- item->set_actual_menu_position(MenuPosition::kAboveBounds);
} else if (state_.anchor == MenuAnchorPosition::kBubbleLeft ||
state_.anchor == MenuAnchorPosition::kBubbleRight) {
if (state_.anchor == MenuAnchorPosition::kBubbleLeft) {
@@ -2473,32 +2509,34 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
}
}
- const int y_below = anchor_bounds.y() - border_and_shadow_insets.top();
- const int y_above = anchor_bounds.bottom() - menu_size.height() +
- border_and_shadow_insets.bottom();
+ const int y_for_menu_below =
+ anchor_bounds.y() - border_and_shadow_insets.top();
+ const int y_for_menu_above = anchor_bounds.bottom() - menu_size.height() +
+ border_and_shadow_insets.bottom();
- const bool able_to_show_below =
- (y_below + menu_size.height() <= monitor_bounds.bottom());
- const bool able_to_show_above = (y_above >= monitor_bounds.y());
+ const bool able_to_show_menu_below =
+ (y_for_menu_below + menu_size.height() <= monitor_bounds.bottom());
+ const bool able_to_show_menu_above =
+ (y_for_menu_above >= monitor_bounds.y());
// Respect the actual menu position calculated earlier if possible, to
// prevent changing positions during menu size updates.
if (item->actual_menu_position() == MenuPosition::kBelowBounds &&
- able_to_show_below) {
- y = y_below;
+ able_to_show_menu_below) {
+ y = y_for_menu_below;
} else if (item->actual_menu_position() == MenuPosition::kAboveBounds &&
- able_to_show_above) {
- y = y_above;
- } else if (able_to_show_below) {
+ able_to_show_menu_above) {
+ y = y_for_menu_above;
+ } else if (able_to_show_menu_below) {
// Show below the anchor. Align the top of the menu with the top of the
// anchor.
- y = y_below;
+ y = y_for_menu_below;
item->set_actual_menu_position(MenuPosition::kBelowBounds);
- } else if (able_to_show_above) {
+ } else if (able_to_show_menu_above) {
// No room below, but there is room above. Show above the anchor. Align
// the bottom of the menu with the bottom of the anchor.
- y = y_above;
+ y = y_for_menu_above;
item->set_actual_menu_position(MenuPosition::kAboveBounds);
} else {
// No room above or below. Show as low as possible. Align the bottom of
@@ -2533,7 +2571,7 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
const bool create_on_right = prefer_leading != layout_is_rtl;
const int width_with_right_inset =
- menu_config.touchable_menu_width + border_and_shadow_insets.right();
+ menu_config.touchable_menu_min_width + border_and_shadow_insets.right();
const int x_max = monitor_bounds.right() - width_with_right_inset;
const int x_left = item_bounds.x() - width_with_right_inset;
const int x_right = item_bounds.right() - border_and_shadow_insets.left();
@@ -2692,7 +2730,7 @@ MenuItemView* MenuController::FindNextSelectableMenuItem(
if (index == stop_index && !include_all_items)
return nullptr;
MenuItemView* child = parent->GetSubmenu()->GetMenuItemAt(index);
- if (child->GetVisible() && child->GetEnabled())
+ if (child->IsTraversableByKeyboard())
return child;
} while (index != stop_index);
return nullptr;
@@ -2807,7 +2845,9 @@ void MenuController::SelectByChar(base::char16 character) {
if (IsReadonlyCombobox() ||
MenuConfig::instance().all_menus_use_prefix_selection) {
- item->GetSubmenu()->GetPrefixSelector()->InsertText(char_array);
+ item->GetSubmenu()->GetPrefixSelector()->InsertText(
+ char_array,
+ ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
} else {
// If no mnemonics found, look at first character of titles.
details = FindChildForMnemonic(item, key, &TitleMatchesMnemonic);
@@ -2823,7 +2863,7 @@ void MenuController::RepostEventAndCancel(SubmenuView* source,
gfx::Point screen_loc(event->location());
View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc);
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
gfx::NativeView native_view = source->GetWidget()->GetNativeView();
gfx::NativeWindow window = nullptr;
if (native_view) {
@@ -2862,7 +2902,7 @@ void MenuController::RepostEventAndCancel(SubmenuView* source,
// of the menus from the last run.
MenuPart last_part = GetMenuPartByScreenCoordinateUsingMenu(
menu_stack_.back().first.item, screen_loc);
- if (last_part.type != MenuPart::NONE)
+ if (last_part.type != MenuPart::Type::kNone)
exit_type = ExitType::kOutermost;
}
#if defined(OS_APPLE)
@@ -3109,10 +3149,11 @@ void MenuController::HandleMouseLocation(SubmenuView* source,
if (for_drop_)
return;
- if (part.type == MenuPart::NONE && ShowSiblingMenu(source, mouse_location))
+ if (part.type == MenuPart::Type::kNone &&
+ ShowSiblingMenu(source, mouse_location))
return;
- if (part.type == MenuPart::MENU_ITEM && part.menu) {
+ if (part.type == MenuPart::Type::kMenuItem && part.menu) {
SetSelection(part.menu, part.should_submenu_show ? SELECTION_OPEN_SUBMENU
: SELECTION_DEFAULT);
} else if (!part.is_scroll() && pending_state_.item &&