[gnome-shell/gbsneto/custom-icon-positions: 3/30] iconGrid: Add drop target API
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/gbsneto/custom-icon-positions: 3/30] iconGrid: Add drop target API
- Date: Wed, 15 Jul 2020 19:46:57 +0000 (UTC)
commit eca935cafb3cd7c51cc1d0aa64a4335bf3d23269
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date: Mon May 25 15:58:39 2020 -0300
iconGrid: Add drop target API
Add a new drop target API. The bulk of it is implemented by
IconGridLayout, since it's the layout manager that knows where
each icon is placed at.
https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1284
js/ui/appDisplay.js | 16 ++++++++
js/ui/iconGrid.js | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 125 insertions(+)
---
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index 807c43a539..421f84b518 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -404,6 +404,22 @@ var BaseAppView = GObject.registerClass({
}
}
+ _getDropTarget(x, y) {
+ let [item, dragLocation] = this._grid.getDropTarget(x, y);
+
+ // Append to the page if dragging over empty area
+ if (dragLocation === IconGrid.DragLocation.EMPTY_SPACE) {
+ const currentPage = this._grid.currentPage;
+ const pageItems =
+ this._grid.getItemsAtPage(currentPage).filter(c => c.visible);
+
+ item = pageItems[pageItems.length - 1];
+ dragLocation = IconGrid.DragLocation.END_EDGE;
+ }
+
+ return [item, dragLocation];
+ }
+
vfunc_allocate(box) {
const width = box.get_width();
const height = box.get_height();
diff --git a/js/ui/iconGrid.js b/js/ui/iconGrid.js
index ecbbcb3ccd..2d3a17a626 100644
--- a/js/ui/iconGrid.js
+++ b/js/ui/iconGrid.js
@@ -52,6 +52,17 @@ const defaultGridModes = [
},
];
+var LEFT_DIVIDER_LEEWAY = 20;
+var RIGHT_DIVIDER_LEEWAY = 20;
+
+var DragLocation = {
+ INVALID: 0,
+ START_EDGE: 1,
+ ON_ICON: 2,
+ END_EDGE: 3,
+ EMPTY_SPACE: 4,
+};
+
var BaseIcon = GObject.registerClass(
class BaseIcon extends St.Bin {
_init(label, params) {
@@ -946,6 +957,99 @@ var IconGridLayout = GObject.registerClass({
}
}
+ /**
+ * getDropTarget:
+ * @param {int} x: position of the horizontal axis
+ * @param {int} y: position of the vertical axis
+ *
+ * Retrieves the item located at (@x, @y), as well as the drag location.
+ * Both @x and @y are relative to the grid.
+ *
+ * @returns {[Clutter.Actor, DragLocation]} the item and drag location
+ * under (@x, @y)
+ */
+ getDropTarget(x, y) {
+ const childSize = this._getChildrenMaxSize();
+ const [leftEmptySpace, topEmptySpace, hSpacing, vSpacing] =
+ this._calculateSpacing(childSize);
+
+ const isRtl =
+ Clutter.get_default_text_direction() === Clutter.TextDirection.RTL;
+
+ let page = this._orientation === Clutter.Orientation.VERTICAL
+ ? Math.floor(y / this._pageHeight)
+ : Math.floor(x / this._pageWidth);
+
+ // Out of bounds
+ if (page >= this._pages.length)
+ return [null, DragLocation.INVALID];
+
+ if (isRtl && this._orientation === Clutter.Orientation.HORIZONTAL)
+ page = swap(page, this._pages.length);
+
+ // Page-relative coordinates from now on
+ x %= this._pageWidth;
+ y %= this._pageHeight;
+
+ if (x < leftEmptySpace || y < topEmptySpace)
+ return [null, DragLocation.INVALID];
+
+ const gridWidth =
+ childSize * this._columnsPerPage +
+ hSpacing * (this._columnsPerPage - 1);
+ const gridHeight =
+ childSize * this._rowsPerPage +
+ vSpacing * (this._rowsPerPage - 1);
+
+ if (x > leftEmptySpace + gridWidth || y > topEmptySpace + gridHeight)
+ return [null, DragLocation.INVALID];
+
+ const halfHSpacing = hSpacing / 2;
+ const halfVSpacing = vSpacing / 2;
+ const visibleItems = this._getVisibleChildrenForPage(page);
+
+ for (const item of visibleItems) {
+ const childBox = item.allocation.copy();
+
+ // Page offset
+ switch (this._orientation) {
+ case Clutter.Orientation.HORIZONTAL:
+ childBox.set_origin(childBox.x1 % this._pageWidth, childBox.y1);
+ break;
+ case Clutter.Orientation.VERTICAL:
+ childBox.set_origin(childBox.x1, childBox.y1 % this._pageHeight);
+ break;
+ }
+
+ // Outside the icon boundaries
+ if (x < childBox.x1 - halfHSpacing ||
+ x > childBox.x2 + halfHSpacing ||
+ y < childBox.y1 - halfVSpacing ||
+ y > childBox.y2 + halfVSpacing)
+ continue;
+
+ let dragLocation;
+
+ if (x < childBox.x1 + LEFT_DIVIDER_LEEWAY)
+ dragLocation = DragLocation.START_EDGE;
+ else if (x > childBox.x2 - RIGHT_DIVIDER_LEEWAY)
+ dragLocation = DragLocation.END_EDGE;
+ else
+ dragLocation = DragLocation.ON_ICON;
+
+ if (isRtl) {
+ if (dragLocation === DragLocation.START_EDGE)
+ dragLocation = DragLocation.END_EDGE;
+ else if (dragLocation === DragLocation.END_EDGE)
+ dragLocation = DragLocation.START_EDGE;
+ }
+
+ return [item, dragLocation];
+ }
+
+ return [null, DragLocation.EMPTY_SPACE];
+ }
+
// eslint-disable-next-line camelcase
get allow_incomplete_pages() {
return this._allowIncompletePages;
@@ -1559,6 +1663,11 @@ var IconGrid = GObject.registerClass({
this.queue_relayout();
}
+ getDropTarget(x, y) {
+ const layoutManager = this.layout_manager;
+ return layoutManager.getDropTarget(x, y, this._currentPage);
+ }
+
get itemsPerPage() {
const layoutManager = this.layout_manager;
return layoutManager.rows_per_page * layoutManager.columns_per_page;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]