mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-08-04 01:08:26 +02:00
[ui] move label inside AttributeItemDelegate
* avoid duplication of code for displaying labels of GroupAttribute's children * display input/output aligned to the left/right * add a background to improve readability
This commit is contained in:
parent
839d8c5fb6
commit
4d3509847a
2 changed files with 216 additions and 197 deletions
|
@ -67,39 +67,14 @@ ColumnLayout {
|
|||
anchors.margins: 6
|
||||
|
||||
clip: true
|
||||
spacing: 4
|
||||
spacing: 1
|
||||
ScrollBar.vertical: ScrollBar { id: scrollBar }
|
||||
|
||||
model: node ? node.attributes : undefined
|
||||
|
||||
delegate: RowLayout {
|
||||
delegate: AttributeItemDelegate {
|
||||
width: attributesListView.width
|
||||
spacing: 4
|
||||
|
||||
Label {
|
||||
id: parameterLabel
|
||||
text: object.label
|
||||
Layout.preferredWidth: 180
|
||||
color: object.isOutput ? "orange" : palette.text
|
||||
elide: Label.ElideRight
|
||||
ToolTip.text: object.desc.description
|
||||
ToolTip.visible: parameterMA.containsMouse && object.desc.description
|
||||
ToolTip.delay: 200
|
||||
|
||||
MouseArea {
|
||||
id: parameterMA
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
}
|
||||
}
|
||||
|
||||
AttributeItemDelegate {
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: scrollBar.width
|
||||
height: childrenRect.height
|
||||
attribute: object
|
||||
readOnly: root.readOnly
|
||||
}
|
||||
attribute: object
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,28 +5,52 @@ import QtQuick.Controls 2.2
|
|||
/**
|
||||
Instantiate a control to visualize and edit an Attribute based on its type.
|
||||
*/
|
||||
Loader {
|
||||
RowLayout {
|
||||
id: root
|
||||
|
||||
property variant attribute: null
|
||||
property bool readOnly: false
|
||||
property bool readOnly: false // whether the attribute's value can be modified
|
||||
|
||||
property bool showLabel: true // whether to show the label
|
||||
property int labelWidth: 180 // the fixed size of the label
|
||||
|
||||
readonly property bool editable: !attribute.isOutput && !attribute.isLink && !readOnly
|
||||
|
||||
sourceComponent: {
|
||||
switch(attribute.type)
|
||||
{
|
||||
case "ChoiceParam": return attribute.desc.exclusive ? comboBox_component : multiChoice_component
|
||||
case "IntParam": return slider_component
|
||||
case "FloatParam": return slider_component
|
||||
case "BoolParam": return checkbox_component
|
||||
case "ListAttribute": return listAttribute_component
|
||||
case "GroupAttribute": return groupAttribute_component
|
||||
default: return textField_component
|
||||
spacing: 4
|
||||
|
||||
Label {
|
||||
id: parameterLabel
|
||||
|
||||
Layout.preferredWidth: labelWidth || implicitWidth
|
||||
Layout.fillHeight: true
|
||||
horizontalAlignment: attribute.isOutput ? Qt.AlignRight : Qt.AlignLeft
|
||||
elide: Label.ElideRight
|
||||
padding: 5
|
||||
wrapMode: Label.WrapAtWordBoundaryOrAnywhere
|
||||
|
||||
text: attribute.label
|
||||
visible: showLabel
|
||||
|
||||
// Tooltip hint with attribute's description
|
||||
ToolTip.text: object.desc.description
|
||||
ToolTip.visible: parameterMA.containsMouse && object.desc.description
|
||||
ToolTip.delay: 800
|
||||
|
||||
background: Rectangle { color: Qt.darker(palette.window, 1.2) }
|
||||
|
||||
MouseArea {
|
||||
id: parameterMA
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.AllButtons
|
||||
|
||||
onClicked: {
|
||||
forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setTextFieldAttribute(attribute, value)
|
||||
function setTextFieldAttribute(value)
|
||||
{
|
||||
// editingFinished called even when TextField is readonly
|
||||
if(!editable)
|
||||
|
@ -35,188 +59,208 @@ Loader {
|
|||
{
|
||||
case "IntParam":
|
||||
case "FloatParam":
|
||||
_reconstruction.setAttribute(attribute, Number(value))
|
||||
_reconstruction.setAttribute(root.attribute, Number(value))
|
||||
break;
|
||||
default:
|
||||
_reconstruction.setAttribute(attribute, value.trim())
|
||||
_reconstruction.setAttribute(root.attribute, value.trim())
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: textField_component
|
||||
TextField {
|
||||
readOnly: !root.editable
|
||||
text: attribute.value
|
||||
selectByMouse: true
|
||||
onEditingFinished: setTextFieldAttribute(attribute, text)
|
||||
onAccepted: setTextFieldAttribute(attribute, text)
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Component {
|
||||
id: comboBox_component
|
||||
ComboBox {
|
||||
enabled: root.editable
|
||||
model: attribute.desc.values
|
||||
Component.onCompleted: currentIndex = find(attribute.value)
|
||||
onActivated: _reconstruction.setAttribute(attribute, currentText)
|
||||
Connections {
|
||||
target: attribute
|
||||
onValueChanged: currentIndex = find(attribute.value)
|
||||
sourceComponent: {
|
||||
switch(attribute.type)
|
||||
{
|
||||
case "ChoiceParam": return attribute.desc.exclusive ? comboBox_component : multiChoice_component
|
||||
case "IntParam": return slider_component
|
||||
case "FloatParam": return slider_component
|
||||
case "BoolParam": return checkbox_component
|
||||
case "ListAttribute": return listAttribute_component
|
||||
case "GroupAttribute": return groupAttribute_component
|
||||
default: return textField_component
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: multiChoice_component
|
||||
Flow {
|
||||
Repeater {
|
||||
id: checkbox_repeater
|
||||
Component {
|
||||
id: textField_component
|
||||
TextField {
|
||||
readOnly: !root.editable
|
||||
text: attribute.value
|
||||
selectByMouse: true
|
||||
onEditingFinished: setTextFieldAttribute(text)
|
||||
onAccepted: setTextFieldAttribute(text)
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: comboBox_component
|
||||
ComboBox {
|
||||
enabled: root.editable
|
||||
model: attribute.desc.values
|
||||
delegate: CheckBox {
|
||||
enabled: root.editable
|
||||
text: modelData
|
||||
checked: attribute.value.indexOf(modelData) >= 0
|
||||
onToggled: {
|
||||
var t = attribute.value
|
||||
if(!checked) { t.splice(t.indexOf(modelData), 1) } // remove element
|
||||
else { t.push(modelData) } // add element
|
||||
_reconstruction.setAttribute(attribute, t)
|
||||
Component.onCompleted: currentIndex = find(attribute.value)
|
||||
onActivated: _reconstruction.setAttribute(attribute, currentText)
|
||||
Connections {
|
||||
target: attribute
|
||||
onValueChanged: currentIndex = find(attribute.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: multiChoice_component
|
||||
Flow {
|
||||
Repeater {
|
||||
id: checkbox_repeater
|
||||
model: attribute.desc.values
|
||||
delegate: CheckBox {
|
||||
enabled: root.editable
|
||||
text: modelData
|
||||
checked: attribute.value.indexOf(modelData) >= 0
|
||||
onToggled: {
|
||||
var t = attribute.value
|
||||
if(!checked) { t.splice(t.indexOf(modelData), 1) } // remove element
|
||||
else { t.push(modelData) } // add element
|
||||
_reconstruction.setAttribute(attribute, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: slider_component
|
||||
RowLayout {
|
||||
TextField {
|
||||
IntValidator {
|
||||
id: intValidator
|
||||
}
|
||||
DoubleValidator {
|
||||
id: doubleValidator
|
||||
}
|
||||
implicitWidth: 70
|
||||
enabled: root.editable
|
||||
text: s.pressed ? s.value : attribute.value
|
||||
selectByMouse: true
|
||||
validator: attribute.type == "FloatParam" ? doubleValidator : intValidator
|
||||
onEditingFinished: setTextFieldAttribute(attribute, text)
|
||||
}
|
||||
Slider {
|
||||
id: s
|
||||
Layout.fillWidth: true
|
||||
enabled: root.editable
|
||||
value: attribute.value
|
||||
from: attribute.desc.range[0]
|
||||
to: attribute.desc.range[1]
|
||||
stepSize: attribute.desc.range[2]
|
||||
snapMode: Slider.SnapAlways
|
||||
|
||||
onPressedChanged: {
|
||||
if(!pressed)
|
||||
_reconstruction.setAttribute(attribute, value)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: checkbox_component
|
||||
Row {
|
||||
CheckBox {
|
||||
enabled: root.editable
|
||||
checked: attribute.value
|
||||
onToggled: _reconstruction.setAttribute(attribute, !attribute.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: listAttribute_component
|
||||
ColumnLayout {
|
||||
id: listAttribute_layout
|
||||
width: parent.width
|
||||
property bool expanded: false
|
||||
Row {
|
||||
spacing: 2
|
||||
ToolButton {
|
||||
text: listAttribute_layout.expanded ? "▾" : "▸"
|
||||
onClicked: listAttribute_layout.expanded = !listAttribute_layout.expanded
|
||||
}
|
||||
Label {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: attribute.value.count + " elements"
|
||||
}
|
||||
ToolButton {
|
||||
text: "+"
|
||||
Component {
|
||||
id: slider_component
|
||||
RowLayout {
|
||||
TextField {
|
||||
IntValidator {
|
||||
id: intValidator
|
||||
}
|
||||
DoubleValidator {
|
||||
id: doubleValidator
|
||||
}
|
||||
implicitWidth: 70
|
||||
enabled: root.editable
|
||||
onClicked: _reconstruction.appendAttribute(attribute, undefined)
|
||||
text: s.pressed ? s.value : attribute.value
|
||||
selectByMouse: true
|
||||
validator: attribute.type == "FloatParam" ? doubleValidator : intValidator
|
||||
onEditingFinished: setTextFieldAttribute(text)
|
||||
}
|
||||
|
||||
Slider {
|
||||
id: s
|
||||
Layout.fillWidth: true
|
||||
enabled: root.editable
|
||||
value: attribute.value
|
||||
from: attribute.desc.range[0]
|
||||
to: attribute.desc.range[1]
|
||||
stepSize: attribute.desc.range[2]
|
||||
snapMode: Slider.SnapAlways
|
||||
|
||||
onPressedChanged: {
|
||||
if(!pressed)
|
||||
_reconstruction.setAttribute(attribute, value)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: checkbox_component
|
||||
Row {
|
||||
CheckBox {
|
||||
enabled: root.editable
|
||||
checked: attribute.value
|
||||
onToggled: _reconstruction.setAttribute(attribute, !attribute.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: listAttribute_component
|
||||
ColumnLayout {
|
||||
id: listAttribute_layout
|
||||
width: parent.width
|
||||
property bool expanded: false
|
||||
Row {
|
||||
spacing: 2
|
||||
ToolButton {
|
||||
text: listAttribute_layout.expanded ? "▾" : "▸"
|
||||
onClicked: listAttribute_layout.expanded = !listAttribute_layout.expanded
|
||||
}
|
||||
Label {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: attribute.value.count + " elements"
|
||||
}
|
||||
ToolButton {
|
||||
text: "+"
|
||||
enabled: root.editable
|
||||
onClicked: _reconstruction.appendAttribute(attribute, undefined)
|
||||
}
|
||||
}
|
||||
ListView {
|
||||
id: lv
|
||||
model: listAttribute_layout.expanded ? attribute.value : undefined
|
||||
visible: model != undefined && count > 0
|
||||
implicitHeight: Math.min(childrenRect.height, 300)
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 4
|
||||
Layout.leftMargin: 10
|
||||
clip: true
|
||||
spacing: 10
|
||||
|
||||
ScrollBar.vertical: ScrollBar { id: sb }
|
||||
|
||||
delegate: RowLayout {
|
||||
id: item
|
||||
property var childAttrib: object
|
||||
layoutDirection: Qt.RightToLeft
|
||||
width: lv.width - sb.width
|
||||
Component.onCompleted: {
|
||||
var cpt = Qt.createComponent("AttributeItemDelegate.qml")
|
||||
var obj = cpt.createObject(item,
|
||||
{'attribute': Qt.binding(function() { return item.childAttrib }),
|
||||
'readOnly': Qt.binding(function() { return root.readOnly })
|
||||
})
|
||||
obj.Layout.fillWidth = true
|
||||
obj.showLabel = false
|
||||
}
|
||||
ToolButton {
|
||||
enabled: root.editable
|
||||
text: "∅"
|
||||
ToolTip.text: "Remove Element"
|
||||
ToolTip.visible: hovered
|
||||
onClicked: _reconstruction.removeAttribute(item.childAttrib)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: groupAttribute_component
|
||||
ListView {
|
||||
id: lv
|
||||
model: listAttribute_layout.expanded ? attribute.value : undefined
|
||||
visible: model != undefined && count > 0
|
||||
implicitHeight: Math.min(childrenRect.height, 300)
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 4
|
||||
clip: true
|
||||
spacing: 10
|
||||
id: chilrenListView
|
||||
model: attribute.value
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: childrenRect.height
|
||||
onCountChanged: forceLayout()
|
||||
spacing: 2
|
||||
|
||||
ScrollBar.vertical: ScrollBar { id: sb }
|
||||
|
||||
delegate: RowLayout {
|
||||
id: item
|
||||
delegate: RowLayout {
|
||||
id: row
|
||||
width: chilrenListView.width
|
||||
property var childAttrib: object
|
||||
layoutDirection: Qt.RightToLeft
|
||||
width: lv.width - sb.width
|
||||
Component.onCompleted: {
|
||||
|
||||
Component.onCompleted: {
|
||||
var cpt = Qt.createComponent("AttributeItemDelegate.qml")
|
||||
var obj = cpt.createObject(item,
|
||||
{'attribute': Qt.binding(function() { return item.childAttrib }),
|
||||
var obj = cpt.createObject(row,
|
||||
{'attribute': Qt.binding(function() { return row.childAttrib }),
|
||||
'readOnly': Qt.binding(function() { return root.readOnly })
|
||||
})
|
||||
obj.Layout.fillWidth = true
|
||||
obj.labelWidth = 100 // reduce label width for children (gain space)
|
||||
}
|
||||
ToolButton {
|
||||
enabled: root.editable
|
||||
text: "∅"
|
||||
ToolTip.text: "Remove Element"
|
||||
ToolTip.visible: hovered
|
||||
onClicked: _reconstruction.removeAttribute(item.childAttrib)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: groupAttribute_component
|
||||
ListView {
|
||||
id: someview
|
||||
model: attribute.value
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: childrenRect.height
|
||||
onCountChanged: forceLayout()
|
||||
spacing: 2
|
||||
|
||||
delegate: RowLayout {
|
||||
id: row
|
||||
width: someview.width
|
||||
property var childAttrib: object
|
||||
|
||||
Label { text: childAttrib.name }
|
||||
Component.onCompleted: {
|
||||
var cpt = Qt.createComponent("AttributeItemDelegate.qml")
|
||||
var obj = cpt.createObject(row,
|
||||
{'attribute': Qt.binding(function() { return row.childAttrib }),
|
||||
'readOnly': Qt.binding(function() { return root.readOnly })
|
||||
})
|
||||
obj.Layout.fillWidth = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue