mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-05-22 05:26:29 +02:00
[ui] Viewer2D: refactoring to simplify layouts
* fix mousearea order * add alpha backgroud * move HDR as a tool button Conflicts: meshroom/ui/qml/Viewer/CircleGizmo.qml meshroom/ui/qml/Viewer/Viewer2D.qml
This commit is contained in:
parent
c9c24b7ff0
commit
d70c625fac
4 changed files with 323 additions and 290 deletions
BIN
meshroom/ui/img/checkerboard_light.png
Normal file
BIN
meshroom/ui/img/checkerboard_light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 102 B |
|
@ -46,8 +46,8 @@ FloatingPane {
|
||||||
id: displayModeCB
|
id: displayModeCB
|
||||||
flat: true
|
flat: true
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
model: featuresViewer.displayModes
|
model: root.featuresViewer.displayModes
|
||||||
onActivated: featuresViewer.displayMode = currentIndex
|
onActivated: root.featuresViewer.displayMode = currentIndex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,12 +67,12 @@ FloatingPane {
|
||||||
implicitHeight: contentHeight
|
implicitHeight: contentHeight
|
||||||
implicitWidth: contentItem.childrenRect.width
|
implicitWidth: contentItem.childrenRect.width
|
||||||
|
|
||||||
model: featuresViewer !== null ? featuresViewer.model : 0
|
model: root.featuresViewer !== null ? root.featuresViewer.model : 0
|
||||||
|
|
||||||
delegate: RowLayout {
|
delegate: RowLayout {
|
||||||
id: featureType
|
id: featureType
|
||||||
|
|
||||||
property var viewer: featuresViewer.itemAt(index)
|
property var viewer: root.featuresViewer.itemAt(index)
|
||||||
spacing: 4
|
spacing: 4
|
||||||
|
|
||||||
// Visibility toogle
|
// Visibility toogle
|
||||||
|
@ -86,10 +86,10 @@ FloatingPane {
|
||||||
ColorChart {
|
ColorChart {
|
||||||
implicitWidth: 12
|
implicitWidth: 12
|
||||||
implicitHeight: implicitWidth
|
implicitHeight: implicitWidth
|
||||||
colors: featuresViewer.colors
|
colors: root.featuresViewer.colors
|
||||||
currentIndex: featureType.viewer.colorIndex
|
currentIndex: featureType.viewer.colorIndex
|
||||||
// offset FeaturesViewer color set when changing the color of one feature type
|
// offset featuresViewer color set when changing the color of one feature type
|
||||||
onColorPicked: featuresViewer.colorOffset = colorIndex - index
|
onColorPicked: root.featuresViewer.colorOffset = colorIndex - index
|
||||||
}
|
}
|
||||||
// Feature type name
|
// Feature type name
|
||||||
Label {
|
Label {
|
||||||
|
|
|
@ -13,9 +13,9 @@ FocusScope {
|
||||||
property var metadata
|
property var metadata
|
||||||
property var viewIn3D
|
property var viewIn3D
|
||||||
|
|
||||||
property Component floatViewerComp: Qt.createComponent("FloatImage.qml", imgContainer)
|
property Component floatViewerComp: Qt.createComponent("FloatImage.qml")
|
||||||
readonly property bool floatViewerAvailable: floatViewerComp.status === Component.Ready
|
readonly property bool floatViewerAvailable: floatViewerComp.status === Component.Ready
|
||||||
property bool useFloatImageViewer: false
|
property alias useFloatImageViewer: displayHDR.checked
|
||||||
|
|
||||||
function clear()
|
function clear()
|
||||||
{
|
{
|
||||||
|
@ -31,13 +31,45 @@ FocusScope {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mouse area
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
property double factor: 1.2
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||||
|
onPressed: {
|
||||||
|
imgContainer.forceActiveFocus()
|
||||||
|
if(mouse.button & Qt.MiddleButton || (mouse.button & Qt.LeftButton && mouse.modifiers & Qt.ShiftModifier))
|
||||||
|
drag.target = imgContainer // start drag
|
||||||
|
}
|
||||||
|
onReleased: {
|
||||||
|
drag.target = undefined // stop drag
|
||||||
|
if(mouse.button & Qt.RightButton) {
|
||||||
|
var menu = contextMenu.createObject(root);
|
||||||
|
menu.x = mouse.x;
|
||||||
|
menu.y = mouse.y;
|
||||||
|
menu.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onWheel: {
|
||||||
|
var zoomFactor = wheel.angleDelta.y > 0 ? factor : 1/factor
|
||||||
|
if(Math.min(imgContainer.width, imgContainer.image.height) * imgContainer.scale * zoomFactor < 10)
|
||||||
|
return
|
||||||
|
var point = mapToItem(imgContainer, wheel.x, wheel.y)
|
||||||
|
imgContainer.x += (1-zoomFactor) * point.x * imgContainer.scale
|
||||||
|
imgContainer.y += (1-zoomFactor) * point.y * imgContainer.scale
|
||||||
|
imgContainer.scale *= zoomFactor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// functions
|
// functions
|
||||||
function fit() {
|
function fit() {
|
||||||
if(imgContainer.image.status != Image.Ready)
|
if(imgContainer.image.status != Image.Ready)
|
||||||
return;
|
return;
|
||||||
imgContainer.scale = Math.min(imgContainer.width/imgContainer.image.width, imgContainer.height/imgContainer.image.height)
|
imgContainer.scale = Math.min(imgLayout.width / imgContainer.image.width, root.height / imgContainer.image.height)
|
||||||
imgContainer.x = Math.max((imgContainer.width-imgContainer.width*imgContainer.scale)*0.5, 0)
|
imgContainer.x = Math.max((imgLayout.width - imgContainer.image.width * imgContainer.scale)*0.5, 0)
|
||||||
imgContainer.y = Math.max((imgContainer.height-imgContainer.height*imgContainer.scale)*0.5, 0)
|
imgContainer.y = Math.max((imgLayout.height - imgContainer.image.height * imgContainer.scale)*0.5, 0)
|
||||||
|
// console.warn("fit: imgLayout.width: " + imgContainer.scale + ", imgContainer.image.width: " + imgContainer.image.width)
|
||||||
|
// console.warn("fit: imgContainer.scale: " + imgContainer.scale + ", x: " + imgContainer.x + ", y: " + imgContainer.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getImageFile(type) {
|
function getImageFile(type) {
|
||||||
|
@ -59,20 +91,58 @@ FocusScope {
|
||||||
text: "Zoom 100%"
|
text: "Zoom 100%"
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
imgContainer.scale = 1
|
imgContainer.scale = 1
|
||||||
imgContainer.x = Math.max((imgContainer.width-imgContainer.width*imgContainer.scale)*0.5, 0)
|
imgContainer.x = Math.max((imgLayout.width-imgContainer.width*imgContainer.scale)*0.5, 0)
|
||||||
imgContainer.y = Math.max((imgContainer.height-imgContainer.height*imgContainer.scale)*0.5, 0)
|
imgContainer.y = Math.max((imgLayout.height-imgContainer.height*imgContainer.scale)*0.5, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
ImageToolbar {
|
||||||
|
id: imageToolbar
|
||||||
|
anchors.margins: 0
|
||||||
|
visible: displayImageToolBarAction.checked && displayImageToolBarAction.enabled
|
||||||
|
Layout.fillWidth: true
|
||||||
|
colorRGBA: {
|
||||||
|
if(!floatImageViewerLoader.item ||
|
||||||
|
floatImageViewerLoader.item.status !== Image.Ready)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if(floatImageViewerLoader.item.containsMouse == false)
|
||||||
|
{
|
||||||
|
// console.warn("floatImageViewerLoader: does not contain mouse");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var pix = floatImageViewerLoader.item.pixelValueAt(Math.floor(floatImageViewerLoader.item.mouseX), Math.floor(floatImageViewerLoader.item.mouseY));
|
||||||
|
// console.warn("floatImageViewerLoader: pixel value at (" << floatImageViewerLoader.item.mouseX << "," << floatImageViewerLoader.item.mouseY << "): ", pix);
|
||||||
|
return pix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Image
|
// Image
|
||||||
|
Item {
|
||||||
|
id: imgLayout
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
clip: true
|
||||||
|
Image {
|
||||||
|
id: alphaBackground
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: displayAlphaBackground.checked
|
||||||
|
fillMode: Image.Tile
|
||||||
|
horizontalAlignment: Image.AlignLeft
|
||||||
|
verticalAlignment: Image.AlignTop
|
||||||
|
source: "../../img/checkerboard_light.png"
|
||||||
|
scale: 4
|
||||||
|
smooth: false
|
||||||
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: imgContainer
|
id: imgContainer
|
||||||
transformOrigin: Item.TopLeft
|
transformOrigin: Item.TopLeft
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
|
|
||||||
property var image: qtImageViewerLoader.active ? qtImageViewerLoader.item : floatImageViewerLoader.item
|
|
||||||
|
|
||||||
// qtAliceVision Image Viewer
|
// qtAliceVision Image Viewer
|
||||||
Loader {
|
Loader {
|
||||||
|
@ -131,6 +201,11 @@ FocusScope {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property var image: qtImageViewerLoader.active ? qtImageViewerLoader.item : floatImageViewerLoader.item
|
||||||
|
width: image ? image.width : 1
|
||||||
|
height: image ? image.height : 1
|
||||||
|
scale: 1.0
|
||||||
|
|
||||||
// FeatureViewer: display view extracted feature points
|
// FeatureViewer: display view extracted feature points
|
||||||
// note: requires QtAliceVision plugin - use a Loader to evaluate plugin avaibility at runtime
|
// note: requires QtAliceVision plugin - use a Loader to evaluate plugin avaibility at runtime
|
||||||
Loader {
|
Loader {
|
||||||
|
@ -162,86 +237,19 @@ FocusScope {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Busy indicator
|
|
||||||
BusyIndicator {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
// running property binding seems broken, only dynamic binding assignment works
|
|
||||||
Component.onCompleted: {
|
|
||||||
running = Qt.binding(function() { return imgContainer.image && imgContainer.image.status === Image.Loading })
|
|
||||||
}
|
|
||||||
// disable the visibility when unused to avoid stealing the mouseEvent to the image color picker
|
|
||||||
visible: running
|
|
||||||
}
|
|
||||||
|
|
||||||
// mouse area
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
property double factor: 1.2
|
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
|
||||||
onPressed: {
|
|
||||||
imgContainer.forceActiveFocus()
|
|
||||||
if(mouse.button & Qt.MiddleButton || (mouse.button & Qt.LeftButton && mouse.modifiers & Qt.ShiftModifier))
|
|
||||||
drag.target = imgContainer // start drag
|
|
||||||
}
|
|
||||||
onReleased: {
|
|
||||||
drag.target = undefined // stop drag
|
|
||||||
if(mouse.button & Qt.RightButton) {
|
|
||||||
var menu = contextMenu.createObject(root);
|
|
||||||
menu.x = mouse.x;
|
|
||||||
menu.y = mouse.y;
|
|
||||||
menu.open()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onWheel: {
|
|
||||||
var zoomFactor = wheel.angleDelta.y > 0 ? factor : 1/factor
|
|
||||||
if(Math.min(imgContainer.width, imgContainer.image.height) * imgContainer.scale * zoomFactor < 10)
|
|
||||||
return
|
|
||||||
var point = mapToItem(imgContainer, wheel.x, wheel.y)
|
|
||||||
imgContainer.x += (1-zoomFactor) * point.x * imgContainer.scale
|
|
||||||
imgContainer.y += (1-zoomFactor) * point.y * imgContainer.scale
|
|
||||||
imgContainer.scale *= zoomFactor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: topToolbar
|
anchors.fill: parent
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.margins: 0
|
|
||||||
width: parent.width
|
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
ImageToolbar {
|
|
||||||
id: imageToolbar
|
|
||||||
anchors.margins: 0
|
|
||||||
visible: displayImageToolBarAction.checked && displayImageToolBarAction.enabled
|
|
||||||
Layout.fillWidth: true
|
|
||||||
colorRGBA: {
|
|
||||||
if(!floatImageViewerLoader.item ||
|
|
||||||
floatImageViewerLoader.item.status !== Image.Ready)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if(floatImageViewerLoader.item.containsMouse == false)
|
|
||||||
{
|
|
||||||
// console.warn("floatImageViewerLoader: does not contain mouse");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
var pix = floatImageViewerLoader.item.pixelValueAt(Math.floor(floatImageViewerLoader.item.mouseX), Math.floor(floatImageViewerLoader.item.mouseY));
|
|
||||||
// console.warn("floatImageViewerLoader: pixel value at (" << floatImageViewerLoader.item.mouseX << "," << floatImageViewerLoader.item.mouseY << "): ", pix);
|
|
||||||
return pix;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FloatingPane {
|
FloatingPane {
|
||||||
id: imagePathToolbar
|
id: imagePathToolbar
|
||||||
anchors.margins: 0
|
|
||||||
radius: 0
|
|
||||||
padding: 4
|
|
||||||
visible: displayImagePathAction.checked
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
// Layout.fillHeight: true
|
||||||
|
Layout.preferredHeight: childrenRect.height
|
||||||
|
visible: displayImagePathAction.checked
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
anchors.fill: parent
|
width: parent.width
|
||||||
|
height: childrenRect.height
|
||||||
|
|
||||||
// selectable filepath to source image
|
// selectable filepath to source image
|
||||||
TextField {
|
TextField {
|
||||||
|
@ -249,6 +257,7 @@ FocusScope {
|
||||||
background: Item {}
|
background: Item {}
|
||||||
horizontalAlignment: TextInput.AlignLeft
|
horizontalAlignment: TextInput.AlignLeft
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
height: contentHeight
|
||||||
font.pointSize: 8
|
font.pointSize: 8
|
||||||
readOnly: true
|
readOnly: true
|
||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
|
@ -265,18 +274,22 @@ FocusScope {
|
||||||
horizontalAlignment: TextInput.AlignLeft
|
horizontalAlignment: TextInput.AlignLeft
|
||||||
Layout.fillWidth: false
|
Layout.fillWidth: false
|
||||||
Layout.preferredWidth: contentWidth
|
Layout.preferredWidth: contentWidth
|
||||||
|
height: contentHeight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Item {
|
||||||
|
id: imgPlaceholder
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
|
||||||
// Image Metadata overlay Pane
|
// Image Metadata overlay Pane
|
||||||
ImageMetadataView {
|
ImageMetadataView {
|
||||||
width: 350
|
width: 350
|
||||||
anchors {
|
anchors {
|
||||||
top: topToolbar.bottom
|
top: parent.top
|
||||||
right: parent.right
|
right: parent.right
|
||||||
bottom: bottomToolbar.top
|
bottom: parent.bottom
|
||||||
}
|
}
|
||||||
|
|
||||||
visible: metadataCB.checked
|
visible: metadataCB.checked
|
||||||
|
@ -284,12 +297,13 @@ FocusScope {
|
||||||
metadata: visible ? root.metadata : {}
|
metadata: visible ? root.metadata : {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: featuresOverlay
|
id: featuresOverlay
|
||||||
anchors.bottom: bottomToolbar.top
|
anchors {
|
||||||
anchors.left: parent.left
|
bottom: parent.bottom
|
||||||
anchors.margins: 2
|
left: parent.left
|
||||||
|
margins: 2
|
||||||
|
}
|
||||||
active: displayFeatures.checked
|
active: displayFeatures.checked
|
||||||
|
|
||||||
sourceComponent: FeaturesInfoOverlay {
|
sourceComponent: FeaturesInfoOverlay {
|
||||||
|
@ -298,14 +312,11 @@ FocusScope {
|
||||||
featuresViewer: featuresViewerLoader.item
|
featuresViewer: featuresViewerLoader.item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
FloatingPane {
|
FloatingPane {
|
||||||
id: bottomToolbar
|
id: bottomToolbar
|
||||||
anchors.bottom: parent.bottom
|
Layout.fillWidth: true
|
||||||
anchors.margins: 0
|
Layout.preferredHeight: childrenRect.height
|
||||||
width: parent.width
|
|
||||||
topPadding: 2
|
|
||||||
bottomPadding: topPadding
|
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
@ -315,6 +326,23 @@ FocusScope {
|
||||||
text: ((imgContainer.image && (imgContainer.image.status == Image.Ready)) ? imgContainer.scale.toFixed(2) : "1.00") + "x"
|
text: ((imgContainer.image && (imgContainer.image.status == Image.Ready)) ? imgContainer.scale.toFixed(2) : "1.00") + "x"
|
||||||
state: "xsmall"
|
state: "xsmall"
|
||||||
}
|
}
|
||||||
|
MaterialToolButton {
|
||||||
|
id: displayAlphaBackground
|
||||||
|
font.pointSize: 11
|
||||||
|
ToolTip.text: "Alpha Background"
|
||||||
|
checkable: true
|
||||||
|
text: MaterialIcons.texture
|
||||||
|
}
|
||||||
|
MaterialToolButton {
|
||||||
|
id: displayHDR
|
||||||
|
font.pointSize: 20
|
||||||
|
padding: 0
|
||||||
|
ToolTip.text: "HDR Floating Point Viewer"
|
||||||
|
text: MaterialIcons.hdr_on
|
||||||
|
checkable: true
|
||||||
|
checked: false
|
||||||
|
enabled: root.floatViewerAvailable
|
||||||
|
}
|
||||||
MaterialToolButton {
|
MaterialToolButton {
|
||||||
id: displayFeatures
|
id: displayFeatures
|
||||||
font.pointSize: 11
|
font.pointSize: 11
|
||||||
|
@ -372,7 +400,22 @@ FocusScope {
|
||||||
smooth: false
|
smooth: false
|
||||||
flat: true
|
flat: true
|
||||||
checkable: enabled
|
checkable: enabled
|
||||||
|
enabled: _reconstruction.selectedViewId >= 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Busy indicator
|
||||||
|
BusyIndicator {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
// running property binding seems broken, only dynamic binding assignment works
|
||||||
|
Component.onCompleted: {
|
||||||
|
running = Qt.binding(function() { return imgContainer.image && imgContainer.image.status === Image.Loading })
|
||||||
|
}
|
||||||
|
// disable the visibility when unused to avoid stealing the mouseEvent to the image color picker
|
||||||
|
visible: running
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -95,21 +95,12 @@ Item {
|
||||||
id: imageViewerMenu
|
id: imageViewerMenu
|
||||||
y: parent.height
|
y: parent.height
|
||||||
x: -width + parent.width
|
x: -width + parent.width
|
||||||
Action {
|
|
||||||
id: useFloatImageViewerAction
|
|
||||||
text: "Use HDR Image Viewer"
|
|
||||||
checkable: true
|
|
||||||
checked: false
|
|
||||||
enabled: viewer2D.floatViewerAvailable
|
|
||||||
|
|
||||||
// tooltip: "Floating Point Image Viewer allows to visualize image with the full color dynamic. It is useful for HDR or RAW visualization. (Requires a plugin)"
|
|
||||||
}
|
|
||||||
Action {
|
Action {
|
||||||
id: displayImageToolBarAction
|
id: displayImageToolBarAction
|
||||||
text: "Display HDR Toolbar"
|
text: "Display HDR Toolbar"
|
||||||
checkable: true
|
checkable: true
|
||||||
checked: true
|
checked: true
|
||||||
enabled: useFloatImageViewerAction.checked
|
enabled: viewer2D.useFloatImageViewer
|
||||||
}
|
}
|
||||||
Action {
|
Action {
|
||||||
id: displayImagePathAction
|
id: displayImagePathAction
|
||||||
|
@ -124,7 +115,6 @@ Item {
|
||||||
Viewer2D {
|
Viewer2D {
|
||||||
id: viewer2D
|
id: viewer2D
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
useFloatImageViewer: useFloatImageViewerAction.checked
|
|
||||||
|
|
||||||
viewIn3D: root.load3DMedia
|
viewIn3D: root.load3DMedia
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue