Skip to content

Commit

Permalink
Merge pull request #2141 from alicevision/dev/wrongBracketsMessage
Browse files Browse the repository at this point in the history
AttributeEditor: Flag attributes with invalid values
  • Loading branch information
mugulmd authored Aug 21, 2023
2 parents 04388ef + 363115b commit e873dbf
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 31 deletions.
21 changes: 21 additions & 0 deletions meshroom/core/attribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ def __init__(self, node, attributeDesc, isOutput, root=None, parent=None):
self._value = copy.copy(attributeDesc.value)
self._label = attributeDesc.label
self._enabled = True
self._validValue = True

# invalidation value for output attributes
self._invalidationValue = ""
Expand Down Expand Up @@ -147,6 +148,24 @@ def getUidIgnoreValue(self):
""" Value for which the attribute should be ignored during the UID computation. """
return self.attributeDesc.uidIgnoreValue

def getValidValue(self):
"""
Get the status of _validValue:
- If it is a function, execute it and return the result
- Otherwise, simply return its value
"""
if isinstance(self.desc.validValue, types.FunctionType):
try:
return self.desc.validValue(self.node)
except Exception:
return True
return self._validValue

def setValidValue(self, value):
if self._validValue == value:
return
self._validValue = value

def _get_value(self):
if self.isLink:
return self.getLinkParam().value
Expand Down Expand Up @@ -338,6 +357,8 @@ def updateInternals(self):
enabledChanged = Signal()
enabled = Property(bool, getEnabled, setEnabled, notify=enabledChanged)
uidIgnoreValue = Property(Variant, getUidIgnoreValue, constant=True)
validValueChanged = Signal()
validValue = Property(bool, getValidValue, setValidValue, notify=validValueChanged)


def raiseIfLink(func):
Expand Down
25 changes: 16 additions & 9 deletions meshroom/core/desc.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ class Attribute(BaseObject):
"""
"""

def __init__(self, name, label, description, value, advanced, semantic, uid, group, enabled, uidIgnoreValue=None):
def __init__(self, name, label, description, value, advanced, semantic, uid, group, enabled, uidIgnoreValue=None,
validValue=True, errorMessage=""):
super(Attribute, self).__init__()
self._name = name
self._label = label
Expand All @@ -26,6 +27,8 @@ def __init__(self, name, label, description, value, advanced, semantic, uid, gro
self._enabled = enabled
self._semantic = semantic
self._uidIgnoreValue = uidIgnoreValue
self._validValue = validValue
self._errorMessage = errorMessage

name = Property(str, lambda self: self._name, constant=True)
label = Property(str, lambda self: self._label, constant=True)
Expand All @@ -37,6 +40,8 @@ def __init__(self, name, label, description, value, advanced, semantic, uid, gro
enabled = Property(Variant, lambda self: self._enabled, constant=True)
semantic = Property(str, lambda self: self._semantic, constant=True)
uidIgnoreValue = Property(Variant, lambda self: self._uidIgnoreValue, constant=True)
validValue = Property(Variant, lambda self: self._validValue, constant=True)
errorMessage = Property(str, lambda self: self._errorMessage, constant=True)
type = Property(str, lambda self: self.__class__.__name__, constant=True)

def validateValue(self, value):
Expand Down Expand Up @@ -205,9 +210,9 @@ def retrieveChildrenUids(self):
class Param(Attribute):
"""
"""
def __init__(self, name, label, description, value, uid, group, advanced, semantic, enabled, uidIgnoreValue=None):
def __init__(self, name, label, description, value, uid, group, advanced, semantic, enabled, uidIgnoreValue=None, validValue=True, errorMessage=""):
super(Param, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled,
uidIgnoreValue=uidIgnoreValue)
uidIgnoreValue=uidIgnoreValue, validValue=validValue, errorMessage=errorMessage)


class File(Attribute):
Expand Down Expand Up @@ -253,9 +258,10 @@ def checkValueTypes(self):
class IntParam(Param):
"""
"""
def __init__(self, name, label, description, value, range, uid, group='allParams', advanced=False, semantic='', enabled=True):
def __init__(self, name, label, description, value, range, uid, group='allParams', advanced=False, semantic='', enabled=True, validValue=True, errorMessage=""):
self._range = range
super(IntParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled)
super(IntParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled,
validValue=validValue, errorMessage=errorMessage)

def validateValue(self, value):
# handle unsigned int values that are translated to int by shiboken and may overflow
Expand All @@ -275,9 +281,10 @@ def checkValueTypes(self):
class FloatParam(Param):
"""
"""
def __init__(self, name, label, description, value, range, uid, group='allParams', advanced=False, semantic='', enabled=True):
def __init__(self, name, label, description, value, range, uid, group='allParams', advanced=False, semantic='', enabled=True, validValue=True, errorMessage=""):
self._range = range
super(FloatParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled)
super(FloatParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled,
validValue=validValue, errorMessage=errorMessage)

def validateValue(self, value):
try:
Expand Down Expand Up @@ -334,9 +341,9 @@ def checkValueTypes(self):
class StringParam(Param):
"""
"""
def __init__(self, name, label, description, value, uid, group='allParams', advanced=False, semantic='', enabled=True, uidIgnoreValue=None):
def __init__(self, name, label, description, value, uid, group='allParams', advanced=False, semantic='', enabled=True, uidIgnoreValue=None, validValue=True, errorMessage=""):
super(StringParam, self).__init__(name=name, label=label, description=description, value=value, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled,
uidIgnoreValue=uidIgnoreValue)
uidIgnoreValue=uidIgnoreValue, validValue=validValue, errorMessage=errorMessage)

def validateValue(self, value):
if not isinstance(value, str):
Expand Down
21 changes: 17 additions & 4 deletions meshroom/nodes/aliceVision/LdrToHdrCalibration.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ class LdrToHdrCalibration(desc.AVCommandLineNode):
range=(0, 15, 1),
uid=[],
group="user", # not used directly on the command line
errorMessage="The set number of brackets is not a multiple of the number of input images.\n"
"Errors will occur during the computation."
),
desc.IntParam(
name="nbBrackets",
Expand All @@ -68,7 +70,7 @@ class LdrToHdrCalibration(desc.AVCommandLineNode):
"It is detected automatically from input Viewpoints metadata if 'userNbBrackets' is 0,\n"
"else it is equal to 'userNbBrackets'.",
value=0,
range=(0, 10, 1),
range=(0, 15, 1),
uid=[0],
group="bracketsParams"
),
Expand Down Expand Up @@ -181,13 +183,24 @@ def update(cls, node):
if "userNbBrackets" not in node.getAttributes().keys():
# Old version of the node
return
if node.userNbBrackets.value != 0:
node.nbBrackets.value = node.userNbBrackets.value
return
node.userNbBrackets.validValue = True # Reset the status of "userNbBrackets"

cameraInitOutput = node.input.getLinkParam(recursive=True)
if not cameraInitOutput:
node.nbBrackets.value = 0
return
if node.userNbBrackets.value != 0:
# The number of brackets has been manually forced: check whether it is valid or not
if cameraInitOutput and cameraInitOutput.node and cameraInitOutput.node.hasAttribute("viewpoints"):
viewpoints = cameraInitOutput.node.viewpoints.value
# The number of brackets should be a multiple of the number of input images
if (len(viewpoints) % node.userNbBrackets.value != 0):
node.userNbBrackets.validValue = False
else:
node.userNbBrackets.validValue = True
node.nbBrackets.value = node.userNbBrackets.value
return

if not cameraInitOutput.node.hasAttribute("viewpoints"):
if cameraInitOutput.node.hasAttribute("input"):
cameraInitOutput = cameraInitOutput.node.input.getLinkParam(recursive=True)
Expand Down
21 changes: 17 additions & 4 deletions meshroom/nodes/aliceVision/LdrToHdrMerge.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ class LdrToHdrMerge(desc.AVCommandLineNode):
range=(0, 15, 1),
uid=[],
group="user", # not used directly on the command line
errorMessage="The set number of brackets is not a multiple of the number of input images.\n"
"Errors will occur during the computation."
),
desc.IntParam(
name="nbBrackets",
Expand All @@ -67,7 +69,7 @@ class LdrToHdrMerge(desc.AVCommandLineNode):
"It is detected automatically from input Viewpoints metadata if 'userNbBrackets'\n"
"is 0, else it is equal to 'userNbBrackets'.",
value=0,
range=(0, 10, 1),
range=(0, 15, 1),
uid=[0],
group="bracketsParams"
),
Expand Down Expand Up @@ -267,13 +269,24 @@ def update(cls, node):
if "userNbBrackets" not in node.getAttributes().keys():
# Old version of the node
return
if node.userNbBrackets.value != 0:
node.nbBrackets.value = node.userNbBrackets.value
return
node.userNbBrackets.validValue = True # Reset the status of "userNbBrackets"

cameraInitOutput = node.input.getLinkParam(recursive=True)
if not cameraInitOutput:
node.nbBrackets.value = 0
return
if node.userNbBrackets.value != 0:
# The number of brackets has been manually forced: check whether it is valid or not
if cameraInitOutput and cameraInitOutput.node and cameraInitOutput.node.hasAttribute("viewpoints"):
viewpoints = cameraInitOutput.node.viewpoints.value
# The number of brackets should be a multiple of the number of input images
if (len(viewpoints) % node.userNbBrackets.value != 0):
node.userNbBrackets.validValue = False
else:
node.userNbBrackets.validValue = True
node.nbBrackets.value = node.userNbBrackets.value
return

if not cameraInitOutput.node.hasAttribute("viewpoints"):
if cameraInitOutput.node.hasAttribute("input"):
cameraInitOutput = cameraInitOutput.node.input.getLinkParam(recursive=True)
Expand Down
21 changes: 17 additions & 4 deletions meshroom/nodes/aliceVision/LdrToHdrSampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ class LdrToHdrSampling(desc.AVCommandLineNode):
range=(0, 15, 1),
uid=[],
group="user", # not used directly on the command line
errorMessage="The set number of brackets is not a multiple of the number of input images.\n"
"Errors will occur during the computation."
),
desc.IntParam(
name="nbBrackets",
Expand All @@ -82,7 +84,7 @@ class LdrToHdrSampling(desc.AVCommandLineNode):
"It is detected automatically from input Viewpoints metadata if 'userNbBrackets'\n"
"is 0, else it is equal to 'userNbBrackets'.",
value=0,
range=(0, 10, 1),
range=(0, 15, 1),
uid=[0],
group="bracketsParams"
),
Expand Down Expand Up @@ -207,13 +209,24 @@ def update(cls, node):
# Old version of the node
return
node.outliersNb = 0 # Reset the number of detected outliers
if node.userNbBrackets.value != 0:
node.nbBrackets.value = node.userNbBrackets.value
return
node.userNbBrackets.validValue = True # Reset the status of "userNbBrackets"

cameraInitOutput = node.input.getLinkParam(recursive=True)
if not cameraInitOutput:
node.nbBrackets.value = 0
return
if node.userNbBrackets.value != 0:
# The number of brackets has been manually forced: check whether it is valid or not
if cameraInitOutput and cameraInitOutput.node and cameraInitOutput.node.hasAttribute("viewpoints"):
viewpoints = cameraInitOutput.node.viewpoints.value
# The number of brackets should be a multiple of the number of input images
if (len(viewpoints) % node.userNbBrackets.value != 0):
node.userNbBrackets.validValue = False
else:
node.userNbBrackets.validValue = True
node.nbBrackets.value = node.userNbBrackets.value
return

if not cameraInitOutput.node.hasAttribute("viewpoints"):
if cameraInitOutput.node.hasAttribute("input"):
cameraInitOutput = cameraInitOutput.node.input.getLinkParam(recursive=True)
Expand Down
51 changes: 41 additions & 10 deletions meshroom/ui/qml/GraphEditor/AttributeItemDelegate.qml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import QtQuick 2.9
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.2
import QtQuick.Dialogs 1.0
import QtQuick.Dialogs 1.3
import MaterialIcons 2.2
import Utils 1.0

Expand All @@ -23,9 +23,22 @@ RowLayout {

spacing: 2

function updateAttributeLabel()
{
background.color = attribute.validValue ? Qt.darker(palette.window, 1.1) : Qt.darker(Colors.red, 1.5)

if (attribute.desc) {
var tooltip = ""
if (!attribute.validValue && attribute.desc.errorMessage !== "")
tooltip += "<i><b>Error: </b>" + Format.plainToHtml(attribute.desc.errorMessage) + "</i><br><br>"
tooltip += "<b> " + attribute.desc.name + "</b><br>" + Format.plainToHtml(attribute.desc.description)

parameterTooltip.text = tooltip
}
}

Pane {
background: Rectangle { color: Qt.darker(parent.palette.window, 1.1) }
background: Rectangle { id: background; color: object.validValue ? Qt.darker(parent.palette.window, 1.1) : Qt.darker(Colors.red, 1.5) }
padding: 0
Layout.preferredWidth: labelWidth || implicitWidth
Layout.fillHeight: true
Expand All @@ -34,6 +47,7 @@ RowLayout {
spacing: 0
width: parent.width
height: parent.height

Label {
id: parameterLabel

Expand All @@ -44,20 +58,29 @@ RowLayout {
padding: 5
wrapMode: Label.WrapAtWordBoundaryOrAnywhere

text: attribute.label
text: object.label

// Tooltip hint with attribute's description
ToolTip.text: "<b>" + object.desc.name + "</b><br>" + Format.plainToHtml(object.desc.description)
ToolTip.visible: parameterMA.containsMouse
ToolTip.delay: 800
ToolTip {
id: parameterTooltip

text: {
var tooltip = ""
if (!object.validValue && object.desc.errorMessage !== "")
tooltip += "<i><b>Error: </b>" + Format.plainToHtml(object.desc.errorMessage) + "</i><br><br>"
tooltip += "<b>" + object.desc.name + "</b><br>" + Format.plainToHtml(object.desc.description)
return tooltip
}
visible: parameterMA.containsMouse
delay: 800
}

// make label bold if attribute's value is not the default one
font.bold: !object.isOutput && !object.isDefault

// make label italic if attribute is a link
font.italic: object.isLink


MouseArea {
id: parameterMA
anchors.fill: parent
Expand All @@ -74,7 +97,10 @@ RowLayout {
MenuItem {
text: "Reset To Default Value"
enabled: root.editable && !attribute.isDefault
onTriggered: _reconstruction.resetAttribute(attribute)
onTriggered: {
_reconstruction.resetAttribute(attribute)
updateAttributeLabel()
}
}

MenuSeparator {
Expand Down Expand Up @@ -129,12 +155,15 @@ RowLayout {
case "IntParam":
case "FloatParam":
_reconstruction.setAttribute(root.attribute, Number(value))
updateAttributeLabel()
break;
case "File":
_reconstruction.setAttribute(root.attribute, value)
break;
default:
_reconstruction.setAttribute(root.attribute, value.trim())
updateAttributeLabel()
break;
}
}

Expand Down Expand Up @@ -370,6 +399,7 @@ RowLayout {
onEditingFinished: setTextFieldAttribute(text)
onAccepted: {
setTextFieldAttribute(text)

// When the text is too long, display the left part
// (with the most important values and cut the floating point details)
ensureVisible(0)
Expand Down Expand Up @@ -400,12 +430,13 @@ RowLayout {
snapMode: Slider.SnapAlways

onPressedChanged: {
if(!pressed)
if (!pressed) {
_reconstruction.setAttribute(attribute, formattedValue)
updateAttributeLabel()
}
}
}
}

}
}

Expand Down
1 change: 1 addition & 0 deletions meshroom/ui/qml/MaterialIcons/MaterialIcons.qml
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ QtObject {
readonly property string crop_portrait: "\ue3c5"
readonly property string crop_rotate: "\ue437"
readonly property string crop_square: "\ue3c6"
readonly property string dangerous: "\ue99a"
readonly property string dashboard: "\ue871"
readonly property string data_usage: "\ue1af"
readonly property string date_range: "\ue916"
Expand Down

0 comments on commit e873dbf

Please sign in to comment.