diff options
author | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-14 18:06:18 +0000 |
---|---|---|
committer | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-14 18:06:18 +0000 |
commit | efa71ab24691126e8a1d11f177b64c674a5c9f68 (patch) | |
tree | a6aabe7e82cba21727a0506d4f0f783db20eae9b /chrome/browser | |
parent | fac9a45d0e29394b6445a4a1a8ec20dc9e917a3d (diff) | |
download | chromium_src-efa71ab24691126e8a1d11f177b64c674a5c9f68.zip chromium_src-efa71ab24691126e8a1d11f177b64c674a5c9f68.tar.gz chromium_src-efa71ab24691126e8a1d11f177b64c674a5c9f68.tar.bz2 |
GTK: expand status bar when user hovers over a link for long enough.
BUG=43192
TEST=none
Review URL: http://codereview.chromium.org/2033010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@47285 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/cocoa/status_bubble_mac.h | 1 | ||||
-rw-r--r-- | chrome/browser/cocoa/status_bubble_mac.mm | 4 | ||||
-rw-r--r-- | chrome/browser/gtk/status_bubble_gtk.cc | 88 | ||||
-rw-r--r-- | chrome/browser/gtk/status_bubble_gtk.h | 64 | ||||
-rw-r--r-- | chrome/browser/status_bubble.h | 8 | ||||
-rw-r--r-- | chrome/browser/views/status_bubble_views.cc | 4 | ||||
-rw-r--r-- | chrome/browser/views/status_bubble_views.h | 3 |
7 files changed, 118 insertions, 54 deletions
diff --git a/chrome/browser/cocoa/status_bubble_mac.h b/chrome/browser/cocoa/status_bubble_mac.h index d01aee2..e1dadb9 100644 --- a/chrome/browser/cocoa/status_bubble_mac.h +++ b/chrome/browser/cocoa/status_bubble_mac.h @@ -38,7 +38,6 @@ class StatusBubbleMac : public StatusBubble { virtual void Hide(); virtual void MouseMoved(const gfx::Point& location, bool left_content); virtual void UpdateDownloadShelfVisibility(bool visible); - virtual void SetBubbleWidth(int width); // Mac-specific method: Update the size and position of the status bubble to // match the parent window. Safe to call even when the status bubble does not diff --git a/chrome/browser/cocoa/status_bubble_mac.mm b/chrome/browser/cocoa/status_bubble_mac.mm index 62b0ae0..7906243 100644 --- a/chrome/browser/cocoa/status_bubble_mac.mm +++ b/chrome/browser/cocoa/status_bubble_mac.mm @@ -292,10 +292,6 @@ void StatusBubbleMac::MouseMoved( void StatusBubbleMac::UpdateDownloadShelfVisibility(bool visible) { } -void StatusBubbleMac::SetBubbleWidth(int width) { - NOTIMPLEMENTED(); -} - void StatusBubbleMac::Create() { if (window_) return; diff --git a/chrome/browser/gtk/status_bubble_gtk.cc b/chrome/browser/gtk/status_bubble_gtk.cc index 960797f..56670dd 100644 --- a/chrome/browser/gtk/status_bubble_gtk.cc +++ b/chrome/browser/gtk/status_bubble_gtk.cc @@ -18,7 +18,6 @@ #include "chrome/browser/gtk/slide_animator_gtk.h" #include "chrome/common/notification_service.h" #include "gfx/gtk_util.h" -#include "googleurl/src/gurl.h" namespace { @@ -42,7 +41,6 @@ StatusBubbleGtk::StatusBubbleGtk(Profile* profile) : theme_provider_(GtkThemeProvider::GetFrom(profile)), padding_(NULL), label_(NULL), - timer_factory_(this), flip_horizontally_(false), y_offset_(0), download_shelf_is_visible_(false), @@ -75,6 +73,9 @@ void StatusBubbleGtk::SetStatus(const std::wstring& status_text_wide) { } void StatusBubbleGtk::SetURL(const GURL& url, const std::wstring& languages) { + url_ = url; + languages_ = languages; + // If we want to clear a displayed URL but there is a status still to // display, display that status instead. if (url.is_empty() && !status_text_.empty()) { @@ -83,21 +84,32 @@ void StatusBubbleGtk::SetURL(const GURL& url, const std::wstring& languages) { return; } - // Set Elided Text corresponding to the GURL object. We limit the width of - // the URL to a third of the width of the browser window (matching the width - // on Windows). + SetStatusTextToURL(); +} + +void StatusBubbleGtk::SetStatusTextToURL() { GtkWidget* parent = gtk_widget_get_parent(container_.get()); - int window_width = parent->allocation.width; + int desired_width = parent->allocation.width; + if (!expanded()) { + expand_timer_.Stop(); + expand_timer_.Start(base::TimeDelta::FromMilliseconds(kExpandHoverDelay), + this, &StatusBubbleGtk::ExpandURL); + // When not expanded, we limit the size to one third the browser's + // width. + desired_width /= 3; + } + // TODO(tc): We don't actually use gfx::Font as the font in the status // bubble. We should extend gfx::ElideUrl to take some sort of pango font. - url_text_ = WideToUTF8(gfx::ElideUrl(url, gfx::Font(), window_width / 3, - languages)); + url_text_ = WideToUTF8(gfx::ElideUrl(url_, gfx::Font(), desired_width, + languages_)); SetStatusTextTo(url_text_); } + void StatusBubbleGtk::Show() { // If we were going to hide, stop. - timer_factory_.RevokeAll(); + hide_timer_.Stop(); gtk_widget_show_all(container_.get()); if (container_->window) @@ -105,14 +117,26 @@ void StatusBubbleGtk::Show() { } void StatusBubbleGtk::Hide() { + // If we were going to expand the bubble, stop. + expand_timer_.Stop(); + expand_animation_.reset(); + gtk_widget_hide_all(container_.get()); } void StatusBubbleGtk::SetStatusTextTo(const std::string& status_utf8) { if (status_utf8.empty()) { - HideInASecond(); + hide_timer_.Stop(); + hide_timer_.Start(base::TimeDelta::FromMilliseconds(kHideDelay), + this, &StatusBubbleGtk::Hide); } else { gtk_label_set_text(GTK_LABEL(label_), status_utf8.c_str()); + GtkRequisition req; + gtk_widget_size_request(label_, &req); + desired_width_ = req.width; + + UpdateLabelSizeRequest(); + if (!last_mouse_left_content_) { // Show the padding and label to update our requisition and then // re-process the last mouse event -- if the label was empty before or the @@ -125,15 +149,6 @@ void StatusBubbleGtk::SetStatusTextTo(const std::string& status_utf8) { } } -void StatusBubbleGtk::HideInASecond() { - if (!timer_factory_.empty()) - timer_factory_.RevokeAll(); - - MessageLoop::current()->PostDelayedTask(FROM_HERE, - timer_factory_.NewRunnableMethod(&StatusBubbleGtk::Hide), - kHideDelay); -} - void StatusBubbleGtk::MouseMoved( const gfx::Point& location, bool left_content) { last_mouse_location_ = location; @@ -210,10 +225,6 @@ void StatusBubbleGtk::UpdateDownloadShelfVisibility(bool visible) { download_shelf_is_visible_ = visible; } -void StatusBubbleGtk::SetBubbleWidth(int width) { - NOTIMPLEMENTED(); -} - void StatusBubbleGtk::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { @@ -298,7 +309,36 @@ void StatusBubbleGtk::SetFlipHorizontally(bool flip_horizontally) { gtk_widget_queue_draw(container_.get()); } -gboolean StatusBubbleGtk::HandleMotionNotify(GdkEventMotion* event) { +void StatusBubbleGtk::ExpandURL() { + start_width_ = label_->allocation.width; + expand_animation_.reset(new SlideAnimation(this)); + expand_animation_->SetTweenType(Tween::LINEAR); + expand_animation_->Show(); + + SetStatusTextToURL(); +} + +void StatusBubbleGtk::UpdateLabelSizeRequest() { + if (!expanded() || !expand_animation_->is_animating()) { + gtk_widget_set_size_request(label_, -1, -1); + return; + } + + int new_width = start_width_ + + (desired_width_ - start_width_) * expand_animation_->GetCurrentValue(); + gtk_widget_set_size_request(label_, new_width, -1); +} + +gboolean StatusBubbleGtk::HandleMotionNotify(GtkWidget* sender, + GdkEventMotion* event) { MouseMoved(gfx::Point(event->x_root, event->y_root), false); return FALSE; } + +void StatusBubbleGtk::AnimationEnded(const Animation* animation) { + UpdateLabelSizeRequest(); +} + +void StatusBubbleGtk::AnimationProgressed(const Animation* animation) { + UpdateLabelSizeRequest(); +} diff --git a/chrome/browser/gtk/status_bubble_gtk.h b/chrome/browser/gtk/status_bubble_gtk.h index c648b8e..497d67e 100644 --- a/chrome/browser/gtk/status_bubble_gtk.h +++ b/chrome/browser/gtk/status_bubble_gtk.h @@ -9,16 +9,18 @@ #include <string> +#include "app/gtk_signal.h" +#include "app/slide_animation.h" #include "base/scoped_ptr.h" -#include "base/task.h" +#include "base/timer.h" #include "chrome/browser/status_bubble.h" #include "chrome/common/notification_observer.h" #include "chrome/common/notification_registrar.h" #include "chrome/common/owned_widget_gtk.h" #include "gfx/point.h" +#include "googleurl/src/gurl.h" class GtkThemeProvider; -class GURL; class Profile; // GTK implementation of StatusBubble. Unlike Windows, our status bubble @@ -26,7 +28,8 @@ class Profile; // window manager to not try to be "helpful" and center our popups, etc. // We therefore position it absolutely in a GtkFixed, that we don't own. class StatusBubbleGtk : public StatusBubble, - public NotificationObserver { + public NotificationObserver, + public AnimationDelegate { public: explicit StatusBubbleGtk(Profile* profile); virtual ~StatusBubbleGtk(); @@ -40,13 +43,15 @@ class StatusBubbleGtk : public StatusBubble, virtual void Hide(); virtual void MouseMoved(const gfx::Point& location, bool left_content); + // AnimationDelegate implementation. + virtual void AnimationEnded(const Animation* animation); + virtual void AnimationProgressed(const Animation* animation); + // Called when the download shelf becomes visible or invisible. // This is used by to ensure that the status bubble does not obscure // the download shelf, when it is visible. virtual void UpdateDownloadShelfVisibility(bool visible); - virtual void SetBubbleWidth(int width); - // Overridden from NotificationObserver: void Observe(NotificationType type, const NotificationSource& source, @@ -62,13 +67,14 @@ class StatusBubbleGtk : public StatusBubble, // with setting the current status or URL text, which may be ignored for now). void SetStatusTextTo(const std::string& status_utf8); + // Sets the status text to the current value of |url_|, eliding it as + // necessary. + void SetStatusTextToURL(); + // Sets the status bubble's location in the parent GtkFixed, shows the widget // and makes sure that the status bubble has the highest z-order. void Show(); - // Sets an internal timer to hide the status bubble after a delay. - void HideInASecond(); - // Builds the widgets, containers, etc. void InitWidgets(); @@ -80,13 +86,22 @@ class StatusBubbleGtk : public StatusBubble, // redraw if necessary. void SetFlipHorizontally(bool flip_horizontally); - static gboolean HandleMotionNotifyThunk(GtkWidget* widget, - GdkEventMotion* event, - gpointer user_data) { - return reinterpret_cast<StatusBubbleGtk*>(user_data)-> - HandleMotionNotify(event); + // Expand the bubble up to the full width of the browser, so that the entire + // URL may be seen. Called after the user hovers over a link for sufficient + // time. + void ExpandURL(); + + // Adjust the actual size of the bubble by changing the label's size request. + void UpdateLabelSizeRequest(); + + // Returns true if the status bubble is in the expand-state (i.e., is + // currently expanded or in the process of expanding). + bool expanded() { + return expand_animation_.get(); } - gboolean HandleMotionNotify(GdkEventMotion* event); + + CHROMEGTK_CALLBACK_1(StatusBubbleGtk, gboolean, HandleMotionNotify, + GdkEventMotion*); NotificationRegistrar registrar_; @@ -105,11 +120,28 @@ class StatusBubbleGtk : public StatusBubble, // The status text we want to display when there are no URLs to display. std::string status_text_; - // The url we want to display when there is no status text to display. + // The URL we are displaying for. + GURL url_; + + // The possibly elided url text we want to display. std::string url_text_; + // Used to determine the character set that the user can read (for eliding + // the url text). + std::wstring languages_; + // A timer that hides our window after a delay. - ScopedRunnableMethodFactory<StatusBubbleGtk> timer_factory_; + base::OneShotTimer<StatusBubbleGtk> hide_timer_; + + // A timer that expands our window after a delay. + base::OneShotTimer<StatusBubbleGtk> expand_timer_; + + // The animation for resizing the status bubble on long hovers. + scoped_ptr<SlideAnimation> expand_animation_; + + // The start and end width of the current resize animation. + int start_width_; + int desired_width_; // Should the bubble be flipped horizontally (e.g. displayed on the right for // an LTR language)? We move the bubble to the other side of the tab contents diff --git a/chrome/browser/status_bubble.h b/chrome/browser/status_bubble.h index 43851be..8ed364f 100644 --- a/chrome/browser/status_bubble.h +++ b/chrome/browser/status_bubble.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -19,6 +19,9 @@ class Point; // class StatusBubble { public: + // On hover, expand status bubble to fit long URL after this delay. + static const int kExpandHoverDelay = 1600; + virtual ~StatusBubble() {} // Sets the bubble contents to a specific string and causes the bubble @@ -49,9 +52,6 @@ class StatusBubble { // This is used by to ensure that the status bubble does not obscure // the download shelf, when it is visible. virtual void UpdateDownloadShelfVisibility(bool visible) = 0; - - // Allow StatusView animation to set width of StatusBubble. - virtual void SetBubbleWidth(int width) = 0; }; #endif // CHROME_BROWSER_STATUS_BUBBLE_H_ diff --git a/chrome/browser/views/status_bubble_views.cc b/chrome/browser/views/status_bubble_views.cc index 1a238026..bd93609 100644 --- a/chrome/browser/views/status_bubble_views.cc +++ b/chrome/browser/views/status_bubble_views.cc @@ -468,7 +468,7 @@ void StatusBubbleViews::StatusView::Paint(gfx::Canvas* canvas) { class StatusBubbleViews::StatusViewExpander : public LinearAnimation, public AnimationDelegate { public: - StatusViewExpander(StatusBubble* status_bubble, + StatusViewExpander(StatusBubbleViews* status_bubble, StatusView* status_view) : ALLOW_THIS_IN_INITIALIZER_LIST(LinearAnimation(kFramerate, this)), status_bubble_(status_bubble), @@ -492,7 +492,7 @@ class StatusBubbleViews::StatusViewExpander : public LinearAnimation, void AnimationEnded(const Animation* animation); // Manager that owns us. - StatusBubble* status_bubble_; + StatusBubbleViews* status_bubble_; // Change the bounds and text of this view. StatusView* status_view_; diff --git a/chrome/browser/views/status_bubble_views.h b/chrome/browser/views/status_bubble_views.h index 4ff9544..4e0b414 100644 --- a/chrome/browser/views/status_bubble_views.h +++ b/chrome/browser/views/status_bubble_views.h @@ -31,9 +31,6 @@ class StatusBubbleViews : public StatusBubble { // The combined vertical padding above and below the text. static const int kTotalVerticalPadding = 7; - // On hover, expand status bubble to fit long URL after this delay. - static const int kExpandHoverDelay = 1600; - explicit StatusBubbleViews(views::Widget* frame); ~StatusBubbleViews(); |