diff options
Diffstat (limited to 'chrome/browser/extensions/extension_shelf.cc')
-rw-r--r-- | chrome/browser/extensions/extension_shelf.cc | 154 |
1 files changed, 140 insertions, 14 deletions
diff --git a/chrome/browser/extensions/extension_shelf.cc b/chrome/browser/extensions/extension_shelf.cc index 0c56833..782ddff 100644 --- a/chrome/browser/extensions/extension_shelf.cc +++ b/chrome/browser/extensions/extension_shelf.cc @@ -16,6 +16,8 @@ #include "chrome/common/notification_service.h" #include "skia/ext/skia_utils.h" #include "views/controls/label.h" +#include "views/screen.h" +#include "views/widget/root_view.h" namespace { @@ -52,6 +54,9 @@ static const int kHandlePadding = 4; // static const SkColor kBackgroundColor = SkColorSetRGB(237, 244, 252); // static const SkColor kTopGradientColor = SkColorSetRGB(222, 234, 248); +// Delays for showing and hiding the shelf handle. +static const int kHideDelayMs = 500; + } // namespace @@ -70,35 +75,41 @@ class ExtensionShelfHandle : public views::View { virtual void Layout(); virtual void OnMouseEntered(const views::MouseEvent& event); virtual void OnMouseExited(const views::MouseEvent& event); + virtual bool OnMousePressed(const views::MouseEvent& event); + virtual bool OnMouseDragged(const views::MouseEvent& event); + virtual void OnMouseReleased(const views::MouseEvent& event, bool canceled); + virtual bool IsFocusable() const { return true; } private: ExtensionShelf* shelf_; ExtensionView* extension_view_; - views::Label* title_; + scoped_ptr<views::Label> title_; + bool dragging_; + gfx::Point initial_drag_location_; DISALLOW_COPY_AND_ASSIGN(ExtensionShelfHandle); }; ExtensionShelfHandle::ExtensionShelfHandle(ExtensionShelf* shelf) - : shelf_(shelf), extension_view_(NULL) { + : shelf_(shelf), extension_view_(NULL), dragging_(false) { 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_| isn't actually put in the view hierarchy. We just use it + // to draw in place. The reason for this is so that we can properly handle + // the various mouse events necessary for hovering and dragging. + title_.reset(new views::Label(L"", rb.GetFont(ResourceBundle::BaseFont))); title_->SetColor(kHandleTextColor); title_->SetDrawHighlighted(true); title_->SetHighlightColor(kHandleTextHighlightColor); title_->SetBounds(kHandlePadding, kHandlePadding, 100, 100); title_->SizeToPreferredSize(); - AddChildView(title_); } void ExtensionShelfHandle::SetExtensionView(ExtensionView* v) { + DCHECK(v->extension()); extension_view_ = v; + if (!extension_view_->extension()) + return; title_->SetText(UTF8ToWide(extension_view_->extension()->name())); title_->SizeToPreferredSize(); SizeToPreferredSize(); @@ -115,15 +126,39 @@ void ExtensionShelfHandle::Paint(gfx::Canvas* canvas) { canvas->FillRectInt(kBorderColor, ext_width, height() - 1, width() - ext_width, 1); } + + // Draw the title using a Label as a stamp. + // See constructor for comment about this. + title_->ProcessPaint(canvas); + + if (dragging_) { + // when we're dragging, draw the bottom border. + canvas->FillRectInt(kBorderColor, 0, height() - 1, width(), 1); + } } gfx::Size ExtensionShelfHandle::GetPreferredSize() { gfx::Size sz = title_->GetPreferredSize(); + if (extension_view_) { + int width = std::max(extension_view_->width() + 2, sz.width()); + sz.set_width(width); + } sz.Enlarge(kHandlePadding * 2, kHandlePadding * 2); + if (dragging_) { + gfx::Size extension_size = extension_view_->GetPreferredSize(); + sz.Enlarge(0, extension_size.height() + 2); + } return sz; } void ExtensionShelfHandle::Layout() { + if (dragging_) { + int y = title_->bounds().bottom() + kHandlePadding + 1; + extension_view_->SetBounds(1, + y, + extension_view_->width(), + extension_view_->height()); + } } void ExtensionShelfHandle::OnMouseEntered(const views::MouseEvent& event) { @@ -136,6 +171,42 @@ void ExtensionShelfHandle::OnMouseExited(const views::MouseEvent& event) { shelf_->OnExtensionMouseLeave(extension_view_); } +bool ExtensionShelfHandle::OnMousePressed(const views::MouseEvent& event) { + initial_drag_location_ = event.location(); + return true; +} + +bool ExtensionShelfHandle::OnMouseDragged(const views::MouseEvent& event) { + if (!dragging_) { + int y_delta = abs(initial_drag_location_.y() - event.location().y()); + if (y_delta > GetVerticalDragThreshold()) { + dragging_ = true; + shelf_->DragExtension(); + } + } else { + // When freely dragging a window, you can really only trust the + // actual screen point. Coordinate conversions, just don't work. + gfx::Point screen = views::Screen::GetCursorScreenPoint(); + + // However, the handle is actually a child of the browser window + // so we need to convert it back to local coordinates. + gfx::Point origin(0, 0); + views::View::ConvertPointToScreen(shelf_->GetRootView(), &origin); + screen.set_x(screen.x() - origin.x() - initial_drag_location_.x()); + screen.set_y(screen.y() - origin.y() - initial_drag_location_.y()); + shelf_->DragHandleTo(screen); + } + return true; +} + +void ExtensionShelfHandle::OnMouseReleased(const views::MouseEvent& event, + bool canceled) { + if (dragging_) { + views::View::OnMouseReleased(event, canceled); + dragging_ = false; + shelf_->DropExtension(event.location(), canceled); + } +} //////////////////////////////////////////////// @@ -144,7 +215,8 @@ ExtensionShelf::ExtensionShelf(Browser* browser) handle_(NULL), handle_visible_(false), current_handle_view_(NULL), - ALLOW_THIS_IN_INITIALIZER_LIST(timer_factory_(this)) { + ALLOW_THIS_IN_INITIALIZER_LIST(timer_factory_(this)), + drag_placeholder_view_(NULL) { // Watch extensions loaded and unloaded notifications. registrar_.Add(this, NotificationType::EXTENSIONS_LOADED, NotificationService::AllSources()); @@ -253,7 +325,7 @@ void ExtensionShelf::OnMouseEntered(const views::MouseEvent& event) { } void ExtensionShelf::OnMouseExited(const views::MouseEvent& event) { - HideShelfHandle(100); + HideShelfHandle(kHideDelayMs); } void ExtensionShelf::Observe(NotificationType type, @@ -332,6 +404,9 @@ bool ExtensionShelf::HasExtensionViews() { } void ExtensionShelf::OnExtensionMouseEvent(ExtensionView* view) { + // Ignore these events when dragging. + if (drag_placeholder_view_) + return; if (view != current_handle_view_) { current_handle_view_ = view; } @@ -339,8 +414,11 @@ void ExtensionShelf::OnExtensionMouseEvent(ExtensionView* view) { } void ExtensionShelf::OnExtensionMouseLeave(ExtensionView* view) { + // Ignore these events when dragging. + if (drag_placeholder_view_) + return; if (view == current_handle_view_) { - HideShelfHandle(100); + HideShelfHandle(kHideDelayMs); } } @@ -353,6 +431,50 @@ void ExtensionShelf::BubbleBrowserWindowClosed(BrowserBubble* bubble) { HideShelfHandle(0); } +void ExtensionShelf::DragExtension() { + // Construct a placeholder view to replace the view. + // TODO(erikkay) the placeholder should draw a dimmed version of the + // extension view + int index = GetChildIndex(current_handle_view_); + drag_placeholder_view_ = new View(); + drag_placeholder_view_->SetBounds(current_handle_view_->bounds()); + AddChildView(index, drag_placeholder_view_); + + // Now move the view into the handle's widget. + ExtensionShelfHandle* handle_view = + static_cast<ExtensionShelfHandle*>(GetHandle()->view()); + handle_view->AddChildView(current_handle_view_); + handle_view->SizeToPreferredSize(); + handle_->ResizeToView(); + handle_view->Layout(); + handle_->DetachFromBrowser(); + SchedulePaint(); +} + +void ExtensionShelf::DropExtension(const gfx::Point& pt, bool cancel) { + handle_->AttachToBrowser(); + + // Replace the placeholder view with the original. + int index = GetChildIndex(drag_placeholder_view_); + AddChildView(index, current_handle_view_); + current_handle_view_->SetBounds(drag_placeholder_view_->bounds()); + RemoveChildView(drag_placeholder_view_); + delete drag_placeholder_view_; + drag_placeholder_view_ = NULL; + + ExtensionShelfHandle* handle_view = + static_cast<ExtensionShelfHandle*>(GetHandle()->view()); + handle_view->SizeToPreferredSize(); + handle_view->Layout(); + handle_->ResizeToView(); + LayoutShelfHandle(); + SchedulePaint(); +} + +void ExtensionShelf::DragHandleTo(const gfx::Point& pt) { + handle_->MoveTo(pt.x(), pt.y()); +} + void ExtensionShelf::InitBackground(gfx::Canvas* canvas, const SkRect& subset) { if (!background_.empty()) @@ -389,6 +511,8 @@ void ExtensionShelf::InitBackground(gfx::Canvas* canvas, } void ExtensionShelf::ShowShelfHandle() { + if (drag_placeholder_view_) + return; if (!timer_factory_.empty()) timer_factory_.RevokeAll(); if (handle_visible_) { @@ -410,6 +534,8 @@ void ExtensionShelf::DoShowShelfHandle() { } void ExtensionShelf::HideShelfHandle(int delay_ms) { + if (drag_placeholder_view_) + return; if (!timer_factory_.empty()) timer_factory_.RevokeAll(); if (!handle_visible_) @@ -427,8 +553,8 @@ 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); + handle_->DetachFromBrowser(); + handle_.reset(NULL); current_handle_view_ = NULL; } } |