Index: ui/app_list/views/apps_grid_view.cc |
diff --git a/ui/app_list/views/apps_grid_view.cc b/ui/app_list/views/apps_grid_view.cc |
index d371ed90cf3fcde99ec0346fef9ec865d881b169..5625c6d4ad0626093849bbf1aff6338f9f471d00 100644 |
--- a/ui/app_list/views/apps_grid_view.cc |
+++ b/ui/app_list/views/apps_grid_view.cc |
@@ -21,6 +21,7 @@ |
#include "ui/app_list/views/apps_grid_view_delegate.h" |
#include "ui/app_list/views/page_switcher.h" |
#include "ui/app_list/views/pulsing_block_view.h" |
+#include "ui/app_list/views/top_icon_animation_view.h" |
#include "ui/compositor/scoped_layer_animation_settings.h" |
#include "ui/events/event.h" |
#include "ui/gfx/animation/animation.h" |
@@ -86,6 +87,9 @@ const int kFolderDroppingDelay = 250; |
// Delays in milliseconds to show re-order preview. |
const int kReorderDelay = 50; |
+// Delays in milliseconds to show folder item reparent UI. |
+const int kFolderItemReparentDealy = 50; |
+ |
// Radius of the circle, in which if entered, show folder dropping preview |
// UI. |
const int kFolderDroppingCircleRadius = 15; |
@@ -316,7 +320,8 @@ AppsGridView::AppsGridView(AppsGridViewDelegate* delegate, |
page_flip_delay_in_ms_(kPageFlipDelayInMs), |
bounds_animator_(this), |
is_root_level_(true), |
- activated_item_view_(NULL) { |
+ activated_item_view_(NULL), |
+ dragging_for_reparent_item_(false) { |
SetPaintToLayer(true); |
SetFillsBoundsOpaquely(false); |
@@ -478,6 +483,9 @@ void AppsGridView::UpdateDragFromItem(Pointer pointer, |
const ui::LocatedEvent& event) { |
DCHECK(drag_view_); |
+ if (!is_root_level_) |
+ UpdateDragStateInsideFolder(pointer, event); |
+ |
gfx::Point drag_point_in_grid_view; |
ExtractDragLocation(event, &drag_point_in_grid_view); |
UpdateDrag(pointer, drag_point_in_grid_view); |
@@ -508,7 +516,8 @@ void AppsGridView::UpdateDrag(Pointer pointer, const gfx::Point& point) { |
ReorderChildView(drag_view_, -1); |
bounds_animator_.StopAnimatingView(drag_view_); |
StartSettingUpSynchronousDrag(); |
- StartDragAndDropHostDrag(point); |
+ if (!dragging_for_reparent_item_) |
+ StartDragAndDropHostDrag(point); |
} |
if (drag_pointer_ != pointer) |
@@ -562,21 +571,36 @@ void AppsGridView::EndDrag(bool cancel) { |
// EndDrag was called before if |drag_view_| is NULL. |
if (!drag_view_) |
return; |
+ |
// Coming here a drag and drop was in progress. |
bool landed_in_drag_and_drop_host = forward_events_to_drag_and_drop_host_; |
if (forward_events_to_drag_and_drop_host_) { |
+ DCHECK(!IsDraggingForReparentInRootLevelGridView()); |
forward_events_to_drag_and_drop_host_ = false; |
drag_and_drop_host_->EndDrag(cancel); |
+ if (IsDraggingForReprentInHiddenGridView()) { |
+ static_cast<AppListFolderView*>(parent())-> |
+ DispatchEndDragEventForReparent(true); |
+ } |
} else if (!cancel && dragging()) { |
- CalculateDropTarget(last_drag_point_, true); |
- if (IsValidIndex(drop_target_)) { |
- if (!EnableFolderDragDropUI()) { |
- MoveItemInModel(drag_view_, drop_target_); |
- } else { |
- if (drop_attempt_ == DROP_FOR_REORDER) |
- MoveItemInModel(drag_view_, drop_target_); |
- else if (drop_attempt_ == DROP_FOR_FOLDER) |
- MoveItemToFolder(drag_view_, drop_target_); |
+ if (IsDraggingForReprentInHiddenGridView()) { |
+ // Forward the EndDrag event to the root level grid view. |
+ static_cast<AppListFolderView*>(parent())-> |
+ DispatchEndDragEventForReparent(false); |
+ EndDragForReparentInHiddenFolderGridView(); |
+ return; |
+ } else { |
+ // Regular drag ending path, ie, not for reparenting. |
+ CalculateDropTarget(last_drag_point_, true); |
+ if (IsValidIndex(drop_target_)) { |
+ if (!EnableFolderDragDropUI()) { |
+ MoveItemInModel(drag_view_, drop_target_); |
+ } else { |
+ if (drop_attempt_ == DROP_FOR_REORDER) |
+ MoveItemInModel(drag_view_, drop_target_); |
+ else if (drop_attempt_ == DROP_FOR_FOLDER) |
+ MoveItemToFolder(drag_view_, drop_target_); |
+ } |
} |
} |
} |
@@ -594,8 +618,8 @@ void AppsGridView::EndDrag(bool cancel) { |
} |
// Fade in slowly if it landed in the shelf. |
SetViewHidden(drag_view_, |
- false /* hide */, |
- !landed_in_drag_and_drop_host /* animate */); |
+ false /* show */, |
+ !landed_in_drag_and_drop_host /* animate */); |
} |
// The drag can be ended after the synchronous drag is created but before it |
@@ -611,9 +635,18 @@ void AppsGridView::EndDrag(bool cancel) { |
drag_start_grid_view_ = gfx::Point(); |
drag_start_page_ = -1; |
drag_view_offset_ = gfx::Point(); |
+ if (IsDraggingForReprentInHiddenGridView()) |
+ dragging_for_reparent_item_ = false; |
AnimateToIdealBounds(); |
StopPageFlipTimer(); |
+ |
+ // If user releases mouse inside a folder's grid view, burst the folder |
+ // container ink bubble. |
+ if (!is_root_level_ && !IsDraggingForReprentInHiddenGridView()) { |
+ static_cast<AppListFolderView*>(parent())-> |
+ UpdateFolderViewBackground(false); |
+ } |
} |
void AppsGridView::StopPageFlipTimer() { |
@@ -650,6 +683,54 @@ void AppsGridView::ScheduleShowHideAnimation(bool show) { |
layer()->SetOpacity(show ? 1.0f : 0.0f); |
} |
+void AppsGridView::InitiateDragFromReparentItemInRootLevelGridView( |
+ AppListItemView* original_drag_view, |
+ const gfx::Rect& drag_view_rect, |
+ const gfx::Point& drag_point) { |
+ DCHECK(original_drag_view && !drag_view_); |
+ DCHECK(!dragging_for_reparent_item_); |
+ |
+ // Create a new AppListItemView to duplicate the original_drag_view in the |
+ // folder's grid view. |
+ AppListItemView* view = new AppListItemView(this, original_drag_view->item()); |
+ AddChildView(view); |
+ drag_view_ = view; |
+ drag_view_->SetPaintToLayer(true); |
+ // Note: For testing purpose, SetFillsBoundsOpaquely can be set to true to |
+ // show the gray background. |
+ drag_view_->SetFillsBoundsOpaquely(false); |
+ drag_view_->SetIconSize(icon_size_); |
+ drag_view_->SetBoundsRect(drag_view_rect); |
+ drag_view_->SetDragUIState(); // Hide the title of the drag_view_. |
+ |
+ // Hide the drag_view_ for drag icon proxy. |
+ SetViewHidden(drag_view_, |
+ true /* hide */, |
+ true /* no animate */); |
+ |
+ // Add drag_view_ to the end of the view_model_. |
+ view_model_.Add(drag_view_, view_model_.view_size()); |
+ |
+ drag_start_page_ = pagination_model_->selected_page(); |
+ drag_start_grid_view_ = drag_point; |
+ |
+ drag_view_start_ = gfx::Point(drag_view_->x(), drag_view_->y()); |
+ |
+ // Set the flag in root level grid view. |
+ dragging_for_reparent_item_ = true; |
+} |
+ |
+void AppsGridView::UpdateDragFromReparentItem( |
+ Pointer pointer, |
+ const ui::LocatedEvent& event) { |
+ DCHECK(drag_view_); |
+ DCHECK(IsDraggingForReparentInRootLevelGridView()); |
+ |
+ gfx::Point drag_point_in_grid_view; |
+ ExtractDragLocation(event, &drag_point_in_grid_view); |
+ UpdateDrag(pointer, drag_point_in_grid_view); |
+} |
+ |
bool AppsGridView::IsDraggedView(const views::View* view) const { |
return drag_view_ == view; |
} |
@@ -1202,11 +1283,173 @@ void AppsGridView::OnReorderTimer() { |
AnimateToIdealBounds(); |
} |
+void AppsGridView::OnFolderItemReparentTimer() { |
+ DCHECK(!is_root_level_); |
+ if (drag_out_of_folder_container_) { |
+ static_cast<AppListFolderView*>(parent())->ReparentItem( |
+ drag_view_, last_drag_point_); |
+ |
+ // Set the flag in the folder's grid view. |
+ dragging_for_reparent_item_ = true; |
+ |
+ // Do not observe any data change since it is going to be hidden. |
+ item_list_->RemoveObserver(this); |
+ item_list_ = NULL; |
+ } |
+} |
+ |
void AppsGridView::OnFolderDroppingTimer() { |
if (drop_attempt_ == DROP_FOR_FOLDER) |
SetAsFolderDroppingTarget(drop_target_, true); |
} |
+void AppsGridView::UpdateDragStateInsideFolder( |
+ Pointer pointer, |
+ const ui::LocatedEvent& event) { |
+ if (IsDraggingForReprentInHiddenGridView()) { |
+ // Dispatch drag event to root level grid view for re-parenting folder |
+ // folder item purpose. |
+ DispatchDragEventForReparent(pointer, event); |
+ return; |
+ } |
+ |
+ // Regular drag and drop in a folder's grid view. |
+ AppListFolderView* folder_view = static_cast<AppListFolderView*>(parent()); |
+ folder_view->UpdateFolderViewBackground(true); |
+ |
+ // Calculate if the drag_view_ is dragged out of the folder's container |
+ // ink bubble. |
+ gfx::Rect bounds_to_folder_view = ConvertRectToParent(drag_view_->bounds()); |
+ gfx::Point pt = bounds_to_folder_view.CenterPoint(); |
+ bool is_item_dragged_out_of_folder = |
+ folder_view->IsPointOutsideOfFolderBoundray(pt); |
+ if (is_item_dragged_out_of_folder) { |
+ if (!drag_out_of_folder_container_) { |
+ folder_item_reparent_timer_.Start(FROM_HERE, |
+ base::TimeDelta::FromMilliseconds(kFolderItemReparentDealy), |
+ this, &AppsGridView::OnFolderItemReparentTimer); |
+ drag_out_of_folder_container_ = true; |
+ } |
+ } else { |
+ folder_item_reparent_timer_.Stop(); |
+ drag_out_of_folder_container_ = false; |
+ } |
+} |
+ |
+bool AppsGridView::IsDraggingForReparentInRootLevelGridView() const { |
+ return (is_root_level_ && dragging_for_reparent_item_); |
+} |
+ |
+bool AppsGridView::IsDraggingForReprentInHiddenGridView() const { |
+ return (!is_root_level_ && dragging_for_reparent_item_); |
+} |
+ |
+gfx::Rect AppsGridView::GetTargetIconRectInFolder( |
+ AppListItemView* drag_item_view, |
+ AppListItemView* folder_item_view) { |
+ gfx::Rect view_ideal_bounds = view_model_.ideal_bounds( |
+ view_model_.GetIndexOfView(folder_item_view)); |
+ gfx::Rect icon_ideal_bounds = |
+ folder_item_view->GetIconBoundsForTargetViewBounds(view_ideal_bounds); |
+ AppListFolderItem* folder_item = |
+ static_cast<AppListFolderItem*>(folder_item_view->item()); |
+ return folder_item->GetTargetIconRectInFolderForItem( |
+ drag_item_view->item(), icon_ideal_bounds); |
+} |
+ |
+void AppsGridView::DispatchDragEventForReparent( |
+ Pointer pointer, |
+ const ui::LocatedEvent& event) { |
+ static_cast<AppListFolderView*>(parent())-> |
+ DispatchDragEventForReparent(pointer, event); |
+} |
+ |
+void AppsGridView::EndDragFromReparentItemInRootLevel( |
+ bool events_forwarded_to_drag_drop_host) { |
+ // EndDrag was called before if |drag_view_| is NULL. |
+ if (!drag_view_) |
+ return; |
+ |
+ DCHECK(IsDraggingForReparentInRootLevelGridView()); |
+ bool cancel_reparent = false; |
+ scoped_ptr<AppListItemView> cached_drag_view; |
+ if (!events_forwarded_to_drag_drop_host) { |
+ CalculateDropTarget(last_drag_point_, true); |
+ if (IsValidIndex(drop_target_)) { |
+ if (drop_attempt_ == DROP_FOR_REORDER) |
+ ReparentItemForReorder(drag_view_, drop_target_); |
+ else if (drop_attempt_ == DROP_FOR_FOLDER) |
+ ReparentItemToAnotherFolder(drag_view_, drop_target_); |
+ else { // DROP_FOR_NONE_ |
+ cancel_reparent = true; |
+ // Note(jennyz): cached_drag_view makes sure drag_view_ will be deleted |
+ // after AnimateToIdealBounds() is called. |
+ // There is a problem in layer() animation which cause DCHECK failure |
+ // if a child view is deleted immediately before re-creating layer in |
+ // layer animation. The layer tree seems marked dirty, and complaining |
+ // when we try to re-create layer in AnimationBetweenRows when calling |
+ // AnimateToIdealBounds. |
+ cached_drag_view.reset(drag_view_); |
+ } |
+ } |
+ |
+ if (!cancel_reparent) { |
+ SetViewHidden(drag_view_, |
+ false /* show */, |
+ true /* no animate */); |
+ } |
+ } |
+ |
+ // The drag can be ended after the synchronous drag is created but before it |
+ // is Run(). |
+ CleanUpSynchronousDrag(); |
+ |
+ SetAsFolderDroppingTarget(drop_target_, false); |
+ drop_attempt_ = DROP_FOR_NONE; |
+ drag_pointer_ = NONE; |
+ drop_target_ = Index(); |
+ if (!cancel_reparent) |
+ drag_view_->OnDragEnded(); |
+ drag_view_ = NULL; |
+ drag_start_grid_view_ = gfx::Point(); |
+ drag_start_page_ = -1; |
+ drag_view_offset_ = gfx::Point(); |
+ dragging_for_reparent_item_ = false; |
+ if (cancel_reparent) |
+ CancelFolderItemReparent(cached_drag_view.get()); |
+ AnimateToIdealBounds(); |
+ |
+ StopPageFlipTimer(); |
+} |
+ |
+void AppsGridView::EndDragForReparentInHiddenFolderGridView() { |
+ if (drag_and_drop_host_) { |
+ // If we had a drag and drop proxy icon, we delete it and make the real |
+ // item visible again. |
+ drag_and_drop_host_->DestroyDragIconProxy(); |
+ } |
+ |
+ // The drag can be ended after the synchronous drag is created but before it |
+ // is Run(). |
+ CleanUpSynchronousDrag(); |
+ |
+ SetAsFolderDroppingTarget(drop_target_, false); |
+ drop_attempt_ = DROP_FOR_NONE; |
+ drag_pointer_ = NONE; |
+ drop_target_ = Index(); |
+ drag_view_->OnDragEnded(); |
+ drag_view_ = NULL; |
+ drag_start_grid_view_ = gfx::Point(); |
+ drag_start_page_ = -1; |
+ drag_view_offset_ = gfx::Point(); |
+ dragging_for_reparent_item_ = false; |
+} |
+ |
+void AppsGridView::OnFolderItemRemoved() { |
+ DCHECK(!is_root_level_); |
+ item_list_ = NULL; |
+} |
+ |
void AppsGridView::StartDragAndDropHostDrag(const gfx::Point& grid_location) { |
// When a drag and drop host is given, the item can be dragged out of the app |
// list window. In that case a proxy widget needs to be used. |
@@ -1226,6 +1469,7 @@ void AppsGridView::StartDragAndDropHostDrag(const gfx::Point& grid_location) { |
// We have to hide the original item since the drag and drop host will do |
// the OS dependent code to "lift off the dragged item". |
+ DCHECK(!IsDraggingForReparentInRootLevelGridView()); |
drag_and_drop_host_->CreateDragIconProxy(screen_location, |
drag_view_->item()->icon(), |
drag_view_, |
@@ -1240,7 +1484,8 @@ void AppsGridView::DispatchDragEventToDragAndDropHost( |
const gfx::Point& location_in_screen_coordinates) { |
if (!drag_view_ || !drag_and_drop_host_) |
return; |
- if (bounds().Contains(last_drag_point_)) { |
+ |
+ if (GetLocalBounds().Contains(last_drag_point_)) { |
// The event was issued inside the app menu and we should get all events. |
if (forward_events_to_drag_and_drop_host_) { |
// The DnD host was previously called and needs to be informed that the |
@@ -1331,30 +1576,33 @@ void AppsGridView::MoveItemInModel(views::View* item_view, |
void AppsGridView::MoveItemToFolder(views::View* item_view, |
const Index& target) { |
- const std::string& source_id = |
+ const std::string& source_item_id = |
static_cast<AppListItemView*>(item_view)->item()->id(); |
AppListItemView* target_view = |
static_cast<AppListItemView*>(GetViewAtSlotOnCurrentPage(target.slot)); |
- const std::string& target_id = target_view->item()->id(); |
+ const std::string& target_view_item_id = target_view->item()->id(); |
// Make change to data model. |
item_list_->RemoveObserver(this); |
- std::string folder_id = model_->MergeItems(target_id, source_id); |
+ |
+ std::string folder_item_id = |
+ model_->MergeItems(target_view_item_id, source_item_id); |
item_list_->AddObserver(this); |
- if (folder_id != target_id) { |
+ if (folder_item_id != target_view_item_id) { |
// New folder was created, change the view model to replace the old target |
// view with the new folder item view. |
- size_t folder_index; |
- if (item_list_->FindItemIndex(folder_id, &folder_index)) { |
- int target_index = view_model_.GetIndexOfView(target_view); |
- view_model_.Remove(target_index); |
+ size_t folder_item_index; |
+ if (item_list_->FindItemIndex(folder_item_id, &folder_item_index)) { |
+ int target_view_index = view_model_.GetIndexOfView(target_view); |
+ view_model_.Remove(target_view_index); |
delete target_view; |
- views::View* target_folder_view = CreateViewForItemAtIndex(folder_index); |
- view_model_.Add(target_folder_view, target_index); |
+ views::View* target_folder_view = |
+ CreateViewForItemAtIndex(folder_item_index); |
+ view_model_.Add(target_folder_view, target_view_index); |
AddChildView(target_folder_view); |
} else { |
- LOG(ERROR) << "Folder no longer in item_list: " << folder_id; |
+ LOG(ERROR) << "Folder no longer in item_list: " << folder_item_id; |
} |
} |
@@ -1364,10 +1612,141 @@ void AppsGridView::MoveItemToFolder(views::View* item_view, |
bounds_animator_.AnimateViewTo(drag_view_, drag_view_->bounds()); |
bounds_animator_.SetAnimationDelegate( |
drag_view_, new ItemRemoveAnimationDelegate(drag_view_), true); |
+ UpdatePaging(); |
+} |
+ |
+void AppsGridView::ReparentItemForReorder(views::View* item_view, |
+ const Index& target) { |
+ item_list_->RemoveObserver(this); |
+ model_->RemoveObserver(this); |
+ |
+ AppListItem* reparent_item = static_cast<AppListItemView*>(item_view)->item(); |
+ DCHECK(reparent_item->IsInFolder()); |
+ AppListFolderItem* source_folder = static_cast<AppListFolderItem*>( |
+ item_list_->FindItem(reparent_item->folder_id())); |
+ // Move the item from its parent folder to top level item list. |
+ // Must move to target_model_index, the location we expect the target item |
+ // to be, not the item location we want to insert before. |
+ int target_model_index = GetModelIndexFromIndex(target); |
+ int current_model_index = view_model_.GetIndexOfView(item_view); |
+ syncer::StringOrdinal target_position; |
+ if (target_model_index < static_cast<int>(item_list_->item_count())) |
+ target_position = item_list_->item_at(target_model_index)->position(); |
+ model_->MoveItemToFolderAt(reparent_item, "", target_position); |
+ view_model_.Move(current_model_index, target_model_index); |
+ |
+ if (source_folder->ChildItemCount() == 1) |
+ RemoveLastItemFromReparentItemFolder(source_folder); |
+ |
+ item_list_->AddObserver(this); |
+ model_->AddObserver(this); |
UpdatePaging(); |
} |
+void AppsGridView::ReparentItemToAnotherFolder(views::View* item_view, |
+ const Index& target) { |
+ DCHECK(IsDraggingForReparentInRootLevelGridView()); |
+ |
+ // Make change to data model. |
+ item_list_->RemoveObserver(this); |
+ |
+ AppListItem* reparent_item = static_cast<AppListItemView*>(item_view)->item(); |
+ DCHECK(reparent_item->IsInFolder()); |
+ AppListFolderItem* source_folder = static_cast<AppListFolderItem*>( |
+ item_list_->FindItem(reparent_item->folder_id())); |
+ |
+ AppListItemView* target_view = |
+ static_cast<AppListItemView*>(GetViewAtSlotOnCurrentPage(target.slot)); |
+ AppListItem* target_item = target_view->item(); |
+ |
+ // Move item to the target folder. |
+ const std::string& target_id_after_merge = |
+ model_->MergeItems(target_item->id(), reparent_item->id()); |
+ |
+ if (target_id_after_merge != target_item->id()) { |
+ // New folder was created, change the view model to replace the old target |
+ // view with the new folder item view. |
+ const std::string& new_folder_id = reparent_item->folder_id(); |
+ size_t new_folder_index; |
+ if (item_list_->FindItemIndex(new_folder_id, &new_folder_index)) { |
+ int target_view_index = view_model_.GetIndexOfView(target_view); |
+ view_model_.Remove(target_view_index); |
+ delete target_view; |
+ views::View* new_folder_view = |
+ CreateViewForItemAtIndex(new_folder_index); |
+ view_model_.Add(new_folder_view, target_view_index); |
+ AddChildView(new_folder_view); |
+ } else { |
+ LOG(ERROR) << "Folder no longer in item_list: " << new_folder_id; |
+ } |
+ } |
+ |
+ if (source_folder->ChildItemCount() == 1) |
+ RemoveLastItemFromReparentItemFolder(source_folder); |
+ |
+ item_list_->AddObserver(this); |
+ |
+ // Fade out the drag_view_ and delete it when animation ends. |
+ int drag_view_index = view_model_.GetIndexOfView(drag_view_); |
+ view_model_.Remove(drag_view_index); |
+ bounds_animator_.AnimateViewTo(drag_view_, drag_view_->bounds()); |
+ bounds_animator_.SetAnimationDelegate( |
+ drag_view_, new ItemRemoveAnimationDelegate(drag_view_), true); |
+ UpdatePaging(); |
+} |
+ |
+// After moving the re-parenting item out of the folder, if there is only 1 item |
+// left, remove the last item out of the folder, delete the folder and insert it |
+// to the data model at the same position. Make the same change to view_model_ |
+// accordingly. |
+void AppsGridView::RemoveLastItemFromReparentItemFolder( |
+ AppListFolderItem* source_folder) { |
+ DCHECK(source_folder->ChildItemCount() == 1); |
+ |
+ // Delete view associated with the folder item to be removed. |
+ AppListItemView* folder_item_view = activated_item_view(); |
+ int folder_model_index = view_model_.GetIndexOfView(folder_item_view); |
+ view_model_.Remove(folder_model_index); |
+ delete folder_item_view; |
+ |
+ // Now make the data change to remove the folder item in model. |
+ AppListItem* last_item = source_folder->item_list()->item_at(0); |
+ model_->MoveItemToFolderAt(last_item, "", source_folder->position()); |
+ |
+ // Create a new item view for the last item in folder. |
+ size_t last_item_index; |
+ item_list_->FindItemIndex(last_item->id(), &last_item_index); |
+ views::View* last_item_view = CreateViewForItemAtIndex(last_item_index); |
+ view_model_.Add(last_item_view, last_item_index); |
+ AddChildView(last_item_view); |
+} |
+ |
+void AppsGridView::CancelFolderItemReparent(AppListItemView* drag_item_view) { |
+ // The icon of the dragged item must target to its final ideal bounds after |
+ // the animation completes. |
+ CalculateIdealBounds(); |
+ |
+ // Remove drag_view_ from view_model_, it will be deleted after the animation. |
+ int drag_view_index = view_model_.GetIndexOfView(drag_item_view); |
+ view_model_.Remove(drag_view_index); |
+ |
+ gfx::Rect target_icon_rect = |
+ GetTargetIconRectInFolder(drag_item_view, activated_item_view_); |
+ |
+ gfx::Rect drag_view_icon_to_grid = |
+ drag_item_view->ConvertRectToParent(drag_item_view->GetIconBounds()); |
+ drag_view_icon_to_grid.ClampToCenteredSize( |
+ gfx::Size(kPreferredIconDimension, kPreferredIconDimension)); |
+ TopIconAnimationView* icon_view = new TopIconAnimationView( |
+ drag_item_view->item()->icon(), |
+ target_icon_rect, |
+ false); /* animate like closing folder */ |
+ AddChildView(icon_view); |
+ icon_view->SetBoundsRect(drag_view_icon_to_grid); |
+ icon_view->TransformView(); |
+} |
+ |
void AppsGridView::CancelContextMenusOnCurrentPage() { |
int start = pagination_model_->selected_page() * tiles_per_page(); |
int end = std::min(view_model_.view_size(), start + tiles_per_page()); |
@@ -1582,6 +1961,14 @@ AppsGridView::Index AppsGridView::GetNearestTileForDragView() { |
drop_attempt_ = DROP_FOR_NONE; |
reorder_timer_.Stop(); |
folder_dropping_timer_.Stop(); |
+ |
+ // When dragging for reparent a folder item, it should go back to its parent |
+ // folder item if there is no drop target. |
+ if (IsDraggingForReparentInRootLevelGridView()) { |
+ DCHECK(activated_item_view_); |
+ return GetIndexOfView(activated_item_view_); |
+ } |
+ |
return GetIndexOfView(drag_view_); |
} |