Commit 04406098 authored by Caroline Rising's avatar Caroline Rising Committed by Commit Bot

Add pin button to extensions menu button.

Pin button is visible when hoving the extensions menu button, when the extension's context menu is open, or when pinned.

Bug: 959920
Change-Id: I73296cfd4502eb963954fa2e0c315ff57972478c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1720862
Commit-Queue: Caroline Rising <corising@chromium.org>
Reviewed-by: default avatarPeter Boström <pbos@chromium.org>
Cr-Commit-Position: refs/heads/master@{#683260}
parent c15ab3b3
...@@ -4311,6 +4311,12 @@ Keep your key file in a safe place. You will need it to create new versions of y ...@@ -4311,6 +4311,12 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_EXTENSIONS_MENU_CONTEXT_MENU_TOOLTIP" desc="Title of the context menu for individual extensions in the Extensions Menu"> <message name="IDS_EXTENSIONS_MENU_CONTEXT_MENU_TOOLTIP" desc="Title of the context menu for individual extensions in the Extensions Menu">
More actions More actions
</message> </message>
<message name="IDS_EXTENSIONS_MENU_PIN_BUTTON_TOOLTIP" desc="The tooltip for the pinning button for individual extensions in the Extensions Menu">
Pin extension
</message>
<message name="IDS_EXTENSIONS_MENU_UNPIN_BUTTON_TOOLTIP" desc="The tooltip for the pinning button for individual extensions in the Extensions Menu">
Unpin extension
</message>
<message name="IDS_EXTENSIONS_MENU_ACCESSING_SITE_DATA" desc="Header for section of extensions that are able to access the current site's data"> <message name="IDS_EXTENSIONS_MENU_ACCESSING_SITE_DATA" desc="Header for section of extensions that are able to access the current site's data">
Accessing this site's data Accessing this site's data
</message> </message>
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "chrome/app/vector_icons/vector_icons.h" #include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h" #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
#include "chrome/browser/ui/views/extensions/extensions_menu_view.h" #include "chrome/browser/ui/views/extensions/extensions_menu_view.h"
#include "chrome/browser/ui/views/extensions/extensions_toolbar_button.h" #include "chrome/browser/ui/views/extensions/extensions_toolbar_button.h"
#include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/browser_view.h"
...@@ -15,9 +16,11 @@ ...@@ -15,9 +16,11 @@
#include "ui/gfx/paint_vector_icon.h" #include "ui/gfx/paint_vector_icon.h"
#include "ui/views/controls/button/button.h" #include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/image_button.h" #include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/button/image_button_factory.h"
#include "ui/views/controls/button/menu_button.h" #include "ui/views/controls/button/menu_button.h"
#include "ui/views/layout/box_layout.h" #include "ui/views/layout/box_layout.h"
#include "ui/views/layout/layout_provider.h" #include "ui/views/layout/layout_provider.h"
#include "ui/views/vector_icons.h"
#include "ui/views/view_class_properties.h" #include "ui/views/view_class_properties.h"
const char ExtensionsMenuButton::kClassName[] = "ExtensionsMenuButton"; const char ExtensionsMenuButton::kClassName[] = "ExtensionsMenuButton";
...@@ -25,6 +28,15 @@ const char ExtensionsMenuButton::kClassName[] = "ExtensionsMenuButton"; ...@@ -25,6 +28,15 @@ const char ExtensionsMenuButton::kClassName[] = "ExtensionsMenuButton";
namespace { namespace {
constexpr int EXTENSION_CONTEXT_MENU = 13; constexpr int EXTENSION_CONTEXT_MENU = 13;
constexpr int EXTENSION_PINNING = 14;
constexpr int kSecondaryIconSizeDp = 16;
void SetSecondaryButtonHighlightPath(views::Button* button) {
auto highlight_path = std::make_unique<SkPath>();
highlight_path->addOval(gfx::RectToSkRect(gfx::Rect(button->size())));
button->SetProperty(views::kHighlightPathKey, highlight_path.release());
}
} // namespace } // namespace
...@@ -39,7 +51,11 @@ ExtensionsMenuButton::ExtensionsMenuButton( ...@@ -39,7 +51,11 @@ ExtensionsMenuButton::ExtensionsMenuButton(
true, true,
true), true),
browser_(browser), browser_(browser),
controller_(std::move(controller)) { controller_(std::move(controller)),
model_(ToolbarActionsModel::Get(browser_->profile())) {
// Set so the extension button receives enter/exit on children to retain hover
// status when hovering child views.
set_notify_enter_exit_on_child(true);
ConfigureSecondaryView(); ConfigureSecondaryView();
set_auto_compute_tooltip(false); set_auto_compute_tooltip(false);
controller_->SetDelegate(this); controller_->SetDelegate(this);
...@@ -48,6 +64,42 @@ ExtensionsMenuButton::ExtensionsMenuButton( ...@@ -48,6 +64,42 @@ ExtensionsMenuButton::ExtensionsMenuButton(
ExtensionsMenuButton::~ExtensionsMenuButton() = default; ExtensionsMenuButton::~ExtensionsMenuButton() = default;
void ExtensionsMenuButton::UpdatePinButton() {
pin_button_->SetTooltipText(l10n_util::GetStringUTF16(
IsPinned() ? IDS_EXTENSIONS_MENU_UNPIN_BUTTON_TOOLTIP
: IDS_EXTENSIONS_MENU_PIN_BUTTON_TOOLTIP));
SkColor unpinned_icon_color =
ui::NativeTheme::GetInstanceForNativeUi()->SystemDarkModeEnabled()
? gfx::kGoogleGrey500
: gfx::kChromeIconGrey;
SkColor icon_color = IsPinned()
? GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_ProminentButtonColor)
: unpinned_icon_color;
views::SetImageFromVectorIcon(
pin_button_, IsPinned() ? views::kUnpinIcon : views::kPinIcon,
kSecondaryIconSizeDp, icon_color);
pin_button_->SetVisible(IsPinned() || IsMouseHovered() || IsMenuRunning());
}
void ExtensionsMenuButton::OnMouseEntered(const ui::MouseEvent& event) {
UpdatePinButton();
// The layout manager does not get notified of visibility changes and the pin
// buttons has not be laid out before if it was invisible.
pin_button_->InvalidateLayout();
views::Button::OnMouseEntered(event);
}
void ExtensionsMenuButton::OnMouseExited(const ui::MouseEvent& event) {
UpdatePinButton();
views::Button::OnMouseExited(event);
}
void ExtensionsMenuButton::OnBoundsChanged(const gfx::Rect& previous_bounds) {
UpdatePinButton();
HoverButton::OnBoundsChanged(previous_bounds);
}
const char* ExtensionsMenuButton::GetClassName() const { const char* ExtensionsMenuButton::GetClassName() const {
return kClassName; return kClassName;
} }
...@@ -57,6 +109,9 @@ void ExtensionsMenuButton::ButtonPressed(Button* sender, ...@@ -57,6 +109,9 @@ void ExtensionsMenuButton::ButtonPressed(Button* sender,
if (sender->GetID() == EXTENSION_CONTEXT_MENU) { if (sender->GetID() == EXTENSION_CONTEXT_MENU) {
RunExtensionContextMenu(ui::MENU_SOURCE_MOUSE); RunExtensionContextMenu(ui::MENU_SOURCE_MOUSE);
return; return;
} else if (sender->GetID() == EXTENSION_PINNING) {
model_->SetActionVisibility(controller_->GetId(), !IsPinned());
return;
} }
DCHECK_EQ(this, sender); DCHECK_EQ(this, sender);
controller_->ExecuteAction(true); controller_->ExecuteAction(true);
...@@ -123,6 +178,10 @@ void ExtensionsMenuButton::OnMenuClosed() { ...@@ -123,6 +178,10 @@ void ExtensionsMenuButton::OnMenuClosed() {
menu_runner_.reset(); menu_runner_.reset();
controller_->OnContextMenuClosed(); controller_->OnContextMenuClosed();
menu_adapter_.reset(); menu_adapter_.reset();
// OnMouseExited is triggered when the context menu is opened. Since we don't
// hide the pin button OnMouseExited if the context menu is open we must
// update its state to hide it when the context menu is closed.
UpdatePinButton();
} }
void ExtensionsMenuButton::ConfigureSecondaryView() { void ExtensionsMenuButton::ConfigureSecondaryView() {
...@@ -136,6 +195,16 @@ void ExtensionsMenuButton::ConfigureSecondaryView() { ...@@ -136,6 +195,16 @@ void ExtensionsMenuButton::ConfigureSecondaryView() {
? gfx::kGoogleGrey500 ? gfx::kGoogleGrey500
: gfx::kChromeIconGrey; : gfx::kChromeIconGrey;
auto pin_button = views::CreateVectorImageButton(this);
pin_button->SetID(EXTENSION_PINNING);
pin_button->set_ink_drop_base_color(icon_color);
pin_button->SizeToPreferredSize();
pin_button_ = pin_button.get();
SetSecondaryButtonHighlightPath(pin_button_);
UpdatePinButton();
container->AddChildView(std::move(pin_button));
auto context_menu_button = auto context_menu_button =
std::make_unique<views::MenuButton>(base::string16(), this); std::make_unique<views::MenuButton>(base::string16(), this);
context_menu_button->SetID(EXTENSION_CONTEXT_MENU); context_menu_button->SetID(EXTENSION_CONTEXT_MENU);
...@@ -144,7 +213,9 @@ void ExtensionsMenuButton::ConfigureSecondaryView() { ...@@ -144,7 +213,9 @@ void ExtensionsMenuButton::ConfigureSecondaryView() {
context_menu_button->SetImage( context_menu_button->SetImage(
views::Button::STATE_NORMAL, views::Button::STATE_NORMAL,
gfx::CreateVectorIcon(kBrowserToolsIcon, 16, icon_color)); gfx::CreateVectorIcon(kBrowserToolsIcon, kSecondaryIconSizeDp,
icon_color));
context_menu_button->set_ink_drop_base_color(icon_color); context_menu_button->set_ink_drop_base_color(icon_color);
context_menu_button->SetBorder( context_menu_button->SetBorder(
views::CreateEmptyBorder(views::LayoutProvider::Get()->GetInsetsMetric( views::CreateEmptyBorder(views::LayoutProvider::Get()->GetInsetsMetric(
...@@ -153,12 +224,15 @@ void ExtensionsMenuButton::ConfigureSecondaryView() { ...@@ -153,12 +224,15 @@ void ExtensionsMenuButton::ConfigureSecondaryView() {
context_menu_button->SetInkDropMode(InkDropMode::ON); context_menu_button->SetInkDropMode(InkDropMode::ON);
context_menu_button->set_has_ink_drop_action_on_click(true); context_menu_button->set_has_ink_drop_action_on_click(true);
auto highlight_path = std::make_unique<SkPath>();
highlight_path->addOval(
gfx::RectToSkRect(gfx::Rect(context_menu_button->size())));
context_menu_button->SetProperty(views::kHighlightPathKey,
highlight_path.release());
context_menu_button_ = context_menu_button.get(); context_menu_button_ = context_menu_button.get();
SetSecondaryButtonHighlightPath(context_menu_button_);
container->AddChildView(std::move(context_menu_button)); container->AddChildView(std::move(context_menu_button));
} }
bool ExtensionsMenuButton::IsPinned() {
// |model_| can be null in unit tests.
if (!model_)
return false;
return model_->IsActionPinned(controller_->GetId());
}
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
namespace views { namespace views {
class Button; class Button;
class ImageButton;
class MenuButton; class MenuButton;
class MenuModelAdapter; class MenuModelAdapter;
class MenuRunner; class MenuRunner;
...@@ -28,9 +29,18 @@ class ExtensionsMenuButton : public HoverButton, ...@@ -28,9 +29,18 @@ class ExtensionsMenuButton : public HoverButton,
std::unique_ptr<ToolbarActionViewController> controller); std::unique_ptr<ToolbarActionViewController> controller);
~ExtensionsMenuButton() override; ~ExtensionsMenuButton() override;
// Update pin button icon, color, tooltip, and visibility based on pinned
// state.
void UpdatePinButton();
static const char kClassName[]; static const char kClassName[];
private: private:
// views::Button:
void OnMouseEntered(const ui::MouseEvent& event) override;
void OnMouseExited(const ui::MouseEvent& event) override;
void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
// views::ButtonListener: // views::ButtonListener:
const char* GetClassName() const override; const char* GetClassName() const override;
void ButtonPressed(Button* sender, const ui::Event& event) override; void ButtonPressed(Button* sender, const ui::Event& event) override;
...@@ -51,8 +61,11 @@ class ExtensionsMenuButton : public HoverButton, ...@@ -51,8 +61,11 @@ class ExtensionsMenuButton : public HoverButton,
// Configures the secondary (right-hand-side) view of this HoverButton. // Configures the secondary (right-hand-side) view of this HoverButton.
void ConfigureSecondaryView(); void ConfigureSecondaryView();
bool IsPinned();
Browser* const browser_; Browser* const browser_;
const std::unique_ptr<ToolbarActionViewController> controller_; const std::unique_ptr<ToolbarActionViewController> controller_;
ToolbarActionsModel* const model_;
// TODO(pbos): There's complicated configuration code in place since menus // TODO(pbos): There's complicated configuration code in place since menus
// can't be triggered from ImageButtons. When MenuRunner::RunMenuAt accepts // can't be triggered from ImageButtons. When MenuRunner::RunMenuAt accepts
...@@ -60,6 +73,8 @@ class ExtensionsMenuButton : public HoverButton, ...@@ -60,6 +73,8 @@ class ExtensionsMenuButton : public HoverButton,
// image_button_factory.h methods to configure it. // image_button_factory.h methods to configure it.
views::MenuButton* context_menu_button_ = nullptr; views::MenuButton* context_menu_button_ = nullptr;
views::ImageButton* pin_button_ = nullptr;
// Responsible for converting the context menu model into |menu_|. // Responsible for converting the context menu model into |menu_|.
std::unique_ptr<views::MenuModelAdapter> menu_adapter_; std::unique_ptr<views::MenuModelAdapter> menu_adapter_;
......
...@@ -5,8 +5,10 @@ ...@@ -5,8 +5,10 @@
#include "chrome/browser/ui/views/extensions/extensions_menu_button.h" #include "chrome/browser/ui/views/extensions/extensions_menu_button.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "chrome/browser/ui/toolbar/test_toolbar_action_view_controller.h" #include "chrome/browser/ui/toolbar/test_toolbar_action_view_controller.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/views/native_widget_factory.h" #include "chrome/browser/ui/views/native_widget_factory.h"
#include "chrome/test/base/browser_with_test_window_test.h" #include "chrome/test/base/browser_with_test_window_test.h"
#include "ui/events/event.h" #include "ui/events/event.h"
...@@ -19,6 +21,7 @@ class ExtensionsMenuButtonTest : public BrowserWithTestWindowTest { ...@@ -19,6 +21,7 @@ class ExtensionsMenuButtonTest : public BrowserWithTestWindowTest {
: initial_extension_name_(base::ASCIIToUTF16("Initial Extension Name")), : initial_extension_name_(base::ASCIIToUTF16("Initial Extension Name")),
initial_tooltip_(base::ASCIIToUTF16("Initial tooltip")) {} initial_tooltip_(base::ASCIIToUTF16("Initial tooltip")) {}
void SetUp() override { void SetUp() override {
scoped_feature_list_.InitAndEnableFeature(features::kExtensionsToolbarMenu);
BrowserWithTestWindowTest::SetUp(); BrowserWithTestWindowTest::SetUp();
widget_ = std::make_unique<views::Widget>(); widget_ = std::make_unique<views::Widget>();
...@@ -64,6 +67,7 @@ class ExtensionsMenuButtonTest : public BrowserWithTestWindowTest { ...@@ -64,6 +67,7 @@ class ExtensionsMenuButtonTest : public BrowserWithTestWindowTest {
test_api.NotifyClick(click_event); test_api.NotifyClick(click_event);
} }
base::test::ScopedFeatureList scoped_feature_list_;
const base::string16 initial_extension_name_; const base::string16 initial_extension_name_;
const base::string16 initial_tooltip_; const base::string16 initial_tooltip_;
std::unique_ptr<views::Widget> widget_; std::unique_ptr<views::Widget> widget_;
......
...@@ -63,6 +63,7 @@ ExtensionsMenuView::ExtensionsMenuView( ...@@ -63,6 +63,7 @@ ExtensionsMenuView::ExtensionsMenuView(
ExtensionsMenuView::~ExtensionsMenuView() { ExtensionsMenuView::~ExtensionsMenuView() {
DCHECK_EQ(g_extensions_dialog, this); DCHECK_EQ(g_extensions_dialog, this);
g_extensions_dialog = nullptr; g_extensions_dialog = nullptr;
extension_menu_buttons_.clear();
} }
void ExtensionsMenuView::ButtonPressed(views::Button* sender, void ExtensionsMenuView::ButtonPressed(views::Button* sender,
...@@ -113,6 +114,7 @@ void ExtensionsMenuView::Repopulate() { ...@@ -113,6 +114,7 @@ void ExtensionsMenuView::Repopulate() {
std::unique_ptr<views::View> std::unique_ptr<views::View>
ExtensionsMenuView::CreateExtensionButtonsContainer() { ExtensionsMenuView::CreateExtensionButtonsContainer() {
extension_menu_buttons_.clear();
content::WebContents* const web_contents = content::WebContents* const web_contents =
browser_->tab_strip_model()->GetActiveWebContents(); browser_->tab_strip_model()->GetActiveWebContents();
...@@ -139,7 +141,6 @@ ExtensionsMenuView::CreateExtensionButtonsContainer() { ...@@ -139,7 +141,6 @@ ExtensionsMenuView::CreateExtensionButtonsContainer() {
} }
auto extension_buttons = std::make_unique<views::View>(); auto extension_buttons = std::make_unique<views::View>();
extension_menu_button_container_for_testing_ = extension_buttons.get();
extension_buttons->SetLayoutManager(std::make_unique<views::BoxLayout>( extension_buttons->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical)); views::BoxLayout::Orientation::kVertical));
...@@ -179,9 +180,11 @@ ExtensionsMenuView::CreateExtensionButtonsContainer() { ...@@ -179,9 +180,11 @@ ExtensionsMenuView::CreateExtensionButtonsContainer() {
}); });
for (auto& controller : *controller_group) { for (auto& controller : *controller_group) {
extension_buttons->AddChildView( std::unique_ptr<ExtensionsMenuButton> extension_button =
std::make_unique<ExtensionsMenuButton>(browser_, std::make_unique<ExtensionsMenuButton>(browser_,
std::move(controller))); std::move(controller));
extension_menu_buttons_.push_back(extension_button.get());
extension_buttons->AddChildView(std::move(extension_button));
} }
controller_group->clear(); controller_group->clear();
}; };
...@@ -233,7 +236,9 @@ void ExtensionsMenuView::OnToolbarModelInitialized() { ...@@ -233,7 +236,9 @@ void ExtensionsMenuView::OnToolbarModelInitialized() {
} }
void ExtensionsMenuView::OnToolbarPinnedActionsChanged() { void ExtensionsMenuView::OnToolbarPinnedActionsChanged() {
Repopulate(); for (auto* button : extension_menu_buttons_) {
button->UpdatePinButton();
}
} }
// static // static
......
...@@ -16,6 +16,7 @@ class Button; ...@@ -16,6 +16,7 @@ class Button;
class ImageView; class ImageView;
} // namespace views } // namespace views
class ExtensionsMenuButton;
class ExtensionsContainer; class ExtensionsContainer;
// This bubble view displays a list of user extensions. // This bubble view displays a list of user extensions.
...@@ -62,8 +63,8 @@ class ExtensionsMenuView : public views::ButtonListener, ...@@ -62,8 +63,8 @@ class ExtensionsMenuView : public views::ButtonListener,
void OnToolbarModelInitialized() override; void OnToolbarModelInitialized() override;
void OnToolbarPinnedActionsChanged() override; void OnToolbarPinnedActionsChanged() override;
views::View* extension_menu_button_container_for_testing() { std::vector<ExtensionsMenuButton*> extension_menu_buttons_for_testing() {
return extension_menu_button_container_for_testing_; return extension_menu_buttons_;
} }
views::Button* manage_extensions_button_for_testing() { views::Button* manage_extensions_button_for_testing() {
return manage_extensions_button_for_testing_; return manage_extensions_button_for_testing_;
...@@ -78,8 +79,8 @@ class ExtensionsMenuView : public views::ButtonListener, ...@@ -78,8 +79,8 @@ class ExtensionsMenuView : public views::ButtonListener,
ToolbarActionsModel* const model_; ToolbarActionsModel* const model_;
ScopedObserver<ToolbarActionsModel, ToolbarActionsModel::Observer> ScopedObserver<ToolbarActionsModel, ToolbarActionsModel::Observer>
model_observer_; model_observer_;
std::vector<ExtensionsMenuButton*> extension_menu_buttons_;
views::View* extension_menu_button_container_for_testing_ = nullptr;
views::Button* manage_extensions_button_for_testing_ = nullptr; views::Button* manage_extensions_button_for_testing_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(ExtensionsMenuView); DISALLOW_COPY_AND_ASSIGN(ExtensionsMenuView);
......
...@@ -58,14 +58,8 @@ class ExtensionsMenuViewBrowserTest : public DialogBrowserTest { ...@@ -58,14 +58,8 @@ class ExtensionsMenuViewBrowserTest : public DialogBrowserTest {
} }
static std::vector<ExtensionsMenuButton*> GetExtensionMenuButtons() { static std::vector<ExtensionsMenuButton*> GetExtensionMenuButtons() {
std::vector<ExtensionsMenuButton*> buttons; return ExtensionsMenuView::GetExtensionsMenuViewForTesting()
for (auto* view : ExtensionsMenuView::GetExtensionsMenuViewForTesting() ->extension_menu_buttons_for_testing();
->extension_menu_button_container_for_testing()
->children()) {
if (view->GetClassName() == ExtensionsMenuButton::kClassName)
buttons.push_back(static_cast<ExtensionsMenuButton*>(view));
}
return buttons;
} }
std::vector<ToolbarActionView*> GetToolbarActionViews() const { std::vector<ToolbarActionView*> GetToolbarActionViews() 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