Commit 319d11d8 authored by Alex Newcomer's avatar Alex Newcomer Committed by Chromium LUCI CQ

[multipaste] Remember old MenuPosition

To prevent multipaste from jumping when deleting items,
remember the old menu position.

Bug: 1165288
Change-Id: I136d43ec9524a6ddcaff1ba371a50e90ce321d0a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2633963
Commit-Queue: Alex Newcomer <newcomer@chromium.org>
Reviewed-by: default avatarPeter Kasting <pkasting@chromium.org>
Cr-Commit-Position: refs/heads/master@{#844314}
parent 87483a42
...@@ -2481,14 +2481,33 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item, ...@@ -2481,14 +2481,33 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
item->set_actual_menu_position(MenuPosition::kBelowBounds); item->set_actual_menu_position(MenuPosition::kBelowBounds);
} }
} else if (state_.anchor == MenuAnchorPosition::kBubbleBelow) { } else if (state_.anchor == MenuAnchorPosition::kBubbleBelow) {
y = y_for_menu_below; // Respect the previous MenuPosition. The menu contents could change
item->set_actual_menu_position(MenuPosition::kBelowBounds); // while the menu is shown, the menu position should not change.
if (y + menu_size.height() > monitor_bounds.bottom()) { 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; y = y_for_menu_above;
item->set_actual_menu_position(MenuPosition::kAboveBounds); 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);
} }
} }
} else if (state_.anchor == MenuAnchorPosition::kBubbleLeft || } else if (state_.anchor == MenuAnchorPosition::kBubbleLeft ||
state_.anchor == MenuAnchorPosition::kBubbleRight) { state_.anchor == MenuAnchorPosition::kBubbleRight) {
if (state_.anchor == MenuAnchorPosition::kBubbleLeft) { if (state_.anchor == MenuAnchorPosition::kBubbleLeft) {
......
...@@ -1063,6 +1063,70 @@ TEST_F(MenuControllerTest, VerifyMenuBubblePositionAfterSizeChanges) { ...@@ -1063,6 +1063,70 @@ TEST_F(MenuControllerTest, VerifyMenuBubblePositionAfterSizeChanges) {
} }
} }
// Verifies that the context menu bubble position, MenuPosition::kBubbleBelow,
// does not shift as items are removed. The menu position will shift it items
// are added and the menu no longer fits in its previous position.
TEST_F(MenuControllerTest, VerifyMenuBubbleBelowPositionAfterSizeChanges) {
constexpr gfx::Rect kMonitorBounds(0, 0, 500, 500);
constexpr gfx::Size kMenuSize(100, 200);
const gfx::Insets border_and_shadow_insets =
BubbleBorder::GetBorderAndShadowInsets(
MenuConfig::instance().touchable_menu_shadow_elevation);
// Calculate the suitable anchor point to ensure that if the menu shows below
// the anchor point, the bottom of the menu should be one pixel off the
// bottom of the display. It means that there is insufficient space for the
// menu below the anchor.
const gfx::Point anchor_point(kMonitorBounds.width() / 2,
kMonitorBounds.bottom() + 1 -
kMenuSize.height() +
border_and_shadow_insets.top());
MenuBoundsOptions options;
options.menu_anchor = MenuAnchorPosition::kBubbleBelow;
options.monitor_bounds = kMonitorBounds;
options.anchor_bounds = gfx::Rect(anchor_point, gfx::Size());
// Case 1: There is insufficient space for the menu below `anchor_point` and
// there is no cached menu position. The menu should show above the anchor.
{
options.menu_size = kMenuSize;
ASSERT_GT(options.anchor_bounds.y() - border_and_shadow_insets.top() +
kMenuSize.height(),
kMonitorBounds.bottom());
CalculateBubbleMenuBounds(options);
EXPECT_EQ(MenuItemView::MenuPosition::kAboveBounds,
menu_item()->ActualMenuPosition());
}
// Case 2: There is insufficient space for the menu below `anchor_point`. The
// cached position is below the anchor. The menu should show above the anchor
// point.
{
options.menu_position = MenuItemView::MenuPosition::kBelowBounds;
CalculateBubbleMenuBounds(options);
EXPECT_EQ(MenuItemView::MenuPosition::kAboveBounds,
menu_item()->ActualMenuPosition());
}
// Case 3: There is enough space for the menu below `anchor_point`. The cached
// menu position is above the anchor. The menu should show above the anchor.
{
// Shrink the menu size. Verify that there is enough space below the anchor
// point now.
constexpr gfx::Size kUpdatedSize(kMenuSize.width(), kMenuSize.height() / 2);
options.menu_size = kUpdatedSize;
EXPECT_LE(options.anchor_bounds.y() - border_and_shadow_insets.top() +
kUpdatedSize.height(),
kMonitorBounds.bottom());
options.menu_position = MenuItemView::MenuPosition::kAboveBounds;
CalculateBubbleMenuBounds(options);
EXPECT_EQ(MenuItemView::MenuPosition::kAboveBounds,
menu_item()->ActualMenuPosition());
}
}
// Tests that opening the menu and pressing 'Home' selects the first menu item. // Tests that opening the menu and pressing 'Home' selects the first menu item.
TEST_F(MenuControllerTest, FirstSelectedItem) { TEST_F(MenuControllerTest, FirstSelectedItem) {
SetPendingStateItem(menu_item()->GetSubmenu()->GetMenuItemAt(0)); SetPendingStateItem(menu_item()->GetSubmenu()->GetMenuItemAt(0));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment