mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-04-28 17:57:16 +02:00
407 lines
18 KiB
QML
407 lines
18 KiB
QML
import QtQuick 2.15
|
|
import QtQuick.Controls 2.3
|
|
import QtQuick.Layouts 1.3
|
|
import MaterialIcons 2.2
|
|
import Qt3D.Core 2.15
|
|
import Qt3D.Render 2.15
|
|
import QtQuick.Controls.Material 2.4
|
|
import Controls 1.0
|
|
import Utils 1.0
|
|
|
|
FloatingPane {
|
|
id: root
|
|
|
|
implicitWidth: 200
|
|
|
|
property int renderMode: 2
|
|
property Grid3D grid: null
|
|
property MediaLibrary mediaLibrary
|
|
property Camera camera
|
|
property var uigraph: null
|
|
|
|
signal mediaFocusRequest(var index)
|
|
signal mediaRemoveRequest(var index)
|
|
signal nodeActivated(var node)
|
|
|
|
padding: 0
|
|
|
|
MouseArea { anchors.fill: parent; onWheel: wheel.accepted = true }
|
|
|
|
ColumnLayout {
|
|
anchors.fill: parent
|
|
spacing: 4
|
|
|
|
Group {
|
|
Layout.fillWidth: true
|
|
title: "DISPLAY"
|
|
|
|
GridLayout {
|
|
width: parent.width
|
|
columns: 2
|
|
columnSpacing: 6
|
|
rowSpacing: 3
|
|
Flow {
|
|
Layout.columnSpan: 2
|
|
Layout.fillWidth: true
|
|
spacing: 1
|
|
MaterialToolButton {
|
|
text: MaterialIcons.grid_on
|
|
ToolTip.text: "Display Grid"
|
|
checked: Viewer3DSettings.displayGrid
|
|
onClicked: Viewer3DSettings.displayGrid = !Viewer3DSettings.displayGrid
|
|
}
|
|
MaterialToolButton {
|
|
text: MaterialIcons.adjust
|
|
checked: Viewer3DSettings.displayGizmo
|
|
ToolTip.text: "Display Trackball"
|
|
onClicked: Viewer3DSettings.displayGizmo = !Viewer3DSettings.displayGizmo
|
|
}
|
|
MaterialToolButton {
|
|
text: MaterialIcons.call_merge
|
|
ToolTip.text: "Display Origin"
|
|
checked: Viewer3DSettings.displayOrigin
|
|
onClicked: Viewer3DSettings.displayOrigin = !Viewer3DSettings.displayOrigin
|
|
}
|
|
}
|
|
MaterialLabel { text: MaterialIcons.grain; padding: 2 }
|
|
RowLayout {
|
|
Slider {
|
|
Layout.fillWidth: true; from: 0; to: 5; stepSize: 0.1
|
|
value: Viewer3DSettings.pointSize
|
|
onValueChanged: Viewer3DSettings.pointSize = value
|
|
ToolTip.text: "Point Size: " + value.toFixed(2)
|
|
ToolTip.visible: hovered || pressed
|
|
ToolTip.delay: 150
|
|
}
|
|
MaterialToolButton {
|
|
text: MaterialIcons.center_focus_strong
|
|
ToolTip.text: "Fixed Point Size"
|
|
font.pointSize: 10
|
|
padding: 3
|
|
checked: Viewer3DSettings.fixedPointSize
|
|
onClicked: Viewer3DSettings.fixedPointSize = !Viewer3DSettings.fixedPointSize
|
|
}
|
|
|
|
}
|
|
MaterialLabel { text: MaterialIcons.videocam; padding: 2 }
|
|
Slider {
|
|
value: Viewer3DSettings.cameraScale
|
|
from: 0
|
|
to: 2
|
|
stepSize: 0.01
|
|
Layout.fillWidth: true
|
|
padding: 0
|
|
onMoved: Viewer3DSettings.cameraScale = value
|
|
ToolTip.text: "Camera Scale: " + value.toFixed(2)
|
|
ToolTip.visible: hovered || pressed
|
|
ToolTip.delay: 150
|
|
}
|
|
}
|
|
}
|
|
|
|
Group {
|
|
Layout.fillWidth: true
|
|
title: "CAMERA"
|
|
ColumnLayout {
|
|
width: parent.width
|
|
|
|
// Image/Camera synchronization
|
|
Flow {
|
|
Layout.fillWidth: true
|
|
spacing: 2
|
|
// Synchronization
|
|
MaterialToolButton {
|
|
id: syncViewpointCamera
|
|
enabled: _reconstruction.sfmReport
|
|
text: MaterialIcons.linked_camera
|
|
ToolTip.text: "Sync with Image Selection"
|
|
checked: enabled && Viewer3DSettings.syncViewpointCamera
|
|
onClicked: Viewer3DSettings.syncViewpointCamera = !Viewer3DSettings.syncViewpointCamera
|
|
}
|
|
// Image Overlay controls
|
|
RowLayout {
|
|
visible: syncViewpointCamera.enabled && Viewer3DSettings.syncViewpointCamera
|
|
spacing: 2
|
|
// Activation
|
|
MaterialToolButton {
|
|
text: MaterialIcons.image
|
|
ToolTip.text: "Image Overlay"
|
|
checked: Viewer3DSettings.viewpointImageOverlay
|
|
onClicked: Viewer3DSettings.viewpointImageOverlay = !Viewer3DSettings.viewpointImageOverlay
|
|
}
|
|
// Opacity
|
|
Slider {
|
|
visible: Viewer3DSettings.showViewpointImageOverlay
|
|
implicitWidth: 60
|
|
from: 0
|
|
to: 100
|
|
value: Viewer3DSettings.viewpointImageOverlayOpacity * 100
|
|
onValueChanged: Viewer3DSettings.viewpointImageOverlayOpacity = value / 100
|
|
ToolTip.text: "Image Opacity: " + Viewer3DSettings.viewpointImageOverlayOpacity.toFixed(2)
|
|
ToolTip.visible: hovered || pressed
|
|
ToolTip.delay: 100
|
|
}
|
|
}
|
|
// Image Frame control
|
|
MaterialToolButton {
|
|
visible: syncViewpointCamera.enabled && Viewer3DSettings.showViewpointImageOverlay
|
|
enabled: Viewer3DSettings.syncViewpointCamera
|
|
text: MaterialIcons.crop_free
|
|
ToolTip.text: "Frame Overlay"
|
|
checked: Viewer3DSettings.viewpointImageFrame
|
|
onClicked: Viewer3DSettings.viewpointImageFrame = !Viewer3DSettings.viewpointImageFrame
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 3D Scene content
|
|
Group {
|
|
title: "SCENE"
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
sidePadding: 0
|
|
|
|
toolBarContent: MaterialToolButton {
|
|
id: infoButton
|
|
ToolTip.text: "Media Info"
|
|
text: MaterialIcons.info_outline
|
|
font.pointSize: 10
|
|
implicitHeight: parent.height
|
|
checkable: true
|
|
checked: true
|
|
}
|
|
|
|
ListView {
|
|
id: mediaListView
|
|
anchors.fill: parent
|
|
clip: true
|
|
model: mediaLibrary.model
|
|
spacing: 4
|
|
|
|
ScrollBar.vertical: ScrollBar { id: scrollBar }
|
|
|
|
currentIndex: -1
|
|
|
|
Connections {
|
|
target: uigraph
|
|
function onSelectedNodeChanged() {
|
|
mediaListView.currentIndex = -1
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: mediaLibrary
|
|
function onLoadRequest() {
|
|
mediaListView.positionViewAtIndex(idx, ListView.Visible);
|
|
}
|
|
}
|
|
|
|
delegate: MouseArea {
|
|
id: mediaDelegate
|
|
// 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.hoveredNode === model.attribute.node : containsMouse
|
|
property bool isSelectedNode: model.attribute ? uigraph.selectedNode === model.attribute.node : false
|
|
|
|
onIsSelectedNodeChanged: updateCurrentIndex()
|
|
|
|
function updateCurrentIndex() {
|
|
if(isSelectedNode) { mediaListView.currentIndex = index }
|
|
}
|
|
|
|
height: childrenRect.height
|
|
width: parent.width - scrollBar.width
|
|
|
|
hoverEnabled: true
|
|
onEntered: { if(model.attribute) uigraph.hoveredNode = model.attribute.node }
|
|
onExited: { if(model.attribute) uigraph.hoveredNode = null }
|
|
onClicked: {
|
|
if(model.attribute)
|
|
uigraph.selectedNode = model.attribute.node;
|
|
else
|
|
uigraph.selectedNode = null;
|
|
if(mouse.button == Qt.RightButton)
|
|
contextMenu.popup();
|
|
mediaListView.currentIndex = index;
|
|
}
|
|
onDoubleClicked: {
|
|
model.visible = true;
|
|
nodeActivated(model.attribute.node);
|
|
}
|
|
|
|
RowLayout {
|
|
width: parent.width
|
|
spacing: 2
|
|
|
|
property string src: model.source
|
|
onSrcChanged: focusAnim.restart()
|
|
|
|
Connections {
|
|
target: mediaListView
|
|
onCountChanged: mediaDelegate.updateCurrentIndex()
|
|
}
|
|
|
|
// Current/selected element indicator
|
|
Rectangle {
|
|
Layout.fillHeight: true
|
|
width: 2
|
|
color: {
|
|
if(mediaListView.currentIndex == index || mediaDelegate.isSelectedNode)
|
|
return label.palette.highlight;
|
|
if(mediaDelegate.hovered)
|
|
return Qt.darker(label.palette.highlight, 1.5);
|
|
return "transparent";
|
|
}
|
|
}
|
|
|
|
// Media visibility/loading control
|
|
MaterialToolButton {
|
|
Layout.alignment: Qt.AlignTop
|
|
Layout.fillHeight: true
|
|
text: model.visible ? MaterialIcons.visibility : MaterialIcons.visibility_off
|
|
font.pointSize: 10
|
|
ToolTip.text: model.visible ? "Hide" : model.requested ? "Show" : model.valid ? "Load and Show" : "Load and Show when Available"
|
|
flat: true
|
|
opacity: model.visible ? 1.0 : 0.6
|
|
onClicked: {
|
|
if(hoverArea.modifiers & Qt.ControlModifier)
|
|
mediaLibrary.solo(index);
|
|
else
|
|
model.visible = !model.visible
|
|
}
|
|
// Handle modifiers on button click
|
|
MouseArea {
|
|
id: hoverArea
|
|
property int modifiers
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onPositionChanged: modifiers = mouse.modifiers
|
|
onExited: modifiers = Qt.NoModifier
|
|
onPressed: {
|
|
modifiers = mouse.modifiers;
|
|
mouse.accepted = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Media label and info
|
|
Item {
|
|
implicitHeight: childrenRect.height
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignTop
|
|
ColumnLayout {
|
|
id: centralLayout
|
|
width: parent.width
|
|
spacing: 1
|
|
|
|
Label {
|
|
id: label
|
|
Layout.fillWidth: true
|
|
leftPadding: 0
|
|
rightPadding: 0
|
|
topPadding: 3
|
|
bottomPadding: topPadding
|
|
text: model.label
|
|
opacity: model.valid ? 1.0 : 0.6
|
|
elide: Text.ElideMiddle
|
|
font.weight: mediaListView.currentIndex == index ? Font.DemiBold : Font.Normal
|
|
background: Rectangle {
|
|
Connections {
|
|
target: mediaLibrary
|
|
onLoadRequest: if(idx == index) focusAnim.restart()
|
|
}
|
|
ColorAnimation on color {
|
|
id: focusAnim
|
|
from: label.palette.highlight
|
|
to: "transparent"
|
|
duration: 2000
|
|
}
|
|
}
|
|
}
|
|
Item {
|
|
visible: infoButton.checked
|
|
Layout.fillWidth: true
|
|
implicitHeight: childrenRect.height
|
|
Flow {
|
|
width: parent.width
|
|
spacing: 4
|
|
visible: model.status === SceneLoader.Ready
|
|
RowLayout {
|
|
spacing: 1
|
|
visible: model.vertexCount
|
|
MaterialLabel { text: MaterialIcons.grain }
|
|
Label { text: Format.intToString(model.vertexCount) }
|
|
}
|
|
RowLayout {
|
|
spacing: 1
|
|
visible: model.faceCount
|
|
MaterialLabel { text: MaterialIcons.details; rotation: -180 }
|
|
Label { text: Format.intToString(model.faceCount) }
|
|
}
|
|
RowLayout {
|
|
spacing: 1
|
|
visible: model.cameraCount
|
|
MaterialLabel { text: MaterialIcons.videocam }
|
|
Label { text: model.cameraCount }
|
|
}
|
|
RowLayout {
|
|
spacing: 1
|
|
visible: model.textureCount
|
|
MaterialLabel { text: MaterialIcons.texture }
|
|
Label { text: model.textureCount }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Menu {
|
|
id: contextMenu
|
|
MenuItem {
|
|
text: "Open Containing Folder"
|
|
enabled: model.valid
|
|
onTriggered: Qt.openUrlExternally(Filepath.dirname(model.source))
|
|
}
|
|
MenuItem {
|
|
text: "Copy Path"
|
|
onTriggered: Clipboard.setText(Filepath.normpath(model.source))
|
|
}
|
|
MenuSeparator {}
|
|
MenuItem {
|
|
text: model.requested ? "Unload Media" : "Load Media"
|
|
enabled: model.valid
|
|
onTriggered: model.requested = !model.requested
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove media from library button
|
|
MaterialToolButton {
|
|
id: removeButton
|
|
Layout.alignment: Qt.AlignTop
|
|
Layout.fillHeight: true
|
|
|
|
visible: !loading && mediaDelegate.containsMouse
|
|
text: MaterialIcons.clear
|
|
font.pointSize: 10
|
|
|
|
ToolTip.text: "Remove"
|
|
ToolTip.delay: 500
|
|
onClicked: mediaLibrary.remove(index)
|
|
}
|
|
|
|
// Media loading indicator
|
|
BusyIndicator {
|
|
visible: loading
|
|
running: visible
|
|
padding: removeButton.padding
|
|
implicitHeight: implicitWidth
|
|
implicitWidth: removeButton.width
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|