Viewer.py
author lbessard
Tue, 10 Jul 2007 09:52:53 +0200
changeset 28 fc23e1f415d8
parent 27 dae55dd9ee14
child 42 4a8400732001
permissions -rw-r--r--
Adding support for concurrent overriden standard function
Adding support for generate initial values
Adding support for expression into FBD variables
#!/usr/bin/env python
# -*- coding: utf-8 -*-

#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor
#based on the plcopen standard. 
#
#Copyright (C): Edouard TISSERANT and Laurent BESSARD
#
#See COPYING file for copyrights details.
#
#This library is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public
#License as published by the Free Software Foundation; either
#version 2.1 of the License, or (at your option) any later version.
#
#This library is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#Lesser General Public License for more details.
#
#You should have received a copy of the GNU General Public
#License along with this library; if not, write to the Free Software
#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

from wxPython.wx import *
import wx

from plcopen.structures import *
from graphics.GraphicCommons import *
from graphics.FBD_Objects import *
from graphics.LD_Objects import *
from graphics.SFC_Objects import *

from Dialogs import *

SCROLLBAR_UNIT = 10
WINDOW_BORDER = 10
SCROLL_ZONE = 10

#-------------------------------------------------------------------------------
#                       Graphic elements Viewer base class
#-------------------------------------------------------------------------------

# ID Constants for menu items
[wxID_FBDVIEWERCONTEXTUALMENUITEMS0, wxID_FBDVIEWERCONTEXTUALMENUITEMS1,
 wxID_FBDVIEWERCONTEXTUALMENUITEMS2, wxID_FBDVIEWERCONTEXTUALMENUITEMS3,
 wxID_FBDVIEWERCONTEXTUALMENUITEMS5, wxID_FBDVIEWERCONTEXTUALMENUITEMS6,
 wxID_FBDVIEWERCONTEXTUALMENUITEMS8, wxID_FBDVIEWERCONTEXTUALMENUITEMS9,
 wxID_FBDVIEWERCONTEXTUALMENUITEMS11,
] = [wx.NewId() for _init_coll_ContextualMenu_Items in range(9)]


"""
Class that implements a Viewer based on a wxScrolledWindow for drawing and 
manipulating graphic elements
"""

class Viewer(wx.ScrolledWindow):
    
    # Create Contextual Menu items
    def _init_coll_ContextualMenu_Items(self, parent):
        # Create menu items
        parent.Append(help='', id=wxID_FBDVIEWERCONTEXTUALMENUITEMS0,
              kind=wx.ITEM_RADIO, text=u'No Modifier')
        parent.Append(help='', id=wxID_FBDVIEWERCONTEXTUALMENUITEMS1,
              kind=wx.ITEM_RADIO, text=u'Negated')
        parent.Append(help='', id=wxID_FBDVIEWERCONTEXTUALMENUITEMS2,
              kind=wx.ITEM_RADIO, text=u'Rising Edge')
        parent.Append(help='', id=wxID_FBDVIEWERCONTEXTUALMENUITEMS3,
              kind=wx.ITEM_RADIO, text=u'Falling Edge')
        parent.AppendSeparator()
        parent.Append(help='', id=wxID_FBDVIEWERCONTEXTUALMENUITEMS5,
              kind=wx.ITEM_NORMAL, text=u'Add Wire Segment')
        parent.Append(help='', id=wxID_FBDVIEWERCONTEXTUALMENUITEMS6,
              kind=wx.ITEM_NORMAL, text=u'Delete Wire Segment')
        parent.AppendSeparator()
        parent.Append(help='', id=wxID_FBDVIEWERCONTEXTUALMENUITEMS8,
              kind=wx.ITEM_NORMAL, text=u'Add Divergence Branch')
        parent.Append(help='', id=wxID_FBDVIEWERCONTEXTUALMENUITEMS9,
              kind=wx.ITEM_NORMAL, text=u'Delete Divergence Branch')
        parent.AppendSeparator()
        parent.Append(help='', id=wxID_FBDVIEWERCONTEXTUALMENUITEMS11,
              kind=wx.ITEM_NORMAL, text=u'Delete')
        # Link menu event to corresponding called functions
        self.Bind(wx.EVT_MENU, self.OnNoModifierMenu,
              id=wxID_FBDVIEWERCONTEXTUALMENUITEMS0)
        self.Bind(wx.EVT_MENU, self.OnNegatedMenu,
              id=wxID_FBDVIEWERCONTEXTUALMENUITEMS1)
        self.Bind(wx.EVT_MENU, self.OnRisingEdgeMenu,
              id=wxID_FBDVIEWERCONTEXTUALMENUITEMS2)
        self.Bind(wx.EVT_MENU, self.OnFallingEdgeMenu,
              id=wxID_FBDVIEWERCONTEXTUALMENUITEMS3)
        self.Bind(wx.EVT_MENU, self.OnAddSegmentMenu,
              id=wxID_FBDVIEWERCONTEXTUALMENUITEMS5)
        self.Bind(wx.EVT_MENU, self.OnDeleteSegmentMenu,
              id=wxID_FBDVIEWERCONTEXTUALMENUITEMS6)
        self.Bind(wx.EVT_MENU, self.OnAddBranchMenu,
              id=wxID_FBDVIEWERCONTEXTUALMENUITEMS8)
        self.Bind(wx.EVT_MENU, self.OnDeleteBranchMenu,
              id=wxID_FBDVIEWERCONTEXTUALMENUITEMS9)
        self.Bind(wx.EVT_MENU, self.OnDeleteMenu,
              id=wxID_FBDVIEWERCONTEXTUALMENUITEMS11)
    
    # Create and initialize Contextual Menu
    def _init_menus(self):
        self.ContextualMenu = wx.Menu(title='')
        
        self._init_coll_ContextualMenu_Items(self.ContextualMenu)
    
    # Create a new Viewer
    def __init__(self, parent, window, controler):
        wx.ScrolledWindow.__init__(self, parent, style=wx.SUNKEN_BORDER | wx.HSCROLL | wx.VSCROLL)
        self._init_menus()
        # Adding a rubberband to Viewer
        self.rubberBand = RubberBand(drawingSurface=self)
        self.SetBackgroundColour(wxColour(255,255,255))
        self.ResetView()
        self.Scaling = None
        #self.Scaling = (8, 8)
        self.DrawGrid = True
        self.current_id = 0    
        
        # Initialize Viewer mode to Selection mode
        self.Mode = MODE_SELECTION
        self.SavedMode = False
        
        self.Parent = window
        self.Controler = controler
        
        # Link Viewer event to corresponding methods
        EVT_PAINT(self, self.OnPaint)
        EVT_LEFT_DOWN(self, self.OnViewerLeftDown)
        EVT_LEFT_UP(self, self.OnViewerLeftUp)
        EVT_LEFT_DCLICK(self, self.OnViewerLeftDClick)
        EVT_RIGHT_UP(self, self.OnViewerRightUp)
        EVT_MOTION(self, self.OnViewerMotion)
        EVT_CHAR(self, self.OnChar)
        EVT_SCROLLWIN(self, self.OnMoveWindow)
        EVT_SIZE(self, self.OnMoveWindow)
    
    # Returns a new id
    def GetNewId(self):
        self.current_id += 1
        return self.current_id
    
    # Destructor
    def __del__(self):
        self.ResetView()

    def GetLogicalDC(self):
        dc = wxClientDC(self)
        self.DoPrepareDC(dc)
        return dc

#-------------------------------------------------------------------------------
#                              Reset functions
#-------------------------------------------------------------------------------

    # Resets Viewer lists
    def ResetView(self):
        self.Blocks = []
        self.Wires = []
        self.Elements = []
        self.SelectedElement = None
    
    # Changes Viewer mode
    def SetMode(self, mode):
        if self.Mode != mode or mode == MODE_SELECTION:
            self.Mode = mode
            self.SavedMode = False
        else:
            self.SavedMode = True
        # Reset selection
        if self.Mode != MODE_SELECTION and self.SelectedElement:
            self.SelectedElement.SetSelected(False)
            self.SelectedElement = None
            self.Refresh()

    # Return current drawing mode
    def GetDrawingMode(self):
        return self.Parent.GetDrawingMode()

#-------------------------------------------------------------------------------
#                          Refresh functions
#-------------------------------------------------------------------------------

    # Refresh Viewer elements
    def RefreshView(self):
        self.current_id = 0
        # Start by reseting Viewer
        self.ResetView()
        instance = True
        # List of ids of already loaded blocks
        ids = []
        # Load Blocks until they are all loaded
        while instance:
            instance = self.Controler.GetCurrentElementEditingInstanceInfos(exclude=ids)
            if instance:
                self.loadInstance(instance, ids)
        self.RefreshScrollBar()
        self.Refresh()
    
    def RefreshScrollBar(self):
        xstart, ystart = self.GetViewStart()
        window_size = self.GetClientSize()
        maxx = maxy = 0
        for element in self.Elements:
            posx, posy = element.GetPosition()
            width, height = element.GetSize()
            maxx = max(maxx, posx + width)
            maxy = max(maxy, posy + height)
        maxx = max(maxx + WINDOW_BORDER, xstart * SCROLLBAR_UNIT + window_size[0])
        maxy = max(maxy + WINDOW_BORDER, ystart * SCROLLBAR_UNIT + window_size[1])
        if self.rubberBand.IsShown():
            extent = self.rubberBand.GetCurrentExtent()
            maxx = max(maxx, extent.x + extent.width)
            maxy = max(maxy, extent.y + extent.height)
        self.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, 
            maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, xstart, ystart)
    
    # Load instance from given informations
    def loadInstance(self, instance, ids):
        ids.append(instance["id"])
        self.current_id = max(self.current_id, instance["id"]) 
        if instance["type"] == "input":
            variable = FBD_Variable(self, INPUT, instance["name"], instance["value_type"], instance["id"])
            variable.SetPosition(instance["x"], instance["y"])
            variable.SetSize(instance["width"], instance["height"])
            self.Blocks.append(variable)
            self.Elements.append(variable)
            connectors = variable.GetConnectors()
            connectors["output"].SetPosition(wxPoint(*instance["connector"]["position"]))
            if instance["connector"]["negated"]:
                connectors["output"].SetNegated(True)
            if instance["connector"]["edge"]:
                connectors["output"].SetEdge(instance["connector"]["edge"])
        elif instance["type"] == "output":
            variable = FBD_Variable(self, OUTPUT, instance["name"], instance["value_type"], instance["id"])
            variable.SetPosition(instance["x"], instance["y"])
            variable.SetSize(instance["width"], instance["height"])
            self.Blocks.append(variable)
            self.Elements.append(variable)
            connectors = variable.GetConnectors()
            connectors["input"].SetPosition(wxPoint(*instance["connector"]["position"]))
            if instance["connector"]["negated"]:
                connectors["input"].SetNegated(True)
            if instance["connector"]["edge"]:
                connectors["input"].SetEdge(instance["connector"]["edge"])
            self.CreateWires(connectors["input"], instance["connector"]["links"], ids)
        elif instance["type"] == "inout":
            variable = FBD_Variable(self, INOUT, instance["name"], instance["value_type"], instance["id"])
            variable.SetPosition(instance["x"], instance["y"])
            variable.SetSize(instance["width"], instance["height"])
            self.Blocks.append(variable)
            self.Elements.append(variable)
            connectors = variable.GetConnectors()
            connectors["output"].SetPosition(wxPoint(*instance["connectors"]["output"]["position"]))
            connectors["input"].SetPosition(wxPoint(*instance["connectors"]["input"]["position"]))
            if instance["connectors"]["output"]["negated"]:
                connectors["output"].SetNegated(True)
            if instance["connectors"]["output"]["edge"]:
                connectors["output"].SetEdge(instance["connectors"]["output"]["edge"])
            if instance["connectors"]["input"]["negated"]:
                connectors["input"].SetNegated(True)
            if instance["connectors"]["input"]["edge"]:
                connectors["input"].SetEdge(instance["connectors"]["input"]["edge"])
            self.CreateWires(connectors["input"], instance["connectors"]["input"]["links"], ids)
        elif instance["type"] == "continuation":
            connection = FBD_Connector(self, CONTINUATION, instance["name"], instance["id"])
            connection.SetPosition(instance["x"], instance["y"])
            connection.SetSize(instance["width"], instance["height"])
            self.Blocks.append(connection)
            self.Elements.append(connection)
            connector = connection.GetConnector()
            connector.SetPosition(wxPoint(*instance["connector"]["position"]))
        elif instance["type"] == "connection":
            connection = FBD_Connector(self, CONNECTOR, instance["name"], instance["id"])
            connection.SetPosition(instance["x"], instance["y"])
            connection.SetSize(instance["width"], instance["height"])
            self.Blocks.append(connection)
            self.Elements.append(connection)
            connector = connection.GetConnector()
            connector.SetPosition(wxPoint(*instance["connector"]["position"]))
            self.CreateWires(connector, instance["connector"]["links"], ids)
        elif instance["type"] == "comment":
            comment = Comment(self, instance["content"], instance["id"])
            comment.SetPosition(instance["x"], instance["y"])
            comment.SetSize(instance["width"], instance["height"])
            self.Elements.append(comment)
        elif instance["type"] == "leftPowerRail":
            leftpowerrail = LD_PowerRail(self, LEFTRAIL, instance["id"], [True for i in range(len(instance["connectors"]))])
            leftpowerrail.SetPosition(instance["x"], instance["y"])
            self.Blocks.append(leftpowerrail)
            self.Elements.append(leftpowerrail)
            connectors = leftpowerrail.GetConnectors()
            for i, connector in enumerate(instance["connectors"]):
                connectors[i].SetPosition(wxPoint(*connector["position"]))
        elif instance["type"] == "rightPowerRail":
            rightpowerrail = LD_PowerRail(self, RIGHTRAIL, instance["id"], [True for i in range(len(instance["connectors"]))])
            rightpowerrail.SetPosition(instance["x"], instance["y"])
            self.Blocks.append(rightpowerrail)
            self.Elements.append(rightpowerrail)
            connectors = rightpowerrail.GetConnectors()
            for i, connector in enumerate(instance["connectors"]):
                connectors[i].SetPosition(wxPoint(*connector["position"]))
                self.CreateWires(connectors[i], connector["links"], ids)
        elif instance["type"] == "contact":
            if instance["negated"]:
                negated = instance["negated"]
            else:
                negated = False
            if instance["edge"]:
                edge = instance["edge"]
            else:
                edge = "none"
            if negated and edge == "none":
                contact_type = CONTACT_REVERSE
            elif not negated and edge == "rising":
                contact_type = CONTACT_RISING
            elif not negated and edge == "falling":
                contact_type = CONTACT_FALLING
            else:
                contact_type = CONTACT_NORMAL
            contact = LD_Contact(self, contact_type, instance["name"], instance["id"])
            contact.SetPosition(instance["x"], instance["y"])
            self.Blocks.append(contact)
            self.Elements.append(contact)
            connectors = contact.GetConnectors()
            connectors["input"].SetPosition(wxPoint(*instance["connectors"]["input"]["position"]))
            self.CreateWires(connectors["input"], instance["connectors"]["input"]["links"], ids)
            connectors["output"].SetPosition(wxPoint(*instance["connectors"]["output"]["position"]))
        elif instance["type"] == "coil":
            if instance["negated"]:
                negated = instance["negated"]
            else:
                negated = False
            if instance["storage"]:
                storage = instance["storage"]
            else:
                storage = "none"
            if negated and storage == "none":
                coil_type = COIL_REVERSE
            elif not negated and storage == "set":
                coil_type = COIL_SET
            elif not negated and storage == "reset":
                coil_type = COIL_RESET
            else:
                coil_type = COIL_NORMAL
            coil = LD_Coil(self, coil_type, instance["name"], instance["id"])
            coil.SetPosition(instance["x"], instance["y"])
            self.Blocks.append(coil)
            self.Elements.append(coil)
            connectors = coil.GetConnectors()
            connectors["input"].SetPosition(wxPoint(*instance["connectors"]["input"]["position"]))
            self.CreateWires(connectors["input"], instance["connectors"]["input"]["links"], ids)
            connectors["output"].SetPosition(wxPoint(*instance["connectors"]["output"]["position"]))
        elif instance["type"] == "step":
            if instance["initial"]:
                initial = instance["initial"]
            else:
                initial = False
            step = SFC_Step(self, instance["name"], initial, instance["id"])
            step.SetPosition(instance["x"], instance["y"])
            step.SetSize(instance["width"], instance["height"])
            self.Blocks.append(step)
            self.Elements.append(step)
            if "output" in instance["connectors"]:
                step.AddOutput()
            if "action" in instance["connectors"]:
                step.AddAction()
            connectors = step.GetConnectors()
            if connectors["input"]:
                connectors["input"].SetPosition(wxPoint(*instance["connectors"]["input"]["position"]))
                self.CreateWires(connectors["input"], instance["connectors"]["input"]["links"], ids)
            if connectors["output"]:
                connectors["output"].SetPosition(wxPoint(*instance["connectors"]["output"]["position"]))
            if connectors["action"]:
                connectors["action"].SetPosition(wxPoint(*instance["connectors"]["action"]["position"]))
        elif instance["type"] == "transition":
            transition = SFC_Transition(self, instance["condition_type"], instance["condition"], instance["id"])
            transition.SetPosition(instance["x"], instance["y"])
            self.Blocks.append(transition)
            self.Elements.append(transition)
            connectors = transition.GetConnectors()
            connectors["input"].SetPosition(wxPoint(*instance["connectors"]["input"]["position"]))
            self.CreateWires(connectors["input"], instance["connectors"]["input"]["links"], ids)
            connectors["output"].SetPosition(wxPoint(*instance["connectors"]["output"]["position"]))
        elif instance["type"] in ["selectionDivergence", "selectionConvergence", "simultaneousDivergence", "simultaneousConvergence"]:
            if instance["type"] == "selectionDivergence":
                divergence = SFC_Divergence(self, SELECTION_DIVERGENCE, 
                    len(instance["connectors"]["outputs"]), instance["id"])
            elif instance["type"] == "selectionConvergence":
                divergence = SFC_Divergence(self, SELECTION_CONVERGENCE, 
                    len(instance["connectors"]["inputs"]), instance["id"])
            elif instance["type"] == "simultaneousDivergence":
                divergence = SFC_Divergence(self, SIMULTANEOUS_DIVERGENCE, 
                    len(instance["connectors"]["outputs"]), instance["id"])
            else:
                divergence = SFC_Divergence(self, SIMULTANEOUS_CONVERGENCE, 
                    len(instance["connectors"]["inputs"]), instance["id"])
            divergence.SetPosition(instance["x"], instance["y"])
            divergence.SetSize(instance["width"], instance["height"])
            self.Blocks.append(divergence)
            self.Elements.append(divergence)
            connectors = divergence.GetConnectors()
            for i, input_connector in enumerate(instance["connectors"]["inputs"]):
                connector = connectors["inputs"][i]
                connector.SetPosition(wxPoint(*input_connector["position"]))
                self.CreateWires(connector, input_connector["links"], ids)
            for i, output_connector in enumerate(instance["connectors"]["outputs"]):
                connector = connectors["outputs"][i]
                connector.SetPosition(wxPoint(*output_connector["position"]))
        elif instance["type"] == "jump":
            jump = SFC_Jump(self, instance["target"], instance["id"])
            jump.SetPosition(instance["x"], instance["y"])
            self.Blocks.append(jump)
            self.Elements.append(jump)
            connector = jump.GetConnector()
            connector.SetPosition(wxPoint(*instance["connector"]["position"]))
            self.CreateWires(connector, instance["connector"]["links"], ids)
        elif instance["type"] == "actionBlock":
            actionBlock = SFC_ActionBlock(self, instance["actions"], instance["id"])
            actionBlock.SetPosition(instance["x"], instance["y"])
            actionBlock.SetSize(instance["width"], instance["height"])
            self.Blocks.append(actionBlock)
            self.Elements.append(actionBlock)
            connector = actionBlock.GetConnector()
            connector.SetPosition(wxPoint(*instance["connector"]["position"]))
            self.CreateWires(connector, instance["connector"]["links"], ids)
        else:
            if instance["name"] != None:
                block = FBD_Block(self, instance["type"], instance["name"], instance["id"], len(instance["connectors"]["inputs"]))
            else:
                block = FBD_Block(self, instance["type"], "", instance["id"], len(instance["connectors"]["inputs"]))
            block.SetPosition(instance["x"], instance["y"])
            block.SetSize(instance["width"], instance["height"])
            self.Blocks.append(block)
            self.Elements.append(block)
            connectors = block.GetConnectors()
            for i, input_connector in enumerate(instance["connectors"]["inputs"]):
                connector = connectors["inputs"][i]
                connector.SetPosition(wxPoint(*input_connector["position"]))
                if input_connector["negated"]:
                    connector.SetNegated(True)
                if input_connector["edge"]:
                    connector.SetEdge(input_connector["edge"])
                self.CreateWires(connector, input_connector["links"], ids)
            for i, output_connector in enumerate(instance["connectors"]["outputs"]):
                connector = connectors["outputs"][i]
                if output_connector["negated"]:
                    connector.SetNegated(True)
                if output_connector["edge"]:
                    connector.SetEdge(output_connector["edge"])
                connector.SetPosition(wxPoint(*output_connector["position"]))
    
    def CreateWires(self, start_connector, links, ids):
        for link in links:
            refLocalId = link["refLocalId"]
            if refLocalId != None:
                if refLocalId not in ids:
                    new_instance = self.Controler.GetCurrentElementEditingInstanceInfos(refLocalId)
                    if new_instance:
                        self.loadInstance(new_instance, ids)
                connected = self.FindElementById(refLocalId)
                if connected:
                    points = link["points"]
                    end_connector = connected.GetConnector(wxPoint(points[-1][0], points[-1][1]), link["formalParameter"])
                    if end_connector:
                        wire = Wire(self)
                        wire.SetPoints(points)
                        start_connector.Connect((wire, 0), False)
                        end_connector.Connect((wire, -1), False)
                        wire.ConnectStartPoint(None, start_connector)
                        wire.ConnectEndPoint(None, end_connector)
                        self.Wires.append(wire)
                        self.Elements.append(wire)

#-------------------------------------------------------------------------------
#                          Search Element functions
#-------------------------------------------------------------------------------

    def FindBlock(self, pos):
        for block in self.Blocks:
            if block.HitTest(pos) or block.TestHandle(pos) != (0, 0):
                return block
        return None
    
    def FindWire(self, pos):
        for wire in self.Wires:
            if wire.HitTest(pos) or wire.TestHandle(pos) != (0, 0):
                return wire
        return None
    
    def FindElement(self, pos, exclude_group = False):
        if self.SelectedElement and not (exclude_group and isinstance(self.SelectedElement, Graphic_Group)):
            if self.SelectedElement.HitTest(pos) or self.SelectedElement.TestHandle(pos) != (0, 0):
                return self.SelectedElement
        for element in self.Elements:
            if element.HitTest(pos) or element.TestHandle(pos) != (0, 0):
                return element
        return None
    
    def FindBlockConnector(self, pos, exclude = True):
        for block in self.Blocks:
            result = block.TestConnector(pos, exclude)
            if result:
                return result
        return None
    
    def FindElementById(self, id):
        for element in self.Elements:
            if element.GetId() == id:
                return element
        return None
    
    def SearchElements(self, bbox):
        elements = []
        for element in self.Elements:
            element_bbox = element.GetBoundingBox()
            if element_bbox.x >= bbox.x and element_bbox.y >= bbox.y and element_bbox.x + element_bbox.width <= bbox.x + bbox.width and element_bbox.y + element_bbox.height <= bbox.y + bbox.height:
                elements.append(element)
        return elements

#-------------------------------------------------------------------------------
#                           Popup menu functions
#-------------------------------------------------------------------------------

    def PopupBlockMenu(self, connector = None):
        type = self.Controler.GetCurrentElementEditingType()
        self.ContextualMenu.FindItemByPosition(0).Enable(connector != None)
        self.ContextualMenu.FindItemByPosition(1).Enable(connector != None)
        self.ContextualMenu.FindItemByPosition(2).Enable(connector != None and type != "function")
        self.ContextualMenu.FindItemByPosition(3).Enable(connector != None and type != "function")
        self.ContextualMenu.FindItemByPosition(5).Enable(False)
        self.ContextualMenu.FindItemByPosition(6).Enable(False)
        self.ContextualMenu.FindItemByPosition(8).Enable(False)
        self.ContextualMenu.FindItemByPosition(9).Enable(False)
        if connector:
            if connector.IsNegated():
                self.ContextualMenu.FindItemByPosition(1).Check(True)
            elif connector.GetEdge() == "rising":
                self.ContextualMenu.FindItemByPosition(2).Check(True)
            elif connector.GetEdge() == "falling":
                self.ContextualMenu.FindItemByPosition(3).Check(True)
            else:
                self.ContextualMenu.FindItemByPosition(0).Check(True)
        self.PopupMenu(self.ContextualMenu)
    
    def PopupVariableMenu(self, connector = None):
        self.ContextualMenu.FindItemByPosition(0).Enable(connector != None)
        self.ContextualMenu.FindItemByPosition(1).Enable(connector != None)
        self.ContextualMenu.FindItemByPosition(2).Enable(False)
        self.ContextualMenu.FindItemByPosition(3).Enable(False)
        self.ContextualMenu.FindItemByPosition(5).Enable(False)
        self.ContextualMenu.FindItemByPosition(6).Enable(False)
        self.ContextualMenu.FindItemByPosition(8).Enable(False)
        self.ContextualMenu.FindItemByPosition(9).Enable(False)
        if connector:
            if connector.IsNegated():
                self.ContextualMenu.FindItemByPosition(1).Check(True)
            else:
                self.ContextualMenu.FindItemByPosition(0).Check(True)
        self.PopupMenu(self.ContextualMenu)

    def PopupWireMenu(self):
        self.ContextualMenu.FindItemByPosition(0).Enable(False)
        self.ContextualMenu.FindItemByPosition(1).Enable(False)
        self.ContextualMenu.FindItemByPosition(2).Enable(False)
        self.ContextualMenu.FindItemByPosition(3).Enable(False)
        self.ContextualMenu.FindItemByPosition(5).Enable(True)
        self.ContextualMenu.FindItemByPosition(6).Enable(True)
        self.ContextualMenu.FindItemByPosition(8).Enable(False)
        self.ContextualMenu.FindItemByPosition(9).Enable(False)
        self.PopupMenu(self.ContextualMenu)
    
    def PopupDivergenceMenu(self, connector):
        self.ContextualMenu.FindItemByPosition(0).Enable(False)
        self.ContextualMenu.FindItemByPosition(1).Enable(False)
        self.ContextualMenu.FindItemByPosition(2).Enable(False)
        self.ContextualMenu.FindItemByPosition(3).Enable(False)
        self.ContextualMenu.FindItemByPosition(5).Enable(False)
        self.ContextualMenu.FindItemByPosition(6).Enable(False)
        self.ContextualMenu.FindItemByPosition(8).Enable(True)
        self.ContextualMenu.FindItemByPosition(9).Enable(connector)
        self.PopupMenu(self.ContextualMenu)
    
    def PopupDefaultMenu(self):
        self.ContextualMenu.FindItemByPosition(0).Enable(False)
        self.ContextualMenu.FindItemByPosition(1).Enable(False)
        self.ContextualMenu.FindItemByPosition(2).Enable(False)
        self.ContextualMenu.FindItemByPosition(3).Enable(False)
        self.ContextualMenu.FindItemByPosition(5).Enable(False)
        self.ContextualMenu.FindItemByPosition(6).Enable(False)
        self.ContextualMenu.FindItemByPosition(8).Enable(False)
        self.ContextualMenu.FindItemByPosition(9).Enable(False)
        self.PopupMenu(self.ContextualMenu)

    def EditCommentContent(self, comment):
        dialog = wxTextEntryDialog(self.Parent, "Edit comment", "Please enter comment text", comment.GetContent(), wxOK|wxCANCEL|wxTE_MULTILINE)
        if dialog.ShowModal() == wxID_OK:
            value = dialog.GetValue()
            comment.SetContent(value)
            infos = {"content" : value}
            infos["width"], infos["height"] = comment.GetSize()
            self.Controler.SetCurrentElementEditingCommentInfos(comment.GetId(), infos)
            self.Refresh()
        dialog.Destroy()

#-------------------------------------------------------------------------------
#                            Menu items functions
#-------------------------------------------------------------------------------

    def OnNoModifierMenu(self, event):
        if self.SelectedElement and self.SelectedElement in self.Blocks:
            self.SelectedElement.SetConnectorNegated(False)
        event.Skip()
    
    def OnNegatedMenu(self, event):
        if self.SelectedElement and self.SelectedElement in self.Blocks:
            self.SelectedElement.SetConnectorNegated(True)
        event.Skip()

    def OnRisingEdgeMenu(self, event):
        if self.SelectedElement and self.SelectedElement in self.Blocks:
            self.SelectedElement.SetConnectorEdge("rising")
        event.Skip()

    def OnFallingEdgeMenu(self, event):
        if self.SelectedElement and self.SelectedElement in self.Blocks:
            self.SelectedElement.SetConnectorEdge("falling")
        event.Skip()

    def OnAddSegmentMenu(self, event):
        if self.SelectedElement and self.SelectedElement in self.Wires:
            self.SelectedElement.AddSegment()
        event.Skip()

    def OnDeleteSegmentMenu(self, event):
        if self.SelectedElement and self.SelectedElement in self.Wires:
            self.SelectedElement.DeleteSegment()
        event.Skip()

    def OnAddBranchMenu(self, event):
        if self.SelectedElement and self.SelectedElement in self.Blocks:
            self.AddDivergenceBranch(self.SelectedElement)
        event.Skip()

    def OnDeleteBranchMenu(self, event):
        if self.SelectedElement and self.SelectedElement in self.Blocks:
            self.RemoveDivergenceBranch(self.SelectedElement)
        event.Skip()

    def OnDeleteMenu(self, event):
        if self.SelectedElement:
            self.SelectedElement.Delete()
            self.SelectedElement = None
        event.Skip()

#-------------------------------------------------------------------------------
#                          Mouse event functions
#-------------------------------------------------------------------------------

    def OnViewerLeftDown(self, event):
        if self.Mode == MODE_SELECTION:
            dc = self.GetLogicalDC()
            pos = event.GetLogicalPosition(dc)
            if event.ControlDown() and self.SelectedElement:
                element = self.FindElement(pos, True)
                if element:
                    if isinstance(self.SelectedElement, Graphic_Group):
                        self.SelectedElement.SetSelected(False)
                        self.SelectedElement.SelectElement(element)
                    elif self.SelectedElement:
                        group = Graphic_Group(self)
                        group.SelectElement(self.SelectedElement)
                        group.SelectElement(element)
                        self.SelectedElement = group
                    elements = self.SelectedElement.GetElements()
                    if len(elements) == 0:
                        self.SelectedElement = element
                    elif len(elements) == 1:
                        self.SelectedElement = elements[0]
                    self.SelectedElement.SetSelected(True)
            else:
                element = self.FindElement(pos)
                if self.SelectedElement and self.SelectedElement != element:
                    self.SelectedElement.SetSelected(False)
                    self.SelectedElement = None
                    self.Refresh()
                if element:
                    self.SelectedElement = element
                    self.SelectedElement.OnLeftDown(event, dc, self.Scaling)
                    self.Refresh()
                else:
                    self.rubberBand.Reset()
                    self.rubberBand.OnLeftDown(event, dc, self.Scaling)
        elif self.Mode in [MODE_BLOCK, MODE_VARIABLE, MODE_CONNECTION, MODE_COMMENT, 
                           MODE_CONTACT, MODE_COIL, MODE_POWERRAIL, MODE_INITIALSTEP, 
                           MODE_STEP, MODE_TRANSITION, MODE_DIVERGENCE, MODE_JUMP, MODE_ACTION]:
            self.rubberBand.Reset()
            self.rubberBand.OnLeftDown(event, self.GetLogicalDC(), self.Scaling)
        elif self.Mode == MODE_WIRE:
            pos = GetScaledEventPosition(event, self.GetLogicalDC(), self.Scaling)
            connector = self.FindBlockConnector(pos)
            if connector:
                if (connector.GetDirection() == EAST):
                    wire = Wire(self, [wxPoint(pos.x, pos.y), EAST], [wxPoint(pos.x, pos.y), WEST])
                else:
                    wire = Wire(self, [wxPoint(pos.x, pos.y), WEST], [wxPoint(pos.x, pos.y), EAST])
                wire.oldPos = pos
                wire.Handle = (HANDLE_POINT, 0)
                wire.ProcessDragging(0, 0)
                wire.Handle = (HANDLE_POINT, 1)
                self.Wires.append(wire)
                self.Elements.append(wire)
                if self.SelectedElement:
                    self.SelectedElement.SetSelected(False)
                self.SelectedElement = wire
            elif self.SelectedElement:
                self.SelectedElement.SetSelected(False)
                self.SelectedElement = None
            self.Refresh()
        event.Skip()

    def OnViewerLeftUp(self, event):
        if self.rubberBand.IsShown():
            if self.Mode == MODE_SELECTION:
                elements = self.SearchElements(self.rubberBand.GetCurrentExtent())
                self.rubberBand.OnLeftUp(event, self.GetLogicalDC(), self.Scaling)
                if len(elements) > 0:
                    self.SelectedElement = Graphic_Group(self)
                    self.SelectedElement.SetElements(elements)
                    self.SelectedElement.SetSelected(True)
                    self.Refresh()
            else:
                bbox = self.rubberBand.GetCurrentExtent()
                self.rubberBand.OnLeftUp(event, self.GetLogicalDC(), self.Scaling)                
                if self.Mode == MODE_BLOCK:
                    wxCallAfter(self.AddNewBlock, bbox)
                elif self.Mode == MODE_VARIABLE:
                    wxCallAfter(self.AddNewVariable, bbox)
                elif self.Mode == MODE_CONNECTION:
                    wxCallAfter(self.AddNewConnection, bbox)
                elif self.Mode == MODE_COMMENT:
                    wxCallAfter(self.AddNewComment, bbox)
                elif self.Mode == MODE_CONTACT:
                    wxCallAfter(self.AddNewContact, bbox)
                elif self.Mode == MODE_COIL:
                    wxCallAfter(self.AddNewContact, bbox)
                elif self.Mode == MODE_POWERRAIL:
                    wxCallAfter(self.AddNewPowerRail, bbox)
                elif self.Mode == MODE_INITIALSTEP:
                    wxCallAfter(self.AddNewInitialStep, bbox)
                elif self.Mode == MODE_STEP:
                    wxCallAfter(self.AddNewStep, bbox)
                elif self.Mode == MODE_TRANSITION:
                    wxCallAfter(self.AddNewTransition, bbox)
                elif self.Mode == MODE_DIVERGENCE:
                    wxCallAfter(self.AddNewDivergence, bbox)
                elif self.Mode == MODE_JUMP:
                    wxCallAfter(self.AddNewJump, bbox)
                elif self.Mode == MODE_ACTION:
                    wxCallAfter(self.AddNewActionBlock, bbox)
        elif self.Mode == MODE_SELECTION and self.SelectedElement:
            self.SelectedElement.OnLeftUp(event, self.GetLogicalDC(), self.Scaling)
            wxCallAfter(self.SetCursor, wxNullCursor)
            self.ReleaseMouse()
            self.Refresh()
        elif self.Mode == MODE_WIRE and self.SelectedElement:
            dc = self.GetLogicalDC()
            pos = GetScaledEventPosition(event, dc, self.Scaling)
            connector = self.FindBlockConnector(pos, False)
            if connector and connector != self.SelectedElement.StartConnected:
                self.SelectedElement.ResetPoints()
                self.SelectedElement.OnMotion(event, dc, self.Scaling)
                self.SelectedElement.GeneratePoints()
                self.SelectedElement.RefreshModel()
                self.SelectedElement.SetSelected(True)
            else:
                self.SelectedElement.Delete()
                self.SelectedElement = None
            self.Refresh()
        if not self.SavedMode:
            wxCallAfter(self.Parent.ResetCurrentMode)
        event.Skip()
    
    def OnViewerRightUp(self, event):
        pos = event.GetPosition()
        element = self.FindElement(pos)
        if element:
            if self.SelectedElement and self.SelectedElement != element:
                self.SelectedElement.SetSelected(False)
            self.SelectedElement = element
            self.SelectedElement.SetSelected(True)
            self.SelectedElement.OnRightUp(event, self.GetLogicalDC(), self.Scaling)
            wxCallAfter(self.SetCursor, wxNullCursor)
            self.ReleaseMouse()
            self.Refresh()
        event.Skip()
    
    def OnViewerLeftDClick(self, event):
        if self.Mode == MODE_SELECTION and self.SelectedElement:
            self.SelectedElement.OnLeftDClick(event, self.GetLogicalDC(), self.Scaling)
            self.Refresh()
        event.Skip()
    
    def OnViewerMotion(self, event):
        if self.rubberBand.IsShown():
            self.rubberBand.OnMotion(event, self.GetLogicalDC(), self.Scaling)
        elif self.Mode == MODE_SELECTION and self.SelectedElement:
            self.SelectedElement.OnMotion(event, self.GetLogicalDC(), self.Scaling)
            self.Refresh()
        elif self.Mode == MODE_WIRE and self.SelectedElement:
            dc = self.GetLogicalDC()
            pos = GetScaledEventPosition(event, dc, self.Scaling)
            connector = self.FindBlockConnector(pos, False)
            if not connector or self.SelectedElement.EndConnected == None:
                self.SelectedElement.ResetPoints()
                self.SelectedElement.OnMotion(event, dc, self.Scaling)
                self.SelectedElement.GeneratePoints()
                self.Refresh()
        if (event.Dragging() and self.SelectedElement) or self.rubberBand.IsShown():
            position = event.GetPosition()
            move_window = wxPoint()
            window_size = self.GetClientSize()
            xstart, ystart = self.GetViewStart()
            if position.x < SCROLL_ZONE and xstart > 0:
                move_window.x = -1
            elif position.x > window_size[0] - SCROLL_ZONE:
                move_window.x = 1
            if position.y < SCROLL_ZONE and ystart > 0:
                move_window.y = -1
            elif position.y > window_size[1] - SCROLL_ZONE:
                move_window.y = 1
            if move_window.x != 0 or move_window.y != 0:
                self.Scroll(xstart + move_window.x, ystart + move_window.y)
            self.RefreshScrollBar()
        event.Skip()

#-------------------------------------------------------------------------------
#                          Keyboard event functions
#-------------------------------------------------------------------------------

    def OnChar(self, event):
        keycode = event.GetKeyCode()
        if self.Scaling:
            scaling = self.Scaling
        else:
            scaling = (8, 8)
        if keycode == WXK_DELETE and self.SelectedElement:
            self.SelectedElement.Clean()
            self.SelectedElement.Delete()
            self.SelectedElement = None
        elif keycode == WXK_LEFT and self.SelectedElement:
            self.SelectedElement.Move(-scaling[0], 0)
        elif keycode == WXK_RIGHT and self.SelectedElement:
            self.SelectedElement.Move(scaling[0], 0)
        elif keycode == WXK_UP and self.SelectedElement:
            self.SelectedElement.Move(0, -scaling[1])
        elif keycode == WXK_DOWN and self.SelectedElement:
            self.SelectedElement.Move(0, scaling[1])
        self.Refresh()
        event.Skip()

#-------------------------------------------------------------------------------
#                          Model adding functions
#-------------------------------------------------------------------------------

    def AddNewBlock(self, bbox):
        dialog = BlockPropertiesDialog(self.Parent)
        dialog.SetBlockList(self.Controler.GetBlockTypes())
        dialog.SetMinBlockSize((bbox.width, bbox.height))
        if dialog.ShowModal() == wxID_OK:
            id = self.GetNewId()
            values = dialog.GetValues()
            if "name" in values:
                block = FBD_Block(self, values["type"], values["name"], id, values["extension"], values["inputs"])
            else:
                block = FBD_Block(self, values["type"], "", id, values["extension"], values["inputs"])
            block.SetPosition(bbox.x, bbox.y)
            block.SetSize(values["width"], values["height"])
            self.Blocks.append(block)
            self.Elements.append(block)
            self.Controler.AddCurrentElementEditingBlock(id)
            self.RefreshBlockModel(block)
            self.Refresh()
        dialog.Destroy()
    
    def AddNewVariable(self, bbox):
        dialog = VariablePropertiesDialog(self.Parent)
        dialog.SetMinVariableSize((bbox.width, bbox.height))
        varlist = []
        vars = self.Controler.GetCurrentElementEditingInterfaceVars()
        if vars:
            for var in vars:
                varlist.append((var["Name"], var["Class"], var["Type"]))
        returntype = self.Controler.GetCurrentElementEditingInterfaceReturnType()
        if returntype:
            varlist.append((self.Controler.GetCurrentElementEditingName(), "Output", returntype))
        dialog.SetVariables(varlist)
        if dialog.ShowModal() == wxID_OK:
            id = self.GetNewId()
            values = dialog.GetValues()
            variable = FBD_Variable(self, values["type"], values["name"], values["value_type"], id)
            variable.SetPosition(bbox.x, bbox.y)
            variable.SetSize(values["width"], values["height"])
            self.Blocks.append(variable)
            self.Elements.append(variable)
            self.Controler.AddCurrentElementEditingVariable(id, values["type"])
            self.RefreshVariableModel(variable)
            self.Refresh()
        dialog.Destroy()

    def AddNewConnection(self, bbox):
        dialog = ConnectionPropertiesDialog(self.Parent)
        dialog.SetMinConnectionSize((bbox.width, bbox.height))
        if dialog.ShowModal() == wxID_OK:
            id = self.GetNewId()
            values = dialog.GetValues()
            connection = FBD_Connector(self, values["type"], values["name"], id)
            connection.SetPosition(bbox.x, bbox.y)
            connection.SetSize(values["width"], values["height"])
            self.Blocks.append(connection)
            self.Elements.append(connection)
            self.Controler.AddCurrentElementEditingConnection(id, values["type"])
            self.RefreshConnectionModel(connection)
            self.Refresh()
        dialog.Destroy()

    def AddNewComment(self, bbox):
        dialog = wxTextEntryDialog(self.Parent, "Add a new comment", "Please enter comment text", "", wxOK|wxCANCEL|wxTE_MULTILINE)
        if dialog.ShowModal() == wxID_OK:
            value = dialog.GetValue()
            id = self.GetNewId()
            comment = Comment(self, value, id)
            comment.SetPosition(bbox.x, bbox.y)
            min_width, min_height = comment.GetMinSize()
            comment.SetSize(max(min_width,bbox.width),max(min_height,bbox.height))
            self.Elements.append(comment)
            self.Controler.AddCurrentElementEditingComment(id)
            self.RefreshCommentModel(comment)
            self.Refresh()
        dialog.Destroy()

    def AddNewContact(self, bbox):
        dialog = LDElementDialog(self.Parent, "contact")
        varlist = []
        vars = self.Controler.GetCurrentElementEditingInterfaceVars()
        if vars:
            for var in vars:
                if var["Class"] != "Output" and var["Type"] == "BOOL":
                    varlist.append(var["Name"])
        dialog.SetVariables(varlist)
        dialog.SetValues({"name":"","type":CONTACT_NORMAL})
        dialog.SetElementSize((bbox.width, bbox.height))
        if dialog.ShowModal() == wxID_OK:
            id = self.GetNewId()
            values = dialog.GetValues()
            contact = LD_Contact(self, values["type"], values["name"], id)
            contact.SetPosition(bbox.x, bbox.y)
            contact.SetSize(values["width"], values["height"])
            self.Blocks.append(contact)
            self.Elements.append(contact)
            self.Controler.AddCurrentElementEditingContact(id)
            self.RefreshContactModel(contact)
            self.Refresh()
        dialog.Destroy()

    def AddNewCoil(self, bbox):
        dialog = LDElementDialog(self.Parent, "coil")
        varlist = []
        vars = self.Controler.GetCurrentElementEditingInterfaceVars()
        if vars:
            for var in vars:
                if var["Class"] != "Input" and var["Type"] == "BOOL":
                    varlist.append(var["Name"])
        returntype = self.Controler.GetCurrentElementEditingInterfaceReturnType()
        if returntype == "BOOL":
            varlist.append(self.Controler.GetCurrentElementEditingName())
        dialog.SetVariables(varlist)
        dialog.SetValues({"name":"","type":COIL_NORMAL})
        dialog.SetElementSize((bbox.width, bbox.height))
        if dialog.ShowModal() == wxID_OK:
            id = self.GetNewId()
            values = dialog.GetValues()
            coil = LD_Coil(self, values["type"], values["name"], id)
            coil.SetPosition(bbox.x, bbox.y)
            coil.SetSize(values["width"], values["height"])
            self.Blocks.append(coil)
            self.Elements.append(coil)
            self.Controler.AddCurrentElementEditingCoil(id)
            self.RefreshCoilModel(contact)
            self.Refresh()
        dialog.Destroy()

    def AddNewPowerRail(self, bbox):
        dialog = LDPowerRailDialog(self.Parent)
        dialog.SetMinSize((bbox.width, bbox.height))
        if dialog.ShowModal() == wxID_OK:
            id = self.GetNewId()
            values = dialog.GetValues()
            powerrail = LD_PowerRail(self, values["type"], id, [True for i in xrange(values["number"])])
            powerrail.SetPosition(bbox.x, bbox.y)
            powerrail.SetSize(values["width"], values["height"])
            self.Blocks.append(powerrail)
            self.Elements.append(powerrail)
            self.Controler.AddCurrentElementEditingPowerRail(id, values["type"])
            self.RefreshPowerRailModel(powerrail)
            self.Refresh()
        dialog.Destroy()

    def AddNewTransition(self, bbox):
        dialog = TransitionContentDialog(self.Parent)
        dialog.SetTransitions(self.Controler.GetCurrentElementEditingTransitions())
        if dialog.ShowModal() == wxID_OK:
            id = self.GetNewId()
            values = dialog.GetValues()
            transition = SFC_Transition(self, values["type"], values["value"], id)
            transition.SetPosition(bbox.x, bbox.y)
            min_width, min_height = transition.GetMinSize()
            transition.SetSize(max(bbox.width, min_width), max(bbox.height, min_height))
            self.Blocks.append(transition)
            self.Elements.append(transition)
            self.Controler.AddCurrentElementEditingTransition(id)
            self.RefreshTransitionModel(transition)
            self.Refresh()
        dialog.Destroy()

    def AddNewDivergence(self, bbox):
        dialog = DivergenceCreateDialog(self.Parent)
        dialog.SetMinSize((bbox.width, bbox.height))
        if dialog.ShowModal() == wxID_OK:
            id = self.GetNewId()
            values = dialog.GetValues()
            divergence = SFC_Divergence(self, values["type"], values["number"], id)
            divergence.SetPosition(bbox.x, bbox.y)
            min_width, min_height = divergence.GetMinSize()
            divergence.SetSize(max(bbox.width, min_width), max(bbox.height, min_height))
            self.Blocks.append(divergence)
            self.Elements.append(divergence)
            self.Controler.AddCurrentElementEditingDivergence(id, values["type"])
            self.RefreshDivergenceModel(divergence)
            self.Refresh()
        dialog.Destroy()


#-------------------------------------------------------------------------------
#                          Edit element content functions
#-------------------------------------------------------------------------------

    def EditBlockContent(self, block):
        dialog = BlockPropertiesDialog(self.Parent)
        dialog.SetBlockList(self.Controler.GetBlockTypes())
        dialog.SetMinBlockSize(block.GetSize())
        values = {"name" : block.GetName(), "type" : block.GetType(), "inputs" : block.GetInputTypes()}
        values["extension"] = block.GetExtension()
        dialog.SetValues(values)
        if dialog.ShowModal() == wxID_OK:
            values = dialog.GetValues()
            if "name" in values:
                block.SetName(values["name"])
            block.SetSize(values["width"], values["height"])
            block.SetType(values["type"], values["extension"])
            self.RefreshBlockModel(block)
            self.Refresh()
        dialog.Destroy()

    def EditVariableContent(self, variable):
        dialog = VariablePropertiesDialog(self.Parent)
        dialog.SetMinVariableSize(variable.GetSize())
        varlist = []
        vars = self.Controler.GetCurrentElementEditingInterfaceVars()
        if vars:
            for var in vars:
                varlist.append((var["Name"], var["Class"], var["Type"]))
        returntype = self.Controler.GetCurrentElementEditingInterfaceReturnType()
        if returntype:
            varlist.append((self.Controler.GetCurrentElementEditingName(), "Output", returntype))
        dialog.SetVariables(varlist)
        values = {"name" : variable.GetName(), "type" : variable.GetType()}
        dialog.SetValues(values)
        if dialog.ShowModal() == wxID_OK:
            old_type = variable.GetType()
            values = dialog.GetValues()
            variable.SetName(values["name"])
            variable.SetType(values["type"], values["value_type"])
            variable.SetSize(values["width"], values["height"])
            if old_type != values["type"]:
                id = variable.GetId()
                self.Controler.RemoveCurrentElementEditingInstance(id)
                self.Controler.AddCurrentElementEditingVariable(id, values["type"])
            self.RefreshVariableModel(variable)
            self.Refresh()
        dialog.Destroy()

    def EditConnectionContent(self, connection):
        dialog = ConnectionPropertiesDialog(self.Parent)
        dialog.SetMinConnectionSize(connection.GetSize())
        values = {"name" : connection.GetName(), "type" : connection.GetType()}
        dialog.SetValues(values)
        if dialog.ShowModal() == wxID_OK:
            old_type = connection.GetType()
            values = dialog.GetValues()
            connection.SetName(values["name"])
            connection.SetType(values["type"])
            connection.SetSize(values["width"], values["height"])
            if old_type != values["type"]:
                id = connection.GetId()
                self.Controler.RemoveCurrentElementEditingInstance(id)
                self.Controler.AddCurrentElementEditingConnection(id, values["type"])
            self.RefreshConnectionModel(connection)
            self.Refresh()
        dialog.Destroy()

    def EditContactContent(self, contact):
        dialog = LDElementDialog(self.Parent, "contact")
        varlist = []
        vars = self.Controler.GetCurrentElementEditingInterfaceVars()
        if vars:
            for var in vars:
                if var["Class"] != "Output" and var["Type"] == "BOOL":
                    varlist.append(var["Name"])
        dialog.SetVariables(varlist)
        values = {"name" : contact.GetName(), "type" : contact.GetType()}
        dialog.SetValues(values)
        dialog.SetElementSize(contact.GetSize())
        if dialog.ShowModal() == wxID_OK:
            values = dialog.GetValues()
            contact.SetName(values["name"])
            contact.SetType(values["type"])
            contact.SetSize(values["width"], values["height"])
            self.RefreshContactModel(contact)
            self.Refresh()
        dialog.Destroy()

    def EditCoilContent(self, coil):
        dialog = LDElementDialog(self.Parent, "coil")
        varlist = []
        vars = self.Controler.GetCurrentElementEditingInterfaceVars()
        if vars:
            for var in vars:
                if var["Class"] != "Input" and var["Type"] == "BOOL":
                    varlist.append(var["Name"])
        returntype = self.Controler.GetCurrentElementEditingInterfaceReturnType()
        if returntype == "BOOL":
            varlist.append(self.Controler.GetCurrentElementEditingName())
        dialog.SetVariables(varlist)
        values = {"name" : coil.GetName(), "type" : coil.GetType()}
        dialog.SetValues(values)
        dialog.SetElementSize(contact.GetSize())
        if dialog.ShowModal() == wxID_OK:
            values = dialog.GetValues()
            coil.SetName(values["name"])
            coil.SetType(values["type"])
            coil.SetSize(values["width"], values["height"])
            self.RefreshContactModel(coil)
            self.Refresh()
        dialog.Destroy()

    def EditPowerRailContent(self, powerrail):
        dialog = LDPowerRailDialog(self.Parent, powerrail.GetType(), len(powerrail.GetConnectors()))
        dialog.SetMinSize(powerrail.GetSize())
        if dialog.ShowModal() == wxID_OK:
            old_type = powerrail.GetType()
            values = dialog.GetValues()
            powerrail.SetType(values["type"])
            powerrail.SetSize(values["width"], values["height"])
            if old_type != values["type"]:
                id = powerrail.GetId()
                self.Controler.RemoveCurrentElementEditingInstance(id)
                self.Controler.AddCurrentElementEditingPowerRail(id, values["type"])
            self.RefreshPowerRailModel(powerrail)
            self.Refresh()
        dialog.Destroy()


    def AddNewTransition(self, bbox):
        dialog = TransitionContentDialog(self.Parent)
        dialog.SetTransitions(self.Controler.GetCurrentElementEditingTransitions())
        if dialog.ShowModal() == wxID_OK:
            id = self.GetNewId()
            values = dialog.GetValues()
            transition = SFC_Transition(self, values["type"], values["value"], id)
            transition.SetPosition(bbox.x, bbox.y)
            min_width, min_height = transition.GetMinSize()
            transition.SetSize(max(bbox.width, min_width), max(bbox.height, min_height))
            self.Blocks.append(transition)
            self.Elements.append(transition)
            self.Controler.AddCurrentElementEditingTransition(id)
            self.RefreshTransitionModel(transition)
            self.Refresh()
        dialog.Destroy()

    def AddNewDivergence(self, bbox):
        dialog = DivergenceCreateDialog(self.Parent)
        dialog.SetMinSize((bbox.width, bbox.height))
        if dialog.ShowModal() == wxID_OK:
            id = self.GetNewId()
            values = dialog.GetValues()
            divergence = SFC_Divergence(self, values["type"], values["number"], id)
            divergence.SetPosition(bbox.x, bbox.y)
            min_width, min_height = divergence.GetMinSize()
            divergence.SetSize(max(bbox.width, min_width), max(bbox.height, min_height))
            self.Blocks.append(divergence)
            self.Elements.append(divergence)
            self.Controler.AddCurrentElementEditingDivergence(id, values["type"])
            self.RefreshDivergenceModel(divergence)
            self.Refresh()
        dialog.Destroy()

#-------------------------------------------------------------------------------
#                          Model update functions
#-------------------------------------------------------------------------------

    def RefreshBlockModel(self, block):
        blockid = block.GetId()
        infos = {}
        infos["type"] = block.GetType()
        infos["name"] = block.GetName()
        infos["x"], infos["y"] = block.GetPosition()
        infos["width"], infos["height"] = block.GetSize()
        infos["connectors"] = block.GetConnectors()
        self.Controler.SetCurrentElementEditingBlockInfos(blockid, infos)
    
    def RefreshVariableModel(self, variable):
        variableid = variable.GetId()
        infos = {}
        infos["name"] = variable.GetName()
        infos["x"], infos["y"] = variable.GetPosition()
        infos["width"], infos["height"] = variable.GetSize()
        infos["connectors"] = variable.GetConnectors()
        self.Controler.SetCurrentElementEditingVariableInfos(variableid, infos)

    def RefreshConnectionModel(self, connection):
        connectionid = connection.GetId()
        infos = {}
        infos["name"] = connection.GetName()
        infos["x"], infos["y"] = connection.GetPosition()
        infos["width"], infos["height"] = connection.GetSize()
        infos["connector"] = connection.GetConnector()
        self.Controler.SetCurrentElementEditingConnectionInfos(connectionid, infos)

    def RefreshCommentModel(self, comment):
        commentid = comment.GetId()
        infos = {}
        infos["content"] = comment.GetContent()
        infos["x"], infos["y"] = comment.GetPosition()
        infos["width"], infos["height"] = comment.GetSize()
        self.Controler.SetCurrentElementEditingCommentInfos(commentid, infos)

    def RefreshPowerRailModel(self, powerrail):
        powerrailid = powerrail.GetId()
        infos = {}
        infos["x"], infos["y"] = powerrail.GetPosition()
        infos["width"], infos["height"] = powerrail.GetSize()
        infos["connectors"] = powerrail.GetConnectors()
        self.Controler.SetCurrentElementEditingPowerRailInfos(powerrailid, infos)

    def RefreshContactModel(self, contact):
        contactid = contact.GetId()
        infos = {}
        infos["name"] = contact.GetName()
        infos["type"] = contact.GetType()
        infos["x"], infos["y"] = contact.GetPosition()
        infos["width"], infos["height"] = contact.GetSize()
        infos["connectors"] = contact.GetConnectors()
        self.Controler.SetCurrentElementEditingContactInfos(contactid, infos)

    def RefreshCoilModel(self, coil):
        coilid = coil.GetId()
        infos = {}
        infos["name"] = coil.GetName()
        infos["type"] = coil.GetType()
        infos["x"], infos["y"] = coil.GetPosition()
        infos["width"], infos["height"] = coil.GetSize()
        infos["connectors"] = coil.GetConnectors()
        self.Controler.SetCurrentElementEditingCoilInfos(coilid, infos)

    def RefreshStepModel(self, step):
        stepid = step.GetId()
        infos = {}
        infos["name"] = step.GetName()
        infos["initial"] = step.GetInitial()
        infos["x"], infos["y"] = step.GetPosition()
        infos["width"], infos["height"] = step.GetSize()
        infos["connectors"] = step.GetConnectors()
        self.Controler.SetCurrentElementEditingStepInfos(stepid, infos)

    def RefreshTransitionModel(self, transition):
        transitionid = transition.GetId()
        infos = {}
        infos["type"] = transition.GetType()
        infos["condition"] = transition.GetCondition()
        infos["x"], infos["y"] = transition.GetPosition()
        infos["width"], infos["height"] = transition.GetSize()
        infos["connectors"] = transition.GetConnectors()
        self.Controler.SetCurrentElementEditingTransitionInfos(transitionid, infos)

    def RefreshDivergenceModel(self, divergence):
        divergenceid = divergence.GetId()
        infos = {}
        infos["x"], infos["y"] = divergence.GetPosition()
        infos["width"], infos["height"] = divergence.GetSize()
        infos["connectors"] = divergence.GetConnectors()
        self.Controler.SetCurrentElementEditingDivergenceInfos(divergenceid, infos)

    def RefreshJumpModel(self, jump):
        jumpid = jump.GetId()
        infos = {}
        infos["target"] = jump.GetTarget()
        infos["x"], infos["y"] = jump.GetPosition()
        infos["width"], infos["height"] = jump.GetSize()
        infos["connector"] = jump.GetConnector()
        self.Controler.SetCurrentElementEditingJumpInfos(jumpid, infos)

    def RefreshActionBlockModel(self, actionblock):
        actionblockid = actionblock.GetId()
        infos = {}
        infos["actions"] = actionblock.GetActions()
        infos["x"], infos["y"] = actionblock.GetPosition()
        infos["width"], infos["height"] = actionblock.GetSize()
        infos["connector"] = actionblock.GetConnector()
        self.Controler.SetCurrentElementEditingActionBlockInfos(actionblockid, infos)


#-------------------------------------------------------------------------------
#                          Model delete functions
#-------------------------------------------------------------------------------


    def DeleteBlock(self, block):
        elements = []
        for output in block.GetConnectors()["outputs"]:
            for element in output.GetConnectedBlocks():
                if element not in elements:
                    elements.append(element)
        block.Clean()
        self.Blocks.remove(block)
        self.Elements.remove(block)
        self.Controler.RemoveCurrentElementEditingInstance(block.GetId())
        for element in elements:
            element.RefreshModel()

    def DeleteVariable(self, variable):
        connectors = variable.GetConnectors()
        if connectors["output"]:
            elements = connectors["output"].GetConnectedBlocks()
        else:
            elements = []
        variable.Clean()
        self.Blocks.remove(variable)
        self.Elements.remove(variable)
        self.Controler.RemoveCurrentElementEditingInstance(variable.GetId())
        for element in elements:
            element.RefreshModel()

    def DeleteConnection(self, connection):
        if connection.GetType() == CONTINUATION:
            elements = connection.GetConnector().GetConnectedBlocks()
        else:
            elements = []
        connection.Clean()
        self.Blocks.remove(connection)
        self.Elements.remove(connection)
        self.Controler.RemoveCurrentElementEditingInstance(connection.GetId())
        for element in elements:
            element.RefreshModel()

    def DeleteComment(self, comment):
        self.Elements.remove(comment)
        self.Controler.RemoveCurrentElementEditingInstance(comment.GetId())

    def DeleteWire(self, wire):
        if wire in self.Wires:
            connected = wire.GetConnected()
            wire.Clean()
            self.Wires.remove(wire)
            self.Elements.remove(wire)
            for connector in connected:
                connector.RefreshParentBlock()

    def DeleteContact(self, contact):
        connectors = contact.GetConnectors()
        elements = connectors["output"].GetConnectedBlocks()
        contact.Clean()
        self.Blocks.remove(contact)
        self.Elements.remove(contact)
        self.Controler.RemoveCurrentElementEditingInstance(contact.GetId())
        for element in elements:
            element.RefreshModel()

    def DeleteCoil(self, coil):
        connectors = coil.GetConnectors()
        elements = connectors["output"].GetConnectedBlocks()
        coil.Clean()
        self.Blocks.remove(coil)
        self.Elements.remove(coil)
        self.Controler.RemoveCurrentElementEditingInstance(coil.GetId())
        for element in elements:
            element.RefreshModel()

    def DeletePowerRail(self, powerrail):
        elements = []
        if powerrail.GetType() == LEFTRAIL:
            for connector in powerrail.GetConnectors():
                for element in connector.GetConnectedBlocks():
                    if element not in elements:
                        elements.append(element)
        powerrrail.Clean()
        self.Blocks.remove(powerrrail)
        self.Elements.remove(powerrrail)
        self.Controler.RemoveCurrentElementEditingInstance(powerrrail.GetId())
        for element in elements:
            element.RefreshModel()

    def DeleteStep(self, step):
        elements = []
        connectors = step.GetConnectors()
        if connectors["output"]:
            for element in connectors["output"].GetConnectedBlocks():
                if element not in elements:
                    elements.append(element)
        if connectors["action"]:
            for element in connectors["action"].GetConnectedBlocks():
                if element not in elements:
                    elements.append(element)
        step.Clean()
        self.Blocks.remove(step)
        self.Elements.remove(step)
        self.Controler.RemoveCurrentElementEditingInstance(step.GetId())
        for element in elements:
            element.RefreshModel()
            
    def DeleteTransition(self, transition):
        elements = []
        connectors = transition.GetConnectors()
        if connectors["output"]:
            for element in connectors["output"].GetConnectedBlocks():
                if element not in elements:
                    elements.append(element)
        transition.Clean()
        self.Blocks.remove(transition)
        self.Elements.remove(transition)
        self.Controler.RemoveCurrentElementEditingInstance(transition.GetId())
        for element in elements:
            element.RefreshModel()

    def DeleteDivergence(self, divergence):
        elements = []
        connectors = divergence.GetConnectors()
        for output in connectors["outputs"]:
            for element in output.GetConnectedBlocks():
                if element not in elements:
                    elements.append(element)
        divergence.Clean()
        self.Blocks.remove(divergence)
        self.Elements.remove(divergence)
        self.Controler.RemoveCurrentElementEditingInstance(divergence.GetId())
        for element in elements:
            element.RefreshModel()
    
    def DeleteJump(self, jump):
        jump.Clean()
        self.Blocks.remove(jump)
        self.Elements.remove(jump)
        self.Controler.RemoveCurrentElementEditingInstance(jump.GetId())
    
    def DeleteActionBlock(self, actionblock):
        actionblock.Clean()
        self.Blocks.remove(actionblock)
        self.Elements.remove(actionblock)
        self.Controler.RemoveCurrentElementEditingInstance(actionblock.GetId())


#-------------------------------------------------------------------------------
#                            Editing functions
#-------------------------------------------------------------------------------
    
    def Cut(self):
        pass
        
    def Copy(self):
        pass
    
    def Paste(self):
        pass

#-------------------------------------------------------------------------------
#                            Drawing functions
#-------------------------------------------------------------------------------

    def OnMoveWindow(self, event):
        self.RefreshScrollBar()
        event.Skip()

    def OnPaint(self, event):
        dc = self.GetLogicalDC()
        dc.Clear()
        dc.SetPen(wxPen(wxColour(230, 230, 230)))
        if self.Scaling and self.DrawGrid:
            width, height = dc.GetSize()
            for i in xrange(1, width / self.Scaling[0] + 1):
                dc.DrawLine(i * self.Scaling[0], 0, i * self.Scaling[0], height)
            for i in xrange(1, height / self.Scaling[1] + 1):
                dc.DrawLine(0, i * self.Scaling[1], width, i * self.Scaling[1])
        for wire in self.Wires:
            if wire != self.SelectedElement:
                wire.Draw(dc)
        for element in self.Elements:
            if element not in self.Wires and element != self.SelectedElement:
                element.Draw(dc)
        if self.SelectedElement:
            self.SelectedElement.Draw(dc)
        if self.rubberBand.IsShown():
            self.rubberBand.Draw()
        event.Skip()