Commit 532a0c7f authored by Caroline Rising's avatar Caroline Rising Committed by Commit Bot

Add a delay to tab hover cards based on tab width.

Create a logarithmic scaled delay based on tab width for tab hover cards to show.

Bug: 910739
Change-Id: I00b4d4de57cea75b837b7cadc81dea4bb5023c6e
Reviewed-on: https://chromium-review.googlesource.com/c/1455057
Commit-Queue: Caroline Rising <corising@chromium.org>
Reviewed-by: default avatarPeter Boström <pbos@chromium.org>
Cr-Commit-Position: refs/heads/master@{#630082}
parent e5e8489e
...@@ -4,18 +4,29 @@ ...@@ -4,18 +4,29 @@
#include "chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h" #include "chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h"
#include <algorithm>
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/views/chrome_typography.h" #include "chrome/browser/ui/views/chrome_typography.h"
#include "chrome/browser/ui/views/tabs/tab.h"
#include "chrome/browser/ui/views/tabs/tab_renderer_data.h" #include "chrome/browser/ui/views/tabs/tab_renderer_data.h"
#include "chrome/browser/ui/views/tabs/tab_style.h"
#include "components/url_formatter/url_formatter.h" #include "components/url_formatter/url_formatter.h"
#include "ui/views/controls/label.h" #include "ui/views/controls/label.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/widget/widget.h" #include "ui/views/widget/widget.h"
TabHoverCardBubbleView::TabHoverCardBubbleView(views::View* anchor_view, namespace {
TabRendererData data)
: BubbleDialogDelegateView(anchor_view, views::BubbleBorder::TOP_LEFT) { constexpr base::TimeDelta kMinimumTriggerDelay =
base::TimeDelta::FromMilliseconds(50);
constexpr base::TimeDelta kMaximumTriggerDelay =
base::TimeDelta::FromMilliseconds(1000);
} // namespace
TabHoverCardBubbleView::TabHoverCardBubbleView(Tab* tab)
: BubbleDialogDelegateView(tab, views::BubbleBorder::TOP_LEFT) {
SetLayoutManager( SetLayoutManager(
std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical)); std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical));
// Set so that when hovering over a tab in a inactive window that window will // Set so that when hovering over a tab in a inactive window that window will
...@@ -28,7 +39,6 @@ TabHoverCardBubbleView::TabHoverCardBubbleView(views::View* anchor_view, ...@@ -28,7 +39,6 @@ TabHoverCardBubbleView::TabHoverCardBubbleView(views::View* anchor_view,
views::style::STYLE_PRIMARY); views::style::STYLE_PRIMARY);
domain_label_ = new views::Label(base::string16(), CONTEXT_BODY_TEXT_LARGE, domain_label_ = new views::Label(base::string16(), CONTEXT_BODY_TEXT_LARGE,
ChromeTextStyle::STYLE_SECONDARY); ChromeTextStyle::STYLE_SECONDARY);
UpdateCardContent(data);
title_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); title_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
title_label_->SetMultiLine(false); title_label_->SetMultiLine(false);
...@@ -42,14 +52,66 @@ TabHoverCardBubbleView::TabHoverCardBubbleView(views::View* anchor_view, ...@@ -42,14 +52,66 @@ TabHoverCardBubbleView::TabHoverCardBubbleView(views::View* anchor_view,
TabHoverCardBubbleView::~TabHoverCardBubbleView() = default; TabHoverCardBubbleView::~TabHoverCardBubbleView() = default;
void TabHoverCardBubbleView::Show() { void TabHoverCardBubbleView::UpdateAndShow(Tab* tab) {
widget_->Show(); UpdateCardContent(tab->data());
views::BubbleDialogDelegateView::SetAnchorView(tab);
// Start trigger timer if necessary.
if (widget_->IsVisible()) {
ShowImmediately();
} else {
// Note that this will restart the timer if it is already running. If the
// hover cards are not yet visible, moving the cursor within the tabstrip
// will not trigger the hover cards.
delayed_show_timer_.Start(FROM_HERE, GetDelay(tab->width()), this,
&TabHoverCardBubbleView::ShowImmediately);
}
} }
void TabHoverCardBubbleView::Hide() { void TabHoverCardBubbleView::Hide() {
delayed_show_timer_.Stop();
widget_->Hide(); widget_->Hide();
} }
int TabHoverCardBubbleView::GetDialogButtons() const {
return ui::DIALOG_BUTTON_NONE;
}
base::TimeDelta TabHoverCardBubbleView::GetDelay(int tab_width) const {
// Delay is calculated as a logarithmic scale and bounded by a minimum width
// based on the width of a pinned tab and a maximum of the standard width.
//
// delay (ms)
// |
// max delay-| *
// | *
// | *
// | *
// | *
// | *
// | *
// | *
// | *
// min delay-|****
// |___________________________________________ tab width
// | |
// pinned tab width standard tab width
double logarithmic_fraction =
std::log(tab_width - TabStyle::GetPinnedWidth() + 1) /
std::log(TabStyle::GetStandardWidth() - TabStyle::GetPinnedWidth() + 1);
base::TimeDelta scaling_factor = kMaximumTriggerDelay - kMinimumTriggerDelay;
base::TimeDelta delay =
logarithmic_fraction * scaling_factor + kMinimumTriggerDelay;
if (delay < kMinimumTriggerDelay)
delay = kMinimumTriggerDelay;
return delay;
}
void TabHoverCardBubbleView::ShowImmediately() {
widget_->Show();
}
void TabHoverCardBubbleView::UpdateCardContent(TabRendererData data) { void TabHoverCardBubbleView::UpdateCardContent(TabRendererData data) {
title_label_->SetText(data.title); title_label_->SetText(data.title);
...@@ -65,14 +127,6 @@ void TabHoverCardBubbleView::UpdateCardContent(TabRendererData data) { ...@@ -65,14 +127,6 @@ void TabHoverCardBubbleView::UpdateCardContent(TabRendererData data) {
domain_label_->SetText(domain); domain_label_->SetText(domain);
} }
void TabHoverCardBubbleView::UpdateCardAnchor(View* tab) {
views::BubbleDialogDelegateView::SetAnchorView(tab);
}
int TabHoverCardBubbleView::GetDialogButtons() const {
return ui::DIALOG_BUTTON_NONE;
}
gfx::Size TabHoverCardBubbleView::CalculatePreferredSize() const { gfx::Size TabHoverCardBubbleView::CalculatePreferredSize() const {
const gfx::Size size = BubbleDialogDelegateView::CalculatePreferredSize(); const gfx::Size size = BubbleDialogDelegateView::CalculatePreferredSize();
return gfx::Size(240, size.height()); return gfx::Size(240, size.height());
......
...@@ -5,42 +5,50 @@ ...@@ -5,42 +5,50 @@
#ifndef CHROME_BROWSER_UI_VIEWS_TABS_TAB_HOVER_CARD_BUBBLE_VIEW_H_ #ifndef CHROME_BROWSER_UI_VIEWS_TABS_TAB_HOVER_CARD_BUBBLE_VIEW_H_
#define CHROME_BROWSER_UI_VIEWS_TABS_TAB_HOVER_CARD_BUBBLE_VIEW_H_ #define CHROME_BROWSER_UI_VIEWS_TABS_TAB_HOVER_CARD_BUBBLE_VIEW_H_
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h"
namespace views { namespace views {
class Label; class Label;
class Widget; class Widget;
} // namespace views } // namespace views
class Tab;
struct TabRendererData; struct TabRendererData;
// Dialog that displays an informational hover card containing page information. // Dialog that displays an informational hover card containing page information.
class TabHoverCardBubbleView : public views::BubbleDialogDelegateView { class TabHoverCardBubbleView : public views::BubbleDialogDelegateView {
public: public:
TabHoverCardBubbleView(views::View* anchor_view, TabRendererData data); explicit TabHoverCardBubbleView(Tab* tab);
~TabHoverCardBubbleView() override; ~TabHoverCardBubbleView() override;
// Creates (if not already created) and shows the widget. // Updates card content and anchoring and shows the tab hover card.
void Show(); void UpdateAndShow(Tab* tab);
void Hide(); void Hide();
// Updates and formats title and domain with given data.
void UpdateCardContent(TabRendererData data);
// Updates where the card should be anchored.
void UpdateCardAnchor(View* tab);
// BubbleDialogDelegateView: // BubbleDialogDelegateView:
int GetDialogButtons() const override; int GetDialogButtons() const override;
private: private:
friend class TabHoverCardBubbleViewBrowserTest; friend class TabHoverCardBubbleViewBrowserTest;
base::OneShotTimer delayed_show_timer_;
views::Widget* widget_ = nullptr; views::Widget* widget_ = nullptr;
views::Label* title_label_; views::Label* title_label_;
views::Label* domain_label_; views::Label* domain_label_;
// Get delay in milliseconds based on tab width.
base::TimeDelta GetDelay(int tab_width) const;
void ShowImmediately();
// Updates and formats title and domain with given data.
void UpdateCardContent(TabRendererData data);
gfx::Size CalculatePreferredSize() const override; gfx::Size CalculatePreferredSize() const override;
}; };
......
...@@ -46,6 +46,32 @@ class WindowDeactivedWaiter : public views::WidgetObserver { ...@@ -46,6 +46,32 @@ class WindowDeactivedWaiter : public views::WidgetObserver {
base::RunLoop run_loop_; base::RunLoop run_loop_;
}; };
// Helper to wait until the hover card widget is visible.
class HoverCardVisibleWaiter : public views::WidgetObserver {
public:
explicit HoverCardVisibleWaiter(Widget* hover_card)
: hover_card_(hover_card) {
hover_card_->AddObserver(this);
}
~HoverCardVisibleWaiter() override { hover_card_->RemoveObserver(this); }
void Wait() {
if (hover_card_->IsVisible())
return;
run_loop_.Run();
}
// WidgetObserver overrides:
void OnWidgetVisibilityChanged(Widget* widget, bool visible) override {
if (visible)
run_loop_.Quit();
}
private:
Widget* const hover_card_;
base::RunLoop run_loop_;
};
class TabHoverCardBubbleViewBrowserTest : public DialogBrowserTest { class TabHoverCardBubbleViewBrowserTest : public DialogBrowserTest {
public: public:
TabHoverCardBubbleViewBrowserTest() = default; TabHoverCardBubbleViewBrowserTest() = default;
...@@ -109,6 +135,10 @@ class TabHoverCardBubbleViewBrowserTest : public DialogBrowserTest { ...@@ -109,6 +135,10 @@ class TabHoverCardBubbleViewBrowserTest : public DialogBrowserTest {
ui::MouseEvent hover_event(ui::ET_MOUSE_ENTERED, gfx::Point(), gfx::Point(), ui::MouseEvent hover_event(ui::ET_MOUSE_ENTERED, gfx::Point(), gfx::Point(),
base::TimeTicks(), ui::EF_NONE, 0); base::TimeTicks(), ui::EF_NONE, 0);
tab->OnMouseEntered(hover_event); tab->OnMouseEntered(hover_event);
TabHoverCardBubbleView* hover_card = GetHoverCard(tab_strip);
Widget* widget = GetHoverCardWidget(hover_card);
HoverCardVisibleWaiter waiter(widget);
waiter.Wait();
} }
private: private:
......
...@@ -1143,17 +1143,13 @@ void TabStrip::UpdateHoverCard(Tab* tab, bool should_show) { ...@@ -1143,17 +1143,13 @@ void TabStrip::UpdateHoverCard(Tab* tab, bool should_show) {
// not trying to show it. // not trying to show it.
if (!should_show) if (!should_show)
return; return;
hover_card_ = new TabHoverCardBubbleView(tab, tab->data()); hover_card_ = new TabHoverCardBubbleView(tab);
hover_card_->views::View::AddObserver(this); hover_card_->views::View::AddObserver(this);
} }
if (should_show)
if (should_show) { hover_card_->UpdateAndShow(tab);
hover_card_->UpdateCardContent(tab->data()); else
hover_card_->UpdateCardAnchor(tab);
hover_card_->Show();
} else {
hover_card_->Hide(); hover_card_->Hide();
}
} }
bool TabStrip::ShouldPaintTab(const Tab* tab, float scale, SkPath* clip) { bool TabStrip::ShouldPaintTab(const Tab* tab, float scale, SkPath* clip) {
......
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