mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-06-04 11:51: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 submitRequest(var node)
|
||||
|
||||
// Files have been dropped
|
||||
signal filesDropped(var drop, var mousePosition)
|
||||
|
||||
// trigger initial fit() after initialization
|
||||
// (ensure GraphEditor has its final size)
|
||||
Component.onCompleted: firstFitTimer.start()
|
||||
|
@ -705,6 +708,20 @@ Item {
|
|||
Item {
|
||||
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
|
||||
|
|
|
@ -28,6 +28,9 @@ Panel {
|
|||
property int defaultCellSize: 160
|
||||
property bool readOnly: false
|
||||
|
||||
property bool isMeshroomScene : false
|
||||
property int nbFilesDropped: 0
|
||||
|
||||
signal removeImageRequest(var attribute)
|
||||
signal allViewpointsCleared()
|
||||
signal filesDropped(var drop, var augmentSfm)
|
||||
|
@ -438,7 +441,16 @@ Panel {
|
|||
anchors.fill: parent
|
||||
enabled: !m.readOnly && !intrinsicsFilterButton.checked
|
||||
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: {
|
||||
var augmentSfm = augmentArea.hovered
|
||||
root.filesDropped(drop, augmentSfm)
|
||||
|
@ -463,7 +475,17 @@ Panel {
|
|||
Layout.fillHeight: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
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
|
||||
background: Rectangle {
|
||||
color: parent.hovered ? parent.palette.highlight : parent.palette.window
|
||||
|
@ -483,7 +505,15 @@ Panel {
|
|||
text: "Augment Reconstruction"
|
||||
font.bold: true
|
||||
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 {
|
||||
color: parent.hovered ? palette.highlight : palette.window
|
||||
opacity: 0.8
|
||||
|
|
|
@ -80,7 +80,9 @@ Item {
|
|||
cameraInitIndex: reconstruction ? reconstruction.cameraInitIndex : -1
|
||||
onRemoveImageRequest: reconstruction.removeAttribute(attribute)
|
||||
onAllViewpointsCleared: { reconstruction.removeAllImages(); reconstruction.selectedViewId = "-1" }
|
||||
onFilesDropped: reconstruction.handleFilesDrop(drop, augmentSfm ? null : cameraInit)
|
||||
onFilesDropped: {
|
||||
reconstruction.handleFilesUrl(drop.urls, augmentSfm ? null : cameraInit)
|
||||
}
|
||||
}
|
||||
LiveSfmView {
|
||||
visible: settings_UILayout.showLiveReconstruction
|
||||
|
|
|
@ -1186,6 +1186,9 @@ ApplicationWindow {
|
|||
_reconstruction.forceNodesStatusUpdate();
|
||||
computeManager.submit(node)
|
||||
}
|
||||
onFilesDropped: {
|
||||
_reconstruction.handleFilesUrl(drop.urls, null, mousePosition)
|
||||
}
|
||||
}
|
||||
|
||||
TaskManager {
|
||||
|
|
|
@ -6,7 +6,7 @@ from collections.abc import Iterable
|
|||
from multiprocessing.pool import ThreadPool
|
||||
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
|
||||
|
||||
import meshroom.core
|
||||
|
@ -716,14 +716,24 @@ class Reconstruction(UIGraph):
|
|||
""" Get all view Ids involved in the reconstruction. """
|
||||
return [vp.viewId.value for node in self._cameraInits for vp in node.viewpoints.value]
|
||||
|
||||
@Slot(QObject, Node)
|
||||
def handleFilesDrop(self, drop, cameraInit):
|
||||
@Slot('QList<QUrl>')
|
||||
@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.
|
||||
Fetching urls from dropEvent is generally expensive in QML/JS (bug ?).
|
||||
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 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,))
|
||||
if filesByType.videos:
|
||||
boundingBox = self.layout.boundingBox()
|
||||
|
@ -773,6 +783,14 @@ class Reconstruction(UIGraph):
|
|||
|
||||
if not filesByType.images and not filesByType.videos and not filesByType.panoramaInfo:
|
||||
if filesByType.other:
|
||||
singleMgFile = False
|
||||
if len(filesByType.other) == 1:
|
||||
url = filesByType.other[0]
|
||||
ext = os.path.splitext(url)[1]
|
||||
if ext == '.mg':
|
||||
self.loadUrl(url)
|
||||
singleMgFile = True
|
||||
if not singleMgFile:
|
||||
extensions = set([os.path.splitext(url)[1] for url in filesByType.other])
|
||||
self.error.emit(
|
||||
Message(
|
||||
|
@ -783,16 +801,15 @@ class Reconstruction(UIGraph):
|
|||
)
|
||||
|
||||
@staticmethod
|
||||
def getFilesByTypeFromDrop(drop):
|
||||
def getFilesByTypeFromDrop(urls):
|
||||
"""
|
||||
|
||||
Args:
|
||||
drop:
|
||||
urls: list of filepaths
|
||||
|
||||
Returns:
|
||||
<images, otherFiles> List of recognized images and list of other files
|
||||
"""
|
||||
urls = drop.property("urls")
|
||||
# Build the list of images paths
|
||||
filesByType = multiview.FilesByType()
|
||||
for url in urls:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue