Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(115)

Unified Diff: ui/app_list/views/apps_grid_view.cc

Issue 553753003: Rework app list item drag zones. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@fasdaj
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 dda664fd8f615211aaf04379244f6b41b0bdfb44..e7c50bb038bc6abd9452ad5f54a785df8cb1913f 100644
--- a/ui/app_list/views/apps_grid_view.cc
+++ b/ui/app_list/views/apps_grid_view.cc
@@ -189,12 +189,6 @@ class ItemMoveAnimationDelegate : public gfx::AnimationDelegate {
DISALLOW_COPY_AND_ASSIGN(ItemMoveAnimationDelegate);
};
-// Gets the distance between the centers of the |rect_1| and |rect_2|.
-int GetDistanceBetweenRects(gfx::Rect rect_1,
- gfx::Rect rect_2) {
- return (rect_1.CenterPoint() - rect_2.CenterPoint()).Length();
-}
-
// Returns true if the |item| is an folder item.
bool IsFolderItem(AppListItem* item) {
return (item->GetItemType() == AppListFolderItem::kItemType);
@@ -488,6 +482,7 @@ void AppsGridView::InitiateDrag(AppListItemView* view,
drag_view_init_index_ = GetIndexOfView(drag_view_);
drag_view_offset_ = event.location();
drag_start_page_ = pagination_model_.selected_page();
+ reorder_placeholder_ = GetIndexOfView(drag_view_);
tapted 2014/09/11 08:08:54 nit: GetIndexOfView(drag_view_); -> drag_view_init
calamity 2014/09/15 03:26:10 Done.
tapted 2014/09/15 06:12:53 missed?
calamity 2014/09/15 06:36:15 Done for real.
ExtractDragLocation(event, &drag_start_grid_view_);
drag_view_start_ = gfx::Point(drag_view_->x(), drag_view_->y());
}
@@ -784,6 +779,10 @@ void AppsGridView::InitiateDragFromReparentItemInRootLevelGridView(
DCHECK(original_drag_view && !drag_view_);
DCHECK(!dragging_for_reparent_item_);
+ // Since the item is new, it's placeholder is conceptually at the back of the
tapted 2014/09/11 08:08:54 nit: `it's` -> `its`
calamity 2014/09/15 03:26:09 Done.
+ // entire apps grid.
+ reorder_placeholder_ = GetLastViewIndex();
+
// 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());
@@ -833,6 +832,7 @@ void AppsGridView::ClearDragState() {
drag_pointer_ = NONE;
reorder_drop_target_ = Index();
folder_drop_target_ = Index();
+ reorder_placeholder_ = Index();
drag_start_grid_view_ = gfx::Point();
drag_start_page_ = -1;
drag_view_offset_ = gfx::Point();
@@ -1115,6 +1115,11 @@ views::View* AppsGridView::GetViewAtIndex(const Index& index) const {
return view_model_.view_at(model_index);
}
+AppsGridView::Index AppsGridView::GetLastViewIndex() const {
+ int view_index = view_model_.view_size() - 1;
tapted 2014/09/11 08:08:53 DCHECK(!view_model_.empty()); .. assuming we can
calamity 2014/09/15 03:26:10 It'll be a shoddy guarantee.. (A component app sho
tapted 2014/09/15 06:12:52 Yep - that's all i'm after really. Since if it is
+ return Index(view_index / tiles_per_page(), view_index % tiles_per_page());
+}
+
void AppsGridView::MoveSelected(int page_delta,
int slot_x_delta,
int slot_y_delta) {
@@ -1388,9 +1393,15 @@ void AppsGridView::CalculateDropTarget(const gfx::Point& drag_point,
void AppsGridView::CalculateDropTargetWithFolderEnabled(
const gfx::Point& drag_point,
tapted 2014/09/11 08:08:53 |drag_point| looks unused now -> remove?
calamity 2014/09/15 03:26:10 Done.
bool use_page_button_hovering) {
- gfx::Point point(drag_point);
- if (!IsPointWithinDragBuffer(drag_point)) {
- point = drag_start_grid_view_;
+ gfx::Point point = drag_view_->icon()->bounds().CenterPoint();
+ views::View::ConvertPointToTarget(drag_view_, this, &point);
+ if (!IsPointWithinDragBuffer(point)) {
+ // Reset the reorder target to the original position if the cursor is
+ // outside the drag buffer.
+ if (!IsDraggingForReparentInRootLevelGridView())
+ reorder_drop_target_ = GetIndexOfView(drag_view_);
tapted 2014/09/11 08:08:53 maybe.. drag_view_init_index_
calamity 2014/09/15 03:26:11 Done.
+ drop_attempt_ = DROP_FOR_NONE;
+ return;
}
if (use_page_button_hovering && page_switcher_view_ &&
@@ -1403,14 +1414,62 @@ void AppsGridView::CalculateDropTargetWithFolderEnabled(
drop_attempt_ = DROP_FOR_NONE;
} else {
tapted 2014/09/11 08:08:54 early return before this. no else.
calamity 2014/09/15 03:26:10 Done.
DCHECK(drag_view_);
tapted 2014/09/11 08:08:54 move this to the start of the function
calamity 2014/09/15 03:26:09 Done.
- // Try to find the nearest target for folder dropping or re-ordering.
- CalculateNearestTileForDragView();
+ const int d_folder_dropping =
tapted 2014/09/11 08:08:55 d looks like an abbreviation - maybe `folder_thres
calamity 2014/09/15 03:26:09 I think this is saying the radius is the distance
tapted 2014/09/15 06:12:52 yep - much nicer
+ kFolderDroppingCircleRadius + kGridIconDimension / 2;
+
+ Index nearest_tile_index(pagination_model_.selected_page(),
+ GetNearestTileSlotForPoint(point));
+
+ int distance_to_tile_center =
+ (point - GetExpectedTileBounds(nearest_tile_index.slot).CenterPoint())
+ .Length();
+ if (nearest_tile_index != reorder_placeholder_ &&
+ distance_to_tile_center < d_folder_dropping &&
+ !IsFolderItem(drag_view_->item()) &&
+ CanDropIntoTarget(nearest_tile_index)) {
tapted 2014/09/11 08:08:54 CanDropIntoTarget returns true if the drop_target
calamity 2014/09/15 03:26:09 Nope. Fixed.
+ drop_attempt_ = DROP_FOR_FOLDER;
+ folder_drop_target_ = nearest_tile_index;
+ return;
tapted 2014/09/11 08:08:53 there's a lot of state above that isn't used for t
calamity 2014/09/15 03:26:11 Done.
+ }
+
+ gfx::Rect bounds = GetContentsBounds();
+ // Get coordinates in tile grid space.
+ int x = point.x() - bounds.x();
+ int y = point.y() - bounds.y();
+ int row = y / kPreferredTileHeight;
+ int grid_col = x / kPreferredTileWidth;
+ Index grid_index(pagination_model_.selected_page(),
+ std::min(row * cols_ + grid_col, view_model_.view_size()));
tapted 2014/09/11 08:08:54 This is pretty fiddly... but I don't see an obviou
calamity 2014/09/15 03:26:11 Done.
+ gfx::Point reorder_placeholder_origin =
+ GetExpectedTileBounds(reorder_placeholder_.slot).CenterPoint();
+
+ int dir = 0;
tapted 2014/09/11 08:08:54 dir isn't a good name - maybe column_offset?
calamity 2014/09/15 03:26:09 Done.
+ if (grid_index == reorder_placeholder_) {
+ dir = reorder_placeholder_origin.x() < point.x() ? 1 : -1;
+ } else {
+ dir = reorder_placeholder_ < grid_index ? 1 : -1;
+ }
+
+ // Offset the target column base on the direction of the target. This will
tapted 2014/09/11 08:08:54 nit: base->based
calamity 2014/09/15 03:26:09 Done.
+ // result in earlier targets getting their reorder zone shifted backwards
+ // and later targets getting their reorder zones shifted forwards.
+ //
+ // This causes the animation to trigger when slotting items into the spaces
+ // between apps.
+ int col = (x - dir * kPreferredTileWidth / 3) / kPreferredTileWidth;
+ col = std::min(std::max(col, 0), cols_ - 1);
+ drop_attempt_ = DROP_FOR_REORDER;
+ reorder_drop_target_ =
+ std::min(Index(pagination_model_.selected_page(), row * cols_ + col),
+ GetLastViewIndex());
}
}
void AppsGridView::OnReorderTimer() {
- if (drop_attempt_ == DROP_FOR_REORDER)
+ if (drop_attempt_ == DROP_FOR_REORDER) {
+ reorder_placeholder_ = reorder_drop_target_;
AnimateToIdealBounds();
+ }
}
void AppsGridView::OnFolderItemReparentTimer() {
@@ -2040,9 +2099,8 @@ void AppsGridView::OnImplicitAnimationsCompleted() {
bool AppsGridView::EnableFolderDragDropUI() {
// Enable drag and drop folder UI only if it is at the app list root level
- // and the switch is on and the target folder can still accept new items.
- return model_->folders_enabled() && !folder_delegate_ &&
- CanDropIntoTarget(folder_drop_target_);
tapted 2014/09/11 08:08:54 I don't think this belongs here. I'd always assume
calamity 2014/09/15 03:26:09 Nothing afaict. It was obviously needed for the "c
+ // and the switch is on.
+ return model_->folders_enabled() && !folder_delegate_;
}
bool AppsGridView::CanDropIntoTarget(const Index& drop_target) {
@@ -2059,124 +2117,11 @@ bool AppsGridView::CanDropIntoTarget(const Index& drop_target) {
!IsOEMFolderItem(target_item);
}
-// TODO(jennyz): Optimize the calculation for finding nearest tile.
-void AppsGridView::CalculateNearestTileForDragView() {
- Index nearest_tile;
- nearest_tile.page = -1;
- nearest_tile.slot = -1;
- int d_min = -1;
-
- // Calculate the top left tile |drag_view| intersects.
- gfx::Point pt = drag_view_->bounds().origin();
- CalculateNearestTileForVertex(pt, &nearest_tile, &d_min);
-
- // Calculate the top right tile |drag_view| intersects.
- pt = drag_view_->bounds().top_right();
- CalculateNearestTileForVertex(pt, &nearest_tile, &d_min);
-
- // Calculate the bottom left tile |drag_view| intersects.
- pt = drag_view_->bounds().bottom_left();
- CalculateNearestTileForVertex(pt, &nearest_tile, &d_min);
-
- // Calculate the bottom right tile |drag_view| intersects.
- pt = drag_view_->bounds().bottom_right();
- CalculateNearestTileForVertex(pt, &nearest_tile, &d_min);
-
- const int d_folder_dropping =
- kFolderDroppingCircleRadius + kGridIconDimension / 2;
- const int d_reorder = kReorderDroppingCircleRadius + kGridIconDimension / 2;
-
- // If user drags an item across pages to the last page, and targets it
- // to the last empty slot on it, push the last item for re-ordering.
- if (IsLastPossibleDropTarget(nearest_tile) && d_min < d_reorder) {
- drop_attempt_ = DROP_FOR_REORDER;
- nearest_tile.slot = nearest_tile.slot - 1;
- reorder_drop_target_ = nearest_tile;
- return;
- }
-
- if (IsValidIndex(nearest_tile)) {
- if (d_min < d_folder_dropping) {
- views::View* target_view = GetViewAtSlotOnCurrentPage(nearest_tile.slot);
- if (target_view &&
- !IsFolderItem(static_cast<AppListItemView*>(drag_view_)->item())) {
- // If a non-folder item is dragged to the target slot with an item
- // sitting on it, attempt to drop the dragged item into the folder
- // containing the item on nearest_tile.
- drop_attempt_ = DROP_FOR_FOLDER;
- folder_drop_target_ = nearest_tile;
- return;
- } else {
- // If the target slot is blank, or the dragged item is a folder, attempt
- // to re-order.
- drop_attempt_ = DROP_FOR_REORDER;
- reorder_drop_target_ = nearest_tile;
- return;
- }
- } else if (d_min < d_reorder) {
- // Entering the re-order circle of the slot.
- drop_attempt_ = DROP_FOR_REORDER;
- reorder_drop_target_ = nearest_tile;
- return;
- }
- }
-
- // If |drag_view| is not entering the re-order or fold dropping region of
- // any items, cancel any previous re-order or folder dropping timer.
- 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_folder_item_view_);
- folder_drop_target_ = GetIndexOfView(activated_folder_item_view_);
- }
-}
-
-void AppsGridView::CalculateNearestTileForVertex(const gfx::Point& vertex,
- Index* nearest_tile,
- int* d_min) {
- Index target_index;
- gfx::Rect target_bounds = GetTileBoundsForPoint(vertex, &target_index);
-
- if (target_bounds.IsEmpty() || target_index == *nearest_tile)
- return;
-
- // Do not count the tile, where drag_view_ used to sit on and is still moving
- // on top of it, in calculating nearest tile for drag_view_.
- views::View* target_view = GetViewAtSlotOnCurrentPage(target_index.slot);
- if (target_index == drag_view_init_index_ && !target_view &&
- !IsDraggingForReparentInRootLevelGridView()) {
- return;
- }
-
- int d_center = GetDistanceBetweenRects(drag_view_->bounds(), target_bounds);
- if (*d_min < 0 || d_center < *d_min) {
- *d_min = d_center;
- *nearest_tile = target_index;
- }
-}
-
-gfx::Rect AppsGridView::GetTileBoundsForPoint(const gfx::Point& point,
- Index *tile_index) {
- // Check if |point| is outside of contents bounds.
- gfx::Rect bounds(GetContentsBounds());
- if (!bounds.Contains(point))
- return gfx::Rect();
-
- // Calculate which tile |point| is enclosed in.
- int x = point.x();
- int y = point.y();
- int col = (x - bounds.x()) / kPreferredTileWidth;
- int row = (y - bounds.y()) / kPreferredTileHeight;
- gfx::Rect tile_rect = GetExpectedTileBounds(row, col);
-
- // Check if |point| is outside a valid item's tile.
- Index index(pagination_model_.selected_page(), row * cols_ + col);
- *tile_index = index;
- return tile_rect;
+int AppsGridView::GetNearestTileSlotForPoint(const gfx::Point& point) {
+ gfx::Rect bounds = GetContentsBounds();
tapted 2014/09/11 08:08:54 maybe DCHECK(IsPointWithinDragBuffer(point)); befo
calamity 2014/09/15 03:26:09 Hmm. Unfortunately IsPointWithinDragBuffer include
tapted 2014/09/15 06:12:52 sweet
+ int col = (point.x() - bounds.x()) / kPreferredTileWidth;
+ int row = (point.y() - bounds.y()) / kPreferredTileHeight;
+ return row * cols_ + col;
}
gfx::Size AppsGridView::GetTileGridSize() const {
@@ -2185,6 +2130,10 @@ gfx::Size AppsGridView::GetTileGridSize() const {
return bounds.size();
}
+gfx::Rect AppsGridView::GetExpectedTileBounds(int slot) const {
+ return GetExpectedTileBounds(slot / cols_, slot % cols_);
+}
+
gfx::Rect AppsGridView::GetExpectedTileBounds(int row, int col) const {
gfx::Rect bounds(GetContentsBounds());
gfx::Size tile_size(kPreferredTileWidth, kPreferredTileHeight);
@@ -2193,12 +2142,6 @@ gfx::Rect AppsGridView::GetExpectedTileBounds(int row, int col) const {
tile_size);
}
-bool AppsGridView::IsLastPossibleDropTarget(const Index& index) const {
- int last_possible_slot = view_model_.view_size() % tiles_per_page();
- return (index.page == pagination_model_.total_pages() - 1 &&
- index.slot == last_possible_slot + 1);
-}
-
views::View* AppsGridView::GetViewAtSlotOnCurrentPage(int slot) {
if (slot < 0)
return NULL;

Powered by Google App Engine
This is Rietveld 408576698