diff options
author | erikkay@google.com <erikkay@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-18 16:40:39 +0000 |
---|---|---|
committer | erikkay@google.com <erikkay@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-18 16:40:39 +0000 |
commit | 0d3bd4daa8b2b851dca9410a18ec5981c1086fc7 (patch) | |
tree | 6d6ce3d0aa0bba59e274d32a8f40a96b3dbd0c7b /chrome | |
parent | 89d7ac15b518146cc57a7cc8df6b73bcf36a1c19 (diff) | |
download | chromium_src-0d3bd4daa8b2b851dca9410a18ec5981c1086fc7.zip chromium_src-0d3bd4daa8b2b851dca9410a18ec5981c1086fc7.tar.gz chromium_src-0d3bd4daa8b2b851dca9410a18ec5981c1086fc7.tar.bz2 |
Add a handle to the ExtensionShelf. This is how users will drag extension toolstrips around, and perhaps where we'll add other UI for manipulating an extension.
BUG=none
TEST=none
depends on the following other changes:
http://codereview.chromium.org/113481
http://codereview.chromium.org/113486
http://codereview.chromium.org/113466
Review URL: http://codereview.chromium.org/113483
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16284 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/extensions/extension_host.cc | 10 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_host.h | 2 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_shelf.cc | 215 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_shelf.h | 52 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_view.cc | 12 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_view.h | 19 |
6 files changed, 305 insertions, 5 deletions
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc index e2f202a..a38fdd5 100644 --- a/chrome/browser/extensions/extension_host.cc +++ b/chrome/browser/extensions/extension_host.cc @@ -155,6 +155,16 @@ void ExtensionHost::TakeFocus(bool reverse) { void ExtensionHost::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) { } +void ExtensionHost::HandleMouseEvent() { + if (view_) + view_->HandleMouseEvent(); +} + +void ExtensionHost::HandleMouseLeave() { + if (view_) + view_->HandleMouseLeave(); +} + Browser* ExtensionHost::GetBrowser() { if (view_) return view_->browser(); diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h index d8e9a50..a6e19d9 100644 --- a/chrome/browser/extensions/extension_host.h +++ b/chrome/browser/extensions/extension_host.h @@ -72,6 +72,8 @@ class ExtensionHost : public RenderViewHostDelegate, virtual void UpdateDragCursor(bool is_drop_target); virtual void TakeFocus(bool reverse); virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event); + virtual void HandleMouseEvent(); + virtual void HandleMouseLeave(); virtual void UpdatePreferredWidth(int pref_width); private: diff --git a/chrome/browser/extensions/extension_shelf.cc b/chrome/browser/extensions/extension_shelf.cc index 6b765d8..17623b6 100644 --- a/chrome/browser/extensions/extension_shelf.cc +++ b/chrome/browser/extensions/extension_shelf.cc @@ -4,7 +4,9 @@ #include "chrome/browser/extensions/extension_shelf.h" +#include "app/resource_bundle.h" #include "base/logging.h" +#include "base/string_util.h" #include "chrome/browser/browser.h" #include "chrome/browser/extensions/extension.h" #include "chrome/browser/extensions/extension_process_manager.h" @@ -13,6 +15,7 @@ #include "chrome/browser/profile.h" #include "chrome/common/notification_service.h" #include "skia/ext/skia_utils.h" +#include "views/controls/label.h" namespace { @@ -36,6 +39,14 @@ static const SkColor kBackgroundColor = SkColorSetRGB(230, 237, 244); static const SkColor kBorderColor = SkColorSetRGB(201, 212, 225); static const SkColor kDividerHighlightColor = SkColorSetRGB(247, 250, 253); +// Text colors for the handle +static const SkColor kHandleTextColor = SkColorSetRGB(6, 45, 117); +static const SkColor kHandleTextHighlightColor = + SkColorSetARGB(200, 255, 255, 255); + +// Handle padding +static const int kHandlePadding = 4; + // TODO(erikkay) convert back to a gradient when Glen figures out the // specs. // static const SkColor kBackgroundColor = SkColorSetRGB(237, 244, 252); @@ -44,7 +55,96 @@ static const SkColor kDividerHighlightColor = SkColorSetRGB(247, 250, 253); } // namespace -ExtensionShelf::ExtensionShelf(Browser* browser) : browser_(browser) { +// A small handle that is used for dragging or otherwise interacting with an +// extension toolstrip. +class ExtensionShelfHandle : public views::View { + public: + explicit ExtensionShelfHandle(ExtensionShelf* shelf); + + // The ExtensionView that the handle is attached to. + void SetExtensionView(ExtensionView* v); + + // View + virtual void Paint(gfx::Canvas* canvas); + virtual gfx::Size GetPreferredSize(); + virtual void Layout(); + virtual void OnMouseEntered(const views::MouseEvent& event); + virtual void OnMouseExited(const views::MouseEvent& event); + + private: + ExtensionShelf* shelf_; + ExtensionView* extension_view_; + views::Label* title_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionShelfHandle); +}; + +ExtensionShelfHandle::ExtensionShelfHandle(ExtensionShelf* shelf) + : shelf_(shelf), extension_view_(NULL) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + title_ = new views::Label(L"", rb.GetFont(ResourceBundle::BaseFont)); + + // Set enabled to false so we get the events. + title_->SetEnabled(false); + + // Set the colors afterwards so that the label doesn't get a disabled + // color. + title_->SetColor(kHandleTextColor); + title_->SetDrawHighlighted(true); + title_->SetHighlightColor(kHandleTextHighlightColor); + title_->SetBounds(kHandlePadding, kHandlePadding, 100, 100); + title_->SizeToPreferredSize(); + AddChildView(title_); +} + +void ExtensionShelfHandle::SetExtensionView(ExtensionView* v) { + extension_view_ = v; + title_->SetText(UTF8ToWide(extension_view_->extension()->name())); + title_->SizeToPreferredSize(); + SizeToPreferredSize(); +} + +void ExtensionShelfHandle::Paint(gfx::Canvas* canvas) { + canvas->FillRectInt(kBackgroundColor, 0, 0, width(), height()); + canvas->FillRectInt(kBorderColor, 0, 0, width(), 1); + canvas->FillRectInt(kBorderColor, 0, 0, 1, height() - 1); + canvas->FillRectInt(kBorderColor, width() - 1, 0, 1, height() - 1); + int ext_width = extension_view_->width() + kToolstripPadding + + kToolstripDividerWidth; + if (ext_width < width()) { + canvas->FillRectInt(kBorderColor, ext_width, height() - 1, + width() - ext_width, 1); + } +} + +gfx::Size ExtensionShelfHandle::GetPreferredSize() { + gfx::Size sz = title_->GetPreferredSize(); + sz.Enlarge(kHandlePadding * 2, kHandlePadding * 2); + return sz; +} + +void ExtensionShelfHandle::Layout() { +} + +void ExtensionShelfHandle::OnMouseEntered(const views::MouseEvent& event) { + DCHECK(extension_view_); + shelf_->OnExtensionMouseEvent(extension_view_); +} + +void ExtensionShelfHandle::OnMouseExited(const views::MouseEvent& event) { + DCHECK(extension_view_); + shelf_->OnExtensionMouseLeave(extension_view_); +} + + +//////////////////////////////////////////////// + +ExtensionShelf::ExtensionShelf(Browser* browser) + : browser_(browser), + handle_(NULL), + handle_visible_(false), + current_handle_view_(NULL), + ALLOW_THIS_IN_INITIALIZER_LIST(timer_factory_(this)) { // Watch extensions loaded notification. NotificationService* ns = NotificationService::current(); Source<Profile> ns_source(browser->profile()->GetOriginalProfile()); @@ -68,6 +168,17 @@ ExtensionShelf::~ExtensionShelf() { NotificationService::AllSources()); } +BrowserBubble* ExtensionShelf::GetHandle() { + if (!handle_.get() && HasExtensionViews() && current_handle_view_) { + ExtensionShelfHandle* handle_view = new ExtensionShelfHandle(this); + handle_view->SetExtensionView(current_handle_view_); + handle_.reset(new BrowserBubble(handle_view, GetWidget(), + gfx::Point(0, 0))); + handle_->set_delegate(this); + } + return handle_.get(); +} + void ExtensionShelf::Paint(gfx::Canvas* canvas) { #if 0 // TODO(erikkay) re-enable this when Glen has the gradient values worked out. @@ -130,9 +241,27 @@ void ExtensionShelf::Layout() { child->Layout(); x = next_x + kToolstripDividerWidth; } + if (handle_.get()) + LayoutShelfHandle(); SchedulePaint(); } +void ExtensionShelf::OnMouseEntered(const views::MouseEvent& event) { + int count = GetChildViewCount(); + for (int i = 0; i < count; ++i) { + ExtensionView* child = static_cast<ExtensionView*>(GetChildViewAt(i)); + if (event.x() > (child->x() + child->width() + kToolstripPadding)) + continue; + current_handle_view_ = child; + ShowShelfHandle(); + break; + } +} + +void ExtensionShelf::OnMouseExited(const views::MouseEvent& event) { + HideShelfHandle(100); +} + void ExtensionShelf::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { @@ -165,6 +294,7 @@ bool ExtensionShelf::AddExtensionViews(const ExtensionList* extensions) { if (!background_.empty()) toolstrip->SetBackground(background_); AddChildView(toolstrip); + toolstrip->SetContainer(this); added_toolstrip = true; } } @@ -180,6 +310,28 @@ bool ExtensionShelf::HasExtensionViews() { return GetChildViewCount() > 0; } +void ExtensionShelf::OnExtensionMouseEvent(ExtensionView* view) { + if (view != current_handle_view_) { + current_handle_view_ = view; + } + ShowShelfHandle(); +} + +void ExtensionShelf::OnExtensionMouseLeave(ExtensionView* view) { + if (view == current_handle_view_) { + HideShelfHandle(100); + } +} + +void ExtensionShelf::BubbleBrowserWindowMoved(BrowserBubble* bubble) { + HideShelfHandle(0); +} + +void ExtensionShelf::BubbleBrowserWindowClosed(BrowserBubble* bubble) { + // We'll be going away shortly, so no need to do any other teardown here. + HideShelfHandle(0); +} + void ExtensionShelf::InitBackground(gfx::Canvas* canvas, const SkRect& subset) { if (!background_.empty()) @@ -214,3 +366,64 @@ void ExtensionShelf::InitBackground(gfx::Canvas* canvas, for (int i = 0; i < count; ++i) static_cast<ExtensionView*>(GetChildViewAt(i))->SetBackground(background_); } + +void ExtensionShelf::ShowShelfHandle() { + if (!timer_factory_.empty()) + timer_factory_.RevokeAll(); + if (handle_visible_) { + // The contents may have changed, even though the handle is still visible. + LayoutShelfHandle(); + return; + } + MessageLoop::current()->PostDelayedTask(FROM_HERE, + timer_factory_.NewRunnableMethod(&ExtensionShelf::DoShowShelfHandle), + 1000); +} + +void ExtensionShelf::DoShowShelfHandle() { + if (!handle_visible_) { + handle_visible_ = true; + LayoutShelfHandle(); + handle_->Show(); + } +} + +void ExtensionShelf::HideShelfHandle(int delay_ms) { + if (!timer_factory_.empty()) + timer_factory_.RevokeAll(); + if (!handle_visible_) + return; + if (delay_ms) { + MessageLoop::current()->PostDelayedTask(FROM_HERE, + timer_factory_.NewRunnableMethod(&ExtensionShelf::DoHideShelfHandle), + delay_ms); + } else { + DoHideShelfHandle(); + } +} + +void ExtensionShelf::DoHideShelfHandle() { + if (handle_visible_) { + handle_visible_ = false; + handle_->Hide(); + // TODO(erikkay) with this enabled, I get an odd crash shortly after hide. + //handle_.reset(NULL); + current_handle_view_ = NULL; + } +} + +void ExtensionShelf::LayoutShelfHandle() { + if (current_handle_view_) { + GetHandle(); // ensure that the handle exists since we delete on hide + ExtensionShelfHandle* handle_view = + static_cast<ExtensionShelfHandle*>(GetHandle()->view()); + handle_view->SetExtensionView(current_handle_view_); + int width = std::max(current_handle_view_->width(), handle_view->width()); + gfx::Point origin(-kToolstripPadding, + -(handle_view->height() + kToolstripPadding - 1)); + views::View::ConvertPointToWidget(current_handle_view_, &origin); + handle_view->SetBounds(0, 0, width, handle_view->height()); + handle_->SetBounds(origin.x(), origin.y(), + width, handle_view->height()); + } +} diff --git a/chrome/browser/extensions/extension_shelf.h b/chrome/browser/extensions/extension_shelf.h index ccfa745..4bc88eb 100644 --- a/chrome/browser/extensions/extension_shelf.h +++ b/chrome/browser/extensions/extension_shelf.h @@ -5,25 +5,41 @@ #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_SHELF_H_ #define CHROME_BROWSER_EXTENSIONS_EXTENSION_SHELF_H_ -#include "chrome/browser/extensions/extensions_service.h" #include "app/gfx/canvas.h" +#include "base/task.h" +#include "chrome/browser/extensions/extension_view.h" +#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/views/browser_bubble.h" #include "chrome/common/notification_observer.h" #include "views/view.h" class Browser; +class ExtensionShelfHandle; +namespace views { + class Label; + class MouseEvent; +} +// A shelf that contains Extension toolstrips. class ExtensionShelf : public views::View, - public NotificationObserver { + public NotificationObserver, + public ExtensionContainer, + public BrowserBubble::Delegate { public: explicit ExtensionShelf(Browser* browser); virtual ~ExtensionShelf(); + // Return the current active ExtensionShelfHandle (if any). + BrowserBubble* GetHandle(); + // View virtual void Paint(gfx::Canvas* canvas); virtual gfx::Size GetPreferredSize(); virtual void Layout(); + virtual void OnMouseExited(const views::MouseEvent& event); + virtual void OnMouseEntered(const views::MouseEvent& event); - // NotificationService method. + // NotificationService virtual void Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details); @@ -31,6 +47,14 @@ class ExtensionShelf : public views::View, bool AddExtensionViews(const ExtensionList* extensions); bool HasExtensionViews(); + // ExtensionContainer + virtual void OnExtensionMouseEvent(ExtensionView* view); + virtual void OnExtensionMouseLeave(ExtensionView* view); + + // BrowserBubble::Delegate + virtual void BubbleBrowserWindowMoved(BrowserBubble* bubble); + virtual void BubbleBrowserWindowClosed(BrowserBubble* bubble); + protected: // View virtual void ChildPreferredSizeChanged(View* child); @@ -39,11 +63,33 @@ class ExtensionShelf : public views::View, // Inits the background bitmap. void InitBackground(gfx::Canvas* canvas, const SkRect& subset); + // Show / Hide the shelf handle. + void ShowShelfHandle(); + void DoShowShelfHandle(); + void HideShelfHandle(int delay_ms); + void DoHideShelfHandle(); + + // Adjust shelf handle size and position. + void LayoutShelfHandle(); + + // Which browser window this shelf is in. Browser* browser_; // Background bitmap to draw under extension views. SkBitmap background_; + // The current shelf handle. + scoped_ptr<BrowserBubble> handle_; + + // Whether to handle is visible; + bool handle_visible_; + + // Which child view the handle is currently over. + ExtensionView* current_handle_view_; + + // Timers for tracking mouse hovering. + ScopedRunnableMethodFactory<ExtensionShelf> timer_factory_; + DISALLOW_COPY_AND_ASSIGN(ExtensionShelf); }; diff --git a/chrome/browser/extensions/extension_view.cc b/chrome/browser/extensions/extension_view.cc index 38028d7..a3a6bc5 100644 --- a/chrome/browser/extensions/extension_view.cc +++ b/chrome/browser/extensions/extension_view.cc @@ -15,7 +15,7 @@ ExtensionView::ExtensionView(ExtensionHost* host, Browser* browser, const GURL& content_url) : host_(host), browser_(browser), content_url_(content_url), - initialized_(false) { + initialized_(false), container_(NULL) { host_->set_view(this); } @@ -114,3 +114,13 @@ void ExtensionView::ViewHierarchyChanged(bool is_add, } } } + +void ExtensionView::HandleMouseEvent() { + if (container_) + container_->OnExtensionMouseEvent(this); +} + +void ExtensionView::HandleMouseLeave() { + if (container_) + container_->OnExtensionMouseLeave(this); +} diff --git a/chrome/browser/extensions/extension_view.h b/chrome/browser/extensions/extension_view.h index d58fdc7..6f27249 100644 --- a/chrome/browser/extensions/extension_view.h +++ b/chrome/browser/extensions/extension_view.h @@ -23,6 +23,15 @@ class Browser; class Extension; +// A class that represents the container that this view is in. +// (bottom shelf, side bar, etc.) +class ExtensionContainer { + public: + // Mouse event notifications from the view. (useful for hover UI). + virtual void OnExtensionMouseEvent(ExtensionView* view) = 0; + virtual void OnExtensionMouseLeave(ExtensionView* view) = 0; +}; + // This handles the display portion of an ExtensionHost. class ExtensionView : public views::HWNDView { public: @@ -36,16 +45,22 @@ class ExtensionView : public views::HWNDView { // Notification from ExtensionHost. void DidContentsPreferredWidthChange(const int pref_width); + void HandleMouseEvent(); + void HandleMouseLeave(); // Set a custom background for the view. The background will be tiled. void SetBackground(const SkBitmap& background); + // Sets the container for this view. + void SetContainer(ExtensionContainer* container) { container_ = container; } + // views::HWNDView virtual void SetVisible(bool is_visible); virtual void DidChangeBounds(const gfx::Rect& previous, const gfx::Rect& current); virtual void ViewHierarchyChanged(bool is_add, views::View *parent, views::View *child); + private: friend class ExtensionHost; @@ -72,6 +87,10 @@ class ExtensionView : public views::HWNDView { // loaded. int pending_preferred_width_; + // The container this view is in (not necessarily its direct superview). + // Note: the view does not own its container. + ExtensionContainer* container_; + DISALLOW_COPY_AND_ASSIGN(ExtensionView); }; |