mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-04-28 17:57:16 +02:00
The workaround on edge crashing is to use the mouse area around the edge and query if the click exists in the edge to accept pressed or released signal
173 lines
5.4 KiB
QML
173 lines
5.4 KiB
QML
import QtQuick
|
|
import QtQuick.Controls
|
|
import QtQuick.Shapes 1.6
|
|
|
|
import GraphEditor 1.0
|
|
import MaterialIcons 2.2
|
|
|
|
/**
|
|
* A cubic spline representing an edge, going from point1 to point2, providing mouse interaction.
|
|
*/
|
|
|
|
Item {
|
|
id: root
|
|
|
|
property var edge
|
|
property real point1x
|
|
property real point1y
|
|
property real point2x
|
|
property real point2y
|
|
property alias thickness: path.strokeWidth
|
|
property alias color: path.strokeColor
|
|
property bool isForLoop: false
|
|
property int loopSize: 0
|
|
property int iteration: 0
|
|
|
|
// BUG: edgeArea is destroyed before path, need to test if not null to avoid warnings
|
|
readonly property bool containsMouse: (loopArea && loopArea.containsMouse) || (edgeArea && edgeArea.containsMouse)
|
|
|
|
signal pressed(var event)
|
|
signal released(var event)
|
|
|
|
x: point1x
|
|
y: point1y
|
|
width: point2x - point1x
|
|
height: point2y - point1y
|
|
|
|
property real startX: 0
|
|
property real startY: 0
|
|
property real endX: width
|
|
property real endY: height
|
|
|
|
|
|
Shape {
|
|
anchors.fill: parent
|
|
// Cause rendering artifacts when enabled (and don't support hot reload really well)
|
|
vendorExtensionsEnabled: false
|
|
opacity: 0.7
|
|
|
|
ShapePath {
|
|
id: path
|
|
startX: root.startX
|
|
startY: root.startY
|
|
fillColor: "transparent"
|
|
|
|
strokeColor: "#3E3E3E"
|
|
strokeStyle: edge !== undefined && ((edge.src !== undefined && edge.src.isOutput) || edge.dst === undefined) ? ShapePath.SolidLine : ShapePath.DashLine
|
|
strokeWidth: 1
|
|
// Final visual width of this path (never below 1)
|
|
readonly property real visualWidth: Math.max(strokeWidth, 1)
|
|
dashPattern: [6 / visualWidth, 4 / visualWidth]
|
|
capStyle: ShapePath.RoundCap
|
|
|
|
PathCubic {
|
|
id: cubic
|
|
property real ctrlPtDist: 30
|
|
x: root.isForLoop ? (root.startX + root.endX) / 2 - loopArea.width / 2 : root.endX
|
|
y: root.isForLoop ? (root.startY + root.endY) / 2 : root.endY
|
|
relativeControl1X: ctrlPtDist
|
|
relativeControl1Y: 0
|
|
control2X: x - ctrlPtDist
|
|
control2Y: y
|
|
}
|
|
}
|
|
|
|
ShapePath {
|
|
id: pathSecondary
|
|
startX: (root.startX + root.endX) / 2 + loopArea.width / 2
|
|
startY: (root.startY + root.endY) / 2
|
|
fillColor: "transparent"
|
|
|
|
strokeColor: root.isForLoop ? root.color : "transparent"
|
|
strokeStyle: edge !== undefined && ((edge.src !== undefined && edge.src.isOutput) || edge.dst === undefined) ? ShapePath.SolidLine : ShapePath.DashLine
|
|
strokeWidth: root.thickness
|
|
// Final visual width of this path (never below 1)
|
|
readonly property real visualWidth: Math.max(strokeWidth, 1)
|
|
dashPattern: [6 / visualWidth, 4 / visualWidth]
|
|
capStyle: ShapePath.RoundCap
|
|
|
|
PathCubic {
|
|
id: cubicSecondary
|
|
property real ctrlPtDist: 30
|
|
x: root.endX
|
|
y: root.endY
|
|
relativeControl1X: ctrlPtDist
|
|
relativeControl1Y: 0
|
|
control2X: x - ctrlPtDist
|
|
control2Y: y
|
|
}
|
|
}
|
|
}
|
|
|
|
Item {
|
|
// Place the label at the middle of the edge
|
|
x: (root.startX + root.endX) / 2
|
|
y: (root.startY + root.endY) / 2
|
|
visible: root.isForLoop
|
|
|
|
Rectangle {
|
|
anchors.centerIn: parent
|
|
property int margin: 2
|
|
width: icon.width + 2 * margin
|
|
height: icon.height + 2 * margin
|
|
radius: width
|
|
color: path.strokeColor
|
|
|
|
MaterialToolLabel {
|
|
id: icon
|
|
anchors.centerIn: parent
|
|
|
|
iconText: MaterialIcons.loop
|
|
label: (root.iteration + 1) + "/" + root.loopSize + " "
|
|
|
|
labelIconColor: palette.base
|
|
ToolTip.text: "Foreach Loop"
|
|
}
|
|
|
|
MouseArea {
|
|
id: loopArea
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onClicked: root.pressed(arguments[0])
|
|
}
|
|
}
|
|
}
|
|
|
|
EdgeMouseArea {
|
|
id: edgeArea
|
|
anchors.fill: parent
|
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
thickness: root.thickness + 4
|
|
curveScale: cubic.ctrlPtDist / root.width // Normalize by width
|
|
}
|
|
|
|
MouseArea {
|
|
x: Math.min(0, root.width)
|
|
y: Math.min(0, root.height)
|
|
height: Math.abs(root.height)
|
|
width: Math.abs(root.width)
|
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
|
|
onPressed: function(event) {
|
|
let xpos = root.width < 0 ? root.height + event.x : event.x;
|
|
let ypos = root.height < 0 ? root.height + event.y: event.y;
|
|
if (edgeArea.containsPoint(Qt.point(xpos, ypos))) {
|
|
root.pressed(event);
|
|
}
|
|
else {
|
|
event.accepted = false;
|
|
}
|
|
}
|
|
|
|
onReleased: function(event) {
|
|
let xpos = root.width < 0 ? root.height + event.x : event.x;
|
|
let ypos = root.height < 0 ? root.height + event.y: event.y;
|
|
if (edgeArea.containsPoint(Qt.point(xpos, ypos))) {
|
|
root.released(event);
|
|
}
|
|
else {
|
|
event.accepted = false;
|
|
}
|
|
}
|
|
}
|
|
}
|