mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-05-03 04:06:45 +02:00
* make Drag/DropArea overflow on the attribute's label to be more tolerant when connecting attributes * add visual feedback when hovering interactive areas * tweak spacings between attributes
182 lines
6.2 KiB
QML
Executable file
182 lines
6.2 KiB
QML
Executable file
import QtQuick 2.9
|
|
import QtQuick.Controls 2.3
|
|
import QtQuick.Layouts 1.3
|
|
|
|
/**
|
|
The representation of an Attribute on a Node.
|
|
*/
|
|
RowLayout {
|
|
id: root
|
|
|
|
property var nodeItem
|
|
property var attribute
|
|
property bool readOnly: false
|
|
|
|
// position of the anchor for attaching and edge to this attribute pin
|
|
readonly property point edgeAnchorPos: Qt.point(edgeAnchor.x + edgeAnchor.width/2,
|
|
edgeAnchor.y + edgeAnchor.height/2)
|
|
|
|
readonly property bool isList: attribute.type == "ListAttribute"
|
|
|
|
signal childPinCreated(var childAttribute, var pin)
|
|
signal childPinDeleted(var childAttribute, var pin)
|
|
|
|
signal pressed(var mouse)
|
|
|
|
objectName: attribute.name + "."
|
|
layoutDirection: attribute.isOutput ? Qt.RightToLeft : Qt.LeftToRight
|
|
spacing: 2
|
|
|
|
// Instantiate empty Items for each child attribute
|
|
Repeater {
|
|
id: childrenRepeater
|
|
model: isList && !attribute.isLink ? attribute.value : 0
|
|
onItemAdded: {childPinCreated(item.childAttribute, item)}
|
|
onItemRemoved: {childPinDeleted(item.childAttribute, item)}
|
|
delegate: Item {
|
|
property var childAttribute: object
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: edgeAnchor
|
|
|
|
width: 7
|
|
height: width
|
|
radius: isList ? 0 : width/2
|
|
Layout.alignment: Qt.AlignVCenter
|
|
border.color: "#3e3e3e"
|
|
color: {
|
|
if(connectMA.containsMouse || connectMA.drag.active || (dropArea.containsDrag && dropArea.acceptableDrop))
|
|
return nameLabel.palette.highlight
|
|
else if(attribute.isLink)
|
|
return "#3e3e3e"
|
|
return "white"
|
|
}
|
|
|
|
DropArea {
|
|
id: dropArea
|
|
|
|
property bool acceptableDrop: false
|
|
|
|
// add negative margins for DropArea to make the connection zone easier to reach
|
|
anchors.fill: parent
|
|
anchors.margins: -2
|
|
// add horizontal negative margins according to the current layout
|
|
anchors.leftMargin: root.layoutDirection == Qt.RightToLeft ? -root.width * 0.3 : 0
|
|
anchors.rightMargin: root.layoutDirection == Qt.LeftToRight ? -root.width * 0.3 : 0
|
|
|
|
keys: [dragTarget.objectName]
|
|
onEntered: {
|
|
// Filter drops:
|
|
if( drag.source.objectName != dragTarget.objectName // not an edge connector
|
|
|| drag.source.nodeItem == dragTarget.nodeItem // connection between attributes of the same node
|
|
|| dragTarget.isOutput // connection on an output
|
|
|| dragTarget.attribute.isLink // already connected attribute
|
|
|| (drag.source.isList && !dragTarget.isList) // connection between a list and a simple attribute
|
|
|| (drag.source.isList && childrenRepeater.count) // source/target are lists but target already has children
|
|
)
|
|
{
|
|
drag.accepted = false
|
|
}
|
|
dropArea.acceptableDrop = drag.accepted
|
|
}
|
|
onExited: acceptableDrop = false
|
|
|
|
onDropped: {
|
|
_reconstruction.addEdge(drag.source.attribute, dragTarget.attribute)
|
|
}
|
|
}
|
|
|
|
Item {
|
|
id: dragTarget
|
|
objectName: "edgeConnector"
|
|
readonly property alias attribute: root.attribute
|
|
readonly property alias nodeItem: root.nodeItem
|
|
readonly property bool isOutput: attribute.isOutput
|
|
readonly property alias isList: root.isList
|
|
anchors.centerIn: root.state == "Dragging" ? undefined : parent
|
|
width: 4
|
|
height: 4
|
|
Drag.keys: [dragTarget.objectName]
|
|
Drag.active: connectMA.drag.active
|
|
Drag.hotSpot.x: width*0.5
|
|
Drag.hotSpot.y: height*0.5
|
|
anchors.onCenterInChanged: {
|
|
// snap dragTarget to current mouse position in connectMA
|
|
if(anchors.centerIn == undefined) {
|
|
var pos = mapFromItem(connectMA, connectMA.mouseX, connectMA.mouseY)
|
|
x = pos.x
|
|
y = pos.y
|
|
}
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: connectMA
|
|
drag.target: dragTarget
|
|
drag.threshold: 0
|
|
enabled: !root.readOnly
|
|
anchors.fill: parent
|
|
// use the same negative margins as DropArea to ease pin selection
|
|
anchors.margins: dropArea.anchors.margins
|
|
anchors.leftMargin: dropArea.anchors.leftMargin
|
|
anchors.rightMargin: dropArea.anchors.rightMargin
|
|
onPressed: root.pressed(mouse)
|
|
onReleased: dragTarget.Drag.drop()
|
|
hoverEnabled: true
|
|
}
|
|
|
|
Edge {
|
|
id: connectEdge
|
|
visible: false
|
|
point1x: parent.width / 2
|
|
point1y: parent.width / 2
|
|
point2x: dragTarget.x + dragTarget.width/2
|
|
point2y: dragTarget.y + dragTarget.height/2
|
|
color: nameLabel.palette.text
|
|
}
|
|
}
|
|
|
|
// Attribute name
|
|
Label {
|
|
id: nameLabel
|
|
text: attribute.name
|
|
elide: Text.ElideMiddle
|
|
Layout.fillWidth: true
|
|
font.pointSize: 5
|
|
horizontalAlignment: attribute.isOutput ? Text.AlignRight : Text.AlignLeft
|
|
|
|
Loader {
|
|
active: parent.truncated && (connectMA.containsMouse || connectMA.drag.active || dropArea.containsDrag)
|
|
anchors.right: root.layoutDirection == Qt.LeftToRight ? undefined : nameLabel.right
|
|
// Non-elided label
|
|
sourceComponent: Label {
|
|
leftPadding: root.layoutDirection == Qt.LeftToRight ? 0 : 1
|
|
rightPadding: root.layoutDirection == Qt.LeftToRight ? 1 : 0
|
|
text: attribute.name
|
|
background: Rectangle {
|
|
color: parent.palette.window
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
state: connectMA.pressed ? "Dragging" : ""
|
|
|
|
states: [
|
|
State {
|
|
name: ""
|
|
},
|
|
|
|
State {
|
|
name: "Dragging"
|
|
PropertyChanges {
|
|
target: connectEdge
|
|
z: 100
|
|
visible: true
|
|
}
|
|
}
|
|
]
|
|
|
|
}
|