# HG changeset patch # User Sergey Surkov # Date 1480599649 -10800 # Node ID 431f4ef34bde5932cce1203376bbae7ccdcf05e9 # Parent d91356480df9fed678571972d4b412db0644746f make only correct blocks(by IEC 61131-3 standard) available in wire popup menu in SFC Viewer diff -r d91356480df9 -r 431f4ef34bde dialogs/SFCDivergenceDialog.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): """ diff -r d91356480df9 -r 431f4ef34bde editors/SFCViewer.py --- 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 #------------------------------------------------------------------------------- diff -r d91356480df9 -r 431f4ef34bde editors/Viewer.py --- 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: