Laurent@814: #!/usr/bin/env python
Laurent@814: # -*- coding: utf-8 -*-
Laurent@814: 
andrej@1571: # This file is part of Beremiz, a Integrated Development Environment for
andrej@1571: # programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
Laurent@814: #
andrej@1571: # Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
Laurent@814: #
andrej@1571: # See COPYING file for copyrights details.
Laurent@814: #
andrej@1571: # This program is free software; you can redistribute it and/or
andrej@1571: # modify it under the terms of the GNU General Public License
andrej@1571: # as published by the Free Software Foundation; either version 2
andrej@1571: # of the License, or (at your option) any later version.
Laurent@814: #
andrej@1571: # This program is distributed in the hope that it will be useful,
andrej@1571: # but WITHOUT ANY WARRANTY; without even the implied warranty of
andrej@1571: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
andrej@1571: # GNU General Public License for more details.
Laurent@814: #
andrej@1571: # You should have received a copy of the GNU General Public License
andrej@1571: # along with this program; if not, write to the Free Software
andrej@1571: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
Laurent@814: 
andrej@1853: 
andrej@1853: from __future__ import absolute_import
andrej@2437: from __future__ import division
Laurent@814: 
Laurent@814: import wx
Laurent@814: 
andrej@1853: from editors.Viewer import *
surkovsv93@1567: from graphics.SFC_Objects import *
surkovsv93@1567: from graphics.GraphicCommons import SELECTION_DIVERGENCE, \
surkovsv93@1567:     SELECTION_CONVERGENCE, SIMULTANEOUS_DIVERGENCE, SIMULTANEOUS_CONVERGENCE, EAST, NORTH, WEST, SOUTH
surkovsv93@1567: 
surkovsv93@1567: SFC_Objects = (SFC_Step, SFC_ActionBlock, SFC_Transition, SFC_Divergence, SFC_Jump)
surkovsv93@1567: 
Laurent@814: 
Laurent@814: class SFC_Viewer(Viewer):
andrej@1730: 
surkovsv93@1584:     SFC_StandardRules = {
surkovsv93@1584:         # The key of this dict is a block that user try to connect,
surkovsv93@1584:         # and the value is a list of blocks, that can be connected with the current block
surkovsv93@1584:         # and with directions of connection
surkovsv93@1584:         "SFC_Step": [("SFC_ActionBlock", EAST),
surkovsv93@1584:                      ("SFC_Transition", SOUTH),
surkovsv93@1584:                      (SELECTION_DIVERGENCE, SOUTH),
surkovsv93@1584:                      (SIMULTANEOUS_CONVERGENCE, SOUTH)],
surkovsv93@1584: 
surkovsv93@1584:         "SFC_ActionBlock": [("SFC_Step", EAST)],
surkovsv93@1584: 
surkovsv93@1584:         "SFC_Transition": [("SFC_Step", SOUTH),
surkovsv93@1584:                            (SELECTION_CONVERGENCE, SOUTH),
surkovsv93@1584:                            (SIMULTANEOUS_DIVERGENCE, SOUTH),
surkovsv93@1584:                            ("SFC_Jump", SOUTH),
surkovsv93@1584:                            ("FBD_Block", EAST),
surkovsv93@1584:                            ("FBD_Variable", EAST),
surkovsv93@1584:                            ("FBD_Connector", EAST),
surkovsv93@1584:                            ("LD_Contact", EAST),
surkovsv93@1584:                            ("LD_PowerRail", EAST),
surkovsv93@1584:                            ("LD_Coil", EAST)],
surkovsv93@1584: 
surkovsv93@1584:         SELECTION_DIVERGENCE: [("SFC_Transition", SOUTH)],
surkovsv93@1584: 
surkovsv93@1584:         SELECTION_CONVERGENCE: [("SFC_Step", SOUTH),
andrej@1767:                                 ("SFC_Jump", SOUTH)],
surkovsv93@1584: 
surkovsv93@1584:         SIMULTANEOUS_DIVERGENCE: [("SFC_Step", SOUTH)],
surkovsv93@1584: 
surkovsv93@1584:         SIMULTANEOUS_CONVERGENCE: [("SFC_Transition", SOUTH)],
surkovsv93@1584: 
surkovsv93@1584:         "SFC_Jump": [],
surkovsv93@1584: 
surkovsv93@1584:         "FBD_Block": [("SFC_Transition", WEST)],
surkovsv93@1584: 
surkovsv93@1584:         "FBD_Variable": [("SFC_Transition", WEST)],
surkovsv93@1584: 
surkovsv93@1584:         "FBD_Connector": [("SFC_Transition", WEST)],
surkovsv93@1584: 
surkovsv93@1584:         "LD_Contact": [("SFC_Transition", WEST)],
surkovsv93@1584: 
surkovsv93@1584:         "LD_PowerRail": [("SFC_Transition", WEST)],
surkovsv93@1584: 
surkovsv93@1584:         "LD_Coil": [("SFC_Transition", WEST)]
surkovsv93@1584:     }
surkovsv93@1584: 
andrej@1744:     def __init__(self, parent, tagname, window, controler, debug=False, instancepath=""):
Laurent@814:         Viewer.__init__(self, parent, tagname, window, controler, debug, instancepath)
Laurent@814:         self.CurrentLanguage = "SFC"
andrej@1730: 
Laurent@814:     def ConnectConnectors(self, start, end):
Laurent@814:         startpoint = [start.GetPosition(False), start.GetDirection()]
Laurent@814:         endpoint = [end.GetPosition(False), end.GetDirection()]
Laurent@814:         wire = Wire(self, startpoint, endpoint)
Laurent@814:         self.AddWire(wire)
Laurent@814:         start.Connect((wire, 0), False)
Laurent@814:         end.Connect((wire, -1), False)
Laurent@814:         wire.ConnectStartPoint(None, start)
Laurent@814:         wire.ConnectEndPoint(None, end)
Laurent@814:         return wire
andrej@1730: 
andrej@1744:     def CreateTransition(self, connector, next=None):
Laurent@814:         previous = connector.GetParentBlock()
Laurent@814:         id = self.GetNewId()
Laurent@814:         transition = SFC_Transition(self, "reference", "", 0, id)
Laurent@814:         pos = connector.GetPosition(False)
Laurent@814:         transition.SetPosition(pos.x, pos.y + SFC_WIRE_MIN_SIZE)
Laurent@814:         transition_connectors = transition.GetConnectors()
Laurent@814:         wire = self.ConnectConnectors(transition_connectors["input"], connector)
Laurent@814:         if isinstance(previous, SFC_Divergence):
Laurent@814:             previous.RefreshConnectedPosition(connector)
Laurent@814:         else:
Laurent@814:             previous.RefreshOutputPosition()
Laurent@814:         wire.SetPoints([wx.Point(pos.x, pos.y + GetWireSize(previous)), wx.Point(pos.x, pos.y)])
Laurent@814:         self.AddBlock(transition)
Laurent@814:         self.Controler.AddEditedElementTransition(self.TagName, id)
Laurent@814:         self.RefreshTransitionModel(transition)
Laurent@814:         if next:
Laurent@814:             wire = self.ConnectConnectors(next, transition_connectors["output"])
Laurent@814:             pos = transition_connectors["output"].GetPosition(False)
Laurent@814:             next_block = next.GetParentBlock()
Laurent@814:             next_pos = next.GetPosition(False)
Laurent@814:             transition.RefreshOutputPosition((0, pos.y + SFC_WIRE_MIN_SIZE - next_pos.y))
Laurent@814:             wire.SetPoints([wx.Point(pos.x, pos.y + SFC_WIRE_MIN_SIZE), wx.Point(pos.x, pos.y)])
Laurent@814:             if isinstance(next_block, SFC_Divergence):
Laurent@814:                 next_block.RefreshPosition()
Laurent@814:             transition.RefreshOutputModel(True)
Laurent@814:         return transition
andrej@1730: 
Laurent@814:     def RemoveTransition(self, transition):
Laurent@814:         connectors = transition.GetConnectors()
Laurent@814:         input_wires = connectors["input"].GetWires()
Laurent@814:         if len(input_wires) != 1:
Laurent@814:             return
Laurent@814:         input_wire = input_wires[0][0]
Laurent@814:         previous = input_wire.EndConnected
Laurent@814:         input_wire.Clean()
Laurent@814:         self.RemoveWire(input_wire)
Laurent@814:         output_wires = connectors["output"].GetWires()
Laurent@814:         if len(output_wires) != 1:
Laurent@814:             return
Laurent@814:         output_wire = output_wires[0][0]
Laurent@814:         next = output_wire.StartConnected
Laurent@814:         output_wire.Clean()
Laurent@814:         self.RemoveWire(output_wire)
Laurent@814:         transition.Clean()
Laurent@814:         self.RemoveBlock(transition)
Laurent@814:         self.Controler.RemoveEditedElementInstance(self.TagName, transition.GetId())
Laurent@814:         wire = self.ConnectConnectors(next, previous)
Laurent@814:         return wire
andrej@1730: 
andrej@1744:     def CreateStep(self, name, connector, next=None):
Laurent@814:         previous = connector.GetParentBlock()
Laurent@814:         id = self.GetNewId()
Laurent@814:         step = SFC_Step(self, name, False, id)
Laurent@814:         if next:
Laurent@814:             step.AddOutput()
Laurent@814:         min_width, min_height = step.GetMinSize()
Laurent@814:         pos = connector.GetPosition(False)
Laurent@814:         step.SetPosition(pos.x, pos.y + SFC_WIRE_MIN_SIZE)
Laurent@814:         step.SetSize(min_width, min_height)
Laurent@814:         step_connectors = step.GetConnectors()
Laurent@814:         wire = self.ConnectConnectors(step_connectors["input"], connector)
Laurent@814:         if isinstance(previous, SFC_Divergence):
Laurent@814:             previous.RefreshConnectedPosition(connector)
Laurent@814:         else:
Laurent@814:             previous.RefreshOutputPosition()
Laurent@814:         wire.SetPoints([wx.Point(pos.x, pos.y + GetWireSize(previous)), wx.Point(pos.x, pos.y)])
Laurent@814:         self.AddBlock(step)
Laurent@814:         self.Controler.AddEditedElementStep(self.TagName, id)
Laurent@814:         self.RefreshStepModel(step)
Laurent@814:         if next:
Laurent@814:             wire = self.ConnectConnectors(next, step_connectors["output"])
Laurent@814:             pos = step_connectors["output"].GetPosition(False)
Laurent@814:             next_block = next.GetParentBlock()
Laurent@814:             next_pos = next.GetPosition(False)
Laurent@814:             step.RefreshOutputPosition((0, pos.y + SFC_WIRE_MIN_SIZE - next_pos.y))
Laurent@814:             wire.SetPoints([wx.Point(pos.x, pos.y + SFC_WIRE_MIN_SIZE), wx.Point(pos.x, pos.y)])
Laurent@814:             if isinstance(next_block, SFC_Divergence):
Laurent@814:                 next_block.RefreshPosition()
Laurent@814:             step.RefreshOutputModel(True)
Laurent@814:         return step
Laurent@814: 
Laurent@814:     def RemoveStep(self, step):
Laurent@814:         connectors = step.GetConnectors()
Laurent@814:         if connectors["input"]:
Laurent@814:             input_wires = connectors["input"].GetWires()
Laurent@814:             if len(input_wires) != 1:
Laurent@814:                 return
Laurent@814:             input_wire = input_wires[0][0]
Laurent@814:             previous = input_wire.EndConnected
Laurent@814:             input_wire.Clean()
Laurent@814:             self.RemoveWire(input_wire)
Laurent@814:         else:
Laurent@814:             previous = None
Laurent@814:         if connectors["output"]:
Laurent@814:             output_wires = connectors["output"].GetWires()
Laurent@814:             if len(output_wires) != 1:
Laurent@814:                 return
Laurent@814:             output_wire = output_wires[0][0]
Laurent@814:             next = output_wire.StartConnected
Laurent@814:             output_wire.Clean()
Laurent@814:             self.RemoveWire(output_wire)
Laurent@814:         else:
Laurent@814:             next = None
Laurent@814:         action = step.GetActionConnected()
Laurent@814:         if action:
Laurent@814:             self.DeleteActionBlock(action.GetParentBlock())
Laurent@814:         step.Clean()
Laurent@814:         self.RemoveBlock(step)
Laurent@814:         self.Controler.RemoveEditedElementInstance(self.TagName, step.GetId())
Laurent@814:         if next and previous:
Laurent@814:             wire = self.ConnectConnectors(next, previous)
Laurent@814:             return wire
Laurent@814:         else:
Laurent@814:             return None
Laurent@814: 
andrej@1782:     # -------------------------------------------------------------------------------
andrej@1782:     #                          Mouse event functions
andrej@1782:     # -------------------------------------------------------------------------------
Laurent@814: 
Laurent@814:     def OnViewerLeftDown(self, event):
Laurent@814:         if self.GetDrawingMode() == FREEDRAWING_MODE:
Laurent@814:             Viewer.OnViewerLeftDown(self, event)
Laurent@814:         elif self.Mode == MODE_SELECTION:
Laurent@814:             if event.ShiftDown() and not event.ControlDown() and self.SelectedElement is not None:
Laurent@814:                 element = self.FindElement(event, True)
Laurent@814:                 if element and not self.IsWire(element):
Laurent@814:                     if isinstance(self.SelectedElement, Graphic_Group):
Laurent@814:                         self.SelectedElement.SelectElement(element)
Laurent@814:                     else:
Laurent@814:                         group = Graphic_Group(self)
Laurent@814:                         self.SelectedElement.SetSelected(False)
Laurent@814:                         group.SelectElement(self.SelectedElement)
Laurent@814:                         group.SelectElement(element)
Laurent@814:                         self.SelectedElement = group
Laurent@814:                     elements = self.SelectedElement.GetElements()
Laurent@814:                     if len(elements) == 0:
Laurent@814:                         self.SelectedElement = element
Laurent@814:                     elif len(elements) == 1:
Laurent@814:                         self.SelectedElement = elements[0]
Laurent@814:                     self.SelectedElement.SetSelected(True)
Laurent@814:             else:
Laurent@814:                 element = self.FindElement(event)
Laurent@814:                 if self.SelectedElement and self.SelectedElement != element:
Laurent@814:                     if self.IsWire(self.SelectedElement):
Laurent@814:                         self.SelectedElement.SetSelectedSegment(None)
Laurent@814:                     else:
Laurent@814:                         self.SelectedElement.SetSelected(False)
Laurent@814:                     self.SelectedElement = None
Laurent@814:                 if element:
Laurent@814:                     self.SelectedElement = element
Laurent@814:                     self.SelectedElement.OnLeftDown(event, self.GetLogicalDC(), self.Scaling)
Laurent@814:                     self.SelectedElement.Refresh()
Laurent@814:                 else:
Laurent@814:                     self.rubberBand.Reset()
Laurent@814:                     self.rubberBand.OnLeftDown(event, self.GetLogicalDC(), self.Scaling)
Laurent@814:         elif self.Mode == MODE_COMMENT:
Laurent@814:             self.rubberBand.Reset()
Laurent@814:             self.rubberBand.OnLeftDown(event, self.GetLogicalDC(), self.Scaling)
Laurent@814:         event.Skip()
Laurent@814: 
Laurent@814:     def OnViewerLeftUp(self, event):
Laurent@814:         if self.GetDrawingMode() == FREEDRAWING_MODE:
Laurent@814:             Viewer.OnViewerLeftUp(self, event)
Laurent@814:         elif self.rubberBand.IsShown():
Laurent@814:             if self.Mode == MODE_SELECTION:
Laurent@814:                 elements = self.SearchElements(self.rubberBand.GetCurrentExtent())
Laurent@814:                 self.rubberBand.OnLeftUp(event, self.GetLogicalDC(), self.Scaling)
Laurent@814:                 if len(elements) > 0:
Laurent@814:                     self.SelectedElement = Graphic_Group(self)
Laurent@814:                     self.SelectedElement.SetElements(elements)
Laurent@814:                     self.SelectedElement.SetSelected(True)
Laurent@814:             elif self.Mode == MODE_COMMENT:
Laurent@814:                 bbox = self.rubberBand.GetCurrentExtent()
Laurent@814:                 self.rubberBand.OnLeftUp(event, self.GetLogicalDC(), self.Scaling)
Laurent@814:                 wx.CallAfter(self.AddComment, bbox)
Laurent@814:         elif self.Mode == MODE_INITIALSTEP:
Laurent@814:             wx.CallAfter(self.AddInitialStep, GetScaledEventPosition(event, self.GetLogicalDC(), self.Scaling))
Laurent@814:         elif self.Mode == MODE_SELECTION and self.SelectedElement:
Laurent@814:             if self.IsWire(self.SelectedElement):
Laurent@814:                 self.SelectedElement.SetSelectedSegment(0)
Laurent@814:             else:
Laurent@814:                 self.SelectedElement.OnLeftUp(event, self.GetLogicalDC(), self.Scaling)
Laurent@814:                 self.SelectedElement.Refresh()
Laurent@814:             wx.CallAfter(self.SetCurrentCursor, 0)
andrej@1872:         #
andrej@1872:         # FIXME:
andrej@1872:         # This code was forgotten by commit
andrej@1872:         # 9c74d00ce93e from plcopeneditor_history repository
andrej@1872:         # 'Last bugs on block and wire moving, resizing with cursor fixed'
andrej@1872:         #
andrej@1872:         # elif self.Mode == MODE_WIRE and self.SelectedElement:
andrej@1872:         #     self.SelectedElement.ResetPoints()
andrej@1872:         #     self.SelectedElement.OnMotion(event, self.GetLogicalDC(), self.Scaling)
andrej@1872:         #     self.SelectedElement.GeneratePoints()
andrej@1872:         #     self.SelectedElement.RefreshModel()
andrej@1872:         #     self.SelectedElement.SetSelected(True)
Laurent@814:         event.Skip()
andrej@1730: 
Laurent@814:     def OnViewerRightUp(self, event):
Laurent@814:         if self.GetDrawingMode() == FREEDRAWING_MODE:
Laurent@814:             Viewer.OnViewerRightUp(self, event)
Laurent@814:         else:
Laurent@814:             element = self.FindElement(event)
Laurent@814:             if element:
Laurent@814:                 if self.SelectedElement and self.SelectedElement != element:
Laurent@814:                     self.SelectedElement.SetSelected(False)
Laurent@814:                 self.SelectedElement = element
Laurent@814:                 if self.IsWire(self.SelectedElement):
Laurent@814:                     self.SelectedElement.SetSelectedSegment(0)
Laurent@814:                 else:
Laurent@814:                     self.SelectedElement.SetSelected(True)
Laurent@814:                     self.SelectedElement.OnRightUp(event, self.GetLogicalDC(), self.Scaling)
Laurent@814:                     self.SelectedElement.Refresh()
Laurent@814:                 wx.CallAfter(self.SetCurrentCursor, 0)
Laurent@814:         event.Skip()
andrej@1730: 
Laurent@814:     def OnViewerLeftDClick(self, event):
Laurent@814:         if self.GetDrawingMode() == FREEDRAWING_MODE:
Laurent@814:             Viewer.OnViewerLeftDClick(self, event)
Laurent@814:         elif self.Mode == MODE_SELECTION and self.SelectedElement:
Laurent@814:             self.SelectedElement.OnLeftDClick(event, self.GetLogicalDC(), self.Scaling)
Laurent@814:             self.Refresh(False)
Laurent@814:         event.Skip()
andrej@1730: 
Laurent@814:     def OnViewerMotion(self, event):
Laurent@814:         if self.GetDrawingMode() == FREEDRAWING_MODE:
Laurent@814:             Viewer.OnViewerMotion(self, event)
Laurent@814:         else:
Laurent@814:             if self.rubberBand.IsShown():
Laurent@814:                 self.rubberBand.OnMotion(event, self.GetLogicalDC(), self.Scaling)
Laurent@814:             elif self.Mode == MODE_SELECTION and self.SelectedElement:
Laurent@814:                 if not self.IsWire(self.SelectedElement) and not isinstance(self.SelectedElement, Graphic_Group):
Laurent@814:                     self.SelectedElement.OnMotion(event, self.GetLogicalDC(), self.Scaling)
Laurent@814:                     self.SelectedElement.Refresh()
andrej@1872:             #
andrej@1872:             # FIXME:
andrej@1872:             # This code was forgotten by commit
andrej@1872:             # 9c74d00ce93e from plcopeneditor_history repository
andrej@1872:             # 'Last bugs on block and wire moving, resizing with cursor fixed'
andrej@1872:             #
andrej@1872:             # elif self.Mode == MODE_WIRE and self.SelectedElement:
andrej@1872:             #     self.SelectedElement.ResetPoints()
andrej@1872:             #     self.SelectedElement.OnMotion(event, self.GetLogicalDC(), self.Scaling)
andrej@1872:             #     self.SelectedElement.GeneratePoints()
andrej@1872:             #     self.SelectedElement.Refresh()
Laurent@814:             self.UpdateScrollPos(event)
Laurent@814:         event.Skip()
Laurent@814: 
surkovsv93@1567:     def GetBlockName(self, block):
surkovsv93@1567:         blockName = block.__class__.__name__
surkovsv93@1567:         if blockName == "SFC_Divergence":
surkovsv93@1584:             blockName = block.Type
surkovsv93@1567:         return blockName
surkovsv93@1567: 
surkovsv93@1567:     # This method check the IEC 61131-3 compatibility between two SFC blocks
andrej@1744:     def BlockCompatibility(self, startblock=None, endblock=None, direction=None):
andrej@1764:         if startblock is not None and endblock is not None and \
andrej@1764:            (isinstance(startblock, SFC_Objects) or isinstance(endblock, SFC_Objects)):
surkovsv93@1584:             # Full "SFC_StandardRules" table would be symmetrical and
surkovsv93@1567:             # to avoid duplicate records and minimize the table only upper part is defined.
andrej@1828:             if direction == SOUTH or direction == EAST:
surkovsv93@1567:                 startblock, endblock = endblock, startblock
surkovsv93@1567:             start = self.GetBlockName(startblock)
surkovsv93@1567:             end = self.GetBlockName(endblock)
surkovsv93@1584:             for val in self.SFC_StandardRules[start]:
surkovsv93@1584:                 if end in val:
surkovsv93@1584:                     return True
surkovsv93@1584:             return False
surkovsv93@1567:         return True
surkovsv93@1567: 
andrej@1782:     # -------------------------------------------------------------------------------
andrej@1782:     #                          Keyboard event functions
andrej@1782:     # -------------------------------------------------------------------------------
Laurent@814: 
Laurent@814:     def OnChar(self, event):
Laurent@814:         if self.GetDrawingMode() == FREEDRAWING_MODE:
Laurent@814:             Viewer.OnChar(self, event)
Laurent@814:         else:
Laurent@814:             xpos, ypos = self.GetScrollPos(wx.HORIZONTAL), self.GetScrollPos(wx.VERTICAL)
Laurent@814:             xmax = self.GetScrollRange(wx.HORIZONTAL) - self.GetScrollThumb(wx.HORIZONTAL)
Laurent@814:             ymax = self.GetScrollRange(wx.VERTICAL) - self.GetScrollThumb(wx.VERTICAL)
Laurent@814:             keycode = event.GetKeyCode()
Laurent@814:             if self.Scaling:
Laurent@814:                 scaling = self.Scaling
Laurent@814:             else:
Laurent@814:                 scaling = (8, 8)
Laurent@814:             if keycode == wx.WXK_DELETE and self.SelectedElement:
Laurent@814:                 self.SelectedElement.Delete()
Laurent@814:                 self.SelectedElement = None
Laurent@814:                 self.RefreshBuffer()
Laurent@814:                 self.RefreshScrollBars()
Laurent@814:                 self.Refresh(False)
Laurent@814:             elif keycode == wx.WXK_LEFT:
Laurent@814:                 if event.ControlDown() and event.ShiftDown():
Laurent@814:                     self.Scroll(0, ypos)
Laurent@814:                 elif event.ControlDown():
Laurent@814:                     event.Skip()
Laurent@814:                 elif self.SelectedElement:
Laurent@814:                     self.SelectedElement.Move(-scaling[0], 0)
Laurent@814:                     self.SelectedElement.RefreshModel()
Laurent@814:                     self.RefreshBuffer()
Laurent@814:                     self.RefreshScrollBars()
Laurent@814:                     self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(-scaling[0], 0)), False)
Laurent@814:             elif keycode == wx.WXK_RIGHT:
Laurent@814:                 if event.ControlDown() and event.ShiftDown():
Laurent@814:                     self.Scroll(xmax, ypos)
Laurent@814:                 elif event.ControlDown():
Laurent@814:                     event.Skip()
Laurent@814:                 elif self.SelectedElement:
Laurent@814:                     self.SelectedElement.Move(scaling[0], 0)
Laurent@814:                     self.SelectedElement.RefreshModel()
Laurent@814:                     self.RefreshBuffer()
Laurent@814:                     self.RefreshScrollBars()
Laurent@814:                     self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(scaling[0], 0)), False)
Laurent@814:             elif keycode == wx.WXK_UP:
Laurent@814:                 if event.ControlDown() and event.ShiftDown():
Laurent@814:                     self.Scroll(xpos, 0)
Laurent@814:                 elif event.ControlDown():
Laurent@814:                     event.Skip()
Laurent@814:                 elif self.SelectedElement:
Laurent@814:                     self.SelectedElement.Move(0, -scaling[1])
Laurent@814:                     self.SelectedElement.RefreshModel()
Laurent@814:                     self.RefreshBuffer()
Laurent@814:                     self.RefreshScrollBars()
Laurent@814:                     self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(0, -scaling[1])), False)
Laurent@814:             elif keycode == wx.WXK_DOWN:
Laurent@814:                 if event.ControlDown() and event.ShiftDown():
Laurent@814:                     self.Scroll(xpos, ymax)
Laurent@814:                 elif event.ControlDown():
Laurent@814:                     event.Skip()
Laurent@814:                 elif self.SelectedElement:
Laurent@814:                     self.SelectedElement.Move(0, scaling[1])
Laurent@814:                     self.SelectedElement.RefreshModel()
Laurent@814:                     self.RefreshBuffer()
Laurent@814:                     self.RefreshScrollBars()
Laurent@814:                     self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(0, scaling[1])), False)
Laurent@814:             else:
Laurent@814:                 event.Skip()
andrej@1730: 
andrej@1782:     # -------------------------------------------------------------------------------
andrej@1782:     #                          Adding element functions
andrej@1782:     # -------------------------------------------------------------------------------
Laurent@814: 
Laurent@814:     def AddInitialStep(self, pos):
andrej@1745:         dialog = SFCStepNameDialog(self.ParentWindow, _("Please enter step name"), _("Add a new initial step"), "", wx.OK | wx.CANCEL)
Laurent@814:         dialog.SetPouNames(self.Controler.GetProjectPouNames(self.Debug))
Laurent@1347:         dialog.SetVariables(self.Controler.GetEditedElementInterfaceVars(self.TagName, debug=self.Debug))
Laurent@814:         dialog.SetStepNames([block.GetName() for block in self.Blocks if isinstance(block, SFC_Step)])
Laurent@814:         if dialog.ShowModal() == wx.ID_OK:
Laurent@814:             id = self.GetNewId()
Laurent@814:             name = dialog.GetValue()
Laurent@814:             step = SFC_Step(self, name, True, id)
Laurent@814:             min_width, min_height = step.GetMinSize()
Laurent@814:             step.SetPosition(pos.x, pos.y)
Laurent@814:             width, height = step.GetSize()
Laurent@814:             step.SetSize(max(min_width, width), max(min_height, height))
Laurent@814:             self.AddBlock(step)
Laurent@814:             self.Controler.AddEditedElementStep(self.TagName, id)
Laurent@814:             self.RefreshStepModel(step)
Laurent@814:             self.RefreshBuffer()
Laurent@814:             self.RefreshScrollBars()
Laurent@814:             self.Refresh(False)
Laurent@814:         dialog.Destroy()
Laurent@814: 
Laurent@814:     def AddStep(self):
Laurent@814:         if self.SelectedElement in self.Wires or isinstance(self.SelectedElement, SFC_Step):
andrej@1745:             dialog = SFCStepNameDialog(self.ParentWindow, _("Add a new step"), _("Please enter step name"), "", wx.OK | wx.CANCEL)
Laurent@814:             dialog.SetPouNames(self.Controler.GetProjectPouNames(self.Debug))
Laurent@1347:             dialog.SetVariables(self.Controler.GetEditedElementInterfaceVars(self.TagName, debug=self.Debug))
Laurent@814:             dialog.SetStepNames([block.GetName() for block in self.Blocks if isinstance(block, SFC_Step)])
Laurent@814:             if dialog.ShowModal() == wx.ID_OK:
Laurent@814:                 name = dialog.GetValue()
Laurent@814:                 if self.IsWire(self.SelectedElement):
Laurent@814:                     self.SelectedElement.SetSelectedSegment(None)
Laurent@814:                     previous = self.SelectedElement.EndConnected
Laurent@814:                     next = self.SelectedElement.StartConnected
Laurent@814:                     self.SelectedElement.Clean()
Laurent@814:                     self.RemoveWire(self.SelectedElement)
Laurent@814:                 else:
Laurent@814:                     connectors = self.SelectedElement.GetConnectors()
Laurent@814:                     if connectors["output"]:
Laurent@814:                         previous = connectors["output"]
Laurent@814:                         wires = previous.GetWires()
Laurent@814:                         if len(wires) != 1:
Laurent@814:                             return
Laurent@814:                         wire = wires[0][0]
Laurent@814:                         next = wire.StartConnected
Laurent@814:                         wire.Clean()
Laurent@814:                         self.RemoveWire(wire)
Laurent@814:                     else:
Laurent@814:                         self.SelectedElement.AddOutput()
Laurent@814:                         connectors = self.SelectedElement.GetConnectors()
Laurent@814:                         self.RefreshStepModel(self.SelectedElement)
Laurent@814:                         previous = connectors["output"]
Laurent@814:                         next = None
Laurent@814:                 previous_block = previous.GetParentBlock()
Laurent@814:                 if isinstance(previous_block, SFC_Step) or isinstance(previous_block, SFC_Divergence) and previous_block.GetType() in [SELECTION_DIVERGENCE, SELECTION_CONVERGENCE]:
Laurent@814:                     transition = self.CreateTransition(previous)
Laurent@814:                     transition_connectors = transition.GetConnectors()
Laurent@814:                     step = self.CreateStep(name, transition_connectors["output"], next)
Laurent@814:                 else:
Laurent@814:                     step = self.CreateStep(name, previous)
Laurent@814:                     step.AddOutput()
Laurent@814:                     step.RefreshModel()
Laurent@814:                     step_connectors = step.GetConnectors()
Laurent@814:                     transition = self.CreateTransition(step_connectors["output"], next)
Laurent@814:                 if self.IsWire(self.SelectedElement):
Laurent@814:                     self.SelectedElement = wire
Laurent@814:                     self.SelectedElement.SetSelectedSegment(0)
Laurent@814:                 else:
Laurent@814:                     self.SelectedElement.SetSelected(False)
Laurent@814:                     self.SelectedElement = step
Laurent@814:                     self.SelectedElement.SetSelected(True)
Laurent@814:                 self.RefreshBuffer()
Laurent@814:                 self.RefreshScrollBars()
Laurent@814:                 self.Refresh(False)
Laurent@814:             dialog.Destroy()
andrej@1730: 
Laurent@814:     def AddStepAction(self):
Laurent@814:         if isinstance(self.SelectedElement, SFC_Step):
Laurent@814:             connectors = self.SelectedElement.GetConnectors()
Laurent@814:             if not connectors["action"]:
Laurent@814:                 dialog = ActionBlockDialog(self.ParentWindow)
Laurent@814:                 dialog.SetQualifierList(self.Controler.GetQualifierTypes())
Laurent@814:                 dialog.SetActionList(self.Controler.GetEditedElementActions(self.TagName, self.Debug))
Laurent@1347:                 dialog.SetVariableList(self.Controler.GetEditedElementInterfaceVars(self.TagName, debug=self.Debug))
Laurent@814:                 if dialog.ShowModal() == wx.ID_OK:
Laurent@814:                     actions = dialog.GetValues()
Laurent@814:                     self.SelectedElement.AddAction()
Laurent@814:                     self.RefreshStepModel(self.SelectedElement)
Laurent@814:                     connectors = self.SelectedElement.GetConnectors()
Laurent@814:                     pos = connectors["action"].GetPosition(False)
Laurent@814:                     id = self.GetNewId()
Laurent@814:                     actionblock = SFC_ActionBlock(self, [], id)
andrej@2437:                     actionblock.SetPosition(pos.x + SFC_WIRE_MIN_SIZE, pos.y - SFC_STEP_DEFAULT_SIZE[1] // 2)
Laurent@814:                     actionblock_connector = actionblock.GetConnector()
Laurent@814:                     wire = self.ConnectConnectors(actionblock_connector, connectors["action"])
Laurent@814:                     wire.SetPoints([wx.Point(pos.x + SFC_WIRE_MIN_SIZE, pos.y), wx.Point(pos.x, pos.y)])
Laurent@814:                     actionblock.SetActions(actions)
Laurent@814:                     self.AddBlock(actionblock)
Laurent@814:                     self.Controler.AddEditedElementActionBlock(self.TagName, id)
Laurent@814:                     self.RefreshActionBlockModel(actionblock)
Laurent@814:                     self.RefreshBuffer()
Laurent@814:                     self.RefreshScrollBars()
Laurent@814:                     self.Refresh(False)
Laurent@814:                 dialog.Destroy()
andrej@1730: 
Laurent@814:     def AddDivergence(self):
andrej@2414:         if self.SelectedElement in self.Wires or isinstance(self.SelectedElement, (Graphic_Group, SFC_Step)):
andrej@1865:             dialog = SFCDivergenceDialog(self.ParentWindow, self.Controler, self.TagName)
Laurent@814:             dialog.SetPreviewFont(self.GetFont())
Laurent@814:             if dialog.ShowModal() == wx.ID_OK:
Laurent@814:                 value = dialog.GetValues()
Laurent@814:                 if value["type"] == SELECTION_DIVERGENCE:
Laurent@814:                     if self.SelectedElement in self.Wires and isinstance(self.SelectedElement.EndConnected.GetParentBlock(), SFC_Step):
Laurent@814:                         self.SelectedElement.SetSelectedSegment(None)
Laurent@814:                         previous = self.SelectedElement.EndConnected
Laurent@814:                         next = self.SelectedElement.StartConnected
Laurent@814:                         self.SelectedElement.Clean()
Laurent@814:                         self.RemoveWire(self.SelectedElement)
Laurent@814:                         self.SelectedElement = None
Laurent@814:                     elif isinstance(self.SelectedElement, SFC_Step):
Laurent@814:                         connectors = self.SelectedElement.GetConnectors()
Laurent@814:                         if connectors["output"]:
Laurent@814:                             previous = connectors["output"]
Laurent@814:                             wires = previous.GetWires()
Laurent@814:                             if len(wires) != 1:
Laurent@814:                                 return
Laurent@814:                             wire = wires[0][0]
Laurent@814:                             next = wire.StartConnected
Laurent@814:                             wire.Clean()
Laurent@814:                             self.RemoveWire(wire)
Laurent@814:                         else:
Laurent@814:                             self.SelectedElement.AddOutput()
Laurent@814:                             connectors = self.SelectedElement.GetConnectors()
Laurent@814:                             self.RefreshStepModel(self.SelectedElement)
Laurent@814:                             previous = connectors["output"]
Laurent@814:                             next = None
Laurent@814:                     else:
Laurent@814:                         return
Laurent@814:                     id = self.GetNewId()
Laurent@814:                     divergence = SFC_Divergence(self, SELECTION_DIVERGENCE, value["number"], id)
Laurent@814:                     pos = previous.GetPosition(False)
Laurent@814:                     previous_block = previous.GetParentBlock()
Laurent@814:                     wire_size = GetWireSize(previous_block)
Laurent@814:                     divergence.SetPosition(pos.x, pos.y + wire_size)
Laurent@814:                     divergence_connectors = divergence.GetConnectors()
Laurent@814:                     wire = self.ConnectConnectors(divergence_connectors["inputs"][0], previous)
Laurent@814:                     previous_block.RefreshOutputPosition()
Laurent@814:                     wire.SetPoints([wx.Point(pos.x, pos.y + wire_size), wx.Point(pos.x, pos.y)])
Laurent@814:                     self.AddBlock(divergence)
Laurent@814:                     self.Controler.AddEditedElementDivergence(self.TagName, id, value["type"])
Laurent@814:                     self.RefreshDivergenceModel(divergence)
andrej@1847:                     for _index, connector in enumerate(divergence_connectors["outputs"]):
Laurent@814:                         if next:
Laurent@814:                             wire = self.ConnectConnectors(next, connector)
Laurent@814:                             pos = connector.GetPosition(False)
Laurent@814:                             next_pos = next.GetPosition(False)
Laurent@814:                             next_block = next.GetParentBlock()
Laurent@814:                             divergence.RefreshOutputPosition((0, pos.y + SFC_WIRE_MIN_SIZE - next_pos.y))
Laurent@814:                             divergence.RefreshConnectedPosition(connector)
Laurent@814:                             wire.SetPoints([wx.Point(pos.x, pos.y + SFC_WIRE_MIN_SIZE), wx.Point(pos.x, pos.y)])
Laurent@814:                             next_block.RefreshModel()
Laurent@814:                             next = None
Laurent@814:                         else:
Laurent@814:                             transition = self.CreateTransition(connector)
Laurent@814:                             transition_connectors = transition.GetConnectors()
andrej@1847:                             _step = self.CreateStep("Step", transition_connectors["output"])
Laurent@814:                 elif value["type"] == SIMULTANEOUS_DIVERGENCE:
Laurent@814:                     if self.SelectedElement in self.Wires and isinstance(self.SelectedElement.EndConnected.GetParentBlock(), SFC_Transition):
Laurent@814:                         self.SelectedElement.SetSelectedSegment(None)
Laurent@814:                         previous = self.SelectedElement.EndConnected
Laurent@814:                         next = self.SelectedElement.StartConnected
Laurent@814:                         self.SelectedElement.Clean()
Laurent@814:                         self.RemoveWire(self.SelectedElement)
Laurent@814:                         self.SelectedElement = None
Laurent@814:                     elif isinstance(self.SelectedElement, SFC_Step):
Laurent@814:                         connectors = self.SelectedElement.GetConnectors()
Laurent@814:                         if connectors["output"]:
Laurent@814:                             previous = connectors["output"]
Laurent@814:                             wires = previous.GetWires()
Laurent@814:                             if len(wires) != 1:
Laurent@814:                                 return
Laurent@814:                             wire = wires[0][0]
Laurent@814:                             next = wire.StartConnected
Laurent@814:                             wire.Clean()
Laurent@814:                             self.RemoveWire(wire)
Laurent@814:                         else:
Laurent@814:                             self.SelectedElement.AddOutput()
Laurent@814:                             connectors = self.SelectedElement.GetConnectors()
Laurent@814:                             self.RefreshStepModel(self.SelectedElement)
Laurent@814:                             previous = connectors["output"]
Laurent@814:                             next = None
Laurent@814:                         transition = self.CreateTransition(previous)
Laurent@814:                         transition_connectors = transition.GetConnectors()
Laurent@814:                         previous = transition_connectors["output"]
Laurent@814:                     else:
Laurent@814:                         return
Laurent@814:                     id = self.GetNewId()
Laurent@814:                     divergence = SFC_Divergence(self, SIMULTANEOUS_DIVERGENCE, value["number"], id)
Laurent@814:                     pos = previous.GetPosition(False)
Laurent@814:                     previous_block = previous.GetParentBlock()
Laurent@814:                     wire_size = GetWireSize(previous_block)
Laurent@814:                     divergence.SetPosition(pos.x, pos.y + wire_size)
Laurent@814:                     divergence_connectors = divergence.GetConnectors()
Laurent@814:                     wire = self.ConnectConnectors(divergence_connectors["inputs"][0], previous)
Laurent@814:                     previous_block.RefreshOutputPosition()
Laurent@814:                     wire.SetPoints([wx.Point(pos.x, pos.y + wire_size), wx.Point(pos.x, pos.y)])
Laurent@814:                     self.AddBlock(divergence)
Laurent@814:                     self.Controler.AddEditedElementDivergence(self.TagName, id, value["type"])
Laurent@814:                     self.RefreshDivergenceModel(divergence)
andrej@1847:                     for _index, connector in enumerate(divergence_connectors["outputs"]):
Laurent@814:                         if next:
Laurent@814:                             wire = self.ConnectConnectors(next, connector)
Laurent@814:                             pos = connector.GetPosition(False)
Laurent@814:                             next_pos = next.GetPosition(False)
Laurent@814:                             next_block = next.GetParentBlock()
Laurent@814:                             divergence.RefreshOutputPosition((0, pos.y + SFC_WIRE_MIN_SIZE - next_pos.y))
Laurent@814:                             divergence.RefreshConnectedPosition(connector)
Laurent@814:                             wire.SetPoints([wx.Point(pos.x, pos.y + SFC_WIRE_MIN_SIZE), wx.Point(pos.x, pos.y)])
Laurent@814:                             next_block.RefreshModel()
Laurent@814:                             next = None
Laurent@814:                         else:
andrej@1847:                             _step = self.CreateStep("Step", connector)
Laurent@814:                 elif isinstance(self.SelectedElement, Graphic_Group) and len(self.SelectedElement.GetElements()) > 1:
Laurent@814:                     next = None
Laurent@814:                     for element in self.SelectedElement.GetElements():
Laurent@814:                         connectors = element.GetConnectors()
Laurent@814:                         if not isinstance(element, SFC_Step) or connectors["output"] and next:
Laurent@814:                             return
Laurent@814:                         elif connectors["output"] and not next:
Laurent@814:                             wires = connectors["output"].GetWires()
Laurent@814:                             if len(wires) != 1:
Laurent@814:                                 return
Laurent@814:                             if value["type"] == SELECTION_CONVERGENCE:
Laurent@814:                                 transition = wires[0][0].StartConnected.GetParentBlock()
Laurent@814:                                 transition_connectors = transition.GetConnectors()
Laurent@814:                                 wires = transition_connectors["output"].GetWires()
Laurent@814:                                 if len(wires) != 1:
Laurent@814:                                     return
Laurent@814:                             wire = wires[0][0]
Laurent@814:                             next = wire.StartConnected
Laurent@814:                             wire.Clean()
Laurent@814:                             self.RemoveWire(wire)
Laurent@814:                     inputs = []
Laurent@814:                     for input in self.SelectedElement.GetElements():
Laurent@814:                         input_connectors = input.GetConnectors()
Laurent@814:                         if not input_connectors["output"]:
Laurent@814:                             input.AddOutput()
Laurent@814:                             input.RefreshModel()
Laurent@814:                             input_connectors = input.GetConnectors()
Laurent@814:                             if value["type"] == SELECTION_CONVERGENCE:
Laurent@814:                                 transition = self.CreateTransition(input_connectors["output"])
Laurent@814:                                 transition_connectors = transition.GetConnectors()
Laurent@814:                                 inputs.append(transition_connectors["output"])
Laurent@814:                             else:
Laurent@814:                                 inputs.append(input_connectors["output"])
Laurent@814:                         elif value["type"] == SELECTION_CONVERGENCE:
Laurent@814:                             wires = input_connectors["output"].GetWires()
Laurent@814:                             transition = wires[0][0].StartConnected.GetParentBlock()
Laurent@814:                             transition_connectors = transition.GetConnectors()
Laurent@814:                             inputs.append(transition_connectors["output"])
Laurent@814:                         else:
Laurent@814:                             inputs.append(input_connectors["output"])
Laurent@814:                     id = self.GetNewId()
Laurent@814:                     divergence = SFC_Divergence(self, value["type"], len(inputs), id)
Laurent@814:                     pos = inputs[0].GetPosition(False)
Laurent@814:                     divergence.SetPosition(pos.x, pos.y + SFC_WIRE_MIN_SIZE)
Laurent@814:                     divergence_connectors = divergence.GetConnectors()
Laurent@814:                     for i, input in enumerate(inputs):
Laurent@814:                         pos = input.GetPosition(False)
Laurent@814:                         wire = self.ConnectConnectors(divergence_connectors["inputs"][i], input)
Laurent@814:                         wire_size = GetWireSize(input)
Laurent@814:                         wire.SetPoints([wx.Point(pos.x, pos.y + wire_size), wx.Point(pos.x, pos.y)])
Laurent@814:                         input_block = input.GetParentBlock()
Laurent@814:                         input_block.RefreshOutputPosition()
Laurent@814:                     divergence.RefreshPosition()
Laurent@814:                     pos = divergence_connectors["outputs"][0].GetRelPosition()
Laurent@814:                     divergence.MoveConnector(divergence_connectors["outputs"][0], - pos.x)
Laurent@814:                     self.AddBlock(divergence)
Laurent@814:                     self.Controler.AddEditedElementDivergence(self.TagName, id, value["type"])
Laurent@814:                     self.RefreshDivergenceModel(divergence)
Laurent@814:                     if next:
Laurent@814:                         wire = self.ConnectConnectors(next, divergence_connectors["outputs"][0])
Laurent@814:                         pos = divergence_connectors["outputs"][0].GetPosition(False)
Laurent@814:                         next_pos = next.GetPosition(False)
Laurent@814:                         next_block = next.GetParentBlock()
Laurent@814:                         divergence.RefreshOutputPosition((0, pos.y + SFC_WIRE_MIN_SIZE - next_pos.y))
Laurent@814:                         divergence.RefreshConnectedPosition(divergence_connectors["outputs"][0])
Laurent@814:                         wire.SetPoints([wx.Point(pos.x, pos.y + SFC_WIRE_MIN_SIZE), wx.Point(pos.x, pos.y)])
Laurent@814:                         next_block.RefreshModel()
Laurent@814:                     else:
Laurent@814:                         if value["type"] == SELECTION_CONVERGENCE:
Laurent@814:                             previous = divergence_connectors["outputs"][0]
Laurent@814:                         else:
Laurent@814:                             transition = self.CreateTransition(divergence_connectors["outputs"][0])
Laurent@814:                             transition_connectors = transition.GetConnectors()
Laurent@814:                             previous = transition_connectors["output"]
Laurent@814:                         self.CreateStep("Step", previous)
Laurent@814:                 self.RefreshBuffer()
Laurent@814:                 self.RefreshScrollBars()
Laurent@814:                 self.Refresh(False)
Laurent@814:             dialog.Destroy()
andrej@1730: 
Laurent@814:     def AddDivergenceBranch(self, divergence):
Laurent@814:         if isinstance(divergence, SFC_Divergence):
Laurent@814:             if self.GetDrawingMode() == FREEDRAWING_MODE:
Laurent@814:                 divergence.AddBranch()
Laurent@814:                 self.RefreshDivergenceModel(divergence)
Laurent@814:             else:
Laurent@814:                 type = divergence.GetType()
Laurent@814:                 if type in [SELECTION_DIVERGENCE, SIMULTANEOUS_DIVERGENCE]:
Laurent@814:                     divergence.AddBranch()
Laurent@814:                     divergence_connectors = divergence.GetConnectors()
Laurent@814:                     if type == SELECTION_DIVERGENCE:
Laurent@814:                         transition = self.CreateTransition(divergence_connectors["outputs"][-1])
Laurent@814:                         transition_connectors = transition.GetConnectors()
Laurent@814:                         previous = transition_connectors["output"]
Laurent@814:                     else:
Laurent@814:                         previous = divergence_connectors["outputs"][-1]
andrej@1847:                     _step = self.CreateStep("Step", previous)
Laurent@814:             self.RefreshBuffer()
Laurent@814:             self.RefreshScrollBars()
Laurent@814:             self.Refresh(False)
andrej@1730: 
Laurent@814:     def RemoveDivergenceBranch(self, divergence):
Laurent@814:         if isinstance(divergence, SFC_Divergence):
Laurent@814:             if self.GetDrawingMode() == FREEDRAWING_MODE:
Laurent@814:                 divergence.RemoveHandledBranch()
Laurent@814:                 self.RefreshDivergenceModel(divergence)
Laurent@814:                 self.RefreshBuffer()
Laurent@814:                 self.RefreshScrollBars()
Laurent@814:                 self.Refresh(False)
andrej@1730: 
Laurent@814:     def AddJump(self):
Laurent@814:         if isinstance(self.SelectedElement, SFC_Step) and not self.SelectedElement.Output:
Laurent@814:             choices = []
Laurent@814:             for block in self.Blocks:
Laurent@814:                 if isinstance(block, SFC_Step):
Laurent@814:                     choices.append(block.GetName())
andrej@1730:             dialog = wx.SingleChoiceDialog(self.ParentWindow,
andrej@1768:                                            _("Add a new jump"),
andrej@1768:                                            _("Please choose a target"),
andrej@1768:                                            choices,
andrej@1768:                                            wx.DEFAULT_DIALOG_STYLE | wx.OK | wx.CANCEL)
Laurent@814:             if dialog.ShowModal() == wx.ID_OK:
Laurent@814:                 value = dialog.GetStringSelection()
Laurent@814:                 self.SelectedElement.AddOutput()
Laurent@814:                 self.RefreshStepModel(self.SelectedElement)
Laurent@814:                 step_connectors = self.SelectedElement.GetConnectors()
Laurent@814:                 transition = self.CreateTransition(step_connectors["output"])
Laurent@814:                 transition_connectors = transition.GetConnectors()
Laurent@814:                 id = self.GetNewId()
Laurent@814:                 jump = SFC_Jump(self, value, id)
Laurent@814:                 pos = transition_connectors["output"].GetPosition(False)
Laurent@814:                 jump.SetPosition(pos.x, pos.y + SFC_WIRE_MIN_SIZE)
Laurent@814:                 self.AddBlock(jump)
Laurent@814:                 self.Controler.AddEditedElementJump(self.TagName, id)
Laurent@814:                 jump_connector = jump.GetConnector()
Laurent@814:                 wire = self.ConnectConnectors(jump_connector, transition_connectors["output"])
Laurent@814:                 transition.RefreshOutputPosition()
Laurent@814:                 wire.SetPoints([wx.Point(pos.x, pos.y + SFC_WIRE_MIN_SIZE), wx.Point(pos.x, pos.y)])
Laurent@814:                 self.RefreshJumpModel(jump)
Laurent@814:                 self.RefreshBuffer()
Laurent@814:                 self.RefreshScrollBars()
Laurent@814:                 self.Refresh(False)
Laurent@814:             dialog.Destroy()
Laurent@814: 
Laurent@814:     def EditStepContent(self, step):
Laurent@814:         if self.GetDrawingMode() == FREEDRAWING_MODE:
Laurent@814:             Viewer.EditStepContent(self, step)
Laurent@814:         else:
andrej@1745:             dialog = SFCStepNameDialog(self.ParentWindow, _("Edit step name"), _("Please enter step name"), step.GetName(), wx.OK | wx.CANCEL)
Laurent@814:             dialog.SetPouNames(self.Controler.GetProjectPouNames(self.Debug))
Laurent@1347:             dialog.SetVariables(self.Controler.GetEditedElementInterfaceVars(self.TagName, debug=self.Debug))
Laurent@814:             dialog.SetStepNames([block.GetName() for block in self.Blocks if isinstance(block, SFC_Step) and block.GetName() != step.GetName()])
Laurent@814:             if dialog.ShowModal() == wx.ID_OK:
Laurent@814:                 value = dialog.GetValue()
Laurent@814:                 step.SetName(value)
Laurent@814:                 min_size = step.GetMinSize()
Laurent@814:                 size = step.GetSize()
Laurent@814:                 step.UpdateSize(max(min_size[0], size[0]), max(min_size[1], size[1]))
Laurent@814:                 step.RefreshModel()
Laurent@814:                 self.RefreshBuffer()
Laurent@814:                 self.RefreshScrollBars()
Laurent@814:                 self.Refresh(False)
Laurent@814:             dialog.Destroy()
Laurent@814: 
andrej@1782:     # -------------------------------------------------------------------------------
andrej@1782:     #                          Delete element functions
andrej@1782:     # -------------------------------------------------------------------------------
Laurent@814: 
Laurent@814:     def DeleteStep(self, step):
Laurent@814:         if self.GetDrawingMode() == FREEDRAWING_MODE:
Laurent@814:             Viewer.DeleteStep(self, step)
Laurent@814:         else:
Laurent@814:             step_connectors = step.GetConnectors()
Laurent@814:             if not step.GetInitial() or not step_connectors["output"]:
Laurent@814:                 previous = step.GetPreviousConnector()
Laurent@814:                 if previous:
Laurent@814:                     previous_block = previous.GetParentBlock()
Laurent@814:                 else:
Laurent@814:                     previous_block = None
Laurent@814:                 next = step.GetNextConnector()
Laurent@814:                 if next:
Laurent@814:                     next_block = next.GetParentBlock()
Laurent@814:                 else:
Laurent@814:                     next_block = None
Laurent@814:                 if isinstance(next_block, SFC_Transition):
Laurent@814:                     self.RemoveTransition(next_block)
Laurent@814:                     next = step.GetNextConnector()
Laurent@814:                     if next:
Laurent@814:                         next_block = next.GetParentBlock()
Laurent@814:                     else:
Laurent@814:                         next_block = None
Laurent@814:                 elif isinstance(previous_block, SFC_Transition):
Laurent@814:                     self.RemoveTransition(previous_block)
Laurent@814:                     previous = step.GetPreviousConnector()
Laurent@814:                     if previous:
Laurent@814:                         previous_block = previous.GetParentBlock()
Laurent@814:                     else:
Laurent@814:                         previous_block = None
Laurent@814:                 wire = self.RemoveStep(step)
Laurent@814:                 self.SelectedElement = None
Laurent@814:                 if next_block:
Laurent@814:                     if isinstance(next_block, SFC_Divergence) and next_block.GetType() == SIMULTANEOUS_CONVERGENCE and isinstance(previous_block, SFC_Divergence) and previous_block.GetType() == SIMULTANEOUS_DIVERGENCE:
Laurent@814:                         wire.Clean()
Laurent@814:                         self.RemoveWire(wire)
Laurent@814:                         next_block.RemoveBranch(next)
Laurent@814:                         if next_block.GetBranchNumber() < 2:
Laurent@814:                             self.DeleteDivergence(next_block)
Laurent@814:                         else:
Laurent@814:                             next_block.RefreshModel()
Laurent@814:                         previous_block.RemoveBranch(previous)
Laurent@814:                         if previous_block.GetBranchNumber() < 2:
Laurent@814:                             self.DeleteDivergence(previous_block)
Laurent@814:                         else:
Laurent@814:                             previous_block.RefreshModel()
Laurent@814:                     else:
Laurent@814:                         pos = previous.GetPosition(False)
Laurent@814:                         next_pos = next.GetPosition(False)
Laurent@814:                         wire_size = GetWireSize(previous_block)
Laurent@814:                         previous_block.RefreshOutputPosition((0, pos.y + wire_size - next_pos.y))
Laurent@814:                         wire.SetPoints([wx.Point(pos.x, pos.y + wire_size), wx.Point(pos.x, pos.y)])
Laurent@814:                         if isinstance(next_block, SFC_Divergence):
Laurent@814:                             next_block.RefreshPosition()
Laurent@814:                         previous_block.RefreshOutputModel(True)
Laurent@814:                 else:
Laurent@814:                     if isinstance(previous_block, SFC_Step):
Laurent@814:                         previous_block.RemoveOutput()
Laurent@814:                         self.RefreshStepModel(previous_block)
Laurent@814:                     elif isinstance(previous_block, SFC_Divergence):
Laurent@814:                         if previous_block.GetType() in [SELECTION_CONVERGENCE, SIMULTANEOUS_CONVERGENCE]:
Laurent@814:                             self.DeleteDivergence(previous_block)
Laurent@814:                         else:
Laurent@814:                             previous_block.RemoveBranch(previous)
Laurent@814:                             if previous_block.GetBranchNumber() < 2:
Laurent@814:                                 self.DeleteDivergence(previous_block)
Laurent@814:                             else:
Laurent@814:                                 self.RefreshDivergenceModel(previous_block)
andrej@1730: 
Laurent@814:     def DeleteTransition(self, transition):
Laurent@814:         if self.GetDrawingMode() == FREEDRAWING_MODE:
Laurent@814:             Viewer.DeleteTransition(self, transition)
Laurent@814:         else:
Laurent@814:             previous = transition.GetPreviousConnector()
Laurent@814:             previous_block = previous.GetParentBlock()
Laurent@814:             next = transition.GetNextConnector()
Laurent@814:             next_block = next.GetParentBlock()
Laurent@814:             if isinstance(previous_block, SFC_Divergence) and previous_block.GetType() == SELECTION_DIVERGENCE and isinstance(next_block, SFC_Divergence) and next_block.GetType() == SELECTION_CONVERGENCE:
Laurent@814:                 wires = previous.GetWires()
Laurent@814:                 if len(wires) != 1:
Laurent@814:                     return
Laurent@814:                 wire = wires[0][0]
Laurent@814:                 wire.Clean()
Laurent@814:                 self.RemoveWire(wire)
Laurent@814:                 wires = next.GetWires()
Laurent@814:                 if len(wires) != 1:
Laurent@814:                     return
Laurent@814:                 wire = wires[0][0]
Laurent@814:                 wire.Clean()
Laurent@814:                 self.RemoveWire(wire)
Laurent@814:                 transition.Clean()
Laurent@814:                 self.RemoveBlock(transition)
Laurent@814:                 self.Controler.RemoveEditedElementInstance(self.TagName, transition.GetId())
Laurent@814:                 previous_block.RemoveBranch(previous)
Laurent@814:                 if previous_block.GetBranchNumber() < 2:
Laurent@814:                     self.DeleteDivergence(previous_block)
Laurent@814:                 else:
Laurent@814:                     self.RefreshDivergenceModel(previous_block)
Laurent@814:                 next_block.RemoveBranch(next)
Laurent@814:                 if next_block.GetBranchNumber() < 2:
Laurent@814:                     self.DeleteDivergence(next_block)
Laurent@814:                 else:
Laurent@814:                     self.RefreshDivergenceModel(next_block)
andrej@1730: 
Laurent@814:     def DeleteDivergence(self, divergence):
Laurent@814:         if self.GetDrawingMode() == FREEDRAWING_MODE:
Laurent@814:             Viewer.DeleteDivergence(self, divergence)
Laurent@814:         else:
Laurent@814:             connectors = divergence.GetConnectors()
Laurent@814:             type = divergence.GetType()
Laurent@814:             if type in [SELECTION_CONVERGENCE, SIMULTANEOUS_CONVERGENCE]:
Laurent@814:                 wires = connectors["outputs"][0].GetWires()
Laurent@814:                 if len(wires) > 1:
Laurent@814:                     return
Laurent@814:                 elif len(wires) == 1:
Laurent@814:                     next = wires[0][0].StartConnected
Laurent@814:                     next_block = next.GetParentBlock()
Laurent@814:                     wire = wires[0][0]
Laurent@814:                     wire.Clean()
Laurent@814:                     self.RemoveWire(wire)
Laurent@814:                 else:
Laurent@814:                     next = None
Laurent@814:                     next_block = None
Laurent@814:                 for index, connector in enumerate(connectors["inputs"]):
Laurent@814:                     if next and index == 0:
Laurent@814:                         wires = connector.GetWires()
Laurent@814:                         wire = wires[0][0]
Laurent@814:                         previous = wires[0][0].EndConnected
Laurent@814:                         wire.Clean()
Laurent@814:                         self.RemoveWire(wire)
Laurent@814:                     else:
Laurent@814:                         if type == SELECTION_CONVERGENCE:
Laurent@814:                             wires = connector.GetWires()
Laurent@814:                             previous_block = wires[0][0].EndConnected.GetParentBlock()
Laurent@814:                             self.RemoveTransition(previous_block)
Laurent@814:                         wires = connector.GetWires()
Laurent@814:                         wire = wires[0][0]
Laurent@814:                         previous_connector = wire.EndConnected
Laurent@814:                         previous_block = previous_connector.GetParentBlock()
Laurent@814:                         wire.Clean()
Laurent@814:                         self.RemoveWire(wire)
Laurent@814:                         if isinstance(previous_block, SFC_Step):
Laurent@814:                             previous_block.RemoveOutput()
Laurent@814:                             self.RefreshStepModel(previous_block)
Laurent@814:                         elif isinstance(previous_block, SFC_Divergence):
Laurent@814:                             if previous_block.GetType() in [SELECTION_DIVERGENCE, SIMULTANEOUS_DIVERGENCE]:
Laurent@814:                                 previous_block.RemoveBranch(previous_connector)
Laurent@814:                                 if previous_block.GetBranchNumber() < 2:
Laurent@814:                                     self.DeleteDivergence(previous_block)
Laurent@814:                                 else:
Laurent@814:                                     self.RefreshDivergenceModel(previous_block)
Laurent@814:                             else:
Laurent@814:                                 self.DeleteDivergence(previous_block)
Laurent@814:                 divergence.Clean()
Laurent@814:                 self.RemoveBlock(divergence)
Laurent@814:                 self.Controler.RemoveEditedElementInstance(self.TagName, divergence.GetId())
Laurent@814:                 if next:
Laurent@814:                     wire = self.ConnectConnectors(next, previous)
Laurent@814:                     previous_block = previous.GetParentBlock()
Laurent@814:                     previous_pos = previous.GetPosition(False)
Laurent@814:                     next_pos = next.GetPosition(False)
Laurent@814:                     wire_size = GetWireSize(previous_block)
Laurent@814:                     previous_block.RefreshOutputPosition((0, previous_pos.y + wire_size - next_pos.y))
andrej@1730:                     wire.SetPoints([wx.Point(previous_pos.x, previous_pos.y + wire_size),
andrej@1768:                                     wx.Point(previous_pos.x, previous_pos.y)])
Laurent@814:                     if isinstance(next_block, SFC_Divergence):
Laurent@814:                         next_block.RefreshPosition()
Laurent@814:                     previous_block.RefreshOutputModel(True)
Laurent@814:             elif divergence.GetBranchNumber() == 1:
Laurent@814:                 wires = connectors["inputs"][0].GetWires()
Laurent@814:                 if len(wires) != 1:
Laurent@814:                     return
Laurent@814:                 wire = wires[0][0]
Laurent@814:                 previous = wire.EndConnected
Laurent@814:                 previous_block = previous.GetParentBlock()
Laurent@814:                 wire.Clean()
Laurent@814:                 self.RemoveWire(wire)
Laurent@814:                 wires = connectors["outputs"][0].GetWires()
Laurent@814:                 if len(wires) != 1:
Laurent@814:                     return
Laurent@814:                 wire = wires[0][0]
Laurent@814:                 next = wire.StartConnected
Laurent@814:                 next_block = next.GetParentBlock()
Laurent@814:                 wire.Clean()
Laurent@814:                 self.RemoveWire(wire)
Laurent@814:                 divergence.Clean()
Laurent@814:                 self.RemoveBlock(divergence)
Laurent@814:                 self.Controler.RemoveEditedElementInstance(self.TagName, divergence.GetId())
Laurent@814:                 wire = self.ConnectConnectors(next, previous)
Laurent@814:                 previous_pos = previous.GetPosition(False)
Laurent@814:                 next_pos = next.GetPosition(False)
Laurent@814:                 wire_size = GetWireSize(previous_block)
Laurent@814:                 previous_block.RefreshOutputPosition((previous_pos.x - next_pos.x, previous_pos.y + wire_size - next_pos.y))
andrej@1730:                 wire.SetPoints([wx.Point(previous_pos.x, previous_pos.y + wire_size),
andrej@1768:                                 wx.Point(previous_pos.x, previous_pos.y)])
Laurent@814:                 if isinstance(next_block, SFC_Divergence):
Laurent@814:                     next_block.RefreshPosition()
Laurent@814:                 previous_block.RefreshOutputModel(True)
andrej@1730: 
Laurent@814:     def DeleteJump(self, jump):
Laurent@814:         if self.GetDrawingMode() == FREEDRAWING_MODE:
Laurent@814:             Viewer.DeleteJump(self, jump)
Laurent@814:         else:
Laurent@814:             previous = jump.GetPreviousConnector()
Laurent@814:             previous_block = previous.GetParentBlock()
Laurent@814:             if isinstance(previous_block, SFC_Transition):
Laurent@814:                 self.RemoveTransition(previous_block)
Laurent@814:                 previous = jump.GetPreviousConnector()
Laurent@814:                 if previous:
Laurent@814:                     previous_block = previous.GetParentBlock()
Laurent@814:                 else:
Laurent@814:                     previous_block = None
Laurent@814:             wires = previous.GetWires()
Laurent@814:             if len(wires) != 1:
Laurent@814:                 return
Laurent@814:             wire = wires[0][0]
Laurent@814:             wire.Clean()
Laurent@814:             self.RemoveWire(wire)
Laurent@814:             jump.Clean()
Laurent@814:             self.RemoveBlock(jump)
Laurent@814:             self.Controler.RemoveEditedElementInstance(self.TagName, jump.GetId())
Laurent@814:             if isinstance(previous_block, SFC_Step):
Laurent@814:                 previous_block.RemoveOutput()
Laurent@814:                 self.RefreshStepModel(previous_block)
Laurent@814:             elif isinstance(previous_block, SFC_Divergence):
Laurent@814:                 if previous_block.GetType() in [SELECTION_CONVERGENCE, SIMULTANEOUS_CONVERGENCE]:
Laurent@814:                     self.DeleteDivergence(previous_block)
Laurent@814:                 else:
Laurent@814:                     previous_block.RemoveBranch(previous)
Laurent@814:                     if previous_block.GetBranchNumber() < 2:
Laurent@814:                         self.DeleteDivergence(previous_block)
Laurent@814:                     else:
Laurent@814:                         previous_block.RefreshModel()
andrej@1730: 
Laurent@814:     def DeleteActionBlock(self, actionblock):
Laurent@814:         if self.GetDrawingMode() == FREEDRAWING_MODE:
Laurent@814:             Viewer.DeleteActionBlock(self, actionblock)
Laurent@814:         else:
Laurent@814:             connector = actionblock.GetConnector()
Laurent@814:             wires = connector.GetWires()
Laurent@814:             if len(wires) != 1:
Laurent@814:                 return
Laurent@814:             wire = wires[0][0]
Laurent@814:             step = wire.EndConnected.GetParentBlock()
Laurent@814:             wire.Clean()
Laurent@814:             self.RemoveWire(wire)
Laurent@814:             actionblock.Clean()
Laurent@814:             self.RemoveBlock(actionblock)
Laurent@814:             self.Controler.RemoveEditedElementInstance(self.TagName, actionblock.GetId())
Laurent@814:             step.RemoveAction()
Laurent@814:             self.RefreshStepModel(step)
Laurent@814:             step.RefreshOutputPosition()
Laurent@814:             step.RefreshOutputModel(True)
andrej@1730: 
Laurent@814:     def DeleteWire(self, wire):
Laurent@814:         if self.GetDrawingMode() == FREEDRAWING_MODE:
Laurent@814:             Viewer.DeleteWire(self, wire)
Laurent@814: 
andrej@1782:     # -------------------------------------------------------------------------------
andrej@1782:     #                          Model update functions
andrej@1782:     # -------------------------------------------------------------------------------
Laurent@814: 
Laurent@814:     def RefreshBlockModel(self, block):
Laurent@814:         blockid = block.GetId()
Laurent@814:         infos = {}
Laurent@814:         infos["type"] = block.GetType()
Laurent@814:         infos["name"] = block.GetName()
Laurent@814:         infos["x"], infos["y"] = block.GetPosition()
Laurent@814:         infos["width"], infos["height"] = block.GetSize()
Laurent@814:         infos["connectors"] = block.GetConnectors()
Laurent@814:         self.Controler.SetEditedElementBlockInfos(self.TagName, blockid, infos)