Commit fae876ef authored by David Jacobo's avatar David Jacobo Committed by Commit Bot

Reland: Create TouchSelectionMenuViews to separate Menu

views::TouchSelectionMenuRunnerViews::Menu should be better by
separating it on their own class, this CL introduces
TouchSelectionMenuViews.

Bug: None
Test: Build.
Change-Id: Ic9e8e258c41d2686746ff9b7d73fef1826424851
Reviewed-on: https://chromium-review.googlesource.com/c/1328281Reviewed-by: default avatarMohsen Izadi <mohsen@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Commit-Queue: David Jacobo <djacobo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#606999}
parent ab01537c
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include "components/arc/arc_service_manager.h" #include "components/arc/arc_service_manager.h"
#include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_operations.h" #include "ui/gfx/image/image_skia_operations.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/label_button.h"
namespace { namespace {
...@@ -24,7 +26,7 @@ TouchSelectionMenuChromeOS::TouchSelectionMenuChromeOS( ...@@ -24,7 +26,7 @@ TouchSelectionMenuChromeOS::TouchSelectionMenuChromeOS(
ui::TouchSelectionMenuClient* client, ui::TouchSelectionMenuClient* client,
aura::Window* context, aura::Window* context,
arc::mojom::TextSelectionActionPtr action) arc::mojom::TextSelectionActionPtr action)
: views::TouchSelectionMenuRunnerViews::Menu(owner, client, context), : views::TouchSelectionMenuViews(owner, client, context),
action_(std::move(action)) {} action_(std::move(action)) {}
void TouchSelectionMenuChromeOS::SetActionsForTesting( void TouchSelectionMenuChromeOS::SetActionsForTesting(
...@@ -58,13 +60,13 @@ void TouchSelectionMenuChromeOS::CreateButtons() { ...@@ -58,13 +60,13 @@ void TouchSelectionMenuChromeOS::CreateButtons() {
AddChildView(button); AddChildView(button);
} }
views::TouchSelectionMenuRunnerViews::Menu::CreateButtons(); views::TouchSelectionMenuViews::CreateButtons();
} }
void TouchSelectionMenuChromeOS::ButtonPressed(views::Button* sender, void TouchSelectionMenuChromeOS::ButtonPressed(views::Button* sender,
const ui::Event& event) { const ui::Event& event) {
if (sender->tag() != kSmartTextSelectionActionTag) { if (sender->tag() != kSmartTextSelectionActionTag) {
views::TouchSelectionMenuRunnerViews::Menu::ButtonPressed(sender, event); views::TouchSelectionMenuViews::ButtonPressed(sender, event);
return; return;
} }
......
...@@ -8,13 +8,16 @@ ...@@ -8,13 +8,16 @@
#include <vector> #include <vector>
#include "components/arc/common/intent_helper.mojom.h" #include "components/arc/common/intent_helper.mojom.h"
#include "ui/views/touchui/touch_selection_menu_runner_views.h" #include "ui/views/touchui/touch_selection_menu_views.h"
namespace views {
class TouchSelectionMenuRunnerViews;
}
// A ChromeOS specific subclass of the the bubble menu. It provides an // A ChromeOS specific subclass of the the bubble menu. It provides an
// additional button for a Smart Text Selection action based on the current // additional button for a Smart Text Selection action based on the current
// user's text selection. // user's text selection.
class TouchSelectionMenuChromeOS class TouchSelectionMenuChromeOS : public views::TouchSelectionMenuViews {
: public views::TouchSelectionMenuRunnerViews::Menu {
public: public:
// Tag used to mark added actions/buttons as generated by the smart text // Tag used to mark added actions/buttons as generated by the smart text
// selection feature. // selection feature.
...@@ -29,7 +32,7 @@ class TouchSelectionMenuChromeOS ...@@ -29,7 +32,7 @@ class TouchSelectionMenuChromeOS
std::vector<arc::mojom::TextSelectionActionPtr> actions); std::vector<arc::mojom::TextSelectionActionPtr> actions);
protected: protected:
// views:TouchSelectionMenuRunnerViews::Menu // views:TouchSelectionMenuViews.
void CreateButtons() override; void CreateButtons() override;
void ButtonPressed(views::Button* sender, const ui::Event& event) override; void ButtonPressed(views::Button* sender, const ui::Event& event) override;
......
...@@ -612,6 +612,7 @@ jumbo_component("views") { ...@@ -612,6 +612,7 @@ jumbo_component("views") {
"event_monitor_aura.h", "event_monitor_aura.h",
"touchui/touch_selection_controller_impl.h", "touchui/touch_selection_controller_impl.h",
"touchui/touch_selection_menu_runner_views.h", "touchui/touch_selection_menu_runner_views.h",
"touchui/touch_selection_menu_views.h",
"view_constants_aura.h", "view_constants_aura.h",
"widget/desktop_aura/desktop_capture_client.h", "widget/desktop_aura/desktop_capture_client.h",
"widget/desktop_aura/desktop_drop_target_win.h", "widget/desktop_aura/desktop_drop_target_win.h",
...@@ -650,6 +651,7 @@ jumbo_component("views") { ...@@ -650,6 +651,7 @@ jumbo_component("views") {
"native_cursor_aura.cc", "native_cursor_aura.cc",
"touchui/touch_selection_controller_impl.cc", "touchui/touch_selection_controller_impl.cc",
"touchui/touch_selection_menu_runner_views.cc", "touchui/touch_selection_menu_runner_views.cc",
"touchui/touch_selection_menu_views.cc",
"view_constants_aura.cc", "view_constants_aura.cc",
"views_touch_selection_controller_factory_aura.cc", "views_touch_selection_controller_factory_aura.cc",
"widget/desktop_aura/desktop_capture_client.cc", "widget/desktop_aura/desktop_capture_client.cc",
......
...@@ -6,184 +6,13 @@ ...@@ -6,184 +6,13 @@
#include <stddef.h> #include <stddef.h>
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size.h"
#include "ui/gfx/text_utils.h" #include "ui/views/controls/button/label_button.h"
#include "ui/strings/grit/ui_strings.h" #include "ui/views/touchui/touch_selection_menu_views.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/style/typography.h"
namespace views { namespace views {
namespace {
const int kMenuCommands[] = {IDS_APP_CUT, IDS_APP_COPY, IDS_APP_PASTE};
const int kSpacingBetweenButtons = 2;
const int kButtonSeparatorColor = SkColorSetARGB(13, 0, 0, 0);
const int kMenuButtonMinHeight = 38;
const int kMenuButtonMinWidth = 63;
const int kMenuMargin = 1;
const char kEllipsesButtonText[] = "...";
const int kEllipsesButtonTag = -1;
} // namespace
TouchSelectionMenuRunnerViews::Menu::Menu(TouchSelectionMenuRunnerViews* owner,
ui::TouchSelectionMenuClient* client,
aura::Window* context)
: BubbleDialogDelegateView(nullptr, BubbleBorder::BOTTOM_CENTER),
owner_(owner),
client_(client) {
DCHECK(owner_);
DCHECK(client_);
set_shadow(BubbleBorder::SMALL_SHADOW);
set_parent_window(context);
set_margins(gfx::Insets(kMenuMargin, kMenuMargin, kMenuMargin, kMenuMargin));
set_can_activate(false);
set_adjust_if_offscreen(true);
EnableCanvasFlippingForRTLUI(true);
SetLayoutManager(std::make_unique<BoxLayout>(
BoxLayout::kHorizontal, gfx::Insets(), kSpacingBetweenButtons));
}
void TouchSelectionMenuRunnerViews::Menu::ShowMenu(
const gfx::Rect& anchor_rect,
const gfx::Size& handle_image_size) {
CreateButtons();
// After buttons are created, check if there is enough room between handles to
// show the menu and adjust anchor rect properly if needed, just in case the
// menu is needed to be shown under the selection.
gfx::Rect adjusted_anchor_rect(anchor_rect);
int menu_width = GetPreferredSize().width();
// TODO(mfomitchev): This assumes that the handles are center-aligned to the
// |achor_rect| edges, which is not true. We should fix this, perhaps by
// passing down the cumulative width occupied by the handles within
// |anchor_rect| plus the handle image height instead of |handle_image_size|.
// Perhaps we should also allow for some minimum padding.
if (menu_width > anchor_rect.width() - handle_image_size.width())
adjusted_anchor_rect.Inset(0, 0, 0, -handle_image_size.height());
SetAnchorRect(adjusted_anchor_rect);
BubbleDialogDelegateView::CreateBubble(this);
Widget* widget = GetWidget();
gfx::Rect bounds = widget->GetWindowBoundsInScreen();
gfx::Rect work_area = display::Screen::GetScreen()
->GetDisplayNearestPoint(bounds.origin())
.work_area();
if (!work_area.IsEmpty()) {
bounds.AdjustToFit(work_area);
widget->SetBounds(bounds);
}
// Using BubbleDialogDelegateView engages its CreateBubbleWidget() which
// invokes widget->StackAbove(context). That causes the bubble to stack
// _immediately_ above |context|; below any already-existing bubbles. That
// doesn't make sense for a menu, so put it back on top.
widget->StackAtTop();
widget->Show();
}
bool TouchSelectionMenuRunnerViews::Menu::IsMenuAvailable(
const ui::TouchSelectionMenuClient* client) {
DCHECK(client);
for (size_t i = 0; i < arraysize(kMenuCommands); i++) {
if (client->IsCommandIdEnabled(kMenuCommands[i]))
return true;
}
return false;
}
TouchSelectionMenuRunnerViews::Menu::~Menu() {
}
void TouchSelectionMenuRunnerViews::Menu::CreateButtons() {
for (size_t i = 0; i < arraysize(kMenuCommands); i++) {
int command_id = kMenuCommands[i];
if (!client_->IsCommandIdEnabled(command_id))
continue;
Button* button =
CreateButton(l10n_util::GetStringUTF16(command_id), command_id);
AddChildView(button);
}
// Finally, add ellipses button.
AddChildView(
CreateButton(base::UTF8ToUTF16(kEllipsesButtonText), kEllipsesButtonTag));
Layout();
}
LabelButton* TouchSelectionMenuRunnerViews::Menu::CreateButton(
const base::string16& title,
int tag) {
base::string16 label =
gfx::RemoveAcceleratorChar(title, '&', nullptr, nullptr);
LabelButton* button = new LabelButton(this, label, style::CONTEXT_TOUCH_MENU);
button->SetMinSize(gfx::Size(kMenuButtonMinWidth, kMenuButtonMinHeight));
button->SetFocusForPlatform();
button->SetHorizontalAlignment(gfx::ALIGN_CENTER);
button->set_tag(tag);
return button;
}
void TouchSelectionMenuRunnerViews::Menu::CloseMenu() {
DisconnectOwner();
// Closing the widget will self-destroy this object.
Widget* widget = GetWidget();
if (widget && !widget->IsClosed())
widget->Close();
}
void TouchSelectionMenuRunnerViews::Menu::DisconnectOwner() {
DCHECK(owner_);
owner_->menu_ = nullptr;
owner_ = nullptr;
}
void TouchSelectionMenuRunnerViews::Menu::OnPaint(gfx::Canvas* canvas) {
BubbleDialogDelegateView::OnPaint(canvas);
// Draw separator bars.
for (int i = 0; i < child_count() - 1; ++i) {
View* child = child_at(i);
int x = child->bounds().right() + kSpacingBetweenButtons / 2;
canvas->FillRect(gfx::Rect(x, 0, 1, child->height()),
kButtonSeparatorColor);
}
}
void TouchSelectionMenuRunnerViews::Menu::WindowClosing() {
DCHECK(!owner_ || owner_->menu_ == this);
BubbleDialogDelegateView::WindowClosing();
if (owner_)
DisconnectOwner();
}
int TouchSelectionMenuRunnerViews::Menu::GetDialogButtons() const {
return ui::DIALOG_BUTTON_NONE;
}
void TouchSelectionMenuRunnerViews::Menu::ButtonPressed(
Button* sender,
const ui::Event& event) {
CloseMenu();
if (sender->tag() != kEllipsesButtonTag)
client_->ExecuteCommand(sender->tag(), event.flags());
else
client_->RunContextMenu();
}
TouchSelectionMenuRunnerViews::TestApi::TestApi( TouchSelectionMenuRunnerViews::TestApi::TestApi(
TouchSelectionMenuRunnerViews* menu_runner) TouchSelectionMenuRunnerViews* menu_runner)
...@@ -194,17 +23,17 @@ TouchSelectionMenuRunnerViews::TestApi::TestApi( ...@@ -194,17 +23,17 @@ TouchSelectionMenuRunnerViews::TestApi::TestApi(
TouchSelectionMenuRunnerViews::TestApi::~TestApi() {} TouchSelectionMenuRunnerViews::TestApi::~TestApi() {}
gfx::Rect TouchSelectionMenuRunnerViews::TestApi::GetAnchorRect() const { gfx::Rect TouchSelectionMenuRunnerViews::TestApi::GetAnchorRect() const {
TouchSelectionMenuRunnerViews::Menu* menu = menu_runner_->menu_; TouchSelectionMenuViews* menu = menu_runner_->menu_;
return menu ? menu->GetAnchorRect() : gfx::Rect(); return menu ? menu->GetAnchorRect() : gfx::Rect();
} }
LabelButton* TouchSelectionMenuRunnerViews::TestApi::GetFirstButton() const { LabelButton* TouchSelectionMenuRunnerViews::TestApi::GetFirstButton() const {
TouchSelectionMenuRunnerViews::Menu* menu = menu_runner_->menu_; TouchSelectionMenuViews* menu = menu_runner_->menu_;
return menu ? static_cast<LabelButton*>(menu->child_at(0)) : nullptr; return menu ? static_cast<LabelButton*>(menu->child_at(0)) : nullptr;
} }
Widget* TouchSelectionMenuRunnerViews::TestApi::GetWidget() const { Widget* TouchSelectionMenuRunnerViews::TestApi::GetWidget() const {
TouchSelectionMenuRunnerViews::Menu* menu = menu_runner_->menu_; TouchSelectionMenuViews* menu = menu_runner_->menu_;
return menu ? menu->GetWidget() : nullptr; return menu ? menu->GetWidget() : nullptr;
} }
TouchSelectionMenuRunnerViews::TouchSelectionMenuRunnerViews() TouchSelectionMenuRunnerViews::TouchSelectionMenuRunnerViews()
...@@ -216,7 +45,7 @@ TouchSelectionMenuRunnerViews::~TouchSelectionMenuRunnerViews() { ...@@ -216,7 +45,7 @@ TouchSelectionMenuRunnerViews::~TouchSelectionMenuRunnerViews() {
} }
void TouchSelectionMenuRunnerViews::ShowMenu( void TouchSelectionMenuRunnerViews::ShowMenu(
Menu* menu, TouchSelectionMenuViews* menu,
const gfx::Rect& anchor_rect, const gfx::Rect& anchor_rect,
const gfx::Size& handle_image_size) { const gfx::Size& handle_image_size) {
menu_ = menu; menu_ = menu;
...@@ -225,7 +54,7 @@ void TouchSelectionMenuRunnerViews::ShowMenu( ...@@ -225,7 +54,7 @@ void TouchSelectionMenuRunnerViews::ShowMenu(
bool TouchSelectionMenuRunnerViews::IsMenuAvailable( bool TouchSelectionMenuRunnerViews::IsMenuAvailable(
const ui::TouchSelectionMenuClient* client) const { const ui::TouchSelectionMenuClient* client) const {
return TouchSelectionMenuRunnerViews::Menu::IsMenuAvailable(client); return TouchSelectionMenuViews::IsMenuAvailable(client);
} }
void TouchSelectionMenuRunnerViews::OpenMenu( void TouchSelectionMenuRunnerViews::OpenMenu(
...@@ -235,10 +64,10 @@ void TouchSelectionMenuRunnerViews::OpenMenu( ...@@ -235,10 +64,10 @@ void TouchSelectionMenuRunnerViews::OpenMenu(
aura::Window* context) { aura::Window* context) {
CloseMenu(); CloseMenu();
if (!TouchSelectionMenuRunnerViews::Menu::IsMenuAvailable(client)) if (!TouchSelectionMenuViews::IsMenuAvailable(client))
return; return;
menu_ = new Menu(this, client, context); menu_ = new TouchSelectionMenuViews(this, client, context);
menu_->ShowMenu(anchor_rect, handle_image_size); menu_->ShowMenu(anchor_rect, handle_image_size);
} }
......
...@@ -9,21 +9,18 @@ ...@@ -9,21 +9,18 @@
#include "base/macros.h" #include "base/macros.h"
#include "ui/touch_selection/touch_selection_menu_runner.h" #include "ui/touch_selection/touch_selection_menu_runner.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/controls/button/button.h" #include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/views_export.h" #include "ui/views/views_export.h"
namespace views { namespace views {
class LabelButton; class LabelButton;
class TouchSelectionMenuViews;
class Widget; class Widget;
// Views implementation for TouchSelectionMenuRunner. // Views implementation for TouchSelectionMenuRunner.
class VIEWS_EXPORT TouchSelectionMenuRunnerViews class VIEWS_EXPORT TouchSelectionMenuRunnerViews
: public ui::TouchSelectionMenuRunner { : public ui::TouchSelectionMenuRunner {
public: public:
class Menu;
// Test API to access internal state in tests. // Test API to access internal state in tests.
class VIEWS_EXPORT TestApi { class VIEWS_EXPORT TestApi {
public: public:
...@@ -45,7 +42,7 @@ class VIEWS_EXPORT TouchSelectionMenuRunnerViews ...@@ -45,7 +42,7 @@ class VIEWS_EXPORT TouchSelectionMenuRunnerViews
protected: protected:
// Sets the menu as the currently runner menu and shows it. // Sets the menu as the currently runner menu and shows it.
void ShowMenu(Menu* menu, void ShowMenu(TouchSelectionMenuViews* menu,
const gfx::Rect& anchor_rect, const gfx::Rect& anchor_rect,
const gfx::Size& handle_image_size); const gfx::Size& handle_image_size);
...@@ -60,61 +57,15 @@ class VIEWS_EXPORT TouchSelectionMenuRunnerViews ...@@ -60,61 +57,15 @@ class VIEWS_EXPORT TouchSelectionMenuRunnerViews
bool IsRunning() const override; bool IsRunning() const override;
private: private:
friend class TouchSelectionMenuViews;
// A pointer to the currently running menu, or |nullptr| if no menu is // A pointer to the currently running menu, or |nullptr| if no menu is
// running. The menu manages its own lifetime and deletes itself when closed. // running. The menu manages its own lifetime and deletes itself when closed.
Menu* menu_; TouchSelectionMenuViews* menu_;
DISALLOW_COPY_AND_ASSIGN(TouchSelectionMenuRunnerViews); DISALLOW_COPY_AND_ASSIGN(TouchSelectionMenuRunnerViews);
}; };
// A bubble that contains actions available for the selected text. An object of
// this type, as a BubbleDialogDelegateView, manages its own lifetime.
class TouchSelectionMenuRunnerViews::Menu : public BubbleDialogDelegateView,
public ButtonListener {
public:
Menu(TouchSelectionMenuRunnerViews* owner,
ui::TouchSelectionMenuClient* client,
aura::Window* context);
void ShowMenu(const gfx::Rect& anchor_rect,
const gfx::Size& handle_image_size);
// Checks whether there is any command available to show in the menu.
static bool IsMenuAvailable(const ui::TouchSelectionMenuClient* client);
// Closes the menu. This will eventually self-destroy the object.
void CloseMenu();
protected:
~Menu() override;
// Queries the |client_| for what commands to show in the menu and sizes the
// menu appropriately.
virtual void CreateButtons();
// Helper method to create a single button.
LabelButton* CreateButton(const base::string16& title, int tag);
// ButtonListener:
void ButtonPressed(Button* sender, const ui::Event& event) override;
private:
friend class TouchSelectionMenuRunnerViews::TestApi;
// Helper to disconnect this menu object from its owning menu runner.
void DisconnectOwner();
// BubbleDialogDelegateView:
void OnPaint(gfx::Canvas* canvas) override;
void WindowClosing() override;
int GetDialogButtons() const override;
TouchSelectionMenuRunnerViews* owner_;
ui::TouchSelectionMenuClient* const client_;
DISALLOW_COPY_AND_ASSIGN(Menu);
};
} // namespace views } // namespace views
#endif // UI_VIEWS_TOUCHUI_TOUCH_SELECTION_MENU_RUNNER_VIEWS_H_ #endif // UI_VIEWS_TOUCHUI_TOUCH_SELECTION_MENU_RUNNER_VIEWS_H_
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/views/touchui/touch_selection_menu_views.h"
#include <memory>
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/aura/window.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/text_utils.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/touch_selection/touch_selection_menu_runner.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/layout/box_layout.h"
namespace views {
namespace {
constexpr int kMenuCommands[] = {IDS_APP_CUT, IDS_APP_COPY, IDS_APP_PASTE};
constexpr int kSpacingBetweenButtons = 2;
constexpr int kButtonSeparatorColor = SkColorSetARGB(13, 0, 0, 0);
constexpr int kMenuButtonMinHeight = 38;
constexpr int kMenuButtonMinWidth = 63;
constexpr int kMenuMargin = 1;
constexpr char kEllipsesButtonText[] = "...";
constexpr int kEllipsesButtonTag = -1;
} // namespace
TouchSelectionMenuViews::TouchSelectionMenuViews(
TouchSelectionMenuRunnerViews* owner,
ui::TouchSelectionMenuClient* client,
aura::Window* context)
: BubbleDialogDelegateView(nullptr, BubbleBorder::BOTTOM_CENTER),
owner_(owner),
client_(client) {
DCHECK(owner_);
DCHECK(client_);
set_shadow(BubbleBorder::SMALL_SHADOW);
set_parent_window(context);
set_margins(gfx::Insets(kMenuMargin, kMenuMargin, kMenuMargin, kMenuMargin));
set_can_activate(false);
set_adjust_if_offscreen(true);
EnableCanvasFlippingForRTLUI(true);
SetLayoutManager(std::make_unique<BoxLayout>(
BoxLayout::kHorizontal, gfx::Insets(), kSpacingBetweenButtons));
}
void TouchSelectionMenuViews::ShowMenu(const gfx::Rect& anchor_rect,
const gfx::Size& handle_image_size) {
CreateButtons();
// After buttons are created, check if there is enough room between handles to
// show the menu and adjust anchor rect properly if needed, just in case the
// menu is needed to be shown under the selection.
gfx::Rect adjusted_anchor_rect(anchor_rect);
int menu_width = GetPreferredSize().width();
// TODO(mfomitchev): This assumes that the handles are center-aligned to the
// |achor_rect| edges, which is not true. We should fix this, perhaps by
// passing down the cumulative width occupied by the handles within
// |anchor_rect| plus the handle image height instead of |handle_image_size|.
// Perhaps we should also allow for some minimum padding.
if (menu_width > anchor_rect.width() - handle_image_size.width())
adjusted_anchor_rect.Inset(0, 0, 0, -handle_image_size.height());
SetAnchorRect(adjusted_anchor_rect);
BubbleDialogDelegateView::CreateBubble(this);
Widget* widget = GetWidget();
gfx::Rect bounds = widget->GetWindowBoundsInScreen();
gfx::Rect work_area = display::Screen::GetScreen()
->GetDisplayNearestPoint(bounds.origin())
.work_area();
if (!work_area.IsEmpty()) {
bounds.AdjustToFit(work_area);
widget->SetBounds(bounds);
}
// Using BubbleDialogDelegateView engages its CreateBubbleWidget() which
// invokes widget->StackAbove(context). That causes the bubble to stack
// _immediately_ above |context|; below any already-existing bubbles. That
// doesn't make sense for a menu, so put it back on top.
widget->StackAtTop();
widget->Show();
}
bool TouchSelectionMenuViews::IsMenuAvailable(
const ui::TouchSelectionMenuClient* client) {
DCHECK(client);
for (size_t i = 0; i < base::size(kMenuCommands); i++) {
if (client->IsCommandIdEnabled(kMenuCommands[i]))
return true;
}
return false;
}
void TouchSelectionMenuViews::CloseMenu() {
DisconnectOwner();
// Closing the widget will self-destroy this object.
Widget* widget = GetWidget();
if (widget && !widget->IsClosed())
widget->Close();
}
TouchSelectionMenuViews::~TouchSelectionMenuViews() = default;
void TouchSelectionMenuViews::CreateButtons() {
for (size_t i = 0; i < base::size(kMenuCommands); i++) {
int command_id = kMenuCommands[i];
if (!client_->IsCommandIdEnabled(command_id))
continue;
Button* button =
CreateButton(l10n_util::GetStringUTF16(command_id), command_id);
AddChildView(button);
}
// Finally, add ellipses button.
AddChildView(
CreateButton(base::UTF8ToUTF16(kEllipsesButtonText), kEllipsesButtonTag));
Layout();
}
LabelButton* TouchSelectionMenuViews::CreateButton(const base::string16& title,
int tag) {
base::string16 label =
gfx::RemoveAcceleratorChar(title, '&', nullptr, nullptr);
LabelButton* button = new LabelButton(this, label, style::CONTEXT_TOUCH_MENU);
button->SetMinSize(gfx::Size(kMenuButtonMinWidth, kMenuButtonMinHeight));
button->SetFocusForPlatform();
button->SetHorizontalAlignment(gfx::ALIGN_CENTER);
button->set_tag(tag);
return button;
}
void TouchSelectionMenuViews::DisconnectOwner() {
DCHECK(owner_);
owner_->menu_ = nullptr;
owner_ = nullptr;
}
void TouchSelectionMenuViews::OnPaint(gfx::Canvas* canvas) {
BubbleDialogDelegateView::OnPaint(canvas);
// Draw separator bars.
for (int i = 0; i < child_count() - 1; ++i) {
View* child = child_at(i);
int x = child->bounds().right() + kSpacingBetweenButtons / 2;
canvas->FillRect(gfx::Rect(x, 0, 1, child->height()),
kButtonSeparatorColor);
}
}
void TouchSelectionMenuViews::WindowClosing() {
DCHECK(!owner_ || owner_->menu_ == this);
BubbleDialogDelegateView::WindowClosing();
if (owner_)
DisconnectOwner();
}
int TouchSelectionMenuViews::GetDialogButtons() const {
return ui::DIALOG_BUTTON_NONE;
}
void TouchSelectionMenuViews::ButtonPressed(Button* sender,
const ui::Event& event) {
CloseMenu();
if (sender->tag() != kEllipsesButtonTag)
client_->ExecuteCommand(sender->tag(), event.flags());
else
client_->RunContextMenu();
}
} // namespace views
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_VIEWS_TOUCHUI_TOUCH_SELECTION_MENU_VIEWS_H_
#define UI_VIEWS_TOUCHUI_TOUCH_SELECTION_MENU_VIEWS_H_
#include "base/macros.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/touchui/touch_selection_menu_runner_views.h"
namespace ui {
class TouchSelectionMenuClient;
} // namespace ui
namespace views {
class LabelButton;
// A bubble that contains actions available for the selected text. An object of
// this type, as a BubbleDialogDelegateView, manages its own lifetime.
class VIEWS_EXPORT TouchSelectionMenuViews : public BubbleDialogDelegateView,
public ButtonListener {
public:
TouchSelectionMenuViews(TouchSelectionMenuRunnerViews* owner,
ui::TouchSelectionMenuClient* client,
aura::Window* context);
void ShowMenu(const gfx::Rect& anchor_rect,
const gfx::Size& handle_image_size);
// Checks whether there is any command available to show in the menu.
static bool IsMenuAvailable(const ui::TouchSelectionMenuClient* client);
// Closes the menu. This will eventually self-destroy the object.
void CloseMenu();
protected:
~TouchSelectionMenuViews() override;
// Queries the |client_| for what commands to show in the menu and sizes the
// menu appropriately.
virtual void CreateButtons();
// Helper method to create a single button.
LabelButton* CreateButton(const base::string16& title, int tag);
// ButtonListener:
void ButtonPressed(Button* sender, const ui::Event& event) override;
private:
friend class TouchSelectionMenuRunnerViews::TestApi;
// Helper to disconnect this menu object from its owning menu runner.
void DisconnectOwner();
// BubbleDialogDelegateView:
void OnPaint(gfx::Canvas* canvas) override;
void WindowClosing() override;
int GetDialogButtons() const override;
TouchSelectionMenuRunnerViews* owner_;
ui::TouchSelectionMenuClient* const client_;
DISALLOW_COPY_AND_ASSIGN(TouchSelectionMenuViews);
};
} // namespace views
#endif // UI_VIEWS_TOUCHUI_TOUCH_SELECTION_MENU_VIEWS_H_
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