mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-07-17 08:37:17 +02:00
Merge pull request #2599 from alicevision/dev/qt6.6
Qt6.6.3 / PySide6.6.3.1 upgrade
This commit is contained in:
commit
66e3dd409d
145 changed files with 2346 additions and 1702 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
# [qt6][qml] Clean-up code and harmonize comments
|
||||||
|
5a0b1c0c9547b0d00f3f10fae6994d6d8ea0b45e
|
||||||
# [nodes] Linting: Clean-up files
|
# [nodes] Linting: Clean-up files
|
||||||
4c0409f573c2694325b104c2686a1532f95cb9bc
|
4c0409f573c2694325b104c2686a1532f95cb9bc
|
||||||
# Linting: Clean-up files
|
# Linting: Clean-up files
|
||||||
|
|
|
@ -15,7 +15,7 @@ Meshroom is licensed under the [MPL2 license](LICENSE-MPL2.md).
|
||||||
Copyright (c) 2001-2018 Python Software Foundation.
|
Copyright (c) 2001-2018 Python Software Foundation.
|
||||||
Distributed under the [PSFL V2 license](https://www.python.org/download/releases/2.7/license/).
|
Distributed under the [PSFL V2 license](https://www.python.org/download/releases/2.7/license/).
|
||||||
|
|
||||||
* __Qt/PySide2__
|
* __Qt/PySide6__
|
||||||
[https://www.qt.io](https://www.qt.io)
|
[https://www.qt.io](https://www.qt.io)
|
||||||
Copyright (C) 2018 The Qt Company Ltd and other contributors.
|
Copyright (C) 2018 The Qt Company Ltd and other contributors.
|
||||||
Distributed under the [LGPL V3 license](https://opensource.org/licenses/LGPL-3.0).
|
Distributed under the [LGPL V3 license](https://opensource.org/licenses/LGPL-3.0).
|
||||||
|
|
|
@ -157,3 +157,4 @@ def setupEnvironment(backend=Backend.STANDALONE):
|
||||||
os.environ["QML_XHR_ALLOW_FILE_READ"] = '1'
|
os.environ["QML_XHR_ALLOW_FILE_READ"] = '1'
|
||||||
os.environ["QML_XHR_ALLOW_FILE_WRITE"] = '1'
|
os.environ["QML_XHR_ALLOW_FILE_WRITE"] = '1'
|
||||||
os.environ["PYSEQ_STRICT_PAD"] = '1'
|
os.environ["PYSEQ_STRICT_PAD"] = '1'
|
||||||
|
os.environ["QSG_RHI_BACKEND"] = "opengl"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from PySide2 import QtCore, QtQml
|
from PySide6 import QtCore, QtQml
|
||||||
import shiboken2
|
import shiboken6
|
||||||
|
|
||||||
|
|
||||||
class QObjectListModel(QtCore.QAbstractListModel):
|
class QObjectListModel(QtCore.QAbstractListModel):
|
||||||
|
@ -285,7 +285,7 @@ class QObjectListModel(QtCore.QAbstractListModel):
|
||||||
|
|
||||||
def _dereferenceItem(self, item):
|
def _dereferenceItem(self, item):
|
||||||
# Ask for object deletion if parented to the model
|
# Ask for object deletion if parented to the model
|
||||||
if shiboken2.isValid(item) and item.parent() == self:
|
if shiboken6.isValid(item) and item.parent() == self:
|
||||||
# delay deletion until the next event loop
|
# delay deletion until the next event loop
|
||||||
# This avoids warnings when the QML engine tries to evaluate (but should not)
|
# This avoids warnings when the QML engine tries to evaluate (but should not)
|
||||||
# an object that has already been deleted
|
# an object that has already been deleted
|
||||||
|
|
|
@ -116,8 +116,11 @@ class StatusData(BaseObject):
|
||||||
|
|
||||||
def toDict(self):
|
def toDict(self):
|
||||||
d = self.__dict__.copy()
|
d = self.__dict__.copy()
|
||||||
d.pop('destroyed', None) # skip non data attributes from BaseObject
|
|
||||||
d["elapsedTimeStr"] = self.elapsedTimeStr
|
d["elapsedTimeStr"] = self.elapsedTimeStr
|
||||||
|
|
||||||
|
# Skip non data attributes from BaseObject
|
||||||
|
d.pop("destroyed", None)
|
||||||
|
d.pop("objectNameChanged", None)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def fromDict(self, d):
|
def fromDict(self, d):
|
||||||
|
|
|
@ -39,7 +39,7 @@ class SimpleFarmSubmitter(BaseSubmitter):
|
||||||
# logging.info('REZ: {}'.format(str(r)))
|
# logging.info('REZ: {}'.format(str(r)))
|
||||||
v = r.split('-')
|
v = r.split('-')
|
||||||
# logging.info(' v: {}'.format(str(v)))
|
# logging.info(' v: {}'.format(str(v)))
|
||||||
if len(v) == 2:
|
if len(v) >= 2:
|
||||||
resolvedVersions[v[0]] = v[1]
|
resolvedVersions[v[0]] = v[1]
|
||||||
for p in packages:
|
for p in packages:
|
||||||
if p.startswith('~'):
|
if p.startswith('~'):
|
||||||
|
|
|
@ -10,4 +10,4 @@ import meshroom.ui
|
||||||
import meshroom.ui.app
|
import meshroom.ui.app
|
||||||
|
|
||||||
meshroom.ui.uiInstance = meshroom.ui.app.MeshroomApp(sys.argv)
|
meshroom.ui.uiInstance = meshroom.ui.app.MeshroomApp(sys.argv)
|
||||||
meshroom.ui.uiInstance.exec_()
|
meshroom.ui.uiInstance.exec()
|
||||||
|
|
|
@ -4,10 +4,11 @@ import re
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from PySide2 import QtCore
|
from PySide6 import __version__ as PySideVersion
|
||||||
from PySide2.QtCore import Qt, QUrl, QJsonValue, qInstallMessageHandler, QtMsgType, QSettings
|
from PySide6 import QtCore
|
||||||
from PySide2.QtGui import QIcon
|
from PySide6.QtCore import Qt, QUrl, QJsonValue, qInstallMessageHandler, QtMsgType, QSettings
|
||||||
from PySide2.QtWidgets import QApplication
|
from PySide6.QtGui import QIcon
|
||||||
|
from PySide6.QtWidgets import QApplication
|
||||||
|
|
||||||
import meshroom
|
import meshroom
|
||||||
from meshroom.core import nodesDesc
|
from meshroom.core import nodesDesc
|
||||||
|
@ -188,7 +189,7 @@ class MeshroomApp(QApplication):
|
||||||
def __init__(self, args):
|
def __init__(self, args):
|
||||||
meshroom.core.initPipelines()
|
meshroom.core.initPipelines()
|
||||||
|
|
||||||
QtArgs = [args[0], '-style', 'fusion'] + args[1:] # force Fusion style by default
|
QtArgs = [args[0], '-style', 'Fusion'] + args[1:] # force Fusion style by default
|
||||||
|
|
||||||
args = createMeshroomParser(args)
|
args = createMeshroomParser(args)
|
||||||
|
|
||||||
|
@ -202,8 +203,6 @@ class MeshroomApp(QApplication):
|
||||||
}
|
}
|
||||||
logging.getLogger().setLevel(logStringToPython[args.verbose])
|
logging.getLogger().setLevel(logStringToPython[args.verbose])
|
||||||
|
|
||||||
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
|
|
||||||
|
|
||||||
super(MeshroomApp, self).__init__(QtArgs)
|
super(MeshroomApp, self).__init__(QtArgs)
|
||||||
|
|
||||||
self.setOrganizationName('AliceVision')
|
self.setOrganizationName('AliceVision')
|
||||||
|
@ -355,6 +354,7 @@ class MeshroomApp(QApplication):
|
||||||
p = {"path": p, "thumbnail": thumbnail}
|
p = {"path": p, "thumbnail": thumbnail}
|
||||||
projects.append(p)
|
projects.append(p)
|
||||||
settings.endArray()
|
settings.endArray()
|
||||||
|
settings.endGroup()
|
||||||
return projects
|
return projects
|
||||||
|
|
||||||
@Slot(str)
|
@Slot(str)
|
||||||
|
@ -394,6 +394,7 @@ class MeshroomApp(QApplication):
|
||||||
settings.setArrayIndex(i)
|
settings.setArrayIndex(i)
|
||||||
settings.setValue("filepath", p)
|
settings.setValue("filepath", p)
|
||||||
settings.endArray()
|
settings.endArray()
|
||||||
|
settings.endGroup()
|
||||||
settings.sync()
|
settings.sync()
|
||||||
|
|
||||||
self.recentProjectFilesChanged.emit()
|
self.recentProjectFilesChanged.emit()
|
||||||
|
@ -539,7 +540,8 @@ class MeshroomApp(QApplication):
|
||||||
import sys
|
import sys
|
||||||
return {
|
return {
|
||||||
'platform': '{} {}'.format(platform.system(), platform.release()),
|
'platform': '{} {}'.format(platform.system(), platform.release()),
|
||||||
'python': 'Python {}'.format(sys.version.split(" ")[0])
|
'python': 'Python {}'.format(sys.version.split(" ")[0]),
|
||||||
|
'pyside': 'PySide6 {}'.format(PySideVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
systemInfo = Property(QJsonValue, _systemInfo, constant=True)
|
systemInfo = Property(QJsonValue, _systemInfo, constant=True)
|
||||||
|
|
|
@ -2,8 +2,8 @@ import logging
|
||||||
import traceback
|
import traceback
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
|
||||||
from PySide2.QtWidgets import QUndoCommand, QUndoStack
|
from PySide6.QtGui import QUndoCommand, QUndoStack
|
||||||
from PySide2.QtCore import Property, Signal
|
from PySide6.QtCore import Property, Signal
|
||||||
|
|
||||||
from meshroom.core.attribute import ListAttribute, Attribute
|
from meshroom.core.attribute import ListAttribute, Attribute
|
||||||
from meshroom.core.graph import GraphModification
|
from meshroom.core.graph import GraphModification
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
def registerTypes():
|
def registerTypes():
|
||||||
from PySide2.QtQml import qmlRegisterType
|
from PySide6.QtQml import qmlRegisterType
|
||||||
from meshroom.ui.components.clipboard import ClipboardHelper
|
from meshroom.ui.components.clipboard import ClipboardHelper
|
||||||
from meshroom.ui.components.edge import EdgeMouseArea
|
from meshroom.ui.components.edge import EdgeMouseArea
|
||||||
from meshroom.ui.components.filepath import FilepathHelper
|
from meshroom.ui.components.filepath import FilepathHelper
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from PySide2.QtCore import Slot, QObject
|
from PySide6.QtCore import Slot, QObject
|
||||||
from PySide2.QtGui import QClipboard
|
from PySide6.QtGui import QClipboard
|
||||||
|
|
||||||
|
|
||||||
class ClipboardHelper(QObject):
|
class ClipboardHelper(QObject):
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from meshroom.common.qt import QObjectListModel
|
from meshroom.common.qt import QObjectListModel
|
||||||
|
|
||||||
from PySide2.QtCore import QObject, Slot, Signal, Property
|
from PySide6.QtCore import QObject, Slot, Signal, Property
|
||||||
from PySide2.QtCharts import QtCharts
|
from PySide6 import QtCharts
|
||||||
|
|
||||||
import csv
|
import csv
|
||||||
import os
|
import os
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from PySide2.QtCore import Signal, Property, QPointF, Qt, QObject
|
from PySide6.QtCore import Signal, Property, QPointF, Qt, QObject
|
||||||
from PySide2.QtGui import QPainterPath, QVector2D
|
from PySide6.QtGui import QPainterPath, QVector2D
|
||||||
from PySide2.QtQuick import QQuickItem
|
from PySide6.QtQuick import QQuickItem
|
||||||
|
|
||||||
|
|
||||||
class MouseEvent(QObject):
|
class MouseEvent(QObject):
|
||||||
|
@ -9,8 +9,8 @@ class MouseEvent(QObject):
|
||||||
"""
|
"""
|
||||||
def __init__(self, evt):
|
def __init__(self, evt):
|
||||||
super(MouseEvent, self).__init__()
|
super(MouseEvent, self).__init__()
|
||||||
self._x = evt.x()
|
self._x = evt.position().x()
|
||||||
self._y = evt.y()
|
self._y = evt.position().y()
|
||||||
self._button = evt.button()
|
self._button = evt.button()
|
||||||
self._modifiers = evt.modifiers()
|
self._modifiers = evt.modifiers()
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# coding:utf-8
|
# coding:utf-8
|
||||||
from PySide2.QtCore import QUrl, QFileInfo
|
from PySide6.QtCore import QUrl, QFileInfo
|
||||||
from PySide2.QtCore import QObject, Slot
|
from PySide6.QtCore import QObject, Slot
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import glob
|
import glob
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
from math import acos, pi, sqrt, atan2, cos, sin, asin
|
from math import acos, pi, sqrt, atan2, cos, sin, asin
|
||||||
|
|
||||||
from PySide2.QtCore import QObject, Slot, QSize, Signal, QPointF
|
from PySide6.QtCore import QObject, Slot, QSize, Signal, QPointF
|
||||||
from PySide2.Qt3DCore import Qt3DCore
|
from PySide6.Qt3DCore import Qt3DCore
|
||||||
from PySide2.Qt3DRender import Qt3DRender
|
from PySide6.Qt3DRender import Qt3DRender
|
||||||
from PySide2.QtGui import QVector3D, QQuaternion, QVector2D, QVector4D, QMatrix4x4
|
from PySide6.QtGui import QVector3D, QQuaternion, QVector2D, QVector4D, QMatrix4x4
|
||||||
|
|
||||||
from meshroom.ui.utils import makeProperty
|
from meshroom.ui.utils import makeProperty
|
||||||
|
|
||||||
|
@ -41,14 +41,14 @@ class Scene3DHelper(QObject):
|
||||||
def faceCount(self, entity):
|
def faceCount(self, entity):
|
||||||
""" Returns face count based on children QGeometry buffers size."""
|
""" Returns face count based on children QGeometry buffers size."""
|
||||||
count = 0
|
count = 0
|
||||||
for geo in entity.findChildren(Qt3DRender.QGeometry):
|
for geo in entity.findChildren(Qt3DCore.QGeometry):
|
||||||
count += sum([attr.count() for attr in geo.attributes() if attr.name() == "vertexPosition"])
|
count += sum([attr.count() for attr in geo.attributes() if attr.name() == "vertexPosition"])
|
||||||
return count / 3
|
return count / 3
|
||||||
|
|
||||||
@Slot(Qt3DCore.QEntity, result=int)
|
@Slot(Qt3DCore.QEntity, result=int)
|
||||||
def vertexColorCount(self, entity):
|
def vertexColorCount(self, entity):
|
||||||
count = 0
|
count = 0
|
||||||
for geo in entity.findChildren(Qt3DRender.QGeometry):
|
for geo in entity.findChildren(Qt3DCore.QGeometry):
|
||||||
count += sum([attr.count() for attr in geo.attributes() if attr.name() == "vertexColor"])
|
count += sum([attr.count() for attr in geo.attributes() if attr.name() == "vertexColor"])
|
||||||
return count
|
return count
|
||||||
|
|
||||||
|
@ -59,10 +59,12 @@ class TrackballController(QObject):
|
||||||
Based on the C++ version from https://github.com/cjmdaixi/Qt3DTrackball
|
Based on the C++ version from https://github.com/cjmdaixi/Qt3DTrackball
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_windowSize = QSize()
|
def __init__(self, parent=None):
|
||||||
_camera = None
|
super().__init__(parent)
|
||||||
_trackballSize = 1.0
|
self._windowSize = QSize()
|
||||||
_rotationSpeed = 5.0
|
self._camera = None
|
||||||
|
self._trackballSize = 1.0
|
||||||
|
self._rotationSpeed = 5.0
|
||||||
|
|
||||||
def projectToTrackball(self, screenCoords):
|
def projectToTrackball(self, screenCoords):
|
||||||
sx = screenCoords.x()
|
sx = screenCoords.x()
|
||||||
|
@ -98,7 +100,7 @@ class TrackballController(QObject):
|
||||||
windowSizeChanged = Signal()
|
windowSizeChanged = Signal()
|
||||||
windowSize = makeProperty(QSize, '_windowSize', windowSizeChanged)
|
windowSize = makeProperty(QSize, '_windowSize', windowSizeChanged)
|
||||||
cameraChanged = Signal()
|
cameraChanged = Signal()
|
||||||
camera = makeProperty(Qt3DRender.QCamera, '_camera', cameraChanged)
|
camera = makeProperty(QObject, '_camera', cameraChanged)
|
||||||
trackballSizeChanged = Signal()
|
trackballSizeChanged = Signal()
|
||||||
trackballSize = makeProperty(float, '_trackballSize', trackballSizeChanged)
|
trackballSize = makeProperty(float, '_trackballSize', trackballSizeChanged)
|
||||||
rotationSpeedChanged = Signal()
|
rotationSpeedChanged = Signal()
|
||||||
|
@ -352,7 +354,23 @@ class Transformations3DHelper(QObject):
|
||||||
U = M * quaternion * M
|
U = M * quaternion * M
|
||||||
|
|
||||||
return U.toEulerAngles()
|
return U.toEulerAngles()
|
||||||
|
|
||||||
|
@Slot(QVector3D, QVector3D, float, float, result=QVector3D)
|
||||||
|
def getRotatedCameraViewVector(self, camereViewVector, cameraUpVector, pitch, yaw):
|
||||||
|
""" Compute the rotated camera view vector with given pitch and yaw (in degrees).
|
||||||
|
Args:
|
||||||
|
camereViewVector (QVector3D): Camera view vector, the displacement from the camera position to its target
|
||||||
|
cameraUpVector (QVector3D): Camera up vector, the direction the top of the camera is facing
|
||||||
|
pitch (float): Rotation pitch (in degrees)
|
||||||
|
yaw (float): Rotation yaw (in degrees)
|
||||||
|
Returns:
|
||||||
|
QVector3D: rotated camera view vector
|
||||||
|
"""
|
||||||
|
cameraSideVector = QVector3D.crossProduct(camereViewVector, cameraUpVector)
|
||||||
|
yawRot = QQuaternion.fromAxisAndAngle(cameraUpVector, yaw)
|
||||||
|
pitchRot = QQuaternion.fromAxisAndAngle(cameraSideVector, pitch)
|
||||||
|
return (yawRot * pitchRot).rotatedVector(camereViewVector)
|
||||||
|
|
||||||
@Slot(QVector3D, QMatrix4x4, Qt3DRender.QCamera, QSize, result=float)
|
@Slot(QVector3D, QMatrix4x4, Qt3DRender.QCamera, QSize, result=float)
|
||||||
def computeScaleUnitFromModelMatrix(self, axis, modelMat, camera, windowSize):
|
def computeScaleUnitFromModelMatrix(self, axis, modelMat, camera, windowSize):
|
||||||
""" Compute the length of the screen projected vector axis unit transformed by the model matrix.
|
""" Compute the length of the screen projected vector axis unit transformed by the model matrix.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from PySide2.QtCore import QObject, Slot
|
from PySide6.QtCore import QObject, Slot
|
||||||
|
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from contextlib import redirect_stdout
|
from contextlib import redirect_stdout
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from meshroom.common import Signal
|
from meshroom.common import Signal
|
||||||
|
|
||||||
from PySide2.QtCore import QObject, Slot, QSize, QUrl, Qt, QStandardPaths
|
from PySide6.QtCore import QObject, Slot, QSize, QUrl, Qt, QStandardPaths
|
||||||
from PySide2.QtGui import QImageReader, QImageWriter
|
from PySide6.QtGui import QImageReader, QImageWriter
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
|
@ -8,7 +8,7 @@ from enum import Enum
|
||||||
from threading import Thread, Event, Lock
|
from threading import Thread, Event, Lock
|
||||||
from multiprocessing.pool import ThreadPool
|
from multiprocessing.pool import ThreadPool
|
||||||
|
|
||||||
from PySide2.QtCore import Slot, QJsonValue, QObject, QUrl, Property, Signal, QPoint
|
from PySide6.QtCore import Slot, QJsonValue, QObject, QUrl, Property, Signal, QPoint
|
||||||
|
|
||||||
from meshroom.core import sessionUid
|
from meshroom.core import sessionUid
|
||||||
from meshroom.common.qt import QObjectListModel
|
from meshroom.common.qt import QObjectListModel
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from PySide2.QtCore import QObject, Qt, Slot, Property, Signal
|
from PySide6.QtCore import QObject, Qt, Slot, Property, Signal
|
||||||
from PySide2.QtGui import QPalette, QColor
|
from PySide6.QtGui import QPalette, QColor
|
||||||
from PySide2.QtWidgets import QApplication
|
from PySide6.QtWidgets import QApplication
|
||||||
|
|
||||||
|
|
||||||
class PaletteManager(QObject):
|
class PaletteManager(QObject):
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import Utils 1.0
|
import Utils 1.0
|
||||||
import MaterialIcons 2.2
|
import MaterialIcons 2.2
|
||||||
|
|
||||||
|
|
||||||
/// Meshroom "About" window
|
/**
|
||||||
|
* Meshroom "About" window
|
||||||
|
*/
|
||||||
|
|
||||||
Dialog {
|
Dialog {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
@ -24,7 +27,7 @@ Dialog {
|
||||||
modal: true
|
modal: true
|
||||||
closePolicy: Dialog.CloseOnEscape | Dialog.CloseOnPressOutside
|
closePolicy: Dialog.CloseOnEscape | Dialog.CloseOnPressOutside
|
||||||
padding: 30
|
padding: 30
|
||||||
topPadding: 0 // header provides top padding
|
topPadding: 0 // Header provides top padding
|
||||||
|
|
||||||
header: Pane {
|
header: Pane {
|
||||||
background: Item {}
|
background: Item {}
|
||||||
|
@ -56,7 +59,8 @@ Dialog {
|
||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
text: "Version " + Qt.application.version + "\n"
|
text: "Version " + Qt.application.version + "\n"
|
||||||
+ MeshroomApp.systemInfo["platform"] + " \n"
|
+ MeshroomApp.systemInfo["platform"] + " \n"
|
||||||
+ MeshroomApp.systemInfo["python"]
|
+ MeshroomApp.systemInfo["python"] + "\n"
|
||||||
|
+ MeshroomApp.systemInfo["pyside"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,16 +178,16 @@ Dialog {
|
||||||
sourceComponent: ScrollView {
|
sourceComponent: ScrollView {
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
// try to load the local file
|
// Try to load the local file
|
||||||
var url = Filepath.stringToUrl(modelData.localUrl)
|
var url = Filepath.stringToUrl(modelData.localUrl)
|
||||||
// fallback to the online url if file is not found
|
// Fallback to the online url if file is not found
|
||||||
if (!Filepath.exists(url))
|
if (!Filepath.exists(url))
|
||||||
url = modelData.onlineUrl
|
url = modelData.onlineUrl
|
||||||
Request.get(url,
|
Request.get(url,
|
||||||
function(xhr) {
|
function(xhr) {
|
||||||
if (xhr.readyState === XMLHttpRequest.DONE)
|
if (xhr.readyState === XMLHttpRequest.DONE)
|
||||||
{
|
{
|
||||||
// status is OK
|
// Status is OK
|
||||||
if (xhr.status === 200)
|
if (xhr.status === 200)
|
||||||
textArea.text = MeshroomApp.markdownToHtml(xhr.responseText)
|
textArea.text = MeshroomApp.markdownToHtml(xhr.responseText)
|
||||||
else
|
else
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import QtQuick 2.15
|
import QtCore
|
||||||
import QtQuick.Controls 2.15
|
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick
|
||||||
import QtQuick.Window 2.15
|
import QtQuick.Controls
|
||||||
import QtQml.Models 2.15
|
import QtQuick.Layouts
|
||||||
|
import QtQml.Models
|
||||||
|
|
||||||
import Qt.labs.platform 1.0 as Platform
|
import Qt.labs.platform 1.0 as Platform
|
||||||
import QtQuick.Dialogs 1.3
|
import QtQuick.Dialogs
|
||||||
|
|
||||||
import Qt.labs.settings 1.0
|
|
||||||
import GraphEditor 1.0
|
import GraphEditor 1.0
|
||||||
import MaterialIcons 2.2
|
import MaterialIcons 2.2
|
||||||
import Utils 1.0
|
import Utils 1.0
|
||||||
|
@ -22,7 +22,7 @@ Page {
|
||||||
|
|
||||||
Settings {
|
Settings {
|
||||||
id: settingsUILayout
|
id: settingsUILayout
|
||||||
category: 'UILayout'
|
category: "UILayout"
|
||||||
property alias showLiveReconstruction: liveSfMVisibilityCB.checked
|
property alias showLiveReconstruction: liveSfMVisibilityCB.checked
|
||||||
property alias showGraphEditor: graphEditorVisibilityCB.checked
|
property alias showGraphEditor: graphEditorVisibilityCB.checked
|
||||||
property alias showImageViewer: imageViewerVisibilityCB.checked
|
property alias showImageViewer: imageViewerVisibilityCB.checked
|
||||||
|
@ -521,8 +521,8 @@ Page {
|
||||||
text: "Load Template"
|
text: "Load Template"
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
ensureSaved(function() {
|
ensureSaved(function() {
|
||||||
initFileDialogFolder(loadTemplateDialog);
|
initFileDialogFolder(loadTemplateDialog)
|
||||||
loadTemplateDialog.open();
|
loadTemplateDialog.open()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1158,15 +1158,15 @@ Page {
|
||||||
uigraph: _reconstruction
|
uigraph: _reconstruction
|
||||||
nodeTypesModel: _nodeTypes
|
nodeTypesModel: _nodeTypes
|
||||||
|
|
||||||
onNodeDoubleClicked: {
|
onNodeDoubleClicked: function(mouse, node) {
|
||||||
_reconstruction.setActiveNode(node);
|
_reconstruction.setActiveNode(node);
|
||||||
workspaceView.viewNode(node, mouse);
|
workspaceView.viewNode(node, mouse);
|
||||||
}
|
}
|
||||||
onComputeRequest: {
|
onComputeRequest: function(nodes) {
|
||||||
_reconstruction.forceNodesStatusUpdate();
|
_reconstruction.forceNodesStatusUpdate();
|
||||||
computeManager.compute(nodes)
|
computeManager.compute(nodes)
|
||||||
}
|
}
|
||||||
onSubmitRequest: {
|
onSubmitRequest: function(nodes) {
|
||||||
_reconstruction.forceNodesStatusUpdate();
|
_reconstruction.forceNodesStatusUpdate();
|
||||||
computeManager.submit(nodes)
|
computeManager.submit(nodes)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A custom CheckBox designed to be used in ChartView's legend.
|
* A custom CheckBox designed to be used in ChartView's legend.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
CheckBox {
|
CheckBox {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtCharts 2.15
|
import QtCharts
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ChartViewLegend is an interactive legend component for ChartViews.
|
* ChartViewLegend is an interactive legend component for ChartViews.
|
||||||
* It provides a CheckBox for each series that can control its visibility,
|
* It provides a CheckBox for each series that can control its visibility,
|
||||||
* and highlight on hovering.
|
* and highlight on hovering.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Flow {
|
Flow {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
@ -49,7 +49,6 @@ Flow {
|
||||||
}
|
}
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
|
|
||||||
// ChartView series can't be accessed directly as a model.
|
// ChartView series can't be accessed directly as a model.
|
||||||
// Use an intermediate ListModel populated with those series.
|
// Use an intermediate ListModel populated with those series.
|
||||||
model: ListModel {
|
model: ListModel {
|
||||||
|
@ -70,7 +69,7 @@ Flow {
|
||||||
root.hoveredSeries = null
|
root.hoveredSeries = null
|
||||||
}
|
}
|
||||||
|
|
||||||
// hovered serie properties override
|
// Hovered serie properties override
|
||||||
states: [
|
states: [
|
||||||
State {
|
State {
|
||||||
when: series && root.hoveredSeries === series
|
when: series && root.hoveredSeries === series
|
||||||
|
@ -84,7 +83,7 @@ Flow {
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: function(mouse) {
|
||||||
if (mouse.modifiers & Qt.ControlModifier)
|
if (mouse.modifiers & Qt.ControlModifier)
|
||||||
root.soloSeries(index)
|
root.soloSeries(index)
|
||||||
else
|
else
|
||||||
|
|
|
@ -1,15 +1,6 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Layouts
|
||||||
import QtQuick.Layouts 1.11
|
import QtCharts
|
||||||
import MaterialIcons 2.2
|
|
||||||
import QtPositioning 5.15
|
|
||||||
import QtLocation 5.15
|
|
||||||
|
|
||||||
import QtCharts 2.15
|
|
||||||
|
|
||||||
import Controls 1.0
|
|
||||||
import Utils 1.0
|
|
||||||
|
|
||||||
|
|
||||||
ChartView {
|
ChartView {
|
||||||
id: root
|
id: root
|
||||||
|
@ -26,32 +17,11 @@ ChartView {
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
property double degreeToScale: 1.0 / 120.0 // default mouse scroll is 15 degree
|
property double degreeToScale: 1.0 / 120.0 // Default mouse scroll is 15 degree
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||||
// onWheel: {
|
|
||||||
// console.warn("root.plotArea before: " + root.plotArea)
|
|
||||||
// var zoomFactor = wheel.angleDelta.y > 0 ? 1.0 / (1.0 + wheel.angleDelta.y * degreeToScale) : (1.0 + Math.abs(wheel.angleDelta.y) * degreeToScale)
|
|
||||||
|
|
||||||
// // var mouse_screen = Qt.point(wheel.x, wheel.y)
|
|
||||||
// var mouse_screen = mapToItem(root, wheel.x, wheel.y)
|
|
||||||
// var mouse_normalized = Qt.point(mouse_screen.x / plotZone.width, mouse_screen.y / plotZone.height)
|
|
||||||
// var mouse_plot = Qt.point(mouse_normalized.x * plotZone.width, mouse_normalized.y * plotZone.height)
|
|
||||||
|
|
||||||
// // var p = mapToValue(mouse_screen, root.series(0))
|
|
||||||
// // var pMin = mapToValue(mouse_screen, Qt.point(root.axisX().min, root.axisY().min))
|
|
||||||
// // var pMax = mapToValue(mouse_screen, Qt.point(root.axisX().max, root.axisY().max))
|
|
||||||
// // console.warn("p: " + p)
|
|
||||||
|
|
||||||
// // Qt.rect()
|
|
||||||
// var r = Qt.rect(mouse_plot.x, mouse_plot.y, plotZone.width * zoomFactor, plotZone.height * zoomFactor)
|
|
||||||
// //var r = Qt.rect(pMin.x, pMin.y, (pMax.x-pMin.x) / 2, (pMax.y-pMin.y) / 2)
|
|
||||||
// root.zoomIn(r)
|
|
||||||
// }
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.zoomReset()
|
root.zoomReset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
|
|
||||||
import Utils 1.0
|
import Utils 1.0
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import Utils 1.0
|
||||||
* ColorChart is a color picker based on a set of predefined colors.
|
* ColorChart is a color picker based on a set of predefined colors.
|
||||||
* It takes the form of a ToolButton that pops-up its palette when pressed.
|
* It takes the form of a ToolButton that pops-up its palette when pressed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ToolButton {
|
ToolButton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
@ -28,10 +29,10 @@ ToolButton {
|
||||||
id: palettePopup
|
id: palettePopup
|
||||||
|
|
||||||
padding: 4
|
padding: 4
|
||||||
// content width is missing side padding (hence the + padding*2)
|
// Content width is missing side padding (hence the + padding*2)
|
||||||
implicitWidth: colorChart.contentItem.width + padding * 2
|
implicitWidth: colorChart.contentItem.width + padding * 2
|
||||||
|
|
||||||
// center the current color
|
// Center the current color
|
||||||
y: -(root.height - padding) / 2
|
y: -(root.height - padding) / 2
|
||||||
x: -colorChart.currentItem.x - padding
|
x: -colorChart.currentItem.x - padding
|
||||||
|
|
||||||
|
@ -44,14 +45,14 @@ ToolButton {
|
||||||
spacing: 2
|
spacing: 2
|
||||||
currentIndex: root.currentIndex
|
currentIndex: root.currentIndex
|
||||||
model: root.colors
|
model: root.colors
|
||||||
// display each color as a ToolButton with a custom background
|
// Display each color as a ToolButton with a custom background
|
||||||
delegate: ToolButton {
|
delegate: ToolButton {
|
||||||
padding: 0
|
padding: 0
|
||||||
width: root.width
|
width: root.width
|
||||||
height: root.height
|
height: root.height
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: modelData
|
color: modelData
|
||||||
// display border of current/selected item
|
// Display border of current/selected item
|
||||||
border.width: hovered || index === colorChart.currentIndex ? 1 : 0
|
border.width: hovered || index === colorChart.currentIndex ? 1 : 0
|
||||||
border.color: Colors.sysPalette.midlight
|
border.color: Colors.sysPalette.midlight
|
||||||
}
|
}
|
||||||
|
|
261
meshroom/ui/qml/Controls/DirectionalLightPane.qml
Normal file
261
meshroom/ui/qml/Controls/DirectionalLightPane.qml
Normal file
|
@ -0,0 +1,261 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Qt5Compat.GraphicalEffects // for OpacityMask & Glow
|
||||||
|
import MaterialIcons 2.2
|
||||||
|
import Utils 1.0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directional Light Pane
|
||||||
|
*
|
||||||
|
* @biref A small pane to control a directional light with a 2d ball controller.
|
||||||
|
*
|
||||||
|
* @param lightYawValue - directional light yaw (degrees)
|
||||||
|
* @param lightPitchValue - directional light pitch (degrees)
|
||||||
|
*/
|
||||||
|
|
||||||
|
FloatingPane {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
// yaw and pitch properties
|
||||||
|
property double lightYawValue: 0
|
||||||
|
property double lightPitchValue: 0
|
||||||
|
|
||||||
|
// 2d controller display size properties
|
||||||
|
readonly property real controllerSize: 80
|
||||||
|
readonly property real controllerRadius: controllerSize * 0.5
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
lightYawValue = 0;
|
||||||
|
lightPitchValue = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update 2d controller if yaw value changed
|
||||||
|
onLightYawValueChanged: { lightBallController.update() }
|
||||||
|
|
||||||
|
// update 2d controller if pitch value changed
|
||||||
|
onLightPitchValueChanged: { lightBallController.update() }
|
||||||
|
|
||||||
|
anchors.margins: 0
|
||||||
|
padding: 5
|
||||||
|
radius: 0
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 5
|
||||||
|
|
||||||
|
// header
|
||||||
|
RowLayout {
|
||||||
|
// pane title
|
||||||
|
Label {
|
||||||
|
text: "Directional Light"
|
||||||
|
font.bold: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
// minimize or maximize button
|
||||||
|
MaterialToolButton {
|
||||||
|
id: bodyButton
|
||||||
|
text: lightPaneBody.visible ? MaterialIcons.arrow_drop_down : MaterialIcons.arrow_drop_up
|
||||||
|
font.pointSize: 10
|
||||||
|
ToolTip.text: lightPaneBody.visible ? "Minimize" : "Maximize"
|
||||||
|
onClicked: { lightPaneBody.visible = !lightPaneBody.visible }
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset button
|
||||||
|
MaterialToolButton {
|
||||||
|
id: resetButton
|
||||||
|
text: MaterialIcons.refresh
|
||||||
|
font.pointSize: 10
|
||||||
|
ToolTip.text: "Reset"
|
||||||
|
onClicked: reset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// body
|
||||||
|
RowLayout {
|
||||||
|
id: lightPaneBody
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
// light parameters
|
||||||
|
GridLayout {
|
||||||
|
columns: 3
|
||||||
|
rowSpacing: 2
|
||||||
|
columnSpacing: 8
|
||||||
|
Layout.alignment: Qt.AlignBottom
|
||||||
|
|
||||||
|
// light yaw
|
||||||
|
Label {
|
||||||
|
text: "Yaw"
|
||||||
|
}
|
||||||
|
TextField {
|
||||||
|
id: lightYawTF
|
||||||
|
text: lightYawValue.toFixed(2)
|
||||||
|
selectByMouse: true
|
||||||
|
horizontalAlignment: TextInput.AlignRight
|
||||||
|
validator: doubleDegreeValidator
|
||||||
|
onEditingFinished: { lightYawValue = lightYawTF.text }
|
||||||
|
ToolTip.text: "Light yaw (degrees)."
|
||||||
|
ToolTip.visible: hovered
|
||||||
|
Layout.preferredWidth: textMetricsDegreeValue.width
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
text: "°"
|
||||||
|
}
|
||||||
|
|
||||||
|
// light pitch
|
||||||
|
Label {
|
||||||
|
text: "Pitch"
|
||||||
|
}
|
||||||
|
TextField {
|
||||||
|
id: lightPitchTF
|
||||||
|
text: lightPitchValue.toFixed(2)
|
||||||
|
selectByMouse: true
|
||||||
|
horizontalAlignment: TextInput.AlignRight
|
||||||
|
validator: doubleDegreeValidator
|
||||||
|
onEditingFinished: { lightPitchValue = lightPitchTF.text }
|
||||||
|
ToolTip.text: "Light pitch (degrees)."
|
||||||
|
ToolTip.visible: hovered
|
||||||
|
Layout.preferredWidth: textMetricsDegreeValue.width
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
text: "°"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// directional light ball controller
|
||||||
|
Rectangle {
|
||||||
|
id: lightBallController
|
||||||
|
anchors.margins: 0
|
||||||
|
width: controllerSize
|
||||||
|
height: controllerSize
|
||||||
|
radius: 180 // circle
|
||||||
|
color: "#FF000000"
|
||||||
|
Layout.rightMargin: 5
|
||||||
|
Layout.leftMargin: 5
|
||||||
|
Layout.bottomMargin: 5
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
// get point from light yaw and pitch
|
||||||
|
var y = (lightPitchValue / 90 * controllerRadius)
|
||||||
|
var xMax = Math.sqrt(controllerRadius * controllerRadius - y * y) // get sphere maximum x coordinate
|
||||||
|
var x = (lightYawValue / 90 * xMax)
|
||||||
|
|
||||||
|
// get angle and distance
|
||||||
|
var angleRad = Math.atan2(y, x)
|
||||||
|
var distance = Math.sqrt(x * x + y * y)
|
||||||
|
|
||||||
|
// avoid controller overflow
|
||||||
|
if(distance > controllerRadius)
|
||||||
|
{
|
||||||
|
x = controllerRadius * Math.cos(angleRad)
|
||||||
|
y = controllerRadius * Math.sin(angleRad)
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute distance function for light gradient emulation
|
||||||
|
var distanceRatio = Math.min(distance, controllerRadius) / controllerRadius
|
||||||
|
var distanceFunct = distanceRatio * distanceRatio * 0.3
|
||||||
|
|
||||||
|
// update light point
|
||||||
|
lightPoint.x = lightPoint.startOffset + x
|
||||||
|
lightPoint.y = lightPoint.startOffset + y
|
||||||
|
|
||||||
|
// update light gradient
|
||||||
|
lightGradient.angle = angleRad * (180 / Math.PI) // radians to degrees
|
||||||
|
lightGradient.horizontalRadius = controllerSize * (1 - distanceFunct)
|
||||||
|
lightGradient.verticalRadius = controllerSize * (1 + distanceFunct)
|
||||||
|
lightGradient.horizontalOffset = x * (1 - distanceFunct)
|
||||||
|
lightGradient.verticalOffset = y * (1 - distanceFunct)
|
||||||
|
}
|
||||||
|
|
||||||
|
RadialGradient {
|
||||||
|
id: lightGradient
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: controllerSize
|
||||||
|
height: width
|
||||||
|
horizontalRadius: controllerSize
|
||||||
|
verticalRadius: controllerSize
|
||||||
|
angle: 0
|
||||||
|
gradient: Gradient {
|
||||||
|
GradientStop { position: 0.00; color: "#FFFFFFFF" }
|
||||||
|
GradientStop { position: 0.10; color: "#FFAAAAAA" }
|
||||||
|
GradientStop { position: 0.50; color: "#FF0C0C0C" }
|
||||||
|
}
|
||||||
|
layer.enabled: true
|
||||||
|
layer.effect: OpacityMask {
|
||||||
|
id: mask
|
||||||
|
maskSource: Rectangle {
|
||||||
|
height: lightGradient.height
|
||||||
|
width: lightGradient.width
|
||||||
|
radius: 180 // circle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: lightPoint
|
||||||
|
|
||||||
|
property double startOffset : (parent.width - width) * 0.5
|
||||||
|
|
||||||
|
x: startOffset
|
||||||
|
y: startOffset
|
||||||
|
width: controllerRadius / 6
|
||||||
|
height: width
|
||||||
|
radius: 180 // circle
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
|
||||||
|
Glow {
|
||||||
|
anchors.fill: lightPoint
|
||||||
|
radius: controllerRadius / 5
|
||||||
|
samples: 17
|
||||||
|
color: "white"
|
||||||
|
source: lightPoint
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: lightMouseArea
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
onPositionChanged: {
|
||||||
|
// get coordinates from center
|
||||||
|
var x = mouseX - controllerRadius
|
||||||
|
var y = mouseY - controllerRadius
|
||||||
|
|
||||||
|
// get distance to center
|
||||||
|
var distance = Math.sqrt(x * x + y * y)
|
||||||
|
|
||||||
|
// avoid controller overflow
|
||||||
|
if(distance > controllerRadius)
|
||||||
|
{
|
||||||
|
var angleRad = Math.atan2(y, x)
|
||||||
|
x = controllerRadius * Math.cos(angleRad)
|
||||||
|
y = controllerRadius * Math.sin(angleRad)
|
||||||
|
}
|
||||||
|
|
||||||
|
// get sphere maximum x coordinate
|
||||||
|
var xMax = Math.sqrt(controllerRadius * controllerRadius - y * y)
|
||||||
|
|
||||||
|
// update light yaw and pitch
|
||||||
|
lightYawValue = (xMax > 0) ? ((x / xMax) * 90) : 0 // between -90 and 90 degrees
|
||||||
|
lightPitchValue = (y / controllerRadius) * 90 // between -90 and 90 degrees
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DoubleValidator {
|
||||||
|
id: doubleDegreeValidator
|
||||||
|
locale: 'C' // use '.' decimal separator disregarding of the system locale
|
||||||
|
bottom: -90.0
|
||||||
|
top: 90.0
|
||||||
|
}
|
||||||
|
|
||||||
|
TextMetrics {
|
||||||
|
id: textMetricsDegreeValue
|
||||||
|
font: lightYawTF.font
|
||||||
|
text: "12.3456"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import QtQuick 2.11
|
import QtQuick
|
||||||
|
|
||||||
import Utils 1.0
|
import Utils 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import MaterialIcons 2.2
|
import MaterialIcons 2.2
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
|
|
||||||
import Utils 1.0
|
import Utils 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FloatingPane provides a Pane with a slightly transparent default background
|
* FloatingPane provides a Pane with a slightly transparent default background
|
||||||
* using palette.base as color. Useful to create floating toolbar/overlays.
|
* using palette.base as color. Useful to create floating toolbar/overlays.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Pane {
|
Pane {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
@ -14,5 +15,9 @@ Pane {
|
||||||
|
|
||||||
padding: 6
|
padding: 6
|
||||||
anchors.margins: 2
|
anchors.margins: 2
|
||||||
background: Rectangle { color: root.palette.base; opacity: opaque ? 1.0 : 0.7; radius: root.radius }
|
background: Rectangle {
|
||||||
|
color: root.palette.base
|
||||||
|
opacity: opaque ? 1.0 : 0.7
|
||||||
|
radius: root.radius
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import MaterialIcons 2.2
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A custom GroupBox with predefined header.
|
* A custom GroupBox with predefined header.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
GroupBox {
|
GroupBox {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
@ -21,13 +21,14 @@ GroupBox {
|
||||||
background: Item {}
|
background: Item {}
|
||||||
|
|
||||||
label: Pane {
|
label: Pane {
|
||||||
|
padding: 2
|
||||||
|
width: root.width
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
id: labelBg
|
id: labelBg
|
||||||
color: palette.base
|
color: palette.base
|
||||||
opacity: 0.8
|
opacity: 0.8
|
||||||
}
|
}
|
||||||
padding: 2
|
|
||||||
width: root.width
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
Label {
|
Label {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import MaterialIcons 2.2
|
import MaterialIcons 2.2
|
||||||
import QtQuick.Controls 2.15
|
|
||||||
import QtQuick.Layouts 1.11
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IntSelector with arrows and a text input to select a number
|
* IntSelector with arrows and a text input to select a number
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import MaterialIcons 2.2
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* KeyValue allows to create a list of key/value, like a table.
|
* KeyValue allows to create a list of key/value, like a table.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
property alias key: keyLabel.text
|
property alias key: keyLabel.text
|
||||||
property alias value: valueText.text
|
property alias value: valueText.text
|
||||||
|
@ -20,7 +20,6 @@ Rectangle {
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.margins: 2
|
anchors.margins: 2
|
||||||
color: Qt.darker(activePalette.window, 1.1)
|
color: Qt.darker(activePalette.window, 1.1)
|
||||||
// Layout.preferredWidth: sizeHandle.x
|
|
||||||
Layout.minimumWidth: 10.0 * Qt.application.font.pixelSize
|
Layout.minimumWidth: 10.0 * Qt.application.font.pixelSize
|
||||||
Layout.maximumWidth: 15.0 * Qt.application.font.pixelSize
|
Layout.maximumWidth: 15.0 * Qt.application.font.pixelSize
|
||||||
Layout.fillWidth: false
|
Layout.fillWidth: false
|
||||||
|
@ -46,7 +45,10 @@ Rectangle {
|
||||||
|
|
||||||
readOnly: true
|
readOnly: true
|
||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
background: Rectangle { anchors.fill: parent; color: Qt.darker(activePalette.window, 1.05) }
|
background: Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Qt.darker(activePalette.window, 1.05)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import QtQuick 2.0
|
import QtQuick
|
||||||
import QtQuick.Controls 2.0
|
import QtQuick.Controls
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MScrollBar is a custom scrollbar implementation.
|
* MScrollBar is a custom scrollbar implementation.
|
||||||
* It is a vertical scrollbar that can be used to scroll a ListView.
|
* It is a vertical scrollbar that can be used to scroll a ListView.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
|
|
||||||
SplitView {
|
SplitView {
|
||||||
id: splitView
|
id: splitView
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import MaterialIcons 2.2
|
import MaterialIcons 2.2
|
||||||
|
|
||||||
Dialog {
|
Dialog {
|
||||||
|
@ -15,7 +16,7 @@ Dialog {
|
||||||
|
|
||||||
default property alias children: layout.children
|
default property alias children: layout.children
|
||||||
|
|
||||||
// the content of this MessageDialog as a string
|
// The content of this MessageDialog as a string
|
||||||
readonly property string asString: titleLabel.text + "\n\n" + text + "\n" + detailedText + "\n" + helperText + "\n"
|
readonly property string asString: titleLabel.text + "\n\n" + text + "\n" + detailedText + "\n" + helperText + "\n"
|
||||||
|
|
||||||
/// Return the text content of this dialog as a simple string.
|
/// Return the text content of this dialog as a simple string.
|
||||||
|
@ -39,7 +40,7 @@ Dialog {
|
||||||
rightPadding: leftPadding
|
rightPadding: leftPadding
|
||||||
|
|
||||||
background: Item {
|
background: Item {
|
||||||
// hidden text edit to perform copy in clipboard
|
// Hidden text edit to perform copy in clipboard
|
||||||
TextEdit {
|
TextEdit {
|
||||||
id: textContent
|
id: textContent
|
||||||
visible: false
|
visible: false
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Panel is a container control with preconfigured header/footer.
|
* Panel is a container control with preconfigured header/footer.
|
||||||
|
@ -12,6 +11,7 @@ import QtQuick.Layouts 1.11
|
||||||
*
|
*
|
||||||
* The footer is empty (and not visible) by default. It does not provided any layout.
|
* The footer is empty (and not visible) by default. It does not provided any layout.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Page {
|
Page {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import MaterialIcons 2.2
|
|
||||||
|
|
||||||
|
import MaterialIcons 2.2
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basic SearchBar component with an appropriate icon and a TextField.
|
* Basic SearchBar component with an appropriate icon and a TextField.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
FocusScope {
|
FocusScope {
|
||||||
property alias textField: field
|
property alias textField: field
|
||||||
property alias text: field.text
|
property alias text: field.text
|
||||||
|
@ -35,7 +36,7 @@ FocusScope {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
|
|
||||||
// ensure the field has focus when the text is modified
|
// Ensure the field has focus when the text is modified
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
forceActiveFocus()
|
forceActiveFocus()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
|
|
||||||
Page {
|
Page {
|
||||||
id: root
|
id: root
|
||||||
|
@ -47,16 +47,16 @@ Page {
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
property bool commonBorder : false
|
property bool commonBorder: false
|
||||||
|
|
||||||
property int lBorderwidth : index === mainTabBar.currentIndex ? 2 : 1
|
property int lBorderwidth: index === mainTabBar.currentIndex ? 2 : 1
|
||||||
property int rBorderwidth : index === mainTabBar.currentIndex ? 2 : 1
|
property int rBorderwidth: index === mainTabBar.currentIndex ? 2 : 1
|
||||||
property int tBorderwidth : index === mainTabBar.currentIndex ? 2 : 1
|
property int tBorderwidth: index === mainTabBar.currentIndex ? 2 : 1
|
||||||
property int bBorderwidth : 0
|
property int bBorderwidth: 0
|
||||||
|
|
||||||
property int commonBorderWidth : 1
|
property int commonBorderWidth: 1
|
||||||
|
|
||||||
z : -1
|
z: -1
|
||||||
|
|
||||||
color: Qt.darker(root.palette.window, 1.50)
|
color: Qt.darker(root.palette.window, 1.50)
|
||||||
|
|
||||||
|
@ -66,10 +66,10 @@ Page {
|
||||||
top: parent.top
|
top: parent.top
|
||||||
bottom: parent.bottom
|
bottom: parent.bottom
|
||||||
|
|
||||||
topMargin : commonBorder ? -commonBorderWidth : -tBorderwidth
|
topMargin: commonBorder ? -commonBorderWidth : -tBorderwidth
|
||||||
bottomMargin : commonBorder ? -commonBorderWidth : -bBorderwidth
|
bottomMargin: commonBorder ? -commonBorderWidth : -bBorderwidth
|
||||||
leftMargin : commonBorder ? -commonBorderWidth : -lBorderwidth
|
leftMargin: commonBorder ? -commonBorderWidth : -lBorderwidth
|
||||||
rightMargin : commonBorder ? -commonBorderWidth : -rBorderwidth
|
rightMargin: commonBorder ? -commonBorderWidth : -rBorderwidth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import MaterialIcons 2.2
|
|
||||||
|
|
||||||
|
import MaterialIcons 2.2
|
||||||
import Utils 1.0
|
import Utils 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Text file viewer with auto-reload feature.
|
* Text file viewer with auto-reload feature.
|
||||||
* Uses a ListView with one delegate by line instead of a TextArea for performance reasons.
|
* Uses a ListView with one delegate by line instead of a TextArea for performance reasons.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
@ -115,7 +116,7 @@ Item {
|
||||||
clip: true
|
clip: true
|
||||||
focus: true
|
focus: true
|
||||||
|
|
||||||
// custom key navigation handling
|
// Custom key navigation handling
|
||||||
keyNavigationEnabled: false
|
keyNavigationEnabled: false
|
||||||
highlightFollowsCurrentItem: true
|
highlightFollowsCurrentItem: true
|
||||||
highlightMoveDuration: 0
|
highlightMoveDuration: 0
|
||||||
|
@ -145,14 +146,14 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setText(value) {
|
function setText(value) {
|
||||||
// store current first index
|
// Store current first index
|
||||||
var topIndex = firstVisibleIndex()
|
var topIndex = firstVisibleIndex()
|
||||||
// store whether autoscroll to bottom is active
|
// Store whether autoscroll to bottom is active
|
||||||
var scrollToBottom = atYEnd && autoscroll.checked
|
var scrollToBottom = atYEnd && autoscroll.checked
|
||||||
// replace text
|
// Replace text
|
||||||
text = value
|
text = value
|
||||||
|
|
||||||
// restore content position by either:
|
// Restore content position by either:
|
||||||
// - autoscrolling to bottom
|
// - autoscrolling to bottom
|
||||||
if (scrollToBottom)
|
if (scrollToBottom)
|
||||||
positionViewAtEnd()
|
positionViewAtEnd()
|
||||||
|
@ -183,7 +184,7 @@ Item {
|
||||||
// TextMetrics for textual progress bar
|
// TextMetrics for textual progress bar
|
||||||
TextMetrics {
|
TextMetrics {
|
||||||
id: progressMetrics
|
id: progressMetrics
|
||||||
// total number of character in textual progress bar
|
// Total number of character in textual progress bar
|
||||||
property int count: 51
|
property int count: 51
|
||||||
property string character: '*'
|
property string character: '*'
|
||||||
text: character.repeat(count)
|
text: character.repeat(count)
|
||||||
|
@ -230,15 +231,15 @@ Item {
|
||||||
Loader {
|
Loader {
|
||||||
id: delegateLoader
|
id: delegateLoader
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
// default line delegate
|
// Default line delegate
|
||||||
sourceComponent: line_component
|
sourceComponent: line_component
|
||||||
|
|
||||||
// line delegate selector based on content
|
// Line delegate selector based on content
|
||||||
StateGroup {
|
StateGroup {
|
||||||
states: [
|
states: [
|
||||||
State {
|
State {
|
||||||
name: "progressBar"
|
name: "progressBar"
|
||||||
// detect textual progressbar (non empty line with only progressbar character)
|
// Detect textual progressbar (non-empty line with only progressbar character)
|
||||||
when: logLine.line.trim().length
|
when: logLine.line.trim().length
|
||||||
&& logLine.line.split(progressMetrics.character).length - 1 === logLine.line.trim().length
|
&& logLine.line.split(progressMetrics.character).length - 1 === logLine.line.trim().length
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
|
@ -281,7 +282,7 @@ Item {
|
||||||
Keys.forwardTo: [textView]
|
Keys.forwardTo: [textView]
|
||||||
|
|
||||||
color: {
|
color: {
|
||||||
// color line according to log level
|
// Color line according to log level
|
||||||
if (text.indexOf("[warning]") >= 0)
|
if (text.indexOf("[warning]") >= 0)
|
||||||
return Colors.orange
|
return Colors.orange
|
||||||
else if(text.indexOf("[error]") >= 0)
|
else if(text.indexOf("[error]") >= 0)
|
||||||
|
@ -350,7 +351,7 @@ Item {
|
||||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||||
textView.setText(xhr.status === 200 ? xhr.responseText : "")
|
textView.setText(xhr.status === 200 ? xhr.responseText : "")
|
||||||
loading = false
|
loading = false
|
||||||
// re-trigger reload source file
|
// Re-trigger reload source file
|
||||||
if (autoReload)
|
if (autoReload)
|
||||||
reloadTimer.restart()
|
reloadTimer.restart()
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,4 +14,5 @@ ExifOrientedViewer 1.0 ExifOrientedViewer.qml
|
||||||
FilterComboBox 1.0 FilterComboBox.qml
|
FilterComboBox 1.0 FilterComboBox.qml
|
||||||
IntSelector 1.0 IntSelector.qml
|
IntSelector 1.0 IntSelector.qml
|
||||||
MScrollBar 1.0 MScrollBar.qml
|
MScrollBar 1.0 MScrollBar.qml
|
||||||
MSplitView 1.0 MSplitView.qml
|
MSplitView 1.0 MSplitView.qml
|
||||||
|
DirectionalLightPane 1.0 DirectionalLightPane.qml
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import MaterialIcons 2.2
|
|
||||||
import Controls 1.0
|
import Controls 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DialogsFactory is utility object to instantiate generic purpose Dialogs.
|
* DialogsFactory is utility object to instantiate generic purpose Dialogs.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
|
|
||||||
readonly property string defaultErrorText: "An unexpected error has occurred"
|
readonly property string defaultErrorText: "An unexpected error has occurred"
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Controls
|
||||||
import QtQuick.Controls 2.15
|
|
||||||
import MaterialIcons 2.2
|
|
||||||
import Utils 1.0
|
|
||||||
import Controls 1.0
|
import Controls 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,7 +40,9 @@ ListView {
|
||||||
filterText: root.filterText
|
filterText: root.filterText
|
||||||
objectsHideable: root.objectsHideable
|
objectsHideable: root.objectsHideable
|
||||||
attribute: object
|
attribute: object
|
||||||
onDoubleClicked: root.attributeDoubleClicked(mouse, attr)
|
onDoubleClicked: function(mouse, attr) {
|
||||||
|
root.attributeDoubleClicked(mouse, attr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onActiveChanged: height = active ? item.implicitHeight : -spacing
|
onActiveChanged: height = active ? item.implicitHeight : -spacing
|
||||||
|
@ -56,12 +56,10 @@ ListView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper MouseArea to lose edit/activeFocus
|
// Helper MouseArea to lose edit/activeFocus when clicking on the background
|
||||||
// when clicking on the background
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: forceActiveFocus()
|
onClicked: forceActiveFocus()
|
||||||
z: -1
|
z: -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,26 @@
|
||||||
import QtQuick 2.9
|
import QtQuick
|
||||||
import QtQuick.Layouts 1.3
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls 2.2
|
import QtQuick.Controls
|
||||||
import QtQuick.Dialogs 1.3
|
import QtQuick.Dialogs
|
||||||
|
|
||||||
import MaterialIcons 2.2
|
import MaterialIcons 2.2
|
||||||
import Utils 1.0
|
import Utils 1.0
|
||||||
import Controls 1.0
|
import Controls 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Instantiate a control to visualize and edit an Attribute based on its type.
|
* Instantiate a control to visualize and edit an Attribute based on its type.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property variant attribute: null
|
property variant attribute: null
|
||||||
property bool readOnly: false // whether the attribute's value can be modified
|
property bool readOnly: false // Whether the attribute's value can be modified
|
||||||
property bool objectsHideable: true
|
property bool objectsHideable: true
|
||||||
property string filterText: ""
|
property string filterText: ""
|
||||||
|
|
||||||
property alias label: parameterLabel // accessor to the internal Label (attribute's name)
|
property alias label: parameterLabel // Accessor to the internal Label (attribute's name)
|
||||||
property int labelWidth // shortcut to set the fixed size of the Label
|
property int labelWidth // Shortcut to set the fixed size of the Label
|
||||||
|
|
||||||
readonly property bool editable: !attribute.isOutput && !attribute.isLink && !readOnly
|
readonly property bool editable: !attribute.isOutput && !attribute.isLink && !readOnly
|
||||||
|
|
||||||
|
@ -42,7 +44,7 @@ RowLayout {
|
||||||
Pane {
|
Pane {
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
id: background
|
id: background
|
||||||
color: object.validValue ? Qt.darker(parent.palette.window, 1.1) : Qt.darker(Colors.red, 1.5)
|
color: object != undefined && object.validValue ? Qt.darker(parent.palette.window, 1.1) : Qt.darker(Colors.red, 1.5)
|
||||||
}
|
}
|
||||||
padding: 0
|
padding: 0
|
||||||
Layout.preferredWidth: labelWidth || implicitWidth
|
Layout.preferredWidth: labelWidth || implicitWidth
|
||||||
|
@ -66,8 +68,10 @@ RowLayout {
|
||||||
text: object.label
|
text: object.label
|
||||||
|
|
||||||
color: {
|
color: {
|
||||||
if ((object.hasOutputConnections || object.isLink) && !object.enabled) return Colors.lightgrey
|
if (object != undefined && (object.hasOutputConnections || object.isLink) && !object.enabled)
|
||||||
else return palette.text
|
return Colors.lightgrey
|
||||||
|
else
|
||||||
|
return palette.text
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tooltip hint with attribute's description
|
// Tooltip hint with attribute's description
|
||||||
|
@ -88,10 +92,10 @@ RowLayout {
|
||||||
delay: 800
|
delay: 800
|
||||||
}
|
}
|
||||||
|
|
||||||
// make label bold if attribute's value is not the default one
|
// Make label bold if attribute's value is not the default one
|
||||||
font.bold: !object.isOutput && !object.isDefault
|
font.bold: !object.isOutput && !object.isDefault
|
||||||
|
|
||||||
// make label italic if attribute is a link
|
// Make label italic if attribute is a link
|
||||||
font.italic: object.isLink
|
font.italic: object.isLink
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
@ -152,7 +156,7 @@ RowLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: function(mouse) {
|
||||||
forceActiveFocus()
|
forceActiveFocus()
|
||||||
if (mouse.button == Qt.RightButton) {
|
if (mouse.button == Qt.RightButton) {
|
||||||
var menu = menuComp.createObject(parameterLabel)
|
var menu = menuComp.createObject(parameterLabel)
|
||||||
|
@ -198,37 +202,37 @@ RowLayout {
|
||||||
sourceComponent: {
|
sourceComponent: {
|
||||||
// PushButtonParam always has value == undefined, so it needs to be excluded from this check
|
// PushButtonParam always has value == undefined, so it needs to be excluded from this check
|
||||||
if (attribute.type != "PushButtonParam" && attribute.value === undefined) {
|
if (attribute.type != "PushButtonParam" && attribute.value === undefined) {
|
||||||
return notComputed_component
|
return notComputedComponent
|
||||||
}
|
}
|
||||||
switch (attribute.type) {
|
switch (attribute.type) {
|
||||||
case "PushButtonParam":
|
case "PushButtonParam":
|
||||||
return pushButton_component
|
return pushButtonComponent
|
||||||
case "ChoiceParam":
|
case "ChoiceParam":
|
||||||
return attribute.desc.exclusive ? comboBox_component : multiChoice_component
|
return attribute.desc.exclusive ? comboBoxComponent : multiChoiceComponent
|
||||||
case "IntParam": return slider_component
|
case "IntParam": return sliderComponent
|
||||||
case "FloatParam":
|
case "FloatParam":
|
||||||
if (attribute.desc.semantic === 'color/hue')
|
if (attribute.desc.semantic === 'color/hue')
|
||||||
return color_hue_component
|
return colorHueComponent
|
||||||
return slider_component
|
return sliderComponent
|
||||||
case "BoolParam":
|
case "BoolParam":
|
||||||
return checkbox_component
|
return checkboxComponent
|
||||||
case "ListAttribute":
|
case "ListAttribute":
|
||||||
return listAttribute_component
|
return listAttributeComponent
|
||||||
case "GroupAttribute":
|
case "GroupAttribute":
|
||||||
return groupAttribute_component
|
return groupAttributeComponent
|
||||||
case "StringParam":
|
case "StringParam":
|
||||||
if (attribute.desc.semantic.includes('multiline'))
|
if (attribute.desc.semantic.includes('multiline'))
|
||||||
return textArea_component
|
return textAreaComponent
|
||||||
return textField_component
|
return textFieldComponent
|
||||||
case "ColorParam":
|
case "ColorParam":
|
||||||
return color_component
|
return colorComponent
|
||||||
default:
|
default:
|
||||||
return textField_component
|
return textFieldComponent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: notComputed_component
|
id: notComputedComponent
|
||||||
Label {
|
Label {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
text: MaterialIcons.do_not_disturb_alt
|
text: MaterialIcons.do_not_disturb_alt
|
||||||
|
@ -244,7 +248,7 @@ RowLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: pushButton_component
|
id: pushButtonComponent
|
||||||
Button {
|
Button {
|
||||||
text: attribute.label
|
text: attribute.label
|
||||||
enabled: root.editable
|
enabled: root.editable
|
||||||
|
@ -255,7 +259,7 @@ RowLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: textField_component
|
id: textFieldComponent
|
||||||
TextField {
|
TextField {
|
||||||
id: textField
|
id: textField
|
||||||
readOnly: !root.editable
|
readOnly: !root.editable
|
||||||
|
@ -268,7 +272,7 @@ RowLayout {
|
||||||
setTextFieldAttribute(text)
|
setTextFieldAttribute(text)
|
||||||
parameterLabel.forceActiveFocus()
|
parameterLabel.forceActiveFocus()
|
||||||
}
|
}
|
||||||
Keys.onPressed: (event)=> {
|
Keys.onPressed: function(event) {
|
||||||
if ((event.key == Qt.Key_Escape)) {
|
if ((event.key == Qt.Key_Escape)) {
|
||||||
event.accepted = true
|
event.accepted = true
|
||||||
parameterLabel.forceActiveFocus()
|
parameterLabel.forceActiveFocus()
|
||||||
|
@ -281,7 +285,7 @@ RowLayout {
|
||||||
DropArea {
|
DropArea {
|
||||||
enabled: root.editable
|
enabled: root.editable
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onDropped: {
|
onDropped: function(drop) {
|
||||||
if (drop.hasUrls)
|
if (drop.hasUrls)
|
||||||
setTextFieldAttribute(Filepath.urlToString(drop.urls[0]))
|
setTextFieldAttribute(Filepath.urlToString(drop.urls[0]))
|
||||||
else if (drop.hasText && drop.text != '')
|
else if (drop.hasText && drop.text != '')
|
||||||
|
@ -291,8 +295,8 @@ RowLayout {
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.RightButton
|
acceptedButtons: Qt.RightButton
|
||||||
onClicked: (mouse)=> {
|
onClicked: function(mouse) {
|
||||||
// Do not loose the selection during the right click
|
// Do not lose the selection during the right click
|
||||||
textField.persistentSelection = true
|
textField.persistentSelection = true
|
||||||
// We store the status of the activeFocus before opening the popup
|
// We store the status of the activeFocus before opening the popup
|
||||||
textField.memoryActiveFocus = textField.activeFocus
|
textField.memoryActiveFocus = textField.activeFocus
|
||||||
|
@ -318,7 +322,7 @@ RowLayout {
|
||||||
Clipboard.clear()
|
Clipboard.clear()
|
||||||
Clipboard.setText(attribute.value)
|
Clipboard.setText(attribute.value)
|
||||||
} else {
|
} else {
|
||||||
// copy selection only
|
// Copy selection only
|
||||||
textField.copy()
|
textField.copy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -328,12 +332,12 @@ RowLayout {
|
||||||
enabled: Clipboard.getText() != "" && !readOnly
|
enabled: Clipboard.getText() != "" && !readOnly
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (textField.memoryActiveFocus) {
|
if (textField.memoryActiveFocus) {
|
||||||
// replace the selected text with the clipboard
|
// Replace the selected text with the clipboard
|
||||||
// or if there is no selection insert at the cursor position
|
// or if there is no selection insert at the cursor position
|
||||||
var before = textField.text.substr(0, textField.selectionStart)
|
var before = textField.text.substr(0, textField.selectionStart)
|
||||||
var after = textField.text.substr(textField.selectionEnd, textField.text.length)
|
var after = textField.text.substr(textField.selectionEnd, textField.text.length)
|
||||||
setTextFieldAttribute(before + Clipboard.getText() + after)
|
setTextFieldAttribute(before + Clipboard.getText() + after)
|
||||||
// set the cursor at the end of the added text
|
// Set the cursor at the end of the added text
|
||||||
textField.cursorPosition = before.length + Clipboard.getText().length
|
textField.cursorPosition = before.length + Clipboard.getText().length
|
||||||
} else {
|
} else {
|
||||||
setTextFieldAttribute(Clipboard.getText())
|
setTextFieldAttribute(Clipboard.getText())
|
||||||
|
@ -346,7 +350,7 @@ RowLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: textArea_component
|
id: textAreaComponent
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
// Fixed background for the flickable object
|
// Fixed background for the flickable object
|
||||||
|
@ -395,17 +399,20 @@ RowLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: color_component
|
id: colorComponent
|
||||||
RowLayout {
|
RowLayout {
|
||||||
CheckBox {
|
CheckBox {
|
||||||
id: color_checkbox
|
id: colorCheckbox
|
||||||
Layout.alignment: Qt.AlignLeft
|
Layout.alignment: Qt.AlignLeft
|
||||||
checked: node && node.color === "" ? false : true
|
checked: node && node.color === "" ? false : true
|
||||||
checkable: root.editable
|
checkable: root.editable
|
||||||
text: "Custom Color"
|
text: "Custom Color"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
_reconstruction.setAttribute(attribute, "#0000FF")
|
if (colorText.text == "")
|
||||||
|
_reconstruction.setAttribute(attribute, "#0000FF")
|
||||||
|
else
|
||||||
|
_reconstruction.setAttribute(attribute, colorText.text)
|
||||||
} else {
|
} else {
|
||||||
_reconstruction.setAttribute(attribute, "")
|
_reconstruction.setAttribute(attribute, "")
|
||||||
}
|
}
|
||||||
|
@ -415,9 +422,9 @@ RowLayout {
|
||||||
id: colorText
|
id: colorText
|
||||||
Layout.alignment: Qt.AlignLeft
|
Layout.alignment: Qt.AlignLeft
|
||||||
implicitWidth: 100
|
implicitWidth: 100
|
||||||
enabled: color_checkbox.checked && root.editable
|
enabled: colorCheckbox.checked && root.editable
|
||||||
visible: color_checkbox.checked
|
visible: colorCheckbox.checked
|
||||||
text: color_checkbox.checked ? attribute.value : ""
|
text: colorCheckbox.checked ? attribute.value : ""
|
||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
onEditingFinished: setTextFieldAttribute(text)
|
onEditingFinished: setTextFieldAttribute(text)
|
||||||
onAccepted: setTextFieldAttribute(text)
|
onAccepted: setTextFieldAttribute(text)
|
||||||
|
@ -431,8 +438,8 @@ RowLayout {
|
||||||
height: colorText.height
|
height: colorText.height
|
||||||
width: colorText.width / 2
|
width: colorText.width / 2
|
||||||
Layout.alignment: Qt.AlignLeft
|
Layout.alignment: Qt.AlignLeft
|
||||||
visible: color_checkbox.checked
|
visible: colorCheckbox.checked
|
||||||
color: color_checkbox.checked ? attribute.value : ""
|
color: colorCheckbox.checked ? colorDialog.selectedColor : ""
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
enabled: root.editable
|
enabled: root.editable
|
||||||
|
@ -444,9 +451,9 @@ RowLayout {
|
||||||
ColorDialog {
|
ColorDialog {
|
||||||
id: colorDialog
|
id: colorDialog
|
||||||
title: "Please choose a color"
|
title: "Please choose a color"
|
||||||
color: attribute.value
|
selectedColor: colorText.text
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
colorText.text = color
|
colorText.text = colorDialog.selectedColor
|
||||||
// Artificially trigger change of attribute value
|
// Artificially trigger change of attribute value
|
||||||
colorText.editingFinished()
|
colorText.editingFinished()
|
||||||
close()
|
close()
|
||||||
|
@ -461,13 +468,13 @@ RowLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: comboBox_component
|
id: comboBoxComponent
|
||||||
|
|
||||||
FilterComboBox {
|
FilterComboBox {
|
||||||
inputModel: attribute.values
|
inputModel: attribute.values
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
// if value not in list, override the text and precise it is not valid
|
// If value not in list, override the text and precise it is not valid
|
||||||
var idx = find(attribute.value)
|
var idx = find(attribute.value)
|
||||||
if (idx === -1) {
|
if (idx === -1) {
|
||||||
displayText = attribute.value
|
displayText = attribute.value
|
||||||
|
@ -484,10 +491,10 @@ RowLayout {
|
||||||
Connections {
|
Connections {
|
||||||
target: attribute
|
target: attribute
|
||||||
function onValueChanged() {
|
function onValueChanged() {
|
||||||
// when reset, clear and find the current index
|
// When reset, clear and find the current index
|
||||||
// but if only reopen the combo box, keep the current value
|
// but if only reopen the combo box, keep the current value
|
||||||
|
|
||||||
//convert all values of desc values as string
|
// Convert all values of desc values as string
|
||||||
var valuesAsString = attribute.values.map(function(value) {
|
var valuesAsString = attribute.values.map(function(value) {
|
||||||
return value.toString()
|
return value.toString()
|
||||||
})
|
})
|
||||||
|
@ -503,10 +510,10 @@ RowLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: multiChoice_component
|
id: multiChoiceComponent
|
||||||
Flow {
|
Flow {
|
||||||
Repeater {
|
Repeater {
|
||||||
id: checkbox_repeater
|
id: checkboxRepeater
|
||||||
model: attribute.values
|
model: attribute.values
|
||||||
delegate: CheckBox {
|
delegate: CheckBox {
|
||||||
enabled: root.editable
|
enabled: root.editable
|
||||||
|
@ -515,9 +522,9 @@ RowLayout {
|
||||||
onToggled: {
|
onToggled: {
|
||||||
var t = attribute.value
|
var t = attribute.value
|
||||||
if (!checked) {
|
if (!checked) {
|
||||||
t.splice(t.indexOf(modelData), 1) // remove element
|
t.splice(t.indexOf(modelData), 1) // Remove element
|
||||||
} else {
|
} else {
|
||||||
t.push(modelData) // add element
|
t.push(modelData) // Add element
|
||||||
}
|
}
|
||||||
_reconstruction.setAttribute(attribute, t)
|
_reconstruction.setAttribute(attribute, t)
|
||||||
}
|
}
|
||||||
|
@ -527,7 +534,7 @@ RowLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: slider_component
|
id: sliderComponent
|
||||||
RowLayout {
|
RowLayout {
|
||||||
TextField {
|
TextField {
|
||||||
IntValidator {
|
IntValidator {
|
||||||
|
@ -535,12 +542,12 @@ RowLayout {
|
||||||
}
|
}
|
||||||
DoubleValidator {
|
DoubleValidator {
|
||||||
id: doubleValidator
|
id: doubleValidator
|
||||||
locale: 'C' // use '.' decimal separator disregarding the system locale
|
locale: 'C' // Use '.' decimal separator disregarding the system locale
|
||||||
}
|
}
|
||||||
implicitWidth: 100
|
implicitWidth: 100
|
||||||
Layout.fillWidth: !slider.active
|
Layout.fillWidth: !slider.active
|
||||||
enabled: root.editable
|
enabled: root.editable
|
||||||
// cast value to string to avoid intrusive scientific notations on numbers
|
// Cast value to string to avoid intrusive scientific notations on numbers
|
||||||
property string displayValue: String(slider.active && slider.item.pressed ? slider.item.formattedValue : attribute.value)
|
property string displayValue: String(slider.active && slider.item.pressed ? slider.item.formattedValue : attribute.value)
|
||||||
text: displayValue
|
text: displayValue
|
||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
|
@ -594,7 +601,7 @@ RowLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: checkbox_component
|
id: checkboxComponent
|
||||||
Row {
|
Row {
|
||||||
CheckBox {
|
CheckBox {
|
||||||
enabled: root.editable
|
enabled: root.editable
|
||||||
|
@ -605,17 +612,17 @@ RowLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: listAttribute_component
|
id: listAttributeComponent
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: listAttribute_layout
|
id: listAttributeLayout
|
||||||
width: parent.width
|
width: parent.width
|
||||||
property bool expanded: false
|
property bool expanded: false
|
||||||
RowLayout {
|
RowLayout {
|
||||||
spacing: 4
|
spacing: 4
|
||||||
ToolButton {
|
ToolButton {
|
||||||
text: listAttribute_layout.expanded ? MaterialIcons.keyboard_arrow_down : MaterialIcons.keyboard_arrow_right
|
text: listAttributeLayout.expanded ? MaterialIcons.keyboard_arrow_down : MaterialIcons.keyboard_arrow_right
|
||||||
font.family: MaterialIcons.fontFamily
|
font.family: MaterialIcons.fontFamily
|
||||||
onClicked: listAttribute_layout.expanded = !listAttribute_layout.expanded
|
onClicked: listAttributeLayout.expanded = !listAttributeLayout.expanded
|
||||||
}
|
}
|
||||||
Label {
|
Label {
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
@ -632,7 +639,7 @@ RowLayout {
|
||||||
}
|
}
|
||||||
ListView {
|
ListView {
|
||||||
id: lv
|
id: lv
|
||||||
model: listAttribute_layout.expanded ? attribute.value : undefined
|
model: listAttributeLayout.expanded ? attribute.value : undefined
|
||||||
visible: model !== undefined && count > 0
|
visible: model !== undefined && count > 0
|
||||||
implicitHeight: Math.min(contentHeight, 300)
|
implicitHeight: Math.min(contentHeight, 300)
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
@ -683,7 +690,7 @@ RowLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: groupAttribute_component
|
id: groupAttributeComponent
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: groupItem
|
id: groupItem
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
@ -692,7 +699,7 @@ RowLayout {
|
||||||
{
|
{
|
||||||
'model': Qt.binding(function() { return attribute.value }),
|
'model': Qt.binding(function() { return attribute.value }),
|
||||||
'readOnly': Qt.binding(function() { return root.readOnly }),
|
'readOnly': Qt.binding(function() { return root.readOnly }),
|
||||||
'labelWidth': 100, // reduce label width for children (space gain)
|
'labelWidth': 100, // Reduce label width for children (space gain)
|
||||||
'objectsHideable': Qt.binding(function() { return root.objectsHideable }),
|
'objectsHideable': Qt.binding(function() { return root.objectsHideable }),
|
||||||
'filterText': Qt.binding(function() { return root.filterText }),
|
'filterText': Qt.binding(function() { return root.filterText }),
|
||||||
})
|
})
|
||||||
|
@ -703,17 +710,17 @@ RowLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: color_hue_component
|
id: colorHueComponent
|
||||||
RowLayout {
|
RowLayout {
|
||||||
TextField {
|
TextField {
|
||||||
implicitWidth: 100
|
implicitWidth: 100
|
||||||
enabled: root.editable
|
enabled: root.editable
|
||||||
// cast value to string to avoid intrusive scientific notations on numbers
|
// Cast value to string to avoid intrusive scientific notations on numbers
|
||||||
property string displayValue: String(slider.pressed ? slider.formattedValue : attribute.value)
|
property string displayValue: String(slider.pressed ? slider.formattedValue : attribute.value)
|
||||||
text: displayValue
|
text: displayValue
|
||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
validator: DoubleValidator {
|
validator: DoubleValidator {
|
||||||
locale: 'C' // use '.' decimal separator disregarding the system locale
|
locale: 'C' // Use '.' decimal separator disregarding the system locale
|
||||||
}
|
}
|
||||||
onEditingFinished: setTextFieldAttribute(text)
|
onEditingFinished: setTextFieldAttribute(text)
|
||||||
onAccepted: setTextFieldAttribute(text)
|
onAccepted: setTextFieldAttribute(text)
|
||||||
|
@ -748,16 +755,7 @@ RowLayout {
|
||||||
width: control.availableWidth
|
width: control.availableWidth
|
||||||
height: control.availableHeight
|
height: control.availableHeight
|
||||||
blending: false
|
blending: false
|
||||||
fragmentShader: "
|
fragmentShader: "qrc:/shaders/AttributeItemDelegate.frag.qsb"
|
||||||
varying mediump vec2 qt_TexCoord0;
|
|
||||||
vec3 hsv2rgb(vec3 c) {
|
|
||||||
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
|
||||||
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
|
|
||||||
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
|
||||||
}
|
|
||||||
void main() {
|
|
||||||
gl_FragColor = vec4(hsv2rgb(vec3(qt_TexCoord0.x, 1.0, 1.0)), 1.0);
|
|
||||||
}"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import MaterialIcons 2.2
|
|
||||||
import Utils 1.0
|
import Utils 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The representation of an Attribute on a Node.
|
* The representation of an Attribute on a Node.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
@ -43,24 +44,23 @@ RowLayout {
|
||||||
x: nameLabel.x
|
x: nameLabel.x
|
||||||
}
|
}
|
||||||
|
|
||||||
function updatePin(isSrc, isVisible)
|
function updatePin(isSrc, isVisible) {
|
||||||
{
|
|
||||||
if (isSrc) {
|
if (isSrc) {
|
||||||
innerOutputAnchor.linkEnabled = isVisible
|
innerOutputAnchor.linkEnabled = isVisible
|
||||||
} else {
|
} else {
|
||||||
innerInputAnchor.linkEnabled = isVisible
|
innerInputAnchor.linkEnabled = isVisible
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instantiate empty Items for each child attribute
|
// Instantiate empty Items for each child attribute
|
||||||
Repeater {
|
Repeater {
|
||||||
id: childrenRepeater
|
id: childrenRepeater
|
||||||
model: isList && !attribute.isLink ? attribute.value : 0
|
model: isList && !attribute.isLink ? attribute.value : 0
|
||||||
onItemAdded: childPinCreated(item.childAttribute, item)
|
onItemAdded: function(index, item) { childPinCreated(item.childAttribute, root) }
|
||||||
onItemRemoved: childPinDeleted(item.childAttribute, item)
|
onItemRemoved: function(index, item) { childPinDeleted(item.childAttribute, root) }
|
||||||
delegate: Item {
|
delegate: Item {
|
||||||
property var childAttribute: object
|
property var childAttribute: object
|
||||||
|
visible: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,38 +95,39 @@ RowLayout {
|
||||||
|
|
||||||
property bool acceptableDrop: false
|
property bool acceptableDrop: false
|
||||||
|
|
||||||
// add negative margins for DropArea to make the connection zone easier to reach
|
// Add negative margins for DropArea to make the connection zone easier to reach
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: -2
|
anchors.margins: -2
|
||||||
// add horizontal negative margins according to the current layout
|
// Add horizontal negative margins according to the current layout
|
||||||
anchors.rightMargin: -root.width * 0.3
|
anchors.rightMargin: -root.width * 0.3
|
||||||
|
|
||||||
keys: [inputDragTarget.objectName]
|
keys: [inputDragTarget.objectName]
|
||||||
onEntered: {
|
onEntered: function(drag) {
|
||||||
// Check if attributes are compatible to create a valid connection
|
// Check if attributes are compatible to create a valid connection
|
||||||
if (root.readOnly // cannot connect on a read-only attribute
|
if (root.readOnly // Cannot connect on a read-only attribute
|
||||||
|| drag.source.objectName != inputDragTarget.objectName // not an edge connector
|
|| drag.source.objectName != inputDragTarget.objectName // Not an edge connector
|
||||||
|| drag.source.baseType !== inputDragTarget.baseType // not the same base type
|
|| drag.source.baseType !== inputDragTarget.baseType // Not the same base type
|
||||||
|| drag.source.nodeItem === inputDragTarget.nodeItem // connection between attributes of the same node
|
|| drag.source.nodeItem === inputDragTarget.nodeItem // Connection between attributes of the same node
|
||||||
|| (drag.source.isList && childrenRepeater.count) // source/target are lists but target already has children
|
|| (drag.source.isList && childrenRepeater.count) // Source/target are lists but target already has children
|
||||||
|| drag.source.connectorType === "input" // refuse to connect an "input pin" on another one (input attr can be connected to input attr, but not the graphical pin)
|
|| drag.source.connectorType === "input" // Refuse to connect an "input pin" on another one (input attr can be connected to input attr, but not the graphical pin)
|
||||||
) {
|
) {
|
||||||
// Refuse attributes connection
|
// Refuse attributes connection
|
||||||
drag.accepted = false
|
drag.accepted = false
|
||||||
} else if (inputDragTarget.attribute.isLink) { // already connected attribute
|
} else if (inputDragTarget.attribute.isLink) { // Already connected attribute
|
||||||
root.edgeAboutToBeRemoved(inputDragTarget.attribute)
|
root.edgeAboutToBeRemoved(inputDragTarget.attribute)
|
||||||
}
|
}
|
||||||
inputDropArea.acceptableDrop = drag.accepted
|
inputDropArea.acceptableDrop = drag.accepted
|
||||||
}
|
}
|
||||||
|
|
||||||
onExited: {
|
onExited: {
|
||||||
if (inputDragTarget.attribute.isLink) { // already connected attribute
|
if (inputDragTarget.attribute.isLink) { // Already connected attribute
|
||||||
root.edgeAboutToBeRemoved(undefined)
|
root.edgeAboutToBeRemoved(undefined)
|
||||||
}
|
}
|
||||||
acceptableDrop = false
|
acceptableDrop = false
|
||||||
drag.source.dropAccepted = false
|
drag.source.dropAccepted = false
|
||||||
}
|
}
|
||||||
|
|
||||||
onDropped: {
|
onDropped: function(drop) {
|
||||||
root.edgeAboutToBeRemoved(undefined)
|
root.edgeAboutToBeRemoved(undefined)
|
||||||
_reconstruction.addEdge(drag.source.attribute, inputDragTarget.attribute)
|
_reconstruction.addEdge(drag.source.attribute, inputDragTarget.attribute)
|
||||||
}
|
}
|
||||||
|
@ -160,11 +161,11 @@ RowLayout {
|
||||||
drag.smoothed: false
|
drag.smoothed: false
|
||||||
enabled: !root.readOnly
|
enabled: !root.readOnly
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
// use the same negative margins as DropArea to ease pin selection
|
// Use the same negative margins as DropArea to ease pin selection
|
||||||
anchors.margins: inputDropArea.anchors.margins
|
anchors.margins: inputDropArea.anchors.margins
|
||||||
anchors.leftMargin: inputDropArea.anchors.leftMargin
|
anchors.leftMargin: inputDropArea.anchors.leftMargin
|
||||||
anchors.rightMargin: inputDropArea.anchors.rightMargin
|
anchors.rightMargin: inputDropArea.anchors.rightMargin
|
||||||
onPressed: {
|
onPressed: function(mouse) {
|
||||||
root.pressed(mouse)
|
root.pressed(mouse)
|
||||||
}
|
}
|
||||||
onReleased: {
|
onReleased: {
|
||||||
|
@ -185,14 +186,11 @@ RowLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Attribute name
|
// Attribute name
|
||||||
Item {
|
Item {
|
||||||
id: nameContainer
|
id: nameContainer
|
||||||
Layout.fillWidth: true
|
|
||||||
implicitHeight: childrenRect.height
|
implicitHeight: childrenRect.height
|
||||||
|
Layout.fillWidth: true
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
|
@ -208,13 +206,13 @@ RowLayout {
|
||||||
anchors.right: attribute && attribute.isOutput ? parent.right : undefined
|
anchors.right: attribute && attribute.isOutput ? parent.right : undefined
|
||||||
rightPadding: 0
|
rightPadding: 0
|
||||||
color: {
|
color: {
|
||||||
if ((object.hasOutputConnections || object.isLink) && !object.enabled) return Colors.lightgrey
|
if ((object.hasOutputConnections || object.isLink) && !object.enabled)
|
||||||
|
return Colors.lightgrey
|
||||||
return hovered ? palette.highlight : palette.text
|
return hovered ? palette.highlight : palette.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: outputAnchor
|
id: outputAnchor
|
||||||
|
|
||||||
|
@ -248,25 +246,25 @@ RowLayout {
|
||||||
|
|
||||||
property bool acceptableDrop: false
|
property bool acceptableDrop: false
|
||||||
|
|
||||||
// add negative margins for DropArea to make the connection zone easier to reach
|
// Add negative margins for DropArea to make the connection zone easier to reach
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: -2
|
anchors.margins: -2
|
||||||
// add horizontal negative margins according to the current layout
|
// Add horizontal negative margins according to the current layout
|
||||||
anchors.leftMargin: -root.width * 0.2
|
anchors.leftMargin: -root.width * 0.2
|
||||||
|
|
||||||
keys: [outputDragTarget.objectName]
|
keys: [outputDragTarget.objectName]
|
||||||
onEntered: {
|
onEntered: function(drag) {
|
||||||
// Check if attributes are compatible to create a valid connection
|
// Check if attributes are compatible to create a valid connection
|
||||||
if (drag.source.objectName != outputDragTarget.objectName // not an edge connector
|
if (drag.source.objectName != outputDragTarget.objectName // Not an edge connector
|
||||||
|| drag.source.baseType !== outputDragTarget.baseType // not the same base type
|
|| drag.source.baseType !== outputDragTarget.baseType // Not the same base type
|
||||||
|| drag.source.nodeItem === outputDragTarget.nodeItem // connection between attributes of the same node
|
|| drag.source.nodeItem === outputDragTarget.nodeItem // Connection between attributes of the same node
|
||||||
|| (!drag.source.isList && outputDragTarget.isList) // connection between a list and a simple attribute
|
|| (!drag.source.isList && outputDragTarget.isList) // Connection between a list and a simple attribute
|
||||||
|| (drag.source.isList && childrenRepeater.count) // source/target are lists but target already has children
|
|| (drag.source.isList && childrenRepeater.count) // Source/target are lists but target already has children
|
||||||
|| drag.source.connectorType === "output" // refuse to connect an output pin on another one
|
|| drag.source.connectorType === "output" // Refuse to connect an output pin on another one
|
||||||
) {
|
) {
|
||||||
// Refuse attributes connection
|
// Refuse attributes connection
|
||||||
drag.accepted = false
|
drag.accepted = false
|
||||||
} else if (drag.source.attribute.isLink) { // already connected attribute
|
} else if (drag.source.attribute.isLink) { // Already connected attribute
|
||||||
root.edgeAboutToBeRemoved(drag.source.attribute)
|
root.edgeAboutToBeRemoved(drag.source.attribute)
|
||||||
}
|
}
|
||||||
outputDropArea.acceptableDrop = drag.accepted
|
outputDropArea.acceptableDrop = drag.accepted
|
||||||
|
@ -276,7 +274,7 @@ RowLayout {
|
||||||
acceptableDrop = false
|
acceptableDrop = false
|
||||||
}
|
}
|
||||||
|
|
||||||
onDropped: {
|
onDropped: function(drop) {
|
||||||
root.edgeAboutToBeRemoved(undefined)
|
root.edgeAboutToBeRemoved(undefined)
|
||||||
_reconstruction.addEdge(outputDragTarget.attribute, drag.source.attribute)
|
_reconstruction.addEdge(outputDragTarget.attribute, drag.source.attribute)
|
||||||
}
|
}
|
||||||
|
@ -309,12 +307,12 @@ RowLayout {
|
||||||
// Move the edge's tip straight to the the current mouse position instead of waiting after the drag operation has started
|
// Move the edge's tip straight to the the current mouse position instead of waiting after the drag operation has started
|
||||||
drag.smoothed: false
|
drag.smoothed: false
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
// use the same negative margins as DropArea to ease pin selection
|
// Use the same negative margins as DropArea to ease pin selection
|
||||||
anchors.margins: outputDropArea.anchors.margins
|
anchors.margins: outputDropArea.anchors.margins
|
||||||
anchors.leftMargin: outputDropArea.anchors.leftMargin
|
anchors.leftMargin: outputDropArea.anchors.leftMargin
|
||||||
anchors.rightMargin: outputDropArea.anchors.rightMargin
|
anchors.rightMargin: outputDropArea.anchors.rightMargin
|
||||||
|
|
||||||
onPressed: root.pressed(mouse)
|
onPressed: function(mouse) { root.pressed(mouse) }
|
||||||
onReleased: outputDragTarget.Drag.drop()
|
onReleased: outputDragTarget.Drag.drop()
|
||||||
|
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import MaterialIcons 2.2
|
|
||||||
import Controls 1.0
|
|
||||||
|
|
||||||
import "common.js" as Common
|
import "common.js" as Common
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ChunkListView
|
* ChunkListView
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: root
|
id: root
|
||||||
property variant chunks
|
property variant chunks
|
||||||
|
@ -78,7 +77,7 @@ ColumnLayout {
|
||||||
id: chunkDelegate
|
id: chunkDelegate
|
||||||
property var chunk: object
|
property var chunk: object
|
||||||
text: index
|
text: index
|
||||||
width: parent ? parent.width : 0
|
width: ListView.view.width
|
||||||
leftPadding: 8
|
leftPadding: 8
|
||||||
onClicked: {
|
onClicked: {
|
||||||
chunksLV.forceActiveFocus()
|
chunksLV.forceActiveFocus()
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import MaterialIcons 2.2
|
import MaterialIcons 2.2
|
||||||
|
|
||||||
|
/**
|
||||||
/** Node Badge to inform about compatibility issues
|
* Node Badge to inform about compatibility issues
|
||||||
* Provides 2 delegates (can be set using sourceComponent property):
|
* Provides 2 delegates (can be set using sourceComponent property):
|
||||||
* - iconDelegate (default): icon + tooltip with information about the issue
|
* - iconDelegate (default): icon + tooltip with information about the issue
|
||||||
* - bannerDelegate: banner with issue info + upgrade request button
|
* - bannerDelegate: banner with issue info + upgrade request button
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,25 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import MaterialIcons 2.2
|
import MaterialIcons 2.2
|
||||||
import Controls 1.0
|
import Controls 1.0
|
||||||
import Utils 1.0
|
import Utils 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CompatibilityManager summarizes and allows to resolve compatibility issues.
|
* CompatibilityManager summarizes and allows to resolve compatibility issues.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
MessageDialog {
|
MessageDialog {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
// the UIGraph instance
|
// The UIGraph instance
|
||||||
property var uigraph
|
property var uigraph
|
||||||
// alias to underlying compatibilityNodes model
|
// Alias to underlying compatibilityNodes model
|
||||||
readonly property var nodesModel: uigraph ? uigraph.graph.compatibilityNodes : undefined
|
readonly property var nodesModel: uigraph ? uigraph.graph.compatibilityNodes : undefined
|
||||||
// the total number of compatibility issues
|
// The total number of compatibility issues
|
||||||
readonly property int issueCount: (nodesModel !== undefined && nodesModel !== null) ? nodesModel.count : 0
|
readonly property int issueCount: (nodesModel !== undefined && nodesModel !== null) ? nodesModel.count : 0
|
||||||
// the number of CompatibilityNodes that can be upgraded
|
// The number of CompatibilityNodes that can be upgraded
|
||||||
readonly property int upgradableCount: {
|
readonly property int upgradableCount: {
|
||||||
var count = 0
|
var count = 0
|
||||||
for (var i = 0; i < issueCount; ++i) {
|
for (var i = 0; i < issueCount; ++i) {
|
||||||
|
@ -27,7 +29,7 @@ MessageDialog {
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
// override MessageDialog.getAsString to add compatibility report
|
// Override MessageDialog.getAsString to add compatibility report
|
||||||
function getAsString() {
|
function getAsString() {
|
||||||
var t = asString + "\n"
|
var t = asString + "\n"
|
||||||
t += '-------------------------\n'
|
t += '-------------------------\n'
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Shapes 1.6
|
||||||
|
|
||||||
import GraphEditor 1.0
|
import GraphEditor 1.0
|
||||||
import QtQuick.Shapes 1.15
|
|
||||||
import MaterialIcons 2.2
|
import MaterialIcons 2.2
|
||||||
import QtQuick.Controls 2.15
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A cubic spline representing an edge, going from point1 to point2, providing mouse interaction.
|
* A cubic spline representing an edge, going from point1 to point2, providing mouse interaction.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
@ -40,7 +42,7 @@ Item {
|
||||||
|
|
||||||
Shape {
|
Shape {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
// cause rendering artifacts when enabled (and don't support hot reload really well)
|
// Cause rendering artifacts when enabled (and don't support hot reload really well)
|
||||||
vendorExtensionsEnabled: false
|
vendorExtensionsEnabled: false
|
||||||
opacity: 0.7
|
opacity: 0.7
|
||||||
|
|
||||||
|
@ -53,7 +55,7 @@ Item {
|
||||||
strokeColor: "#3E3E3E"
|
strokeColor: "#3E3E3E"
|
||||||
strokeStyle: edge !== undefined && ((edge.src !== undefined && edge.src.isOutput) || edge.dst === undefined) ? ShapePath.SolidLine : ShapePath.DashLine
|
strokeStyle: edge !== undefined && ((edge.src !== undefined && edge.src.isOutput) || edge.dst === undefined) ? ShapePath.SolidLine : ShapePath.DashLine
|
||||||
strokeWidth: 1
|
strokeWidth: 1
|
||||||
// final visual width of this path (never below 1)
|
// Final visual width of this path (never below 1)
|
||||||
readonly property real visualWidth: Math.max(strokeWidth, 1)
|
readonly property real visualWidth: Math.max(strokeWidth, 1)
|
||||||
dashPattern: [6 / visualWidth, 4 / visualWidth]
|
dashPattern: [6 / visualWidth, 4 / visualWidth]
|
||||||
capStyle: ShapePath.RoundCap
|
capStyle: ShapePath.RoundCap
|
||||||
|
@ -68,7 +70,6 @@ Item {
|
||||||
control2X: x - ctrlPtDist
|
control2X: x - ctrlPtDist
|
||||||
control2Y: y
|
control2Y: y
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ShapePath {
|
ShapePath {
|
||||||
|
@ -80,7 +81,7 @@ Item {
|
||||||
strokeColor: root.isForLoop ? root.color : "transparent"
|
strokeColor: root.isForLoop ? root.color : "transparent"
|
||||||
strokeStyle: edge !== undefined && ((edge.src !== undefined && edge.src.isOutput) || edge.dst === undefined) ? ShapePath.SolidLine : ShapePath.DashLine
|
strokeStyle: edge !== undefined && ((edge.src !== undefined && edge.src.isOutput) || edge.dst === undefined) ? ShapePath.SolidLine : ShapePath.DashLine
|
||||||
strokeWidth: root.thickness
|
strokeWidth: root.thickness
|
||||||
// final visual width of this path (never below 1)
|
// Final visual width of this path (never below 1)
|
||||||
readonly property real visualWidth: Math.max(strokeWidth, 1)
|
readonly property real visualWidth: Math.max(strokeWidth, 1)
|
||||||
dashPattern: [6 / visualWidth, 4 / visualWidth]
|
dashPattern: [6 / visualWidth, 4 / visualWidth]
|
||||||
capStyle: ShapePath.RoundCap
|
capStyle: ShapePath.RoundCap
|
||||||
|
@ -97,11 +98,13 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
// place the label at the middle of the edge
|
// Place the label at the middle of the edge
|
||||||
x: (root.startX + root.endX) / 2
|
x: (root.startX + root.endX) / 2
|
||||||
y: (root.startY + root.endY) / 2
|
y: (root.startY + root.endY) / 2
|
||||||
visible: root.isForLoop
|
visible: root.isForLoop
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
property int margin: 2
|
property int margin: 2
|
||||||
|
@ -109,6 +112,7 @@ Item {
|
||||||
height: icon.height + 2 * margin
|
height: icon.height + 2 * margin
|
||||||
radius: width
|
radius: width
|
||||||
color: path.strokeColor
|
color: path.strokeColor
|
||||||
|
|
||||||
MaterialToolLabel {
|
MaterialToolLabel {
|
||||||
id: icon
|
id: icon
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
@ -119,6 +123,7 @@ Item {
|
||||||
color: palette.base
|
color: palette.base
|
||||||
ToolTip.text: "Foreach Loop"
|
ToolTip.text: "Foreach Loop"
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: loopArea
|
id: loopArea
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
@ -126,16 +131,25 @@ Item {
|
||||||
onClicked: root.pressed(arguments[0])
|
onClicked: root.pressed(arguments[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EdgeMouseArea {
|
EdgeMouseArea {
|
||||||
id: edgeArea
|
id: edgeArea
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
curveScale: cubic.ctrlPtDist / root.width // normalize by width
|
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
thickness: root.thickness + 4
|
thickness: root.thickness + 4
|
||||||
onPressed: root.pressed(arguments[0]) // can't get named args, use arguments array
|
onPressed: function(event) {
|
||||||
onReleased: root.released(arguments[0])
|
root.pressed(event)
|
||||||
|
}
|
||||||
|
onReleased: function(event) {
|
||||||
|
root.released(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
/* The curve scale must be set only once the component has been fully created, so
|
||||||
|
* that all the events following the update of the curve scale can be taken into
|
||||||
|
* account */
|
||||||
|
curveScale = cubic.ctrlPtDist / root.width // Normalize by width
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import Controls 1.0
|
import Controls 1.0
|
||||||
import Utils 1.0
|
|
||||||
import MaterialIcons 2.2
|
import MaterialIcons 2.2
|
||||||
|
import Utils 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A component displaying a Graph (nodes, attributes and edges).
|
* A component displaying a Graph (nodes, attributes and edges).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property variant uigraph: null /// Meshroom ui graph (UIGraph)
|
property variant uigraph: null /// Meshroom UI graph (UIGraph)
|
||||||
readonly property variant graph: uigraph ? uigraph.graph : null /// core graph contained in ui graph
|
readonly property variant graph: uigraph ? uigraph.graph : null /// Core graph contained in the UI graph
|
||||||
property variant nodeTypesModel: null /// the list of node types that can be instantiated
|
property variant nodeTypesModel: null /// The list of node types that can be instantiated
|
||||||
property real maxZoom: 2.0
|
property real maxZoom: 2.0
|
||||||
property real minZoom: 0.1
|
property real minZoom: 0.1
|
||||||
|
|
||||||
|
@ -21,7 +23,7 @@ Item {
|
||||||
|
|
||||||
property var _attributeToDelegate: ({})
|
property var _attributeToDelegate: ({})
|
||||||
|
|
||||||
// signals
|
// Signals
|
||||||
signal workspaceMoved()
|
signal workspaceMoved()
|
||||||
signal workspaceClicked()
|
signal workspaceClicked()
|
||||||
|
|
||||||
|
@ -33,10 +35,9 @@ Item {
|
||||||
|
|
||||||
property int nbMeshroomScenes: 0
|
property int nbMeshroomScenes: 0
|
||||||
property int nbDraggedFiles: 0
|
property int nbDraggedFiles: 0
|
||||||
// Files have been dropped
|
signal filesDropped(var drop, var mousePosition) // 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()
|
||||||
|
|
||||||
|
@ -132,7 +133,7 @@ Item {
|
||||||
return mapToItem(draggable, mouseArea.width / 2, mouseArea.height / 2)
|
return mapToItem(draggable, mouseArea.width / 2, mouseArea.height / 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onPressed: {
|
Keys.onPressed: function(event) {
|
||||||
if (event.key === Qt.Key_F) {
|
if (event.key === Qt.Key_F) {
|
||||||
fit()
|
fit()
|
||||||
} else if (event.key === Qt.Key_Delete) {
|
} else if (event.key === Qt.Key_Delete) {
|
||||||
|
@ -172,7 +173,7 @@ Item {
|
||||||
drag.threshold: 0
|
drag.threshold: 0
|
||||||
cursorShape: drag.target == draggable ? Qt.ClosedHandCursor : Qt.ArrowCursor
|
cursorShape: drag.target == draggable ? Qt.ClosedHandCursor : Qt.ArrowCursor
|
||||||
|
|
||||||
onWheel: {
|
onWheel: function(wheel) {
|
||||||
var zoomFactor = wheel.angleDelta.y > 0 ? factor : 1 / factor
|
var zoomFactor = wheel.angleDelta.y > 0 ? factor : 1 / factor
|
||||||
var scale = draggable.scale * zoomFactor
|
var scale = draggable.scale * zoomFactor
|
||||||
scale = Math.min(Math.max(minZoom, scale), maxZoom)
|
scale = Math.min(Math.max(minZoom, scale), maxZoom)
|
||||||
|
@ -185,7 +186,7 @@ Item {
|
||||||
workspaceMoved()
|
workspaceMoved()
|
||||||
}
|
}
|
||||||
|
|
||||||
onPressed: {
|
onPressed: function(mouse) {
|
||||||
if (mouse.button != Qt.MiddleButton && mouse.modifiers == Qt.NoModifier) {
|
if (mouse.button != Qt.MiddleButton && mouse.modifiers == Qt.NoModifier) {
|
||||||
uigraph.clearNodeSelection()
|
uigraph.clearNodeSelection()
|
||||||
}
|
}
|
||||||
|
@ -200,19 +201,21 @@ Item {
|
||||||
drag.target = draggable // start drag
|
drag.target = draggable // start drag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onReleased: {
|
onReleased: {
|
||||||
drag.target = undefined // stop drag
|
drag.target = undefined // stop drag
|
||||||
root.forceActiveFocus()
|
root.forceActiveFocus()
|
||||||
workspaceClicked()
|
workspaceClicked()
|
||||||
}
|
}
|
||||||
|
|
||||||
onPositionChanged: {
|
onPositionChanged: {
|
||||||
if (drag.active)
|
if (drag.active)
|
||||||
workspaceMoved()
|
workspaceMoved()
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: function(mouse) {
|
||||||
if (mouse.button == Qt.RightButton) {
|
if (mouse.button == Qt.RightButton) {
|
||||||
// store mouse click position in 'draggable' coordinates as new node spawn position
|
// Store mouse click position in 'draggable' coordinates as new node spawn position
|
||||||
newNodeMenu.spawnPosition = mouseArea.mapToItem(draggable, mouse.x, mouse.y)
|
newNodeMenu.spawnPosition = mouseArea.mapToItem(draggable, mouse.x, mouse.y)
|
||||||
newNodeMenu.popup()
|
newNodeMenu.popup()
|
||||||
}
|
}
|
||||||
|
@ -271,7 +274,7 @@ Item {
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
searchBar.clear()
|
searchBar.clear()
|
||||||
if (visible) {
|
if (visible) {
|
||||||
// when menu is shown, give focus to the TextField filter
|
// When menu is shown, give focus to the TextField filter
|
||||||
searchBar.forceActiveFocus()
|
searchBar.forceActiveFocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -295,12 +298,12 @@ Item {
|
||||||
// Forward key events to the search bar to continue typing seamlessly
|
// Forward key events to the search bar to continue typing seamlessly
|
||||||
// even if this delegate took the activeFocus due to mouse hovering
|
// even if this delegate took the activeFocus due to mouse hovering
|
||||||
Keys.forwardTo: [searchBar.textField]
|
Keys.forwardTo: [searchBar.textField]
|
||||||
Keys.onPressed: {
|
Keys.onPressed: function(event) {
|
||||||
event.accepted = false;
|
event.accepted = false;
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case Qt.Key_Return:
|
case Qt.Key_Return:
|
||||||
case Qt.Key_Enter:
|
case Qt.Key_Enter:
|
||||||
// create node on validation (Enter/Return keys)
|
// Create node on validation (Enter/Return keys)
|
||||||
newNodeMenu.createNode(modelData)
|
newNodeMenu.createNode(modelData)
|
||||||
event.accepted = true
|
event.accepted = true
|
||||||
break
|
break
|
||||||
|
@ -308,7 +311,7 @@ Item {
|
||||||
case Qt.Key_Down:
|
case Qt.Key_Down:
|
||||||
case Qt.Key_Left:
|
case Qt.Key_Left:
|
||||||
case Qt.Key_Right:
|
case Qt.Key_Right:
|
||||||
break // ignore if arrow key was pressed to let the menu be controlled
|
break // Ignore if arrow key was pressed to let the menu be controlled
|
||||||
default:
|
default:
|
||||||
searchBar.forceActiveFocus()
|
searchBar.forceActiveFocus()
|
||||||
}
|
}
|
||||||
|
@ -323,8 +326,8 @@ Item {
|
||||||
name: "invisible"
|
name: "invisible"
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: menuItemDelegate
|
target: menuItemDelegate
|
||||||
height: 0 // make sure the item is no visible by setting height to 0
|
height: 0 // Make sure the item is no visible by setting height to 0
|
||||||
focusPolicy: Qt.NoFocus // don't grab focus when not visible
|
focusPolicy: Qt.NoFocus // Don't grab focus when not visible
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -335,7 +338,7 @@ Item {
|
||||||
id: nodeMenuRepeater
|
id: nodeMenuRepeater
|
||||||
model: searchBar.text !== "" ? Object.values(newNodeMenu.menuKeys) : undefined
|
model: searchBar.text !== "" ? Object.values(newNodeMenu.menuKeys) : undefined
|
||||||
|
|
||||||
// create Menu items from available items
|
// Create Menu items from available items
|
||||||
delegate: menuItemDelegateComponent
|
delegate: menuItemDelegateComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,8 +346,13 @@ Item {
|
||||||
Instantiator {
|
Instantiator {
|
||||||
id: instantiator
|
id: instantiator
|
||||||
model: (searchBar.text === "") ? Object.keys(newNodeMenu.parseCategories()).sort() : undefined
|
model: (searchBar.text === "") ? Object.keys(newNodeMenu.parseCategories()).sort() : undefined
|
||||||
onObjectAdded: newNodeMenu.insertMenu(index + 1, object ) // add sub-menu under the search bar
|
onObjectAdded: function(index, object) {
|
||||||
onObjectRemoved: newNodeMenu.removeMenu(object)
|
// Add sub-menu under the search bar
|
||||||
|
newNodeMenu.insertMenu(index + 1, object)
|
||||||
|
}
|
||||||
|
onObjectRemoved: function(index, object) {
|
||||||
|
newNodeMenu.removeMenu(object)
|
||||||
|
}
|
||||||
|
|
||||||
delegate: Menu {
|
delegate: Menu {
|
||||||
title: modelData
|
title: modelData
|
||||||
|
@ -352,8 +360,12 @@ Item {
|
||||||
|
|
||||||
Instantiator {
|
Instantiator {
|
||||||
model: newNodeMenu.visible ? newNodeMenu.parseCategories()[modelData] : undefined
|
model: newNodeMenu.visible ? newNodeMenu.parseCategories()[modelData] : undefined
|
||||||
onObjectAdded: newNodeSubMenu.insertItem(index, object)
|
onObjectAdded: function(index, object) {
|
||||||
onObjectRemoved: newNodeSubMenu.removeItem(object)
|
newNodeSubMenu.insertItem(index, object)
|
||||||
|
}
|
||||||
|
onObjectRemoved: function(index, object) {
|
||||||
|
newNodeSubMenu.removeItem(object)
|
||||||
|
}
|
||||||
delegate: menuItemDelegateComponent
|
delegate: menuItemDelegateComponent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -417,7 +429,7 @@ Item {
|
||||||
const newSrcAttr = listAttr.value.at(value - 1)
|
const newSrcAttr = listAttr.value.at(value - 1)
|
||||||
const dst = edgeMenu.currentEdge.dst
|
const dst = edgeMenu.currentEdge.dst
|
||||||
|
|
||||||
// if the edge exists do not replace it
|
// If the edge exists, do not replace it
|
||||||
if (newSrcAttr === edgeMenu.currentEdge.src && dst === edgeMenu.currentEdge.dst) {
|
if (newSrcAttr === edgeMenu.currentEdge.src && dst === edgeMenu.currentEdge.dst) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -476,7 +488,7 @@ Item {
|
||||||
Repeater {
|
Repeater {
|
||||||
id: edgesRepeater
|
id: edgesRepeater
|
||||||
|
|
||||||
// delay edges loading after nodes (edges needs attribute pins to be created)
|
// Delay edges loading after nodes (edges needs attribute pins to be created)
|
||||||
model: nodeRepeater.loaded && root.graph ? root.graph.edges : undefined
|
model: nodeRepeater.loaded && root.graph ? root.graph.edges : undefined
|
||||||
|
|
||||||
delegate: Edge {
|
delegate: Edge {
|
||||||
|
@ -500,12 +512,11 @@ Item {
|
||||||
}
|
}
|
||||||
return (inFocus) ? 2 : 1
|
return (inFocus) ? 2 : 1
|
||||||
}
|
}
|
||||||
|
|
||||||
point1x: isValidEdge ? src.globalX + src.outputAnchorPos.x : 0
|
point1x: isValidEdge ? src.globalX + src.outputAnchorPos.x : 0
|
||||||
point1y: isValidEdge ? src.globalY + src.outputAnchorPos.y : 0
|
point1y: isValidEdge ? src.globalY + src.outputAnchorPos.y : 0
|
||||||
point2x: isValidEdge ? dst.globalX + dst.inputAnchorPos.x : 0
|
point2x: isValidEdge ? dst.globalX + dst.inputAnchorPos.x : 0
|
||||||
point2y: isValidEdge ? dst.globalY + dst.inputAnchorPos.y : 0
|
point2y: isValidEdge ? dst.globalY + dst.inputAnchorPos.y : 0
|
||||||
onPressed: {
|
onPressed: function(event) {
|
||||||
const canEdit = !edge.dst.node.locked
|
const canEdit = !edge.dst.node.locked
|
||||||
|
|
||||||
if (event.button) {
|
if (event.button) {
|
||||||
|
@ -540,7 +551,7 @@ Item {
|
||||||
id: nodeMenu
|
id: nodeMenu
|
||||||
property var currentNode: null
|
property var currentNode: null
|
||||||
property bool canComputeNode: currentNode != null && uigraph.graph.canComputeTopologically(currentNode)
|
property bool canComputeNode: currentNode != null && uigraph.graph.canComputeTopologically(currentNode)
|
||||||
//canSubmitOrCompute: return int n : 0 >= n <= 3 | n=0 cannot submit or compute | n=1 can compute | n=2 can submit | n=3 can compute & submit
|
// canSubmitOrCompute: return int n : 0 >= n <= 3 | n=0 cannot submit or compute | n=1 can compute | n=2 can submit | n=3 can compute & submit
|
||||||
property int canSubmitOrCompute: currentNode != null && uigraph.graph.canSubmitOrCompute(currentNode)
|
property int canSubmitOrCompute: currentNode != null && uigraph.graph.canSubmitOrCompute(currentNode)
|
||||||
property bool isComputed: {
|
property bool isComputed: {
|
||||||
var count = 0
|
var count = 0
|
||||||
|
@ -589,7 +600,7 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return canCompute //canSubmit if canSubmitOrCompute == 1(can compute) or 3(can compute & submit)
|
return canCompute // canSubmit if canSubmitOrCompute == 1(can compute) or 3(can compute & submit)
|
||||||
}
|
}
|
||||||
|
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
|
@ -823,14 +834,14 @@ Item {
|
||||||
selected: uigraph.selectedNodes.contains(node)
|
selected: uigraph.selectedNodes.contains(node)
|
||||||
hovered: uigraph.hoveredNode === node
|
hovered: uigraph.hoveredNode === node
|
||||||
|
|
||||||
onAttributePinCreated: registerAttributePin(attribute, pin)
|
onAttributePinCreated: function(attribute, pin) { registerAttributePin(attribute, pin) }
|
||||||
onAttributePinDeleted: unregisterAttributePin(attribute, pin)
|
onAttributePinDeleted: function(attribute, pin) { unregisterAttributePin(attribute, pin) }
|
||||||
|
|
||||||
onPressed: {
|
onPressed: function(mouse) {
|
||||||
if (mouse.button === Qt.LeftButton) {
|
if (mouse.button === Qt.LeftButton) {
|
||||||
if (mouse.modifiers & Qt.ControlModifier && !(mouse.modifiers & Qt.AltModifier)) {
|
if (mouse.modifiers & Qt.ControlModifier && !(mouse.modifiers & Qt.AltModifier)) {
|
||||||
if (mainSelected && selected) {
|
if (mainSelected && selected) {
|
||||||
// left clicking a selected node twice with control will deselect it
|
// Left clicking a selected node twice with control will deselect it
|
||||||
uigraph.selectedNodes.remove(node)
|
uigraph.selectedNodes.remove(node)
|
||||||
uigraph.selectedNodesChanged()
|
uigraph.selectedNodesChanged()
|
||||||
selectNode(null)
|
selectNode(null)
|
||||||
|
@ -854,21 +865,19 @@ Item {
|
||||||
selectNode(node)
|
selectNode(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
onDoubleClicked: root.nodeDoubleClicked(mouse, node)
|
onDoubleClicked: function(mouse) { root.nodeDoubleClicked(mouse, node) }
|
||||||
|
|
||||||
onMoved: uigraph.moveNode(node, position, uigraph.selectedNodes)
|
onMoved: function(position) { uigraph.moveNode(node, position, uigraph.selectedNodes) }
|
||||||
|
|
||||||
onEntered: uigraph.hoveredNode = node
|
onEntered: uigraph.hoveredNode = node
|
||||||
onExited: uigraph.hoveredNode = null
|
onExited: uigraph.hoveredNode = null
|
||||||
|
|
||||||
onEdgeAboutToBeRemoved: {
|
onEdgeAboutToBeRemoved: function(input) {
|
||||||
/*
|
/*
|
||||||
Sometimes the signals are not in the right order
|
* Sometimes the signals are not in the right order because of weird Qt/QML update order
|
||||||
because of weird Qt/QML update order (next DropArea
|
* (next DropArea entered signal before previous DropArea exited signal) so edgeAboutToBeRemoved
|
||||||
entered signal before previous DropArea exited signal)
|
* must be set to undefined before it can be set to another attribute object.
|
||||||
so edgeAboutToBeRemoved must be set to undefined before
|
*/
|
||||||
it can be set to another attribute object.
|
|
||||||
*/
|
|
||||||
if (input === undefined) {
|
if (input === undefined) {
|
||||||
if (nodeRepeater.temporaryEdgeAboutToBeRemoved === undefined) {
|
if (nodeRepeater.temporaryEdgeAboutToBeRemoved === undefined) {
|
||||||
root.edgeAboutToBeRemoved = input
|
root.edgeAboutToBeRemoved = input
|
||||||
|
@ -887,7 +896,7 @@ Item {
|
||||||
|
|
||||||
onPositionChanged: {
|
onPositionChanged: {
|
||||||
if (dragging && uigraph.selectedNodes.contains(node)) {
|
if (dragging && uigraph.selectedNodes.contains(node)) {
|
||||||
// update all selected nodes positions with this node that is being dragged
|
// Update all selected nodes positions with this node that is being dragged
|
||||||
for (var i = 0; i < nodeRepeater.count; i++) {
|
for (var i = 0; i < nodeRepeater.count; i++) {
|
||||||
var otherNode = nodeRepeater.itemAt(i)
|
var otherNode = nodeRepeater.itemAt(i)
|
||||||
if (uigraph.selectedNodes.contains(otherNode.node) && otherNode.node !== node) {
|
if (uigraph.selectedNodes.contains(otherNode.node) && otherNode.node !== node) {
|
||||||
|
@ -898,10 +907,10 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow all nodes to know if they are being dragged
|
// Allow all nodes to know if they are being dragged
|
||||||
onDraggingChanged: nodeRepeater.dragging = dragging
|
onDraggingChanged: nodeRepeater.dragging = dragging
|
||||||
|
|
||||||
// must not be enabled during drag because the other nodes will be slow to match the movement of the node being dragged
|
// Must not be enabled during drag because the other nodes will be slow to match the movement of the node being dragged
|
||||||
Behavior on x {
|
Behavior on x {
|
||||||
enabled: !nodeRepeater.dragging
|
enabled: !nodeRepeater.dragging
|
||||||
NumberAnimation { duration: 100 }
|
NumberAnimation { duration: 100 }
|
||||||
|
@ -956,12 +965,12 @@ Item {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onDropped: {
|
onDropped: function(drop) {
|
||||||
if (nbMeshroomScenes == nbDraggedFiles || nbMeshroomScenes == 0) {
|
if (nbMeshroomScenes == nbDraggedFiles || nbMeshroomScenes == 0) {
|
||||||
// retrieve mouse position and convert coordinate system
|
// Retrieve mouse position and convert coordinate system
|
||||||
// from pixel values to graph reference system
|
// from pixel values to graph reference system
|
||||||
var mousePosition = mapToItem(draggable, drag.x, drag.y)
|
var mousePosition = mapToItem(draggable, drag.x, drag.y)
|
||||||
// send the list of files,
|
// Send the list of files,
|
||||||
// to create the corresponding nodes or open another scene
|
// to create the corresponding nodes or open another scene
|
||||||
filesDropped(drop, mousePosition)
|
filesDropped(drop, mousePosition)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1110,12 +1119,12 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
function nextItem() {
|
function nextItem() {
|
||||||
// compute bounding box
|
// Compute bounding box
|
||||||
var node = nodeRepeater.itemAt(filteredNodes.itemAt(navigation.currentIndex).index_)
|
var node = nodeRepeater.itemAt(filteredNodes.itemAt(navigation.currentIndex).index_)
|
||||||
var bbox = Qt.rect(node.x, node.y, node.width, node.height)
|
var bbox = Qt.rect(node.x, node.y, node.width, node.height)
|
||||||
// rescale to fit the bounding box in the view, zoom is limited to prevent huge text
|
// Rescale to fit the bounding box in the view, zoom is limited to prevent huge text
|
||||||
draggable.scale = Math.min(Math.min(root.width / bbox.width, root.height / bbox.height),maxZoom)
|
draggable.scale = Math.min(Math.min(root.width / bbox.width, root.height / bbox.height),maxZoom)
|
||||||
// recenter
|
// Recenter
|
||||||
draggable.x = bbox.x*draggable.scale * -1 + (root.width - bbox.width * draggable.scale) * 0.5
|
draggable.x = bbox.x*draggable.scale * -1 + (root.width - bbox.width * draggable.scale) * 0.5
|
||||||
draggable.y = bbox.y*draggable.scale * -1 + (root.height - bbox.height * draggable.scale) * 0.5
|
draggable.y = bbox.y*draggable.scale * -1 + (root.height - bbox.height * draggable.scale) * 0.5
|
||||||
}
|
}
|
||||||
|
@ -1124,6 +1133,7 @@ Item {
|
||||||
function registerAttributePin(attribute, pin) {
|
function registerAttributePin(attribute, pin) {
|
||||||
root._attributeToDelegate[attribute] = pin
|
root._attributeToDelegate[attribute] = pin
|
||||||
}
|
}
|
||||||
|
|
||||||
function unregisterAttributePin(attribute, pin) {
|
function unregisterAttributePin(attribute, pin) {
|
||||||
delete root._attributeToDelegate[attribute]
|
delete root._attributeToDelegate[attribute]
|
||||||
}
|
}
|
||||||
|
@ -1148,11 +1158,11 @@ Item {
|
||||||
|
|
||||||
// Fit graph to fill root
|
// Fit graph to fill root
|
||||||
function fit() {
|
function fit() {
|
||||||
// compute bounding box
|
// Compute bounding box
|
||||||
var bbox = boundingBox()
|
var bbox = boundingBox()
|
||||||
// rescale to fit the bounding box in the view, zoom is limited to prevent huge text
|
// Rescale to fit the bounding box in the view, zoom is limited to prevent huge text
|
||||||
draggable.scale = Math.min(Math.min(root.width / bbox.width, root.height / bbox.height), maxZoom)
|
draggable.scale = Math.min(Math.min(root.width / bbox.width, root.height / bbox.height), maxZoom)
|
||||||
// recenter
|
// Recenter
|
||||||
draggable.x = bbox.x * draggable.scale * -1 + (root.width - bbox.width * draggable.scale) * 0.5
|
draggable.x = bbox.x * draggable.scale * -1 + (root.width - bbox.width * draggable.scale) * 0.5
|
||||||
draggable.y = bbox.y * draggable.scale * -1 + (root.height - bbox.height * draggable.scale) * 0.5
|
draggable.y = bbox.y * draggable.scale * -1 + (root.height - bbox.height * draggable.scale) * 0.5
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
pragma Singleton
|
pragma Singleton
|
||||||
import Qt.labs.settings 1.0
|
import QtCore
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Persistent Settings related to the GraphEditor module.
|
* Persistent Settings related to the GraphEditor module.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Settings {
|
Settings {
|
||||||
category: 'GraphEditor'
|
category: 'GraphEditor'
|
||||||
property bool showAdvancedAttributes: false
|
property bool showAdvancedAttributes: false
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import QtGraphicalEffects 1.12
|
import Qt5Compat.GraphicalEffects
|
||||||
|
|
||||||
import Utils 1.0
|
|
||||||
import MaterialIcons 2.2
|
import MaterialIcons 2.2
|
||||||
|
import Utils 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visual representation of a Graph Node.
|
* Visual representation of a Graph Node.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
@ -121,12 +121,12 @@ Item {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: body.height
|
height: body.height
|
||||||
drag.target: root
|
drag.target: root
|
||||||
// small drag threshold to avoid moving the node by mistake
|
// Small drag threshold to avoid moving the node by mistake
|
||||||
drag.threshold: 2
|
drag.threshold: 2
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
onPressed: root.pressed(mouse)
|
onPressed: function(mouse) { root.pressed(mouse) }
|
||||||
onDoubleClicked: root.doubleClicked(mouse)
|
onDoubleClicked: function(mouse) { root.doubleClicked(mouse) }
|
||||||
onEntered: root.entered()
|
onEntered: root.entered()
|
||||||
onExited: root.exited()
|
onExited: root.exited()
|
||||||
drag.onActiveChanged: {
|
drag.onActiveChanged: {
|
||||||
|
@ -412,8 +412,8 @@ Item {
|
||||||
property real globalX: root.x + nodeAttributes.x + outputs.x + outputLoader.x + outPin.x
|
property real globalX: root.x + nodeAttributes.x + outputs.x + outputLoader.x + outPin.x
|
||||||
property real globalY: root.y + nodeAttributes.y + outputs.y + outputLoader.y + outPin.y
|
property real globalY: root.y + nodeAttributes.y + outputs.y + outputLoader.y + outPin.y
|
||||||
|
|
||||||
onPressed: root.pressed(mouse)
|
onPressed: function(mouse) { root.pressed(mouse) }
|
||||||
onEdgeAboutToBeRemoved: root.edgeAboutToBeRemoved(input)
|
onEdgeAboutToBeRemoved: function(input) { root.edgeAboutToBeRemoved(input) }
|
||||||
|
|
||||||
Component.onCompleted: attributePinCreated(attribute, outPin)
|
Component.onCompleted: attributePinCreated(attribute, outPin)
|
||||||
onChildPinCreated: attributePinCreated(childAttribute, outPin)
|
onChildPinCreated: attributePinCreated(childAttribute, outPin)
|
||||||
|
@ -446,13 +446,13 @@ Item {
|
||||||
property real globalX: root.x + nodeAttributes.x + inputs.x + inputLoader.x + inPin.x
|
property real globalX: root.x + nodeAttributes.x + inputs.x + inputLoader.x + inPin.x
|
||||||
property real globalY: root.y + nodeAttributes.y + inputs.y + inputLoader.y + inPin.y
|
property real globalY: root.y + nodeAttributes.y + inputs.y + inputLoader.y + inPin.y
|
||||||
|
|
||||||
readOnly: root.readOnly || object.isReadOnly
|
readOnly: Boolean(root.readOnly || object.isReadOnly)
|
||||||
Component.onCompleted: attributePinCreated(attribute, inPin)
|
Component.onCompleted: attributePinCreated(attribute, inPin)
|
||||||
Component.onDestruction: attributePinDeleted(attribute, inPin)
|
Component.onDestruction: attributePinDeleted(attribute, inPin)
|
||||||
onPressed: root.pressed(mouse)
|
onPressed: function(mouse) { root.pressed(mouse) }
|
||||||
onEdgeAboutToBeRemoved: root.edgeAboutToBeRemoved(input)
|
onEdgeAboutToBeRemoved: function(input) { root.edgeAboutToBeRemoved(input) }
|
||||||
onChildPinCreated: attributePinCreated(childAttribute, inPin)
|
onChildPinCreated: function(childAttribute, inPin) { attributePinCreated(childAttribute, inPin) }
|
||||||
onChildPinDeleted: attributePinDeleted(childAttribute, inPin)
|
onChildPinDeleted: function(childAttribute, inPin) { attributePinDeleted(childAttribute, inPin) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -512,10 +512,10 @@ Item {
|
||||||
readOnly: Boolean(root.readOnly || object.isReadOnly)
|
readOnly: Boolean(root.readOnly || object.isReadOnly)
|
||||||
Component.onCompleted: attributePinCreated(attribute, inParamsPin)
|
Component.onCompleted: attributePinCreated(attribute, inParamsPin)
|
||||||
Component.onDestruction: attributePinDeleted(attribute, inParamsPin)
|
Component.onDestruction: attributePinDeleted(attribute, inParamsPin)
|
||||||
onPressed: root.pressed(mouse)
|
onPressed: function(mouse) { root.pressed(mouse) }
|
||||||
onEdgeAboutToBeRemoved: root.edgeAboutToBeRemoved(input)
|
onEdgeAboutToBeRemoved: function(input) { root.edgeAboutToBeRemoved(input) }
|
||||||
onChildPinCreated: attributePinCreated(childAttribute, inParamsPin)
|
onChildPinCreated: function(childAttribute, inParamsPin) { attributePinCreated(childAttribute, inParamsPin) }
|
||||||
onChildPinDeleted: attributePinDeleted(childAttribute, inParamsPin)
|
onChildPinDeleted: function(childAttribute, inParamsPin) { attributePinDeleted(childAttribute, inParamsPin) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import Utils 1.0
|
|
||||||
|
|
||||||
//import "common.js" as Common
|
import Utils 1.0
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
id: root
|
id: root
|
||||||
|
@ -14,7 +13,7 @@ ListView {
|
||||||
property real chunkHeight: height
|
property real chunkHeight: height
|
||||||
property bool modelIsBig: (3 * model.count >= width)
|
property bool modelIsBig: (3 * model.count >= width)
|
||||||
property real chunkWidth: {
|
property real chunkWidth: {
|
||||||
if(!model || model.count == 0)
|
if (!model || model.count == 0)
|
||||||
return 0
|
return 0
|
||||||
return (width / model.count) - spacing
|
return (width / model.count) - spacing
|
||||||
}
|
}
|
||||||
|
@ -29,13 +28,12 @@ ListView {
|
||||||
width: root.chunkWidth
|
width: root.chunkWidth
|
||||||
property var chunkColor: Colors.getChunkColor(object, { "NONE": root.defaultColor })
|
property var chunkColor: Colors.getChunkColor(object, { "NONE": root.defaultColor })
|
||||||
color: {
|
color: {
|
||||||
if(!highlightChunks || model.count == 1)
|
if (!highlightChunks || model.count == 1)
|
||||||
return chunkColor
|
return chunkColor
|
||||||
if(index % 2 == 0)
|
if (index % 2 == 0)
|
||||||
return Qt.lighter(chunkColor, 1.1)
|
return Qt.lighter(chunkColor, 1.1)
|
||||||
else
|
else
|
||||||
return Qt.darker(chunkColor, 1.1)
|
return Qt.darker(chunkColor, 1.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import Controls 1.0
|
import Controls 1.0
|
||||||
|
|
||||||
import "common.js" as Common
|
import "common.js" as Common
|
||||||
|
@ -8,6 +9,7 @@ import "common.js" as Common
|
||||||
/**
|
/**
|
||||||
* Displays Node documentation
|
* Displays Node documentation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
FocusScope {
|
FocusScope {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import MaterialIcons 2.2
|
|
||||||
import Controls 1.0
|
|
||||||
import Utils 1.0
|
|
||||||
|
|
||||||
|
import Controls 1.0
|
||||||
|
import MaterialIcons 2.2
|
||||||
|
import Utils 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NodeEditor allows to visualize and edit the parameters of a Node.
|
* NodeEditor allows to visualize and edit the parameters of a Node.
|
||||||
* It mainly provides an attribute editor and a log inspector.
|
* It mainly provides an attribute editor and a log inspector.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Panel {
|
Panel {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
@ -35,7 +36,7 @@ Panel {
|
||||||
if (node !== null && (node.isFinishedOrRunning() || globalStatus == "ERROR")) {
|
if (node !== null && (node.isFinishedOrRunning() || globalStatus == "ERROR")) {
|
||||||
computationInfo.text = Format.sec2timeStr(node.elapsedTime)
|
computationInfo.text = Format.sec2timeStr(node.elapsedTime)
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
computationInfo.text = ""
|
computationInfo.text = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,6 +118,7 @@ Panel {
|
||||||
Menu {
|
Menu {
|
||||||
id: settingsMenu
|
id: settingsMenu
|
||||||
y: parent.height
|
y: parent.height
|
||||||
|
|
||||||
Menu {
|
Menu {
|
||||||
id: filterAttributesMenu
|
id: filterAttributesMenu
|
||||||
title: "Filter Attributes"
|
title: "Filter Attributes"
|
||||||
|
@ -138,7 +140,9 @@ Panel {
|
||||||
enabled: tabBar.currentIndex === 0
|
enabled: tabBar.currentIndex === 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
CheckBox {
|
CheckBox {
|
||||||
id: defaultToggle
|
id: defaultToggle
|
||||||
|
@ -157,7 +161,9 @@ Panel {
|
||||||
enabled: tabBar.currentIndex === 0
|
enabled: tabBar.currentIndex === 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
CheckBox {
|
CheckBox {
|
||||||
id: linkToggle
|
id: linkToggle
|
||||||
|
@ -176,7 +182,9 @@ Panel {
|
||||||
enabled: tabBar.currentIndex === 0
|
enabled: tabBar.currentIndex === 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
|
|
||||||
CheckBox {
|
CheckBox {
|
||||||
id: advancedToggle
|
id: advancedToggle
|
||||||
text: "Advanced"
|
text: "Advanced"
|
||||||
|
@ -196,7 +204,9 @@ Panel {
|
||||||
enabled: root.node !== null
|
enabled: root.node !== null
|
||||||
onClicked: Qt.openUrlExternally(Filepath.stringToUrl(root.node.internalFolder))
|
onClicked: Qt.openUrlExternally(Filepath.stringToUrl(root.node.internalFolder))
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
|
|
||||||
MenuItem {
|
MenuItem {
|
||||||
enabled: root.node !== null
|
enabled: root.node !== null
|
||||||
text: "Clear Pending Status"
|
text: "Clear Pending Status"
|
||||||
|
@ -208,6 +218,7 @@ Panel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
@ -215,7 +226,7 @@ Panel {
|
||||||
Loader {
|
Loader {
|
||||||
active: root.isCompatibilityNode
|
active: root.isCompatibilityNode
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
visible: active // for layout update
|
visible: active // For layout update
|
||||||
|
|
||||||
sourceComponent: CompatibilityBadge {
|
sourceComponent: CompatibilityBadge {
|
||||||
canUpgrade: root.node.canUpgrade
|
canUpgrade: root.node.canUpgrade
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import MaterialIcons 2.2
|
|
||||||
import Controls 1.0
|
import Controls 1.0
|
||||||
|
|
||||||
import "common.js" as Common
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NodeLog displays log and statistics data of Node's chunks (NodeChunks)
|
* NodeLog displays the log file of Node's chunks (NodeChunks).
|
||||||
*
|
*
|
||||||
* To ease monitoring, it provides periodic auto-reload of the opened file
|
* To ease monitoring, it provides periodic auto-reload of the opened file
|
||||||
* if the related NodeChunk is being computed.
|
* if the related NodeChunk is being computed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
FocusScope {
|
FocusScope {
|
||||||
id: root
|
id: root
|
||||||
property variant node
|
property variant node
|
||||||
|
@ -29,7 +28,7 @@ FocusScope {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
property string currentFile: (root.currentChunkIndex >= 0 && root.currentChunk) ? root.currentChunk["logFile"] : ""
|
property string currentFile: (root.currentChunkIndex >= 0 && root.currentChunk) ? root.currentChunk["logFile"] : ""
|
||||||
property url source: Filepath.stringToUrl(currentFile)
|
property url sourceFile: Filepath.stringToUrl(currentFile)
|
||||||
|
|
||||||
sourceComponent: textFileViewerComponent
|
sourceComponent: textFileViewerComponent
|
||||||
}
|
}
|
||||||
|
@ -40,9 +39,8 @@ FocusScope {
|
||||||
TextFileViewer {
|
TextFileViewer {
|
||||||
id: textFileViewer
|
id: textFileViewer
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
source: componentLoader.source
|
source: componentLoader.sourceFile
|
||||||
autoReload: root.currentChunk !== undefined && root.currentChunk.statusName === "RUNNING"
|
autoReload: root.currentChunk !== undefined && root.currentChunk.statusName === "RUNNING"
|
||||||
// source is set in fileSelector
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import MaterialIcons 2.2
|
|
||||||
import Controls 1.0
|
|
||||||
import Utils 1.0
|
|
||||||
|
|
||||||
import "common.js" as Common
|
import Controls 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NodeLog displays log and statistics data of Node's chunks (NodeChunks)
|
* NodeStatistics displays statistics data of Node's chunks (NodeChunks).
|
||||||
*
|
*
|
||||||
* To ease monitoring, it provides periodic auto-reload of the opened file
|
* To ease monitoring, it provides periodic auto-reload of the opened file
|
||||||
* if the related NodeChunk is being computed.
|
* if the related NodeChunk is being computed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
FocusScope {
|
FocusScope {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
@ -27,7 +25,7 @@ FocusScope {
|
||||||
clip: true
|
clip: true
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
property string currentFile: currentChunk ? currentChunk["statisticsFile"] : ""
|
property string currentFile: currentChunk ? currentChunk["statisticsFile"] : ""
|
||||||
property url source: Filepath.stringToUrl(currentFile)
|
property url sourceFile: Filepath.stringToUrl(currentFile)
|
||||||
|
|
||||||
sourceComponent: chunksLV.chunksSummary ? statViewerComponent : chunkStatViewerComponent
|
sourceComponent: chunksLV.chunksSummary ? statViewerComponent : chunkStatViewerComponent
|
||||||
}
|
}
|
||||||
|
@ -37,7 +35,7 @@ FocusScope {
|
||||||
StatViewer {
|
StatViewer {
|
||||||
id: statViewer
|
id: statViewer
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
source: componentLoader.source
|
source: componentLoader.sourceFile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,14 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import MaterialIcons 2.2
|
|
||||||
import Controls 1.0
|
|
||||||
|
|
||||||
import "common.js" as Common
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NodeLog displays log and statistics data of Node's chunks (NodeChunks)
|
* NodeStatus displays the status-related information of Node's chunks (NodeChunks)
|
||||||
*
|
*
|
||||||
* To ease monitoring, it provides periodic auto-reload of the opened file
|
* To ease monitoring, it provides periodic auto-reload of the opened file
|
||||||
* if the related NodeChunk is being computed.
|
* if the related NodeChunk is being computed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
FocusScope {
|
FocusScope {
|
||||||
id: root
|
id: root
|
||||||
property variant node
|
property variant node
|
||||||
|
@ -26,7 +23,7 @@ FocusScope {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
property string currentFile: (root.currentChunkIndex >= 0) ? root.currentChunk["statusFile"] : ""
|
property string currentFile: (root.currentChunkIndex >= 0) ? root.currentChunk["statusFile"] : ""
|
||||||
property url source: Filepath.stringToUrl(currentFile)
|
property url sourceFile: Filepath.stringToUrl(currentFile)
|
||||||
|
|
||||||
sourceComponent: statViewerComponent
|
sourceComponent: statViewerComponent
|
||||||
}
|
}
|
||||||
|
@ -35,7 +32,7 @@ FocusScope {
|
||||||
id: statViewerComponent
|
id: statViewerComponent
|
||||||
Item {
|
Item {
|
||||||
id: statusViewer
|
id: statusViewer
|
||||||
property url source: componentLoader.source
|
property url source: componentLoader.sourceFile
|
||||||
property var lastModified: undefined
|
property var lastModified: undefined
|
||||||
|
|
||||||
onSourceChanged: {
|
onSourceChanged: {
|
||||||
|
@ -46,7 +43,7 @@ FocusScope {
|
||||||
id: statusListModel
|
id: statusListModel
|
||||||
|
|
||||||
function readSourceFile() {
|
function readSourceFile() {
|
||||||
// make sure we are trying to load a statistics file
|
// Make sure we are trying to load a statistics file
|
||||||
if (!Filepath.urlToString(source).endsWith("status"))
|
if (!Filepath.urlToString(source).endsWith("status"))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -55,31 +52,28 @@ FocusScope {
|
||||||
|
|
||||||
xhr.onreadystatechange = function() {
|
xhr.onreadystatechange = function() {
|
||||||
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
|
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
|
||||||
// console.warn("StatusListModel: read valid file")
|
|
||||||
if (lastModified === undefined || lastModified !== xhr.getResponseHeader('Last-Modified')) {
|
if (lastModified === undefined || lastModified !== xhr.getResponseHeader('Last-Modified')) {
|
||||||
lastModified = xhr.getResponseHeader('Last-Modified')
|
lastModified = xhr.getResponseHeader('Last-Modified')
|
||||||
try {
|
try {
|
||||||
var jsonObject = JSON.parse(xhr.responseText)
|
var jsonObject = JSON.parse(xhr.responseText)
|
||||||
|
|
||||||
var entries = []
|
var entries = []
|
||||||
// prepare data to populate the ListModel from the input json object
|
// Prepare data to populate the ListModel from the input json object
|
||||||
for (var key in jsonObject) {
|
for (var key in jsonObject) {
|
||||||
var entry = {}
|
var entry = {}
|
||||||
entry["key"] = key
|
entry["key"] = key
|
||||||
entry["value"] = String(jsonObject[key])
|
entry["value"] = String(jsonObject[key])
|
||||||
entries.push(entry)
|
entries.push(entry)
|
||||||
}
|
}
|
||||||
// reset the model with prepared data (limit to one update event)
|
// Reset the model with prepared data (limit to one update event)
|
||||||
statusListModel.clear()
|
statusListModel.clear()
|
||||||
statusListModel.append(entries)
|
statusListModel.append(entries)
|
||||||
} catch(exc) {
|
} catch(exc) {
|
||||||
// console.warn("StatusListModel: failed to read file")
|
|
||||||
lastModified = undefined
|
lastModified = undefined
|
||||||
statusListModel.clear()
|
statusListModel.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// console.warn("StatusListModel: invalid file")
|
|
||||||
lastModified = undefined
|
lastModified = undefined
|
||||||
statusListModel.clear()
|
statusListModel.clear()
|
||||||
}
|
}
|
||||||
|
@ -103,7 +97,6 @@ FocusScope {
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: statusKey
|
id: statusKey
|
||||||
anchors.margins: 2
|
anchors.margins: 2
|
||||||
// height: statusValue.height
|
|
||||||
color: Qt.darker(activePalette.window, 1.1)
|
color: Qt.darker(activePalette.window, 1.1)
|
||||||
Layout.preferredWidth: sizeHandle.x
|
Layout.preferredWidth: sizeHandle.x
|
||||||
Layout.minimumWidth: 10.0 * Qt.application.font.pixelSize
|
Layout.minimumWidth: 10.0 * Qt.application.font.pixelSize
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Dialogs
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import Controls 1.0
|
import Controls 1.0
|
||||||
import Utils 1.0
|
|
||||||
import MaterialIcons 2.2
|
import MaterialIcons 2.2
|
||||||
|
import Utils 1.0
|
||||||
|
|
||||||
import Qt.labs.platform 1.0 as Platform
|
import Qt.labs.platform 1.0 as Platform
|
||||||
import QtQuick.Dialogs 1.3
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import QtQuick 2.15
|
import QtCharts
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick
|
||||||
import QtCharts 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import Utils 1.0
|
|
||||||
import Charts 1.0
|
import Charts 1.0
|
||||||
import MaterialIcons 2.2
|
import MaterialIcons 2.2
|
||||||
|
import Utils 1.0
|
||||||
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
@ -36,8 +37,7 @@ Item {
|
||||||
|
|
||||||
property color textColor: Colors.sysPalette.text
|
property color textColor: Colors.sysPalette.text
|
||||||
|
|
||||||
|
readonly property var colors: [
|
||||||
readonly property var colors: [
|
|
||||||
"#f44336",
|
"#f44336",
|
||||||
"#e91e63",
|
"#e91e63",
|
||||||
"#9c27b0",
|
"#9c27b0",
|
||||||
|
@ -93,7 +93,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
function readSourceFile() {
|
function readSourceFile() {
|
||||||
// make sure we are trying to load a statistics file
|
// Make sure we are trying to load a statistics file
|
||||||
if (!Filepath.urlToString(source).endsWith("statistics"))
|
if (!Filepath.urlToString(source).endsWith("statistics"))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ Item {
|
||||||
|
|
||||||
xhr.onreadystatechange = function() {
|
xhr.onreadystatechange = function() {
|
||||||
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status == 200) {
|
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status == 200) {
|
||||||
if (sourceModified === undefined || sourceModified < xhr.getResponseHeader('Last-Modified')) {
|
if (sourceModified === undefined || sourceModified < xhr.getResponseHeader("Last-Modified")) {
|
||||||
try {
|
try {
|
||||||
root.jsonObject = JSON.parse(xhr.responseText)
|
root.jsonObject = JSON.parse(xhr.responseText)
|
||||||
} catch(exc) {
|
} catch(exc) {
|
||||||
|
@ -111,7 +111,7 @@ Item {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
resetCharts()
|
resetCharts()
|
||||||
sourceModified = xhr.getResponseHeader('Last-Modified')
|
sourceModified = xhr.getResponseHeader("Last-Modified")
|
||||||
root.createCharts()
|
root.createCharts()
|
||||||
reloadTimer.restart()
|
reloadTimer.restart()
|
||||||
}
|
}
|
||||||
|
@ -129,8 +129,8 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
function createCharts() {
|
function createCharts() {
|
||||||
root.deltaTime = getPropertyWithDefault(jsonObject, 'interval', 30) / 60.0;
|
root.deltaTime = getPropertyWithDefault(jsonObject, "interval", 30) / 60.0;
|
||||||
root.fileVersion = getPropertyWithDefault(jsonObject, 'fileVersion', 0.0)
|
root.fileVersion = getPropertyWithDefault(jsonObject, "fileVersion", 0.0)
|
||||||
initCpuChart()
|
initCpuChart()
|
||||||
initRamChart()
|
initRamChart()
|
||||||
initGpuChart()
|
initGpuChart()
|
||||||
|
@ -157,7 +157,7 @@ Item {
|
||||||
var nbCores = categories.length
|
var nbCores = categories.length
|
||||||
root.nbCores = nbCores
|
root.nbCores = nbCores
|
||||||
|
|
||||||
root.cpuFrequency = getPropertyWithDefault(jsonObject.computer, 'cpuFreq', -1)
|
root.cpuFrequency = getPropertyWithDefault(jsonObject.computer, "cpuFreq", -1)
|
||||||
|
|
||||||
root.nbReads = categories[0].length-1
|
root.nbReads = categories[0].length-1
|
||||||
|
|
||||||
|
@ -218,9 +218,9 @@ Item {
|
||||||
|
|
||||||
function initRamChart() {
|
function initRamChart() {
|
||||||
|
|
||||||
var ram = getPropertyWithDefault(jsonObject.computer.curves, 'ramUsage', -1)
|
var ram = getPropertyWithDefault(jsonObject.computer.curves, "ramUsage", -1)
|
||||||
|
|
||||||
root.ramTotal = getPropertyWithDefault(jsonObject.computer, 'ramTotal', -1)
|
root.ramTotal = getPropertyWithDefault(jsonObject.computer, "ramTotal", -1)
|
||||||
root.ramLabel = "RAM: "
|
root.ramLabel = "RAM: "
|
||||||
if (root.ramTotal <= 0) {
|
if (root.ramTotal <= 0) {
|
||||||
var maxRamPeak = 0
|
var maxRamPeak = 0
|
||||||
|
@ -248,17 +248,18 @@ Item {
|
||||||
ramSerie.color = colors[10]
|
ramSerie.color = colors[10]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************
|
/**************************
|
||||||
*** GPU ***
|
*** GPU ***
|
||||||
**************************/
|
**************************/
|
||||||
|
|
||||||
function initGpuChart() {
|
function initGpuChart() {
|
||||||
root.gpuTotalMemory = getPropertyWithDefault(jsonObject.computer, 'gpuMemoryTotal', 0)
|
root.gpuTotalMemory = getPropertyWithDefault(jsonObject.computer, "gpuMemoryTotal", 0)
|
||||||
root.gpuName = getPropertyWithDefault(jsonObject.computer, 'gpuName', '')
|
root.gpuName = getPropertyWithDefault(jsonObject.computer, "gpuName", "")
|
||||||
|
|
||||||
var gpuUsedMemory = getPropertyWithDefault(jsonObject.computer.curves, 'gpuMemoryUsed', 0)
|
var gpuUsedMemory = getPropertyWithDefault(jsonObject.computer.curves, "gpuMemoryUsed", 0)
|
||||||
var gpuUsed = getPropertyWithDefault(jsonObject.computer.curves, 'gpuUsed', 0)
|
var gpuUsed = getPropertyWithDefault(jsonObject.computer.curves, "gpuUsed", 0)
|
||||||
var gpuTemperature = getPropertyWithDefault(jsonObject.computer.curves, 'gpuTemperature', 0)
|
var gpuTemperature = getPropertyWithDefault(jsonObject.computer.curves, "gpuTemperature", 0)
|
||||||
|
|
||||||
var gpuUsedSerie = gpuChart.createSeries(ChartView.SeriesTypeLine, "GPU", valueGpuX, valueGpuY)
|
var gpuUsedSerie = gpuChart.createSeries(ChartView.SeriesTypeLine, "GPU", valueGpuX, valueGpuY)
|
||||||
var gpuUsedMemorySerie = gpuChart.createSeries(ChartView.SeriesTypeLine, "Memory", valueGpuX, valueGpuY)
|
var gpuUsedMemorySerie = gpuChart.createSeries(ChartView.SeriesTypeLine, "Memory", valueGpuX, valueGpuY)
|
||||||
|
@ -389,7 +390,7 @@ Item {
|
||||||
plotAreaColor: "transparent"
|
plotAreaColor: "transparent"
|
||||||
titleColor: textColor
|
titleColor: textColor
|
||||||
|
|
||||||
visible: (root.fileVersion > 0.0) // only visible if we have valid information
|
visible: (root.fileVersion > 0.0) // Only visible if we have valid information
|
||||||
title: "CPU: " + root.nbCores + " cores, " + root.cpuFrequency + "MHz"
|
title: "CPU: " + root.nbCores + " cores, " + root.cpuFrequency + "MHz"
|
||||||
|
|
||||||
ValueAxis {
|
ValueAxis {
|
||||||
|
@ -421,7 +422,6 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**************************
|
/**************************
|
||||||
*** RAM UI ***
|
*** RAM UI ***
|
||||||
**************************/
|
**************************/
|
||||||
|
@ -443,7 +443,7 @@ Item {
|
||||||
plotAreaColor: "transparent"
|
plotAreaColor: "transparent"
|
||||||
titleColor: textColor
|
titleColor: textColor
|
||||||
|
|
||||||
visible: (root.fileVersion > 0.0) // only visible if we have valid information
|
visible: (root.fileVersion > 0.0) // Only visible if we have valid information
|
||||||
title: root.ramLabel + root.ramTotal + "GB"
|
title: root.ramLabel + root.ramTotal + "GB"
|
||||||
|
|
||||||
ValueAxis {
|
ValueAxis {
|
||||||
|
@ -475,7 +475,6 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**************************
|
/**************************
|
||||||
*** GPU UI ***
|
*** GPU UI ***
|
||||||
**************************/
|
**************************/
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import Controls 1.0
|
import Controls 1.0
|
||||||
import Utils 1.0
|
import Utils 1.0
|
||||||
import MaterialIcons 2.2
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
@ -133,7 +133,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: RowLayout {
|
delegate: RowLayout {
|
||||||
width: parent != null ? parent.width : undefined
|
width: ListView.view.width
|
||||||
height: 18
|
height: 18
|
||||||
spacing: 3
|
spacing: 3
|
||||||
|
|
||||||
|
@ -261,7 +261,6 @@ Item {
|
||||||
radius: 3
|
radius: 3
|
||||||
border.width: 2
|
border.width: 2
|
||||||
border.color: chunkList.node === uigraph.selectedNode ? Colors.sysPalette.text : Colors.getChunkColor(object, {"NONE": bgColor})
|
border.color: chunkList.node === uigraph.selectedNode ? Colors.sysPalette.text : Colors.getChunkColor(object, {"NONE": bgColor})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
var statusColors = {
|
var statusColors = {
|
||||||
"NONE": "transparent",
|
"NONE": "transparent",
|
||||||
"SUBMITTED": "#009688",
|
"SUBMITTED": "#009688",
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import Utils 1.0
|
import Utils 1.0
|
||||||
import MaterialIcons 2.2
|
import MaterialIcons 2.2
|
||||||
import Controls 1.0
|
import Controls 1.0
|
||||||
|
@ -21,7 +22,6 @@ Page {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
|
||||||
SplitView.minimumWidth: 250
|
SplitView.minimumWidth: 250
|
||||||
SplitView.preferredWidth: 330
|
SplitView.preferredWidth: 330
|
||||||
SplitView.maximumWidth: 500
|
SplitView.maximumWidth: 500
|
||||||
|
@ -372,10 +372,10 @@ Page {
|
||||||
Connections {
|
Connections {
|
||||||
target: projectDelegate
|
target: projectDelegate
|
||||||
function onClicked() {
|
function onClicked() {
|
||||||
if (!modelData["path"]){
|
if (!modelData["path"]) {
|
||||||
initFileDialogFolder(openFileDialog)
|
initFileDialogFolder(openFileDialog)
|
||||||
openFileDialog.open()
|
openFileDialog.open()
|
||||||
} else{
|
} else {
|
||||||
// Open project
|
// Open project
|
||||||
mainStack.push("Application.qml")
|
mainStack.push("Application.qml")
|
||||||
if (_reconstruction.loadUrl(modelData["path"])) {
|
if (_reconstruction.loadUrl(modelData["path"])) {
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
|
|
||||||
import MaterialIcons 2.2
|
import MaterialIcons 2.2
|
||||||
import Utils 1.0
|
import Utils 1.0
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ImageBadge is a preset MaterialLabel to display an icon bagdge on an image.
|
* ImageBadge is a preset MaterialLabel to display an icon bagdge on an image.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
MaterialLabel {
|
MaterialLabel {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
font.pointSize: 10
|
font.pointSize: 10
|
||||||
padding: 2
|
padding: 2
|
||||||
background: Rectangle { color: Colors.sysPalette.window; opacity: 0.6 }
|
background: Rectangle {
|
||||||
|
color: Colors.sysPalette.window
|
||||||
|
opacity: 0.6
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import Utils 1.0
|
|
||||||
|
|
||||||
|
import Utils 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ImageDelegate for a Viewpoint object.
|
* ImageDelegate for a Viewpoint object.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ Item {
|
||||||
|
|
||||||
default property alias children: imageMA.children
|
default property alias children: imageMA.children
|
||||||
|
|
||||||
// retrieve viewpoints inner data
|
// Retrieve viewpoints inner data
|
||||||
QtObject {
|
QtObject {
|
||||||
id: _viewpoint
|
id: _viewpoint
|
||||||
property url source: viewpoint ? Filepath.stringToUrl(viewpoint.get("path").value) : ''
|
property url source: viewpoint ? Filepath.stringToUrl(viewpoint.get("path").value) : ''
|
||||||
|
@ -33,8 +34,8 @@ Item {
|
||||||
property var metadata: metadataStr ? JSON.parse(viewpoint.get("metadata").value) : {}
|
property var metadata: metadataStr ? JSON.parse(viewpoint.get("metadata").value) : {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update thumbnail location
|
// Update thumbnail location
|
||||||
// can be called from the GridView when a new thumbnail has been written on disk
|
// Can be called from the GridView when a new thumbnail has been written on disk
|
||||||
function updateThumbnail() {
|
function updateThumbnail() {
|
||||||
thumbnail.source = ThumbnailCache.thumbnail(root.source, root.cellID)
|
thumbnail.source = ThumbnailCache.thumbnail(root.source, root.cellID)
|
||||||
}
|
}
|
||||||
|
@ -60,7 +61,7 @@ Item {
|
||||||
anchors.margins: 6
|
anchors.margins: 6
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
onPressed: {
|
onPressed: function(mouse) {
|
||||||
if (mouse.button == Qt.RightButton)
|
if (mouse.button == Qt.RightButton)
|
||||||
imageMenu.popup()
|
imageMenu.popup()
|
||||||
root.pressed(mouse)
|
root.pressed(mouse)
|
||||||
|
@ -135,6 +136,7 @@ Item {
|
||||||
running: thumbnail.status != Image.Ready
|
running: thumbnail.status != Image.Ready
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Image basename
|
// Image basename
|
||||||
Label {
|
Label {
|
||||||
id: imageLabel
|
id: imageLabel
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import MaterialIcons 2.2
|
import QtQml.Models
|
||||||
import QtQml.Models 2.15
|
|
||||||
import Qt.labs.qmlmodels 1.0
|
import Qt.labs.qmlmodels 1.0
|
||||||
|
|
||||||
import Controls 1.0
|
import Controls 1.0
|
||||||
|
import MaterialIcons 2.2
|
||||||
import Utils 1.0
|
import Utils 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ImageGallery displays as a grid of Images a model containing Viewpoints objects.
|
* ImageGallery displays as a grid of Images a model containing Viewpoints objects.
|
||||||
* It manages a model of multiple CameraInit nodes as individual groups.
|
* It manages a model of multiple CameraInit nodes as individual groups.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Panel {
|
Panel {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ Panel {
|
||||||
property int defaultCellSize: 160
|
property int defaultCellSize: 160
|
||||||
property bool readOnly: false
|
property bool readOnly: false
|
||||||
|
|
||||||
property var filesByType: {}
|
property var filesByType: ({})
|
||||||
property int nbMeshroomScenes: 0
|
property int nbMeshroomScenes: 0
|
||||||
property int nbDraggedFiles: 0
|
property int nbDraggedFiles: 0
|
||||||
|
|
||||||
|
@ -98,7 +99,7 @@ Panel {
|
||||||
intrinsic[currentAttribute.name + "." + currentAttribute.value.at(k).name] = currentAttribute.value.at(k)
|
intrinsic[currentAttribute.name + "." + currentAttribute.value.at(k).name] = currentAttribute.value.at(k)
|
||||||
}
|
}
|
||||||
} else if (currentAttribute.type === "ListAttribute") {
|
} else if (currentAttribute.type === "ListAttribute") {
|
||||||
// not needed for now
|
// Not needed for now
|
||||||
} else {
|
} else {
|
||||||
intrinsic[currentAttribute.name] = currentAttribute
|
intrinsic[currentAttribute.name] = currentAttribute
|
||||||
}
|
}
|
||||||
|
@ -217,12 +218,12 @@ Panel {
|
||||||
Connections {
|
Connections {
|
||||||
target: ThumbnailCache
|
target: ThumbnailCache
|
||||||
function onThumbnailCreated(imgSource, callerID) {
|
function onThumbnailCreated(imgSource, callerID) {
|
||||||
let item = grid.itemAtIndex(callerID); // item is an ImageDelegate
|
let item = grid.itemAtIndex(callerID); // "item" is an ImageDelegate
|
||||||
if (item && item.source === imgSource) {
|
if (item && item.source === imgSource) {
|
||||||
item.updateThumbnail()
|
item.updateThumbnail()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// fallback in case the ImageDelegate cellID changed
|
// Fallback in case the ImageDelegate cellID changed
|
||||||
for (let idx = 0; idx < grid.count; idx++) {
|
for (let idx = 0; idx < grid.count; idx++) {
|
||||||
item = grid.itemAtIndex(idx)
|
item = grid.itemAtIndex(idx)
|
||||||
if (item && item.source === imgSource) {
|
if (item && item.source === imgSource) {
|
||||||
|
@ -250,7 +251,7 @@ Panel {
|
||||||
]
|
]
|
||||||
property var reconstructionFilter: undefined
|
property var reconstructionFilter: undefined
|
||||||
|
|
||||||
// override modelData to return basename of viewpoint's path for sorting
|
// Override modelData to return basename of viewpoint's path for sorting
|
||||||
function modelData(item, roleName_) {
|
function modelData(item, roleName_) {
|
||||||
var roleNameAndCmd = roleName_.split(".")
|
var roleNameAndCmd = roleName_.split(".")
|
||||||
var roleName = roleName_
|
var roleName = roleName_
|
||||||
|
@ -305,7 +306,7 @@ Panel {
|
||||||
}
|
}
|
||||||
|
|
||||||
onRemoveRequest: sendRemoveRequest()
|
onRemoveRequest: sendRemoveRequest()
|
||||||
Keys.onPressed: (event) => {
|
Keys.onPressed: function(event) {
|
||||||
if (event.key === Qt.Key_Delete && event.modifiers === Qt.ShiftModifier) {
|
if (event.key === Qt.Key_Delete && event.modifiers === Qt.ShiftModifier) {
|
||||||
removeAllImages()
|
removeAllImages()
|
||||||
} else if (event.key === Qt.Key_Delete) {
|
} else if (event.key === Qt.Key_Delete) {
|
||||||
|
@ -375,7 +376,7 @@ Panel {
|
||||||
|
|
||||||
// Keyboard shortcut to change current image group
|
// Keyboard shortcut to change current image group
|
||||||
Keys.priority: Keys.BeforeItem
|
Keys.priority: Keys.BeforeItem
|
||||||
Keys.onPressed: {
|
Keys.onPressed: function(event) {
|
||||||
if (event.modifiers & Qt.AltModifier) {
|
if (event.modifiers & Qt.AltModifier) {
|
||||||
if (event.key === Qt.Key_Right) {
|
if (event.key === Qt.Key_Right) {
|
||||||
_reconstruction.cameraInitIndex = Math.min(root.cameraInits.count - 1, root.cameraInitIndex + 1)
|
_reconstruction.cameraInitIndex = Math.min(root.cameraInits.count - 1, root.cameraInitIndex + 1)
|
||||||
|
@ -442,12 +443,12 @@ 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"]
|
||||||
onEntered: {
|
onEntered: function(drag) {
|
||||||
nbDraggedFiles = drag.urls.length
|
nbDraggedFiles = drag.urls.length
|
||||||
filesByType = _reconstruction.getFilesByTypeFromDrop(drag.urls)
|
filesByType = _reconstruction.getFilesByTypeFromDrop(drag.urls)
|
||||||
nbMeshroomScenes = filesByType["meshroomScenes"].length
|
nbMeshroomScenes = filesByType["meshroomScenes"].length
|
||||||
}
|
}
|
||||||
onDropped: {
|
onDropped: function(drop) {
|
||||||
var augmentSfm = augmentArea.hovered
|
var augmentSfm = augmentArea.hovered
|
||||||
if (nbMeshroomScenes == nbDraggedFiles || nbMeshroomScenes == 0) {
|
if (nbMeshroomScenes == nbDraggedFiles || nbMeshroomScenes == 0) {
|
||||||
root.filesDropped(filesByType, augmentSfm)
|
root.filesDropped(filesByType, augmentSfm)
|
||||||
|
@ -529,7 +530,7 @@ Panel {
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onPressed: {
|
onPressed: function(mouse) {
|
||||||
if (mouse.button == Qt.LeftButton)
|
if (mouse.button == Qt.LeftButton)
|
||||||
grid.forceActiveFocus()
|
grid.forceActiveFocus()
|
||||||
mouse.accepted = false
|
mouse.accepted = false
|
||||||
|
@ -831,8 +832,7 @@ Panel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onEnabledChanged: {
|
onEnabledChanged: {
|
||||||
// Reset the toggle to avoid getting stuck
|
// Reset the toggle to avoid getting stuck with the HDR node checked but disabled
|
||||||
// with the HDR node checked but disabled.
|
|
||||||
if (checked) {
|
if (checked) {
|
||||||
checked = false
|
checked = false
|
||||||
close()
|
close()
|
||||||
|
@ -875,8 +875,7 @@ Panel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onEnabledChanged: {
|
onEnabledChanged: {
|
||||||
// Reset the toggle to avoid getting stuck
|
// Reset the toggle to avoid getting stuck with the HDR node checked but disabled
|
||||||
// with the HDR node checked but disabled.
|
|
||||||
if (checked) {
|
if (checked) {
|
||||||
checked = false
|
checked = false
|
||||||
close()
|
close()
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import MaterialIcons 2.2
|
|
||||||
import Utils 1.0
|
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: root
|
id: root
|
||||||
|
@ -49,11 +47,12 @@ RowLayout {
|
||||||
if (!attribute)
|
if (!attribute)
|
||||||
return undefined
|
return undefined
|
||||||
switch (attribute.type) {
|
switch (attribute.type) {
|
||||||
case "ChoiceParam": return choice_component
|
case "ChoiceParam": return choiceComponent
|
||||||
case "IntParam": return int_component
|
case "IntParam": return intComponent
|
||||||
case "FloatParam": return float_component
|
case "FloatParam": return floatComponent
|
||||||
case "BoolParam": return bool_component
|
case "BoolParam": return boolComponent
|
||||||
case "StringParam": return textField_component
|
case "StringParam": return textFieldComponent
|
||||||
|
case "File": return textFieldComponent
|
||||||
default: return undefined
|
default: return undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +61,7 @@ RowLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: textField_component
|
id: textFieldComponent
|
||||||
TextInput {
|
TextInput {
|
||||||
text: attribute.value
|
text: attribute.value
|
||||||
width: intrinsicModel.columnWidths[columnIndex]
|
width: intrinsicModel.columnWidths[columnIndex]
|
||||||
|
@ -81,14 +80,14 @@ RowLayout {
|
||||||
_reconstruction.setAttribute(attribute, text)
|
_reconstruction.setAttribute(attribute, text)
|
||||||
}
|
}
|
||||||
Component.onDestruction: {
|
Component.onDestruction: {
|
||||||
if(activeFocus)
|
if (activeFocus)
|
||||||
_reconstruction.setAttribute(attribute, text)
|
_reconstruction.setAttribute(attribute, text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: int_component
|
id: intComponent
|
||||||
|
|
||||||
TextInput {
|
TextInput {
|
||||||
text: model.display.value
|
text: model.display.value
|
||||||
|
@ -121,7 +120,7 @@ RowLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: choice_component
|
id: choiceComponent
|
||||||
ComboBox {
|
ComboBox {
|
||||||
id: combo
|
id: combo
|
||||||
model: attribute.desc !== undefined ? attribute.desc.values : undefined
|
model: attribute.desc !== undefined ? attribute.desc.values : undefined
|
||||||
|
@ -146,7 +145,7 @@ RowLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: bool_component
|
id: boolComponent
|
||||||
CheckBox {
|
CheckBox {
|
||||||
checked: attribute ? attribute.value : false
|
checked: attribute ? attribute.value : false
|
||||||
padding: 12
|
padding: 12
|
||||||
|
@ -156,7 +155,7 @@ RowLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: float_component
|
id: floatComponent
|
||||||
TextInput {
|
TextInput {
|
||||||
readonly property real formattedValue: attribute.value.toFixed(2)
|
readonly property real formattedValue: attribute.value.toFixed(2)
|
||||||
property string displayValue: String(formattedValue)
|
property string displayValue: String(formattedValue)
|
||||||
|
@ -179,9 +178,9 @@ RowLayout {
|
||||||
|
|
||||||
autoScroll: activeFocus
|
autoScroll: activeFocus
|
||||||
|
|
||||||
//Use this function to ensure the left part is visible
|
// Use this function to ensure the left part is visible
|
||||||
//while keeping the trick for formatting the text
|
// while keeping the trick for formatting the text
|
||||||
//Timing issues otherwise
|
// Timing issues otherwise
|
||||||
onActiveFocusChanged: {
|
onActiveFocusChanged: {
|
||||||
if (activeFocus)
|
if (activeFocus)
|
||||||
text = String(attribute.value)
|
text = String(attribute.value)
|
||||||
|
@ -192,7 +191,7 @@ RowLayout {
|
||||||
|
|
||||||
DoubleValidator {
|
DoubleValidator {
|
||||||
id: doubleValidator
|
id: doubleValidator
|
||||||
locale: 'C' // use '.' decimal separator disregarding the system locale
|
locale: 'C' // Use '.' decimal separator disregarding the system locale
|
||||||
}
|
}
|
||||||
|
|
||||||
validator: doubleValidator
|
validator: doubleValidator
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
|
|
||||||
import MaterialIcons 2.2
|
import MaterialIcons 2.2
|
||||||
import Utils 1.0
|
import Utils 1.0
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display camera initialization status and the value of metadata
|
* Display camera initialization status and the value of metadata
|
||||||
* that take part in this process.
|
* that take part in this process.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ImageBadge {
|
ImageBadge {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
@ -27,7 +28,8 @@ ImageBadge {
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
// access useful metadata
|
|
||||||
|
// Access useful metadata
|
||||||
readonly property var make: findMetadata("Make")
|
readonly property var make: findMetadata("Make")
|
||||||
readonly property var model: findMetadata("Model")
|
readonly property var model: findMetadata("Model")
|
||||||
readonly property var focalLength: findMetadata("FocalLength")
|
readonly property var focalLength: findMetadata("FocalLength")
|
||||||
|
@ -103,13 +105,12 @@ ImageBadge {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
State {
|
State {
|
||||||
// fallback status when initialization mode is unset
|
// Fallback status when initialization mode is unset
|
||||||
name: "none"
|
name: "none"
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: root
|
target: root
|
||||||
visible: false
|
visible: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import MaterialIcons 2.2
|
import MaterialIcons 2.2
|
||||||
import Controls 1.0
|
import Controls 1.0
|
||||||
|
|
||||||
|
|
||||||
MessageDialog {
|
MessageDialog {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import MaterialIcons 2.2
|
import MaterialIcons 2.2
|
||||||
import Qt.labs.platform 1.0 as Platform // for FileDialog
|
import Qt.labs.platform 1.0 as Platform
|
||||||
|
|
||||||
import Controls 1.0
|
import Controls 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LiveSfMView provides controls for setting up and starting a live reconstruction.
|
* LiveSfMView provides controls for setting up and starting a live reconstruction.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Panel {
|
Panel {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MLabel is a standard Label.
|
* MLabel is a standard Label.
|
||||||
* If ToolTip.text is set, it shows up a tooltip when hovered.
|
* If ToolTip.text is set, it shows up a tooltip when hovered.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
padding: 4
|
padding: 4
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
pragma Singleton
|
pragma Singleton
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
property FontLoader fl: FontLoader {
|
property FontLoader fl: FontLoader {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MaterialLabel is a standard Label using MaterialIcons font.
|
* MaterialLabel is a standard Label using MaterialIcons font.
|
||||||
* If ToolTip.text is set, it also shows up a tooltip when hovered.
|
* If ToolTip.text is set, it also shows up a tooltip when hovered.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
font.family: MaterialIcons.fontFamily
|
font.family: MaterialIcons.fontFamily
|
||||||
font.pointSize: 10
|
font.pointSize: 10
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MaterialToolButton is a standard ToolButton using MaterialIcons font.
|
* MaterialToolButton is a standard ToolButton using MaterialIcons font.
|
||||||
* It also shows up its tooltip when hovered.
|
* It also shows up its tooltip when hovered.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ToolButton {
|
ToolButton {
|
||||||
id: control
|
id: control
|
||||||
font.family: MaterialIcons.fontFamily
|
font.family: MaterialIcons.fontFamily
|
||||||
|
@ -19,7 +19,7 @@ ToolButton {
|
||||||
}
|
}
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: {
|
color: {
|
||||||
if (pressed || checked || hovered) {
|
if (enabled && (pressed || checked || hovered)) {
|
||||||
if (pressed || checked)
|
if (pressed || checked)
|
||||||
return Qt.darker(parent.palette.base, 1.3)
|
return Qt.darker(parent.palette.base, 1.3)
|
||||||
if (hovered)
|
if (hovered)
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MaterialToolLabel is a Label with an icon (using MaterialIcons).
|
* MaterialToolLabel is a Label with an icon (using MaterialIcons).
|
||||||
* It shows up its tooltip when hovered.
|
* It shows up its tooltip when hovered.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: control
|
id: control
|
||||||
property alias iconText: iconItem.text
|
property alias iconText: iconItem.text
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MaterialToolButton is a standard ToolButton using MaterialIcons font.
|
* MaterialToolButton is a standard ToolButton using MaterialIcons font.
|
||||||
* It also shows up its tooltip when hovered.
|
* It also shows up its tooltip when hovered.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ToolButton {
|
ToolButton {
|
||||||
id: control
|
id: control
|
||||||
property alias iconText: icon.text
|
property alias iconText: icon.text
|
||||||
|
@ -41,7 +41,7 @@ ToolButton {
|
||||||
}
|
}
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: {
|
color: {
|
||||||
if (pressed || checked || hovered) {
|
if (enabled && (pressed || checked || hovered)) {
|
||||||
if (pressed || checked)
|
if (pressed || checked)
|
||||||
return Qt.darker(parent.palette.base, 1.3)
|
return Qt.darker(parent.palette.base, 1.3)
|
||||||
if (hovered)
|
if (hovered)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import Meshroom.Helpers 1.0
|
||||||
/**
|
/**
|
||||||
* Clipboard singleton object to copy values to paste buffer.
|
* Clipboard singleton object to copy values to paste buffer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ClipboardHelper {
|
ClipboardHelper {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
pragma Singleton
|
pragma Singleton
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Singleton that gathers useful colors, shades and system palettes.
|
* Singleton that gathers useful colors, shades and system palettes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
property SystemPalette sysPalette: SystemPalette {}
|
property SystemPalette sysPalette: SystemPalette {}
|
||||||
property SystemPalette disabledSysPalette: SystemPalette { colorGroup: SystemPalette.Disabled }
|
property SystemPalette disabledSysPalette: SystemPalette { colorGroup: SystemPalette.Disabled }
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
pragma Singleton
|
pragma Singleton
|
||||||
import QtQuick 2.11
|
import QtQuick
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Singleton that defines utility functions for supporting exif orientation tags.
|
* Singleton that defines utility functions for supporting exif orientation tags.
|
||||||
|
|
|
@ -2,5 +2,4 @@ pragma Singleton
|
||||||
import Meshroom.Helpers 1.0
|
import Meshroom.Helpers 1.0
|
||||||
|
|
||||||
Scene3DHelper {
|
Scene3DHelper {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQml.Models 2.15
|
import QtQml.Models
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SortFilderDelegateModel adds sorting and filtering capabilities on a source model.
|
* SortFilderDelegateModel adds sorting and filtering capabilities on a source model.
|
||||||
|
@ -17,21 +17,21 @@ import QtQuick.Controls 2.15
|
||||||
*
|
*
|
||||||
* Based on http://doc.qt.io/qt-5/qtquick-tutorials-dynamicview-dynamicview4-example.html
|
* Based on http://doc.qt.io/qt-5/qtquick-tutorials-dynamicview-dynamicview4-example.html
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DelegateModel {
|
DelegateModel {
|
||||||
id: sortFilterModel
|
id: sortFilterModel
|
||||||
|
|
||||||
property string sortRole: "" /// the role to use for sorting
|
property string sortRole: "" /// The role to use for sorting
|
||||||
property int sortOrder: Qt.AscendingOrder /// the sorting order
|
property int sortOrder: Qt.AscendingOrder /// The sorting order
|
||||||
property var filters: [] /// filter format: {role: "roleName", value: "filteringValue"}
|
property var filters: [] /// Filter format: {role: "roleName", value: "filteringValue"}
|
||||||
|
|
||||||
onSortRoleChanged: invalidateSort()
|
onSortRoleChanged: invalidateSort()
|
||||||
onSortOrderChanged: invalidateSort()
|
onSortOrderChanged: invalidateSort()
|
||||||
onFiltersChanged: invalidateFilters()
|
onFiltersChanged: invalidateFilters()
|
||||||
|
|
||||||
// display "filtered" group
|
// Display "filtered" group
|
||||||
filterOnGroup: "filtered"
|
filterOnGroup: "filtered"
|
||||||
// don't include elements in "items" group by default
|
// Don't include elements in "items" group by default as they must fall in the "unsorted" group
|
||||||
// as they must fall in the "unsorted" group
|
|
||||||
items.includeByDefault: false
|
items.includeByDefault: false
|
||||||
|
|
||||||
groups: [
|
groups: [
|
||||||
|
@ -41,15 +41,15 @@ DelegateModel {
|
||||||
|
|
||||||
name: "unsorted"
|
name: "unsorted"
|
||||||
includeByDefault: true
|
includeByDefault: true
|
||||||
// if the source model changes, perform sorting and filtering
|
// If the source model changes, perform sorting and filtering
|
||||||
onChanged: {
|
onChanged: {
|
||||||
// no sorting: move everything from unsorted to sorted group
|
// No sorting: move everything from unsorted to sorted group
|
||||||
if(sortRole == "") {
|
if(sortRole == "") {
|
||||||
unsortedItems.setGroups(0, unsortedItems.count, ["items"])
|
unsortedItems.setGroups(0, unsortedItems.count, ["items"])
|
||||||
} else {
|
} else {
|
||||||
sort()
|
sort()
|
||||||
}
|
}
|
||||||
// perform filter invalidation in both cases
|
// Perform filter invalidation in both cases
|
||||||
invalidateFilters()
|
invalidateFilters()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -87,8 +87,7 @@ DelegateModel {
|
||||||
if (filter === undefined) {
|
if (filter === undefined) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
switch (value.constructor.name)
|
switch (value.constructor.name) {
|
||||||
{
|
|
||||||
case "String":
|
case "String":
|
||||||
return value.toLowerCase().indexOf(filter.toLowerCase()) > -1
|
return value.toLowerCase().indexOf(filter.toLowerCase()) > -1
|
||||||
default:
|
default:
|
||||||
|
@ -98,8 +97,8 @@ DelegateModel {
|
||||||
|
|
||||||
/// Apply respectFilter mapping and logical AND/OR reduction on filters
|
/// Apply respectFilter mapping and logical AND/OR reduction on filters
|
||||||
function respectFilters(item) {
|
function respectFilters(item) {
|
||||||
let cond = (filter => respectFilter(modelData(item, filter.role), filter.value));
|
let cond = (filter => respectFilter(modelData(item, filter.role), filter.value))
|
||||||
return filters.every(x => Array.isArray(x) ? x.some(cond) : cond(x));
|
return filters.every(x => Array.isArray(x) ? x.some(cond) : cond(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reverse sort order (toggle between Qt.AscendingOrder / Qt.DescendingOrder)
|
/// Reverse sort order (toggle between Qt.AscendingOrder / Qt.DescendingOrder)
|
||||||
|
@ -108,40 +107,42 @@ DelegateModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
property var lessThan: [
|
property var lessThan: [
|
||||||
function(left, right) { return modelData(left, sortRole) < modelData(right, sortRole) }
|
function(left, right) {
|
||||||
|
return modelData(left, sortRole) < modelData(right, sortRole)
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
function invalidateSort() {
|
function invalidateSort() {
|
||||||
if (!sortFilterModel.model || !sortFilterModel.model.count)
|
if (!sortFilterModel.model || !sortFilterModel.model.count)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// move everything from "items" to "unsorted
|
// Move everything from "items" to "unsorted", will trigger "unsorted" DelegateModelGroup 'changed' signal
|
||||||
// will trigger "unsorted" DelegateModelGroup 'changed' signal
|
|
||||||
items.setGroups(0, items.count, ["unsorted"])
|
items.setGroups(0, items.count, ["unsorted"])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invalidate filtering
|
/// Invalidate filtering
|
||||||
function invalidateFilters() {
|
function invalidateFilters() {
|
||||||
for (var i = 0; i < items.count; ++i) {
|
for (var i = 0; i < items.count; ++i) {
|
||||||
// if the property value contains filterText, add it to the filtered group
|
// If the property value contains filterText, add it to the filtered group
|
||||||
if (respectFilters(items.get(i))) {
|
if (respectFilters(items.get(i))) {
|
||||||
items.addGroups(items.get(i), 1, "filtered")
|
items.addGroups(items.get(i), 1, "filtered")
|
||||||
} else { // otherwise, remove it from the filtered group
|
} else { // Otherwise, remove it from the filtered group
|
||||||
items.removeGroups(items.get(i), 1, "filtered")
|
items.removeGroups(items.get(i), 1, "filtered")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute insert position of 'item' based on the value
|
/// Compute insert position of 'item' based on the value of its sortProperty
|
||||||
/// of its sortProperty
|
|
||||||
function insertPosition(lessThan, item) {
|
function insertPosition(lessThan, item) {
|
||||||
var lower = 0
|
var lower = 0
|
||||||
var upper = items.count
|
var upper = items.count
|
||||||
while (lower < upper) {
|
while (lower < upper) {
|
||||||
var middle = Math.floor(lower + (upper - lower) / 2)
|
var middle = Math.floor(lower + (upper - lower) / 2)
|
||||||
var result = lessThan(item, items.get(middle))
|
var result = lessThan(item, items.get(middle))
|
||||||
if (sortOrder == Qt.DescendingOrder)
|
if (sortOrder == Qt.DescendingOrder) {
|
||||||
result = !result
|
result = !result
|
||||||
|
}
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
upper = middle
|
upper = middle
|
||||||
} else {
|
} else {
|
||||||
|
@ -159,7 +160,7 @@ DelegateModel {
|
||||||
item.groups = ["items"]
|
item.groups = ["items"]
|
||||||
items.move(item.itemsIndex, index)
|
items.move(item.itemsIndex, index)
|
||||||
}
|
}
|
||||||
// if some items were actually sorted, filter will be correctly invalidated
|
// If some items were actually sorted, filter will be correctly invalidated
|
||||||
// as unsortedGroup 'changed' signal will be triggered
|
// as unsortedGroup 'changed' signal will be triggered
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,5 +2,4 @@ pragma Singleton
|
||||||
import Meshroom.Helpers 1.0
|
import Meshroom.Helpers 1.0
|
||||||
|
|
||||||
Transformations3DHelper {
|
Transformations3DHelper {
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
.pragma library
|
.pragma library
|
||||||
|
|
||||||
|
|
||||||
function intToString(v) {
|
function intToString(v) {
|
||||||
// use EN locale to get comma separated thousands
|
// Use EN locale to get comma separated thousands
|
||||||
// + remove automatically added trailing decimals
|
// + remove automatically added trailing decimals
|
||||||
// (this 'toLocaleString' does not take any option)
|
// (this 'toLocaleString' does not take any option)
|
||||||
return v.toLocaleString(Qt.locale('en-US')).split('.')[0]
|
return v.toLocaleString(Qt.locale('en-US')).split('.')[0]
|
||||||
|
@ -10,8 +9,8 @@ function intToString(v) {
|
||||||
|
|
||||||
// Convert a plain text to an html escaped string.
|
// Convert a plain text to an html escaped string.
|
||||||
function plainToHtml(t) {
|
function plainToHtml(t) {
|
||||||
var escaped = t.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>') // escape text
|
var escaped = t.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>') // Escape text
|
||||||
return escaped.replace(/\n/g, '<br>') // replace line breaks
|
return escaped.replace(/\n/g, '<br>') // Replace line breaks
|
||||||
}
|
}
|
||||||
|
|
||||||
function divmod(x, y) {
|
function divmod(x, y) {
|
||||||
|
@ -41,8 +40,7 @@ function sec2timecode(timeSeconds) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function sec2timeStr(timeSeconds) {
|
function sec2timeStr(timeSeconds) {
|
||||||
// Need to decide the rounding precision first
|
// Need to decide the rounding precision first to propagate the right values
|
||||||
// to propagate the right values
|
|
||||||
if (timeSeconds >= 60.0) {
|
if (timeSeconds >= 60.0) {
|
||||||
timeSeconds = Math.round(timeSeconds)
|
timeSeconds = Math.round(timeSeconds)
|
||||||
} else {
|
} else {
|
||||||
|
@ -57,7 +55,7 @@ function sec2timeStr(timeSeconds) {
|
||||||
timeStr += timeObj.minutes + "m"
|
timeStr += timeObj.minutes + "m"
|
||||||
}
|
}
|
||||||
if (timeObj.hours === 0) {
|
if (timeObj.hours === 0) {
|
||||||
// seconds only matter if the elapsed time is less than 1 hour
|
// Seconds only matter if the elapsed time is less than 1 hour
|
||||||
if (timeObj.minutes === 0) {
|
if (timeObj.minutes === 0) {
|
||||||
// If less than a minute, keep millisecond precision
|
// If less than a minute, keep millisecond precision
|
||||||
timeStr += timeObj.seconds.toFixed(2) + "s"
|
timeStr += timeObj.seconds.toFixed(2) + "s"
|
||||||
|
@ -103,4 +101,4 @@ function GB2SizeStr(GB) {
|
||||||
sizeStr += sizeObj.KB + "KB"
|
sizeStr += sizeObj.KB + "KB"
|
||||||
}
|
}
|
||||||
return sizeStr
|
return sizeStr
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import MaterialIcons 2.2
|
|
||||||
import QtPositioning 5.15
|
|
||||||
import QtLocation 5.15
|
|
||||||
import QtCharts 2.15
|
|
||||||
import Charts 1.0
|
|
||||||
|
|
||||||
|
import QtCharts
|
||||||
|
|
||||||
|
import Charts 1.0
|
||||||
import Controls 1.0
|
import Controls 1.0
|
||||||
import Utils 1.0
|
|
||||||
import DataObjects 1.0
|
import DataObjects 1.0
|
||||||
|
|
||||||
FloatingPane {
|
FloatingPane {
|
||||||
|
@ -34,7 +31,7 @@ FloatingPane {
|
||||||
onWheel: {}
|
onWheel: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// note: We need to use csvData.getNbColumns() slot instead of the csvData.nbColumns property to avoid a crash on linux.
|
// Note: We need to use csvData.getNbColumns() slot instead of the csvData.nbColumns property to avoid a crash on linux.
|
||||||
property bool crfReady: csvData && csvData.ready && (csvData.getNbColumns() >= 4)
|
property bool crfReady: csvData && csvData.ready && (csvData.getNbColumns() >= 4)
|
||||||
onCrfReadyChanged: {
|
onCrfReadyChanged: {
|
||||||
if (crfReady) {
|
if (crfReady) {
|
||||||
|
@ -80,24 +77,24 @@ FloatingPane {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We cannot use a Repeater with these Components so we need to instantiate them one by one
|
// We cannot use a Repeater with these Components so we need to instantiate them one by one
|
||||||
// Red curve
|
|
||||||
LineSeries {
|
LineSeries {
|
||||||
|
// Red curve
|
||||||
id: redCurve
|
id: redCurve
|
||||||
axisX: valueAxisX
|
axisX: valueAxisX
|
||||||
axisY: valueAxisY
|
axisY: valueAxisY
|
||||||
name: crfReady ? csvData.getColumn(1).title : ""
|
name: crfReady ? csvData.getColumn(1).title : ""
|
||||||
color: name.toLowerCase()
|
color: name.toLowerCase()
|
||||||
}
|
}
|
||||||
// Green curve
|
|
||||||
LineSeries {
|
LineSeries {
|
||||||
|
// Green curve
|
||||||
id: greenCurve
|
id: greenCurve
|
||||||
axisX: valueAxisX
|
axisX: valueAxisX
|
||||||
axisY: valueAxisY
|
axisY: valueAxisY
|
||||||
name: crfReady ? csvData.getColumn(2).title : ""
|
name: crfReady ? csvData.getColumn(2).title : ""
|
||||||
color: name.toLowerCase()
|
color: name.toLowerCase()
|
||||||
}
|
}
|
||||||
// Blue curve
|
|
||||||
LineSeries {
|
LineSeries {
|
||||||
|
// Blue curve
|
||||||
id: blueCurve
|
id: blueCurve
|
||||||
axisX: valueAxisX
|
axisX: valueAxisX
|
||||||
axisY: valueAxisY
|
axisY: valueAxisY
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
@ -49,7 +49,7 @@ Item {
|
||||||
propagateComposedEvents: true
|
propagateComposedEvents: true
|
||||||
|
|
||||||
property bool controlModifierEnabled: false
|
property bool controlModifierEnabled: false
|
||||||
onPositionChanged: {
|
onPositionChanged: function(mouse) {
|
||||||
mArea.controlModifierEnabled = (mouse.modifiers & Qt.ControlModifier)
|
mArea.controlModifierEnabled = (mouse.modifiers & Qt.ControlModifier)
|
||||||
mouse.accepted = false
|
mouse.accepted = false
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ Item {
|
||||||
onPressed: {
|
onPressed: {
|
||||||
forceActiveFocus()
|
forceActiveFocus()
|
||||||
}
|
}
|
||||||
onWheel: {
|
onWheel: function(wheel) {
|
||||||
mArea.controlModifierEnabled = (wheel.modifiers & Qt.ControlModifier)
|
mArea.controlModifierEnabled = (wheel.modifiers & Qt.ControlModifier)
|
||||||
if (wheel.modifiers & Qt.ControlModifier) {
|
if (wheel.modifiers & Qt.ControlModifier) {
|
||||||
root.incrementRadius(wheel.angleDelta.y / 120.0)
|
root.incrementRadius(wheel.angleDelta.y / 120.0)
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
// required for perspective transform
|
// Required for perspective transform
|
||||||
property real sizeX: 1675.0 // might be overridden in ColorCheckerViewer
|
property real sizeX: 1675.0 // Might be overridden in ColorCheckerViewer
|
||||||
property real sizeY: 1125.0 // might be overridden in ColorCheckerViewer
|
property real sizeY: 1125.0 // Might be overridden in ColorCheckerViewer
|
||||||
|
|
||||||
property var colors: null
|
property var colors: null
|
||||||
property var window: null
|
property var window: null
|
||||||
|
@ -27,10 +27,8 @@ Item {
|
||||||
id: transformation
|
id: transformation
|
||||||
matrix: Qt.matrix4x4()
|
matrix: Qt.matrix4x4()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function applyTransform(m) {
|
function applyTransform(m) {
|
||||||
transformation.matrix = Qt.matrix4x4(
|
transformation.matrix = Qt.matrix4x4(
|
||||||
m[0][0], m[0][1], 0, m[0][2],
|
m[0][0], m[0][1], 0, m[0][2],
|
||||||
|
@ -38,5 +36,4 @@ Item {
|
||||||
0, 0, 1, 0,
|
0, 0, 1, 0,
|
||||||
m[2][0], m[2][1], 0, m[2][2])
|
m[2][0], m[2][1], 0, m[2][2])
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
|
|
||||||
import Controls 1.0
|
import Controls 1.0
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@ FloatingPane {
|
||||||
padding: 4
|
padding: 4
|
||||||
anchors.rightMargin: 0
|
anchors.rightMargin: 0
|
||||||
|
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
@ -34,9 +33,7 @@ FloatingPane {
|
||||||
height: root.height / grid.rows - grid.spacing * (grid.rows + 1) / grid.rows
|
height: root.height / grid.rows - grid.spacing * (grid.rows + 1) / grid.rows
|
||||||
color: Qt.rgba(modelData.r, modelData.g, modelData.b, 1.0)
|
color: Qt.rgba(modelData.r, modelData.g, modelData.b, 1.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
@ -8,9 +8,9 @@ Item {
|
||||||
property var viewpoint: null
|
property var viewpoint: null
|
||||||
property real zoom: 1.0
|
property real zoom: 1.0
|
||||||
|
|
||||||
// required for perspective transform
|
// Required for perspective transform
|
||||||
// Match theoretical values in AliceVision
|
// Match theoretical values in AliceVision
|
||||||
// see https://github.com/alicevision/AliceVision/blob/68ab70bcbc3eb01b73dc8dea78c78d8b4778461c/src/software/utils/main_colorCheckerDetection.cpp#L47
|
// See https://github.com/alicevision/AliceVision/blob/68ab70bcbc3eb01b73dc8dea78c78d8b4778461c/src/software/utils/main_colorCheckerDetection.cpp#L47
|
||||||
readonly property real ccheckerSizeX: 1675.0
|
readonly property real ccheckerSizeX: 1675.0
|
||||||
readonly property real ccheckerSizeY: 1125.0
|
readonly property real ccheckerSizeY: 1125.0
|
||||||
|
|
||||||
|
@ -34,16 +34,13 @@ Item {
|
||||||
|
|
||||||
function readSourceFile() {
|
function readSourceFile() {
|
||||||
var xhr = new XMLHttpRequest
|
var xhr = new XMLHttpRequest
|
||||||
// console.warn("readSourceFile: " + root.source)
|
|
||||||
xhr.open("GET", root.source)
|
xhr.open("GET", root.source)
|
||||||
|
|
||||||
xhr.onreadystatechange = function() {
|
xhr.onreadystatechange = function() {
|
||||||
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status == 200) {
|
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status == 200) {
|
||||||
try {
|
try {
|
||||||
root.json = null
|
root.json = null
|
||||||
// console.warn("readSourceFile: update json from " + root.source)
|
|
||||||
root.json = JSON.parse(xhr.responseText)
|
root.json = JSON.parse(xhr.responseText)
|
||||||
// console.warn("readSourceFile: root.json.checkers.length=" + root.json.checkers.length)
|
|
||||||
} catch(exc) {
|
} catch(exc) {
|
||||||
console.warn("Failed to parse ColorCheckerDetection JSON file: " + source)
|
console.warn("Failed to parse ColorCheckerDetection JSON file: " + source)
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import MaterialIcons 2.2
|
|
||||||
|
|
||||||
import Utils 1.0
|
|
||||||
import Controls 1.0
|
import Controls 1.0
|
||||||
|
import MaterialIcons 2.2
|
||||||
|
import Utils 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FeaturesInfoOverlay is an overlay that displays info and
|
* FeaturesInfoOverlay is an overlay that displays info and
|
||||||
* provides controls over a FeaturesViewer component.
|
* provides controls over a FeaturesViewer component.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
FloatingPane {
|
FloatingPane {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
@ -65,7 +66,10 @@ FloatingPane {
|
||||||
ComboBox {
|
ComboBox {
|
||||||
id: featureDisplayModeCB
|
id: featureDisplayModeCB
|
||||||
flat: true
|
flat: true
|
||||||
ToolTip.text: "Feature Display Mode:\n* Points: Simple points.\n* Square: Scaled filled squares.\n* Oriented Square: Scaled and oriented squares."
|
ToolTip.text: "Feature Display Mode:\n" +
|
||||||
|
"* Points: Simple points.\n" +
|
||||||
|
"* Square: Scaled filled squares.\n" +
|
||||||
|
"* Oriented Square: Scaled and oriented squares."
|
||||||
ToolTip.visible: hovered
|
ToolTip.visible: hovered
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
|
@ -81,7 +85,10 @@ FloatingPane {
|
||||||
ComboBox {
|
ComboBox {
|
||||||
id: trackDisplayModeCB
|
id: trackDisplayModeCB
|
||||||
flat: true
|
flat: true
|
||||||
ToolTip.text: "Track Display Mode:\n* Lines Only: Only track lines.\n* Current Matches: Track lines with current matches / landmarks.\n* All Matches: Track lines with all matches / landmarks."
|
ToolTip.text: "Track Display Mode:\n" +
|
||||||
|
"* Lines Only: Only track lines.\n" +
|
||||||
|
"* Current Matches: Track lines with current matches/landmarks.\n" +
|
||||||
|
"* All Matches: Track lines with all matches / landmarks."
|
||||||
ToolTip.visible: hovered
|
ToolTip.visible: hovered
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
|
@ -152,7 +159,8 @@ FloatingPane {
|
||||||
}
|
}
|
||||||
SpinBox {
|
SpinBox {
|
||||||
id: timeWindowSB
|
id: timeWindowSB
|
||||||
ToolTip.text: "Time Window: The number of frames to consider for tracks display.\ne.g. With time window set at x, tracks will start at current frame - x and they will end at current frame + x."
|
ToolTip.text: "Time Window: The number of frames to consider for tracks display.\n" +
|
||||||
|
"e.g. With time window set at x, tracks will start at current frame - x and they will end at current frame + x."
|
||||||
ToolTip.visible: hovered
|
ToolTip.visible: hovered
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
|
@ -261,7 +269,9 @@ FloatingPane {
|
||||||
colors: root.featuresViewer.colors
|
colors: root.featuresViewer.colors
|
||||||
currentIndex: featureType.viewer.colorIndex
|
currentIndex: featureType.viewer.colorIndex
|
||||||
// offset featuresViewer color set when changing the color of one feature type
|
// offset featuresViewer color set when changing the color of one feature type
|
||||||
onColorPicked: featureType.viewer.colorOffset = colorIndex - index
|
onColorPicked: function(colorIndex) {
|
||||||
|
featureType.viewer.colorOffset = colorIndex - index
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Feature type name
|
// Feature type name
|
||||||
Label {
|
Label {
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import AliceVision 1.0 as AliceVision
|
|
||||||
|
|
||||||
|
import AliceVision 1.0 as AliceVision
|
||||||
import Utils 1.0
|
import Utils 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FeaturesViewer displays the extracted feature points of a View.
|
* FeaturesViewer displays the extracted feature points of a View.
|
||||||
* Requires QtAliceVision plugin.
|
* Requires QtAliceVision plugin.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
@ -60,7 +61,7 @@ Repeater {
|
||||||
|
|
||||||
model: root.describerTypes
|
model: root.describerTypes
|
||||||
|
|
||||||
// instantiate one FeaturesViewer by describer type
|
// Instantiate one FeaturesViewer by describer type
|
||||||
delegate: AliceVision.FeaturesViewer {
|
delegate: AliceVision.FeaturesViewer {
|
||||||
readonly property int colorIndex: (index + colorOffset) % root.colors.length
|
readonly property int colorIndex: (index + colorOffset) % root.colors.length
|
||||||
property int colorOffset: 0
|
property int colorOffset: 0
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import Utils 1.0
|
|
||||||
|
|
||||||
import AliceVision 1.0 as AliceVision
|
import AliceVision 1.0 as AliceVision
|
||||||
|
import Utils 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FloatImage displays an Image with gamma / offset / channel controls
|
* FloatImage displays an Image with gamma / offset / channel controls
|
||||||
|
@ -96,7 +96,6 @@ AliceVision.FloatImageViewer {
|
||||||
if (!isHighlightable) root.surface.mouseOver = false
|
if (!isHighlightable) root.surface.mouseOver = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Principal Point
|
* Principal Point
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import MaterialIcons 2.2
|
|
||||||
import Controls 1.0
|
import Controls 1.0
|
||||||
|
|
||||||
FloatingPane {
|
FloatingPane {
|
||||||
|
@ -30,19 +30,18 @@ FloatingPane {
|
||||||
|
|
||||||
DoubleValidator {
|
DoubleValidator {
|
||||||
id: doubleValidator
|
id: doubleValidator
|
||||||
locale: 'C' // use '.' decimal separator disregarding of the system locale
|
locale: 'C' // Use '.' decimal separator disregarding of the system locale
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: toolLayout
|
id: toolLayout
|
||||||
// anchors.verticalCenter: parent
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
// channel mode
|
// Channel mode
|
||||||
ComboBox {
|
ComboBox {
|
||||||
id: channelsCtrl
|
id: channelsCtrl
|
||||||
|
|
||||||
// set min size to 4 characters + one margin for the combobox
|
// Set min size to 4 characters + one margin for the combobox
|
||||||
Layout.minimumWidth: 5.0 * Qt.application.font.pixelSize
|
Layout.minimumWidth: 5.0 * Qt.application.font.pixelSize
|
||||||
Layout.preferredWidth: Layout.minimumWidth
|
Layout.preferredWidth: Layout.minimumWidth
|
||||||
flat: true
|
flat: true
|
||||||
|
@ -57,7 +56,7 @@ FloatingPane {
|
||||||
model: channels
|
model: channels
|
||||||
}
|
}
|
||||||
|
|
||||||
// gain slider
|
// Gain slider
|
||||||
RowLayout {
|
RowLayout {
|
||||||
spacing: 5
|
spacing: 5
|
||||||
|
|
||||||
|
@ -97,7 +96,7 @@ FloatingPane {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// gamma slider
|
// Gamma slider
|
||||||
RowLayout {
|
RowLayout {
|
||||||
spacing: 5
|
spacing: 5
|
||||||
|
|
||||||
|
@ -242,7 +241,7 @@ FloatingPane {
|
||||||
TextMetrics {
|
TextMetrics {
|
||||||
id: textMetrics_colorValue
|
id: textMetrics_colorValue
|
||||||
font: red.font
|
font: red.font
|
||||||
text: "1.2345" // use one more than expected to get the correct value (probably needed due to TextField margin)
|
text: "1.2345" // Use one more than expected to get the correct value (probably needed due to TextField margin)
|
||||||
}
|
}
|
||||||
TextMetrics {
|
TextMetrics {
|
||||||
id: textMetrics_gainValue
|
id: textMetrics_gainValue
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import MaterialIcons 2.2
|
|
||||||
import QtPositioning 5.15
|
import QtPositioning 6.6
|
||||||
import QtLocation 5.15
|
import QtLocation 6.6
|
||||||
|
|
||||||
import Controls 1.0
|
import Controls 1.0
|
||||||
|
import MaterialIcons 2.2
|
||||||
import Utils 1.0
|
import Utils 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ImageMetadataView displays a JSON model representing an image's metadata as a ListView.
|
* ImageMetadataView displays a JSON model representing an image's metadata as a ListView.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
FloatingPane {
|
FloatingPane {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
@ -31,11 +33,11 @@ FloatingPane {
|
||||||
var values = value.split(",")
|
var values = value.split(",")
|
||||||
var result = 0
|
var result = 0
|
||||||
for (var i = 0; i < values.length; ++i) {
|
for (var i = 0; i < values.length; ++i) {
|
||||||
// divide each component by the corresponding power of 60
|
// Divide each component by the corresponding power of 60
|
||||||
// 1 for degree, 60 for minutes, 3600 for seconds
|
// 1 for degree, 60 for minutes, 3600 for seconds
|
||||||
result += Number(values[i]) / Math.pow(60, i)
|
result += Number(values[i]) / Math.pow(60, i)
|
||||||
}
|
}
|
||||||
// handle opposite reference: South (latitude) or West (longitude)
|
// Handle opposite reference: South (latitude) or West (longitude)
|
||||||
return (ref === "S" || ref === "W") ? -result : result
|
return (ref === "S" || ref === "W") ? -result : result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,14 +64,14 @@ FloatingPane {
|
||||||
id: metadataModel
|
id: metadataModel
|
||||||
property var metadata: ({})
|
property var metadata: ({})
|
||||||
|
|
||||||
// reset model when metadata changes
|
// Reset model when metadata changes
|
||||||
onMetadataChanged: {
|
onMetadataChanged: {
|
||||||
metadataModel.clear()
|
metadataModel.clear()
|
||||||
var entries = []
|
var entries = []
|
||||||
// prepare data to populate the model from the input metadata object
|
// Prepare data to populate the model from the input metadata object
|
||||||
for (var key in metadata) {
|
for (var key in metadata) {
|
||||||
var entry = {}
|
var entry = {}
|
||||||
// split on ":" to get group and key
|
// Split on ":" to get group and key
|
||||||
var i = key.lastIndexOf(":")
|
var i = key.lastIndexOf(":")
|
||||||
if (i === -1) {
|
if (i === -1) {
|
||||||
i = key.lastIndexOf("/")
|
i = key.lastIndexOf("/")
|
||||||
|
@ -79,7 +81,7 @@ FloatingPane {
|
||||||
entry["group"] = key.substr(0, i)
|
entry["group"] = key.substr(0, i)
|
||||||
entry["key"] = key.substr(i+1)
|
entry["key"] = key.substr(i+1)
|
||||||
} else {
|
} else {
|
||||||
// set default group to something convenient for sorting
|
// Set default group to something convenient for sorting
|
||||||
entry["group"] = "-"
|
entry["group"] = "-"
|
||||||
entry["key"] = key
|
entry["key"] = key
|
||||||
}
|
}
|
||||||
|
@ -93,7 +95,7 @@ FloatingPane {
|
||||||
entry["raw"] = entry["group"] + ":" + entry["key"] + "=" + entry["value"]
|
entry["raw"] = entry["group"] + ":" + entry["key"] + "=" + entry["value"]
|
||||||
entries.push(entry)
|
entries.push(entry)
|
||||||
}
|
}
|
||||||
// reset the model with prepared data (limit to one update event)
|
// Reset the model with prepared data (limit to one update event)
|
||||||
metadataModel.append(entries)
|
metadataModel.append(entries)
|
||||||
coordinates = getGPSCoordinates(metadata)
|
coordinates = getGPSCoordinates(metadata)
|
||||||
}
|
}
|
||||||
|
@ -103,7 +105,7 @@ FloatingPane {
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.MiddleButton
|
acceptedButtons: Qt.MiddleButton
|
||||||
onWheel: wheel.accepted = true
|
onWheel: function(wheel) { wheel.accepted = true }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main Layout
|
// Main Layout
|
||||||
|
@ -174,7 +176,7 @@ FloatingPane {
|
||||||
sortRole: "raw"
|
sortRole: "raw"
|
||||||
filters: [{role: "raw", value: searchBar.text}]
|
filters: [{role: "raw", value: searchBar.text}]
|
||||||
delegate: RowLayout {
|
delegate: RowLayout {
|
||||||
width: parent ? parent.width : 0
|
width: ListView.view.width
|
||||||
Label {
|
Label {
|
||||||
text: key
|
text: key
|
||||||
leftPadding: 6
|
leftPadding: 6
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import MaterialIcons 2.2
|
|
||||||
import Controls 1.0
|
import Controls 1.0
|
||||||
|
import MaterialIcons 2.2
|
||||||
import Utils 1.0
|
import Utils 1.0
|
||||||
|
|
||||||
FloatingPane {
|
FloatingPane {
|
||||||
|
@ -30,7 +31,7 @@ FloatingPane {
|
||||||
|
|
||||||
DoubleValidator {
|
DoubleValidator {
|
||||||
id: doubleValidator
|
id: doubleValidator
|
||||||
locale: 'C' // use '.' decimal separator disregarding of the system locale
|
locale: 'C' // Use '.' decimal separator disregarding of the system locale
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
@ -62,7 +63,7 @@ FloatingPane {
|
||||||
padding : 10
|
padding : 10
|
||||||
colors: root.colors
|
colors: root.colors
|
||||||
currentIndex: root.colorIndex
|
currentIndex: root.colorIndex
|
||||||
onColorPicked: root.colorOffset = colorIndex
|
onColorPicked: function(colorIndex) { root.colorOffset = colorIndex }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grid opacity slider
|
// Grid opacity slider
|
||||||
|
@ -147,12 +148,11 @@ FloatingPane {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Fill rectangle to have a better UI
|
// Fill rectangle to have a better UI
|
||||||
Rectangle {
|
Rectangle {
|
||||||
color: root.palette.window
|
color: root.palette.window
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TextMetrics {
|
TextMetrics {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
|
|
||||||
import AliceVision 1.0 as AliceVision
|
import AliceVision 1.0 as AliceVision
|
||||||
|
|
||||||
// Data from the View / Features.
|
// Data from the View / Features.
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
|
|
||||||
import AliceVision 1.0 as AliceVision
|
import AliceVision 1.0 as AliceVision
|
||||||
|
|
||||||
// Data from the SfM
|
// Data from the SfM
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
|
|
||||||
import AliceVision 1.0 as AliceVision
|
import AliceVision 1.0 as AliceVision
|
||||||
|
|
||||||
AliceVision.MTracks {
|
AliceVision.MTracks {
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts 1.11
|
import QtQuick.Layouts
|
||||||
import MaterialIcons 2.2
|
|
||||||
import Controls 1.0
|
import Controls 1.0
|
||||||
|
import MaterialIcons 2.2
|
||||||
import Utils 1.0
|
import Utils 1.0
|
||||||
|
|
||||||
FloatingPane {
|
FloatingPane {
|
||||||
|
@ -31,7 +32,7 @@ FloatingPane {
|
||||||
|
|
||||||
DoubleValidator {
|
DoubleValidator {
|
||||||
id: doubleValidator
|
id: doubleValidator
|
||||||
locale: 'C' // use '.' decimal separator disregarding of the system locale
|
locale: 'C' // Use '.' decimal separator disregarding of the system locale
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
@ -131,7 +132,6 @@ FloatingPane {
|
||||||
Layout.fillWidth: false
|
Layout.fillWidth: false
|
||||||
Layout.maximumWidth: 50
|
Layout.maximumWidth: 50
|
||||||
|
|
||||||
|
|
||||||
validator: DoubleValidator {
|
validator: DoubleValidator {
|
||||||
bottom: Math.min(speedSpinBox.from, speedSpinBox.to)
|
bottom: Math.min(speedSpinBox.from, speedSpinBox.to)
|
||||||
top: Math.max(speedSpinBox.from, speedSpinBox.to)
|
top: Math.max(speedSpinBox.from, speedSpinBox.to)
|
||||||
|
@ -164,7 +164,6 @@ FloatingPane {
|
||||||
Layout.fillWidth: false
|
Layout.fillWidth: false
|
||||||
Layout.maximumWidth: 50
|
Layout.maximumWidth: 50
|
||||||
|
|
||||||
|
|
||||||
validator: DoubleValidator {
|
validator: DoubleValidator {
|
||||||
bottom: Math.min(downscaleSpinBox.from, downscaleSpinBox.to)
|
bottom: Math.min(downscaleSpinBox.from, downscaleSpinBox.to)
|
||||||
top: Math.max(downscaleSpinBox.from, downscaleSpinBox.to)
|
top: Math.max(downscaleSpinBox.from, downscaleSpinBox.to)
|
||||||
|
@ -179,8 +178,8 @@ FloatingPane {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TextMetrics {
|
TextMetrics {
|
||||||
id: textMetrics_subdivisionsValue
|
id: textMetrics_subdivisionsValue
|
||||||
font: subdivisionsLabel.font
|
font: subdivisionsLabel.font
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import Utils 1.0
|
|
||||||
|
|
||||||
import AliceVision 1.0 as AliceVision
|
import AliceVision 1.0 as AliceVision
|
||||||
|
import Utils 1.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PanoramaViwer displays a list of Float Images
|
* PanoramaViwer displays a list of Float Images
|
||||||
|
@ -73,7 +73,7 @@ AliceVision.PanoramaViewer {
|
||||||
property double pitchNode: activeNode ? activeNode.attribute("manualTransform.manualRotation.x").value : 0
|
property double pitchNode: activeNode ? activeNode.attribute("manualTransform.manualRotation.x").value : 0
|
||||||
property double rollNode: activeNode ? activeNode.attribute("manualTransform.manualRotation.z").value : 0
|
property double rollNode: activeNode ? activeNode.attribute("manualTransform.manualRotation.z").value : 0
|
||||||
|
|
||||||
//Convert angle functions
|
// Convert angle functions
|
||||||
function toDegrees(radians) {
|
function toDegrees(radians) {
|
||||||
return radians * (180 / Math.PI)
|
return radians * (180 / Math.PI)
|
||||||
}
|
}
|
||||||
|
@ -82,12 +82,16 @@ AliceVision.PanoramaViewer {
|
||||||
return degrees * (Math.PI / 180)
|
return degrees * (Math.PI / 180)
|
||||||
}
|
}
|
||||||
|
|
||||||
function fmod(a,b) { return Number((a - (Math.floor(a / b) * b)).toPrecision(8)) }
|
function fmod(a,b) {
|
||||||
|
return Number((a - (Math.floor(a / b) * b)).toPrecision(8))
|
||||||
|
}
|
||||||
|
|
||||||
// Limit angle between -180 and 180
|
// Limit angle between -180 and 180
|
||||||
function limitAngle(angle) {
|
function limitAngle(angle) {
|
||||||
if (angle > 180) angle = -180.0 + (angle - 180.0)
|
if (angle > 180)
|
||||||
if (angle < -180) angle = 180.0 - (Math.abs(angle) - 180)
|
angle = -180.0 + (angle - 180.0)
|
||||||
|
if (angle < -180)
|
||||||
|
angle = 180.0 - (Math.abs(angle) - 180)
|
||||||
return angle
|
return angle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +125,7 @@ AliceVision.PanoramaViewer {
|
||||||
if (isEditable)
|
if (isEditable)
|
||||||
isRotating ? Qt.ClosedHandCursor : Qt.OpenHandCursor
|
isRotating ? Qt.ClosedHandCursor : Qt.OpenHandCursor
|
||||||
}
|
}
|
||||||
onPositionChanged: {
|
onPositionChanged: function(mouse) {
|
||||||
// Send Mouse Coordinates to Float Images Viewers
|
// Send Mouse Coordinates to Float Images Viewers
|
||||||
idSelected = -1
|
idSelected = -1
|
||||||
for (var i = 0; i < repeater.model && isHighlightable; ++i) {
|
for (var i = 0; i < repeater.model && isHighlightable; ++i) {
|
||||||
|
@ -171,7 +175,7 @@ AliceVision.PanoramaViewer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onPressed:{
|
onPressed: function(mouse) {
|
||||||
_reconstruction.beginModification("Panorama Manual Rotation")
|
_reconstruction.beginModification("Panorama Manual Rotation")
|
||||||
isRotating = true
|
isRotating = true
|
||||||
lastX = mouse.x
|
lastX = mouse.x
|
||||||
|
@ -185,7 +189,7 @@ AliceVision.PanoramaViewer {
|
||||||
previous_roll = roll
|
previous_roll = roll
|
||||||
}
|
}
|
||||||
|
|
||||||
onReleased: {
|
onReleased: function(mouse) {
|
||||||
_reconstruction.endModification()
|
_reconstruction.endModification()
|
||||||
isRotating = false
|
isRotating = false
|
||||||
lastX = 0
|
lastX = 0
|
||||||
|
@ -273,33 +277,31 @@ AliceVision.PanoramaViewer {
|
||||||
var sourceItem = Filepath.stringToUrl(msfmData.getUrlFromViewId(idViewItem))
|
var sourceItem = Filepath.stringToUrl(msfmData.getUrlFromViewId(idViewItem))
|
||||||
|
|
||||||
setSource("FloatImage.qml", {
|
setSource("FloatImage.qml", {
|
||||||
'surface.viewerType': AliceVision.Surface.EViewerType.PANORAMA,
|
"surface.viewerType": AliceVision.Surface.EViewerType.PANORAMA,
|
||||||
'viewerTypeString': 'panorama',
|
"viewerTypeString": "panorama",
|
||||||
'surface.subdivisions': Qt.binding(function() { return subdivisionsPano }),
|
"surface.subdivisions": Qt.binding(function() { return subdivisionsPano }),
|
||||||
'cropFisheye' : Qt.binding(function(){ return cropFisheyePano }),
|
"cropFisheye" : Qt.binding(function(){ return cropFisheyePano }),
|
||||||
'surface.pitch': Qt.binding(function() { return root.pitch }),
|
"surface.pitch": Qt.binding(function() { return root.pitch }),
|
||||||
'surface.yaw': Qt.binding(function() { return root.yaw }),
|
"surface.yaw": Qt.binding(function() { return root.yaw }),
|
||||||
'surface.roll': Qt.binding(function() { return root.roll }),
|
"surface.roll": Qt.binding(function() { return root.roll }),
|
||||||
'idView': Qt.binding(function() { return idViewItem }),
|
"idView": Qt.binding(function() { return idViewItem }),
|
||||||
'gamma': Qt.binding(function() { return hdrImageToolbar.gammaValue }),
|
"gamma": Qt.binding(function() { return hdrImageToolbar.gammaValue }),
|
||||||
'gain': Qt.binding(function() { return hdrImageToolbar.gainValue }),
|
"gain": Qt.binding(function() { return hdrImageToolbar.gainValue }),
|
||||||
'channelModeString': Qt.binding(function() { return hdrImageToolbar.channelModeValue }),
|
"channelModeString": Qt.binding(function() { return hdrImageToolbar.channelModeValue }),
|
||||||
'downscaleLevel' : Qt.binding(function() { return downscale }),
|
"downscaleLevel": Qt.binding(function() { return downscale }),
|
||||||
'source': Qt.binding(function() { return sourceItem }),
|
"source": Qt.binding(function() { return sourceItem }),
|
||||||
'surface.msfmData': Qt.binding(function() { return root.msfmData }),
|
"surface.msfmData": Qt.binding(function() { return root.msfmData }),
|
||||||
'canBeHovered': true,
|
"canBeHovered": true,
|
||||||
'useSequence': false
|
"useSequence": false
|
||||||
})
|
})
|
||||||
imageLoaded = Qt.binding(function() { return repeater.itemAt(index).item.imageStatus === Image.Ready ? true : false })
|
imageLoaded = Qt.binding(function() { return repeater.itemAt(index).item.imageStatus === Image.Ready ? true : false })
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Repeater {
|
Repeater {
|
||||||
id: repeater
|
id: repeater
|
||||||
model: 0
|
model: 0
|
||||||
delegate: imgPano
|
delegate: imgPano
|
||||||
|
|
||||||
}
|
}
|
||||||
Connections {
|
Connections {
|
||||||
target: root
|
target: root
|
||||||
|
@ -309,7 +311,7 @@ AliceVision.PanoramaViewer {
|
||||||
// Retrieve downscale value from C++
|
// Retrieve downscale value from C++
|
||||||
panoramaViewerToolbar.updateDownscaleValue(root.downscale)
|
panoramaViewerToolbar.updateDownscaleValue(root.downscale)
|
||||||
|
|
||||||
//Changing the repeater model (number of elements)
|
// Changing the repeater model (number of elements)
|
||||||
panoImages.updateRepeater()
|
panoImages.updateRepeater()
|
||||||
|
|
||||||
root.readyToLoad = Image.Ready
|
root.readyToLoad = Image.Ready
|
||||||
|
|
48
meshroom/ui/qml/Viewer/PhongImageViewer.qml
Normal file
48
meshroom/ui/qml/Viewer/PhongImageViewer.qml
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import QtQuick
|
||||||
|
import Utils 1.0
|
||||||
|
|
||||||
|
import AliceVision 1.0 as AliceVision
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PhongImageViewer displays an Image (albedo + normal) with a given light direction.
|
||||||
|
* Shading is done using Blinn-Phong reflection model, material and light direction parameters available.
|
||||||
|
* Accept HdrImageToolbar controls (gamma / offset / channel).
|
||||||
|
*
|
||||||
|
* <!> Requires QtAliceVision plugin.
|
||||||
|
*/
|
||||||
|
|
||||||
|
AliceVision.PhongImageViewer {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
width: sourceSize.width
|
||||||
|
height: sourceSize.height
|
||||||
|
visible: true
|
||||||
|
|
||||||
|
// paintedWidth / paintedHeight / imageStatus for compatibility with standard Image
|
||||||
|
property int paintedWidth: sourceSize.width
|
||||||
|
property int paintedHeight: sourceSize.height
|
||||||
|
property var imageStatus: {
|
||||||
|
if (root.status === AliceVision.PhongImageViewer.EStatus.LOADING) {
|
||||||
|
return Image.Loading
|
||||||
|
} else if (root.status === AliceVision.PhongImageViewer.EStatus.LOADING_ERROR ||
|
||||||
|
root.status === AliceVision.PhongImageViewer.EStatus.MISSING_FILE) {
|
||||||
|
return Image.Error
|
||||||
|
} else if ((root.sourcePath === "") || (root.sourceSize.height <= 0) || (root.sourceSize.width <= 0)) {
|
||||||
|
return Image.Null
|
||||||
|
}
|
||||||
|
|
||||||
|
return Image.Ready
|
||||||
|
}
|
||||||
|
|
||||||
|
property string channelModeString : "rgba"
|
||||||
|
channelMode: {
|
||||||
|
switch (channelModeString) {
|
||||||
|
case "rgb": return AliceVision.PhongImageViewer.EChannelMode.RGB
|
||||||
|
case "r": return AliceVision.PhongImageViewer.EChannelMode.R
|
||||||
|
case "g": return AliceVision.PhongImageViewer.EChannelMode.G
|
||||||
|
case "b": return AliceVision.PhongImageViewer.EChannelMode.B
|
||||||
|
case "a": return AliceVision.PhongImageViewer.EChannelMode.A
|
||||||
|
default: return AliceVision.PhongImageViewer.EChannelMode.RGBA
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue