Meshroom/meshroom/ui/reconstruction.py
Yann Lanthony 00366cda00 [ui] introduce first functional UI with a graph editor
First functional UI that allows to visualize, modify and execute a graph locally.
* use QtQuick Controls 2 + Shapes (Qt >=5.10)
* main menu to save/load a graph
2017-10-31 16:54:16 +01:00

121 lines
3.8 KiB
Python
Executable file

import os
from threading import Thread
from PySide2.QtCore import QObject, Slot, Property, Signal, QJsonValue, QUrl
from meshroom import multiview
from meshroom.core import graph, defaultCacheFolder, cacheFolderName
from meshroom.ui import commands
class Reconstruction(QObject):
def __init__(self, graphFilepath="", parent=None):
super(Reconstruction, self).__init__(parent)
self._graph = None
self._undoStack = commands.UndoStack(self)
self._computeThread = Thread()
self._filepath = graphFilepath
if self._filepath:
self.load(self._filepath)
else:
self.new()
@Slot()
def new(self):
self.clear()
self._graph = multiview.photogrammetryPipeline()
self._graph.cacheDir = defaultCacheFolder
self.graphChanged.emit()
def clear(self):
if self._graph:
self._graph.deleteLater()
self._graph = None
self.setFilepath("")
self._undoStack.clear()
def setFilepath(self, path):
if self._filepath == path:
return
self._filepath = path
self.filepathChanged.emit()
@Slot(str)
def addNode(self, nodeType):
self._undoStack.tryAndPush(commands.AddNodeCommand(self._graph, nodeType))
@Slot(graph.Node)
def removeNode(self, node):
self._undoStack.tryAndPush(commands.RemoveNodeCommand(self._graph, node))
@Slot(graph.Attribute, graph.Attribute)
def addEdge(self, src, dst):
self._undoStack.tryAndPush(commands.AddEdgeCommand(self._graph, src, dst))
@Slot(graph.Edge)
def removeEdge(self, edge):
self._undoStack.tryAndPush(commands.RemoveEdgeCommand(self._graph, edge))
@Slot(graph.Attribute, "QVariant")
def setAttribute(self, attribute, value):
self._undoStack.tryAndPush(commands.SetAttributeCommand(self._graph, attribute, value))
@Slot(graph.Attribute, QJsonValue)
def appendAttribute(self, attribute, value):
self._undoStack.tryAndPush(commands.ListAttributeAppendCommand(self._graph, attribute, value.toObject()))
@Slot(graph.Attribute)
def removeAttribute(self, attribute):
self._undoStack.tryAndPush(commands.ListAttributeRemoveCommand(self._graph, attribute))
def load(self, filepath):
self.clear()
self._graph = graph.Graph("")
self._graph.load(filepath)
self.setFilepath(filepath)
self.graphChanged.emit()
@Slot(QUrl)
def loadUrl(self, url):
self.load(url.toLocalFile())
@Slot(QUrl)
def saveAs(self, url):
self.setFilepath(url.toLocalFile())
self.save()
@Slot()
def save(self):
self._graph.save(self._filepath)
self._graph.cacheDir = os.path.join(os.path.dirname(self._filepath), cacheFolderName)
self._undoStack.setClean()
@Slot(graph.Node)
def execute(self, node=None):
if self.computing:
return
nodes = [node] if node else self._graph.getLeaves()
self._computeThread = Thread(target=self._execute, args=(nodes,))
self._computeThread.start()
def _execute(self, nodes):
self.computingChanged.emit()
graph.execute(self._graph, nodes)
self.computingChanged.emit()
@Slot()
def stopExecution(self):
if not self.computing:
return
self._graph.stopExecution()
self._computeThread.join()
self.computingChanged.emit()
undoStack = Property(QObject, lambda self: self._undoStack, constant=True)
graphChanged = Signal()
graph = Property(graph.Graph, lambda self: self._graph, notify=graphChanged)
computingChanged = Signal()
computing = Property(bool, lambda self: self._computeThread.is_alive(), notify=computingChanged)
filepathChanged = Signal()
filepath = Property(str, lambda self: self._filepath, notify=filepathChanged)