Commit 8472ed0f authored by Greg Thompson's avatar Greg Thompson Committed by Commit Bot

Show/hide the TryChromeDialog's close button on mouse enter/leave.

BUG=717091

Change-Id: Iaa193a2c59c61846535b5686f234cf3022f2c24e
Reviewed-on: https://chromium-review.googlesource.com/678510
Commit-Queue: Scott Violet <sky@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Cr-Commit-Position: refs/heads/master@{#506441}
parent b35515df
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "chrome/installer/util/experiment.h" #include "chrome/installer/util/experiment.h"
#include "chrome/installer/util/experiment_storage.h" #include "chrome/installer/util/experiment_storage.h"
#include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkColor.h"
#include "ui/aura/window.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
#include "ui/display/display.h" #include "ui/display/display.h"
#include "ui/display/screen.h" #include "ui/display/screen.h"
...@@ -37,6 +38,7 @@ ...@@ -37,6 +38,7 @@
#include "ui/views/controls/button/label_button.h" #include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/image_view.h" #include "ui/views/controls/image_view.h"
#include "ui/views/layout/grid_layout.h" #include "ui/views/layout/grid_layout.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
namespace { namespace {
...@@ -56,7 +58,6 @@ enum class ButtonTag { CLOSE_BUTTON, OK_BUTTON, NO_THANKS_BUTTON }; ...@@ -56,7 +58,6 @@ enum class ButtonTag { CLOSE_BUTTON, OK_BUTTON, NO_THANKS_BUTTON };
// Experiment specification information needed for layout. // Experiment specification information needed for layout.
// TODO(skare): Suppress x-to-close in relevant variations. // TODO(skare): Suppress x-to-close in relevant variations.
// TODO(skare): Implement hover behavior for x-to-close.
struct ExperimentVariations { struct ExperimentVariations {
// Resource ID for header message string. // Resource ID for header message string.
int heading_id; int heading_id;
...@@ -124,6 +125,25 @@ std::unique_ptr<views::LabelButton> CreateWin10StyleButton( ...@@ -124,6 +125,25 @@ std::unique_ptr<views::LabelButton> CreateWin10StyleButton(
return button; return button;
} }
// A View that unconditionally reports that it handles mouse presses. This
// results in the widget capturing the mouse so that it receives a
// ET_MOUSE_CAPTURE_CHANGED event upon button release following a drag out of
// the background of the widget.
class ClickableView : public views::View {
public:
ClickableView() = default;
// views::View:
bool OnMousePressed(const ui::MouseEvent& event) override;
private:
DISALLOW_COPY_AND_ASSIGN(ClickableView);
};
bool ClickableView::OnMousePressed(const ui::MouseEvent& event) {
return true;
}
} // namespace } // namespace
// TryChromeDialog::ModalShowDelegate ------------------------------------------ // TryChromeDialog::ModalShowDelegate ------------------------------------------
...@@ -262,19 +282,20 @@ void TryChromeDialog::OnTaskbarIconRect(const gfx::Rect& icon_rect) { ...@@ -262,19 +282,20 @@ void TryChromeDialog::OnTaskbarIconRect(const gfx::Rect& icon_rect) {
// An approximate window size. Layout() can adjust. // An approximate window size. Layout() can adjust.
params.bounds = gfx::Rect(kToastWidth, 120); params.bounds = gfx::Rect(kToastWidth, 120);
popup_ = new views::Widget; popup_ = new views::Widget;
popup_->Init(params);
popup_->AddObserver(this); popup_->AddObserver(this);
popup_->Init(params);
views::View* root_view = popup_->GetRootView(); auto contents_view = std::make_unique<ClickableView>();
root_view->SetBackground(views::CreateSolidBackground(kBackgroundColor)); contents_view->SetBackground(views::CreateSolidBackground(kBackgroundColor));
views::GridLayout* layout = views::GridLayout::CreateAndInstall(root_view); views::GridLayout* layout =
views::GridLayout::CreateAndInstall(contents_view.get());
layout->set_minimum_size(gfx::Size(kToastWidth, 0)); layout->set_minimum_size(gfx::Size(kToastWidth, 0));
views::ColumnSet* columns; views::ColumnSet* columns;
// Note the right padding is smaller than other dimensions, // Note the right padding is smaller than other dimensions,
// to acommodate the close 'x' button. // to acommodate the close 'x' button.
static constexpr gfx::Insets kInsets(10, 10, 12, 3); static constexpr gfx::Insets kInsets(10, 10, 12, 3);
root_view->SetBorder(views::CreatePaddedBorder( contents_view->SetBorder(views::CreatePaddedBorder(
views::CreateSolidBorder(1, kBorderColor), kInsets)); views::CreateSolidBorder(1, kBorderColor), kInsets));
static constexpr int kLabelSpacing = 10; static constexpr int kLabelSpacing = 10;
...@@ -331,7 +352,9 @@ void TryChromeDialog::OnTaskbarIconRect(const gfx::Rect& icon_rect) { ...@@ -331,7 +352,9 @@ void TryChromeDialog::OnTaskbarIconRect(const gfx::Rect& icon_rect) {
views::Button::STATE_NORMAL, views::Button::STATE_NORMAL,
gfx::CreateVectorIcon(kInactiveToastCloseIcon, kBodyColor)); gfx::CreateVectorIcon(kInactiveToastCloseIcon, kBodyColor));
close_button->set_tag(static_cast<int>(ButtonTag::CLOSE_BUTTON)); close_button->set_tag(static_cast<int>(ButtonTag::CLOSE_BUTTON));
close_button_ = close_button.get();
layout->AddView(close_button.release()); layout->AddView(close_button.release());
close_button_->SetVisible(false);
// Second row: May have text or may be blank. // Second row: May have text or may be blank.
layout->StartRow(0, 1); layout->StartRow(0, 1);
...@@ -363,7 +386,7 @@ void TryChromeDialog::OnTaskbarIconRect(const gfx::Rect& icon_rect) { ...@@ -363,7 +386,7 @@ void TryChromeDialog::OnTaskbarIconRect(const gfx::Rect& icon_rect) {
} }
// Padding between buttons and the edge of the view is via the border. // Padding between buttons and the edge of the view is via the border.
gfx::Size preferred = layout->GetPreferredSize(root_view); gfx::Size preferred = layout->GetPreferredSize(contents_view.get());
installer::ExperimentMetrics::ToastLocation location = installer::ExperimentMetrics::ToastLocation location =
installer::ExperimentMetrics::kOverTaskbarPin; installer::ExperimentMetrics::kOverTaskbarPin;
...@@ -374,7 +397,7 @@ void TryChromeDialog::OnTaskbarIconRect(const gfx::Rect& icon_rect) { ...@@ -374,7 +397,7 @@ void TryChromeDialog::OnTaskbarIconRect(const gfx::Rect& icon_rect) {
} }
popup_->SetBounds(bounds); popup_->SetBounds(bounds);
layout->Layout(root_view); popup_->SetContentsView(contents_view.release());
popup_->Show(); popup_->Show();
delegate_->SetToastLocation(location); delegate_->SetToastLocation(location);
...@@ -453,6 +476,7 @@ gfx::Rect TryChromeDialog::ComputePopupBoundsOverNoficationArea( ...@@ -453,6 +476,7 @@ gfx::Rect TryChromeDialog::ComputePopupBoundsOverNoficationArea(
} }
void TryChromeDialog::CompleteInteraction() { void TryChromeDialog::CompleteInteraction() {
DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
endsession_observer_.reset(); endsession_observer_.reset();
delegate_->SetExperimentState(state_); delegate_->SetExperimentState(state_);
delegate_->InteractionComplete(); delegate_->InteractionComplete();
...@@ -495,6 +519,18 @@ void TryChromeDialog::OnWindowMessage(HWND window, ...@@ -495,6 +519,18 @@ void TryChromeDialog::OnWindowMessage(HWND window,
delegate_->SetExperimentState(state_); delegate_->SetExperimentState(state_);
} }
void TryChromeDialog::GainedMouseHover() {
DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
DCHECK(close_button_);
close_button_->SetVisible(true);
}
void TryChromeDialog::LostMouseHover() {
DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
DCHECK(close_button_);
close_button_->SetVisible(false);
}
void TryChromeDialog::ButtonPressed(views::Button* sender, void TryChromeDialog::ButtonPressed(views::Button* sender,
const ui::Event& event) { const ui::Event& event) {
DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
...@@ -526,12 +562,59 @@ void TryChromeDialog::ButtonPressed(views::Button* sender, ...@@ -526,12 +562,59 @@ void TryChromeDialog::ButtonPressed(views::Button* sender,
popup_->Close(); popup_->Close();
} }
void TryChromeDialog::OnWidgetClosing(views::Widget* widget) {
DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
DCHECK_EQ(widget, popup_);
popup_->GetNativeWindow()->RemovePreTargetHandler(this);
}
void TryChromeDialog::OnWidgetCreated(views::Widget* widget) {
DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
DCHECK_EQ(widget, popup_);
popup_->GetNativeWindow()->AddPreTargetHandler(this);
}
void TryChromeDialog::OnWidgetDestroyed(views::Widget* widget) { void TryChromeDialog::OnWidgetDestroyed(views::Widget* widget) {
DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
DCHECK_EQ(widget, popup_); DCHECK_EQ(widget, popup_);
popup_->RemoveObserver(this); popup_->RemoveObserver(this);
popup_ = nullptr; popup_ = nullptr;
close_button_ = nullptr;
CompleteInteraction(); CompleteInteraction();
} }
void TryChromeDialog::OnMouseEvent(ui::MouseEvent* event) {
DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
DCHECK(popup_);
switch (event->type()) {
// A MOUSE_ENTERED event is received if the mouse is over the dialog when it
// opens.
case ui::ET_MOUSE_ENTERED:
case ui::ET_MOUSE_MOVED:
if (!has_hover_) {
has_hover_ = true;
GainedMouseHover();
}
break;
case ui::ET_MOUSE_EXITED:
if (has_hover_) {
has_hover_ = false;
LostMouseHover();
}
break;
case ui::ET_MOUSE_CAPTURE_CHANGED:
if (has_hover_ && !display::Screen::GetScreen()->IsWindowUnderCursor(
popup_->GetNativeWindow())) {
has_hover_ = false;
LostMouseHover();
}
break;
default:
break;
}
}
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/sequence_checker.h" #include "base/sequence_checker.h"
#include "chrome/installer/util/experiment_metrics.h" #include "chrome/installer/util/experiment_metrics.h"
#include "ui/events/event_handler.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/views/controls/button/button.h" #include "ui/views/controls/button/button.h"
...@@ -23,6 +24,7 @@ class SingletonHwndObserver; ...@@ -23,6 +24,7 @@ class SingletonHwndObserver;
} }
namespace views { namespace views {
class View;
class Widget; class Widget;
} }
...@@ -41,7 +43,8 @@ class Widget; ...@@ -41,7 +43,8 @@ class Widget;
// //
// Some variants do not have body text, or only have one button. // Some variants do not have body text, or only have one button.
class TryChromeDialog : public views::ButtonListener, class TryChromeDialog : public views::ButtonListener,
public views::WidgetObserver { public views::WidgetObserver,
public ui::EventHandler {
public: public:
// Receives a closure to run upon process singleton notification when the // Receives a closure to run upon process singleton notification when the
// modal dialog is open, or a null closure when the active dialog is // modal dialog is open, or a null closure when the active dialog is
...@@ -127,16 +130,25 @@ class TryChromeDialog : public views::ButtonListener, ...@@ -127,16 +130,25 @@ class TryChromeDialog : public views::ButtonListener,
// singleton. Triggers completion of the interaction by closing the dialog. // singleton. Triggers completion of the interaction by closing the dialog.
void OnProcessNotification(); void OnProcessNotification();
// Handles for events sent by the dialog's Widget.
void GainedMouseHover();
void LostMouseHover();
// views::ButtonListener: // views::ButtonListener:
// Updates the result_ and state_ based on which button was pressed and // Updates the result_ and state_ based on which button was pressed and
// closes the dialog. // closes the dialog.
void ButtonPressed(views::Button* sender, const ui::Event& event) override; void ButtonPressed(views::Button* sender, const ui::Event& event) override;
// views::WidgetObserver: // views::WidgetObserver:
// Completes the interaction. void OnWidgetClosing(views::Widget* widget) override;
void OnWidgetCreated(views::Widget* widget) override;
void OnWidgetDestroyed(views::Widget* widget) override; void OnWidgetDestroyed(views::Widget* widget) override;
Result result() const { return result_; } Result result() const { return result_; }
// ui::EventHandler:
void OnMouseEvent(ui::MouseEvent* event) override;
// A gfx::SingletonHwndObserver::WndProc for handling WM_ENDSESSION messages. // A gfx::SingletonHwndObserver::WndProc for handling WM_ENDSESSION messages.
void OnWindowMessage(HWND window, UINT message, WPARAM wparam, LPARAM lparam); void OnWindowMessage(HWND window, UINT message, WPARAM wparam, LPARAM lparam);
...@@ -164,6 +176,12 @@ class TryChromeDialog : public views::ButtonListener, ...@@ -164,6 +176,12 @@ class TryChromeDialog : public views::ButtonListener,
// Unowned; |popup_| owns itself. // Unowned; |popup_| owns itself.
views::Widget* popup_ = nullptr; views::Widget* popup_ = nullptr;
// The close button; owned by |popup_|.
views::View* close_button_ = nullptr;
// True when the mouse is considered to be hovering over the dialog.
bool has_hover_ = false;
SEQUENCE_CHECKER(my_sequence_checker_); SEQUENCE_CHECKER(my_sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(TryChromeDialog); DISALLOW_COPY_AND_ASSIGN(TryChromeDialog);
......
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