Index: src/sas/qtgui/GUITests.py
===================================================================
--- src/sas/qtgui/GUITests.py	(revision 50bfab0745a9a59df918aa1ba6a00bf46be39c11)
+++ src/sas/qtgui/GUITests.py	(revision 0595bb7954497ab0a25be7ffb88395a048df52ae)
@@ -56,10 +56,9 @@
 from Perspectives.Fitting.UnitTesting import FitPageTest
 from Perspectives.Fitting.UnitTesting import FittingOptionsTest
+from Perspectives.Fitting.UnitTesting import MultiConstraintTest
+
 #  Invariant
 from Perspectives.Invariant.UnitTesting import InvariantPerspectiveTest
 from Perspectives.Invariant.UnitTesting import InvariantDetailsTest
-#  Inversion
-from Perspectives.Inversion.UnitTesting import InversionPerspectiveTest
-
 
 def suite():
@@ -114,4 +113,5 @@
         unittest.makeSuite(FitPageTest.FitPageTest,                       'test'),
         unittest.makeSuite(FittingOptionsTest.FittingOptionsTest,         'test'),
+        unittest.makeSuite(MultiConstraintTest.MultiConstraintTest,       'test'),
         #  Invariant
         unittest.makeSuite(InvariantPerspectiveTest.InvariantPerspectiveTest,  'test'),
Index: src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/FittingWidget.py	(revision 7fd20fcaad0240e364298e5839ff98bd609bacb4)
+++ src/sas/qtgui/Perspectives/Fitting/FittingWidget.py	(revision 0595bb7954497ab0a25be7ffb88395a048df52ae)
@@ -80,4 +80,5 @@
     Main widget for selecting form and structure factor models
     """
+    constraintAddedSignal = QtCore.pyqtSignal(list)
     def __init__(self, parent=None, data=None, tab_id=1):
 
@@ -452,4 +453,5 @@
         # Respond to change in parameters from the UI
         self._model_model.itemChanged.connect(self.onMainParamsChange)
+        self.constraintAddedSignal.connect(self.modifyViewOnConstraint)
         self._poly_model.itemChanged.connect(self.onPolyModelChange)
         self._magnet_model.itemChanged.connect(self.onMagnetModelChange)
@@ -506,27 +508,62 @@
 
         # Define the callbacks
-        self.actionConstrain.triggered.connect(self.addConstraint)
-        self.actionMutualMultiConstrain.triggered.connect(self.showMultiConstrain)
+        self.actionConstrain.triggered.connect(self.addSimpleConstraint)
+        self.actionMutualMultiConstrain.triggered.connect(self.showMultiConstraint)
         self.actionSelect.triggered.connect(self.selectParameters)
         self.actionDeselect.triggered.connect(self.deselectParameters)
         return menu
 
-    def showMultiConstrain(self):
+    def showMultiConstraint(self):
         """
         Show the constraint widget and receive the expression
         """
         from sas.qtgui.Perspectives.Fitting.MultiConstraint import MultiConstraint
-        params_list = [s.data() for s in self.lstParams.selectionModel().selectedRows()]
+        from .Constraints import Constraint
+        selected_rows = self.lstParams.selectionModel().selectedRows()
+
+        params_list = [s.data() for s in selected_rows]
         mc_widget = MultiConstraint(self, params=params_list)
         mc_widget.exec_()
-        constraint = mc_widget.txtConstraint.text()
+        constraint = Constraint()
+        c_text = mc_widget.txtConstraint.text()
         # Pass the constraint to the parser
+
         self.communicate.statusBarUpdateSignal.emit('Constraints added')
+        # Change the colour of the row
         pass
 
-    def addConstraint(self):
+    def modifyViewOnConstraint(self, row):
+        """
+        Add visual cues that the parameter is constrained
+        """
+        value = self._model_model.item(row, 1).text()
+        # Set min/max to the value constrained
+        self._model_model.item(row,2).setText(value)
+        self._model_model.item(row,3).setText(value)
+        font = QtGui.QFont()
+        font.setItalic(True)
+        brush = QtGui.QBrush(QtGui.QColor('blue'))
+        self._model_model.blockSignals(True)
+        # Modify font and foreground of affected rows
+        for column in range(0, self._model_model.columnCount()):
+            self._model_model.item(row, column).setForeground(brush)
+            self._model_model.item(row, column).setFont(font)
+            self._model_model.item(row, column).setEditable(False)
+        self._model_model.blockSignals(False)
+
+    def addSimpleConstraint(self):
         """
         Adds a constraint on a single parameter.
         """
+        from .Constraints import Constraint
+        for row in self.selectedParameters():
+            param = self._model_model.item(row, 0).text()
+            value = self._model_model.item(row, 1).text()
+            constraint = Constraint(param=param, value=value)
+            item = QtGui.QStandardItem()
+            item.setData(constraint)
+            self._model_model.item(row, 1).setChild(0, item)
+            #self.constraintAddedSignal.emit([row])
+            self.modifyViewOnConstraint(row)
         self.communicate.statusBarUpdateSignal.emit('Constraint added')
         pass
Index: src/sas/qtgui/Perspectives/Fitting/MultiConstraint.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/MultiConstraint.py	(revision 7fd20fcaad0240e364298e5839ff98bd609bacb4)
+++ src/sas/qtgui/Perspectives/Fitting/MultiConstraint.py	(revision 0595bb7954497ab0a25be7ffb88395a048df52ae)
@@ -2,4 +2,6 @@
 Widget for parameter constraints.
 """
+from numpy import *
+
 from PyQt5 import QtCore
 from PyQt5 import QtGui
@@ -23,6 +25,10 @@
         self.setupTooltip()
 
+        # Set param text control to the second parameter passed
+        self.txtConstraint.setText(self.params[1])
+
         self.cmdOK.clicked.connect(self.accept)
         self.cmdRevert.clicked.connect(self.revert)
+        self.txtConstraint.editingFinished.connect(self.validateFormula)
 
     def revert(self):
@@ -52,4 +58,63 @@
         self.txtConstraint.setToolTip(tooltip)
 
-        pass
+    def validateFormula(self):
+        """
+        Add visual cues when formula is incorrect
+        """
+        formula_is_valid = False
+        formula_is_valid = self.validateConstraint(self.txtConstraint.text())
+        if not formula_is_valid:
+            self.cmdOK.setEnabled(False)
+            self.txtConstraint.setStyleSheet("QLineEdit {background-color: red;}")
+        else:
+            self.cmdOK.setEnabled(True)
+            self.txtConstraint.setStyleSheet("QLineEdit {background-color: white;}")
 
+    def validateConstraint(self, constraint_text):
+        """
+        Ensure the constraint has proper form
+        """
+        # 0. none or empty
+        if not constraint_text or not isinstance(constraint_text, str):
+            return False
+
+        param_str = str(self.params[1])
+        constraint_text = constraint_text.strip()
+
+        # 1. just the parameter
+        if param_str == constraint_text:
+            return True
+
+        # 2. ensure the text contains parameter name
+        parameter_string_start = constraint_text.find(param_str)
+        has_parameter_name = (parameter_string_start > -1)
+        if not has_parameter_name:
+            return False
+        parameter_string_end = parameter_string_start + len(param_str)
+
+        # 3. parameter name should be a separate word, but can have "()[]*+-/" around
+        valid_neighbours = "()[]*+-/ "
+        has_only_parameter = False
+        start_loc = parameter_string_start -1
+        end_loc = parameter_string_end
+        if not any([constraint_text[start_loc] == char for char in valid_neighbours]):
+            return False
+        if end_loc < len(constraint_text):
+            if not any([constraint_text[end_loc] == char for char in valid_neighbours]):
+                return False
+
+        # 4. replace parameter name with "1" and try to evaluate the expression
+        try:
+            expression_to_evaluate = constraint_text.replace(param_str, "1.0")
+            eval(expression_to_evaluate)
+        except Exception:
+            # Too many cases to cover individually, just a blanket
+            # Exception should be sufficient
+            # Note that in current numpy things like sqrt(-1) don't
+            # raise but just return warnings
+            return False
+
+        return True
+
+
+
Index: src/sas/qtgui/Perspectives/Fitting/UnitTesting/MultiConstraintTest.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/UnitTesting/MultiConstraintTest.py	(revision 0595bb7954497ab0a25be7ffb88395a048df52ae)
+++ src/sas/qtgui/Perspectives/Fitting/UnitTesting/MultiConstraintTest.py	(revision 0595bb7954497ab0a25be7ffb88395a048df52ae)
@@ -0,0 +1,99 @@
+import sys
+import unittest
+import numpy as np
+
+from unittest.mock import MagicMock
+
+from PyQt5 import QtGui, QtWidgets
+from PyQt5 import QtWebKit
+
+# set up import paths
+import path_prepare
+
+# Local
+from sas.qtgui.Perspectives.Fitting.MultiConstraint import MultiConstraint
+
+if not QtWidgets.QApplication.instance():
+    app = QtWidgets.QApplication(sys.argv)
+
+class MultiConstraintTest(unittest.TestCase):
+    '''Test the MultiConstraint dialog'''
+    def setUp(self):
+        '''Create MultiConstraint dialog'''
+        params = ['p1', 'p2']
+        self.p1 = params[0]
+        self.p2 = params[1]
+        self.widget = MultiConstraint(parent=None, params=params)
+
+    def tearDown(self):
+        '''Destroy the GUI'''
+        self.widget.close()
+        self.widget = None
+
+    def testDefaults(self):
+        '''Test the GUI in its default state'''
+        self.assertIsInstance(self.widget, QtWidgets.QDialog)
+        # Default title
+        self.assertEqual(self.widget.windowTitle(), "2 parameter constraint")
+
+        # modal window
+        self.assertTrue(self.widget.isModal())
+
+    def testLabels(self):
+        ''' various labels on the widget '''
+        # params related setup
+        self.assertEqual(self.widget.txtParam1.text(), self.p1)
+        self.assertEqual(self.widget.txtParam1_2.text(), self.p1)
+        self.assertEqual(self.widget.txtParam2.text(), self.p2)
+
+    def testTooltip(self):
+        ''' test the tooltip'''
+        tooltip = "E.g.\n%s = 2.0 * (%s)\n" %(self.p1, self.p2)
+        tooltip += "%s = sqrt(%s) + 5"%(self.p1, self.p2)
+        self.assertEqual(self.widget.txtConstraint.toolTip(), tooltip)
+
+    def testValidateFormula(self):
+        ''' assure enablement and color for valid formula '''
+        # Invalid string
+        self.widget.validateConstraint = MagicMock(return_value=False)
+        self.widget.validateFormula()
+        style_sheet = "QLineEdit {background-color: red;}"
+        self.assertFalse(self.widget.cmdOK.isEnabled())
+        self.assertEqual(self.widget.txtConstraint.styleSheet(),style_sheet)
+
+        # Valid string
+        self.widget.validateConstraint = MagicMock(return_value=True)
+        self.widget.validateFormula()
+        style_sheet = "QLineEdit {background-color: white;}"
+        self.assertTrue(self.widget.cmdOK.isEnabled())
+        self.assertEqual(self.widget.txtConstraint.styleSheet(),style_sheet)
+
+    def testValidateConstraint(self):
+        ''' constraint validator test'''
+        #### BAD
+        # none
+        self.assertFalse(self.widget.validateConstraint(None))
+        # inf
+        self.assertFalse(self.widget.validateConstraint(np.inf))
+        # 0
+        self.assertFalse(self.widget.validateConstraint(0))
+        # ""
+        self.assertFalse(self.widget.validateConstraint(""))
+        # p2_
+        self.assertFalse(self.widget.validateConstraint("p2_"))
+        # p1
+        self.assertFalse(self.widget.validateConstraint("p1"))
+
+        ### GOOD
+        # p2
+        self.assertTrue(self.widget.validateConstraint("p2"))
+        # " p2    "
+        self.assertTrue(self.widget.validateConstraint(" p2    "))
+        # sqrt(p2)
+        self.assertTrue(self.widget.validateConstraint("sqrt(p2)"))
+        # -p2
+        self.assertTrue(self.widget.validateConstraint("-p2"))
+        # log10(p2) - sqrt(p2) + p2
+        self.assertTrue(self.widget.validateConstraint("log10(p2) - sqrt(p2) + p2"))
+        # log10(    p2    ) +  p2
+        self.assertTrue(self.widget.validateConstraint("log10(    p2    ) +  p2  "))
