diff options
author | skuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-24 14:37:57 +0000 |
---|---|---|
committer | skuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-24 14:37:57 +0000 |
commit | 28fb77a6148d028bce84e9c8a62ba98c02e5484d (patch) | |
tree | c695c78df574b4a2c4d463a523a1965ecd5e536a /ash/launcher/launcher_view.cc | |
parent | e42cb727b87b6a6d671ea686798b92ada92b3688 (diff) | |
download | chromium_src-28fb77a6148d028bce84e9c8a62ba98c02e5484d.zip chromium_src-28fb77a6148d028bce84e9c8a62ba98c02e5484d.tar.gz chromium_src-28fb77a6148d028bce84e9c8a62ba98c02e5484d.tar.bz2 |
Adding business logic for dragging items from shelf to the desktop to unpin
The new feature has to be enabled by a new flag and this part of the implementation is ...
... adding the business logic to enable the dragging and removing.
... cleaning up a few things.
The still required changes are marked with TODO's accordingly.
BUG=249081
TEST=Unittest
Review URL: https://chromiumcodereview.appspot.com/23338004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@219436 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash/launcher/launcher_view.cc')
-rw-r--r-- | ash/launcher/launcher_view.cc | 144 |
1 files changed, 135 insertions, 9 deletions
diff --git a/ash/launcher/launcher_view.cc b/ash/launcher/launcher_view.cc index b6095a8..eb7cefb 100644 --- a/ash/launcher/launcher_view.cc +++ b/ash/launcher/launcher_view.cc @@ -98,6 +98,12 @@ const SkColor kCaptionItemForegroundColor = SK_ColorBLACK; // The maximum allowable length of a menu line of an application menu in pixels. const int kMaximumAppMenuItemLength = 350; +// The distance of the cursor from the outer rim of the shelf before it +// separates / re-inserts. Note that the rip off distance is bigger then the +// re-insertion distance to avoid "flickering" between the two states. +const int kRipOffDistance = 48; +const int kReinsertDistance = 32; + namespace { // The MenuModelAdapter gets slightly changed to adapt the menu appearance to @@ -401,7 +407,8 @@ LauncherView::LauncherView(LauncherModel* model, closing_event_time_(base::TimeDelta()), got_deleted_(NULL), drag_and_drop_item_pinned_(false), - drag_and_drop_launcher_id_(0) { + drag_and_drop_launcher_id_(0), + dragged_off_shelf_(false) { DCHECK(model_); bounds_animator_.reset(new views::BoundsAnimator(this)); bounds_animator_->AddObserver(this); @@ -670,7 +677,7 @@ void LauncherView::EndDrag(bool cancel) { // Either destroy the temporarily created item - or - make the item visible. if (drag_and_drop_item_pinned_ && cancel) - delegate_->UnpinAppsWithID(drag_and_drop_app_id_); + delegate_->UnpinAppWithID(drag_and_drop_app_id_); else if (drag_and_drop_view) drag_and_drop_view->SetSize(pre_drag_and_drop_size_); @@ -987,21 +994,29 @@ void LauncherView::PrepareForDrag(Pointer pointer, } void LauncherView::ContinueDrag(const ui::LocatedEvent& event) { - ShelfLayoutManager* shelf = tooltip_->shelf_layout_manager(); - - // TODO: I don't think this works correctly with RTL. - gfx::Point drag_point(event.location()); - views::View::ConvertPointToTarget(drag_view_, this, &drag_point); + // Due to a syncing operation the application might have been removed. + // Bail if it is gone. int current_index = view_model_->GetIndexOfView(drag_view_); DCHECK_NE(-1, current_index); - - // If the item is no longer draggable, bail out. if (current_index == -1 || !delegate_->IsDraggable(model_->items()[current_index])) { CancelDrag(-1); return; } + // If this is not a drag and drop host operation, check if the item got + // ripped off the shelf - if it did we are done. + if (!drag_and_drop_launcher_id_ && ash::switches::UseDragOffShelf()) { + if (HandleRipOffDrag(event)) + return; + // The rip off handler could have changed the location of the item. + current_index = view_model_->GetIndexOfView(drag_view_); + } + + // TODO: I don't think this works correctly with RTL. + gfx::Point drag_point(event.location()); + views::View::ConvertPointToTarget(drag_view_, this, &drag_point); + // Constrain the location to the range of valid indices for the type. std::pair<int, int> indices(GetDragRange(current_index)); int first_drag_index = indices.first; @@ -1012,6 +1027,7 @@ void LauncherView::ContinueDrag(const ui::LocatedEvent& event) { last_drag_index > last_visible_index_) last_drag_index = last_visible_index_; int x = 0, y = 0; + ShelfLayoutManager* shelf = tooltip_->shelf_layout_manager(); if (shelf->IsHorizontalAlignment()) { x = std::max(view_model_->ideal_bounds(indices.first).x(), drag_point.x() - drag_offset_); @@ -1050,6 +1066,91 @@ void LauncherView::ContinueDrag(const ui::LocatedEvent& event) { bounds_animator_->StopAnimatingView(drag_view_); } +bool LauncherView::HandleRipOffDrag(const ui::LocatedEvent& event) { + // Determine the distance to the shelf. + int delta = CalculateShelfDistance(event.root_location()); + int current_index = view_model_->GetIndexOfView(drag_view_); + DCHECK_NE(-1, current_index); + // To avoid ugly forwards and backwards flipping we use different constants + // for ripping off / re-inserting the items. + if (dragged_off_shelf_) { + // If the re-insertion distance is undercut we insert the item back into + // the shelf. Note that the reinsertion value is slightly smaller then the + // rip off distance to avoid flickering. + if (delta < kReinsertDistance) { + // Destroy our proxy view item. + // TODO(skuhne): Do it! + // Re-insert the item and return simply false since the caller will handle + // the move as in any normal case. + dragged_off_shelf_ = false; + drag_view_->layer()->SetOpacity(1.0f); + return false; + } + // Move our proxy view item. + // TODO(skuhne): Do it! + return true; + } + // Check if we are too far away from the shelf to enter the ripped off state. + if (delta > kRipOffDistance) { + // Create a proxy view item which can be moved anywhere. + // TODO(skuhne): Do it! + // Move the item to the end of the launcher and hide it. + drag_view_->layer()->SetOpacity(0.0f); + model_->Move(current_index, model_->item_count() - 1); + AnimateToIdealBounds(); + dragged_off_shelf_ = true; + return true; + } + return false; +} + +void LauncherView::FinalizeRipOffDrag(bool cancel) { + if (!dragged_off_shelf_) + return; + // Make sure we do not come in here again. + dragged_off_shelf_ = false; + + // Coming here we should always have a |drag_view_|. + DCHECK(drag_view_); + int current_index = view_model_->GetIndexOfView(drag_view_); + // If the view isn't part of the model anymore, a sync operation must have + // removed it. In that case we shouldn't change the model and only delete the + // proxy image. + if (current_index == -1) { + // TODO(skuhne): Destroy the proxy immediately. + } else { + // Items which cannot be dragged off will be handled as a cancel. + if (!cancel) { + // Make sure we do not try to remove un-removable items like items which + // were not pinned or have to be always there. + LauncherItemType type = model_->items()[current_index].type; + std::string app_id = + delegate_->GetAppIDForLauncherID(model_->items()[current_index].id); + if (type == TYPE_APP_LIST || + type == TYPE_BROWSER_SHORTCUT || + !delegate_->IsAppPinned(app_id)) { + cancel = true; + } else { + // Make sure the item stays invisible upon removal. + drag_view_->SetVisible(false); + delegate_->UnpinAppWithID(app_id); + } + } + if (cancel) { + // TODO(skuhne): This is not correct since it shows the animation from + // the outer rim towards the old location instead of the animation from + // the proxy towards the original location. + if (!cancelling_drag_model_changed_) { + // When a cancelling drag model is happening, the view model is diverged + // from the menu model and movements / animations should not be done. + model_->Move(current_index, start_drag_index_); + AnimateToIdealBounds(); + } + drag_view_->layer()->SetOpacity(1.0f); + } + } +} + bool LauncherView::SameDragType(LauncherItemType typea, LauncherItemType typeb) const { switch (typea) { @@ -1168,6 +1269,7 @@ bool LauncherView::ShouldHideTooltip(const gfx::Point& cursor_location) { } int LauncherView::CancelDrag(int modified_index) { + FinalizeRipOffDrag(true); if (!drag_view_) return modified_index; bool was_dragging = dragging(); @@ -1425,6 +1527,7 @@ void LauncherView::PointerReleasedOnButton(views::View* view, if (canceled) { CancelDrag(-1); } else if (drag_pointer_ == pointer) { + FinalizeRipOffDrag(false); drag_pointer_ = NONE; AnimateToIdealBounds(); } @@ -1716,5 +1819,28 @@ bool LauncherView::ShouldShowTooltipForView(const views::View* view) const { return (!item || delegate_->ShouldShowTooltip(*item)); } +int LauncherView::CalculateShelfDistance(const gfx::Point& coordinate) const { + ShelfWidget* shelf = RootWindowController::ForLauncher( + GetWidget()->GetNativeView())->shelf(); + ash::ShelfAlignment align = shelf->GetAlignment(); + const gfx::Rect bounds = GetBoundsInScreen(); + int distance = 0; + switch (align) { + case ash::SHELF_ALIGNMENT_BOTTOM: + distance = bounds.y() - coordinate.y(); + break; + case ash::SHELF_ALIGNMENT_LEFT: + distance = coordinate.x() - bounds.right(); + break; + case ash::SHELF_ALIGNMENT_RIGHT: + distance = bounds.x() - coordinate.x(); + break; + case ash::SHELF_ALIGNMENT_TOP: + distance = coordinate.y() - bounds.bottom(); + break; + } + return distance > 0 ? distance : 0; +} + } // namespace internal } // namespace ash |