[ui] Viewer3D: synchronize media list and graph hover/selection

* ease bidirectional navigation between 3D media list and graph
* use same mechanism to indicate selected/hovered elements
* remove 'frame' button (space gain + action available on double click)
This commit is contained in:
Yann Lanthony 2018-12-06 19:35:26 +01:00
parent 05854ed897
commit 2f307c16fb
3 changed files with 91 additions and 40 deletions

View file

@ -19,6 +19,7 @@ FloatingPane {
property Grid3D grid: null property Grid3D grid: null
property MediaLibrary mediaLibrary property MediaLibrary mediaLibrary
property Camera camera property Camera camera
property var uigraph: null
signal mediaFocusRequest(var index) signal mediaFocusRequest(var index)
signal mediaRemoveRequest(var index) signal mediaRemoveRequest(var index)
@ -128,6 +129,13 @@ FloatingPane {
} }
} }
currentIndex: -1
Connections {
target: uigraph
onSelectedNodeChanged: mediaListView.currentIndex = -1
}
Connections { Connections {
target: mediaLibrary target: mediaLibrary
onLoadRequest: { onLoadRequest: {
@ -136,6 +144,7 @@ FloatingPane {
} }
delegate: RowLayout { delegate: RowLayout {
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 // is re-evaluated when mediaLibrary delegates are modified
property bool loading: model.status === SceneLoader.Loading property bool loading: model.status === SceneLoader.Loading
@ -145,12 +154,37 @@ FloatingPane {
property string src: model.source property string src: model.source
onSrcChanged: focusAnim.restart() onSrcChanged: focusAnim.restart()
RowLayout { property bool hovered: model.attribute ? uigraph.hoveredNode === model.attribute.node : mouseArea.containsMouse
Layout.alignment: Qt.AlignTop property bool isSelectedNode: model.attribute ? uigraph.selectedNode === model.attribute.node : false
spacing: 0
MaterialToolButton { function updateCurrentIndex() {
text: model.visible ? MaterialIcons.visibility : MaterialIcons.visibility_off if(isSelectedNode) { mediaListView.currentIndex = index }
}
onIsSelectedNodeChanged: updateCurrentIndex()
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
text: model.visible ? MaterialIcons.visibility : MaterialIcons.visibility_off
font.pointSize: 10 font.pointSize: 10
ToolTip.text: model.visible ? "Hide" : "Show" ToolTip.text: model.visible ? "Hide" : "Show"
flat: true flat: true
@ -173,47 +207,42 @@ FloatingPane {
modifiers = mouse.modifiers; modifiers = mouse.modifiers;
mouse.accepted = false; mouse.accepted = false;
} }
}
}
MaterialToolButton {
text: MaterialIcons.filter_center_focus
font.pointSize: 10
ToolTip.text: "Frame"
onClicked: camera.viewEntity(mediaLibrary.entityAt(index))
flat: true
} }
} }
ColumnLayout { // Media label and info
Item {
implicitHeight: childrenRect.height
Layout.fillWidth: true Layout.fillWidth: true
spacing: 1
Layout.alignment: Qt.AlignTop Layout.alignment: Qt.AlignTop
ColumnLayout {
id: centralLayout
width: parent.width
spacing: 1
Label { Label {
id: label id: label
leftPadding: 0 Layout.fillWidth: true
rightPadding: 0 leftPadding: 0
topPadding: 3 rightPadding: 0
bottomPadding: topPadding topPadding: 3
Layout.fillWidth: true bottomPadding: topPadding
text: model.label text: model.label
elide: Text.ElideMiddle opacity: model.valid ? 1.0 : 0.6
background: Rectangle { elide: Text.ElideMiddle
Connections { font.weight: mediaListView.currentIndex == index ? Font.DemiBold : Font.Normal
target: mediaLibrary background: Rectangle {
onLoadRequest: if(idx == index) focusAnim.restart() Connections {
target: mediaLibrary
onLoadRequest: if(idx == index) focusAnim.restart()
}
ColorAnimation on color {
id: focusAnim
from: label.palette.highlight
to: "transparent"
duration: 2000
}
} }
ColorAnimation on color {
id: focusAnim
from: label.palette.highlight
to: "transparent"
duration: 2000
}
MouseArea {
anchors.fill: parent
onDoubleClicked: camera.viewEntity(mediaLibrary.entityAt(index))
}
}
} }
Item { Item {
Layout.fillWidth: true Layout.fillWidth: true
@ -230,6 +259,25 @@ FloatingPane {
Label { visible: model.textureCount; text: model.textureCount } Label { visible: model.textureCount; text: model.textureCount }
} }
} }
}
MouseArea {
id: mouseArea
anchors.fill: centralLayout
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;
mediaListView.currentIndex = index;
}
onDoubleClicked: {
model.visible = true;
camera.viewEntity(mediaLibrary.entityAt(index));
}
}
} }
// Media unavailability indicator // Media unavailability indicator

View file

@ -19,6 +19,7 @@ FocusScope {
property int renderMode: 2 property int renderMode: 2
property alias library: mediaLibrary property alias library: mediaLibrary
property alias inspector: inspector3d
// functions // functions
function resetCameraCenter() { function resetCameraCenter() {
@ -218,7 +219,7 @@ FocusScope {
Item { Layout.fillWidth: true; Layout.minimumWidth: parent.width * 0.5 } Item { Layout.fillWidth: true; Layout.minimumWidth: parent.width * 0.5 }
Inspector3D { Inspector3D {
id: inspector id: inspector3d
width: 220 width: 220
Layout.minimumWidth: 5 Layout.minimumWidth: 5

View file

@ -124,6 +124,8 @@ Item {
readonly property int outputMediaIndex: library.find(outputAttribute) readonly property int outputMediaIndex: library.find(outputAttribute)
anchors.fill: parent anchors.fill: parent
inspector.uigraph: reconstruction
DropArea { DropArea {
anchors.fill: parent anchors.fill: parent
keys: ["text/uri-list"] keys: ["text/uri-list"]