| Index: chrome/browser/extensions/extension_shelf.cc
|
| ===================================================================
|
| --- chrome/browser/extensions/extension_shelf.cc (revision 17478)
|
| +++ chrome/browser/extensions/extension_shelf.cc (working copy)
|
| @@ -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 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 @@
|
| 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 @@
|
| 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,7 +171,43 @@
|
| 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);
|
| + }
|
| +}
|
| +
|
| ////////////////////////////////////////////////
|
|
|
| ExtensionShelf::ExtensionShelf(Browser* browser)
|
| @@ -144,7 +215,8 @@
|
| 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::OnMouseExited(const views::MouseEvent& event) {
|
| - HideShelfHandle(100);
|
| + HideShelfHandle(kHideDelayMs);
|
| }
|
|
|
| void ExtensionShelf::Observe(NotificationType type,
|
| @@ -332,6 +404,9 @@
|
| }
|
|
|
| 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::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 @@
|
| 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::ShowShelfHandle() {
|
| + if (drag_placeholder_view_)
|
| + return;
|
| if (!timer_factory_.empty())
|
| timer_factory_.RevokeAll();
|
| if (handle_visible_) {
|
| @@ -410,6 +534,8 @@
|
| }
|
|
|
| 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 @@
|
| 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;
|
| }
|
| }
|
|
|