@@ -26,6 +26,7 @@ class Sample(QObject):
2626 layersIndexChanged = Signal ()
2727
2828 qRangeChanged = Signal ()
29+ constraintsChanged = Signal ()
2930
3031 externalRefreshPlot = Signal ()
3132 externalSampleChanged = Signal ()
@@ -412,6 +413,10 @@ def _clearCacheAndEmitLayersChanged(self):
412413 def parameterNames (self ) -> list [dict [str , str ]]:
413414 return [parameter ['name' ] for parameter in self ._parameters_logic .parameters ]
414415
416+ @Property ('QVariantList' , notify = layersChange )
417+ def dependentParameterNames (self ) -> list [dict [str , str ]]:
418+ return [parameter ['name' ] for parameter in self ._parameters_logic .parameters if parameter ['independent' ]]
419+
415420 @Property ('QVariantList' , notify = layersChange )
416421 def relationOperators (self ) -> list [str ]:
417422 return self ._parameters_logic .constraint_relations ()
@@ -420,16 +425,93 @@ def relationOperators(self) -> list[str]:
420425 def arithmicOperators (self ) -> list [str ]:
421426 return self ._parameters_logic .constraint_arithmetic ()
422427
428+ @Property ('QVariantList' , notify = constraintsChanged )
429+ def constraintsList (self ) -> list [dict [str , str ]]:
430+ """Get the list of active constraints from dependent parameters."""
431+ constraints = []
432+ parameters = self ._parameters_logic .parameters
433+ for param in parameters :
434+ if not param ['independent' ]:
435+ constraints .append ({param ['name' ]: param ['dependency' ]})
436+
437+ return constraints
438+
439+ @Slot (int )
440+ def removeConstraintByIndex (self , index_str : str ) -> None :
441+ """Remove constraint by index by making the parameter independent."""
442+ try :
443+ index = int (index_str )
444+ except ValueError :
445+ return
446+
447+ constraints_list = self .constraintsList
448+ if index >= len (constraints_list ):
449+ return
450+
451+ param_name = list (constraints_list [index ].keys ())[0 ]
452+ param_obj = self ._find_parameter_object_by_name (param_name )
453+
454+ if param_obj is None or param_obj .independent :
455+ return
456+
457+ self ._make_parameter_independent (param_obj )
458+ self .constraintsChanged .emit ()
459+ self .externalSampleChanged .emit ()
460+
461+ def _find_parameter_object_by_name (self , param_name : str ):
462+ """Find parameter object by name."""
463+ parameters = self ._parameters_logic .parameters
464+ for param in parameters :
465+ if param ['name' ] == param_name :
466+ return param ['object' ]
467+ return None
468+
469+ def _make_parameter_independent (self , param_obj ) -> None :
470+ """Make a parameter independent, handling different parameter types."""
471+ try :
472+ param_obj .make_independent ()
473+ except AttributeError :
474+ param_obj ._independent = True # Fallback for custom ERL constraints
475+
423476 @Slot (str , str , str , str , str )
424477 def addConstraint (self , value1 : str , value2 : str , value3 : str , value4 : str , value5 : str ) -> None :
425- self ._parameters_logic .add_constraint (
426- dependent_idx = int (value1 ),
427- relational_operator = value2 ,
428- value = float (value3 ),
429- arithmetic_operator = value4 ,
430- independent_idx = int (value5 ),
431- )
478+ dependent = self ._project_lib .parameters [int (value1 )]
479+ if value5 == '-1' :
480+ independent = None
481+ else :
482+ independent = self ._project_lib .parameters [int (value5 )]
483+ relational_operator = value2
484+ arithmetic_operator = value4
485+ value = float (value3 )
486+ if arithmetic_operator == '' :
487+ if relational_operator == '=' :
488+ # simple parameter equality
489+ # assign to the parameter and make it frozen
490+ dependent .value = value
491+ dependent .free = False
492+ # here, we need to make the parameter "dependent" so it can't be changed in GUI
493+ dependent ._independent = False
494+
495+ elif relational_operator == '>' :
496+ # set the minimum value of the parameter
497+ dependent .min = value
498+ dependent .free = True
499+
500+ elif relational_operator == '<' :
501+ # set the maximum value of the parameter
502+ dependent .max = value
503+ dependent .free = True
504+ else :
505+ # make the parameter dependent on another parameter
506+ # e.g. thickness = 2 * a + 5
507+ expr = "a " + arithmetic_operator + str (float (value ))
508+ dependency_map = {'a' : independent }
509+ dependent .make_dependent_on (
510+ dependency_expression = expr , dependency_map = dependency_map
511+ )
512+ self .constraintsChanged .emit ()
432513 self .externalSampleChanged .emit ()
514+ self .layersChange .emit ()
433515
434516 # # #
435517 # Q Range
0 commit comments