[ui] Inspector3D: simplify handling of scene media items hovering

* add MouseArea at root of media
* use flow to display media info and avoid text clipping
This commit is contained in:
Yann Lanthony 2019-09-11 10:47:49 +02:00
parent 312b9f5e0b
commit 03e91bea49
No known key found for this signature in database
GPG key ID: 519FAE6DF7A70642

View file

@ -21,6 +21,7 @@ FloatingPane {
signal mediaFocusRequest(var index)
signal mediaRemoveRequest(var index)
signal nodeActivated(var node)
padding: 0
@ -194,186 +195,208 @@ FloatingPane {
}
}
delegate: RowLayout {
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
spacing: 2
width: parent.width - scrollBar.width / 2
property string src: model.source
onSrcChanged: focusAnim.restart()
property bool hovered: model.attribute ? uigraph.hoveredNode === model.attribute.node : mouseArea.containsMouse
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 }
}
onIsSelectedNodeChanged: updateCurrentIndex()
height: childrenRect.height
width: parent.width - scrollBar.width
Connections {
target: mediaListView
onCountChanged: mediaDelegate.updateCurrentIndex()
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;
camera.viewEntity(root.mediaLibrary.entityAt(index));
}
// 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";
}
}
RowLayout {
width: parent.width
spacing: 2
// Media visibility/loading control
MaterialToolButton {
Layout.alignment: Qt.AlignTop
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
property string src: model.source
onSrcChanged: focusAnim.restart()
Connections {
target: mediaListView
onCountChanged: mediaDelegate.updateCurrentIndex()
}
// 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;
// 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 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
RowLayout {
visible: model.status === SceneLoader.Ready
MaterialLabel { visible: model.vertexCount; text: MaterialIcons.grain }
Label { visible: model.vertexCount; text: Format.intToString(model.vertexCount) }
MaterialLabel { visible: model.faceCount; text: MaterialIcons.details; rotation: -180 }
Label { visible: model.faceCount; text: Format.intToString(model.faceCount) }
MaterialLabel { visible: model.cameraCount; text: MaterialIcons.videocam }
Label { visible: model.cameraCount; text: model.cameraCount }
MaterialLabel { visible: model.textureCount; text: MaterialIcons.texture }
Label { visible: model.textureCount; text: model.textureCount }
}
}
}
MouseArea {
id: mouseArea
anchors.fill: centralLayout
hoverEnabled: true
acceptedButtons: Qt.AllButtons
onEntered: { if(model.attribute) uigraph.hoveredNode = model.attribute.node }
onExited: { if(model.attribute) uigraph.hoveredNode = null }
// 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(model.attribute)
uigraph.selectedNode = model.attribute.node;
if(hoverArea.modifiers & Qt.ControlModifier)
mediaLibrary.solo(index);
else
uigraph.selectedNode = null;
if(mouse.button == Qt.RightButton)
contextMenu.popup();
mediaListView.currentIndex = index;
model.visible = !model.visible
}
onDoubleClicked: {
model.visible = true;
camera.viewEntity(mediaLibrary.entityAt(index));
// 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;
}
}
}
Menu {
id: contextMenu
MenuItem {
text: "Open Containing Folder"
enabled: model.valid
onTriggered: Qt.openUrlExternally(Filepath.dirname(model.source))
// 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 }
}
}
}
}
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
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
// Remove media from library button
MaterialToolButton {
id: removeButton
Layout.alignment: Qt.AlignTop
Layout.fillHeight: true
visible: hovered || mouseArea.containsMouse && !loading
text: MaterialIcons.clear
font.pointSize: 10
ToolTip.text: "Remove"
onClicked: mediaLibrary.remove(index)
}
visible: !loading && mediaDelegate.containsMouse
text: MaterialIcons.clear
font.pointSize: 10
// Media loading indicator
BusyIndicator {
visible: loading
running: visible
padding: removeButton.padding
implicitHeight: implicitWidth
implicitWidth: removeButton.width
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
}
}
}
}