make only correct blocks(by IEC 61131-3 standard) available in wire popup menu in SFC Viewer
authorSergey Surkov <surkovsv93@gmail.com>
Thu, 01 Dec 2016 16:40:49 +0300
changeset 1584 431f4ef34bde
parent 1583 d91356480df9
child 1585 60c0db313ec9
make only correct blocks(by IEC 61131-3 standard) available in wire popup menu in SFC Viewer
dialogs/SFCDivergenceDialog.py
editors/SFCViewer.py
editors/Viewer.py
--- a/dialogs/SFCDivergenceDialog.py	Wed Nov 30 14:27:18 2016 +0300
+++ b/dialogs/SFCDivergenceDialog.py	Thu Dec 01 16:40:49 2016 +0300
@@ -40,12 +40,13 @@
 
 class SFCDivergenceDialog(BlockPreviewDialog):
     
-    def __init__(self, parent, controller, tagname):
+    def __init__(self, parent, controller, tagname, poss_div_types = None):
         """
         Constructor
         @param parent: Parent wx.Window of dialog for modal
         @param controller: Reference to project controller
         @param tagname: Tagname of project POU edited
+        @param poss_div_types: Types of divergence that will be available in the dialog window
         """
         BlockPreviewDialog.__init__(self, parent, controller, tagname, 
               size=wx.Size(500, 300), 
@@ -59,19 +60,28 @@
         self.LeftGridSizer.AddWindow(type_label, flag=wx.GROW)
         
         # Create radio buttons for selecting divergence type
+        divergence_buttons = [
+            (SELECTION_DIVERGENCE, _('Selection Divergence')),
+            (SELECTION_CONVERGENCE, _('Selection Convergence')),
+            (SIMULTANEOUS_DIVERGENCE, _('Simultaneous Divergence')),
+            (SIMULTANEOUS_CONVERGENCE, _('Simultaneous Convergence'))]
+        poss_div_btns = []
+        if poss_div_types is not None:
+             for val in poss_div_types:
+                 poss_div_btns.append(divergence_buttons[val])
+        else:
+            poss_div_btns = divergence_buttons
         self.TypeRadioButtons = {}
         first = True
-        for type, label in [
-                (SELECTION_DIVERGENCE, _('Selection Divergence')),
-                (SELECTION_CONVERGENCE, _('Selection Convergence')),
-                (SIMULTANEOUS_DIVERGENCE, _('Simultaneous Divergence')),
-                (SIMULTANEOUS_CONVERGENCE, _('Simultaneous Convergence'))]:
+        focusbtn = None
+        for type, label in poss_div_btns:
             radio_button = wx.RadioButton(self, label=label, 
                   style=(wx.RB_GROUP if first else 0))
             radio_button.SetValue(first)
             self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, radio_button)
             self.LeftGridSizer.AddWindow(radio_button, flag=wx.GROW)
             self.TypeRadioButtons[type] = radio_button
+            if first: focusbtn = type
             first = False
 
         # Create label for number of divergence sequences
@@ -94,7 +104,7 @@
         
         # Selection divergence radio button is default control having keyboard
         # focus
-        self.TypeRadioButtons[SELECTION_DIVERGENCE].SetFocus()
+        self.TypeRadioButtons[focusbtn].SetFocus()
     
     def GetMinElementSize(self):
         """
--- a/editors/SFCViewer.py	Wed Nov 30 14:27:18 2016 +0300
+++ b/editors/SFCViewer.py	Thu Dec 01 16:40:49 2016 +0300
@@ -31,55 +31,57 @@
 from graphics.GraphicCommons import SELECTION_DIVERGENCE, \
     SELECTION_CONVERGENCE, SIMULTANEOUS_DIVERGENCE, SIMULTANEOUS_CONVERGENCE, EAST, NORTH, WEST, SOUTH
 
-type = [SELECTION_DIVERGENCE, SELECTION_CONVERGENCE, SIMULTANEOUS_DIVERGENCE, SIMULTANEOUS_CONVERGENCE]
-divergence = dict(zip(type,["SELECTION_DIVERGENCE", "SELECTION_CONVERGENCE",\
-                            "SIMULTANEOUS_DIVERGENCE", "SIMULTANEOUS_CONVERGENCE"]))
 SFC_Objects = (SFC_Step, SFC_ActionBlock, SFC_Transition, SFC_Divergence, SFC_Jump)
 
-StandardRules = {
-    # The key of this dict is a block that user try to connect,
-    # and the value is a list of blocks, that can be connected with the current block.
-    "SFC_Step" :                 ["SFC_ActionBlock",
-                                  "SFC_Transition",
-                                  "SELECTION_DIVERGENCE",
-                                  "SIMULTANEOUS_CONVERGENCE"],
-
-    "SFC_ActionBlock" :          ["SFC_Step"],
-
-    "SFC_Transition" :           ["SFC_Step",
-                                  "SELECTION_CONVERGENCE",
-                                  "SIMULTANEOUS_DIVERGENCE",
-                                  "SFC_Jump",
-                                  "FBD_Block",
-                                  "FBD_Variable"
-                                  "LD_Contact",
-                                  "LD_PowerRail",
-                                  "LD_Coil"],
-
-    "SELECTION_DIVERGENCE" :     ["SFC_Transition"],
-
-    "SELECTION_CONVERGENCE" :    ["SFC_Step",
-                                  "SFC_Jump"],
-
-    "SIMULTANEOUS_DIVERGENCE" :  ["SFC_Step"],
-
-    "SIMULTANEOUS_CONVERGENCE" : ["SFC_Transition"],
-
-    "SFC_Jump" :                 [],
-
-    "FBD_Block" :                ["SFC_Transition"],
-
-    "FBD_Variable" :             ["SFC_Transition"],
-
-    "LD_Contact" :               ["SFC_Transition"],
-
-    "LD_PowerRail" :             ["SFC_Transition"],
-
-    "LD_Coil" :                  ["SFC_Transition"]
-                }
 
 class SFC_Viewer(Viewer):
     
+    SFC_StandardRules = {
+        # The key of this dict is a block that user try to connect,
+        # and the value is a list of blocks, that can be connected with the current block
+        # and with directions of connection
+        "SFC_Step": [("SFC_ActionBlock", EAST),
+                     ("SFC_Transition", SOUTH),
+                     (SELECTION_DIVERGENCE, SOUTH),
+                     (SIMULTANEOUS_CONVERGENCE, SOUTH)],
+
+        "SFC_ActionBlock": [("SFC_Step", EAST)],
+
+        "SFC_Transition": [("SFC_Step", SOUTH),
+                           (SELECTION_CONVERGENCE, SOUTH),
+                           (SIMULTANEOUS_DIVERGENCE, SOUTH),
+                           ("SFC_Jump", SOUTH),
+                           ("FBD_Block", EAST),
+                           ("FBD_Variable", EAST),
+                           ("FBD_Connector", EAST),
+                           ("LD_Contact", EAST),
+                           ("LD_PowerRail", EAST),
+                           ("LD_Coil", EAST)],
+
+        SELECTION_DIVERGENCE: [("SFC_Transition", SOUTH)],
+
+        SELECTION_CONVERGENCE: [("SFC_Step", SOUTH),
+                                  ("SFC_Jump", SOUTH)],
+
+        SIMULTANEOUS_DIVERGENCE: [("SFC_Step", SOUTH)],
+
+        SIMULTANEOUS_CONVERGENCE: [("SFC_Transition", SOUTH)],
+
+        "SFC_Jump": [],
+
+        "FBD_Block": [("SFC_Transition", WEST)],
+
+        "FBD_Variable": [("SFC_Transition", WEST)],
+
+        "FBD_Connector": [("SFC_Transition", WEST)],
+
+        "LD_Contact": [("SFC_Transition", WEST)],
+
+        "LD_PowerRail": [("SFC_Transition", WEST)],
+
+        "LD_Coil": [("SFC_Transition", WEST)]
+    }
+
     def __init__(self, parent, tagname, window, controler, debug = False, instancepath = ""):
         Viewer.__init__(self, parent, tagname, window, controler, debug, instancepath)
         self.CurrentLanguage = "SFC"
@@ -335,20 +337,23 @@
     def GetBlockName(self, block):
         blockName = block.__class__.__name__
         if blockName == "SFC_Divergence":
-            blockName = divergence[block.Type]
+            blockName = block.Type
         return blockName
 
     # This method check the IEC 61131-3 compatibility between two SFC blocks
     def BlockCompatibility(self,startblock = None, endblock = None, direction = None):
         if startblock!= None and endblock != None and (isinstance(startblock,SFC_Objects)\
                                                                or isinstance(endblock,SFC_Objects)):
-            # Full "StandardRules" table would be simmetrical and
+            # Full "SFC_StandardRules" table would be symmetrical and
             # to avoid duplicate records and minimize the table only upper part is defined.
             if (direction == SOUTH or direction == EAST):
                 startblock, endblock = endblock, startblock
             start = self.GetBlockName(startblock)
             end = self.GetBlockName(endblock)
-            return end in StandardRules[start]
+            for val in self.SFC_StandardRules[start]:
+                if end in val:
+                    return True
+            return False
         return True
 
 #-------------------------------------------------------------------------------
--- a/editors/Viewer.py	Wed Nov 30 14:27:18 2016 +0300
+++ b/editors/Viewer.py	Thu Dec 01 16:40:49 2016 +0300
@@ -43,6 +43,7 @@
 SCROLL_ZONE = 10
 
 CURSORS = None
+SFC_Objects = (SFC_Step, SFC_ActionBlock, SFC_Transition, SFC_Divergence, SFC_Jump)
 
 def ResetCursors():
     global CURSORS
@@ -146,6 +147,9 @@
                                         specific_values.priority, id)
     return transition
 
+divergence_types = [SELECTION_DIVERGENCE,
+                    SELECTION_CONVERGENCE, SIMULTANEOUS_DIVERGENCE, SIMULTANEOUS_CONVERGENCE]
+
 def GetDivergenceCreationFunction(divergence_type):
     def divergenceCreationFunction(viewer, id, specific_values):
         return SFC_Divergence(viewer, divergence_type,
@@ -2060,47 +2064,7 @@
                     self.SelectedElement.HighlightPoint(pos)
                     self.RefreshBuffer()
                 elif connector is None or self.SelectedElement.GetDragging():
-                    start_connector = self.SelectedElement.GetStartConnected()
-                    start_direction = start_connector.GetDirection()
-
-                    items = []
-
-                    if self.CurrentLanguage == "SFC" and start_direction == SOUTH:
-                        items.extend([
-                            (_(u'Initial Step'), self.GetAddToWireMenuCallBack(self.AddNewStep, True)),
-                            (_(u'Step'), self.GetAddToWireMenuCallBack(self.AddNewStep, False)),
-                            (_(u'Transition'), self.GetAddToWireMenuCallBack(self.AddNewTransition, False)),
-                            (_(u'Divergence'), self.GetAddToWireMenuCallBack(self.AddNewDivergence)),
-                            (_(u'Jump'), self.GetAddToWireMenuCallBack(self.AddNewJump)),
-                        ])
-
-                    elif start_direction == EAST:
-
-                        if isinstance(start_connector.GetParentBlock(), SFC_Step):
-                            items.append(
-                                (_(u'Action Block'), self.GetAddToWireMenuCallBack(self.AddNewActionBlock))
-                            )
-                        else:
-                            items.extend([
-                                (_(u'Block'), self.GetAddToWireMenuCallBack(self.AddNewBlock)),
-                                (_(u'Variable'), self.GetAddToWireMenuCallBack(self.AddNewVariable, True)),
-                                (_(u'Connection'), self.GetAddToWireMenuCallBack(self.AddNewConnection)),
-                            ])
-
-                            if self.CurrentLanguage != "FBD":
-                                items.append(
-                                    (_(u'Contact'), self.GetAddToWireMenuCallBack(self.AddNewContact))
-                                )
-                            if self.CurrentLanguage == "LD":
-                                items.extend([
-                                    (_(u'Coil'), self.GetAddToWireMenuCallBack(self.AddNewCoil)),
-                                    (_(u'Power Rail'), self.GetAddToWireMenuCallBack(self.AddNewPowerRail)),
-                                ])
-                            if self.CurrentLanguage == "SFC":
-                                items.append(
-                                    (_(u'Transition'), self.GetAddToWireMenuCallBack(self.AddNewTransition, True))
-                                )
-
+                    items = self.GetPopupMenuItems()
                     if len(items) > 0:
                         if self.Editor.HasCapture():
                             self.Editor.ReleaseMouse()
@@ -2356,6 +2320,51 @@
     def BlockCompatibility(self, startblock=None, endblock=None, direction = None):
         return True
 
+    def GetPopupMenuItems(self):
+        start_connector = self.SelectedElement.GetStartConnected()
+        start_direction = start_connector.GetDirection()
+        startblock = start_connector.GetParentBlock()
+        items = []
+        if isinstance(startblock, SFC_Objects):
+            startblockname = self.GetBlockName(startblock)
+            poss_div_types = []
+
+            SFC_WireMenu_Buttons = {
+                'SFC_Step': (_(u'Step'), self.GetAddToWireMenuCallBack(self.AddNewStep, False)),
+                'SFC_Jump': (_(u'Jump'), self.GetAddToWireMenuCallBack(self.AddNewJump)),
+                'SFC_Transition': (_(u'Transition'), self.GetAddToWireMenuCallBack(self.AddNewTransition, False)),
+                'SFC_ActionBlock': (_(u'Action Block'), self.GetAddToWireMenuCallBack(self.AddNewActionBlock))}
+
+            for endblock in self.SFC_StandardRules.get(startblockname):
+                if start_direction in endblock:
+                    if endblock[0] in divergence_types:
+                        poss_div_types.append(endblock[0])
+                    else:
+                        items.append(SFC_WireMenu_Buttons[endblock[0]])
+            if len(poss_div_types) > 0:
+                items.append((_(u'Divergence'), self.GetAddToWireMenuCallBack(self.AddNewDivergence,
+                                                                              poss_div_types)))
+        elif start_direction == EAST:
+                items.extend([
+                    (_(u'Block'), self.GetAddToWireMenuCallBack(self.AddNewBlock)),
+                    (_(u'Connection'), self.GetAddToWireMenuCallBack(self.AddNewConnection))])
+
+                if self.CurrentLanguage != "FBD":
+                    items.append((_(u'Contact'), self.GetAddToWireMenuCallBack(self.AddNewContact)))
+
+                if self.CurrentLanguage == "LD":
+                    items.extend([
+                        (_(u'Coil'), self.GetAddToWireMenuCallBack(self.AddNewCoil)),
+                        (_(u'Power Rail'), self.GetAddToWireMenuCallBack(self.AddNewPowerRail))])
+
+                if self.CurrentLanguage == "SFC":
+                    items.append(
+                        (_(u'Transition'), self.GetAddToWireMenuCallBack(self.AddNewTransition, True)))
+                else:
+                    items.append(
+                        (_(u'Variable'), self.GetAddToWireMenuCallBack(self.AddNewVariable, True)))
+        return items
+
 #-------------------------------------------------------------------------------
 #                          Keyboard event functions
 #-------------------------------------------------------------------------------
@@ -2667,8 +2676,8 @@
                 connector = transition.GetConnectors()["inputs"][0]
             self.AddNewElement(transition, bbox, wire, connector)
 
-    def AddNewDivergence(self, bbox, wire=None):
-        dialog = SFCDivergenceDialog(self.ParentWindow, self.Controler, self.TagName)
+    def AddNewDivergence(self, bbox, poss_div_types = None, wire=None):
+        dialog = SFCDivergenceDialog(self.ParentWindow, self.Controler, self.TagName, poss_div_types)
         dialog.SetPreviewFont(self.GetFont())
         dialog.SetMinElementSize((bbox.width, bbox.height))
         if dialog.ShowModal() == wx.ID_OK: