mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-07-20 18:17:17 +02:00
[ui] improve atts filtering and add search bar ...
...for node attributes and 3D inspector - add search bar for node attributes - add search bar for 3D inspector - improve attributes filtering by adding more flexibility and fixing some issues
This commit is contained in:
parent
6c2e9eb583
commit
b5093ac3a0
6 changed files with 408 additions and 301 deletions
|
@ -112,6 +112,10 @@ class Attribute(BaseObject):
|
||||||
def getLabel(self):
|
def getLabel(self):
|
||||||
return self._label
|
return self._label
|
||||||
|
|
||||||
|
@Slot(str, result=bool)
|
||||||
|
def matchText(self, text):
|
||||||
|
return self.fullLabel.lower().find(text.lower()) > -1
|
||||||
|
|
||||||
def getFullLabel(self):
|
def getFullLabel(self):
|
||||||
""" Full Label includes the name of all parent groups, e.g. 'groupLabel subGroupLabel Label' """
|
""" Full Label includes the name of all parent groups, e.g. 'groupLabel subGroupLabel Label' """
|
||||||
if isinstance(self.root, ListAttribute):
|
if isinstance(self.root, ListAttribute):
|
||||||
|
@ -349,6 +353,7 @@ class Attribute(BaseObject):
|
||||||
isOutput = Property(bool, isOutput.fget, constant=True)
|
isOutput = Property(bool, isOutput.fget, constant=True)
|
||||||
isLinkChanged = Signal()
|
isLinkChanged = Signal()
|
||||||
isLink = Property(bool, isLink.fget, notify=isLinkChanged)
|
isLink = Property(bool, isLink.fget, notify=isLinkChanged)
|
||||||
|
isLinkNested = isLink
|
||||||
hasOutputConnectionsChanged = Signal()
|
hasOutputConnectionsChanged = Signal()
|
||||||
hasOutputConnections = Property(bool, hasOutputConnections.fget, notify=hasOutputConnectionsChanged)
|
hasOutputConnections = Property(bool, hasOutputConnections.fget, notify=hasOutputConnectionsChanged)
|
||||||
isDefault = Property(bool, _isDefault, notify=valueChanged)
|
isDefault = Property(bool, _isDefault, notify=valueChanged)
|
||||||
|
@ -502,10 +507,19 @@ class ListAttribute(Attribute):
|
||||||
for attr in self._value:
|
for attr in self._value:
|
||||||
attr.updateInternals()
|
attr.updateInternals()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def isLinkNested(self):
|
||||||
|
""" Whether the attribute or any of its elements is a link to another attribute. """
|
||||||
|
# note: directly use self.node.graph._edges to avoid using the property that may become invalid at some point
|
||||||
|
return self.isLink \
|
||||||
|
or self.node.graph and self.isInput and self.node.graph._edges \
|
||||||
|
and any(v in self.node.graph._edges.keys() for v in self._value)
|
||||||
|
|
||||||
# Override value property setter
|
# Override value property setter
|
||||||
value = Property(Variant, Attribute._get_value, _set_value, notify=Attribute.valueChanged)
|
value = Property(Variant, Attribute._get_value, _set_value, notify=Attribute.valueChanged)
|
||||||
isDefault = Property(bool, _isDefault, notify=Attribute.valueChanged)
|
isDefault = Property(bool, _isDefault, notify=Attribute.valueChanged)
|
||||||
baseType = Property(str, getBaseType, constant=True)
|
baseType = Property(str, getBaseType, constant=True)
|
||||||
|
isLinkNested = Property(bool, isLinkNested.fget)
|
||||||
|
|
||||||
|
|
||||||
class GroupAttribute(Attribute):
|
class GroupAttribute(Attribute):
|
||||||
|
@ -622,6 +636,10 @@ class GroupAttribute(Attribute):
|
||||||
for attr in self._value:
|
for attr in self._value:
|
||||||
attr.updateInternals()
|
attr.updateInternals()
|
||||||
|
|
||||||
|
@Slot(str, result=bool)
|
||||||
|
def matchText(self, text):
|
||||||
|
return super().matchText(text) or any(c.matchText(text) for c in self._value)
|
||||||
|
|
||||||
# Override value property
|
# Override value property
|
||||||
value = Property(Variant, Attribute._get_value, _set_value, notify=Attribute.valueChanged)
|
value = Property(Variant, Attribute._get_value, _set_value, notify=Attribute.valueChanged)
|
||||||
isDefault = Property(bool, _isDefault, notify=Attribute.valueChanged)
|
isDefault = Property(bool, _isDefault, notify=Attribute.valueChanged)
|
||||||
|
|
|
@ -13,6 +13,7 @@ ListView {
|
||||||
property bool readOnly: false
|
property bool readOnly: false
|
||||||
property int labelWidth: 180
|
property int labelWidth: 180
|
||||||
property bool objectsHideable: true
|
property bool objectsHideable: true
|
||||||
|
property string filterText: ""
|
||||||
|
|
||||||
signal upgradeRequest()
|
signal upgradeRequest()
|
||||||
signal attributeDoubleClicked(var mouse, var attribute)
|
signal attributeDoubleClicked(var mouse, var attribute)
|
||||||
|
@ -24,21 +25,21 @@ ListView {
|
||||||
ScrollBar.vertical: ScrollBar { id: scrollBar }
|
ScrollBar.vertical: ScrollBar { id: scrollBar }
|
||||||
|
|
||||||
delegate: Loader {
|
delegate: Loader {
|
||||||
active: {
|
active: object.enabled && (
|
||||||
object.enabled
|
!objectsHideable
|
||||||
&& (!object.desc.advanced || GraphEditorSettings.showAdvancedAttributes)
|
|| ((!object.desc.advanced || GraphEditorSettings.showAdvancedAttributes)
|
||||||
&& (
|
&& (object.isDefault && GraphEditorSettings.showDefaultAttributes || !object.isDefault && GraphEditorSettings.showModifiedAttributes)
|
||||||
!(object.isDefault || object.isOutput || object.isLink)
|
&& (object.isOutput && GraphEditorSettings.showOutputAttributes || !object.isOutput && GraphEditorSettings.showInputAttributes)
|
||||||
|| !GraphEditorSettings.showOnlyModifiedAttributes
|
&& (object.isLinkNested && GraphEditorSettings.showLinkAttributes || !object.isLink && GraphEditorSettings.showNotLinkAttributes))
|
||||||
|| !objectsHideable
|
) && object.matchText(filterText)
|
||||||
)
|
|
||||||
}
|
|
||||||
visible: active
|
visible: active
|
||||||
|
|
||||||
sourceComponent: AttributeItemDelegate {
|
sourceComponent: AttributeItemDelegate {
|
||||||
width: root.width - scrollBar.width
|
width: root.width - scrollBar.width
|
||||||
readOnly: root.readOnly
|
readOnly: root.readOnly
|
||||||
labelWidth: root.labelWidth
|
labelWidth: root.labelWidth
|
||||||
|
filterText: root.filterText
|
||||||
|
objectsHideable: root.objectsHideable
|
||||||
attribute: object
|
attribute: object
|
||||||
onDoubleClicked: root.attributeDoubleClicked(mouse, attr)
|
onDoubleClicked: root.attributeDoubleClicked(mouse, attr)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ RowLayout {
|
||||||
|
|
||||||
property variant attribute: null
|
property variant attribute: null
|
||||||
property bool readOnly: false // whether the attribute's value can be modified
|
property bool readOnly: false // whether the attribute's value can be modified
|
||||||
|
property bool objectsHideable: true
|
||||||
|
property string filterText: ""
|
||||||
|
|
||||||
property alias label: parameterLabel // accessor to the internal Label (attribute's name)
|
property alias label: parameterLabel // accessor to the internal Label (attribute's name)
|
||||||
property int labelWidth // shortcut to set the fixed size of the Label
|
property int labelWidth // shortcut to set the fixed size of the Label
|
||||||
|
@ -489,32 +491,39 @@ RowLayout {
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBar { id: sb }
|
ScrollBar.vertical: ScrollBar { id: sb }
|
||||||
|
|
||||||
delegate: RowLayout {
|
delegate: Loader{
|
||||||
id: item
|
active: !objectsHideable
|
||||||
property var childAttrib: object
|
|| ((object.isDefault && GraphEditorSettings.showDefaultAttributes || !object.isDefault && GraphEditorSettings.showModifiedAttributes)
|
||||||
layoutDirection: Qt.RightToLeft
|
&& (object.isLinkNested && GraphEditorSettings.showLinkAttributes || !object.isLinkNested && GraphEditorSettings.showNotLinkAttributes))
|
||||||
width: lv.width - sb.width
|
visible: active
|
||||||
Component.onCompleted: {
|
height: item ? implicitHeight : -spacing // compensate for spacing if item is hidden
|
||||||
var cpt = Qt.createComponent("AttributeItemDelegate.qml")
|
sourceComponent: RowLayout {
|
||||||
var obj = cpt.createObject(item,
|
id: item
|
||||||
{'attribute': Qt.binding(function() { return item.childAttrib }),
|
property var childAttrib: object
|
||||||
'readOnly': Qt.binding(function() { return !root.editable })
|
layoutDirection: Qt.RightToLeft
|
||||||
})
|
width: lv.width - sb.width
|
||||||
obj.Layout.fillWidth = true
|
Component.onCompleted: {
|
||||||
obj.label.text = index
|
var cpt = Qt.createComponent("AttributeItemDelegate.qml")
|
||||||
obj.label.horizontalAlignment = Text.AlignHCenter
|
var obj = cpt.createObject(item,
|
||||||
obj.label.verticalAlignment = Text.AlignVCenter
|
{'attribute': Qt.binding(function() { return item.childAttrib }),
|
||||||
obj.doubleClicked.connect(function(attr) {root.doubleClicked(attr)})
|
'readOnly': Qt.binding(function() { return !root.editable })
|
||||||
}
|
})
|
||||||
ToolButton {
|
obj.Layout.fillWidth = true
|
||||||
enabled: root.editable
|
obj.label.text = index
|
||||||
text: MaterialIcons.remove_circle_outline
|
obj.label.horizontalAlignment = Text.AlignHCenter
|
||||||
font.family: MaterialIcons.fontFamily
|
obj.label.verticalAlignment = Text.AlignVCenter
|
||||||
font.pointSize: 11
|
obj.doubleClicked.connect(function(attr) {root.doubleClicked(attr)})
|
||||||
padding: 2
|
}
|
||||||
ToolTip.text: "Remove Element"
|
ToolButton {
|
||||||
ToolTip.visible: hovered
|
enabled: root.editable
|
||||||
onClicked: _reconstruction.removeAttribute(item.childAttrib)
|
text: MaterialIcons.remove_circle_outline
|
||||||
|
font.family: MaterialIcons.fontFamily
|
||||||
|
font.pointSize: 11
|
||||||
|
padding: 2
|
||||||
|
ToolTip.text: "Remove Element"
|
||||||
|
ToolTip.visible: hovered
|
||||||
|
onClicked: _reconstruction.removeAttribute(item.childAttrib)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -531,6 +540,8 @@ RowLayout {
|
||||||
{'model': Qt.binding(function() { return attribute.value }),
|
{'model': Qt.binding(function() { return attribute.value }),
|
||||||
'readOnly': Qt.binding(function() { return root.readOnly }),
|
'readOnly': Qt.binding(function() { return root.readOnly }),
|
||||||
'labelWidth': 100, // reduce label width for children (space gain)
|
'labelWidth': 100, // reduce label width for children (space gain)
|
||||||
|
'objectsHideable': Qt.binding(function() { return root.objectsHideable }),
|
||||||
|
'filterText': Qt.binding(function() { return root.filterText }),
|
||||||
})
|
})
|
||||||
obj.Layout.fillWidth = true;
|
obj.Layout.fillWidth = true;
|
||||||
obj.attributeDoubleClicked.connect(function(attr) {root.doubleClicked(attr)})
|
obj.attributeDoubleClicked.connect(function(attr) {root.doubleClicked(attr)})
|
||||||
|
|
|
@ -8,6 +8,11 @@ import Qt.labs.settings 1.0
|
||||||
Settings {
|
Settings {
|
||||||
category: 'GraphEditor'
|
category: 'GraphEditor'
|
||||||
property bool showAdvancedAttributes: false
|
property bool showAdvancedAttributes: false
|
||||||
property bool showOnlyModifiedAttributes: false
|
property bool showDefaultAttributes: true
|
||||||
|
property bool showModifiedAttributes: true
|
||||||
|
property bool showInputAttributes: true
|
||||||
|
property bool showOutputAttributes: true
|
||||||
|
property bool showLinkAttributes: true
|
||||||
|
property bool showNotLinkAttributes: true
|
||||||
property bool lockOnCompute: true
|
property bool lockOnCompute: true
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,12 @@ Panel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SearchBar {
|
||||||
|
id: searchBar
|
||||||
|
width: 150
|
||||||
|
enabled: tabBar.currentIndex === 0 || tabBar.currentIndex === 5
|
||||||
|
}
|
||||||
|
|
||||||
MaterialToolButton {
|
MaterialToolButton {
|
||||||
text: MaterialIcons.more_vert
|
text: MaterialIcons.more_vert
|
||||||
font.pointSize: 11
|
font.pointSize: 11
|
||||||
|
@ -96,32 +102,79 @@ Panel {
|
||||||
Menu {
|
Menu {
|
||||||
id: settingsMenu
|
id: settingsMenu
|
||||||
y: parent.height
|
y: parent.height
|
||||||
MenuItem {
|
Menu {
|
||||||
id: advancedToggle
|
id: filterAttributesMenu
|
||||||
text: "Advanced Attributes"
|
title: "Filter Attributes"
|
||||||
MaterialLabel {
|
RowLayout {
|
||||||
anchors.right: parent.right; anchors.rightMargin: parent.padding;
|
CheckBox {
|
||||||
text: MaterialIcons.build
|
id: outputToggle
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
text: "Output"
|
||||||
font.pointSize: 8
|
checkable: true
|
||||||
|
checked: GraphEditorSettings.showOutputAttributes
|
||||||
|
onClicked: GraphEditorSettings.showOutputAttributes = !GraphEditorSettings.showOutputAttributes
|
||||||
|
enabled: tabBar.currentIndex === 0
|
||||||
|
}
|
||||||
|
CheckBox {
|
||||||
|
id: inputToggle
|
||||||
|
text: "Input"
|
||||||
|
checkable: true
|
||||||
|
checked: GraphEditorSettings.showInputAttributes
|
||||||
|
onClicked: GraphEditorSettings.showInputAttributes = !GraphEditorSettings.showInputAttributes
|
||||||
|
enabled: tabBar.currentIndex === 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
checkable: true
|
MenuSeparator {}
|
||||||
checked: GraphEditorSettings.showAdvancedAttributes
|
RowLayout {
|
||||||
onClicked: GraphEditorSettings.showAdvancedAttributes = !GraphEditorSettings.showAdvancedAttributes
|
CheckBox {
|
||||||
}
|
id: defaultToggle
|
||||||
MenuItem {
|
text: "Default"
|
||||||
id: modifiedToggle
|
checkable: true
|
||||||
text: "Only Modified Attributes"
|
checked: GraphEditorSettings.showDefaultAttributes
|
||||||
MaterialLabel {
|
onClicked: GraphEditorSettings.showDefaultAttributes = !GraphEditorSettings.showDefaultAttributes
|
||||||
anchors.right: parent.right; anchors.rightMargin: parent.padding;
|
enabled: tabBar.currentIndex === 0
|
||||||
text: MaterialIcons.edit
|
}
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
CheckBox {
|
||||||
font.pointSize: 8
|
id: modifiedToggle
|
||||||
|
text: "Modified"
|
||||||
|
checkable: true
|
||||||
|
checked: GraphEditorSettings.showModifiedAttributes
|
||||||
|
onClicked: GraphEditorSettings.showModifiedAttributes = !GraphEditorSettings.showModifiedAttributes
|
||||||
|
enabled: tabBar.currentIndex === 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MenuSeparator {}
|
||||||
|
RowLayout {
|
||||||
|
CheckBox {
|
||||||
|
id: linkToggle
|
||||||
|
text: "Link"
|
||||||
|
checkable: true
|
||||||
|
checked: GraphEditorSettings.showLinkAttributes
|
||||||
|
onClicked: GraphEditorSettings.showLinkAttributes = !GraphEditorSettings.showLinkAttributes
|
||||||
|
enabled: tabBar.currentIndex === 0
|
||||||
|
}
|
||||||
|
CheckBox {
|
||||||
|
id: notLinkToggle
|
||||||
|
text: "Not Link"
|
||||||
|
checkable: true
|
||||||
|
checked: GraphEditorSettings.showNotLinkAttributes
|
||||||
|
onClicked: GraphEditorSettings.showNotLinkAttributes = !GraphEditorSettings.showNotLinkAttributes
|
||||||
|
enabled: tabBar.currentIndex === 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MenuSeparator {}
|
||||||
|
CheckBox {
|
||||||
|
id: advancedToggle
|
||||||
|
text: "Advanced"
|
||||||
|
MaterialLabel {
|
||||||
|
anchors.right: parent.right; anchors.rightMargin: parent.padding;
|
||||||
|
text: MaterialIcons.build
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
font.pointSize: 8
|
||||||
|
}
|
||||||
|
checkable: true
|
||||||
|
checked: GraphEditorSettings.showAdvancedAttributes
|
||||||
|
onClicked: GraphEditorSettings.showAdvancedAttributes = !GraphEditorSettings.showAdvancedAttributes
|
||||||
}
|
}
|
||||||
checkable: true
|
|
||||||
checked: GraphEditorSettings.showOnlyModifiedAttributes
|
|
||||||
onClicked: GraphEditorSettings.showOnlyModifiedAttributes = !GraphEditorSettings.showOnlyModifiedAttributes
|
|
||||||
enabled: tabBar.currentIndex === 0
|
|
||||||
}
|
}
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: "Open Cache Folder"
|
text: "Open Cache Folder"
|
||||||
|
@ -207,6 +260,7 @@ Panel {
|
||||||
readOnly: root.readOnly || root.isCompatibilityNode
|
readOnly: root.readOnly || root.isCompatibilityNode
|
||||||
onAttributeDoubleClicked: root.attributeDoubleClicked(mouse, attribute)
|
onAttributeDoubleClicked: root.attributeDoubleClicked(mouse, attribute)
|
||||||
onUpgradeRequest: root.upgradeRequest()
|
onUpgradeRequest: root.upgradeRequest()
|
||||||
|
filterText: searchBar.text
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
|
@ -273,6 +327,7 @@ Panel {
|
||||||
readOnly: root.readOnly || root.isCompatibilityNode
|
readOnly: root.readOnly || root.isCompatibilityNode
|
||||||
onAttributeDoubleClicked: root.attributeDoubleClicked(mouse, attribute)
|
onAttributeDoubleClicked: root.attributeDoubleClicked(mouse, attribute)
|
||||||
onUpgradeRequest: root.upgradeRequest()
|
onUpgradeRequest: root.upgradeRequest()
|
||||||
|
filterText: searchBar.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,273 +172,290 @@ FloatingPane {
|
||||||
checked: true
|
checked: true
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
ColumnLayout {
|
||||||
id: mediaListView
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
clip: true
|
|
||||||
model: mediaLibrary.model
|
|
||||||
spacing: 4
|
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBar { id: scrollBar }
|
SearchBar {
|
||||||
|
id: searchBar
|
||||||
currentIndex: -1
|
Layout.minimumWidth: 150
|
||||||
|
Layout.fillWidth: true
|
||||||
Connections {
|
Layout.rightMargin: 10
|
||||||
target: uigraph
|
Layout.leftMargin: 10
|
||||||
function onSelectedNodeChanged() {
|
|
||||||
mediaListView.currentIndex = -1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
ListView {
|
||||||
target: mediaLibrary
|
id: mediaListView
|
||||||
function onLoadRequest(idx) {
|
Layout.fillHeight: true
|
||||||
mediaListView.positionViewAtIndex(idx, ListView.Visible)
|
Layout.fillWidth: true
|
||||||
}
|
clip: true
|
||||||
}
|
spacing: 4
|
||||||
|
|
||||||
delegate: MouseArea {
|
ScrollBar.vertical: ScrollBar { id: scrollBar }
|
||||||
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 ? uigraph.hoveredNode === model.attribute.node : false) : containsMouse
|
|
||||||
property bool isSelectedNode: model.attribute ? (uigraph ? uigraph.selectedNode === model.attribute.node : false) : false
|
|
||||||
|
|
||||||
onIsSelectedNodeChanged: updateCurrentIndex()
|
currentIndex: -1
|
||||||
|
|
||||||
function updateCurrentIndex() {
|
Connections {
|
||||||
if(isSelectedNode) { mediaListView.currentIndex = index }
|
target: uigraph
|
||||||
}
|
function onSelectedNodeChanged() {
|
||||||
|
mediaListView.currentIndex = -1
|
||||||
height: childrenRect.height
|
|
||||||
width: {
|
|
||||||
if (parent != null)
|
|
||||||
return parent.width - scrollBar.width
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
function onCountChanged() {
|
|
||||||
mediaDelegate.updateCurrentIndex()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Current/selected element indicator
|
Connections {
|
||||||
Rectangle {
|
target: mediaLibrary
|
||||||
Layout.fillHeight: true
|
function onLoadRequest(idx) {
|
||||||
width: 2
|
mediaListView.positionViewAtIndex(idx, ListView.Visible)
|
||||||
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
|
model: SortFilterDelegateModel {
|
||||||
MaterialToolButton {
|
model: mediaLibrary.model
|
||||||
Layout.alignment: Qt.AlignTop
|
sortRole: "label"
|
||||||
Layout.fillHeight: true
|
filters: [{role: "label", value: searchBar.text}]
|
||||||
text: model.visible ? MaterialIcons.visibility : MaterialIcons.visibility_off
|
delegate: MouseArea {
|
||||||
font.pointSize: 10
|
id: mediaDelegate
|
||||||
ToolTip.text: model.visible ? "Hide" : model.requested ? "Show" : model.valid ? "Load and Show" : "Load and Show when Available"
|
// add mediaLibrary.count in the binding to ensure 'entity'
|
||||||
flat: true
|
// is re-evaluated when mediaLibrary delegates are modified
|
||||||
opacity: model.visible ? 1.0 : 0.6
|
property bool loading: model.status === SceneLoader.Loading
|
||||||
|
property bool hovered: model.attribute ? (uigraph ? uigraph.hoveredNode === model.attribute.node : false) : containsMouse
|
||||||
|
property bool isSelectedNode: model.attribute ? (uigraph ? uigraph.selectedNode === model.attribute.node : false) : false
|
||||||
|
|
||||||
|
onIsSelectedNodeChanged: updateCurrentIndex()
|
||||||
|
|
||||||
|
function updateCurrentIndex() {
|
||||||
|
if(isSelectedNode) { mediaListView.currentIndex = index }
|
||||||
|
}
|
||||||
|
|
||||||
|
height: childrenRect.height
|
||||||
|
width: {
|
||||||
|
if (parent != null)
|
||||||
|
return parent.width - scrollBar.width
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
hoverEnabled: true
|
||||||
|
onEntered: { if(model.attribute) uigraph.hoveredNode = model.attribute.node }
|
||||||
|
onExited: { if(model.attribute) uigraph.hoveredNode = null }
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if(hoverArea.modifiers & Qt.ControlModifier)
|
if(model.attribute)
|
||||||
mediaLibrary.solo(index);
|
uigraph.selectedNode = model.attribute.node;
|
||||||
else
|
else
|
||||||
model.visible = !model.visible
|
uigraph.selectedNode = null;
|
||||||
|
if(mouse.button == Qt.RightButton)
|
||||||
|
contextMenu.popup();
|
||||||
|
mediaListView.currentIndex = index;
|
||||||
}
|
}
|
||||||
// Handle modifiers on button click
|
onDoubleClicked: {
|
||||||
MouseArea {
|
model.visible = true;
|
||||||
id: hoverArea
|
nodeActivated(model.attribute.node);
|
||||||
property int modifiers
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
onPositionChanged: modifiers = mouse.modifiers
|
|
||||||
onExited: modifiers = Qt.NoModifier
|
|
||||||
onPressed: {
|
|
||||||
modifiers = mouse.modifiers;
|
|
||||||
mouse.accepted = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// BoundingBox visibility (if meshing node)
|
RowLayout {
|
||||||
MaterialToolButton {
|
|
||||||
visible: model.hasBoundingBox
|
|
||||||
enabled: model.visible
|
|
||||||
Layout.alignment: Qt.AlignTop
|
|
||||||
Layout.fillHeight: true
|
|
||||||
text: MaterialIcons.transform
|
|
||||||
font.pointSize: 10
|
|
||||||
ToolTip.text: model.displayBoundingBox ? "Hide BBox" : "Show BBox"
|
|
||||||
flat: true
|
|
||||||
opacity: model.visible ? (model.displayBoundingBox ? 1.0 : 0.6) : 0.6
|
|
||||||
onClicked: {
|
|
||||||
model.displayBoundingBox = !model.displayBoundingBox
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transform visibility (if SfMTransform node)
|
|
||||||
MaterialToolButton {
|
|
||||||
visible: model.hasTransform
|
|
||||||
enabled: model.visible
|
|
||||||
Layout.alignment: Qt.AlignTop
|
|
||||||
Layout.fillHeight: true
|
|
||||||
text: MaterialIcons._3d_rotation
|
|
||||||
font.pointSize: 10
|
|
||||||
ToolTip.text: model.displayTransform ? "Hide Gizmo" : "Show Gizmo"
|
|
||||||
flat: true
|
|
||||||
opacity: model.visible ? (model.displayTransform ? 1.0 : 0.6) : 0.6
|
|
||||||
onClicked: {
|
|
||||||
model.displayTransform = !model.displayTransform
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Media label and info
|
|
||||||
Item {
|
|
||||||
implicitHeight: childrenRect.height
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.alignment: Qt.AlignTop
|
|
||||||
ColumnLayout {
|
|
||||||
id: centralLayout
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: 1
|
spacing: 2
|
||||||
|
|
||||||
Label {
|
property string src: model.source
|
||||||
id: label
|
onSrcChanged: focusAnim.restart()
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: mediaListView
|
||||||
|
function 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoundingBox visibility (if meshing node)
|
||||||
|
MaterialToolButton {
|
||||||
|
visible: model.hasBoundingBox
|
||||||
|
enabled: model.visible
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
Layout.fillHeight: true
|
||||||
|
text: MaterialIcons.transform
|
||||||
|
font.pointSize: 10
|
||||||
|
ToolTip.text: model.displayBoundingBox ? "Hide BBox" : "Show BBox"
|
||||||
|
flat: true
|
||||||
|
opacity: model.visible ? (model.displayBoundingBox ? 1.0 : 0.6) : 0.6
|
||||||
|
onClicked: {
|
||||||
|
model.displayBoundingBox = !model.displayBoundingBox
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform visibility (if SfMTransform node)
|
||||||
|
MaterialToolButton {
|
||||||
|
visible: model.hasTransform
|
||||||
|
enabled: model.visible
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
Layout.fillHeight: true
|
||||||
|
text: MaterialIcons._3d_rotation
|
||||||
|
font.pointSize: 10
|
||||||
|
ToolTip.text: model.displayTransform ? "Hide Gizmo" : "Show Gizmo"
|
||||||
|
flat: true
|
||||||
|
opacity: model.visible ? (model.displayTransform ? 1.0 : 0.6) : 0.6
|
||||||
|
onClicked: {
|
||||||
|
model.displayTransform = !model.displayTransform
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Media label and info
|
||||||
|
Item {
|
||||||
|
implicitHeight: childrenRect.height
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
leftPadding: 0
|
Layout.alignment: Qt.AlignTop
|
||||||
rightPadding: 0
|
ColumnLayout {
|
||||||
topPadding: 3
|
id: centralLayout
|
||||||
bottomPadding: topPadding
|
width: parent.width
|
||||||
text: model.label
|
spacing: 1
|
||||||
opacity: model.valid ? 1.0 : 0.6
|
|
||||||
elide: Text.ElideMiddle
|
Label {
|
||||||
font.weight: mediaListView.currentIndex === index ? Font.DemiBold : Font.Normal
|
id: label
|
||||||
background: Rectangle {
|
Layout.fillWidth: true
|
||||||
Connections {
|
leftPadding: 0
|
||||||
target: mediaLibrary
|
rightPadding: 0
|
||||||
function onLoadRequest(idx) {
|
topPadding: 3
|
||||||
if(idx === index)
|
bottomPadding: topPadding
|
||||||
focusAnim.restart()
|
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
|
||||||
|
function onLoadRequest(idx) {
|
||||||
|
if(idx === index)
|
||||||
|
focusAnim.restart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ColorAnimation on color {
|
||||||
|
id: focusAnim
|
||||||
|
from: label.palette.highlight
|
||||||
|
to: "transparent"
|
||||||
|
duration: 2000
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ColorAnimation on color {
|
Item {
|
||||||
id: focusAnim
|
visible: infoButton.checked
|
||||||
from: label.palette.highlight
|
Layout.fillWidth: true
|
||||||
to: "transparent"
|
implicitHeight: childrenRect.height
|
||||||
duration: 2000
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Item {
|
|
||||||
visible: infoButton.checked
|
// Remove media from library button
|
||||||
Layout.fillWidth: true
|
MaterialToolButton {
|
||||||
implicitHeight: childrenRect.height
|
id: removeButton
|
||||||
Flow {
|
Layout.alignment: Qt.AlignTop
|
||||||
width: parent.width
|
Layout.fillHeight: true
|
||||||
spacing: 4
|
|
||||||
visible: model.status === SceneLoader.Ready
|
visible: !loading && mediaDelegate.containsMouse
|
||||||
RowLayout {
|
text: MaterialIcons.clear
|
||||||
spacing: 1
|
font.pointSize: 10
|
||||||
visible: model.vertexCount
|
|
||||||
MaterialLabel { text: MaterialIcons.grain }
|
ToolTip.text: "Remove"
|
||||||
Label { text: Format.intToString(model.vertexCount) }
|
ToolTip.delay: 500
|
||||||
}
|
onClicked: mediaLibrary.remove(index)
|
||||||
RowLayout {
|
}
|
||||||
spacing: 1
|
|
||||||
visible: model.faceCount
|
// Media loading indicator
|
||||||
MaterialLabel { text: MaterialIcons.details; rotation: -180 }
|
BusyIndicator {
|
||||||
Label { text: Format.intToString(model.faceCount) }
|
visible: loading
|
||||||
}
|
running: visible
|
||||||
RowLayout {
|
padding: removeButton.padding
|
||||||
spacing: 1
|
implicitHeight: implicitWidth
|
||||||
visible: model.cameraCount
|
implicitWidth: removeButton.width
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue