[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:
Fabien Castan 2020-03-04 17:24:51 +01:00
parent c9c24b7ff0
commit d70c625fac
4 changed files with 323 additions and 290 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 B

View file

@ -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 {

View file

@ -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
}
}

View file

@ -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