-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ui] Utils: add SelectionBox and DelegateSelectionBox
- SelectionBox: generic Selection box component. - DelegateSelectionBox: specialized SelectionBox to select model delegates from an instantiator (Repeater, ListView). Also Introduce a Geom2D helper class to provide missing features for intersection testing in QML.
- Loading branch information
Showing
5 changed files
with
106 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from PySide6.QtCore import QObject, Slot, QRectF | ||
|
||
|
||
class Geom2D(QObject): | ||
@Slot(QRectF, QRectF, result=bool) | ||
def rectRectIntersect(self, rect1: QRectF, rect2: QRectF) -> bool: | ||
"""Check if two rectangles intersect.""" | ||
return rect1.intersects(rect2) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import QtQuick | ||
import Meshroom.Helpers | ||
|
||
/* | ||
A SelectionBox that can be used to select delegates in a model instantiator (Repeater, ListView...). | ||
Interesection test is done in the coordinate system of the container Item, using delegate's bounding boxes. | ||
The list of selected indices is emitted when the selection ends. | ||
*/ | ||
|
||
SelectionBox { | ||
id: root | ||
|
||
// The Item instantiating the delegates. | ||
property Item modelInstantiator | ||
// The Item containing the delegates (used for coordinate mapping). | ||
property Item container | ||
// Emitted when the selection has ended, with the list of selected indices and modifiers. | ||
signal delegateSelectionEnded(list<int> indices, int modifiers) | ||
|
||
onSelectionEnded: function(selectionRect, modifiers) { | ||
let selectedIndices = []; | ||
const mappedSelectionRect = mapToItem(container, selectionRect); | ||
for (var i = 0; i < modelInstantiator.count; ++i) { | ||
const delegate = modelInstantiator.itemAt(i); | ||
const delegateRect = Qt.rect(delegate.x, delegate.y, delegate.width, delegate.height); | ||
if (Geom2D.rectRectIntersect(mappedSelectionRect, delegateRect)) { | ||
selectedIndices.push(i); | ||
} | ||
} | ||
delegateSelectionEnded(selectedIndices, modifiers); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import QtQuick | ||
|
||
/* | ||
Simple selection box that can be used by a MouseArea. | ||
Usage: | ||
1. Create a MouseArea and a SelectionBox. | ||
2. Bind the SelectionBox to the MouseArea by setting the `mouseArea` property. | ||
3. Call startSelection() with coordinates when the selection starts. | ||
4. Call endSelection() when the selection ends. | ||
5. Listen to the selectionEnded signal to get the selection rectangle. | ||
*/ | ||
|
||
Item { | ||
id: root | ||
|
||
property MouseArea mouseArea | ||
property alias color: selectionBox.color | ||
property alias border: selectionBox.border | ||
|
||
readonly property bool active: mouseArea.drag.target == dragTarget | ||
|
||
signal selectionEnded(rect selectionRect, int modifiers) | ||
|
||
function startSelection(mouse) { | ||
dragTarget.startPos.x = dragTarget.x = mouse.x; | ||
dragTarget.startPos.y = dragTarget.y = mouse.y; | ||
dragTarget.modifiers = mouse.modifiers; | ||
mouseArea.drag.target = dragTarget; | ||
} | ||
|
||
function endSelection() { | ||
if (!active) { | ||
return; | ||
} | ||
mouseArea.drag.target = null; | ||
const rect = Qt.rect(selectionBox.x, selectionBox.y, selectionBox.width, selectionBox.height) | ||
selectionEnded(rect, dragTarget.modifiers); | ||
} | ||
|
||
visible: active | ||
|
||
Rectangle { | ||
id: selectionBox | ||
color: "#109b9b9b" | ||
border.width: 1 | ||
border.color: "#b4b4b4" | ||
|
||
x: Math.min(dragTarget.startPos.x, dragTarget.x) | ||
y: Math.min(dragTarget.startPos.y, dragTarget.y) | ||
width: Math.abs(dragTarget.x - dragTarget.startPos.x) | ||
height: Math.abs(dragTarget.y - dragTarget.startPos.y) | ||
} | ||
|
||
Item { | ||
id: dragTarget | ||
property point startPos | ||
property var modifiers | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters