mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-06-01 18:31:58 +02:00
[qt6][qml] Clean-up code and harmonize comments
This commit is contained in:
parent
b12d1fed06
commit
5a0b1c0c95
85 changed files with 575 additions and 538 deletions
|
@ -5,7 +5,10 @@ import Utils 1.0
|
|||
import MaterialIcons 2.2
|
||||
|
||||
|
||||
/// Meshroom "About" window
|
||||
/**
|
||||
* Meshroom "About" window
|
||||
*/
|
||||
|
||||
Dialog {
|
||||
id: root
|
||||
|
||||
|
@ -24,7 +27,7 @@ Dialog {
|
|||
modal: true
|
||||
closePolicy: Dialog.CloseOnEscape | Dialog.CloseOnPressOutside
|
||||
padding: 30
|
||||
topPadding: 0 // header provides top padding
|
||||
topPadding: 0 // Header provides top padding
|
||||
|
||||
header: Pane {
|
||||
background: Item {}
|
||||
|
@ -175,16 +178,16 @@ Dialog {
|
|||
sourceComponent: ScrollView {
|
||||
|
||||
Component.onCompleted: {
|
||||
// try to load the local file
|
||||
// Try to load the local file
|
||||
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))
|
||||
url = modelData.onlineUrl
|
||||
Request.get(url,
|
||||
function(xhr) {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE)
|
||||
{
|
||||
// status is OK
|
||||
// Status is OK
|
||||
if (xhr.status === 200)
|
||||
textArea.text = MeshroomApp.markdownToHtml(xhr.responseText)
|
||||
else
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
|
||||
/**
|
||||
* A custom CheckBox designed to be used in ChartView's legend.
|
||||
*/
|
||||
|
||||
CheckBox {
|
||||
id: root
|
||||
|
||||
|
|
|
@ -2,12 +2,12 @@ import QtQuick
|
|||
import QtQuick.Controls
|
||||
import QtCharts
|
||||
|
||||
|
||||
/**
|
||||
* ChartViewLegend is an interactive legend component for ChartViews.
|
||||
* It provides a CheckBox for each series that can control its visibility,
|
||||
* and highlight on hovering.
|
||||
*/
|
||||
|
||||
Flow {
|
||||
id: root
|
||||
|
||||
|
@ -49,7 +49,6 @@ Flow {
|
|||
}
|
||||
|
||||
Repeater {
|
||||
|
||||
// ChartView series can't be accessed directly as a model.
|
||||
// Use an intermediate ListModel populated with those series.
|
||||
model: ListModel {
|
||||
|
@ -70,7 +69,7 @@ Flow {
|
|||
root.hoveredSeries = null
|
||||
}
|
||||
|
||||
// hovered serie properties override
|
||||
// Hovered serie properties override
|
||||
states: [
|
||||
State {
|
||||
when: series && root.hoveredSeries === series
|
||||
|
|
|
@ -7,6 +7,7 @@ import Utils 1.0
|
|||
* 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.
|
||||
*/
|
||||
|
||||
ToolButton {
|
||||
id: root
|
||||
|
||||
|
@ -28,10 +29,10 @@ ToolButton {
|
|||
id: palettePopup
|
||||
|
||||
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
|
||||
|
||||
// center the current color
|
||||
// Center the current color
|
||||
y: -(root.height - padding) / 2
|
||||
x: -colorChart.currentItem.x - padding
|
||||
|
||||
|
@ -44,14 +45,14 @@ ToolButton {
|
|||
spacing: 2
|
||||
currentIndex: root.currentIndex
|
||||
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 {
|
||||
padding: 0
|
||||
width: root.width
|
||||
height: root.height
|
||||
background: Rectangle {
|
||||
color: modelData
|
||||
// display border of current/selected item
|
||||
// Display border of current/selected item
|
||||
border.width: hovered || index === colorChart.currentIndex ? 1 : 0
|
||||
border.color: Colors.sysPalette.midlight
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import QtQuick.Layouts
|
|||
* FloatingPane provides a Pane with a slightly transparent default background
|
||||
* using palette.base as color. Useful to create floating toolbar/overlays.
|
||||
*/
|
||||
|
||||
Pane {
|
||||
id: root
|
||||
|
||||
|
@ -14,5 +15,9 @@ Pane {
|
|||
|
||||
padding: 6
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import QtQuick.Layouts
|
|||
/**
|
||||
* A custom GroupBox with predefined header.
|
||||
*/
|
||||
|
||||
GroupBox {
|
||||
id: root
|
||||
|
||||
|
@ -20,13 +21,14 @@ GroupBox {
|
|||
background: Item {}
|
||||
|
||||
label: Pane {
|
||||
padding: 2
|
||||
width: root.width
|
||||
background: Rectangle {
|
||||
id: labelBg
|
||||
color: palette.base
|
||||
opacity: 0.8
|
||||
}
|
||||
padding: 2
|
||||
width: root.width
|
||||
|
||||
RowLayout {
|
||||
width: parent.width
|
||||
Label {
|
||||
|
|
|
@ -5,6 +5,7 @@ import QtQuick.Layouts
|
|||
/**
|
||||
* KeyValue allows to create a list of key/value, like a table.
|
||||
*/
|
||||
|
||||
Rectangle {
|
||||
property alias key: keyLabel.text
|
||||
property alias value: valueText.text
|
||||
|
@ -19,7 +20,6 @@ Rectangle {
|
|||
Rectangle {
|
||||
anchors.margins: 2
|
||||
color: Qt.darker(activePalette.window, 1.1)
|
||||
// Layout.preferredWidth: sizeHandle.x
|
||||
Layout.minimumWidth: 10.0 * Qt.application.font.pixelSize
|
||||
Layout.maximumWidth: 15.0 * Qt.application.font.pixelSize
|
||||
Layout.fillWidth: false
|
||||
|
@ -45,7 +45,10 @@ Rectangle {
|
|||
|
||||
readOnly: 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ Dialog {
|
|||
|
||||
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"
|
||||
|
||||
/// Return the text content of this dialog as a simple string.
|
||||
|
@ -40,7 +40,7 @@ Dialog {
|
|||
rightPadding: leftPadding
|
||||
|
||||
background: Item {
|
||||
// hidden text edit to perform copy in clipboard
|
||||
// Hidden text edit to perform copy in clipboard
|
||||
TextEdit {
|
||||
id: textContent
|
||||
visible: false
|
||||
|
|
|
@ -2,7 +2,6 @@ import QtQuick
|
|||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
|
||||
/**
|
||||
* Panel is a container control with preconfigured header/footer.
|
||||
*
|
||||
|
@ -12,6 +11,7 @@ import QtQuick.Layouts
|
|||
*
|
||||
* The footer is empty (and not visible) by default. It does not provided any layout.
|
||||
*/
|
||||
|
||||
Page {
|
||||
id: root
|
||||
|
||||
|
|
|
@ -4,10 +4,10 @@ import QtQuick.Layouts
|
|||
|
||||
import MaterialIcons 2.2
|
||||
|
||||
|
||||
/**
|
||||
* Basic SearchBar component with an appropriate icon and a TextField.
|
||||
*/
|
||||
|
||||
FocusScope {
|
||||
property alias textField: field
|
||||
property alias text: field.text
|
||||
|
@ -36,7 +36,7 @@ FocusScope {
|
|||
Layout.fillWidth: true
|
||||
selectByMouse: true
|
||||
|
||||
// ensure the field has focus when the text is modified
|
||||
// Ensure the field has focus when the text is modified
|
||||
onTextChanged: {
|
||||
forceActiveFocus()
|
||||
}
|
||||
|
|
|
@ -47,16 +47,16 @@ Page {
|
|||
}
|
||||
|
||||
Rectangle {
|
||||
property bool commonBorder : false
|
||||
property bool commonBorder: false
|
||||
|
||||
property int lBorderwidth : index === mainTabBar.currentIndex ? 2 : 1
|
||||
property int rBorderwidth : index === mainTabBar.currentIndex ? 2 : 1
|
||||
property int tBorderwidth : index === mainTabBar.currentIndex ? 2 : 1
|
||||
property int bBorderwidth : 0
|
||||
property int lBorderwidth: index === mainTabBar.currentIndex ? 2 : 1
|
||||
property int rBorderwidth: index === mainTabBar.currentIndex ? 2 : 1
|
||||
property int tBorderwidth: index === mainTabBar.currentIndex ? 2 : 1
|
||||
property int bBorderwidth: 0
|
||||
|
||||
property int commonBorderWidth : 1
|
||||
property int commonBorderWidth: 1
|
||||
|
||||
z : -1
|
||||
z: -1
|
||||
|
||||
color: Qt.darker(root.palette.window, 1.50)
|
||||
|
||||
|
@ -66,10 +66,10 @@ Page {
|
|||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
|
||||
topMargin : commonBorder ? -commonBorderWidth : -tBorderwidth
|
||||
bottomMargin : commonBorder ? -commonBorderWidth : -bBorderwidth
|
||||
leftMargin : commonBorder ? -commonBorderWidth : -lBorderwidth
|
||||
rightMargin : commonBorder ? -commonBorderWidth : -rBorderwidth
|
||||
topMargin: commonBorder ? -commonBorderWidth : -tBorderwidth
|
||||
bottomMargin: commonBorder ? -commonBorderWidth : -bBorderwidth
|
||||
leftMargin: commonBorder ? -commonBorderWidth : -lBorderwidth
|
||||
rightMargin: commonBorder ? -commonBorderWidth : -rBorderwidth
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import Utils 1.0
|
|||
* Text file viewer with auto-reload feature.
|
||||
* Uses a ListView with one delegate by line instead of a TextArea for performance reasons.
|
||||
*/
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
|
@ -115,7 +116,7 @@ Item {
|
|||
clip: true
|
||||
focus: true
|
||||
|
||||
// custom key navigation handling
|
||||
// Custom key navigation handling
|
||||
keyNavigationEnabled: false
|
||||
highlightFollowsCurrentItem: true
|
||||
highlightMoveDuration: 0
|
||||
|
@ -145,14 +146,14 @@ Item {
|
|||
}
|
||||
|
||||
function setText(value) {
|
||||
// store current first index
|
||||
// Store current first index
|
||||
var topIndex = firstVisibleIndex()
|
||||
// store whether autoscroll to bottom is active
|
||||
// Store whether autoscroll to bottom is active
|
||||
var scrollToBottom = atYEnd && autoscroll.checked
|
||||
// replace text
|
||||
// Replace text
|
||||
text = value
|
||||
|
||||
// restore content position by either:
|
||||
// Restore content position by either:
|
||||
// - autoscrolling to bottom
|
||||
if (scrollToBottom)
|
||||
positionViewAtEnd()
|
||||
|
@ -183,7 +184,7 @@ Item {
|
|||
// TextMetrics for textual progress bar
|
||||
TextMetrics {
|
||||
id: progressMetrics
|
||||
// total number of character in textual progress bar
|
||||
// Total number of character in textual progress bar
|
||||
property int count: 51
|
||||
property string character: '*'
|
||||
text: character.repeat(count)
|
||||
|
@ -230,15 +231,15 @@ Item {
|
|||
Loader {
|
||||
id: delegateLoader
|
||||
Layout.fillWidth: true
|
||||
// default line delegate
|
||||
// Default line delegate
|
||||
sourceComponent: line_component
|
||||
|
||||
// line delegate selector based on content
|
||||
// Line delegate selector based on content
|
||||
StateGroup {
|
||||
states: [
|
||||
State {
|
||||
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
|
||||
&& logLine.line.split(progressMetrics.character).length - 1 === logLine.line.trim().length
|
||||
PropertyChanges {
|
||||
|
@ -281,7 +282,7 @@ Item {
|
|||
Keys.forwardTo: [textView]
|
||||
|
||||
color: {
|
||||
// color line according to log level
|
||||
// Color line according to log level
|
||||
if (text.indexOf("[warning]") >= 0)
|
||||
return Colors.orange
|
||||
else if(text.indexOf("[error]") >= 0)
|
||||
|
@ -350,7 +351,7 @@ Item {
|
|||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
textView.setText(xhr.status === 200 ? xhr.responseText : "")
|
||||
loading = false
|
||||
// re-trigger reload source file
|
||||
// Re-trigger reload source file
|
||||
if (autoReload)
|
||||
reloadTimer.restart()
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import Controls 1.0
|
|||
/**
|
||||
* DialogsFactory is utility object to instantiate generic purpose Dialogs.
|
||||
*/
|
||||
|
||||
QtObject {
|
||||
|
||||
readonly property string defaultErrorText: "An unexpected error has occurred"
|
||||
|
|
|
@ -56,12 +56,10 @@ ListView {
|
|||
}
|
||||
}
|
||||
|
||||
// Helper MouseArea to lose edit/activeFocus
|
||||
// when clicking on the background
|
||||
// Helper MouseArea to lose edit/activeFocus when clicking on the background
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: forceActiveFocus()
|
||||
z: -1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,18 +8,19 @@ import Utils 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 {
|
||||
id: root
|
||||
|
||||
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 string filterText: ""
|
||||
|
||||
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 alias label: parameterLabel // Accessor to the internal Label (attribute's name)
|
||||
property int labelWidth // Shortcut to set the fixed size of the Label
|
||||
|
||||
readonly property bool editable: !attribute.isOutput && !attribute.isLink && !readOnly
|
||||
|
||||
|
@ -91,10 +92,10 @@ RowLayout {
|
|||
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
|
||||
|
||||
// make label italic if attribute is a link
|
||||
// Make label italic if attribute is a link
|
||||
font.italic: object.isLink
|
||||
|
||||
MouseArea {
|
||||
|
@ -295,7 +296,7 @@ RowLayout {
|
|||
anchors.fill: parent
|
||||
acceptedButtons: Qt.RightButton
|
||||
onClicked: function(mouse) {
|
||||
// Do not loose the selection during the right click
|
||||
// Do not lose the selection during the right click
|
||||
textField.persistentSelection = true
|
||||
// We store the status of the activeFocus before opening the popup
|
||||
textField.memoryActiveFocus = textField.activeFocus
|
||||
|
@ -321,7 +322,7 @@ RowLayout {
|
|||
Clipboard.clear()
|
||||
Clipboard.setText(attribute.value)
|
||||
} else {
|
||||
// copy selection only
|
||||
// Copy selection only
|
||||
textField.copy()
|
||||
}
|
||||
}
|
||||
|
@ -331,12 +332,12 @@ RowLayout {
|
|||
enabled: Clipboard.getText() != "" && !readOnly
|
||||
onTriggered: {
|
||||
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
|
||||
var before = textField.text.substr(0, textField.selectionStart)
|
||||
var after = textField.text.substr(textField.selectionEnd, textField.text.length)
|
||||
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
|
||||
} else {
|
||||
setTextFieldAttribute(Clipboard.getText())
|
||||
|
@ -473,7 +474,7 @@ RowLayout {
|
|||
inputModel: attribute.values
|
||||
|
||||
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)
|
||||
if (idx === -1) {
|
||||
displayText = attribute.value
|
||||
|
@ -490,10 +491,10 @@ RowLayout {
|
|||
Connections {
|
||||
target: attribute
|
||||
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
|
||||
|
||||
//convert all values of desc values as string
|
||||
// Convert all values of desc values as string
|
||||
var valuesAsString = attribute.values.map(function(value) {
|
||||
return value.toString()
|
||||
})
|
||||
|
@ -521,9 +522,9 @@ RowLayout {
|
|||
onToggled: {
|
||||
var t = attribute.value
|
||||
if (!checked) {
|
||||
t.splice(t.indexOf(modelData), 1) // remove element
|
||||
t.splice(t.indexOf(modelData), 1) // Remove element
|
||||
} else {
|
||||
t.push(modelData) // add element
|
||||
t.push(modelData) // Add element
|
||||
}
|
||||
_reconstruction.setAttribute(attribute, t)
|
||||
}
|
||||
|
@ -541,12 +542,12 @@ RowLayout {
|
|||
}
|
||||
DoubleValidator {
|
||||
id: doubleValidator
|
||||
locale: 'C' // use '.' decimal separator disregarding the system locale
|
||||
locale: 'C' // Use '.' decimal separator disregarding the system locale
|
||||
}
|
||||
implicitWidth: 100
|
||||
Layout.fillWidth: !slider.active
|
||||
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)
|
||||
text: displayValue
|
||||
selectByMouse: true
|
||||
|
@ -698,7 +699,7 @@ RowLayout {
|
|||
{
|
||||
'model': Qt.binding(function() { return attribute.value }),
|
||||
'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 }),
|
||||
'filterText': Qt.binding(function() { return root.filterText }),
|
||||
})
|
||||
|
@ -714,12 +715,12 @@ RowLayout {
|
|||
TextField {
|
||||
implicitWidth: 100
|
||||
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)
|
||||
text: displayValue
|
||||
selectByMouse: true
|
||||
validator: DoubleValidator {
|
||||
locale: 'C' // use '.' decimal separator disregarding the system locale
|
||||
locale: 'C' // Use '.' decimal separator disregarding the system locale
|
||||
}
|
||||
onEditingFinished: setTextFieldAttribute(text)
|
||||
onAccepted: setTextFieldAttribute(text)
|
||||
|
|
|
@ -5,8 +5,9 @@ import QtQuick.Layouts
|
|||
import Utils 1.0
|
||||
|
||||
/**
|
||||
The representation of an Attribute on a Node.
|
||||
*/
|
||||
* The representation of an Attribute on a Node.
|
||||
*/
|
||||
|
||||
RowLayout {
|
||||
id: root
|
||||
|
||||
|
@ -43,14 +44,12 @@ RowLayout {
|
|||
x: nameLabel.x
|
||||
}
|
||||
|
||||
function updatePin(isSrc, isVisible)
|
||||
{
|
||||
function updatePin(isSrc, isVisible) {
|
||||
if (isSrc) {
|
||||
innerOutputAnchor.linkEnabled = isVisible
|
||||
} else {
|
||||
innerInputAnchor.linkEnabled = isVisible
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Instantiate empty Items for each child attribute
|
||||
|
@ -96,21 +95,21 @@ RowLayout {
|
|||
|
||||
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.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
|
||||
|
||||
keys: [inputDragTarget.objectName]
|
||||
onEntered: function(drag) {
|
||||
// Check if attributes are compatible to create a valid connection
|
||||
if (root.readOnly // cannot connect on a read-only attribute
|
||||
|| drag.source.objectName != inputDragTarget.objectName // not an edge connector
|
||||
|| drag.source.baseType !== inputDragTarget.baseType // not the same base type
|
||||
|| 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.connectorType === "input" // refuse to connect an "input pin" on another one (input attr can be connected to input attr, but not the graphical pin)
|
||||
if (root.readOnly // Cannot connect on a read-only attribute
|
||||
|| drag.source.objectName != inputDragTarget.objectName // Not an edge connector
|
||||
|| drag.source.baseType !== inputDragTarget.baseType // Not the same base type
|
||||
|| 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.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
|
||||
drag.accepted = false
|
||||
|
@ -119,6 +118,7 @@ RowLayout {
|
|||
}
|
||||
inputDropArea.acceptableDrop = drag.accepted
|
||||
}
|
||||
|
||||
onExited: {
|
||||
if (inputDragTarget.attribute.isLink) { // Already connected attribute
|
||||
root.edgeAboutToBeRemoved(undefined)
|
||||
|
@ -161,7 +161,7 @@ RowLayout {
|
|||
drag.smoothed: false
|
||||
enabled: !root.readOnly
|
||||
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.leftMargin: inputDropArea.anchors.leftMargin
|
||||
anchors.rightMargin: inputDropArea.anchors.rightMargin
|
||||
|
@ -186,14 +186,11 @@ RowLayout {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Attribute name
|
||||
Item {
|
||||
id: nameContainer
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: childrenRect.height
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
Label {
|
||||
|
@ -209,13 +206,13 @@ RowLayout {
|
|||
anchors.right: attribute && attribute.isOutput ? parent.right : undefined
|
||||
rightPadding: 0
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Rectangle {
|
||||
id: outputAnchor
|
||||
|
||||
|
@ -258,12 +255,12 @@ RowLayout {
|
|||
keys: [outputDragTarget.objectName]
|
||||
onEntered: function(drag) {
|
||||
// Check if attributes are compatible to create a valid connection
|
||||
if (drag.source.objectName != outputDragTarget.objectName // not an edge connector
|
||||
|| drag.source.baseType !== outputDragTarget.baseType // not the same base type
|
||||
|| 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 && childrenRepeater.count) // source/target are lists but target already has children
|
||||
|| drag.source.connectorType === "output" // refuse to connect an output pin on another one
|
||||
if (drag.source.objectName != outputDragTarget.objectName // Not an edge connector
|
||||
|| drag.source.baseType !== outputDragTarget.baseType // Not the same base type
|
||||
|| 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 && childrenRepeater.count) // Source/target are lists but target already has children
|
||||
|| drag.source.connectorType === "output" // Refuse to connect an output pin on another one
|
||||
) {
|
||||
// Refuse attributes connection
|
||||
drag.accepted = false
|
||||
|
@ -310,7 +307,7 @@ RowLayout {
|
|||
// Move the edge's tip straight to the the current mouse position instead of waiting after the drag operation has started
|
||||
drag.smoothed: false
|
||||
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.leftMargin: outputDropArea.anchors.leftMargin
|
||||
anchors.rightMargin: outputDropArea.anchors.rightMargin
|
||||
|
|
|
@ -7,6 +7,7 @@ import "common.js" as Common
|
|||
/**
|
||||
* ChunkListView
|
||||
*/
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
property variant chunks
|
||||
|
|
|
@ -4,12 +4,13 @@ import QtQuick.Layouts
|
|||
|
||||
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):
|
||||
* - iconDelegate (default): icon + tooltip with information about the issue
|
||||
* - bannerDelegate: banner with issue info + upgrade request button
|
||||
*/
|
||||
*/
|
||||
|
||||
Loader {
|
||||
id: root
|
||||
|
||||
|
|
|
@ -8,17 +8,18 @@ import Utils 1.0
|
|||
|
||||
/**
|
||||
* CompatibilityManager summarizes and allows to resolve compatibility issues.
|
||||
*/
|
||||
*/
|
||||
|
||||
MessageDialog {
|
||||
id: root
|
||||
|
||||
// the UIGraph instance
|
||||
// The UIGraph instance
|
||||
property var uigraph
|
||||
// alias to underlying compatibilityNodes model
|
||||
// Alias to underlying compatibilityNodes model
|
||||
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
|
||||
// the number of CompatibilityNodes that can be upgraded
|
||||
// The number of CompatibilityNodes that can be upgraded
|
||||
readonly property int upgradableCount: {
|
||||
var count = 0
|
||||
for (var i = 0; i < issueCount; ++i) {
|
||||
|
@ -28,7 +29,7 @@ MessageDialog {
|
|||
return count
|
||||
}
|
||||
|
||||
// override MessageDialog.getAsString to add compatibility report
|
||||
// Override MessageDialog.getAsString to add compatibility report
|
||||
function getAsString() {
|
||||
var t = asString + "\n"
|
||||
t += '-------------------------\n'
|
||||
|
|
|
@ -6,8 +6,9 @@ import GraphEditor 1.0
|
|||
import MaterialIcons 2.2
|
||||
|
||||
/**
|
||||
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 {
|
||||
id: root
|
||||
|
||||
|
@ -69,7 +70,6 @@ Item {
|
|||
control2X: x - ctrlPtDist
|
||||
control2Y: y
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ShapePath {
|
||||
|
@ -98,11 +98,13 @@ Item {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
// Place the label at the middle of the edge
|
||||
x: (root.startX + root.endX) / 2
|
||||
y: (root.startY + root.endY) / 2
|
||||
visible: root.isForLoop
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
property int margin: 2
|
||||
|
@ -110,6 +112,7 @@ Item {
|
|||
height: icon.height + 2 * margin
|
||||
radius: width
|
||||
color: path.strokeColor
|
||||
|
||||
MaterialToolLabel {
|
||||
id: icon
|
||||
anchors.centerIn: parent
|
||||
|
@ -120,6 +123,7 @@ Item {
|
|||
color: palette.base
|
||||
ToolTip.text: "Foreach Loop"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: loopArea
|
||||
anchors.fill: parent
|
||||
|
|
|
@ -7,14 +7,15 @@ 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 {
|
||||
id: root
|
||||
|
||||
property variant uigraph: null /// Meshroom ui graph (UIGraph)
|
||||
readonly property variant graph: uigraph ? uigraph.graph : null /// core graph contained in ui graph
|
||||
property variant nodeTypesModel: null /// the list of node types that can be instantiated
|
||||
property variant uigraph: null /// Meshroom UI graph (UIGraph)
|
||||
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 real maxZoom: 2.0
|
||||
property real minZoom: 0.1
|
||||
|
||||
|
@ -22,7 +23,7 @@ Item {
|
|||
|
||||
property var _attributeToDelegate: ({})
|
||||
|
||||
// signals
|
||||
// Signals
|
||||
signal workspaceMoved()
|
||||
signal workspaceClicked()
|
||||
|
||||
|
@ -34,10 +35,9 @@ Item {
|
|||
|
||||
property int nbMeshroomScenes: 0
|
||||
property int nbDraggedFiles: 0
|
||||
// Files have been dropped
|
||||
signal filesDropped(var drop, var mousePosition)
|
||||
signal filesDropped(var drop, var mousePosition) // Files have been dropped
|
||||
|
||||
// trigger initial fit() after initialization
|
||||
// Trigger initial fit() after initialization
|
||||
// (ensure GraphEditor has its final size)
|
||||
Component.onCompleted: firstFitTimer.start()
|
||||
|
||||
|
@ -215,7 +215,7 @@ Item {
|
|||
|
||||
onClicked: function(mouse) {
|
||||
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.popup()
|
||||
}
|
||||
|
@ -274,7 +274,7 @@ Item {
|
|||
onVisibleChanged: {
|
||||
searchBar.clear()
|
||||
if (visible) {
|
||||
// when menu is shown, give focus to the TextField filter
|
||||
// When menu is shown, give focus to the TextField filter
|
||||
searchBar.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
@ -298,12 +298,12 @@ Item {
|
|||
// Forward key events to the search bar to continue typing seamlessly
|
||||
// even if this delegate took the activeFocus due to mouse hovering
|
||||
Keys.forwardTo: [searchBar.textField]
|
||||
Keys.onPressed: {
|
||||
Keys.onPressed: function(event) {
|
||||
event.accepted = false;
|
||||
switch (event.key) {
|
||||
case Qt.Key_Return:
|
||||
case Qt.Key_Enter:
|
||||
// create node on validation (Enter/Return keys)
|
||||
// Create node on validation (Enter/Return keys)
|
||||
newNodeMenu.createNode(modelData)
|
||||
event.accepted = true
|
||||
break
|
||||
|
@ -311,7 +311,7 @@ Item {
|
|||
case Qt.Key_Down:
|
||||
case Qt.Key_Left:
|
||||
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:
|
||||
searchBar.forceActiveFocus()
|
||||
}
|
||||
|
@ -326,8 +326,8 @@ Item {
|
|||
name: "invisible"
|
||||
PropertyChanges {
|
||||
target: menuItemDelegate
|
||||
height: 0 // make sure the item is no visible by setting height to 0
|
||||
focusPolicy: Qt.NoFocus // don't grab focus when not visible
|
||||
height: 0 // Make sure the item is no visible by setting height to 0
|
||||
focusPolicy: Qt.NoFocus // Don't grab focus when not visible
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -429,7 +429,7 @@ Item {
|
|||
const newSrcAttr = listAttr.value.at(value - 1)
|
||||
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) {
|
||||
return
|
||||
}
|
||||
|
@ -488,7 +488,7 @@ Item {
|
|||
Repeater {
|
||||
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
|
||||
|
||||
delegate: Edge {
|
||||
|
@ -512,7 +512,6 @@ Item {
|
|||
}
|
||||
return (inFocus) ? 2 : 1
|
||||
}
|
||||
|
||||
point1x: isValidEdge ? src.globalX + src.outputAnchorPos.x : 0
|
||||
point1y: isValidEdge ? src.globalY + src.outputAnchorPos.y : 0
|
||||
point2x: isValidEdge ? dst.globalX + dst.inputAnchorPos.x : 0
|
||||
|
@ -552,7 +551,7 @@ Item {
|
|||
id: nodeMenu
|
||||
property var currentNode: null
|
||||
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 bool isComputed: {
|
||||
var count = 0
|
||||
|
@ -601,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: {
|
||||
|
@ -875,11 +874,9 @@ Item {
|
|||
|
||||
onEdgeAboutToBeRemoved: function(input) {
|
||||
/*
|
||||
Sometimes the signals are not in the right order
|
||||
because of weird Qt/QML update order (next DropArea
|
||||
entered signal before previous DropArea exited signal)
|
||||
so edgeAboutToBeRemoved must be set to undefined before
|
||||
it can be set to another attribute object.
|
||||
* Sometimes the signals are not in the right order because of weird Qt/QML update order
|
||||
* (next DropArea entered signal before previous DropArea exited signal) so edgeAboutToBeRemoved
|
||||
* must be set to undefined before it can be set to another attribute object.
|
||||
*/
|
||||
if (input === undefined) {
|
||||
if (nodeRepeater.temporaryEdgeAboutToBeRemoved === undefined) {
|
||||
|
@ -899,7 +896,7 @@ Item {
|
|||
|
||||
onPositionChanged: {
|
||||
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++) {
|
||||
var otherNode = nodeRepeater.itemAt(i)
|
||||
if (uigraph.selectedNodes.contains(otherNode.node) && otherNode.node !== node) {
|
||||
|
@ -910,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
|
||||
|
||||
// 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 {
|
||||
enabled: !nodeRepeater.dragging
|
||||
NumberAnimation { duration: 100 }
|
||||
|
@ -1122,12 +1119,12 @@ Item {
|
|||
}
|
||||
|
||||
function nextItem() {
|
||||
// compute bounding box
|
||||
// Compute bounding box
|
||||
var node = nodeRepeater.itemAt(filteredNodes.itemAt(navigation.currentIndex).index_)
|
||||
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)
|
||||
// recenter
|
||||
// Recenter
|
||||
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
|
||||
}
|
||||
|
@ -1136,6 +1133,7 @@ Item {
|
|||
function registerAttributePin(attribute, pin) {
|
||||
root._attributeToDelegate[attribute] = pin
|
||||
}
|
||||
|
||||
function unregisterAttributePin(attribute, pin) {
|
||||
delete root._attributeToDelegate[attribute]
|
||||
}
|
||||
|
@ -1160,11 +1158,11 @@ Item {
|
|||
|
||||
// Fit graph to fill root
|
||||
function fit() {
|
||||
// compute bounding box
|
||||
// Compute bounding box
|
||||
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)
|
||||
// recenter
|
||||
// Recenter
|
||||
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
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
pragma Singleton
|
||||
import QtCore
|
||||
|
||||
|
||||
/**
|
||||
* Persistent Settings related to the GraphEditor module.
|
||||
*/
|
||||
|
||||
Settings {
|
||||
category: 'GraphEditor'
|
||||
property bool showAdvancedAttributes: false
|
||||
|
|
|
@ -6,10 +6,10 @@ import Qt5Compat.GraphicalEffects
|
|||
import MaterialIcons 2.2
|
||||
import Utils 1.0
|
||||
|
||||
|
||||
/**
|
||||
* Visual representation of a Graph Node.
|
||||
*/
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@ import QtQuick
|
|||
|
||||
import Utils 1.0
|
||||
|
||||
//import "common.js" as Common
|
||||
|
||||
ListView {
|
||||
id: root
|
||||
interactive: false
|
||||
|
@ -15,7 +13,7 @@ ListView {
|
|||
property real chunkHeight: height
|
||||
property bool modelIsBig: (3 * model.count >= width)
|
||||
property real chunkWidth: {
|
||||
if(!model || model.count == 0)
|
||||
if (!model || model.count == 0)
|
||||
return 0
|
||||
return (width / model.count) - spacing
|
||||
}
|
||||
|
@ -30,13 +28,12 @@ ListView {
|
|||
width: root.chunkWidth
|
||||
property var chunkColor: Colors.getChunkColor(object, { "NONE": root.defaultColor })
|
||||
color: {
|
||||
if(!highlightChunks || model.count == 1)
|
||||
if (!highlightChunks || model.count == 1)
|
||||
return chunkColor
|
||||
if(index % 2 == 0)
|
||||
if (index % 2 == 0)
|
||||
return Qt.lighter(chunkColor, 1.1)
|
||||
else
|
||||
return Qt.darker(chunkColor, 1.1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import "common.js" as Common
|
|||
/**
|
||||
* Displays Node documentation
|
||||
*/
|
||||
|
||||
FocusScope {
|
||||
id: root
|
||||
|
||||
|
|
|
@ -6,11 +6,11 @@ import Controls 1.0
|
|||
import MaterialIcons 2.2
|
||||
import Utils 1.0
|
||||
|
||||
|
||||
/**
|
||||
* NodeEditor allows to visualize and edit the parameters of a Node.
|
||||
* It mainly provides an attribute editor and a log inspector.
|
||||
*/
|
||||
|
||||
Panel {
|
||||
id: root
|
||||
|
||||
|
@ -36,7 +36,7 @@ Panel {
|
|||
if (node !== null && (node.isFinishedOrRunning() || globalStatus == "ERROR")) {
|
||||
computationInfo.text = Format.sec2timeStr(node.elapsedTime)
|
||||
}
|
||||
else{
|
||||
else {
|
||||
computationInfo.text = ""
|
||||
}
|
||||
}
|
||||
|
@ -118,6 +118,7 @@ Panel {
|
|||
Menu {
|
||||
id: settingsMenu
|
||||
y: parent.height
|
||||
|
||||
Menu {
|
||||
id: filterAttributesMenu
|
||||
title: "Filter Attributes"
|
||||
|
@ -139,7 +140,9 @@ Panel {
|
|||
enabled: tabBar.currentIndex === 0
|
||||
}
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
RowLayout {
|
||||
CheckBox {
|
||||
id: defaultToggle
|
||||
|
@ -158,7 +161,9 @@ Panel {
|
|||
enabled: tabBar.currentIndex === 0
|
||||
}
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
RowLayout {
|
||||
CheckBox {
|
||||
id: linkToggle
|
||||
|
@ -177,7 +182,9 @@ Panel {
|
|||
enabled: tabBar.currentIndex === 0
|
||||
}
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
CheckBox {
|
||||
id: advancedToggle
|
||||
text: "Advanced"
|
||||
|
@ -197,7 +204,9 @@ Panel {
|
|||
enabled: root.node !== null
|
||||
onClicked: Qt.openUrlExternally(Filepath.stringToUrl(root.node.internalFolder))
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
MenuItem {
|
||||
enabled: root.node !== null
|
||||
text: "Clear Pending Status"
|
||||
|
@ -209,6 +218,7 @@ Panel {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
|
@ -216,7 +226,7 @@ Panel {
|
|||
Loader {
|
||||
active: root.isCompatibilityNode
|
||||
Layout.fillWidth: true
|
||||
visible: active // for layout update
|
||||
visible: active // For layout update
|
||||
|
||||
sourceComponent: CompatibilityBadge {
|
||||
canUpgrade: root.node.canUpgrade
|
||||
|
|
|
@ -5,11 +5,12 @@ import QtQuick.Layouts
|
|||
import Controls 1.0
|
||||
|
||||
/**
|
||||
* 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
|
||||
* if the related NodeChunk is being computed.
|
||||
*/
|
||||
|
||||
FocusScope {
|
||||
id: root
|
||||
property variant node
|
||||
|
@ -40,7 +41,6 @@ FocusScope {
|
|||
anchors.fill: parent
|
||||
source: componentLoader.sourceFile
|
||||
autoReload: root.currentChunk !== undefined && root.currentChunk.statusName === "RUNNING"
|
||||
// source is set in fileSelector
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,12 @@ import QtQuick.Layouts
|
|||
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
|
||||
* if the related NodeChunk is being computed.
|
||||
*/
|
||||
|
||||
FocusScope {
|
||||
id: root
|
||||
|
||||
|
|
|
@ -3,11 +3,12 @@ import QtQuick.Controls
|
|||
import QtQuick.Layouts
|
||||
|
||||
/**
|
||||
* 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
|
||||
* if the related NodeChunk is being computed.
|
||||
*/
|
||||
|
||||
FocusScope {
|
||||
id: root
|
||||
property variant node
|
||||
|
@ -42,7 +43,7 @@ FocusScope {
|
|||
id: statusListModel
|
||||
|
||||
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"))
|
||||
return
|
||||
|
||||
|
@ -51,31 +52,28 @@ FocusScope {
|
|||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
|
||||
// console.warn("StatusListModel: read valid file")
|
||||
if (lastModified === undefined || lastModified !== xhr.getResponseHeader('Last-Modified')) {
|
||||
lastModified = xhr.getResponseHeader('Last-Modified')
|
||||
try {
|
||||
var jsonObject = JSON.parse(xhr.responseText)
|
||||
|
||||
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) {
|
||||
var entry = {}
|
||||
entry["key"] = key
|
||||
entry["value"] = String(jsonObject[key])
|
||||
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.append(entries)
|
||||
} catch(exc) {
|
||||
// console.warn("StatusListModel: failed to read file")
|
||||
lastModified = undefined
|
||||
statusListModel.clear()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// console.warn("StatusListModel: invalid file")
|
||||
lastModified = undefined
|
||||
statusListModel.clear()
|
||||
}
|
||||
|
@ -99,7 +97,6 @@ FocusScope {
|
|||
Rectangle {
|
||||
id: statusKey
|
||||
anchors.margins: 2
|
||||
// height: statusValue.height
|
||||
color: Qt.darker(activePalette.window, 1.1)
|
||||
Layout.preferredWidth: sizeHandle.x
|
||||
Layout.minimumWidth: 10.0 * Qt.application.font.pixelSize
|
||||
|
|
|
@ -37,7 +37,6 @@ Item {
|
|||
|
||||
property color textColor: Colors.sysPalette.text
|
||||
|
||||
|
||||
readonly property var colors: [
|
||||
"#f44336",
|
||||
"#e91e63",
|
||||
|
@ -94,7 +93,7 @@ Item {
|
|||
}
|
||||
|
||||
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"))
|
||||
return
|
||||
|
||||
|
@ -103,7 +102,7 @@ Item {
|
|||
|
||||
xhr.onreadystatechange = function() {
|
||||
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 {
|
||||
root.jsonObject = JSON.parse(xhr.responseText)
|
||||
} catch(exc) {
|
||||
|
@ -112,7 +111,7 @@ Item {
|
|||
return
|
||||
}
|
||||
resetCharts()
|
||||
sourceModified = xhr.getResponseHeader('Last-Modified')
|
||||
sourceModified = xhr.getResponseHeader("Last-Modified")
|
||||
root.createCharts()
|
||||
reloadTimer.restart()
|
||||
}
|
||||
|
@ -130,8 +129,8 @@ Item {
|
|||
}
|
||||
|
||||
function createCharts() {
|
||||
root.deltaTime = getPropertyWithDefault(jsonObject, 'interval', 30) / 60.0;
|
||||
root.fileVersion = getPropertyWithDefault(jsonObject, 'fileVersion', 0.0)
|
||||
root.deltaTime = getPropertyWithDefault(jsonObject, "interval", 30) / 60.0;
|
||||
root.fileVersion = getPropertyWithDefault(jsonObject, "fileVersion", 0.0)
|
||||
initCpuChart()
|
||||
initRamChart()
|
||||
initGpuChart()
|
||||
|
@ -158,7 +157,7 @@ Item {
|
|||
var nbCores = categories.length
|
||||
root.nbCores = nbCores
|
||||
|
||||
root.cpuFrequency = getPropertyWithDefault(jsonObject.computer, 'cpuFreq', -1)
|
||||
root.cpuFrequency = getPropertyWithDefault(jsonObject.computer, "cpuFreq", -1)
|
||||
|
||||
root.nbReads = categories[0].length-1
|
||||
|
||||
|
@ -219,9 +218,9 @@ Item {
|
|||
|
||||
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: "
|
||||
if (root.ramTotal <= 0) {
|
||||
var maxRamPeak = 0
|
||||
|
@ -249,17 +248,18 @@ Item {
|
|||
ramSerie.color = colors[10]
|
||||
}
|
||||
|
||||
|
||||
/**************************
|
||||
*** GPU ***
|
||||
**************************/
|
||||
|
||||
function initGpuChart() {
|
||||
root.gpuTotalMemory = getPropertyWithDefault(jsonObject.computer, 'gpuMemoryTotal', 0)
|
||||
root.gpuName = getPropertyWithDefault(jsonObject.computer, 'gpuName', '')
|
||||
root.gpuTotalMemory = getPropertyWithDefault(jsonObject.computer, "gpuMemoryTotal", 0)
|
||||
root.gpuName = getPropertyWithDefault(jsonObject.computer, "gpuName", "")
|
||||
|
||||
var gpuUsedMemory = getPropertyWithDefault(jsonObject.computer.curves, 'gpuMemoryUsed', 0)
|
||||
var gpuUsed = getPropertyWithDefault(jsonObject.computer.curves, 'gpuUsed', 0)
|
||||
var gpuTemperature = getPropertyWithDefault(jsonObject.computer.curves, 'gpuTemperature', 0)
|
||||
var gpuUsedMemory = getPropertyWithDefault(jsonObject.computer.curves, "gpuMemoryUsed", 0)
|
||||
var gpuUsed = getPropertyWithDefault(jsonObject.computer.curves, "gpuUsed", 0)
|
||||
var gpuTemperature = getPropertyWithDefault(jsonObject.computer.curves, "gpuTemperature", 0)
|
||||
|
||||
var gpuUsedSerie = gpuChart.createSeries(ChartView.SeriesTypeLine, "GPU", valueGpuX, valueGpuY)
|
||||
var gpuUsedMemorySerie = gpuChart.createSeries(ChartView.SeriesTypeLine, "Memory", valueGpuX, valueGpuY)
|
||||
|
@ -390,7 +390,7 @@ Item {
|
|||
plotAreaColor: "transparent"
|
||||
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"
|
||||
|
||||
ValueAxis {
|
||||
|
@ -422,7 +422,6 @@ Item {
|
|||
}
|
||||
|
||||
|
||||
|
||||
/**************************
|
||||
*** RAM UI ***
|
||||
**************************/
|
||||
|
@ -444,7 +443,7 @@ Item {
|
|||
plotAreaColor: "transparent"
|
||||
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"
|
||||
|
||||
ValueAxis {
|
||||
|
@ -476,7 +475,6 @@ Item {
|
|||
}
|
||||
|
||||
|
||||
|
||||
/**************************
|
||||
*** GPU UI ***
|
||||
**************************/
|
||||
|
|
|
@ -261,7 +261,6 @@ Item {
|
|||
radius: 3
|
||||
border.width: 2
|
||||
border.color: chunkList.node === uigraph.selectedNode ? Colors.sysPalette.text : Colors.getChunkColor(object, {"NONE": bgColor})
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
var statusColors = {
|
||||
"NONE": "transparent",
|
||||
"SUBMITTED": "#009688",
|
||||
|
|
|
@ -3,14 +3,17 @@ import QtQuick
|
|||
import MaterialIcons 2.2
|
||||
import Utils 1.0
|
||||
|
||||
|
||||
/**
|
||||
* ImageBadge is a preset MaterialLabel to display an icon bagdge on an image.
|
||||
*/
|
||||
|
||||
MaterialLabel {
|
||||
id: root
|
||||
|
||||
font.pointSize: 10
|
||||
padding: 2
|
||||
background: Rectangle { color: Colors.sysPalette.window; opacity: 0.6 }
|
||||
background: Rectangle {
|
||||
color: Colors.sysPalette.window
|
||||
opacity: 0.6
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,10 +4,10 @@ import QtQuick.Layouts
|
|||
|
||||
import Utils 1.0
|
||||
|
||||
|
||||
/**
|
||||
* ImageDelegate for a Viewpoint object.
|
||||
*/
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
|
@ -25,7 +25,7 @@ Item {
|
|||
|
||||
default property alias children: imageMA.children
|
||||
|
||||
// retrieve viewpoints inner data
|
||||
// Retrieve viewpoints inner data
|
||||
QtObject {
|
||||
id: _viewpoint
|
||||
property url source: viewpoint ? Filepath.stringToUrl(viewpoint.get("path").value) : ''
|
||||
|
@ -34,8 +34,8 @@ Item {
|
|||
property var metadata: metadataStr ? JSON.parse(viewpoint.get("metadata").value) : {}
|
||||
}
|
||||
|
||||
// update thumbnail location
|
||||
// can be called from the GridView when a new thumbnail has been written on disk
|
||||
// Update thumbnail location
|
||||
// Can be called from the GridView when a new thumbnail has been written on disk
|
||||
function updateThumbnail() {
|
||||
thumbnail.source = ThumbnailCache.thumbnail(root.source, root.cellID)
|
||||
}
|
||||
|
@ -136,6 +136,7 @@ Item {
|
|||
running: thumbnail.status != Image.Ready
|
||||
}
|
||||
}
|
||||
|
||||
// Image basename
|
||||
Label {
|
||||
id: imageLabel
|
||||
|
|
|
@ -12,6 +12,7 @@ import Utils 1.0
|
|||
* ImageGallery displays as a grid of Images a model containing Viewpoints objects.
|
||||
* It manages a model of multiple CameraInit nodes as individual groups.
|
||||
*/
|
||||
|
||||
Panel {
|
||||
id: root
|
||||
|
||||
|
@ -28,7 +29,7 @@ Panel {
|
|||
property int defaultCellSize: 160
|
||||
property bool readOnly: false
|
||||
|
||||
property var filesByType: {}
|
||||
property var filesByType: ({})
|
||||
property int nbMeshroomScenes: 0
|
||||
property int nbDraggedFiles: 0
|
||||
|
||||
|
@ -98,7 +99,7 @@ Panel {
|
|||
intrinsic[currentAttribute.name + "." + currentAttribute.value.at(k).name] = currentAttribute.value.at(k)
|
||||
}
|
||||
} else if (currentAttribute.type === "ListAttribute") {
|
||||
// not needed for now
|
||||
// Not needed for now
|
||||
} else {
|
||||
intrinsic[currentAttribute.name] = currentAttribute
|
||||
}
|
||||
|
@ -217,12 +218,12 @@ Panel {
|
|||
Connections {
|
||||
target: ThumbnailCache
|
||||
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) {
|
||||
item.updateThumbnail()
|
||||
return
|
||||
}
|
||||
// fallback in case the ImageDelegate cellID changed
|
||||
// Fallback in case the ImageDelegate cellID changed
|
||||
for (let idx = 0; idx < grid.count; idx++) {
|
||||
item = grid.itemAtIndex(idx)
|
||||
if (item && item.source === imgSource) {
|
||||
|
@ -250,7 +251,7 @@ Panel {
|
|||
]
|
||||
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_) {
|
||||
var roleNameAndCmd = roleName_.split(".")
|
||||
var roleName = roleName_
|
||||
|
@ -831,8 +832,7 @@ Panel {
|
|||
}
|
||||
}
|
||||
onEnabledChanged: {
|
||||
// Reset the toggle to avoid getting stuck
|
||||
// with the HDR node checked but disabled.
|
||||
// Reset the toggle to avoid getting stuck with the HDR node checked but disabled
|
||||
if (checked) {
|
||||
checked = false
|
||||
close()
|
||||
|
@ -875,8 +875,7 @@ Panel {
|
|||
}
|
||||
}
|
||||
onEnabledChanged: {
|
||||
// Reset the toggle to avoid getting stuck
|
||||
// with the HDR node checked but disabled.
|
||||
// Reset the toggle to avoid getting stuck with the HDR node checked but disabled
|
||||
if (checked) {
|
||||
checked = false
|
||||
close()
|
||||
|
|
|
@ -190,7 +190,7 @@ RowLayout {
|
|||
|
||||
DoubleValidator {
|
||||
id: doubleValidator
|
||||
locale: 'C' // use '.' decimal separator disregarding the system locale
|
||||
locale: 'C' // Use '.' decimal separator disregarding the system locale
|
||||
}
|
||||
|
||||
validator: doubleValidator
|
||||
|
|
|
@ -4,11 +4,11 @@ import QtQuick.Controls
|
|||
import MaterialIcons 2.2
|
||||
import Utils 1.0
|
||||
|
||||
|
||||
/**
|
||||
* Display camera initialization status and the value of metadata
|
||||
* that take part in this process.
|
||||
*/
|
||||
|
||||
ImageBadge {
|
||||
id: root
|
||||
|
||||
|
@ -28,7 +28,8 @@ ImageBadge {
|
|||
}
|
||||
return ""
|
||||
}
|
||||
// access useful metadata
|
||||
|
||||
// Access useful metadata
|
||||
readonly property var make: findMetadata("Make")
|
||||
readonly property var model: findMetadata("Model")
|
||||
readonly property var focalLength: findMetadata("FocalLength")
|
||||
|
@ -104,13 +105,12 @@ ImageBadge {
|
|||
}
|
||||
},
|
||||
State {
|
||||
// fallback status when initialization mode is unset
|
||||
// Fallback status when initialization mode is unset
|
||||
name: "none"
|
||||
PropertyChanges {
|
||||
target: root
|
||||
visible: false
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import QtQuick.Layouts
|
|||
import MaterialIcons 2.2
|
||||
import Controls 1.0
|
||||
|
||||
|
||||
MessageDialog {
|
||||
id: root
|
||||
|
||||
|
|
|
@ -3,13 +3,14 @@ import QtQuick.Controls
|
|||
import QtQuick.Layouts
|
||||
|
||||
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
|
||||
|
||||
/**
|
||||
* LiveSfMView provides controls for setting up and starting a live reconstruction.
|
||||
*/
|
||||
|
||||
Panel {
|
||||
id: root
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
|
||||
/**
|
||||
* MLabel is a standard Label.
|
||||
* If ToolTip.text is set, it shows up a tooltip when hovered.
|
||||
*/
|
||||
|
||||
Label {
|
||||
padding: 4
|
||||
MouseArea {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
|
||||
/**
|
||||
* MaterialLabel is a standard Label using MaterialIcons font.
|
||||
* If ToolTip.text is set, it also shows up a tooltip when hovered.
|
||||
*/
|
||||
|
||||
Label {
|
||||
font.family: MaterialIcons.fontFamily
|
||||
font.pointSize: 10
|
||||
|
|
|
@ -2,11 +2,11 @@ import QtQuick
|
|||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
|
||||
/**
|
||||
* MaterialToolButton is a standard ToolButton using MaterialIcons font.
|
||||
* It also shows up its tooltip when hovered.
|
||||
*/
|
||||
|
||||
ToolButton {
|
||||
id: control
|
||||
font.family: MaterialIcons.fontFamily
|
||||
|
|
|
@ -2,11 +2,11 @@ import QtQuick
|
|||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
|
||||
/**
|
||||
* MaterialToolLabel is a Label with an icon (using MaterialIcons).
|
||||
* It shows up its tooltip when hovered.
|
||||
*/
|
||||
|
||||
Item {
|
||||
id: control
|
||||
property alias iconText: iconItem.text
|
||||
|
|
|
@ -2,11 +2,11 @@ import QtQuick
|
|||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
|
||||
/**
|
||||
* MaterialToolButton is a standard ToolButton using MaterialIcons font.
|
||||
* It also shows up its tooltip when hovered.
|
||||
*/
|
||||
|
||||
ToolButton {
|
||||
id: control
|
||||
property alias iconText: icon.text
|
||||
|
|
|
@ -4,6 +4,7 @@ import Meshroom.Helpers 1.0
|
|||
/**
|
||||
* Clipboard singleton object to copy values to paste buffer.
|
||||
*/
|
||||
|
||||
ClipboardHelper {
|
||||
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import QtQuick.Controls
|
|||
/**
|
||||
* Singleton that gathers useful colors, shades and system palettes.
|
||||
*/
|
||||
|
||||
QtObject {
|
||||
property SystemPalette sysPalette: SystemPalette {}
|
||||
property SystemPalette disabledSysPalette: SystemPalette { colorGroup: SystemPalette.Disabled }
|
||||
|
|
|
@ -2,5 +2,4 @@ pragma Singleton
|
|||
import Meshroom.Helpers 1.0
|
||||
|
||||
Scene3DHelper {
|
||||
|
||||
}
|
||||
|
|
|
@ -17,21 +17,21 @@ import QtQuick.Controls
|
|||
*
|
||||
* Based on http://doc.qt.io/qt-5/qtquick-tutorials-dynamicview-dynamicview4-example.html
|
||||
*/
|
||||
|
||||
DelegateModel {
|
||||
id: sortFilterModel
|
||||
|
||||
property string sortRole: "" /// the role to use for sorting
|
||||
property int sortOrder: Qt.AscendingOrder /// the sorting order
|
||||
property var filters: [] /// filter format: {role: "roleName", value: "filteringValue"}
|
||||
property string sortRole: "" /// The role to use for sorting
|
||||
property int sortOrder: Qt.AscendingOrder /// The sorting order
|
||||
property var filters: [] /// Filter format: {role: "roleName", value: "filteringValue"}
|
||||
|
||||
onSortRoleChanged: invalidateSort()
|
||||
onSortOrderChanged: invalidateSort()
|
||||
onFiltersChanged: invalidateFilters()
|
||||
|
||||
// display "filtered" group
|
||||
// Display "filtered" group
|
||||
filterOnGroup: "filtered"
|
||||
// don't include elements in "items" group by default
|
||||
// as they must fall in the "unsorted" group
|
||||
// Don't include elements in "items" group by default as they must fall in the "unsorted" group
|
||||
items.includeByDefault: false
|
||||
|
||||
groups: [
|
||||
|
@ -41,15 +41,15 @@ DelegateModel {
|
|||
|
||||
name: "unsorted"
|
||||
includeByDefault: true
|
||||
// if the source model changes, perform sorting and filtering
|
||||
// If the source model changes, perform sorting and filtering
|
||||
onChanged: {
|
||||
// no sorting: move everything from unsorted to sorted group
|
||||
// No sorting: move everything from unsorted to sorted group
|
||||
if(sortRole == "") {
|
||||
unsortedItems.setGroups(0, unsortedItems.count, ["items"])
|
||||
} else {
|
||||
sort()
|
||||
}
|
||||
// perform filter invalidation in both cases
|
||||
// Perform filter invalidation in both cases
|
||||
invalidateFilters()
|
||||
}
|
||||
},
|
||||
|
@ -87,8 +87,7 @@ DelegateModel {
|
|||
if (filter === undefined) {
|
||||
return true;
|
||||
}
|
||||
switch (value.constructor.name)
|
||||
{
|
||||
switch (value.constructor.name) {
|
||||
case "String":
|
||||
return value.toLowerCase().indexOf(filter.toLowerCase()) > -1
|
||||
default:
|
||||
|
@ -98,8 +97,8 @@ DelegateModel {
|
|||
|
||||
/// Apply respectFilter mapping and logical AND/OR reduction on filters
|
||||
function respectFilters(item) {
|
||||
let cond = (filter => respectFilter(modelData(item, filter.role), filter.value));
|
||||
return filters.every(x => Array.isArray(x) ? x.some(cond) : cond(x));
|
||||
let cond = (filter => respectFilter(modelData(item, filter.role), filter.value))
|
||||
return filters.every(x => Array.isArray(x) ? x.some(cond) : cond(x))
|
||||
}
|
||||
|
||||
/// Reverse sort order (toggle between Qt.AscendingOrder / Qt.DescendingOrder)
|
||||
|
@ -108,40 +107,42 @@ DelegateModel {
|
|||
}
|
||||
|
||||
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() {
|
||||
if (!sortFilterModel.model || !sortFilterModel.model.count)
|
||||
return;
|
||||
|
||||
// move everything from "items" to "unsorted
|
||||
// will trigger "unsorted" DelegateModelGroup 'changed' signal
|
||||
// Move everything from "items" to "unsorted", will trigger "unsorted" DelegateModelGroup 'changed' signal
|
||||
items.setGroups(0, items.count, ["unsorted"])
|
||||
}
|
||||
|
||||
/// Invalidate filtering
|
||||
function invalidateFilters() {
|
||||
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))) {
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute insert position of 'item' based on the value
|
||||
/// of its sortProperty
|
||||
/// Compute insert position of 'item' based on the value of its sortProperty
|
||||
function insertPosition(lessThan, item) {
|
||||
var lower = 0
|
||||
var upper = items.count
|
||||
while (lower < upper) {
|
||||
var middle = Math.floor(lower + (upper - lower) / 2)
|
||||
var result = lessThan(item, items.get(middle))
|
||||
if (sortOrder == Qt.DescendingOrder)
|
||||
if (sortOrder == Qt.DescendingOrder) {
|
||||
result = !result
|
||||
}
|
||||
|
||||
if (result) {
|
||||
upper = middle
|
||||
} else {
|
||||
|
@ -159,7 +160,7 @@ DelegateModel {
|
|||
item.groups = ["items"]
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,5 +2,4 @@ pragma Singleton
|
|||
import Meshroom.Helpers 1.0
|
||||
|
||||
Transformations3DHelper {
|
||||
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
.pragma library
|
||||
|
||||
|
||||
function intToString(v) {
|
||||
// use EN locale to get comma separated thousands
|
||||
// Use EN locale to get comma separated thousands
|
||||
// + remove automatically added trailing decimals
|
||||
// (this 'toLocaleString' does not take any option)
|
||||
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.
|
||||
function plainToHtml(t) {
|
||||
var escaped = t.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>') // escape text
|
||||
return escaped.replace(/\n/g, '<br>') // replace line breaks
|
||||
var escaped = t.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>') // Escape text
|
||||
return escaped.replace(/\n/g, '<br>') // Replace line breaks
|
||||
}
|
||||
|
||||
function divmod(x, y) {
|
||||
|
@ -41,8 +40,7 @@ function sec2timecode(timeSeconds) {
|
|||
}
|
||||
|
||||
function sec2timeStr(timeSeconds) {
|
||||
// Need to decide the rounding precision first
|
||||
// to propagate the right values
|
||||
// Need to decide the rounding precision first to propagate the right values
|
||||
if (timeSeconds >= 60.0) {
|
||||
timeSeconds = Math.round(timeSeconds)
|
||||
} else {
|
||||
|
@ -57,7 +55,7 @@ function sec2timeStr(timeSeconds) {
|
|||
timeStr += timeObj.minutes + "m"
|
||||
}
|
||||
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 less than a minute, keep millisecond precision
|
||||
timeStr += timeObj.seconds.toFixed(2) + "s"
|
||||
|
|
|
@ -31,7 +31,7 @@ FloatingPane {
|
|||
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)
|
||||
onCrfReadyChanged: {
|
||||
if (crfReady) {
|
||||
|
@ -77,24 +77,24 @@ FloatingPane {
|
|||
}
|
||||
|
||||
// We cannot use a Repeater with these Components so we need to instantiate them one by one
|
||||
// Red curve
|
||||
LineSeries {
|
||||
// Red curve
|
||||
id: redCurve
|
||||
axisX: valueAxisX
|
||||
axisY: valueAxisY
|
||||
name: crfReady ? csvData.getColumn(1).title : ""
|
||||
color: name.toLowerCase()
|
||||
}
|
||||
// Green curve
|
||||
LineSeries {
|
||||
// Green curve
|
||||
id: greenCurve
|
||||
axisX: valueAxisX
|
||||
axisY: valueAxisY
|
||||
name: crfReady ? csvData.getColumn(2).title : ""
|
||||
color: name.toLowerCase()
|
||||
}
|
||||
// Blue curve
|
||||
LineSeries {
|
||||
// Blue curve
|
||||
id: blueCurve
|
||||
axisX: valueAxisX
|
||||
axisY: valueAxisY
|
||||
|
|
|
@ -3,9 +3,9 @@ import QtQuick
|
|||
Item {
|
||||
id: root
|
||||
|
||||
// required for perspective transform
|
||||
property real sizeX: 1675.0 // might be overridden in ColorCheckerViewer
|
||||
property real sizeY: 1125.0 // might be overridden in ColorCheckerViewer
|
||||
// Required for perspective transform
|
||||
property real sizeX: 1675.0 // Might be overridden in ColorCheckerViewer
|
||||
property real sizeY: 1125.0 // Might be overridden in ColorCheckerViewer
|
||||
|
||||
property var colors: null
|
||||
property var window: null
|
||||
|
@ -27,10 +27,8 @@ Item {
|
|||
id: transformation
|
||||
matrix: Qt.matrix4x4()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function applyTransform(m) {
|
||||
transformation.matrix = Qt.matrix4x4(
|
||||
m[0][0], m[0][1], 0, m[0][2],
|
||||
|
@ -38,5 +36,4 @@ Item {
|
|||
0, 0, 1, 0,
|
||||
m[2][0], m[2][1], 0, m[2][2])
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ FloatingPane {
|
|||
padding: 4
|
||||
anchors.rightMargin: 0
|
||||
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
|
@ -34,9 +33,7 @@ FloatingPane {
|
|||
height: root.height / grid.rows - grid.spacing * (grid.rows + 1) / grid.rows
|
||||
color: Qt.rgba(modelData.r, modelData.g, modelData.b, 1.0)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@ Item {
|
|||
property var viewpoint: null
|
||||
property real zoom: 1.0
|
||||
|
||||
// required for perspective transform
|
||||
// Required for perspective transform
|
||||
// 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 ccheckerSizeY: 1125.0
|
||||
|
||||
|
@ -34,16 +34,13 @@ Item {
|
|||
|
||||
function readSourceFile() {
|
||||
var xhr = new XMLHttpRequest
|
||||
// console.warn("readSourceFile: " + root.source)
|
||||
xhr.open("GET", root.source)
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status == 200) {
|
||||
try {
|
||||
root.json = null
|
||||
// console.warn("readSourceFile: update json from " + root.source)
|
||||
root.json = JSON.parse(xhr.responseText)
|
||||
// console.warn("readSourceFile: root.json.checkers.length=" + root.json.checkers.length)
|
||||
} catch(exc) {
|
||||
console.warn("Failed to parse ColorCheckerDetection JSON file: " + source)
|
||||
return
|
||||
|
|
|
@ -10,6 +10,7 @@ import Utils 1.0
|
|||
* FeaturesInfoOverlay is an overlay that displays info and
|
||||
* provides controls over a FeaturesViewer component.
|
||||
*/
|
||||
|
||||
FloatingPane {
|
||||
id: root
|
||||
|
||||
|
@ -65,7 +66,10 @@ FloatingPane {
|
|||
ComboBox {
|
||||
id: featureDisplayModeCB
|
||||
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
|
||||
Layout.fillHeight: true
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
@ -81,7 +85,10 @@ FloatingPane {
|
|||
ComboBox {
|
||||
id: trackDisplayModeCB
|
||||
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
|
||||
Layout.fillHeight: true
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
@ -152,7 +159,8 @@ FloatingPane {
|
|||
}
|
||||
SpinBox {
|
||||
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
|
||||
Layout.fillHeight: true
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
|
|
@ -7,6 +7,7 @@ import Utils 1.0
|
|||
* FeaturesViewer displays the extracted feature points of a View.
|
||||
* Requires QtAliceVision plugin.
|
||||
*/
|
||||
|
||||
Repeater {
|
||||
id: root
|
||||
|
||||
|
@ -60,7 +61,7 @@ Repeater {
|
|||
|
||||
model: root.describerTypes
|
||||
|
||||
// instantiate one FeaturesViewer by describer type
|
||||
// Instantiate one FeaturesViewer by describer type
|
||||
delegate: AliceVision.FeaturesViewer {
|
||||
readonly property int colorIndex: (index + colorOffset) % root.colors.length
|
||||
property int colorOffset: 0
|
||||
|
|
|
@ -96,7 +96,6 @@ AliceVision.FloatImageViewer {
|
|||
if (!isHighlightable) root.surface.mouseOver = false
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Principal Point
|
||||
*/
|
||||
|
|
|
@ -30,19 +30,18 @@ FloatingPane {
|
|||
|
||||
DoubleValidator {
|
||||
id: doubleValidator
|
||||
locale: 'C' // use '.' decimal separator disregarding of the system locale
|
||||
locale: 'C' // Use '.' decimal separator disregarding of the system locale
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: toolLayout
|
||||
// anchors.verticalCenter: parent
|
||||
anchors.fill: parent
|
||||
|
||||
// channel mode
|
||||
// Channel mode
|
||||
ComboBox {
|
||||
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.preferredWidth: Layout.minimumWidth
|
||||
flat: true
|
||||
|
@ -57,7 +56,7 @@ FloatingPane {
|
|||
model: channels
|
||||
}
|
||||
|
||||
// gain slider
|
||||
// Gain slider
|
||||
RowLayout {
|
||||
spacing: 5
|
||||
|
||||
|
@ -97,7 +96,7 @@ FloatingPane {
|
|||
}
|
||||
}
|
||||
|
||||
// gamma slider
|
||||
// Gamma slider
|
||||
RowLayout {
|
||||
spacing: 5
|
||||
|
||||
|
@ -242,7 +241,7 @@ FloatingPane {
|
|||
TextMetrics {
|
||||
id: textMetrics_colorValue
|
||||
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 {
|
||||
id: textMetrics_gainValue
|
||||
|
|
|
@ -12,6 +12,7 @@ import Utils 1.0
|
|||
/**
|
||||
* ImageMetadataView displays a JSON model representing an image's metadata as a ListView.
|
||||
*/
|
||||
|
||||
FloatingPane {
|
||||
id: root
|
||||
|
||||
|
@ -94,7 +95,7 @@ FloatingPane {
|
|||
entry["raw"] = entry["group"] + ":" + entry["key"] + "=" + entry["value"]
|
||||
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)
|
||||
coordinates = getGPSCoordinates(metadata)
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ FloatingPane {
|
|||
|
||||
DoubleValidator {
|
||||
id: doubleValidator
|
||||
locale: 'C' // use '.' decimal separator disregarding of the system locale
|
||||
locale: 'C' // Use '.' decimal separator disregarding of the system locale
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
|
@ -148,12 +148,11 @@ FloatingPane {
|
|||
}
|
||||
}
|
||||
|
||||
//Fill rectangle to have a better UI
|
||||
// Fill rectangle to have a better UI
|
||||
Rectangle {
|
||||
color: root.palette.window
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
|
|
|
@ -32,7 +32,7 @@ FloatingPane {
|
|||
|
||||
DoubleValidator {
|
||||
id: doubleValidator
|
||||
locale: 'C' // use '.' decimal separator disregarding of the system locale
|
||||
locale: 'C' // Use '.' decimal separator disregarding of the system locale
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
|
@ -132,7 +132,6 @@ FloatingPane {
|
|||
Layout.fillWidth: false
|
||||
Layout.maximumWidth: 50
|
||||
|
||||
|
||||
validator: DoubleValidator {
|
||||
bottom: Math.min(speedSpinBox.from, speedSpinBox.to)
|
||||
top: Math.max(speedSpinBox.from, speedSpinBox.to)
|
||||
|
@ -165,7 +164,6 @@ FloatingPane {
|
|||
Layout.fillWidth: false
|
||||
Layout.maximumWidth: 50
|
||||
|
||||
|
||||
validator: DoubleValidator {
|
||||
bottom: Math.min(downscaleSpinBox.from, downscaleSpinBox.to)
|
||||
top: Math.max(downscaleSpinBox.from, downscaleSpinBox.to)
|
||||
|
@ -180,8 +178,8 @@ FloatingPane {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: textMetrics_subdivisionsValue
|
||||
font: subdivisionsLabel.font
|
||||
|
|
|
@ -73,7 +73,7 @@ AliceVision.PanoramaViewer {
|
|||
property double pitchNode: activeNode ? activeNode.attribute("manualTransform.manualRotation.x").value : 0
|
||||
property double rollNode: activeNode ? activeNode.attribute("manualTransform.manualRotation.z").value : 0
|
||||
|
||||
//Convert angle functions
|
||||
// Convert angle functions
|
||||
function toDegrees(radians) {
|
||||
return radians * (180 / Math.PI)
|
||||
}
|
||||
|
@ -82,12 +82,16 @@ AliceVision.PanoramaViewer {
|
|||
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
|
||||
function limitAngle(angle) {
|
||||
if (angle > 180) angle = -180.0 + (angle - 180.0)
|
||||
if (angle < -180) angle = 180.0 - (Math.abs(angle) - 180)
|
||||
if (angle > 180)
|
||||
angle = -180.0 + (angle - 180.0)
|
||||
if (angle < -180)
|
||||
angle = 180.0 - (Math.abs(angle) - 180)
|
||||
return angle
|
||||
}
|
||||
|
||||
|
@ -273,33 +277,31 @@ AliceVision.PanoramaViewer {
|
|||
var sourceItem = Filepath.stringToUrl(msfmData.getUrlFromViewId(idViewItem))
|
||||
|
||||
setSource("FloatImage.qml", {
|
||||
'surface.viewerType': AliceVision.Surface.EViewerType.PANORAMA,
|
||||
'viewerTypeString': 'panorama',
|
||||
'surface.subdivisions': Qt.binding(function() { return subdivisionsPano }),
|
||||
'cropFisheye' : Qt.binding(function(){ return cropFisheyePano }),
|
||||
'surface.pitch': Qt.binding(function() { return root.pitch }),
|
||||
'surface.yaw': Qt.binding(function() { return root.yaw }),
|
||||
'surface.roll': Qt.binding(function() { return root.roll }),
|
||||
'idView': Qt.binding(function() { return idViewItem }),
|
||||
'gamma': Qt.binding(function() { return hdrImageToolbar.gammaValue }),
|
||||
'gain': Qt.binding(function() { return hdrImageToolbar.gainValue }),
|
||||
'channelModeString': Qt.binding(function() { return hdrImageToolbar.channelModeValue }),
|
||||
'downscaleLevel' : Qt.binding(function() { return downscale }),
|
||||
'source': Qt.binding(function() { return sourceItem }),
|
||||
'surface.msfmData': Qt.binding(function() { return root.msfmData }),
|
||||
'canBeHovered': true,
|
||||
'useSequence': false
|
||||
"surface.viewerType": AliceVision.Surface.EViewerType.PANORAMA,
|
||||
"viewerTypeString": "panorama",
|
||||
"surface.subdivisions": Qt.binding(function() { return subdivisionsPano }),
|
||||
"cropFisheye" : Qt.binding(function(){ return cropFisheyePano }),
|
||||
"surface.pitch": Qt.binding(function() { return root.pitch }),
|
||||
"surface.yaw": Qt.binding(function() { return root.yaw }),
|
||||
"surface.roll": Qt.binding(function() { return root.roll }),
|
||||
"idView": Qt.binding(function() { return idViewItem }),
|
||||
"gamma": Qt.binding(function() { return hdrImageToolbar.gammaValue }),
|
||||
"gain": Qt.binding(function() { return hdrImageToolbar.gainValue }),
|
||||
"channelModeString": Qt.binding(function() { return hdrImageToolbar.channelModeValue }),
|
||||
"downscaleLevel": Qt.binding(function() { return downscale }),
|
||||
"source": Qt.binding(function() { return sourceItem }),
|
||||
"surface.msfmData": Qt.binding(function() { return root.msfmData }),
|
||||
"canBeHovered": true,
|
||||
"useSequence": false
|
||||
})
|
||||
imageLoaded = Qt.binding(function() { return repeater.itemAt(index).item.imageStatus === Image.Ready ? true : false })
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Repeater {
|
||||
id: repeater
|
||||
model: 0
|
||||
delegate: imgPano
|
||||
|
||||
}
|
||||
Connections {
|
||||
target: root
|
||||
|
@ -309,7 +311,7 @@ AliceVision.PanoramaViewer {
|
|||
// Retrieve downscale value from C++
|
||||
panoramaViewerToolbar.updateDownscaleValue(root.downscale)
|
||||
|
||||
//Changing the repeater model (number of elements)
|
||||
// Changing the repeater model (number of elements)
|
||||
panoImages.updateRepeater()
|
||||
|
||||
root.readyToLoad = Image.Ready
|
||||
|
|
|
@ -100,7 +100,6 @@ FloatingPane {
|
|||
anchors.leftMargin: residualsPerViewChart.width * 0.25
|
||||
|
||||
RowLayout {
|
||||
|
||||
ChartViewCheckBox {
|
||||
id: allObservations
|
||||
text: "ALL"
|
||||
|
@ -198,7 +197,6 @@ FloatingPane {
|
|||
anchors.leftMargin: observationsLengthsPerViewChart.width * 0.25
|
||||
|
||||
RowLayout {
|
||||
|
||||
ChartViewCheckBox {
|
||||
id: allModes
|
||||
text: "ALL"
|
||||
|
|
|
@ -145,7 +145,6 @@ FloatingPane {
|
|||
anchors.leftMargin: observationsLengthsChart.width * 0.25
|
||||
|
||||
RowLayout {
|
||||
|
||||
ChartViewCheckBox {
|
||||
id: allObservations
|
||||
text: "ALL"
|
||||
|
@ -213,7 +212,6 @@ FloatingPane {
|
|||
anchors.leftMargin: observationsScaleChart.width * 0.15
|
||||
|
||||
RowLayout {
|
||||
|
||||
ChartViewCheckBox {
|
||||
id: allObservationsScales
|
||||
text: "ALL"
|
||||
|
|
|
@ -5,6 +5,7 @@ import AliceVision 1.0
|
|||
/**
|
||||
* To evaluate if the QtAliceVision plugin is available.
|
||||
*/
|
||||
|
||||
Item {
|
||||
id: root
|
||||
}
|
||||
|
|
|
@ -123,11 +123,13 @@ FocusScope {
|
|||
anchors.fill: parent
|
||||
property double factor: 1.2
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
|
||||
onPressed: function(mouse) {
|
||||
imgContainer.forceActiveFocus()
|
||||
if (mouse.button & Qt.MiddleButton || (mouse.button & Qt.LeftButton && mouse.modifiers & Qt.ShiftModifier))
|
||||
drag.target = imgContainer // Start drag
|
||||
}
|
||||
|
||||
onReleased: function(mouse) {
|
||||
drag.target = undefined // Stop drag
|
||||
if (mouse.button & Qt.RightButton) {
|
||||
|
@ -137,6 +139,7 @@ FocusScope {
|
|||
menu.open()
|
||||
}
|
||||
}
|
||||
|
||||
onWheel: function(wheel) {
|
||||
var zoomFactor = wheel.angleDelta.y > 0 ? factor : 1 / factor
|
||||
|
||||
|
@ -184,17 +187,17 @@ FocusScope {
|
|||
function tryLoadNode(node) {
|
||||
useExternal = false
|
||||
|
||||
// safety check
|
||||
// Safety check
|
||||
if (!node) {
|
||||
return false
|
||||
}
|
||||
|
||||
// node must be computed or at least running
|
||||
// Node must be computed or at least running
|
||||
if (node.isComputable && !node.isPartiallyFinished()) {
|
||||
return false
|
||||
}
|
||||
|
||||
// node must have at least one output attribute with the image semantic
|
||||
// Node must have at least one output attribute with the image semantic
|
||||
if (!node.hasImageOutput && !node.hasSequenceOutput) {
|
||||
return false
|
||||
}
|
||||
|
@ -212,7 +215,6 @@ FocusScope {
|
|||
function getViewpoint(viewId) {
|
||||
// Get viewpoint from cameraInit with matching id
|
||||
// This requires to loop over all viewpoints
|
||||
|
||||
for (var i = 0; i < _reconstruction.viewpoints.count; i++) {
|
||||
var vp = _reconstruction.viewpoints.at(i)
|
||||
if (vp.childAttribute("viewId").value == viewId) {
|
||||
|
@ -264,11 +266,11 @@ FocusScope {
|
|||
|
||||
if (displayedNode && displayedNode.hasSequenceOutput && displayedAttr) {
|
||||
|
||||
// reset current frame to 0 if it is imageList but not sequence
|
||||
// Reset current frame to 0 if it is imageList but not sequence
|
||||
if (displayedAttr.desc.semantic === "imageList") {
|
||||
let includesSeqMissingFiles = false // list only the existing files
|
||||
let [_, filesSeqs] = Filepath.resolveSequence(pathTemplate, includesSeqMissingFiles)
|
||||
// concat in one array all sequences in resolved
|
||||
// Concat in one array all sequences in resolved
|
||||
outputFiles = [].concat.apply([], filesSeqs)
|
||||
let newFrameRange = [0, outputFiles.length - 1]
|
||||
|
||||
|
@ -287,7 +289,7 @@ FocusScope {
|
|||
let [frameRanges, filesSeqs] = Filepath.resolveSequence(pathTemplate, includesSeqMissingFiles)
|
||||
let newFrameRange = [0, 0]
|
||||
if (filesSeqs.length > 0) {
|
||||
// if there is one or several sequences, take the first one
|
||||
// If there is one or several sequences, take the first one
|
||||
outputFiles = filesSeqs[0]
|
||||
newFrameRange = frameRanges[0]
|
||||
|
||||
|
@ -321,7 +323,6 @@ FocusScope {
|
|||
|
||||
function getSequence() {
|
||||
// Entry point for getting the current image sequence
|
||||
|
||||
if (useExternal) {
|
||||
return []
|
||||
}
|
||||
|
@ -342,10 +343,10 @@ FocusScope {
|
|||
root.source = ""
|
||||
}
|
||||
|
||||
// update output attribute names
|
||||
// Update output attribute names
|
||||
var names = []
|
||||
if (displayedNode) {
|
||||
// store attr name for output attributes that represent images
|
||||
// Store attr name for output attributes that represent images
|
||||
for (var i = 0; i < displayedNode.attributes.count; i++) {
|
||||
var attr = displayedNode.attributes.at(i)
|
||||
if (attr.isOutput && (attr.desc.semantic === "image" || attr.desc.semantic === "sequence" ||
|
||||
|
@ -546,28 +547,28 @@ FocusScope {
|
|||
// Instantiate and initialize a FloatImage component dynamically using Loader.setSource
|
||||
// Note: It does not work to use previously created component, so we re-create it with setSource.
|
||||
floatImageViewerLoader.setSource("FloatImage.qml", {
|
||||
'source': Qt.binding(function() { return getImageFile() }),
|
||||
'gamma': Qt.binding(function() { return hdrImageToolbar.gammaValue }),
|
||||
'gain': Qt.binding(function() { return hdrImageToolbar.gainValue }),
|
||||
'channelModeString': Qt.binding(function() { return hdrImageToolbar.channelModeValue }),
|
||||
'isPrincipalPointsDisplayed': Qt.binding(function() { return lensDistortionImageToolbar.displayPrincipalPoint }),
|
||||
'surface.displayGrid': Qt.binding(function() { return lensDistortionImageToolbar.visible && lensDistortionImageToolbar.displayGrid }),
|
||||
'surface.gridOpacity': Qt.binding(function() { return lensDistortionImageToolbar.opacityValue }),
|
||||
'surface.gridColor': Qt.binding(function() { return lensDistortionImageToolbar.color }),
|
||||
'surface.subdivisions': Qt.binding(function() { return root.useFloatImageViewer ? 1 : lensDistortionImageToolbar.subdivisionsValue }),
|
||||
'viewerTypeString': Qt.binding(function() { return displayLensDistortionViewer.checked ? "distortion" : "hdr" }),
|
||||
'surface.msfmData': Qt.binding(function() { return (msfmDataLoader.status === Loader.Ready && msfmDataLoader.item != null && msfmDataLoader.item.status === 2) ? msfmDataLoader.item : null }),
|
||||
'canBeHovered': false,
|
||||
'idView': Qt.binding(function() { return ((root.displayedNode && !root.displayedNode.hasSequenceOutput && _reconstruction) ? _reconstruction.selectedViewId : -1) }),
|
||||
'cropFisheye': false,
|
||||
'sequence': Qt.binding(function() { return ((root.enableSequencePlayer && (_reconstruction || (root.displayedNode && root.displayedNode.hasSequenceOutput))) ? getSequence() : []) }),
|
||||
'resizeRatio': Qt.binding(function() { return floatImageViewerLoader.resizeRatio }),
|
||||
'targetSize': Qt.binding(function() { return floatImageViewerLoader.targetSize }),
|
||||
'useSequence': Qt.binding(function() {
|
||||
"source": Qt.binding(function() { return getImageFile() }),
|
||||
"gamma": Qt.binding(function() { return hdrImageToolbar.gammaValue }),
|
||||
"gain": Qt.binding(function() { return hdrImageToolbar.gainValue }),
|
||||
"channelModeString": Qt.binding(function() { return hdrImageToolbar.channelModeValue }),
|
||||
"isPrincipalPointsDisplayed": Qt.binding(function() { return lensDistortionImageToolbar.displayPrincipalPoint }),
|
||||
"surface.displayGrid": Qt.binding(function() { return lensDistortionImageToolbar.visible && lensDistortionImageToolbar.displayGrid }),
|
||||
"surface.gridOpacity": Qt.binding(function() { return lensDistortionImageToolbar.opacityValue }),
|
||||
"surface.gridColor": Qt.binding(function() { return lensDistortionImageToolbar.color }),
|
||||
"surface.subdivisions": Qt.binding(function() { return root.useFloatImageViewer ? 1 : lensDistortionImageToolbar.subdivisionsValue }),
|
||||
"viewerTypeString": Qt.binding(function() { return displayLensDistortionViewer.checked ? "distortion" : "hdr" }),
|
||||
"surface.msfmData": Qt.binding(function() { return (msfmDataLoader.status === Loader.Ready && msfmDataLoader.item != null && msfmDataLoader.item.status === 2) ? msfmDataLoader.item : null }),
|
||||
"canBeHovered": false,
|
||||
"idView": Qt.binding(function() { return ((root.displayedNode && !root.displayedNode.hasSequenceOutput && _reconstruction) ? _reconstruction.selectedViewId : -1) }),
|
||||
"cropFisheye": false,
|
||||
"sequence": Qt.binding(function() { return ((root.enableSequencePlayer && (_reconstruction || (root.displayedNode && root.displayedNode.hasSequenceOutput))) ? getSequence() : []) }),
|
||||
"resizeRatio": Qt.binding(function() { return floatImageViewerLoader.resizeRatio }),
|
||||
"targetSize": Qt.binding(function() { return floatImageViewerLoader.targetSize }),
|
||||
"useSequence": Qt.binding(function() {
|
||||
return (root.enableSequencePlayer && !useExternal && (_reconstruction || (root.displayedNode && root.displayedNode.hasSequenceOutput && (displayedAttr.desc.semantic === "imageList" || displayedAttr.desc.semantic === "sequence"))))
|
||||
}),
|
||||
'fetchingSequence': Qt.binding(function() { return sequencePlayer.loading }),
|
||||
'memoryLimit': Qt.binding(function() { return sequencePlayer.settings_SequencePlayer.maxCacheMemory }),
|
||||
"fetchingSequence": Qt.binding(function() { return sequencePlayer.loading }),
|
||||
"memoryLimit": Qt.binding(function() { return sequencePlayer.settings_SequencePlayer.maxCacheMemory }),
|
||||
})
|
||||
} else {
|
||||
// Forcing the unload (instead of using Component.onCompleted to load it once and for all) is necessary since Qt 5.14
|
||||
|
@ -588,14 +589,14 @@ FocusScope {
|
|||
onActiveChanged: {
|
||||
if (active) {
|
||||
setSource("PanoramaViewer.qml", {
|
||||
'subdivisionsPano': Qt.binding(function() { return panoramaViewerToolbar.subdivisionsValue }),
|
||||
'cropFisheyePano': Qt.binding(function() { return root.cropFisheye }),
|
||||
'downscale': Qt.binding(function() { return panoramaViewerToolbar.downscaleValue }),
|
||||
'isEditable': Qt.binding(function() { return panoramaViewerToolbar.enableEdit }),
|
||||
'isHighlightable': Qt.binding(function() { return panoramaViewerToolbar.enableHover }),
|
||||
'displayGridPano': Qt.binding(function() { return panoramaViewerToolbar.displayGrid }),
|
||||
'mouseMultiplier': Qt.binding(function() { return panoramaViewerToolbar.mouseSpeed }),
|
||||
'msfmData': Qt.binding(function() { return (msfmDataLoader && msfmDataLoader.item && msfmDataLoader.status === Loader.Ready
|
||||
"subdivisionsPano": Qt.binding(function() { return panoramaViewerToolbar.subdivisionsValue }),
|
||||
"cropFisheyePano": Qt.binding(function() { return root.cropFisheye }),
|
||||
"downscale": Qt.binding(function() { return panoramaViewerToolbar.downscaleValue }),
|
||||
"isEditable": Qt.binding(function() { return panoramaViewerToolbar.enableEdit }),
|
||||
"isHighlightable": Qt.binding(function() { return panoramaViewerToolbar.enableHover }),
|
||||
"displayGridPano": Qt.binding(function() { return panoramaViewerToolbar.displayGrid }),
|
||||
"mouseMultiplier": Qt.binding(function() { return panoramaViewerToolbar.mouseSpeed }),
|
||||
"msfmData": Qt.binding(function() { return (msfmDataLoader && msfmDataLoader.item && msfmDataLoader.status === Loader.Ready
|
||||
&& msfmDataLoader.item.status === 2) ? msfmDataLoader.item : null }),
|
||||
})
|
||||
} else {
|
||||
|
@ -622,7 +623,7 @@ FocusScope {
|
|||
onWidthChanged: if (status==Image.Ready) fit()
|
||||
source: getImageFile()
|
||||
onStatusChanged: {
|
||||
// update cache source when image is loaded
|
||||
// Update cache source when image is loaded
|
||||
if (status === Image.Ready)
|
||||
qtImageViewerCache.source = source
|
||||
}
|
||||
|
@ -655,7 +656,7 @@ FocusScope {
|
|||
scale: 1.0
|
||||
|
||||
// FeatureViewer: display view extracted feature points
|
||||
// note: requires QtAliceVision plugin - use a Loader to evaluate plugin availability at runtime
|
||||
// Note: requires QtAliceVision plugin - use a Loader to evaluate plugin availability at runtime
|
||||
ExifOrientedViewer {
|
||||
id: featuresViewerLoader
|
||||
active: displayFeatures.checked && !useExternal
|
||||
|
@ -671,12 +672,12 @@ FocusScope {
|
|||
if (active) {
|
||||
// Instantiate and initialize a FeaturesViewer component dynamically using Loader.setSource
|
||||
setSource("FeaturesViewer.qml", {
|
||||
'model': Qt.binding(function() { return activeNode ? activeNode.attribute("describerTypes").value : "" }),
|
||||
'currentViewId': Qt.binding(function() { return _reconstruction.selectedViewId }),
|
||||
'features': Qt.binding(function() { return mfeaturesLoader.status === Loader.Ready ? mfeaturesLoader.item : null }),
|
||||
'tracks': Qt.binding(function() { return mtracksLoader.status === Loader.Ready ? mtracksLoader.item : null }),
|
||||
'sfmData': Qt.binding(function() { return msfmDataLoader.status === Loader.Ready ? msfmDataLoader.item : null }),
|
||||
'syncFeaturesSelected': Qt.binding(function() { return sequencePlayer.syncFeaturesSelected }),
|
||||
"model": Qt.binding(function() { return activeNode ? activeNode.attribute("describerTypes").value : "" }),
|
||||
"currentViewId": Qt.binding(function() { return _reconstruction.selectedViewId }),
|
||||
"features": Qt.binding(function() { return mfeaturesLoader.status === Loader.Ready ? mfeaturesLoader.item : null }),
|
||||
"tracks": Qt.binding(function() { return mtracksLoader.status === Loader.Ready ? mtracksLoader.item : null }),
|
||||
"sfmData": Qt.binding(function() { return msfmDataLoader.status === Loader.Ready ? msfmDataLoader.item : null }),
|
||||
"syncFeaturesSelected": Qt.binding(function() { return sequencePlayer.syncFeaturesSelected }),
|
||||
})
|
||||
} else {
|
||||
// Forcing the unload (instead of using Component.onCompleted to load it once and for all) is necessary since Qt 5.14
|
||||
|
@ -756,7 +757,7 @@ FocusScope {
|
|||
onJsonFolderChanged: {
|
||||
json = null
|
||||
if (activeNode.attribute("autoDetect").value) {
|
||||
// auto detection enabled
|
||||
// Auto detection enabled
|
||||
var jsonPath = activeNode.attribute("output").value
|
||||
Request.get(Filepath.stringToUrl(jsonPath), function(xhr) {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
|
@ -778,25 +779,25 @@ FocusScope {
|
|||
|
||||
function updateGizmo() {
|
||||
if (activeNode.attribute("autoDetect").value) {
|
||||
// update gizmo from auto detection json file
|
||||
// Update gizmo from auto detection JSON file
|
||||
if (json) {
|
||||
// json file found
|
||||
// JSON file found
|
||||
var data = json[currentViewId]
|
||||
if (data && data[0]) {
|
||||
// current view id found
|
||||
// Current view id found
|
||||
circleX = data[0].x
|
||||
circleY= data[0].y
|
||||
circleRadius = data[0].r
|
||||
return
|
||||
}
|
||||
}
|
||||
// no auto detection data
|
||||
// No auto detection data
|
||||
circleX = -1
|
||||
circleY= -1
|
||||
circleRadius = 0
|
||||
}
|
||||
else {
|
||||
// update gizmo from node manual parameters
|
||||
// Update gizmo from node manual parameters
|
||||
circleX = nodeCircleX
|
||||
circleY = nodeCircleY
|
||||
circleRadius = nodeCircleRadius
|
||||
|
@ -816,7 +817,7 @@ FocusScope {
|
|||
}
|
||||
|
||||
// ColorCheckerViewer: display color checker detection results
|
||||
// note: use a Loader to evaluate if a ColorCheckerDetection node exist and displayColorChecker checked at runtime
|
||||
// Note: use a Loader to evaluate if a ColorCheckerDetection node exist and displayColorChecker checked at runtime
|
||||
ExifOrientedViewer {
|
||||
id: colorCheckerViewerLoader
|
||||
anchors.centerIn: parent
|
||||
|
@ -845,6 +846,7 @@ FocusScope {
|
|||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
FloatingPane {
|
||||
id: imagePathToolbar
|
||||
Layout.fillWidth: true
|
||||
|
@ -856,7 +858,7 @@ FocusScope {
|
|||
width: parent.width
|
||||
height: childrenRect.height
|
||||
|
||||
// selectable filepath to source image
|
||||
// Selectable filepath to source image
|
||||
TextField {
|
||||
padding: 0
|
||||
background: Item {}
|
||||
|
@ -869,7 +871,7 @@ FocusScope {
|
|||
text: Filepath.urlToString(getImageFile())
|
||||
}
|
||||
|
||||
// write which node is being displayed
|
||||
// Write which node is being displayed
|
||||
Label {
|
||||
id: displayedNodeName
|
||||
text: root.displayedNode ? root.displayedNode.label : ""
|
||||
|
@ -881,7 +883,7 @@ FocusScope {
|
|||
height: contentHeight
|
||||
}
|
||||
|
||||
// button to clear currently displayed file
|
||||
// Button to clear currently displayed file
|
||||
MaterialToolButton {
|
||||
id: clearViewerButton
|
||||
text: MaterialIcons.close
|
||||
|
@ -889,8 +891,10 @@ FocusScope {
|
|||
enabled: root.displayedNode || root.useExternal
|
||||
visible: root.displayedNode || root.useExternal
|
||||
onClicked: {
|
||||
if (root.displayedNode) root.displayedNode = null
|
||||
if (root.useExternal) root.useExternal = false
|
||||
if (root.displayedNode)
|
||||
root.displayedNode = null
|
||||
if (root.useExternal)
|
||||
root.useExternal = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -946,7 +950,7 @@ FocusScope {
|
|||
}
|
||||
|
||||
visible: metadataCB.checked
|
||||
// only load metadata model if visible
|
||||
// Only load metadata model if visible
|
||||
metadata: {
|
||||
if (visible) {
|
||||
if (root.useExternal || outputAttribute.name != "gallery") {
|
||||
|
@ -985,13 +989,13 @@ FocusScope {
|
|||
|
||||
onActiveChanged: {
|
||||
if (active) {
|
||||
// instantiate and initialize a MFeatures component dynamically using Loader.setSource
|
||||
// so it can fail safely if the c++ plugin is not available
|
||||
// Instantiate and initialize a MFeatures component dynamically using Loader.setSource
|
||||
// so it can fail safely if the C++ plugin is not available
|
||||
setSource("MFeatures.qml", {
|
||||
'describerTypes': Qt.binding(function() {
|
||||
"describerTypes": Qt.binding(function() {
|
||||
return activeNode ? activeNode.attribute("describerTypes").value : {}
|
||||
}),
|
||||
'featureFolders': Qt.binding(function() {
|
||||
"featureFolders": Qt.binding(function() {
|
||||
let result = []
|
||||
if (activeNode) {
|
||||
if (activeNode.nodeType == "FeatureExtraction" && isComputed) {
|
||||
|
@ -1005,7 +1009,7 @@ FocusScope {
|
|||
}
|
||||
return result
|
||||
}),
|
||||
'viewIds': Qt.binding(function() {
|
||||
"viewIds": Qt.binding(function() {
|
||||
if (_reconstruction) {
|
||||
let result = [];
|
||||
for (let i = 0; i < _reconstruction.viewpoints.count; i++) {
|
||||
|
@ -1023,6 +1027,7 @@ FocusScope {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: msfmDataLoader
|
||||
|
||||
|
@ -1060,10 +1065,10 @@ FocusScope {
|
|||
|
||||
onActiveChanged: {
|
||||
if (active) {
|
||||
// instantiate and initialize a SfmStatsView component dynamically using Loader.setSource
|
||||
// Instantiate and initialize a SfmStatsView component dynamically using Loader.setSource
|
||||
// so it can fail safely if the c++ plugin is not available
|
||||
setSource("MSfMData.qml", {
|
||||
'sfmDataPath': Qt.binding(function() { return filepath }),
|
||||
"sfmDataPath": Qt.binding(function() { return filepath }),
|
||||
})
|
||||
} else {
|
||||
// Force the unload (instead of using Component.onCompleted to load it once and for all) is necessary since Qt 5.14
|
||||
|
@ -1071,6 +1076,7 @@ FocusScope {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: mtracksLoader
|
||||
|
||||
|
@ -1090,7 +1096,7 @@ FocusScope {
|
|||
// instantiate and initialize a SfmStatsView component dynamically using Loader.setSource
|
||||
// so it can fail safely if the c++ plugin is not available
|
||||
setSource("MTracks.qml", {
|
||||
'matchingFolders': Qt.binding(function() {
|
||||
"matchingFolders": Qt.binding(function() {
|
||||
let result = []
|
||||
if (activeNode) {
|
||||
if (activeNode.nodeType == "FeatureMatching" && isComputed) {
|
||||
|
@ -1111,6 +1117,7 @@ FocusScope {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: sfmStatsView
|
||||
anchors.fill: parent
|
||||
|
@ -1129,6 +1136,7 @@ FocusScope {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: sfmGlobalStats
|
||||
anchors.fill: parent
|
||||
|
@ -1139,8 +1147,8 @@ FocusScope {
|
|||
// (necessary since Qt 5.14, Component.onCompleted cannot be used anymore to load the data once and for all)
|
||||
if (active) {
|
||||
setSource("SfmGlobalStats.qml", {
|
||||
'msfmData': Qt.binding(function() { return msfmDataLoader.item }),
|
||||
'mTracks': Qt.binding(function() { return mtracksLoader.item }),
|
||||
"msfmData": Qt.binding(function() { return msfmDataLoader.item }),
|
||||
"mTracks": Qt.binding(function() { return mtracksLoader.item }),
|
||||
|
||||
})
|
||||
} else {
|
||||
|
@ -1148,6 +1156,7 @@ FocusScope {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: featuresOverlay
|
||||
anchors {
|
||||
|
@ -1171,7 +1180,7 @@ FocusScope {
|
|||
id: ldrHdrCalibrationGraph
|
||||
anchors.fill: parent
|
||||
|
||||
property var activeNode: _reconstruction ? _reconstruction.activeNodes.get('LdrToHdrCalibration').node : null
|
||||
property var activeNode: _reconstruction ? _reconstruction.activeNodes.get("LdrToHdrCalibration").node : null
|
||||
property var isEnabled: displayLdrHdrCalibrationGraph.checked && activeNode && activeNode.isComputed
|
||||
active: isEnabled
|
||||
|
||||
|
@ -1183,6 +1192,7 @@ FocusScope {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
FloatingPane {
|
||||
id: bottomToolbar
|
||||
padding: 4
|
||||
|
@ -1192,9 +1202,11 @@ FocusScope {
|
|||
RowLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
// zoom label
|
||||
// Zoom label
|
||||
MLabel {
|
||||
text: ((imgContainer.image && (imgContainer.image.imageStatus === Image.Ready)) ? imgContainer.scale.toFixed(2) : "1.00") + "x"
|
||||
ToolTip.text: "Zoom"
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
|
@ -1210,8 +1222,8 @@ FocusScope {
|
|||
}
|
||||
}
|
||||
}
|
||||
ToolTip.text: "Zoom"
|
||||
}
|
||||
|
||||
MaterialToolButton {
|
||||
id: displayAlphaBackground
|
||||
ToolTip.text: "Alpha Background"
|
||||
|
@ -1220,13 +1232,12 @@ FocusScope {
|
|||
Layout.minimumWidth: 0
|
||||
checkable: true
|
||||
}
|
||||
MaterialToolButton
|
||||
{
|
||||
|
||||
MaterialToolButton {
|
||||
id: displayHDR
|
||||
ToolTip.text: "High-Dynamic-Range Image Viewer"
|
||||
text: MaterialIcons.hdr_on
|
||||
// larger font but smaller padding,
|
||||
// so it is visually similar.
|
||||
// Larger font but smaller padding, so it is visually similar
|
||||
font.pointSize: 20
|
||||
padding: 0
|
||||
Layout.minimumWidth: 0
|
||||
|
@ -1241,12 +1252,12 @@ FocusScope {
|
|||
root.useFloatImageViewer = !root.useFloatImageViewer
|
||||
}
|
||||
}
|
||||
|
||||
MaterialToolButton {
|
||||
id: displayLensDistortionViewer
|
||||
|
||||
property int numberChanges: 0
|
||||
property bool previousChecked: false
|
||||
property var activeNode: root.aliceVisionPluginAvailable && _reconstruction ? _reconstruction.activeNodes.get('sfmData').node : null
|
||||
property var activeNode: root.aliceVisionPluginAvailable && _reconstruction ? _reconstruction.activeNodes.get("sfmData").node : null
|
||||
property bool isComputed: {
|
||||
if (!activeNode)
|
||||
return false
|
||||
|
@ -1294,9 +1305,10 @@ FocusScope {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
MaterialToolButton {
|
||||
id: displayPanoramaViewer
|
||||
property var activeNode: root.aliceVisionPluginAvailable && _reconstruction ? _reconstruction.activeNodes.get('SfMTransform').node : null
|
||||
property var activeNode: root.aliceVisionPluginAvailable && _reconstruction ? _reconstruction.activeNodes.get("SfMTransform").node : null
|
||||
property bool isComputed: {
|
||||
if (!activeNode)
|
||||
return false
|
||||
|
@ -1333,6 +1345,7 @@ FocusScope {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
MaterialToolButton {
|
||||
id: displayFeatures
|
||||
ToolTip.text: "Display Features"
|
||||
|
@ -1343,16 +1356,18 @@ FocusScope {
|
|||
checked: false
|
||||
enabled: root.aliceVisionPluginAvailable && !displayPanoramaViewer.checked && !useExternal
|
||||
onEnabledChanged : {
|
||||
if (useExternal) return
|
||||
if (enabled == false) checked = false
|
||||
if (useExternal)
|
||||
return
|
||||
if (enabled == false)
|
||||
checked = false
|
||||
}
|
||||
}
|
||||
|
||||
MaterialToolButton {
|
||||
id: displayFisheyeCircleLoader
|
||||
property var activeNode: _reconstruction ? _reconstruction.activeNodes.get('PanoramaInit').node : null
|
||||
property var activeNode: _reconstruction ? _reconstruction.activeNodes.get("PanoramaInit").node : null
|
||||
ToolTip.text: "Display Fisheye Circle: " + (activeNode ? activeNode.label : "No Node")
|
||||
text: MaterialIcons.vignette
|
||||
// text: MaterialIcons.panorama_fish_eye
|
||||
font.pointSize: 11
|
||||
Layout.minimumWidth: 0
|
||||
checkable: true
|
||||
|
@ -1360,9 +1375,10 @@ FocusScope {
|
|||
enabled: activeNode && activeNode.attribute("useFisheye").value && !displayPanoramaViewer.checked
|
||||
visible: activeNode
|
||||
}
|
||||
|
||||
MaterialToolButton {
|
||||
id: displayLightingCircleLoader
|
||||
property var activeNode: _reconstruction.activeNodes.get('SphereDetection').node
|
||||
property var activeNode: _reconstruction.activeNodes.get("SphereDetection").node
|
||||
ToolTip.text: "Display Lighting Circle: " + (activeNode ? activeNode.label : "No Node")
|
||||
text: MaterialIcons.location_searching
|
||||
font.pointSize: 11
|
||||
|
@ -1372,11 +1388,12 @@ FocusScope {
|
|||
enabled: activeNode
|
||||
visible: activeNode
|
||||
}
|
||||
|
||||
MaterialToolButton {
|
||||
id: displayColorCheckerViewerLoader
|
||||
property var activeNode: _reconstruction ? _reconstruction.activeNodes.get('ColorCheckerDetection').node : null
|
||||
property var activeNode: _reconstruction ? _reconstruction.activeNodes.get("ColorCheckerDetection").node : null
|
||||
ToolTip.text: "Display Color Checker: " + (activeNode ? activeNode.label : "No Node")
|
||||
text: MaterialIcons.view_comfy //view_module grid_on gradient view_comfy border_all
|
||||
text: MaterialIcons.view_comfy
|
||||
font.pointSize: 11
|
||||
Layout.minimumWidth: 0
|
||||
checkable: true
|
||||
|
@ -1465,7 +1482,7 @@ FocusScope {
|
|||
|
||||
MaterialToolButton {
|
||||
id: displaySfmStatsView
|
||||
property var activeNode: root.aliceVisionPluginAvailable && _reconstruction ? _reconstruction.activeNodes.get('sfm').node : null
|
||||
property var activeNode: root.aliceVisionPluginAvailable && _reconstruction ? _reconstruction.activeNodes.get("sfm").node : null
|
||||
property bool isComputed: activeNode && activeNode.isComputed
|
||||
|
||||
font.family: MaterialIcons.fontFamily
|
||||
|
@ -1491,7 +1508,7 @@ FocusScope {
|
|||
|
||||
MaterialToolButton {
|
||||
id: displaySfmDataGlobalStats
|
||||
property var activeNode: root.aliceVisionPluginAvailable && _reconstruction ? _reconstruction.activeNodes.get('sfm').node : null
|
||||
property var activeNode: root.aliceVisionPluginAvailable && _reconstruction ? _reconstruction.activeNodes.get("sfm").node : null
|
||||
property bool isComputed: activeNode && activeNode.isComputed
|
||||
|
||||
font.family: MaterialIcons.fontFamily
|
||||
|
@ -1514,6 +1531,7 @@ FocusScope {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
MaterialToolButton {
|
||||
id: metadataCB
|
||||
|
||||
|
@ -1543,7 +1561,11 @@ FocusScope {
|
|||
id: sequencePlayer
|
||||
anchors.margins: 0
|
||||
Layout.fillWidth: true
|
||||
sortedViewIds: { return (root.enableSequencePlayer && (root.displayedNode && root.displayedNode.hasSequenceOutput)) ? root.sequence : (_reconstruction && _reconstruction.viewpoints.count > 0) ? buildOrderedSequence("<VIEW_ID>") : [] }
|
||||
sortedViewIds: {
|
||||
return (root.enableSequencePlayer && (root.displayedNode && root.displayedNode.hasSequenceOutput)) ?
|
||||
root.sequence :
|
||||
(_reconstruction && _reconstruction.viewpoints.count > 0) ? buildOrderedSequence("<VIEW_ID>") : []
|
||||
}
|
||||
viewer: floatImageViewerLoader.status === Loader.Ready ? floatImageViewerLoader.item : null
|
||||
visible: root.enableSequencePlayer
|
||||
enabled: root.enableSequencePlayer
|
||||
|
@ -1556,14 +1578,14 @@ FocusScope {
|
|||
// Busy indicator
|
||||
BusyIndicator {
|
||||
anchors.centerIn: parent
|
||||
// running property binding seems broken, only dynamic binding assignment works
|
||||
// Running property binding seems broken, only dynamic binding assignment works
|
||||
Component.onCompleted: {
|
||||
running = Qt.binding(function() {
|
||||
return (root.usePanoramaViewer === true && imgContainer.image && imgContainer.image.allImagesLoaded === false)
|
||||
|| (imgContainer.image && imgContainer.image.imageStatus === Image.Loading)
|
||||
})
|
||||
}
|
||||
// disable the visibility when unused to avoid stealing the mouseEvent to the image color picker
|
||||
// Disable the visibility when unused to avoid stealing the mouseEvent to the image color picker
|
||||
visible: running
|
||||
|
||||
onVisibleChanged: {
|
||||
|
@ -1578,10 +1600,10 @@ FocusScope {
|
|||
|
||||
shortcut: "R"
|
||||
onTriggered: {
|
||||
if (hdrImageToolbar.channelModeValue !== 'r') {
|
||||
hdrImageToolbar.channelModeValue = 'r'
|
||||
if (hdrImageToolbar.channelModeValue !== "r") {
|
||||
hdrImageToolbar.channelModeValue = "r"
|
||||
} else {
|
||||
hdrImageToolbar.channelModeValue = 'rgba'
|
||||
hdrImageToolbar.channelModeValue = "rgba"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1591,10 +1613,10 @@ FocusScope {
|
|||
|
||||
shortcut: "G"
|
||||
onTriggered: {
|
||||
if (hdrImageToolbar.channelModeValue !== 'g') {
|
||||
hdrImageToolbar.channelModeValue = 'g'
|
||||
if (hdrImageToolbar.channelModeValue !== "g") {
|
||||
hdrImageToolbar.channelModeValue = "g"
|
||||
} else {
|
||||
hdrImageToolbar.channelModeValue = 'rgba'
|
||||
hdrImageToolbar.channelModeValue = "rgba"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1604,10 +1626,10 @@ FocusScope {
|
|||
|
||||
shortcut: "B"
|
||||
onTriggered: {
|
||||
if (hdrImageToolbar.channelModeValue !== 'b') {
|
||||
hdrImageToolbar.channelModeValue = 'b'
|
||||
if (hdrImageToolbar.channelModeValue !== "b") {
|
||||
hdrImageToolbar.channelModeValue = "b"
|
||||
} else {
|
||||
hdrImageToolbar.channelModeValue = 'rgba'
|
||||
hdrImageToolbar.channelModeValue = "rgba"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1617,10 +1639,10 @@ FocusScope {
|
|||
|
||||
shortcut: "A"
|
||||
onTriggered: {
|
||||
if (hdrImageToolbar.channelModeValue !== 'a') {
|
||||
hdrImageToolbar.channelModeValue = 'a'
|
||||
if (hdrImageToolbar.channelModeValue !== "a") {
|
||||
hdrImageToolbar.channelModeValue = "a"
|
||||
} else {
|
||||
hdrImageToolbar.channelModeValue = 'rgba'
|
||||
hdrImageToolbar.channelModeValue = "rgba"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ Entity {
|
|||
onWheel: function(wheel) {
|
||||
var d = root.camera.viewCenter.minus(root.camera.position).length() // Distance between camera position and center position
|
||||
var zoomPower = 0.2
|
||||
var angleStep = 120 // wheel.angleDelta.y = +- 120 * number of wheel rotations
|
||||
var angleStep = 120
|
||||
var tz = (wheel.angleDelta.y / angleStep) * d * zoomPower // Translation to apply depending on user action (mouse wheel), bigger absolute value means we'll zoom/dezoom more
|
||||
var tzThreshold = 0.001
|
||||
|
||||
|
@ -129,8 +129,7 @@ Entity {
|
|||
sourceDevice: keyboardSourceDevice
|
||||
property bool _pressed
|
||||
|
||||
// When focus is lost while pressing a key, the corresponding action
|
||||
// stays active, even when it's released.
|
||||
// When focus is lost while pressing a key, the corresponding action stays active, even when it's released.
|
||||
// Handle this issue manually by keeping an additional _pressed state
|
||||
// which is cleared when focus changes (used for 'pickingActive' property).
|
||||
onFocusChanged: function(focus) {
|
||||
|
|
|
@ -4,11 +4,12 @@ import DepthMapEntity 2.1
|
|||
* Support for Depth Map files (EXR) in Qt3d.
|
||||
* Create this component dynamically to test for DepthMapEntity plugin availability.
|
||||
*/
|
||||
|
||||
DepthMapEntity {
|
||||
id: root
|
||||
|
||||
pointSize: Viewer3DSettings.pointSize * (Viewer3DSettings.fixedPointSize ? 1.0 : 0.001)
|
||||
// map render modes to custom visualization modes
|
||||
// Map render modes to custom visualization modes
|
||||
displayMode: Viewer3DSettings.renderMode == 0 ? DepthMapEntity.Points : DepthMapEntity.Triangles
|
||||
displayColor: Viewer3DSettings.renderMode == 1
|
||||
}
|
||||
|
|
|
@ -3,12 +3,12 @@ import Qt3D.Core 2.6
|
|||
import Qt3D.Render 2.6
|
||||
import Qt3D.Extras 2.15
|
||||
|
||||
|
||||
/**
|
||||
* EnvironmentMap maps an equirectangular image on a Sphere.
|
||||
* The 'position' property can be used to virually attach it to a camera
|
||||
* and get the impression of an environment at an infinite distance.
|
||||
*/
|
||||
|
||||
Entity {
|
||||
id: root
|
||||
|
||||
|
|
|
@ -20,30 +20,29 @@ Entity {
|
|||
buffer: Buffer {
|
||||
data: {
|
||||
function buildGrid(first, last, offset, attribute) {
|
||||
var vertexCount = (((last-first)/offset)+1)*4;
|
||||
var f32 = new Float32Array(vertexCount*3);
|
||||
for (var id = 0, i = first; i <= last; i += offset, id++)
|
||||
{
|
||||
f32[12*id] = i;
|
||||
f32[12*id+1] = 0.0;
|
||||
f32[12*id+2] = first;
|
||||
var vertexCount = (((last - first) / offset) + 1) * 4
|
||||
var f32 = new Float32Array(vertexCount * 3)
|
||||
for (var id = 0, i = first; i <= last; i += offset, id++) {
|
||||
f32[12 * id] = i
|
||||
f32[12 * id + 1] = 0.0
|
||||
f32[12 * id + 2] = first
|
||||
|
||||
f32[12*id+3] = i;
|
||||
f32[12*id+4] = 0.0;
|
||||
f32[12*id+5] = last;
|
||||
f32[12 * id + 3] = i
|
||||
f32[12 * id + 4] = 0.0
|
||||
f32[12 * id + 5] = last
|
||||
|
||||
f32[12*id+6] = first;
|
||||
f32[12*id+7] = 0.0;
|
||||
f32[12*id+8] = i;
|
||||
f32[12 * id + 6] = first
|
||||
f32[12 * id + 7] = 0.0
|
||||
f32[12 * id + 8] = i
|
||||
|
||||
f32[12*id+9] = last;
|
||||
f32[12*id+10] = 0.0;
|
||||
f32[12*id+11] = i;
|
||||
f32[12 * id + 9] = last
|
||||
f32[12 * id + 10] = 0.0
|
||||
f32[12 * id + 11] = i
|
||||
}
|
||||
attribute.count = vertexCount;
|
||||
return f32;
|
||||
attribute.count = vertexCount
|
||||
return f32
|
||||
}
|
||||
return buildGrid(-12, 12, 1, gridPosition);
|
||||
return buildGrid(-12, 12, 1, gridPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,11 @@ import QtQuick.Layouts
|
|||
* It takes the principal point correction into account and handle image ratio to
|
||||
* correctly fit or crop according to original image ratio and parent Item ratio.
|
||||
*/
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
/// The url of the image to display
|
||||
/// The URL of the image to display
|
||||
property alias source: image.source
|
||||
/// Source image ratio
|
||||
property real imageRatio: 1.0
|
||||
|
@ -53,14 +54,13 @@ Item {
|
|||
smooth: false
|
||||
anchors.fill: parent
|
||||
visible: false
|
||||
// Preserver aspect fit while display ratio is aligned with image ratio, crop otherwise
|
||||
fillMode: width/height >= imageRatio ? Image.PreserveAspectFit : Image.PreserveAspectCrop
|
||||
// Preserve aspect fit while display ratio is aligned with image ratio, crop otherwise
|
||||
fillMode: width / height >= imageRatio ? Image.PreserveAspectFit : Image.PreserveAspectCrop
|
||||
autoTransform: true
|
||||
}
|
||||
|
||||
|
||||
// Custom shader for displaying undistorted images
|
||||
// with principal point correction
|
||||
// Custom shader for displaying undistorted images with principal point correction
|
||||
ShaderEffect {
|
||||
id: shader
|
||||
anchors.centerIn: parent
|
||||
|
|
|
@ -352,7 +352,7 @@ FloatingPane {
|
|||
filters: [{role: "label", value: searchBar.text}]
|
||||
delegate: MouseArea {
|
||||
id: mediaDelegate
|
||||
// add mediaLibrary.count in the binding to ensure 'entity'
|
||||
// Add mediaLibrary.count in the binding to ensure 'entity'
|
||||
// is re-evaluated when mediaLibrary delegates are modified
|
||||
property bool loading: model.status === SceneLoader.Loading
|
||||
property bool hovered: model.attribute ? (uigraph ? uigraph.hoveredNode === model.attribute.node : false) : containsMouse
|
||||
|
|
|
@ -11,6 +11,7 @@ import "Materials"
|
|||
* MaterialSwitcher is an Entity that can change its parent's material
|
||||
* by setting the 'mode' property.
|
||||
*/
|
||||
|
||||
Entity {
|
||||
id: root
|
||||
objectName: "MaterialSwitcher"
|
||||
|
@ -28,7 +29,7 @@ Entity {
|
|||
id: m
|
||||
property Material material
|
||||
onMaterialChanged: {
|
||||
// remove previous material(s)
|
||||
// Remove previous material(s)
|
||||
removeComponentsByType(parent, "Material")
|
||||
Scene3DHelper.addComponent(root.parent, material)
|
||||
}
|
||||
|
@ -38,10 +39,8 @@ Entity {
|
|||
{
|
||||
if (!entity)
|
||||
return
|
||||
for (var i = 0; i < entity.components.length; ++i)
|
||||
{
|
||||
for (var i = 0; i < entity.components.length; ++i) {
|
||||
if (entity.components[i].toString().indexOf(type) !== -1) {
|
||||
//entity.components[i].enabled = false;
|
||||
Scene3DHelper.removeComponent(entity, entity.components[i])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ Material {
|
|||
/// Whether to display normals instead of SH
|
||||
property bool displayNormals: false
|
||||
|
||||
// default coefficients (uniform magenta)
|
||||
// Default coefficients (uniform magenta)
|
||||
readonly property var noCoeffs: [
|
||||
Qt.vector3d(0.0, 0.0, 0.0),
|
||||
Qt.vector3d(0.0, 0.0, 0.0),
|
||||
|
@ -29,10 +29,11 @@ Material {
|
|||
effect: SphericalHarmonicsEffect {}
|
||||
|
||||
onShlSourceChanged: {
|
||||
if(!shlSource) {
|
||||
coefficients = noCoeffs;
|
||||
return;
|
||||
if (!shlSource) {
|
||||
coefficients = noCoeffs
|
||||
return
|
||||
}
|
||||
|
||||
Request.get(Filepath.urlToString(shlSource), function(xhr) {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
var coeffs = []
|
||||
|
@ -40,7 +41,8 @@ Material {
|
|||
lines.forEach(function(l) {
|
||||
var lineCoeffs = []
|
||||
l.split(" ").forEach(function(v) {
|
||||
if (v) { lineCoeffs.push(v) }
|
||||
if (v)
|
||||
lineCoeffs.push(v)
|
||||
})
|
||||
if (lineCoeffs.length == 3)
|
||||
coeffs.push(Qt.vector3d(lineCoeffs[0], lineCoeffs[1], lineCoeffs[2]))
|
||||
|
|
|
@ -10,7 +10,7 @@ Entity {
|
|||
/// Enable debug mode (show cache entity with a scale applied)
|
||||
property bool debug: false
|
||||
|
||||
enabled: false // disabled entity
|
||||
enabled: false // Disabled entity
|
||||
|
||||
components: [
|
||||
Transform {
|
||||
|
@ -58,7 +58,7 @@ Entity {
|
|||
if (debug) { console.log("[cache] add: " + source) }
|
||||
mediaCache[source] = object
|
||||
object.parent = root
|
||||
// remove oldest entry in cache
|
||||
// Remove oldest entry in cache
|
||||
if (currentSize() > cacheSize)
|
||||
shrink()
|
||||
return true
|
||||
|
@ -72,7 +72,7 @@ Entity {
|
|||
var obj = mediaCache[source]
|
||||
delete mediaCache[source]
|
||||
if (debug) { console.log("[cache] pop: " + source) }
|
||||
// delete cached obj if file does not exist on disk anymore
|
||||
// Delete cached obj if file does not exist on disk anymore
|
||||
if (!Filepath.exists(source)) {
|
||||
if (debug) { console.log("[cache] destroy: " + source) }
|
||||
obj.destroy()
|
||||
|
|
|
@ -9,13 +9,14 @@ import Utils 1.0
|
|||
* MediaLibrary is an Entity that loads and manages a list of 3D media.
|
||||
* It also uses an internal cache to instantly reload media.
|
||||
*/
|
||||
|
||||
Entity {
|
||||
id: root
|
||||
|
||||
readonly property alias model: m.mediaModel
|
||||
property int renderMode
|
||||
property bool pickingEnabled: false
|
||||
readonly property alias count: instantiator.count // number of instantiated media delegates
|
||||
readonly property alias count: instantiator.count // Number of instantiated media delegates
|
||||
|
||||
// For TransformGizmo in BoundingBox
|
||||
property DefaultCameraController sceneCameraController
|
||||
|
@ -47,10 +48,10 @@ Entity {
|
|||
"valid": true,
|
||||
"label": "",
|
||||
"visible": true,
|
||||
"hasBoundingBox": false, // for Meshing node only
|
||||
"displayBoundingBox": true, // for Meshing node only
|
||||
"hasTransform": false, // for SfMTransform node only
|
||||
"displayTransform": true, // for SfMTransform node only
|
||||
"hasBoundingBox": false, // For Meshing node only
|
||||
"displayBoundingBox": true, // For Meshing node only
|
||||
"hasTransform": false, // For SfMTransform node only
|
||||
"displayTransform": true, // For SfMTransform node only
|
||||
"section": "",
|
||||
"attribute": null,
|
||||
"entity": null,
|
||||
|
@ -71,7 +72,7 @@ Entity {
|
|||
}
|
||||
|
||||
function ensureVisible(source) {
|
||||
var idx = find(source);
|
||||
var idx = find(source)
|
||||
if (idx === -1)
|
||||
return
|
||||
m.mediaModel.get(idx).visible = true
|
||||
|
@ -194,7 +195,7 @@ Entity {
|
|||
// Whether MediaLoader has been fully instantiated by the NodeInstantiator
|
||||
property bool fullyInstantiated: false
|
||||
|
||||
// explicitly store some attached model properties for outside use and ease binding
|
||||
// Explicitly store some attached model properties for outside use and ease binding
|
||||
readonly property var attribute: model.attribute
|
||||
readonly property int idx: index
|
||||
readonly property var modelSource: attribute || model.source
|
||||
|
@ -340,7 +341,7 @@ Entity {
|
|||
}
|
||||
|
||||
// Transform: display a TransformGizmo for SfMTransform node only
|
||||
// note: use a NodeInstantiator to evaluate if the current node is a SfMTransform node and if the transform mode is set to Manual
|
||||
// Note: use a NodeInstantiator to evaluate if the current node is a SfMTransform node and if the transform mode is set to Manual
|
||||
NodeInstantiator {
|
||||
id: sfmTransformGizmoInstantiator
|
||||
active: instantiatedEntity.hasTransform
|
||||
|
@ -362,7 +363,7 @@ Entity {
|
|||
}
|
||||
|
||||
// BoundingBox: display bounding box for MESHING computation
|
||||
// note: use a NodeInstantiator to evaluate if the current node is a MESHING node and if the checkbox is active
|
||||
// Note: use a NodeInstantiator to evaluate if the current node is a MESHING node and if the checkbox is active
|
||||
NodeInstantiator {
|
||||
id: boundingBoxInstantiator
|
||||
active: instantiatedEntity.hasBoundingBox
|
||||
|
|
|
@ -7,11 +7,11 @@ import QtQuick.Scene3D 2.6
|
|||
import "Materials"
|
||||
import Utils 1.0
|
||||
|
||||
|
||||
/**
|
||||
* MediaLoader provides a single entry point for 3D media loading.
|
||||
* It encapsulates all available plugins/loaders.
|
||||
*/
|
||||
|
||||
Entity {
|
||||
id: root
|
||||
|
||||
|
@ -32,7 +32,7 @@ import Utils 1.0
|
|||
return
|
||||
}
|
||||
|
||||
// clear previously created object if any
|
||||
// Clear previously created object if any
|
||||
if (object) {
|
||||
object.destroy()
|
||||
object = null
|
||||
|
@ -48,13 +48,11 @@ import Utils 1.0
|
|||
|
||||
switch (Filepath.extension(source)) {
|
||||
case ".ply":
|
||||
if ((Filepath.extension(Filepath.removeExtension(source))) == ".pc")
|
||||
{
|
||||
if ((Filepath.extension(Filepath.removeExtension(source))) == ".pc") {
|
||||
if (Viewer3DSettings.supportSfmData)
|
||||
component = sfmDataLoaderEntityComponent
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
component = sceneLoaderEntityComponent
|
||||
}
|
||||
break
|
||||
|
@ -108,28 +106,28 @@ import Utils 1.0
|
|||
id: sfmDataLoaderEntity
|
||||
Component.onCompleted: {
|
||||
var obj = Viewer3DSettings.sfmDataLoaderComp.createObject(sfmDataLoaderEntity, {
|
||||
'source': source,
|
||||
'pointSize': Qt.binding(function() { return 0.01 * Viewer3DSettings.pointSize }),
|
||||
'locatorScale': Qt.binding(function() { return Viewer3DSettings.cameraScale }),
|
||||
'cameraPickingEnabled': Qt.binding(function() { return root.enabled }),
|
||||
'resectionId': Qt.binding(function() { return Viewer3DSettings.resectionId }),
|
||||
'displayResections': Qt.binding(function() { return Viewer3DSettings.displayResectionIds }),
|
||||
'syncPickedViewId': Qt.binding(function() { return Viewer3DSettings.syncWithPickedViewId })
|
||||
"source": source,
|
||||
"pointSize": Qt.binding(function() { return 0.01 * Viewer3DSettings.pointSize }),
|
||||
"locatorScale": Qt.binding(function() { return Viewer3DSettings.cameraScale }),
|
||||
"cameraPickingEnabled": Qt.binding(function() { return root.enabled }),
|
||||
"resectionId": Qt.binding(function() { return Viewer3DSettings.resectionId }),
|
||||
"displayResections": Qt.binding(function() { return Viewer3DSettings.displayResectionIds }),
|
||||
"syncPickedViewId": Qt.binding(function() { return Viewer3DSettings.syncWithPickedViewId })
|
||||
});
|
||||
|
||||
obj.statusChanged.connect(function() {
|
||||
if (obj.status === SceneLoader.Ready) {
|
||||
for (var i = 0; i < obj.pointClouds.length; ++i) {
|
||||
vertexCount += Scene3DHelper.vertexCount(obj.pointClouds[i]);
|
||||
vertexCount += Scene3DHelper.vertexCount(obj.pointClouds[i])
|
||||
}
|
||||
cameraCount = obj.spawnCameraSelectors();
|
||||
cameraCount = obj.spawnCameraSelectors()
|
||||
}
|
||||
Viewer3DSettings.resectionIdCount = obj.countResectionIds();
|
||||
Viewer3DSettings.resectionGroups = obj.countResectionGroups(Viewer3DSettings.resectionIdCount + 1);
|
||||
Viewer3DSettings.resectionIdCount = obj.countResectionIds()
|
||||
Viewer3DSettings.resectionGroups = obj.countResectionGroups(Viewer3DSettings.resectionIdCount + 1)
|
||||
resectionIdCount = Viewer3DSettings.resectionIdCount
|
||||
resectionGroups = Viewer3DSettings.resectionGroups
|
||||
resectionId = Viewer3DSettings.resectionIdCount
|
||||
root.status = obj.status;
|
||||
root.status = obj.status
|
||||
})
|
||||
|
||||
obj.cameraSelected.connect(
|
||||
|
@ -158,7 +156,7 @@ import Utils 1.0
|
|||
// - [1] as a depth map
|
||||
var obj = Viewer3DSettings.depthMapLoaderComp.createObject(
|
||||
exrLoaderEntity, {
|
||||
'source': source
|
||||
"source": source
|
||||
})
|
||||
|
||||
if (obj.status === SceneLoader.Ready) {
|
||||
|
@ -172,8 +170,8 @@ import Utils 1.0
|
|||
root.status = SceneLoader.Loading
|
||||
obj = Qt.createComponent("EnvironmentMapEntity.qml").createObject(
|
||||
exrLoaderEntity, {
|
||||
'source': source,
|
||||
'position': Qt.binding(function() { return root.camera.position })
|
||||
"source": source,
|
||||
"position": Qt.binding(function() { return root.camera.position })
|
||||
})
|
||||
obj.statusChanged.connect(function() {
|
||||
root.status = obj.status;
|
||||
|
@ -208,9 +206,9 @@ import Utils 1.0
|
|||
{
|
||||
var comp = entity.components[i]
|
||||
|
||||
// handle DiffuseMapMaterials created by SceneLoader
|
||||
// Handle DiffuseMapMaterials created by SceneLoader
|
||||
if (comp.toString().indexOf("QDiffuseMapMaterial") > -1) {
|
||||
// store material definition
|
||||
// Store material definition
|
||||
var m = {
|
||||
"diffuseMap": comp.diffuse.data[0].source,
|
||||
"shininess": comp.shininess,
|
||||
|
@ -224,19 +222,19 @@ import Utils 1.0
|
|||
}
|
||||
|
||||
if (comp.toString().indexOf("QPhongMaterial") > -1) {
|
||||
// create MaterialSwitcher with default colors
|
||||
// Create MaterialSwitcher with default colors
|
||||
mats.push({})
|
||||
componentsToRemove.push(comp)
|
||||
}
|
||||
}
|
||||
|
||||
mats.forEach(function(m) {
|
||||
// create a material switcher for each material definition
|
||||
// Create a material switcher for each material definition
|
||||
var matSwitcher = materialSwitcherComponent.createObject(entity, m)
|
||||
matSwitcher.mode = Qt.binding(function(){ return root.renderMode })
|
||||
matSwitcher.mode = Qt.binding(function() { return root.renderMode })
|
||||
})
|
||||
|
||||
// remove replaced components
|
||||
// Remove replaced components
|
||||
componentsToRemove.forEach(function(comp) {
|
||||
Scene3DHelper.removeComponent(entity, comp)
|
||||
})
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import QtQuick
|
||||
import Qt3D.Core 2.6
|
||||
|
||||
|
||||
/**
|
||||
* MediaLoaderEntity provides a unified interface for accessing statistics
|
||||
* of a 3D media independently from the way it was loaded.
|
||||
*/
|
||||
|
||||
Entity {
|
||||
property url source
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import QtQuick
|
|||
* Gizmo for SfMTransform node.
|
||||
* Uses EntityWithGizmo wrapper because we should not instantiate TransformGizmo alone.
|
||||
*/
|
||||
|
||||
Entity {
|
||||
id: root
|
||||
property DefaultCameraController sceneCameraController
|
||||
|
|
|
@ -8,13 +8,13 @@ import QtQuick.Controls
|
|||
|
||||
import Utils 1.0
|
||||
|
||||
|
||||
/**
|
||||
* Simple transformation gizmo entirely made with Qt3D entities.
|
||||
* Uses Python Transformations3DHelper to compute matrices.
|
||||
* This TransformGizmo entity should only be instantiated in EntityWithGizmo entity which is its wrapper.
|
||||
* It means, to use it for a specified application, make sure to instantiate EntityWithGizmo.
|
||||
*/
|
||||
|
||||
Entity {
|
||||
id: root
|
||||
property Camera camera
|
||||
|
@ -284,7 +284,8 @@ Entity {
|
|||
const gizmoToCameraVector = camera.position.toVector4d().minus(gizmoCenterPoint)
|
||||
const orientation = gizmoLocalAxisVector.dotProduct(gizmoToCameraVector) > 0 ? 1 : -1
|
||||
|
||||
if (angle !== 0) doRelativeRotation(objectPicker.modelMatrix, pickedAxis, angle * orientation) // Do a rotation from the initial Object Model Matrix when we picked the gizmo
|
||||
if (angle !== 0)
|
||||
doRelativeRotation(objectPicker.modelMatrix, pickedAxis, angle * orientation) // Do a rotation from the initial Object Model Matrix when we picked the gizmo
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -564,7 +565,7 @@ Entity {
|
|||
// These three surfaces have "forward direction". The three othersurfaces have "backward direction".
|
||||
NodeInstantiator {
|
||||
model: 2
|
||||
active: !root.uniformScale // shouldn't be active for SfmTransform Gizmo node for example
|
||||
active: !root.uniformScale // Shouldn't be active for SfmTransform Gizmo node for example
|
||||
|
||||
Entity {
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ FocusScope {
|
|||
readonly property var viewpoint: _reconstruction ? _reconstruction.selectedViewpoint : null
|
||||
readonly property bool doSyncViewpointCamera: Viewer3DSettings.syncViewpointCamera && (viewpoint && viewpoint.isReconstructed)
|
||||
|
||||
// functions
|
||||
// Functions
|
||||
function resetCameraPosition() {
|
||||
mainCamera.position = defaultCamPosition
|
||||
mainCamera.upVector = defaultCamUpVector
|
||||
|
@ -63,7 +63,7 @@ FocusScope {
|
|||
id: scene3D
|
||||
anchors.fill: parent
|
||||
cameraAspectRatioMode: Scene3D.AutomaticAspectRatio // vs. UserAspectRatio
|
||||
hoverEnabled: true // if true, will trigger positionChanged events in attached MouseHandler
|
||||
hoverEnabled: true // If true, will trigger positionChanged events in attached MouseHandler
|
||||
aspects: ["logic", "input"]
|
||||
focus: true
|
||||
|
||||
|
@ -85,9 +85,9 @@ FocusScope {
|
|||
|
||||
Keys.onPressed: function(event) {
|
||||
if (event.key === Qt.Key_F) {
|
||||
resetCameraPosition();
|
||||
resetCameraPosition()
|
||||
} else if (Qt.Key_1 <= event.key && event.key < Qt.Key_1 + Viewer3DSettings.renderModes.length) {
|
||||
Viewer3DSettings.renderMode = event.key - Qt.Key_1;
|
||||
Viewer3DSettings.renderMode = event.key - Qt.Key_1
|
||||
} else {
|
||||
event.accepted = false
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ FocusScope {
|
|||
|
||||
components: [
|
||||
RenderSettings {
|
||||
pickingSettings.pickMethod: PickingSettings.PrimitivePicking // enables point/edge/triangle picking
|
||||
pickingSettings.pickMethod: PickingSettings.PrimitivePicking // Enables point/edge/triangle picking
|
||||
pickingSettings.pickResultMode: PickingSettings.NearestPick
|
||||
renderPolicy: RenderSettings.Always
|
||||
|
||||
|
@ -326,7 +326,7 @@ FocusScope {
|
|||
font.pointSize: 11
|
||||
onClicked: Viewer3DSettings.renderMode = index
|
||||
checked: Viewer3DSettings.renderMode === index
|
||||
checkable: !checked // hack to disabled check on toggle
|
||||
checkable: !checked // Hack to disabled check on toggle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,22 +6,23 @@ import MaterialIcons 2.2
|
|||
/**
|
||||
* Viewer3DSettings singleton gathers properties related to the 3D Viewer capabilities, state and display options.
|
||||
*/
|
||||
|
||||
Item {
|
||||
readonly property Component sfmDataLoaderComp: Qt.createComponent("SfmDataLoader.qml")
|
||||
readonly property bool supportSfmData: sfmDataLoaderComp.status == Component.Ready
|
||||
readonly property Component depthMapLoaderComp: Qt.createComponent("DepthMapLoader.qml")
|
||||
readonly property bool supportDepthMap: depthMapLoaderComp.status == Component.Ready
|
||||
|
||||
// supported 3D files extensions
|
||||
// Supported 3D files extensions
|
||||
readonly property var supportedExtensions: {
|
||||
var exts = ['.obj', '.stl', '.fbx', '.gltf', '.ply'];
|
||||
var exts = [".obj", ".stl", ".fbx", ".gltf", ".ply"];
|
||||
if (supportSfmData) {
|
||||
exts.push('.abc')
|
||||
exts.push('.json')
|
||||
exts.push('.sfm')
|
||||
exts.push(".abc")
|
||||
exts.push(".json")
|
||||
exts.push(".sfm")
|
||||
}
|
||||
if (supportDepthMap)
|
||||
exts.push('.exr')
|
||||
exts.push(".exr")
|
||||
|
||||
return exts;
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@ import QtQuick
|
|||
import Qt3D.Core 2.6
|
||||
import Qt3D.Render 2.6
|
||||
|
||||
|
||||
/**
|
||||
* ViewpointCamera sets up a Camera to match a Viewpoint's internal parameters.
|
||||
*/
|
||||
|
||||
Entity {
|
||||
id: root
|
||||
|
||||
|
@ -51,5 +51,4 @@ Entity {
|
|||
}
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -143,8 +143,7 @@ ApplicationWindow {
|
|||
// Check and return whether no local computation is in progress
|
||||
function ensureNotComputing()
|
||||
{
|
||||
if (_reconstruction.computingLocally)
|
||||
{
|
||||
if (_reconstruction.computingLocally) {
|
||||
// Open a warning dialog to ask for computation to be stopped
|
||||
mainStack.currentItem.computingAtExitDialog.open()
|
||||
return false
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue