Commit 6f92518b authored by Peter Boström's avatar Peter Boström Committed by Commit Bot

Use inset anchor bounds for toolbar buttons

Adds a Views::GetAnchorBoundsInScreen() method. This defaults to
GetBoundsInScreen() but can be overridden for views whose visual
bounds differ from their actual bounds. This is the case for toolbar
buttons on Touch (that provide larger hit targets than their visual
size).

This method is then used for the menus spawned by AppMenuButton and
ToolbarButton as well as BubbleDialogDelegate which allows these
specific menus and BubbleDialogDelegates in general to be better
aligned visually to their anchors.

Bug: chromium:800372, chromium:869928
Change-Id: I9c516d8a7ecb6c922e347d4db61ce1db72c71be7
Reviewed-on: https://chromium-review.googlesource.com/1152525
Commit-Queue: Peter Boström <pbos@chromium.org>
Reviewed-by: default avatarTrent Apted <tapted@chromium.org>
Reviewed-by: default avatarBret Sepulveda <bsep@chromium.org>
Cr-Commit-Position: refs/heads/master@{#579861}
parent 68f2ed57
...@@ -827,11 +827,9 @@ void AppMenu::Init(ui::MenuModel* model) { ...@@ -827,11 +827,9 @@ void AppMenu::Init(ui::MenuModel* model) {
} }
void AppMenu::RunMenu(views::MenuButton* host) { void AppMenu::RunMenu(views::MenuButton* host) {
gfx::Point screen_loc;
views::View::ConvertPointToScreen(host, &screen_loc);
gfx::Rect bounds(screen_loc, host->size());
base::RecordAction(UserMetricsAction("ShowAppMenu")); base::RecordAction(UserMetricsAction("ShowAppMenu"));
menu_runner_->RunMenuAt(host->GetWidget(), host, bounds, menu_runner_->RunMenuAt(host->GetWidget(), host,
host->GetAnchorBoundsInScreen(),
views::MENU_ANCHOR_TOPRIGHT, ui::MENU_SOURCE_NONE); views::MENU_ANCHOR_TOPRIGHT, ui::MENU_SOURCE_NONE);
} }
......
...@@ -291,6 +291,22 @@ void BrowserAppMenuButton::OnBoundsChanged(const gfx::Rect& previous_bounds) { ...@@ -291,6 +291,22 @@ void BrowserAppMenuButton::OnBoundsChanged(const gfx::Rect& previous_bounds) {
AppMenuButton::OnBoundsChanged(previous_bounds); AppMenuButton::OnBoundsChanged(previous_bounds);
} }
gfx::Rect BrowserAppMenuButton::GetAnchorBoundsInScreen() const {
gfx::Rect bounds = GetBoundsInScreen();
gfx::Insets insets =
GetInkDropInsets(this, gfx::Insets(0, 0, 0, margin_trailing_));
// If the button is extended, don't inset the trailing edge. The anchored menu
// should extend to the screen edge as well so the menu is easier to hit
// (Fitts's law).
// TODO(pbos): Make sure the button is aware of that it is being extended or
// not (margin_trailing_ cannot be used as it can be 0 in fullscreen on
// Touch). When this is implemented, use 0 as a replacement for
// margin_trailing_ in fullscreen only. Always keep the rest.
insets.Set(insets.top(), 0, insets.bottom(), 0);
bounds.Inset(insets);
return bounds;
}
gfx::Rect BrowserAppMenuButton::GetThemePaintRect() const { gfx::Rect BrowserAppMenuButton::GetThemePaintRect() const {
gfx::Rect rect(MenuButton::GetThemePaintRect()); gfx::Rect rect(MenuButton::GetThemePaintRect());
rect.Inset(0, 0, margin_trailing_, 0); rect.Inset(0, 0, margin_trailing_, 0);
......
...@@ -47,6 +47,7 @@ class BrowserAppMenuButton : public AppMenuButton, ...@@ -47,6 +47,7 @@ class BrowserAppMenuButton : public AppMenuButton,
// views::MenuButton: // views::MenuButton:
void OnBoundsChanged(const gfx::Rect& previous_bounds) override; void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
gfx::Rect GetAnchorBoundsInScreen() const override;
gfx::Size CalculatePreferredSize() const override; gfx::Size CalculatePreferredSize() const override;
void Layout() override; void Layout() override;
void OnThemeChanged() override; void OnThemeChanged() override;
......
...@@ -98,6 +98,12 @@ void ToolbarActionView::OnBoundsChanged(const gfx::Rect& previous_bounds) { ...@@ -98,6 +98,12 @@ void ToolbarActionView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
MenuButton::OnBoundsChanged(previous_bounds); MenuButton::OnBoundsChanged(previous_bounds);
} }
gfx::Rect ToolbarActionView::GetAnchorBoundsInScreen() const {
gfx::Rect bounds = GetBoundsInScreen();
bounds.Inset(GetInkDropInsets(this, gfx::Insets()));
return bounds;
}
void ToolbarActionView::GetAccessibleNodeData(ui::AXNodeData* node_data) { void ToolbarActionView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
views::MenuButton::GetAccessibleNodeData(node_data); views::MenuButton::GetAccessibleNodeData(node_data);
node_data->role = ax::mojom::Role::kButton; node_data->role = ax::mojom::Role::kButton;
......
...@@ -63,6 +63,7 @@ class ToolbarActionView : public views::MenuButton, ...@@ -63,6 +63,7 @@ class ToolbarActionView : public views::MenuButton,
// views::MenuButton: // views::MenuButton:
void OnBoundsChanged(const gfx::Rect& previous_bounds) override; void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
gfx::Rect GetAnchorBoundsInScreen() const override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
std::unique_ptr<views::LabelButtonBorder> CreateDefaultBorder() std::unique_ptr<views::LabelButtonBorder> CreateDefaultBorder()
const override; const override;
......
...@@ -127,6 +127,22 @@ void ToolbarButton::OnBoundsChanged(const gfx::Rect& previous_bounds) { ...@@ -127,6 +127,22 @@ void ToolbarButton::OnBoundsChanged(const gfx::Rect& previous_bounds) {
LabelButton::OnBoundsChanged(previous_bounds); LabelButton::OnBoundsChanged(previous_bounds);
} }
gfx::Rect ToolbarButton::GetAnchorBoundsInScreen() const {
gfx::Rect bounds = GetBoundsInScreen();
gfx::Insets insets =
GetInkDropInsets(this, gfx::Insets(0, leading_margin_, 0, 0));
// If the button is extended, don't inset the leading edge. The anchored menu
// should extend to the screen edge as well so the menu is easier to hit
// (Fitts's law).
// TODO(pbos): Make sure the button is aware of that it is being extended or
// not (leading_margin_ cannot be used as it can be 0 in fullscreen on Touch).
// When this is implemented, use 0 as a replacement for leading_margin_ in
// fullscreen only. Always keep the rest.
insets.Set(insets.top(), 0, insets.bottom(), 0);
bounds.Inset(insets);
return bounds;
}
bool ToolbarButton::OnMousePressed(const ui::MouseEvent& event) { bool ToolbarButton::OnMousePressed(const ui::MouseEvent& event) {
if (IsTriggerableEvent(event) && enabled() && ShouldShowMenu() && if (IsTriggerableEvent(event) && enabled() && ShouldShowMenu() &&
HitTestPoint(event.location())) { HitTestPoint(event.location())) {
...@@ -260,16 +276,7 @@ void ToolbarButton::ShowDropDownMenu(ui::MenuSourceType source_type) { ...@@ -260,16 +276,7 @@ void ToolbarButton::ShowDropDownMenu(ui::MenuSourceType source_type) {
if (!ShouldShowMenu()) if (!ShouldShowMenu())
return; return;
gfx::Rect lb = GetLocalBounds(); gfx::Rect menu_anchor_bounds = GetAnchorBoundsInScreen();
// Both the menu position and the menu anchor type change if the UI layout
// is right-to-left.
gfx::Point menu_position(lb.origin());
menu_position.Offset(0, lb.height() - 1);
if (base::i18n::IsRTL())
menu_position.Offset(lb.width() - 1, 0);
View::ConvertPointToScreen(this, &menu_position);
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
// A window won't overlap between displays on ChromeOS. // A window won't overlap between displays on ChromeOS.
...@@ -287,8 +294,8 @@ void ToolbarButton::ShowDropDownMenu(ui::MenuSourceType source_type) { ...@@ -287,8 +294,8 @@ void ToolbarButton::ShowDropDownMenu(ui::MenuSourceType source_type) {
screen->GetDisplayNearestPoint(screen->GetCursorScreenPoint()); screen->GetDisplayNearestPoint(screen->GetCursorScreenPoint());
int left_bound = display.bounds().x(); int left_bound = display.bounds().x();
#endif #endif
if (menu_position.x() < left_bound) if (menu_anchor_bounds.x() < left_bound)
menu_position.set_x(left_bound); menu_anchor_bounds.set_x(left_bound);
// Make the button look depressed while the menu is open. // Make the button look depressed while the menu is open.
SetState(STATE_PRESSED); SetState(STATE_PRESSED);
...@@ -312,8 +319,7 @@ void ToolbarButton::ShowDropDownMenu(ui::MenuSourceType source_type) { ...@@ -312,8 +319,7 @@ void ToolbarButton::ShowDropDownMenu(ui::MenuSourceType source_type) {
menu_model_adapter_->set_triggerable_event_flags(triggerable_event_flags()); menu_model_adapter_->set_triggerable_event_flags(triggerable_event_flags());
menu_runner_ = std::make_unique<views::MenuRunner>( menu_runner_ = std::make_unique<views::MenuRunner>(
menu_model_adapter_->CreateMenu(), views::MenuRunner::HAS_MNEMONICS); menu_model_adapter_->CreateMenu(), views::MenuRunner::HAS_MNEMONICS);
menu_runner_->RunMenuAt(GetWidget(), nullptr, menu_runner_->RunMenuAt(GetWidget(), nullptr, menu_anchor_bounds,
gfx::Rect(menu_position, gfx::Size(0, 0)),
views::MENU_ANCHOR_TOPLEFT, source_type); views::MENU_ANCHOR_TOPLEFT, source_type);
} }
......
...@@ -66,6 +66,7 @@ class ToolbarButton : public views::LabelButton, ...@@ -66,6 +66,7 @@ class ToolbarButton : public views::LabelButton,
// views::LabelButton: // views::LabelButton:
void OnBoundsChanged(const gfx::Rect& previous_bounds) override; void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
gfx::Rect GetAnchorBoundsInScreen() const override;
bool OnMousePressed(const ui::MouseEvent& event) override; bool OnMousePressed(const ui::MouseEvent& event) override;
bool OnMouseDragged(const ui::MouseEvent& event) override; bool OnMouseDragged(const ui::MouseEvent& event) override;
void OnMouseReleased(const ui::MouseEvent& event) override; void OnMouseReleased(const ui::MouseEvent& event) override;
......
...@@ -206,7 +206,7 @@ gfx::Rect BubbleDialogDelegateView::GetAnchorRect() const { ...@@ -206,7 +206,7 @@ gfx::Rect BubbleDialogDelegateView::GetAnchorRect() const {
if (!GetAnchorView()) if (!GetAnchorView())
return anchor_rect_; return anchor_rect_;
anchor_rect_ = GetAnchorView()->GetBoundsInScreen(); anchor_rect_ = GetAnchorView()->GetAnchorBoundsInScreen();
anchor_rect_.Inset(anchor_view_insets_); anchor_rect_.Inset(anchor_view_insets_);
return anchor_rect_; return anchor_rect_;
} }
......
...@@ -89,6 +89,8 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView, ...@@ -89,6 +89,8 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView,
title_margins_ = title_margins; title_margins_ = title_margins;
} }
// TODO(pbos): Remove by overriding Views::GetAnchorBoundsInScreen() instead.
// See https://crbug.com/869928.
const gfx::Insets& anchor_view_insets() const { return anchor_view_insets_; } const gfx::Insets& anchor_view_insets() const { return anchor_view_insets_; }
void set_anchor_view_insets(const gfx::Insets& i) { anchor_view_insets_ = i; } void set_anchor_view_insets(const gfx::Insets& i) { anchor_view_insets_ = i; }
......
...@@ -419,6 +419,10 @@ gfx::Rect View::GetBoundsInScreen() const { ...@@ -419,6 +419,10 @@ gfx::Rect View::GetBoundsInScreen() const {
return gfx::Rect(origin, size()); return gfx::Rect(origin, size());
} }
gfx::Rect View::GetAnchorBoundsInScreen() const {
return GetBoundsInScreen();
}
gfx::Size View::GetPreferredSize() const { gfx::Size View::GetPreferredSize() const {
if (preferred_size_) if (preferred_size_)
return *preferred_size_; return *preferred_size_;
......
...@@ -363,6 +363,11 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, ...@@ -363,6 +363,11 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Return the bounds of the View in screen coordinate system. // Return the bounds of the View in screen coordinate system.
gfx::Rect GetBoundsInScreen() const; gfx::Rect GetBoundsInScreen() const;
// Return the bounds that an anchored widget should anchor to. These can be
// different from |GetBoundsInScreen()| when a view is larger than its visible
// size, for instance to provide a larger hittable area.
virtual gfx::Rect GetAnchorBoundsInScreen() const;
// Returns the baseline of this view, or -1 if this view has no baseline. The // Returns the baseline of this view, or -1 if this view has no baseline. The
// return value is relative to the preferred height. // return value is relative to the preferred height.
virtual int GetBaseline() const; virtual int GetBaseline() const;
......
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