mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-06-06 04:41:58 +02:00
[ui] drag&drop: common behavior for graph editor and image gallery
In Image Gallery : - drop 1 .mg open the scene - drop images either create new camera or augment the reconstruction In Graph Editor : - drop 1 .mg open the scene - drop images create new camera at position of mouse
This commit is contained in:
parent
bb9661a141
commit
67fbf1b00f
5 changed files with 88 additions and 19 deletions
|
@ -29,6 +29,9 @@ Item {
|
||||||
signal computeRequest(var node)
|
signal computeRequest(var node)
|
||||||
signal submitRequest(var node)
|
signal submitRequest(var node)
|
||||||
|
|
||||||
|
// Files have been dropped
|
||||||
|
signal filesDropped(var drop, var mousePosition)
|
||||||
|
|
||||||
// trigger initial fit() after initialization
|
// trigger initial fit() after initialization
|
||||||
// (ensure GraphEditor has its final size)
|
// (ensure GraphEditor has its final size)
|
||||||
Component.onCompleted: firstFitTimer.start()
|
Component.onCompleted: firstFitTimer.start()
|
||||||
|
@ -705,6 +708,20 @@ Item {
|
||||||
Item {
|
Item {
|
||||||
id: boxSelectDraggable
|
id: boxSelectDraggable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DropArea {
|
||||||
|
id: dropArea
|
||||||
|
anchors.fill: parent
|
||||||
|
keys: ["text/uri-list"]
|
||||||
|
onDropped: {
|
||||||
|
// retrieve mouse position and convert coordinate system
|
||||||
|
// from pixel values to graph reference system
|
||||||
|
var mousePosition = mapToItem(draggable, drag.x, drag.y)
|
||||||
|
// send the list of files,
|
||||||
|
// to create the corresponding nodes or open another scene
|
||||||
|
filesDropped(drop, mousePosition)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toolbar
|
// Toolbar
|
||||||
|
|
|
@ -28,6 +28,9 @@ Panel {
|
||||||
property int defaultCellSize: 160
|
property int defaultCellSize: 160
|
||||||
property bool readOnly: false
|
property bool readOnly: false
|
||||||
|
|
||||||
|
property bool isMeshroomScene : false
|
||||||
|
property int nbFilesDropped: 0
|
||||||
|
|
||||||
signal removeImageRequest(var attribute)
|
signal removeImageRequest(var attribute)
|
||||||
signal allViewpointsCleared()
|
signal allViewpointsCleared()
|
||||||
signal filesDropped(var drop, var augmentSfm)
|
signal filesDropped(var drop, var augmentSfm)
|
||||||
|
@ -438,7 +441,16 @@ Panel {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
enabled: !m.readOnly && !intrinsicsFilterButton.checked
|
enabled: !m.readOnly && !intrinsicsFilterButton.checked
|
||||||
keys: ["text/uri-list"]
|
keys: ["text/uri-list"]
|
||||||
// TODO: onEntered: call specific method to filter files based on extension
|
onEntered: {
|
||||||
|
isMeshroomScene = false
|
||||||
|
nbFilesDropped = drag.urls.length
|
||||||
|
if (nbFilesDropped == 1){
|
||||||
|
var url = drag.urls[0]
|
||||||
|
if (url.endsWith(".mg")){
|
||||||
|
isMeshroomScene = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
onDropped: {
|
onDropped: {
|
||||||
var augmentSfm = augmentArea.hovered
|
var augmentSfm = augmentArea.hovered
|
||||||
root.filesDropped(drop, augmentSfm)
|
root.filesDropped(drop, augmentSfm)
|
||||||
|
@ -463,7 +475,17 @@ Panel {
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
text: "Add Images"
|
text: {
|
||||||
|
if (isMeshroomScene) {
|
||||||
|
if(nbFilesDropped == 1) {
|
||||||
|
return "Load Project"
|
||||||
|
} else {
|
||||||
|
return "Only one project"
|
||||||
|
}
|
||||||
|
}else if (!isMeshroomScene){
|
||||||
|
return "Add Images"
|
||||||
|
}
|
||||||
|
}
|
||||||
font.bold: true
|
font.bold: true
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: parent.hovered ? parent.palette.highlight : parent.palette.window
|
color: parent.hovered ? parent.palette.highlight : parent.palette.window
|
||||||
|
@ -483,7 +505,15 @@ Panel {
|
||||||
text: "Augment Reconstruction"
|
text: "Augment Reconstruction"
|
||||||
font.bold: true
|
font.bold: true
|
||||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||||
visible: m.viewpoints ? m.viewpoints.count > 0 : false
|
visible: {
|
||||||
|
if(isMeshroomScene)
|
||||||
|
return false
|
||||||
|
if(m.viewpoints){
|
||||||
|
return m.viewpoints.count > 0
|
||||||
|
}else{
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: parent.hovered ? palette.highlight : palette.window
|
color: parent.hovered ? palette.highlight : palette.window
|
||||||
opacity: 0.8
|
opacity: 0.8
|
||||||
|
|
|
@ -80,7 +80,9 @@ Item {
|
||||||
cameraInitIndex: reconstruction ? reconstruction.cameraInitIndex : -1
|
cameraInitIndex: reconstruction ? reconstruction.cameraInitIndex : -1
|
||||||
onRemoveImageRequest: reconstruction.removeAttribute(attribute)
|
onRemoveImageRequest: reconstruction.removeAttribute(attribute)
|
||||||
onAllViewpointsCleared: { reconstruction.removeAllImages(); reconstruction.selectedViewId = "-1" }
|
onAllViewpointsCleared: { reconstruction.removeAllImages(); reconstruction.selectedViewId = "-1" }
|
||||||
onFilesDropped: reconstruction.handleFilesDrop(drop, augmentSfm ? null : cameraInit)
|
onFilesDropped: {
|
||||||
|
reconstruction.handleFilesUrl(drop.urls, augmentSfm ? null : cameraInit)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
LiveSfmView {
|
LiveSfmView {
|
||||||
visible: settings_UILayout.showLiveReconstruction
|
visible: settings_UILayout.showLiveReconstruction
|
||||||
|
|
|
@ -1186,6 +1186,9 @@ ApplicationWindow {
|
||||||
_reconstruction.forceNodesStatusUpdate();
|
_reconstruction.forceNodesStatusUpdate();
|
||||||
computeManager.submit(node)
|
computeManager.submit(node)
|
||||||
}
|
}
|
||||||
|
onFilesDropped: {
|
||||||
|
_reconstruction.handleFilesUrl(drop.urls, null, mousePosition)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskManager {
|
TaskManager {
|
||||||
|
|
|
@ -6,7 +6,7 @@ from collections.abc import Iterable
|
||||||
from multiprocessing.pool import ThreadPool
|
from multiprocessing.pool import ThreadPool
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
from PySide2.QtCore import QObject, Slot, Property, Signal, QUrl, QSizeF
|
from PySide2.QtCore import QObject, Slot, Property, Signal, QUrl, QSizeF, QPoint
|
||||||
from PySide2.QtGui import QMatrix4x4, QMatrix3x3, QQuaternion, QVector3D, QVector2D
|
from PySide2.QtGui import QMatrix4x4, QMatrix3x3, QQuaternion, QVector3D, QVector2D
|
||||||
|
|
||||||
import meshroom.core
|
import meshroom.core
|
||||||
|
@ -716,14 +716,24 @@ class Reconstruction(UIGraph):
|
||||||
""" Get all view Ids involved in the reconstruction. """
|
""" Get all view Ids involved in the reconstruction. """
|
||||||
return [vp.viewId.value for node in self._cameraInits for vp in node.viewpoints.value]
|
return [vp.viewId.value for node in self._cameraInits for vp in node.viewpoints.value]
|
||||||
|
|
||||||
@Slot(QObject, Node)
|
@Slot('QList<QUrl>')
|
||||||
def handleFilesDrop(self, drop, cameraInit):
|
@Slot('QList<QUrl>', Node)
|
||||||
|
@Slot('QList<QUrl>', Node, 'QPoint')
|
||||||
|
def handleFilesUrl(self, urls, cameraInit=None, position=None):
|
||||||
""" Handle drop events aiming to add images to the Reconstruction.
|
""" Handle drop events aiming to add images to the Reconstruction.
|
||||||
Fetching urls from dropEvent is generally expensive in QML/JS (bug ?).
|
|
||||||
This method allows to reduce process time by doing it on Python side.
|
This method allows to reduce process time by doing it on Python side.
|
||||||
"""
|
"""
|
||||||
filesByType = self.getFilesByTypeFromDrop(drop)
|
filesByType = self.getFilesByTypeFromDrop(urls)
|
||||||
if filesByType.images:
|
if filesByType.images:
|
||||||
|
if cameraInit is None:
|
||||||
|
boundingBox = self.layout.boundingBox()
|
||||||
|
if not position:
|
||||||
|
p = Position(boundingBox[0], boundingBox[1] + boundingBox[3])
|
||||||
|
elif isinstance(position, QPoint):
|
||||||
|
p = Position(position.x(), position.y())
|
||||||
|
else:
|
||||||
|
p = position
|
||||||
|
cameraInit = self.addNewNode("CameraInit", position=p)
|
||||||
self._workerThreads.apply_async(func=self.importImagesSync, args=(filesByType.images, cameraInit,))
|
self._workerThreads.apply_async(func=self.importImagesSync, args=(filesByType.images, cameraInit,))
|
||||||
if filesByType.videos:
|
if filesByType.videos:
|
||||||
boundingBox = self.layout.boundingBox()
|
boundingBox = self.layout.boundingBox()
|
||||||
|
@ -773,26 +783,33 @@ class Reconstruction(UIGraph):
|
||||||
|
|
||||||
if not filesByType.images and not filesByType.videos and not filesByType.panoramaInfo:
|
if not filesByType.images and not filesByType.videos and not filesByType.panoramaInfo:
|
||||||
if filesByType.other:
|
if filesByType.other:
|
||||||
extensions = set([os.path.splitext(url)[1] for url in filesByType.other])
|
singleMgFile = False
|
||||||
self.error.emit(
|
if len(filesByType.other) == 1:
|
||||||
Message(
|
url = filesByType.other[0]
|
||||||
"No Recognized Input File",
|
ext = os.path.splitext(url)[1]
|
||||||
"No recognized input file in the {} dropped files".format(len(filesByType.other)),
|
if ext == '.mg':
|
||||||
"Unknown file extensions: " + ', '.join(extensions)
|
self.loadUrl(url)
|
||||||
|
singleMgFile = True
|
||||||
|
if not singleMgFile:
|
||||||
|
extensions = set([os.path.splitext(url)[1] for url in filesByType.other])
|
||||||
|
self.error.emit(
|
||||||
|
Message(
|
||||||
|
"No Recognized Input File",
|
||||||
|
"No recognized input file in the {} dropped files".format(len(filesByType.other)),
|
||||||
|
"Unknown file extensions: " + ', '.join(extensions)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getFilesByTypeFromDrop(drop):
|
def getFilesByTypeFromDrop(urls):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
drop:
|
urls: list of filepaths
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
<images, otherFiles> List of recognized images and list of other files
|
<images, otherFiles> List of recognized images and list of other files
|
||||||
"""
|
"""
|
||||||
urls = drop.property("urls")
|
|
||||||
# Build the list of images paths
|
# Build the list of images paths
|
||||||
filesByType = multiview.FilesByType()
|
filesByType = multiview.FilesByType()
|
||||||
for url in urls:
|
for url in urls:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue