[ui] GraphEditor: solo 3D media with Double Click + Control modifier

* allow to solo a 3D media from the GraphEditor by double clicking on a node or an attribute with the Control modifier pressed
* consistent with Viewer3D.MediaLibrary behavior (solo on Ctrl+Click on visibility button)
* handle supported file extensions in Viewer3DSettings
This commit is contained in:
Yann Lanthony 2019-01-07 15:25:06 +01:00
parent 4541d825ad
commit b5c985b3fb
8 changed files with 46 additions and 30 deletions

View file

@ -15,7 +15,7 @@ ListView {
property int labelWidth: 180 property int labelWidth: 180
signal upgradeRequest() signal upgradeRequest()
signal attributeDoubleClicked(var attribute) signal attributeDoubleClicked(var mouse, var attribute)
implicitHeight: contentHeight implicitHeight: contentHeight
@ -40,7 +40,7 @@ ListView {
readOnly: root.readOnly readOnly: root.readOnly
labelWidth: root.labelWidth labelWidth: root.labelWidth
attribute: object attribute: object
onDoubleClicked: root.attributeDoubleClicked(attr) onDoubleClicked: root.attributeDoubleClicked(mouse, attr)
} }
} }
} }

View file

@ -18,7 +18,7 @@ RowLayout {
readonly property bool editable: !attribute.isOutput && !attribute.isLink && !readOnly readonly property bool editable: !attribute.isOutput && !attribute.isLink && !readOnly
signal doubleClicked(var attr) signal doubleClicked(var mouse, var attr)
spacing: 2 spacing: 2
@ -62,7 +62,7 @@ RowLayout {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
acceptedButtons: Qt.AllButtons acceptedButtons: Qt.AllButtons
onDoubleClicked: root.doubleClicked(root.attribute) onDoubleClicked: root.doubleClicked(mouse, root.attribute)
property Component menuComp: Menu { property Component menuComp: Menu {
id: paramMenu id: paramMenu

View file

@ -21,7 +21,7 @@ Item {
// signals // signals
signal workspaceMoved() signal workspaceMoved()
signal workspaceClicked() signal workspaceClicked()
signal nodeDoubleClicked(var node) signal nodeDoubleClicked(var mouse, var node)
// trigger initial fit() after initialization // trigger initial fit() after initialization
// (ensure GraphEditor has its final size) // (ensure GraphEditor has its final size)
@ -409,7 +409,7 @@ Item {
} }
} }
onDoubleClicked: root.nodeDoubleClicked(node) onDoubleClicked: root.nodeDoubleClicked(mouse, node)
onMoved: uigraph.moveNode(node, position) onMoved: uigraph.moveNode(node, position)

View file

@ -16,7 +16,7 @@ Panel {
property bool readOnly: false property bool readOnly: false
property bool isCompatibilityNode: node && node.compatibilityIssue !== undefined property bool isCompatibilityNode: node && node.compatibilityIssue !== undefined
signal attributeDoubleClicked(var attribute) signal attributeDoubleClicked(var mouse, var attribute)
signal upgradeRequest() signal upgradeRequest()
title: "Node" + (node !== null ? " - <b>" + node.label + "</b>" : "") title: "Node" + (node !== null ? " - <b>" + node.label + "</b>" : "")
@ -116,7 +116,7 @@ Panel {
Layout.fillWidth: true Layout.fillWidth: true
attributes: root.node.attributes attributes: root.node.attributes
readOnly: root.readOnly || root.isCompatibilityNode readOnly: root.readOnly || root.isCompatibilityNode
onAttributeDoubleClicked: root.attributeDoubleClicked(attribute) onAttributeDoubleClicked: root.attributeDoubleClicked(mouse, attribute)
onUpgradeRequest: root.upgradeRequest() onUpgradeRequest: root.upgradeRequest()
} }

View file

@ -37,8 +37,21 @@ FocusScope {
mediaLibrary.load(filepath); mediaLibrary.load(filepath);
} }
/// View 'attribute' in the 3D Viewer. Media will be loaded if needed.
/// Returns whether the attribute can be visualized (matching type and extension).
function view(attribute) { function view(attribute) {
mediaLibrary.view(attribute) if( attribute.desc.type === "File"
&& Viewer3DSettings.supportedExtensions.indexOf(Filepath.extension(attribute.value)) > - 1 )
{
mediaLibrary.view(attribute);
return true;
}
return false;
}
/// Solo (i.e display only) the given attribute.
function solo(attribute) {
mediaLibrary.solo(mediaLibrary.find(attribute));
} }
function clear() { function clear() {

View file

@ -11,6 +11,16 @@ Item {
readonly property Component depthMapLoaderComp: Qt.createComponent("DepthMapLoader.qml") readonly property Component depthMapLoaderComp: Qt.createComponent("DepthMapLoader.qml")
readonly property bool supportDepthMap: depthMapLoaderComp.status == Component.Ready readonly property bool supportDepthMap: depthMapLoaderComp.status == Component.Ready
// supported 3D files extensions
readonly property var supportedExtensions: {
var exts = ['.obj'];
if(supportAlembic)
exts.push('.abc');
if(supportDepthMap)
exts.push('.exr');
return exts;
}
// Available render modes // Available render modes
readonly property var renderModes: [ // Can't use ListModel because of MaterialIcons expressions readonly property var renderModes: [ // Can't use ListModel because of MaterialIcons expressions
{"name": "Solid", "icon": MaterialIcons.crop_din }, {"name": "Solid", "icon": MaterialIcons.crop_din },

View file

@ -21,6 +21,7 @@ Item {
property variant reconstruction: _reconstruction property variant reconstruction: _reconstruction
readonly property variant cameraInits: _reconstruction.cameraInits readonly property variant cameraInits: _reconstruction.cameraInits
property bool readOnly: false property bool readOnly: false
readonly property Viewer3D viewer3D: viewer3D
implicitWidth: 300 implicitWidth: 300
@ -32,10 +33,6 @@ Item {
viewer3D.load(filepath); viewer3D.load(filepath);
} }
function viewAttribute(attr) {
viewer3D.view(attr);
}
Connections { Connections {
target: reconstruction target: reconstruction
onGraphChanged: viewer3D.clear() onGraphChanged: viewer3D.clear()
@ -48,7 +45,7 @@ Item {
function viewSfM() { function viewSfM() {
if(!reconstruction.sfm) if(!reconstruction.sfm)
return; return;
viewAttribute(reconstruction.sfm.attribute('output')); viewer3D.view(reconstruction.sfm.attribute('output'));
} }
SystemPalette { id: activePalette } SystemPalette { id: activePalette }
@ -144,7 +141,7 @@ Item {
anchors.bottomMargin: 10 anchors.bottomMargin: 10
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
visible: outputReady && outputMediaIndex == -1 visible: outputReady && outputMediaIndex == -1
onClicked: viewAttribute(_reconstruction.endNode.attribute("outputMesh")) onClicked: viewer3D.view(_reconstruction.endNode.attribute("outputMesh"))
} }
} }
} }

View file

@ -31,8 +31,6 @@ ApplicationWindow {
return t return t
} }
// supported 3D files extensions
readonly property var _3dFileExtensions: ['.obj', '.abc']
onClosing: { onClosing: {
// make sure document is saved before exiting application // make sure document is saved before exiting application
close.accepted = false close.accepted = false
@ -505,6 +503,14 @@ ApplicationWindow {
Layout.minimumHeight: 50 Layout.minimumHeight: 50
reconstruction: _reconstruction reconstruction: _reconstruction
readOnly: _reconstruction.computing readOnly: _reconstruction.computing
function viewIn3D(attribute, mouse) {
var loaded = viewer3D.view(attribute);
// solo media if Control modifier was held
if(loaded && mouse && mouse.modifiers & Qt.ControlModifier)
viewer3D.solo(attribute);
return loaded;
}
} }
} }
@ -550,15 +556,6 @@ ApplicationWindow {
} }
} }
function displayAttribute(attr) {
if( attr.desc.type === "File"
&& _3dFileExtensions.indexOf(Filepath.extension(attr.value)) > - 1 )
{
workspaceView.viewAttribute(attr);
return true;
}
return false;
}
GraphEditor { GraphEditor {
id: graphEditor id: graphEditor
@ -571,14 +568,13 @@ ApplicationWindow {
onNodeDoubleClicked: { onNodeDoubleClicked: {
if(node.nodeType === "StructureFromMotion") if(node.nodeType === "StructureFromMotion")
{ {
_reconstruction.sfm = node _reconstruction.sfm = node;
return
} }
for(var i=0; i < node.attributes.count; ++i) for(var i=0; i < node.attributes.count; ++i)
{ {
var attr = node.attributes.at(i) var attr = node.attributes.at(i)
if(attr.isOutput if(attr.isOutput
&& graphEditorPanel.displayAttribute(attr)) && workspaceView.viewIn3D(attr, mouse))
{ {
break; break;
} }
@ -592,7 +588,7 @@ ApplicationWindow {
node: _reconstruction.selectedNode node: _reconstruction.selectedNode
// Make NodeEditor readOnly when computing // Make NodeEditor readOnly when computing
readOnly: graphLocked readOnly: graphLocked
onAttributeDoubleClicked: graphEditorPanel.displayAttribute(attribute) onAttributeDoubleClicked: workspaceView.viewIn3D(attribute, mouse)
onUpgradeRequest: { onUpgradeRequest: {
var n = _reconstruction.upgradeNode(node); var n = _reconstruction.upgradeNode(node);
_reconstruction.selectedNode = n; _reconstruction.selectedNode = n;