Adding scaling
authorlbessard
Fri, 11 Jan 2008 17:51:56 +0100
changeset 145 4fb225afddf4
parent 144 b67a5de5a24a
child 146 cc70dd430601
Adding scaling
Lots of bugs fixed
Dialogs.py
PLCControler.py
PLCOpenEditor.py
RessourceEditor.py
SFCViewer.py
TextViewer.py
Viewer.py
examples/example.xml
graphics/FBD_Objects.py
graphics/GraphicCommons.py
graphics/LD_Objects.py
graphics/SFC_Objects.py
plcopen/plcopen.py
--- a/Dialogs.py	Fri Jan 04 17:49:17 2008 +0100
+++ b/Dialogs.py	Fri Jan 11 17:51:56 2008 +0100
@@ -161,6 +161,7 @@
               size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL|wx.SIMPLE_BORDER)
         self.Preview.SetBackgroundColour(wx.Colour(255,255,255))
         setattr(self.Preview, "GetDrawingMode", lambda:FREEDRAWING_MODE)
+        setattr(self.Preview, "GetScaling", lambda:None)
 
         self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
         if wx.VERSION >= (2, 5, 0):
@@ -502,6 +503,7 @@
               size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL|wx.SIMPLE_BORDER)
         self.Preview.SetBackgroundColour(wx.Colour(255,255,255))
         setattr(self.Preview, "GetDrawingMode", lambda:FREEDRAWING_MODE)
+        setattr(self.Preview, "GetScaling", lambda:None)
 
         self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
 
@@ -764,6 +766,7 @@
               size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL|wx.SIMPLE_BORDER)
         self.Preview.SetBackgroundColour(wx.Colour(255,255,255))
         setattr(self.Preview, "GetDrawingMode", lambda:FREEDRAWING_MODE)
+        setattr(self.Preview, "GetScaling", lambda:None)
 
         self.Spacer = wx.Panel(id=ID_CONNECTIONPROPERTIESDIALOGSPACER,
               name='Spacer', parent=self, pos=wx.Point(0, 0),
@@ -958,6 +961,7 @@
               size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL|wx.SIMPLE_BORDER)
         self.Preview.SetBackgroundColour(wx.Colour(255,255,255))
         setattr(self.Preview, "GetDrawingMode", lambda:FREEDRAWING_MODE)
+        setattr(self.Preview, "GetScaling", lambda:None)
 
         self.Spacer = wx.Panel(id=ID_LDELEMENTDIALOGSPACER,
               name='Spacer', parent=self, pos=wx.Point(0, 0),
@@ -1174,6 +1178,7 @@
               size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL|wx.SIMPLE_BORDER)
         self.Preview.SetBackgroundColour(wx.Colour(255,255,255))
         setattr(self.Preview, "GetDrawingMode", lambda:FREEDRAWING_MODE)
+        setattr(self.Preview, "GetScaling", lambda:None)
 
         self.Spacer = wx.Panel(id=ID_LDELEMENTDIALOGSPACER,
               name='Spacer', parent=self, pos=wx.Point(0, 0),
@@ -1357,6 +1362,7 @@
         self.Preview.SetBackgroundColour(wx.Colour(255,255,255))
         setattr(self.Preview, "GetDrawingMode", lambda:FREEDRAWING_MODE)
         setattr(self.Preview, "RefreshStepModel", lambda x:None)
+        setattr(self.Preview, "GetScaling", lambda:None)
 
         self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
         if wx.VERSION >= (2, 5, 0):
@@ -1610,6 +1616,7 @@
         self.Preview.SetBackgroundColour(wx.Colour(255,255,255))
         setattr(self.Preview, "GetDrawingMode", lambda:FREEDRAWING_MODE)
         setattr(self.Preview, "RefreshTransitionModel", lambda x:None)
+        setattr(self.Preview, "GetScaling", lambda:None)
 
         self.Spacer = wx.Panel(id=ID_TRANSITIONCONTENTDIALOGSPACER,
               name='Spacer', parent=self, pos=wx.Point(0, 0),
--- a/PLCControler.py	Fri Jan 04 17:49:17 2008 +0100
+++ b/PLCControler.py	Fri Jan 11 17:51:56 2008 +0100
@@ -27,6 +27,7 @@
 from types import StringType, UnicodeType
 import cPickle
 import os,sys,re
+from time import localtime
 from datetime import *
 
 from plcopen import plcopen
@@ -188,10 +189,12 @@
         return self.Project != None
 
     # Create a new project by replacing the current one
-    def CreateNewProject(self, name):
+    def CreateNewProject(self, properties):
         # Create the project
         self.Project = plcopen.project()
-        self.Project.setName(name)
+        properties["creationDateTime"] = datetime(*localtime()[:6])
+        self.Project.setFileHeader(properties)
+        self.Project.setContentHeader(properties)
         self.SetFilePath("")
         # Initialize the project buffer
         self.ProjectBuffer = UndoBuffer(self.Copy(self.Project), False)
@@ -261,13 +264,14 @@
             self.Project.setName(name)
         if properties != None:
             self.Project.setFileHeader(properties)
+            self.Project.setContentHeader(properties)
         if name != None or properties != None:
             self.BufferProject()
             
     # Return project properties
     def GetProjectProperties(self):
         properties = self.Project.getFileHeader()
-        properties["projectName"] = self.Project.getName()
+        properties.update(self.Project.getContentHeader())
         return properties
     
     # Return project informations
@@ -1420,24 +1424,12 @@
                         infos["connectors"]["input"]["links"].append(dic)
             elif isinstance(instance, plcopen.continuation):
                 infos["name"] = instance.getName()
-                infos["value_type"] = self.GetCurrentPouVarValueType(infos["name"])
                 infos["type"] = "continuation"
-                executionOrder = instance.getExecutionOrderId()
-                if executionOrder is not None:
-                    infos["executionOrder"] = executionOrder
-                else:
-                    infos["executionOrder"] = 0
                 infos["connector"] = {}
                 infos["connector"]["position"] = instance.connectionPointOut.getRelPosition()
             elif isinstance(instance, plcopen.connector):
                 infos["name"] = instance.getName()
-                infos["value_type"] = self.GetCurrentPouVarValueType(infos["name"])
                 infos["type"] = "connection"
-                executionOrder = instance.getExecutionOrderId()
-                if executionOrder is not None:
-                    infos["executionOrder"] = executionOrder
-                else:
-                    infos["executionOrder"] = 0
                 infos["connector"] = {}
                 infos["connector"]["position"] = instance.connectionPointIn.getRelPosition()
                 infos["connector"]["links"] = []
@@ -1664,6 +1656,18 @@
                     connection.setConnectionParameter(idx, None)
                 idx += 1
     
+    def AddEditedElementPouVar(self, tagname, type, name):
+        words = tagname.split("::")
+        if words[0] in ['P', 'T', 'A']:
+            pou = self.Project.getPou(words[1])
+            pou.addPouVar(type, name)
+            
+    def ChangeEditedElementPouVar(self, tagname, old_type, old_name, new_type, new_name):
+        words = tagname.split("::")
+        if words[0] in ['P', 'T', 'A']:
+            pou = self.Project.getPou(words[1])
+            pou.changePouVar(old_type, old_name, new_type, new_name)
+    
     def AddEditedElementBlock(self, tagname, id, blocktype, blockname = None):
         element = self.GetEditedElement(tagname)
         if element is not None:
@@ -1673,7 +1677,7 @@
             blocktype_infos = GetBlockType(blocktype)
             if blocktype_infos["type"] != "function" and blockname is not None:
                 block.setInstanceName(blockname)
-                element.addPouVar(blocktype, blockname)    
+                self.AddEditedElementPouVar(tagname, blocktype, blockname)
             element.addInstance("block", block)
             self.RefreshPouUsingTree()
     
@@ -1681,12 +1685,15 @@
         element = self.GetEditedElement(tagname)
         if element is not None:
             block = element.getInstance(id)
-            if "name" in infos or "type" in infos:
-                old_name = block.getInstanceName()
-                old_type = block.getTypeName()
-                new_name = infos.get("name", old_name)
-                new_type = infos.get("type", old_type)
-                self.GetEditedElement(tagname).changePouVar(old_type, old_name, new_type, new_name)
+            blocktype = infos.get("type", block.getTypeName())
+            blocktype_infos = GetBlockType(blocktype)
+            if blocktype_infos["type"] != "function":
+                if "name" in infos or "type" in infos:
+                    old_name = block.getInstanceName()
+                    old_type = block.getTypeName()
+                    new_name = infos.get("name", old_name)
+                    new_type = infos.get("type", old_type)
+                    self.ChangeEditedElementPouVar(tagname, old_type, old_name, new_type, new_name)
             for param, value in infos.items():
                 if param == "name":
                     block.setInstanceName(value)
@@ -2337,6 +2344,10 @@
         if not filepath and self.FilePath == "":
             return False
         else:
+            contentheader = self.Project.getContentHeader()
+            contentheader["modificationDateTime"] = datetime(*localtime()[:6])
+            self.Project.setContentHeader(contentheader)
+            
             text = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
             extras = {"xmlns" : "http://www.plcopen.org/xml/tc6.xsd",
                       "xmlns:xhtml" : "http://www.w3.org/1999/xhtml",
--- a/PLCOpenEditor.py	Fri Jan 04 17:49:17 2008 +0100
+++ b/PLCOpenEditor.py	Fri Jan 11 17:51:56 2008 +0100
@@ -22,7 +22,6 @@
 #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 time import localtime
 from datetime import datetime
 import wx, wx.grid
 
@@ -423,11 +422,11 @@
                     self.OnPouSelectedChanged)
         
         if wx.VERSION < (2, 8, 0):
-            self.VariablePanelIndexer = VariablePanelIndexer(self.SecondSplitter, self.Controler)
+            self.VariablePanelIndexer = VariablePanelIndexer(self.SecondSplitter, self, self.Controler)
             
             self.SecondSplitter.SplitHorizontally(self.TabsOpened, self.VariablePanelIndexer, -200)
         else:
-            self.VariablePanelIndexer = VariablePanelIndexer(self, self.Controler)
+            self.VariablePanelIndexer = VariablePanelIndexer(self, self, self.Controler)
             self.AUIManager.AddPane(self.VariablePanelIndexer, wx.aui.AuiPaneInfo().Caption("Variable Panel").Bottom().Layer(0).BestSize(wx.Size(800, 200)).CloseButton(False))
             
             self.AUIManager.Update()
@@ -644,10 +643,16 @@
         dialog.SetValues(old_values)
         if dialog.ShowModal() == wx.ID_OK:
             new_values = dialog.GetValues()
-            projectname = new_values.pop("projectName")
             new_values["creationDateTime"] = old_values["creationDateTime"]
-            self.Controler.SetProjectProperties(projectname, new_values)
-            self.RefreshProjectTree()
+            if new_values != old_values:
+                self.Controler.SetProjectProperties(None, new_values)
+                self.RefreshTitle()
+                self.RefreshFileMenu()
+                self.RefreshEditMenu()
+                self.RefreshProjectTree()
+                for i in xrange(self.GetPageCount()):
+                    editor = self.GetPage(i)
+                    editor.RefreshScaling()
         dialog.Destroy()
 
     def OnCloseFrame(self, event):
@@ -675,11 +680,8 @@
     def OnNewProjectMenu(self, event):
         dialog = ProjectDialog(self)
         if dialog.ShowModal() == wx.ID_OK:
-            values = dialog.GetValues()
-            projectname = values.pop("projectName")
-            values["creationDateTime"] = datetime(*localtime()[:6])
-            self.Controler.CreateNewProject(projectname)
-            self.Controler.SetProjectProperties(projectname, values)
+            properties = dialog.GetValues()
+            self.Controler.CreateNewProject(properties)
             self.RefreshTitle()
             self.RefreshFileMenu()
             self.RefreshEditMenu()
@@ -1036,10 +1038,12 @@
                 dragSource.DoDragDrop()
             self.ResetSelectedItem()
 
-    def RefreshEditorNames(self, item_type, old_name, new_name):
+    def RefreshEditorNames(self, old_tagname, new_tagname):
         for i in xrange(self.GetPageCount()):
             editor = self.GetPage(i)
-            editor.RefreshName(item_type, old_name, new_name)
+            if editor.GetTagName() == old_tagname:
+                editor.SetTagName(new_tagname)
+        self.VariablePanelIndexer.UpdateVariablePanelTagName(old_tagname, new_tagname)
 
     def OnProjectTreeItemEndEdit(self, event):
         message = None
@@ -1062,7 +1066,8 @@
                         abort = True
                     if not abort:
                         self.Controler.ChangeDataTypeName(old_name, new_name)
-                        self.RefreshEditorNames(itemtype, old_name, new_name)
+                        self.RefreshEditorNames(self.Controler.ComputeDataTypeName(old_name), 
+                                                self.Controler.ComputeDataTypeName(new_name))
                         self.RefreshPageTitles()
                 elif itemtype == ITEM_POU:
                     if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames() if name != old_name]:
@@ -1075,7 +1080,8 @@
                         messageDialog.Destroy()
                     if not abort:
                         self.Controler.ChangePouName(old_name, new_name)
-                        self.RefreshEditorNames(itemtype, old_name, new_name)
+                        self.RefreshEditorNames(self.Controler.ComputePouName(old_name), 
+                                                self.Controler.ComputePouName(new_name))
                         self.RefreshPageTitles()
                 elif itemtype == ITEM_TRANSITION:
                     parent = self.ProjectTree.GetItemParent(item)
@@ -1090,7 +1096,8 @@
                         message = "A variable with \"%s\" as name already exists in this pou!"%new_name
                     else:
                         self.Controler.ChangePouTransitionName(pou_name, old_name, new_name)
-                        self.RefreshEditorNames(itemtype, old_name, new_name)
+                        self.RefreshEditorNames(self.Controler.ComputePouTransitionName(pou_name, old_name), 
+                                                self.Controler.ComputePouTransitionName(pou_name, new_name))
                         self.RefreshPageTitles()
                 elif itemtype == ITEM_ACTION:
                     parent = self.ProjectTree.GetItemParent(item)
@@ -1105,7 +1112,8 @@
                         message = "A variable with \"%s\" as name already exists in this pou!"%new_name
                     else:
                         self.Controler.ChangePouActionName(pou_name, old_name, new_name)
-                        self.RefreshEditorNames(itemtype, old_name, new_name)
+                        self.RefreshEditorNames(self.Controler.ComputePouActionName(pou_name, old_name), 
+                                                self.Controler.ComputePouActionName(pou_name, new_name))
                         self.RefreshPageTitles()
                 elif itemtype == ITEM_CONFIGURATION:
                     if new_name.upper() in [name.upper() for name in self.Controler.GetProjectConfigNames() if name != old_name]:
@@ -1123,7 +1131,8 @@
                         messageDialog.Destroy()
                     if not abort:
                         self.Controler.ChangeConfigurationName(old_name, new_name)
-                        self.RefreshEditorNames(itemtype, old_name, new_name)
+                        self.RefreshEditorNames(self.Controler.ComputeConfigurationName(old_name), 
+                                                self.Controler.ComputeConfigurationName(new_name))
                         self.RefreshPageTitles()
                 elif itemtype == ITEM_RESOURCE:
                     parent = self.ProjectTree.GetItemParent(item)
@@ -1147,7 +1156,8 @@
                         messageDialog.Destroy()
                     if not abort:
                         self.Controler.ChangeConfigurationResourceName(config_name, old_name, new_name)
-                        self.RefreshEditorNames(itemtype, old_name, new_name)
+                        self.RefreshEditorNames(self.Controler.ComputeConfigurationResourceName(config_name, old_name), 
+                                                self.Controler.ComputeConfigurationResourceName(config_name, new_name))
                         self.RefreshPageTitles()
             if message or abort:
                 if message:
@@ -1287,10 +1297,13 @@
                     bodytype = self.Controler.GetEditedElementBodyType(tagname)
                     if bodytype == "FBD":
                         new_window = MDIViewer(self, tagname, self, self.Controler)
+                        new_window.GetViewer().RefreshScaling(False)
                     elif bodytype == "LD":
                         new_window = LD_MDIViewer(self, tagname, self, self.Controler)
+                        new_window.GetViewer().RefreshScaling(False)
                     elif bodytype == "SFC":
                         new_window = SFC_MDIViewer(self, tagname, self, self.Controler)
+                        new_window.GetViewer().RefreshScaling(False)
                     else:
                         new_window = TextMDIViewer(self, tagname, self, self.Controler)
                         viewer = new_window.GetViewer()
@@ -1315,10 +1328,13 @@
                     bodytype = self.Controler.GetEditedElementBodyType(tagname)
                     if bodytype == "FBD":
                         new_window = Viewer(self.TabsOpened, tagname, self, self.Controler)
+                        new_window.RefreshScaling(False)
                     elif bodytype == "LD":
                         new_window = LD_Viewer(self.TabsOpened, tagname, self, self.Controler)
+                        new_window.RefreshScaling(False)
                     elif bodytype == "SFC":
                         new_window = SFC_Viewer(self.TabsOpened, tagname, self, self.Controler)
+                        new_window.RefreshScaling(False)
                     else:
                         new_window = TextViewer(self.TabsOpened, tagname, self, self.Controler)
                         new_window.SetTextSyntax(elementtype)
@@ -1741,16 +1757,83 @@
 #                            Create Project Dialog
 #-------------------------------------------------------------------------------
 
-[ID_PROJECTDIALOG, ID_PROJECTDIALOGPROJECTNAME, 
- ID_PROJECTDIALOGCOMPANYNAME, ID_PROJECTDIALOGCOMPANYURL, 
+[ID_SCALINGPANEL, ID_SCALINGPANELXSCALE, 
+ ID_SCALINGPANELYSCALE, ID_SCALINGPANELSTATICTEXT1, 
+ ID_SCALINGPANELSTATICTEXT2, 
+] = [wx.NewId() for _init_ctrls in range(5)]
+
+class ScalingPanel(wx.Panel):
+    
+    def _init_coll_ScalingPanelSizer_Items(self, parent):
+        parent.AddWindow(self.staticText1, 0, border=10, flag=wx.GROW|wx.TOP|wx.LEFT)
+        parent.AddWindow(self.XScale, 0, border=10, flag=wx.GROW|wx.TOP|wx.RIGHT)
+        parent.AddWindow(self.staticText2, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.LEFT)
+        parent.AddWindow(self.YScale, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.RIGHT)
+
+    def _init_coll_ScalingPanelSizer_Growables(self, parent):
+        parent.AddGrowableCol(1)
+
+    def _init_sizers(self):
+        self.ScalingPanelSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=2, vgap=5)
+        
+        self._init_coll_ScalingPanelSizer_Items(self.ScalingPanelSizer)
+        self._init_coll_ScalingPanelSizer_Growables(self.ScalingPanelSizer)
+
+        self.SetSizer(self.ScalingPanelSizer)
+
+    def _init_ctrls(self, prnt):
+        wx.Panel.__init__(self, id=ID_SCALINGPANEL,
+              name='ScalingPanel', parent=prnt, pos=wx.Point(0, 0),
+              size=wx.Size(0, 0), style=0)
+        
+        self.staticText1 = wx.StaticText(id=ID_SCALINGPANELSTATICTEXT1,
+              label='X Scale:', name='staticText1', parent=self,
+              pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0)
+        
+        self.XScale = wx.SpinCtrl(id=ID_SCALINGPANELXSCALE,
+              name='XScale', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(0, 24), style=0, min=0, max=2**16)
+        
+        self.staticText2 = wx.StaticText(id=ID_SCALINGPANELSTATICTEXT2,
+              label='Y Scale:', name='staticText2', parent=self,
+              pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0)
+        
+        self.YScale = wx.SpinCtrl(id=ID_SCALINGPANELYSCALE,
+              name='YScale', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(0, 24), style=0, min=0, max=2**16)
+        
+        self._init_sizers()
+        
+    def __init__(self, parent):
+        self._init_ctrls(parent)
+
+    def SetScaling(self, x, y):
+        self.XScale.SetValue(x)
+        self.YScale.SetValue(y)
+        
+    def GetScaling(self):
+        return self.XScale.GetValue(), self.YScale.GetValue()
+
+[ID_PROJECTDIALOG, ID_PROJECTDIALOGMAINNOTEBOOK, 
+ ID_PROJECTDIALOGPROJECTPANEL, ID_PROJECTDIALOGAUTHORPANEL, 
+ ID_PROJECTDIALOGGRAPHICSPANEL, ID_PROJECTDIALOGMISCELLANEOUSPANEL, 
+ ID_PROJECTDIALOGPROJECTNAME, ID_PROJECTDIALOGPROJECTVERSION, 
  ID_PROJECTDIALOGPRODUCTNAME, ID_PROJECTDIALOGPRODUCTVERSION, 
- ID_PROJECTDIALOGPRODUCTRELEASE, ID_PROJECTDIALOGCONTENTDESCRIPTION, 
+ ID_PROJECTDIALOGPRODUCTRELEASE, ID_PROJECTDIALOGCOMPANYNAME, 
+ ID_PROJECTDIALOGCOMPANYURL, ID_PROJECTDIALOGAUTHORNAME, 
+ ID_PROJECTDIALOGORGANIZATION, ID_PROJECTDIALOGLANGUAGE, 
+ ID_PROJECTDIALOGCONTENTDESCRIPTION, ID_PROJECTDIALOGSCALINGNOTEBOOK, 
+ ID_PROJECTDIALOGPAGEWIDTH, ID_PROJECTDIALOGPAGEHEIGHT, 
  ID_PROJECTDIALOGSTATICTEXT1, ID_PROJECTDIALOGSTATICTEXT2, 
  ID_PROJECTDIALOGSTATICTEXT3, ID_PROJECTDIALOGSTATICTEXT4, 
  ID_PROJECTDIALOGSTATICTEXT5, ID_PROJECTDIALOGSTATICTEXT6, 
- ID_PROJECTDIALOGSTATICTEXT7, 
-] = [wx.NewId() for _init_ctrls in range(15)]
-        
+ ID_PROJECTDIALOGSTATICTEXT7, ID_PROJECTDIALOGSTATICTEXT8, 
+ ID_PROJECTDIALOGSTATICTEXT9, ID_PROJECTDIALOGSTATICTEXT10, 
+ ID_PROJECTDIALOGSTATICTEXT11, ID_PROJECTDIALOGSTATICTEXT12, 
+ ID_PROJECTDIALOGSTATICTEXT13, ID_PROJECTDIALOGSTATICTEXT14, 
+ ID_PROJECTDIALOGSTATICTEXT15, 
+] = [wx.NewId() for _init_ctrls in range(35)]
+
 class ProjectDialog(wx.Dialog):
     if wx.VERSION < (2, 6, 0):
         def Bind(self, event, function, id = None):
@@ -1760,106 +1843,261 @@
                 event(self, function)
                 
     def _init_coll_flexGridSizer1_Items(self, parent):
-        parent.AddSizer(self.MainSizer, 0, border=20, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
+        parent.AddSizer(self.MainNotebook, 0, border=0, flag=wx.GROW)
         parent.AddSizer(self.ButtonSizer, 0, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
         
     def _init_coll_flexGridSizer1_Growables(self, parent):
         parent.AddGrowableCol(0)
         parent.AddGrowableRow(0)
     
-    def _init_coll_MainSizer_Items(self, parent):
-        parent.AddWindow(self.staticText1, 0, border=4, flag=wx.GROW|wx.TOP)
-        parent.AddWindow(self.ProjectName, 0, border=0, flag=wx.GROW)
-        parent.AddWindow(self.staticText2, 0, border=4, flag=wx.GROW|wx.TOP)
-        parent.AddWindow(self.CompanyName, 0, border=0, flag=wx.GROW)
-        parent.AddWindow(self.staticText3, 0, border=4, flag=wx.GROW|wx.TOP)
-        parent.AddWindow(self.CompanyURL, 0, border=0, flag=wx.GROW)
-        parent.AddWindow(self.staticText4, 0, border=4, flag=wx.GROW|wx.TOP)
-        parent.AddWindow(self.ProductName, 0, border=0, flag=wx.GROW)
-        parent.AddWindow(self.staticText5, 0, border=4, flag=wx.GROW|wx.TOP)
-        parent.AddWindow(self.ProductVersion, 0, border=0, flag=wx.GROW)
-        parent.AddWindow(self.staticText6, 0, border=4, flag=wx.GROW|wx.TOP)
-        parent.AddWindow(self.ProductRelease, 0, border=0, flag=wx.GROW)
-        parent.AddWindow(self.staticText7, 0, border=4, flag=wx.GROW|wx.TOP)
-        parent.AddWindow(self.ContentDescription, 0, border=0, flag=wx.GROW)
-        
-    def _init_coll_MainSizer_Growables(self, parent):
+    def _init_coll_ProjectPanelSizer_Items(self, parent):
+        parent.AddWindow(self.staticText1, 0, border=10, flag=wx.GROW|wx.TOP|wx.LEFT)
+        parent.AddWindow(self.ProjectName, 0, border=10, flag=wx.GROW|wx.TOP|wx.RIGHT)
+        parent.AddWindow(self.staticText2, 0, border=10, flag=wx.GROW|wx.LEFT)
+        parent.AddWindow(self.ProjectVersion, 0, border=10, flag=wx.GROW|wx.RIGHT)
+        parent.AddWindow(self.staticText3, 0, border=10, flag=wx.GROW|wx.LEFT)
+        parent.AddWindow(self.ProductName, 0, border=10, flag=wx.GROW|wx.RIGHT)
+        parent.AddWindow(self.staticText4, 0, border=10, flag=wx.GROW|wx.LEFT)
+        parent.AddWindow(self.ProductVersion, 0, border=10, flag=wx.GROW|wx.RIGHT)
+        parent.AddWindow(self.staticText5, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.LEFT)
+        parent.AddWindow(self.ProductRelease, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.RIGHT)
+        
+    def _init_coll_ProjectPanelSizer_Growables(self, parent):
         parent.AddGrowableCol(1)
-        parent.AddGrowableRow(6)
+
+    def _init_coll_AuthorPanelSizer_Items(self, parent):
+        parent.AddWindow(self.staticText6, 0, border=10, flag=wx.GROW|wx.TOP|wx.LEFT)
+        parent.AddWindow(self.CompanyName, 0, border=10, flag=wx.GROW|wx.TOP|wx.RIGHT)
+        parent.AddWindow(self.staticText7, 0, border=10, flag=wx.GROW|wx.LEFT)
+        parent.AddWindow(self.CompanyURL, 0, border=10, flag=wx.GROW|wx.RIGHT)
+        parent.AddWindow(self.staticText8, 0, border=10, flag=wx.GROW|wx.LEFT)
+        parent.AddWindow(self.AuthorName, 0, border=10, flag=wx.GROW|wx.RIGHT)
+        parent.AddWindow(self.staticText9, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.LEFT)
+        parent.AddWindow(self.Organization, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.RIGHT)
+    
+    def _init_coll_AuthorPanelSizer_Growables(self, parent):
+        parent.AddGrowableCol(1)
+    
+    def _init_coll_GraphicsPanelSizer_Items(self, parent):
+        parent.AddWindow(self.staticText12, 0, border=10, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
+        parent.AddSizer(self.GraphicsPageSizeSizer, 0, border=10, flag=wx.GROW|wx.LEFT|wx.RIGHT)
+        parent.AddWindow(self.staticText15, 0, border=10, flag=wx.GROW|wx.LEFT|wx.RIGHT)
+        parent.AddWindow(self.ScalingNotebook, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT)
+        
+    def _init_coll_GraphicsPanelSizer_Growables(self, parent):
+        parent.AddGrowableCol(0)
+        parent.AddGrowableRow(3)
+    
+    def _init_coll_GraphicsPageSizeSizer_Items(self, parent):
+        parent.AddWindow(self.staticText13, 0, border=12, flag=wx.GROW|wx.LEFT)
+        parent.AddWindow(self.PageWidth, 0, border=0, flag=wx.GROW)
+        parent.AddWindow(self.staticText14, 0, border=12, flag=wx.GROW|wx.LEFT)
+        parent.AddWindow(self.PageHeight, 0, border=0, flag=wx.GROW)
+    
+    def _init_coll_GraphicsPageSizeSizer_Growables(self, parent):
+        parent.AddGrowableCol(1)
+    
+    def _init_coll_MiscellaneousPanelSizer_Items(self, parent):
+        parent.AddWindow(self.staticText10, 0, border=10, flag=wx.GROW|wx.TOP|wx.LEFT)
+        parent.AddWindow(self.Language, 0, border=10, flag=wx.GROW|wx.TOP|wx.RIGHT)
+        parent.AddWindow(self.staticText11, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.LEFT)
+        parent.AddWindow(self.ContentDescription, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.RIGHT)
+        
+    def _init_coll_MiscellaneousPanelSizer_Growables(self, parent):
+        parent.AddGrowableCol(1)
+        parent.AddGrowableRow(1)
         
     def _init_sizers(self):
         self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10)
-        self.MainSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=7, vgap=15)
+        self.ProjectPanelSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=5, vgap=15)
+        self.AuthorPanelSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=4, vgap=15)
+        self.GraphicsPanelSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=4, vgap=5)
+        self.GraphicsPageSizeSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=2, vgap=5)
+        self.MiscellaneousPanelSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=2, vgap=15)
 
         self._init_coll_flexGridSizer1_Items(self.flexGridSizer1)
         self._init_coll_flexGridSizer1_Growables(self.flexGridSizer1)
-        self._init_coll_MainSizer_Items(self.MainSizer)
-        self._init_coll_MainSizer_Growables(self.MainSizer)
+        self._init_coll_ProjectPanelSizer_Items(self.ProjectPanelSizer)
+        self._init_coll_ProjectPanelSizer_Growables(self.ProjectPanelSizer)
+        self._init_coll_AuthorPanelSizer_Items(self.AuthorPanelSizer)
+        self._init_coll_AuthorPanelSizer_Growables(self.AuthorPanelSizer)
+        self._init_coll_GraphicsPanelSizer_Items(self.GraphicsPanelSizer)
+        self._init_coll_GraphicsPanelSizer_Growables(self.GraphicsPanelSizer)
+        self._init_coll_GraphicsPageSizeSizer_Items(self.GraphicsPageSizeSizer)
+        self._init_coll_GraphicsPageSizeSizer_Growables(self.GraphicsPageSizeSizer)
+        self._init_coll_MiscellaneousPanelSizer_Items(self.MiscellaneousPanelSizer)
+        self._init_coll_MiscellaneousPanelSizer_Growables(self.MiscellaneousPanelSizer)
 
         self.SetSizer(self.flexGridSizer1)
+        self.ProjectPanel.SetSizer(self.ProjectPanelSizer)
+        self.AuthorPanel.SetSizer(self.AuthorPanelSizer)
+        self.GraphicsPanel.SetSizer(self.GraphicsPanelSizer)
+        self.MiscellaneousPanel.SetSizer(self.MiscellaneousPanelSizer)
 
     def _init_ctrls(self, prnt):
         wx.Dialog.__init__(self, id=ID_PROJECTDIALOG,
               name='ProjectDialog', parent=prnt, pos=wx.Point(376, 223),
-              size=wx.Size(550, 450), style=wx.DEFAULT_DIALOG_STYLE,
+              size=wx.Size(500, 350), style=wx.DEFAULT_DIALOG_STYLE,
               title='Create a new project')
-        self.SetClientSize(wx.Size(550, 450))
+        self.SetClientSize(wx.Size(500, 350))
+
+        self.MainNotebook = wx.Notebook(id=ID_PROJECTDIALOGMAINNOTEBOOK,
+                  name='MainNotebook', parent=self, pos=wx.Point(0,
+                  0), size=wx.Size(0, 0), style=0)
+
+        # Project Panel elements
+
+        self.ProjectPanel = wx.Panel(id=ID_PROJECTDIALOGPROJECTPANEL,
+              name='ProjectPanel', parent=self.MainNotebook, pos=wx.Point(0, 0),
+              size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
 
         self.staticText1 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT1,
-              label='Project Name (required):', name='staticText1', parent=self,
+              label='Project Name (required):', name='staticText1', parent=self.ProjectPanel,
               pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0)
 
         self.ProjectName = wx.TextCtrl(id=ID_PROJECTDIALOGPROJECTNAME,
-              name='ProjectName', parent=self, pos=wx.Point(0, 0), 
+              name='ProjectName', parent=self.ProjectPanel, pos=wx.Point(0, 0), 
               size=wx.Size(0, 24), style=0)
 
         self.staticText2 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT2,
-              label='Company Name (required):', name='staticText2', parent=self,
+              label='Project Version (optional):', name='staticText2', parent=self.ProjectPanel,
               pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0)
 
+        self.ProjectVersion = wx.TextCtrl(id=ID_PROJECTDIALOGPROJECTVERSION,
+              name='ProjectVersion', parent=self.ProjectPanel, pos=wx.Point(0, 0), 
+              size=wx.Size(0, 24), style=0)
+
+        self.staticText3 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT3,
+              label='Product Name (required):', name='staticText3', parent=self.ProjectPanel,
+              pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0)
+
+        self.ProductName = wx.TextCtrl(id=ID_PROJECTDIALOGPRODUCTNAME,
+              name='ProductName', parent=self.ProjectPanel, pos=wx.Point(0, 0),
+              size=wx.Size(0, 24), style=0)
+
+        self.staticText4 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT4,
+              label='Product Version (required):', name='staticText4', parent=self.ProjectPanel,
+              pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0)
+
+        self.ProductVersion = wx.TextCtrl(id=ID_PROJECTDIALOGPRODUCTVERSION,
+              name='ProductVersion', parent=self.ProjectPanel, pos=wx.Point(0, 0),
+              size=wx.Size(0, 24), style=0)
+
+        self.staticText5 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT5,
+              label='Product Release (optional):', name='staticText5', parent=self.ProjectPanel,
+              pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0)
+
+        self.ProductRelease = wx.TextCtrl(id=ID_PROJECTDIALOGPRODUCTRELEASE,
+              name='ProductRelease', parent=self.ProjectPanel, pos=wx.Point(0, 0),
+              size=wx.Size(0, 24), style=0)
+
+        self.MainNotebook.AddPage(self.ProjectPanel, "Project")
+        
+        # Author Panel elements
+
+        self.AuthorPanel = wx.Panel(id=ID_PROJECTDIALOGAUTHORPANEL,
+              name='AuthorPanel', parent=self.MainNotebook, pos=wx.Point(0, 0),
+              size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
+
+        self.staticText6 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT6,
+              label='Company Name (required):', name='staticText6', parent=self.AuthorPanel,
+              pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0)
+
         self.CompanyName = wx.TextCtrl(id=ID_PROJECTDIALOGCOMPANYNAME,
-              name='CompanyName', parent=self, pos=wx.Point(0, 0),
+              name='CompanyName', parent=self.AuthorPanel, pos=wx.Point(0, 0),
               size=wx.Size(0, 24), style=0)
 
-        self.staticText3 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT3,
-              label='Company URL (optional):', name='staticText3', parent=self,
+        self.staticText7 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT7,
+              label='Company URL (optional):', name='staticText7', parent=self.AuthorPanel,
               pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0)
 
         self.CompanyURL = wx.TextCtrl(id=ID_PROJECTDIALOGCOMPANYURL,
-              name='CompanyURL', parent=self, pos=wx.Point(0, 0),
+              name='CompanyURL', parent=self.AuthorPanel, pos=wx.Point(0, 0),
               size=wx.Size(0, 24), style=0)
 
-        self.staticText4 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT4,
-              label='Product Name (required):', name='staticText4', parent=self,
+        self.staticText8 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT8,
+              label='Author Name (optional):', name='staticText8', parent=self.AuthorPanel,
               pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0)
 
-        self.ProductName = wx.TextCtrl(id=ID_PROJECTDIALOGPRODUCTNAME,
-              name='ProductName', parent=self, pos=wx.Point(0, 0),
+        self.AuthorName = wx.TextCtrl(id=ID_PROJECTDIALOGAUTHORNAME,
+              name='AuthorName', parent=self.AuthorPanel, pos=wx.Point(0, 0),
               size=wx.Size(0, 24), style=0)
 
-        self.staticText5 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT5,
-              label='Product Version (required):', name='staticText5', parent=self,
+        self.staticText9 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT9,
+              label='Organization (optional):', name='staticText9', parent=self.AuthorPanel,
               pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0)
 
-        self.ProductVersion = wx.TextCtrl(id=ID_PROJECTDIALOGPRODUCTVERSION,
-              name='ProductVersion', parent=self, pos=wx.Point(0, 0),
+        self.Organization = wx.TextCtrl(id=ID_PROJECTDIALOGORGANIZATION,
+              name='Organization', parent=self.AuthorPanel, pos=wx.Point(0, 0),
               size=wx.Size(0, 24), style=0)
 
-        self.staticText6 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT6,
-              label='Product Release (optional):', name='staticText6', parent=self,
+        self.MainNotebook.AddPage(self.AuthorPanel, "Author")
+
+        # Graphics Panel elements
+
+        self.GraphicsPanel = wx.Panel(id=ID_PROJECTDIALOGGRAPHICSPANEL,
+              name='GraphicsPanel', parent=self.MainNotebook, pos=wx.Point(0, 0),
+              size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
+
+        self.staticText12 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT12,
+              label='Page Size (optional):', name='staticText12', parent=self.GraphicsPanel,
               pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0)
 
-        self.ProductRelease = wx.TextCtrl(id=ID_PROJECTDIALOGPRODUCTRELEASE,
-              name='ProductRelease', parent=self, pos=wx.Point(0, 0),
+        self.staticText13 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT13,
+              label='Width:', name='staticText13', parent=self.GraphicsPanel,
+              pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0)
+        
+        self.PageWidth = wx.SpinCtrl(id=ID_PROJECTDIALOGPAGEWIDTH,
+              name='PageWidth', parent=self.GraphicsPanel, pos=wx.Point(0, 0),
+              size=wx.Size(0, 24), style=0, min=0, max=2**16)
+
+        self.staticText14 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT14,
+              label='Height:', name='staticText14', parent=self.GraphicsPanel,
+              pos=wx.Point(0, 0), size=wx.Size(150, 17), style=0)
+        
+        self.PageHeight = wx.SpinCtrl(id=ID_PROJECTDIALOGPAGEHEIGHT,
+              name='PageHeight', parent=self.GraphicsPanel, pos=wx.Point(0, 0),
+              size=wx.Size(0, 24), style=0, min=0, max=2**16)
+        
+        self.staticText15 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT15,
+              label='Scaling:', name='staticText15', parent=self.GraphicsPanel,
+              pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0)
+        
+        self.ScalingNotebook = wx.Notebook(id=ID_PROJECTDIALOGSCALINGNOTEBOOK,
+              name='ScalingNotebook', parent=self.GraphicsPanel, pos=wx.Point(0,
+              0), size=wx.Size(0, 0), style=0)
+        
+        self.Scalings = {}
+        for language in ["FBD", "LD", "SFC"]:
+            window = ScalingPanel(self.ScalingNotebook)
+            self.Scalings[language] = window
+            self.ScalingNotebook.AddPage(window, language)
+        
+        self.MainNotebook.AddPage(self.GraphicsPanel, "Graphics")
+
+        # Miscellaneous Panel elements
+
+        self.MiscellaneousPanel = wx.Panel(id=ID_PROJECTDIALOGMISCELLANEOUSPANEL,
+              name='MiscellaneousPanel', parent=self.MainNotebook, pos=wx.Point(0, 0),
+              size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
+
+        self.staticText10 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT10,
+              label='Language (optional):', name='staticText10', parent=self.MiscellaneousPanel,
+              pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0)
+
+        self.Language = wx.Choice(id=ID_PROJECTDIALOGLANGUAGE,
+              name='Language', parent=self.MiscellaneousPanel, pos=wx.Point(0, 0),
               size=wx.Size(0, 24), style=0)
 
-        self.staticText7 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT7,
-              label='Content Description (optional):', name='staticText7', parent=self,
+        self.staticText11 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT11,
+              label='Content Description (optional):', name='staticText11', parent=self.MiscellaneousPanel,
               pos=wx.Point(0, 0), size=wx.Size(200, 17), style=0)
 
         self.ContentDescription = wx.TextCtrl(id=ID_PROJECTDIALOGCONTENTDESCRIPTION,
-              name='ProductRelease', parent=self, pos=wx.Point(0, 0),
-              size=wx.Size(0, 120), style=wx.TE_MULTILINE)
+              name='ContentDescription', parent=self.MiscellaneousPanel, pos=wx.Point(0, 0),
+              size=wx.Size(0, 24), style=wx.TE_MULTILINE)
+
+        self.MainNotebook.AddPage(self.MiscellaneousPanel, "Miscellaneous")
 
         self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
         self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetAffirmativeButton().GetId())
@@ -1869,6 +2107,11 @@
     def __init__(self, parent):
         self._init_ctrls(parent)
         
+        languages = ["", "en-US", "fr-FR"]
+        
+        for language in languages:
+            self.Language.Append(language)
+        
     def OnOK(self, event):
         error = []
         if self.ProjectName.GetValue() == "":
@@ -1887,7 +2130,7 @@
                 elif i == len(error) - 1:
                     text += " and %s"%item
                 else:
-                    text += ", %s"%item 
+                    text += ", %s"%item
             message = wx.MessageDialog(self, "Form isn't complete. %s must be filled!"%text, "Error", wx.OK|wx.ICON_ERROR)
             message.ShowModal()
             message.Destroy()
@@ -1898,31 +2141,58 @@
         for item, value in values.items():
             if item == "projectName":
                 self.ProjectName.SetValue(value)
-            elif item == "companyName":
-                self.CompanyName.SetValue(value)
-            elif item == "companyURL":
-                self.CompanyURL.SetValue(value)
+            elif item == "projectVersion":
+                self.ProjectVersion.SetValue(value)
             elif item == "productName":
                 self.ProductName.SetValue(value)
             elif item == "productVersion":
                 self.ProductVersion.SetValue(value)
             elif item == "productRelease":
                 self.ProductRelease.SetValue(value)
+            elif item == "companyName":
+                self.CompanyName.SetValue(value)
+            elif item == "companyURL":
+                self.CompanyURL.SetValue(value)
+            elif item == "authorName":
+                self.AuthorName.SetValue(value)
+            elif item == "organization":
+                self.Organization.SetValue(value)
+            elif item == "language":
+                self.Language.SetStringSelection(value)
             elif item == "contentDescription":
                 self.ContentDescription.SetValue(value)
-
+            elif item == "pageSize":
+                self.PageWidth.SetValue(value[0])
+                self.PageHeight.SetValue(value[1])
+            elif item == "scaling":
+                for language, (x, y) in value.items():
+                    if language in self.Scalings:
+                        self.Scalings[language].SetScaling(x, y)
+    
     def GetValues(self):
         values = {}
         values["projectName"] = self.ProjectName.GetValue()
-        values["companyName"] = self.CompanyName.GetValue()
-        if self.CompanyURL.GetValue() != None:
-            values["companyURL"] = self.CompanyURL.GetValue()
+        if self.ProjectVersion.GetValue() != "":
+            values["projectVersion"] = self.ProjectVersion.GetValue()
         values["productName"] = self.ProductName.GetValue()
         values["productVersion"] = self.ProductVersion.GetValue()
-        if self.ProductRelease.GetValue() != None:
+        if self.ProductRelease.GetValue() != "":
             values["productRelease"] = self.ProductRelease.GetValue()
-        if self.ProductRelease.GetValue() != None:
+        values["companyName"] = self.CompanyName.GetValue()
+        if self.CompanyURL.GetValue() != "":
+            values["companyURL"] = self.CompanyURL.GetValue()
+        if self.AuthorName.GetValue() != "":
+            values["authorName"] = self.AuthorName.GetValue()
+        if self.Organization.GetValue() != "":
+            values["organization"] = self.Organization.GetValue()
+        if self.Language.GetStringSelection() != "":
+            values["language"] = self.Language.GetStringSelection()
+        if self.ProductRelease.GetValue() != "":
             values["contentDescription"] = self.ContentDescription.GetValue()
+        values["pageSize"] = (self.PageWidth.GetValue(), self.PageHeight.GetValue())
+        values["scaling"] = {}
+        for language in ["FBD", "LD", "SFC"]:
+            values["scaling"][language] = self.Scalings[language].GetScaling()
         return values
 
 #-------------------------------------------------------------------------------
@@ -2572,10 +2842,10 @@
         
         self._init_sizers()
     
-    def __init__(self, parent, controler):
+    def __init__(self, parent, window, controler):
         self._init_ctrls(parent)
         
-        self.ParentWindow = parent
+        self.ParentWindow = window
         self.Controler = controler
         
         self.VariablePanelList = {}
@@ -2605,7 +2875,7 @@
         self.CurrentPanel = None
     
     def UpdateVariablePanelTagName(self, old_tagname, new_tagname):
-        if old_name in self.VariablePanelList:
+        if old_tagname in self.VariablePanelList:
             self.VariablePanelList[new_tagname] = self.VariablePanelList.pop(old_tagname)
             if self.CurrentPanel == old_tagname:
                 self.CurrentPanel = new_tagname
--- a/RessourceEditor.py	Fri Jan 04 17:49:17 2008 +0100
+++ b/RessourceEditor.py	Fri Jan 11 17:51:56 2008 +0100
@@ -96,6 +96,9 @@
     def RefreshView(self):
         pass
 
+    def RefreshScaling(self, refresh=True):
+        pass
+
 #-------------------------------------------------------------------------------
 #                            Resource Editor class
 #-------------------------------------------------------------------------------
@@ -506,9 +509,13 @@
         self.InstancesTable.ResetView(self.InstancesGrid)
         self.TasksTable.ResetView(self.TasksGrid)
 
+    def RefreshScaling(self, refresh=True):
+        pass
+
     def OnAddTaskButton(self, event):
         self.TasksTable.AppendRow(self.TasksDefaultValue.copy())
         self.RefreshModel()
+        self.RefreshView()
         event.Skip()
 
     def OnDeleteTaskButton(self, event):
--- a/SFCViewer.py	Fri Jan 04 17:49:17 2008 +0100
+++ b/SFCViewer.py	Fri Jan 11 17:51:56 2008 +0100
@@ -222,17 +222,6 @@
         elif self.Mode == MODE_COMMENT:
             self.rubberBand.Reset()
             self.rubberBand.OnLeftDown(event, self.GetLogicalDC(), self.Scaling)
-        elif self.Mode == MODE_WIRE:
-            pos = GetScaledEventPosition(event, self.GetLogicalDC(), self.Scaling)
-            wire = Wire(self, [wx.Point(pos.x, pos.y), SOUTH], [wx.Point(pos.x, pos.y), NORTH])
-            wire.oldPos = pos
-            wire.Handle = (HANDLE_POINT, 0)
-            wire.ProcessDragging(0, 0)
-            wire.Handle = (HANDLE_POINT, 1)
-            self.AddWire(wire)
-            if self.SelectedElement:
-                self.SelectedElement.SetSelected(False)
-            self.SelectedElement = wire
         event.Skip()
 
     def OnViewerLeftUp(self, event):
--- a/TextViewer.py	Fri Jan 04 17:49:17 2008 +0100
+++ b/TextViewer.py	Fri Jan 11 17:51:56 2008 +0100
@@ -295,6 +295,9 @@
         
         self.Colourise(0, -1)
     
+    def RefreshScaling(self, refresh=True):
+        pass
+    
     def OnStyleNeeded(self, event):
         self.TextChanged = True
         line = self.LineFromPosition(self.GetEndStyled())
--- a/Viewer.py	Fri Jan 04 17:49:17 2008 +0100
+++ b/Viewer.py	Fri Jan 11 17:51:56 2008 +0100
@@ -68,6 +68,7 @@
     
     def OnDropText(self, x, y, data):
         x, y = self.ParentWindow.CalcUnscrolledPosition(x, y)
+        scaling = self.ParentWindow.Scaling
         values = eval(data)
         if values[1] == "program":
             message = wx.MessageDialog(self.ParentWindow, "Programs can't be used by other POUs!", "Error", wx.OK|wx.ICON_ERROR)
@@ -96,15 +97,20 @@
                     dialog.Destroy()
                 id = self.ParentWindow.GetNewId()
                 block = FBD_Block(self.ParentWindow, values[0], blockname, id)
+                width, height = block.GetMinSize()
+                if scaling is not None:
+                    x = round(float(x) / float(scaling[0])) * scaling[0]
+                    y = round(float(y) / float(scaling[1])) * scaling[1]
+                    width = round(float(width) / float(scaling[0]) + 0.5) * scaling[0]
+                    height = round(float(height) / float(scaling[1]) + 0.5) * scaling[1]
                 block.SetPosition(x, y)
-                width, height = block.GetMinSize()
                 block.SetSize(width, height)
                 self.ParentWindow.AddBlock(block)
                 self.ParentWindow.Controler.AddEditedElementBlock(self.ParentWindow.GetTagName(), id, values[0], blockname)
                 self.ParentWindow.RefreshBlockModel(block)
                 self.ParentWindow.RefreshBuffer()
                 self.ParentWindow.RefreshScrollBars()
-                self.ParentWindow.ParentWindow.RefreshVariablePanel(self.TagName)
+                self.ParentWindow.ParentWindow.RefreshVariablePanel(self.ParentWindow.GetTagName())
                 self.ParentWindow.Refresh()
         elif values[1] != "location":
             if values[3] == self.ParentWindow.GetTagName():
@@ -116,11 +122,16 @@
                 else:
                     var_type = INPUT
                 variable = FBD_Variable(self.ParentWindow, var_type, values[0], values[2], id)
+                width, height = variable.GetMinSize()
+                if scaling is not None:
+                    x = round(float(x) / float(scaling[0])) * scaling[0]
+                    y = round(float(y) / float(scaling[1])) * scaling[1]
+                    width = round(float(width) / float(scaling[0]) + 0.5) * scaling[0]
+                    height = round(float(height) / float(scaling[1]) + 0.5) * scaling[1]
                 variable.SetPosition(x, y)
-                width, height = variable.GetMinSize()
                 variable.SetSize(width, height)
                 self.ParentWindow.AddBlock(variable)
-                self.ParentWindow.Controler.AddEditedElementVariable(self.ParentWindow.TagName, id, var_type)
+                self.ParentWindow.Controler.AddEditedElementVariable(self.ParentWindow.GetTagName(), id, var_type)
                 self.ParentWindow.RefreshVariableModel(variable)
                 self.ParentWindow.RefreshBuffer()
                 self.ParentWindow.RefreshScrollBars()
@@ -269,8 +280,8 @@
         self.SetBackgroundColour(wx.Colour(255,255,255))
         self.ResetView()
         self.Scaling = None
-        #self.Scaling = (8, 8)
         self.DrawGrid = True
+        self.GridBrush = wx.TRANSPARENT_BRUSH
         self.DrawingWire = False
         self.current_id = 0
         self.TagName = tagname
@@ -293,6 +304,7 @@
         self.Bind(wx.EVT_LEFT_DOWN, self.OnViewerLeftDown)
         self.Bind(wx.EVT_LEFT_UP, self.OnViewerLeftUp)
         self.Bind(wx.EVT_LEFT_DCLICK, self.OnViewerLeftDClick)
+        self.Bind(wx.EVT_RIGHT_DOWN, self.OnViewerRightDown)
         self.Bind(wx.EVT_RIGHT_UP, self.OnViewerRightUp)
         self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveViewer)
         self.Bind(wx.EVT_MOTION, self.OnViewerMotion)
@@ -304,6 +316,9 @@
         rect.x, rect.y = self.CalcScrolledPosition(rect.x, rect.y)
         return rect
     
+    def GetScaling(self):
+        return self.Scaling
+    
     def SetTagName(self, tagname):
         self.TagName = tagname
         
@@ -423,6 +438,29 @@
         self.ParentWindow.RefreshTitle()
         self.ParentWindow.RefreshEditMenu()
 
+    # Refresh the current scaling
+    def RefreshScaling(self, refresh=True):
+        properties = self.Controler.GetProjectProperties()
+        scaling = properties["scaling"][self.CurrentLanguage]
+        if scaling != (0, 0):
+            self.Scaling = scaling
+            if self.DrawGrid:
+                bitmap = wx.EmptyBitmap(*scaling)
+                dc = wx.MemoryDC(bitmap)
+                dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
+                dc.Clear()
+                dc.SetPen(wx.Pen(wx.Colour(180, 180, 180)))
+                dc.DrawPoint(0, 0)
+                self.GridBrush = wx.BrushFromBitmap(bitmap)
+            else:
+                self.GridBrush = wx.TRANSPARENT_BRUSH
+        else:
+            self.Scaling = None
+            self.GridBrush = wx.TRANSPARENT_BRUSH
+        if refresh:
+            self.Refresh()
+        
+        
 #-------------------------------------------------------------------------------
 #                          Refresh functions
 #-------------------------------------------------------------------------------
@@ -571,6 +609,7 @@
                 contact_type = CONTACT_NORMAL
             contact = LD_Contact(self, contact_type, instance["name"], instance["id"])
             contact.SetPosition(instance["x"], instance["y"])
+            contact.SetSize(instance["width"], instance["height"])
             self.AddBlock(contact)
             connectors = contact.GetConnectors()
             connectors["input"].SetPosition(wx.Point(*instance["connectors"]["input"]["position"]))
@@ -595,6 +634,7 @@
                 coil_type = COIL_NORMAL
             coil = LD_Coil(self, coil_type, instance["name"], instance["id"])
             coil.SetPosition(instance["x"], instance["y"])
+            coil.SetSize(instance["width"], instance["height"])
             self.AddBlock(coil)
             connectors = coil.GetConnectors()
             connectors["input"].SetPosition(wx.Point(*instance["connectors"]["input"]["position"]))
@@ -624,6 +664,7 @@
         elif instance["type"] == "transition":
             transition = SFC_Transition(self, instance["condition_type"], instance["condition"], instance["priority"], instance["id"])
             transition.SetPosition(instance["x"], instance["y"])
+            transition.SetSize(instance["width"], instance["height"])
             self.AddBlock(transition)
             connectors = transition.GetConnectors()
             connectors["input"].SetPosition(wx.Point(*instance["connectors"]["input"]["position"]))
@@ -658,6 +699,7 @@
         elif instance["type"] == "jump":
             jump = SFC_Jump(self, instance["target"], instance["id"])
             jump.SetPosition(instance["x"], instance["y"])
+            jump.SetSize(instance["width"], instance["height"])
             self.AddBlock(jump)
             connector = jump.GetConnector()
             connector.SetPosition(wx.Point(*instance["connector"]["position"]))
@@ -877,36 +919,42 @@
         if self.SelectedElement and isinstance(self.SelectedElement, Graphic_Group):
             self.SelectedElement.AlignElements(ALIGN_LEFT, None)
             self.RefreshBuffer()
+            self.Refresh()
         event.Skip()
     
     def OnAlignCenterMenu(self, event):
         if self.SelectedElement and isinstance(self.SelectedElement, Graphic_Group):
             self.SelectedElement.AlignElements(ALIGN_CENTER, None)
             self.RefreshBuffer()
+            self.Refresh()
         event.Skip()
     
     def OnAlignRightMenu(self, event):
         if self.SelectedElement and isinstance(self.SelectedElement, Graphic_Group):
             self.SelectedElement.AlignElements(ALIGN_RIGHT, None)
             self.RefreshBuffer()
+            self.Refresh()
         event.Skip()
     
     def OnAlignTopMenu(self, event):
         if self.SelectedElement and isinstance(self.SelectedElement, Graphic_Group):
             self.SelectedElement.AlignElements(None, ALIGN_TOP)
             self.RefreshBuffer()
+            self.Refresh()
         event.Skip()
     
     def OnAlignMiddleMenu(self, event):
         if self.SelectedElement and isinstance(self.SelectedElement, Graphic_Group):
             self.SelectedElement.AlignElements(None, ALIGN_MIDDLE)
             self.RefreshBuffer()
+            self.Refresh()
         event.Skip()
     
     def OnAlignBottomMenu(self, event):
         if self.SelectedElement and isinstance(self.SelectedElement, Graphic_Group):
             self.SelectedElement.AlignElements(None, ALIGN_BOTTOM)
             self.RefreshBuffer()
+            self.Refresh()
         event.Skip()
         
     def OnNoModifierMenu(self, event):
@@ -1004,7 +1052,10 @@
                     self.SelectedElement.SetSelected(True)
             else:
                 element = self.FindElement(pos)
-                connector = self.FindBlockConnector(pos)
+                if element is None or element.TestHandle(pos) == (0, 0):
+                    connector = self.FindBlockConnector(pos)
+                else:
+                    connector = None
                 if self.DrawingWire:
                     self.DrawingWire = False
                     if connector:
@@ -1020,6 +1071,7 @@
                     else:
                         rect = self.SelectedElement.GetRedrawRect()
                         self.SelectedElement.Delete()
+                        self.SelectedElement = None
                         element = None
                         self.RefreshRect(self.GetScrolledRect(rect))
                 elif connector:
@@ -1031,7 +1083,7 @@
                         wire = Wire(self, [wx.Point(pos.x, pos.y), WEST], [wx.Point(pos.x, pos.y), EAST])
                     wire.oldPos = pos
                     wire.Handle = (HANDLE_POINT, 0)
-                    wire.ProcessDragging(0, 0)
+                    wire.ProcessDragging(0, 0, self.Scaling)
                     wire.Handle = (HANDLE_POINT, 1)
                     self.AddWire(wire)
                     if self.SelectedElement:
@@ -1104,10 +1156,17 @@
                 connector = self.FindBlockConnector(pos)
                 if self.SelectedElement.EndConnected is not None:
                     self.DrawingWire = False
+                    self.SelectedElement.StartConnected.HighlightParentBlock(False)
+                    self.SelectedElement.EndConnected.HighlightParentBlock(False)
                     self.SelectedElement.ResetPoints()
                     self.SelectedElement.OnMotion(event, dc, self.Scaling)
                     self.SelectedElement.GeneratePoints()
                     self.SelectedElement.RefreshModel()
+                    if self.HighlightedElement is not None:
+                        self.HighlightedElement.SetHighlighted(False)
+                        self.HighlightedElement = None
+                    self.SelectedElement.SetHighlighted(True)
+                    self.HighlightedElement = self.SelectedElement
                     self.SelectedElement.SetSelected(True)
                     self.RefreshBuffer()
                 elif connector is None or self.SelectedElement.GetDragging():
@@ -1124,17 +1183,26 @@
             wx.CallAfter(self.ParentWindow.ResetCurrentMode)
         event.Skip()
     
+    def OnViewerRightDown(self, event):
+        if self.Mode == MODE_SELECTION:
+            dc = self.GetLogicalDC()
+            pos = event.GetLogicalPosition(dc)
+            element = self.FindElement(pos)
+            if self.SelectedElement and self.SelectedElement != element:
+                self.SelectedElement.SetSelected(False)
+                self.SelectedElement = None
+            if element:
+                self.SelectedElement = element
+                self.SelectedElement.OnRightDown(event, dc, self.Scaling)
+                self.SelectedElement.Refresh()
+        event.Skip()
+    
     def OnViewerRightUp(self, event):
         dc = self.GetLogicalDC()
-        pos = event.GetLogicalPosition(dc)
-        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)
+        if self.SelectedElement:
+            self.SelectedElement.OnRightUp(event, dc, self.Scaling)
             wx.CallAfter(self.SetCursor, wx.NullCursor)
+            self.SelectedElement.Refresh()
         else:
             self.PopupDefaultMenu(False)
         event.Skip()
@@ -1154,7 +1222,6 @@
         if not event.Dragging():
             highlighted = self.FindElement(pos) 
             if self.HighlightedElement is not None and self.HighlightedElement != highlighted:
-                rect = self.HighlightedElement.GetRedrawRect()
                 self.HighlightedElement.SetHighlighted(False)
                 self.HighlightedElement = None
             if highlighted is not None and self.HighlightedElement != highlighted:
@@ -1284,6 +1351,12 @@
 #                          Model adding functions
 #-------------------------------------------------------------------------------
 
+    def GetScaledSize(self, width, height):
+        if self.Scaling is not None:
+            width = round(float(width) / float(self.Scaling[0]) + 0.4) * self.Scaling[0]
+            height = round(float(height) / float(self.Scaling[1]) + 0.4) * self.Scaling[1]
+        return width, height
+
     def AddNewBlock(self, bbox):
         dialog = BlockPropertiesDialog(self.ParentWindow)
         dialog.SetBlockList(self.Controler.GetBlockTypes(self.TagName))
@@ -1298,7 +1371,7 @@
             else:
                 block = FBD_Block(self, values["type"], "", id, values["extension"], values["inputs"])
             block.SetPosition(bbox.x, bbox.y)
-            block.SetSize(values["width"], values["height"])
+            block.SetSize(*self.GetScaledSize(values["width"], values["height"]))
             self.AddBlock(block)
             self.Controler.AddEditedElementBlock(self.TagName, id, values["type"], values.get("name", None))
             self.RefreshBlockModel(block)
@@ -1326,7 +1399,7 @@
             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"])
+            variable.SetSize(*self.GetScaledSize(values["width"], values["height"]))
             self.AddBlock(variable)
             self.Controler.AddEditedElementVariable(self.TagName, id, values["type"])
             self.RefreshVariableModel(variable)
@@ -1343,7 +1416,7 @@
             values = dialog.GetValues()
             connection = FBD_Connector(self, values["type"], values["name"], id)
             connection.SetPosition(bbox.x, bbox.y)
-            connection.SetSize(values["width"], values["height"])
+            connection.SetSize(*self.GetScaledSize(values["width"], values["height"]))
             self.AddBlock(connection)
             self.Controler.AddEditedElementConnection(self.TagName, id, values["type"])
             self.RefreshConnectionModel(connection)
@@ -1363,7 +1436,7 @@
             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))
+            comment.SetSize(*self.GetScaledSize(max(min_width,bbox.width),max(min_height,bbox.height)))
             self.AddComment(comment)
             self.Controler.AddEditedElementComment(self.TagName, id)
             self.RefreshCommentModel(comment)
@@ -1388,7 +1461,7 @@
             values = dialog.GetValues()
             contact = LD_Contact(self, values["type"], values["name"], id)
             contact.SetPosition(bbox.x, bbox.y)
-            contact.SetSize(values["width"], values["height"])
+            contact.SetSize(*self.GetScaledSize(values["width"], values["height"]))
             self.AddBlock(contact)
             self.Controler.AddEditedElementContact(self.TagName, id)
             self.RefreshContactModel(contact)
@@ -1416,7 +1489,7 @@
             values = dialog.GetValues()
             coil = LD_Coil(self, values["type"], values["name"], id)
             coil.SetPosition(bbox.x, bbox.y)
-            coil.SetSize(values["width"], values["height"])
+            coil.SetSize(*self.GetScaledSize(values["width"], values["height"]))
             self.AddBlock(coil)
             self.Controler.AddEditedElementCoil(self.TagName, id)
             self.RefreshCoilModel(coil)
@@ -1433,7 +1506,7 @@
             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"])
+            powerrail.SetSize(*self.GetScaledSize(values["width"], values["height"]))
             self.AddBlock(powerrail)
             self.Controler.AddEditedElementPowerRail(self.TagName, id, values["type"])
             self.RefreshPowerRailModel(powerrail)
@@ -1466,7 +1539,7 @@
                 step.RemoveAction()
             step.SetPosition(bbox.x, bbox.y)
             min_width, min_height = step.GetMinSize()
-            step.SetSize(max(bbox.width, min_width), max(bbox.height, min_height))
+            step.SetSize(*self.GetScaledSize(max(bbox.width, min_width), max(bbox.height, min_height)))
             self.AddBlock(step)
             self.Controler.AddEditedElementStep(self.TagName, id)
             self.RefreshStepModel(step)
@@ -1484,7 +1557,7 @@
             transition = SFC_Transition(self, values["type"], values["value"], values["priority"], 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))
+            transition.SetSize(*self.GetScaledSize(max(bbox.width, min_width), max(bbox.height, min_height)))
             self.AddBlock(transition)
             self.Controler.AddEditedElementTransition(self.TagName, id)
             self.RefreshTransitionModel(transition)
@@ -1502,7 +1575,7 @@
             divergence = SFC_Divergence(self, values["type"], values["number"], id)
             divergence.SetPosition(bbox.x, bbox.y)
             min_width, min_height = divergence.GetMinSize(True)
-            divergence.SetSize(max(bbox.width, min_width), max(bbox.height, min_height))
+            divergence.SetSize(*self.GetScaledSize(max(bbox.width, min_width), max(bbox.height, min_height)))
             self.AddBlock(divergence)
             self.Controler.AddEditedElementDivergence(self.TagName, id, values["type"])
             self.RefreshDivergenceModel(divergence)
@@ -1523,7 +1596,7 @@
             jump = SFC_Jump(self, value, id)
             jump.SetPosition(bbox.x, bbox.y)
             min_width, min_height = jump.GetMinSize()
-            jump.SetSize(max(bbox.width, min_width), max(bbox.height, min_height))
+            jump.SetSize(*self.GetScaledSize(max(bbox.width, min_width), max(bbox.height, min_height)))
             self.AddBlock(jump)
             self.Controler.AddEditedElementJump(self.TagName, id)
             self.RefreshJumpModel(jump)
@@ -1543,7 +1616,7 @@
             actionblock = SFC_ActionBlock(self, actions, id)
             actionblock.SetPosition(bbox.x, bbox.y)
             min_width, min_height = actionblock.GetMinSize()
-            actionblock.SetSize(max(bbox.width, min_width), max(bbox.height, min_height))
+            actionblock.SetSize(*self.GetScaledSize(max(bbox.width, min_width), max(bbox.height, min_height)))
             self.AddBlock(actionblock)
             self.Controler.AddEditedElementActionBlock(self.TagName, id)
             self.RefreshActionBlockModel(actionblock)
@@ -1572,7 +1645,7 @@
             new_values = dialog.GetValues()
             if "name" in new_values:
                 block.SetName(new_values["name"])
-            block.SetSize(new_values["width"], new_values["height"])
+            block.SetSize(*self.GetScaledSize(new_values["width"], new_values["height"]))
             block.SetType(new_values["type"], new_values["extension"])
             block.SetExecutionOrder(new_values["executionOrder"])
             self.RefreshBlockModel(block)
@@ -1604,7 +1677,7 @@
             new_values = dialog.GetValues()
             variable.SetName(new_values["name"])
             variable.SetType(new_values["type"], new_values["value_type"])
-            variable.SetSize(new_values["width"], new_values["height"])
+            variable.SetSize(*self.GetScaledSize(new_values["width"], new_values["height"]))
             variable.SetExecutionOrder(new_values["executionOrder"])
             if old_values["type"] != new_values["type"]:
                 id = variable.GetId()
@@ -1628,7 +1701,7 @@
             values = dialog.GetValues()
             connection.SetName(values["name"])
             connection.SetType(values["type"])
-            connection.SetSize(values["width"], values["height"])
+            connection.SetSize(*self.GetScaledSize(values["width"], values["height"]))
             if old_type != values["type"]:
                 id = connection.GetId()
                 self.Controler.RemoveEditedElementInstance(self.TagName, id)
@@ -1655,7 +1728,7 @@
             values = dialog.GetValues()
             contact.SetName(values["name"])
             contact.SetType(values["type"])
-            contact.SetSize(values["width"], values["height"])
+            contact.SetSize(*self.GetScaledSize(values["width"], values["height"]))
             self.RefreshContactModel(contact)
             self.RefreshBuffer()
             self.RefreshScrollBars()
@@ -1681,7 +1754,7 @@
             values = dialog.GetValues()
             coil.SetName(values["name"])
             coil.SetType(values["type"])
-            coil.SetSize(values["width"], values["height"])
+            coil.SetSize(*self.GetScaledSize(values["width"], values["height"]))
             self.RefreshCoilModel(coil)
             self.RefreshBuffer()
             self.RefreshScrollBars()
@@ -1695,7 +1768,7 @@
             old_type = powerrail.GetType()
             values = dialog.GetValues()
             powerrail.SetType(values["type"], [True for i in xrange(values["number"])])
-            powerrail.SetSize(values["width"], values["height"])
+            powerrail.SetSize(*self.GetScaledSize(values["width"], values["height"]))
             if old_type != values["type"]:
                 id = powerrail.GetId()
                 self.Controler.RemoveEditedElementInstance(self.TagName, id)
@@ -1733,7 +1806,7 @@
                 step.AddAction()    
             else:
                 step.RemoveAction()
-            step.UpdateSize(values["width"], values["height"])
+            step.UpdateSize(*self.GetScaledSize(values["width"], values["height"]))
             step.RefreshModel()
             self.RefreshBuffer()
             self.RefreshScrollBars()
@@ -1779,6 +1852,7 @@
         if dialog.ShowModal() == wx.ID_OK:
             actions = dialog.GetValues()
             actionblock.SetActions(actions)
+            actionblock.SetSize(*self.GetScaledSize(*actionblock.GetSize()))
             actionblock.RefreshModel()
             self.RefreshBuffer()
             self.RefreshScrollBars()
@@ -1793,6 +1867,7 @@
         if dialog.ShowModal() == wx.ID_OK:
             value = dialog.GetValue()
             comment.SetContent(value)
+            comment.SetSize(*self.GetScaledSize(*comment.GetSize()))
             comment.RefreshModel()
             self.RefreshBuffer()
             self.RefreshScrollBars()
@@ -1808,7 +1883,8 @@
         infos = {}
         infos["type"] = block.GetType()
         infos["name"] = block.GetName()
-        infos["executionOrder"] = block.GetExecutionOrder()
+        if self.CurrentLanguage == "FBD":
+            infos["executionOrder"] = block.GetExecutionOrder()
         infos["x"], infos["y"] = block.GetPosition()
         infos["width"], infos["height"] = block.GetSize()
         infos["connectors"] = block.GetConnectors()
@@ -1818,7 +1894,8 @@
         variableid = variable.GetId()
         infos = {}
         infos["name"] = variable.GetName()
-        infos["executionOrder"] = variable.GetExecutionOrder()
+        if self.CurrentLanguage == "FBD":
+            infos["executionOrder"] = variable.GetExecutionOrder()
         infos["x"], infos["y"] = variable.GetPosition()
         infos["width"], infos["height"] = variable.GetSize()
         infos["connectors"] = variable.GetConnectors()
@@ -1828,7 +1905,6 @@
         connectionid = connection.GetId()
         infos = {}
         infos["name"] = connection.GetName()
-        infos["executionOrder"] = connection.GetExecutionOrder()
         infos["x"], infos["y"] = connection.GetPosition()
         infos["width"], infos["height"] = connection.GetSize()
         infos["connector"] = connection.GetConnector()
@@ -2163,15 +2239,14 @@
 
     def OnPaint(self, event):
         dc = self.GetLogicalDC(True)
+        dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
         dc.Clear()
-        dc.SetPen(wx.Pen(wx.Colour(230, 230, 230)))
         dc.BeginDrawing()
         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])
+            dc.SetPen(wx.TRANSPARENT_PEN)
+            dc.SetBrush(self.GridBrush)
+            width, height = self.GetVirtualSize()
+            dc.DrawRectangle(0, 0, width, height)
         
         # Draw all elements
         for comment in self.Comments:
--- a/examples/example.xml	Fri Jan 04 17:49:17 2008 +0100
+++ b/examples/example.xml	Fri Jan 11 17:51:56 2008 +0100
@@ -3,14 +3,22 @@
          xmlns="http://www.plcopen.org/xml/tc6.xsd"
          xmlns:xhtml="http://www.w3.org/1999/xhtml"
          xsi:schemaLocation="http://www.plcopen.org/xml/tc6.xsd http://www.plcopen.org/xml/tc6.xsd">
-  <fileHeader companyName="Lolitech"
+  <fileHeader contentDescription="Example of PLCOpenEditor usage"
+              companyName="Lolitech"
+              companyURL="www.lolitech.net"
               productName="PLCOpenEditorExample"
+              productRelease="rc1"
               productVersion="1.0"
               creationDateTime="2006-09-07 18:52:43"/>
-  <contentHeader name="Test">
+  <contentHeader name="Test"
+                 language="en-US"
+                 author="Laurent Bessard"
+                 modificationDateTime="2008-01-10 17:33:58"
+                 version="1">
     <coordinateInfo>
+      <pageSize y="2000" x="1000"/>
       <fbd>
-        <scaling y="0" x="0"/>
+        <scaling y="8" x="8"/>
       </fbd>
       <ld>
         <scaling y="0" x="0"/>
@@ -34,17 +42,25 @@
         </baseType>
         <initialValue>
           <arrayValue>
-            <value>
-              <simpleValue value="8([-100"/>
+            <value repetitionValue="8">
+              <arrayValue>
+                <value>
+                  <simpleValue value="-100"/>
+                </value>
+                <value>
+                  <simpleValue value="100"/>
+                </value>
+              </arrayValue>
             </value>
-            <value>
-              <simpleValue value="100])"/>
-            </value>
-            <value>
-              <simpleValue value="8([100"/>
-            </value>
-            <value>
-              <simpleValue value="-100])"/>
+            <value repetitionValue="8">
+              <arrayValue>
+                <value>
+                  <simpleValue value="100"/>
+                </value>
+                <value>
+                  <simpleValue value="-100"/>
+                </value>
+              </arrayValue>
             </value>
           </arrayValue>
         </initialValue>
@@ -127,53 +143,53 @@
         </interface>
         <body>
           <FBD>
-            <inVariable localId="2" width="89" height="27">
-              <position y="84" x="64"/>
-              <connectionPointOut>
-                <relPosition y="13" x="89"/>
+            <inVariable localId="2" width="88" height="32" executionOrderId="0">
+              <position y="80" x="64"/>
+              <connectionPointOut>
+                <relPosition y="16" x="88"/>
               </connectionPointOut>
               <expression>IN1</expression>
             </inVariable>
-            <inVariable localId="3" width="90" height="27">
-              <position y="204" x="63"/>
-              <connectionPointOut>
-                <relPosition y="13" x="90"/>
+            <inVariable localId="3" width="88" height="32" executionOrderId="0">
+              <position y="200" x="64"/>
+              <connectionPointOut>
+                <relPosition y="16" x="88"/>
               </connectionPointOut>
               <expression>IN2</expression>
             </inVariable>
-            <outVariable localId="4" width="95" height="33" executionOrderId="2">
-              <position y="182" x="587"/>
+            <outVariable localId="4" width="96" height="32" executionOrderId="2">
+              <position y="176" x="584"/>
               <connectionPointIn>
                 <relPosition y="16" x="0"/>
                 <connection refLocalId="11" formalParameter="Q1">
-                  <position y="198" x="587"/>
-                  <position y="198" x="523"/>
+                  <position y="192" x="584"/>
+                  <position y="192" x="528"/>
                 </connection>
               </connectionPointIn>
               <expression>OUT</expression>
             </outVariable>
-            <block localId="6" height="84" width="99" executionOrderId="3" typeName="AND">
-              <position y="105" x="235"/>
+            <block localId="6" height="88" width="104" executionOrderId="3" instanceName="" typeName="AND">
+              <position y="104" x="232"/>
               <inputVariables>
                 <variable formalParameter="IN1" edge="rising">
                   <connectionPointIn>
-                    <relPosition y="36" x="0"/>
+                    <relPosition y="40" x="0"/>
                     <connection refLocalId="2">
-                      <position y="141" x="235"/>
-                      <position y="141" x="190"/>
-                      <position y="97" x="190"/>
-                      <position y="97" x="153"/>
+                      <position y="144" x="232"/>
+                      <position y="144" x="192"/>
+                      <position y="96" x="192"/>
+                      <position y="96" x="152"/>
                     </connection>
                   </connectionPointIn>
                 </variable>
                 <variable formalParameter="IN2">
                   <connectionPointIn>
-                    <relPosition y="68" x="0"/>
+                    <relPosition y="72" x="0"/>
                     <connection refLocalId="3">
-                      <position y="173" x="235"/>
-                      <position y="173" x="190"/>
-                      <position y="217" x="190"/>
-                      <position y="217" x="153"/>
+                      <position y="176" x="232"/>
+                      <position y="176" x="192"/>
+                      <position y="216" x="192"/>
+                      <position y="216" x="152"/>
                     </connection>
                   </connectionPointIn>
                 </variable>
@@ -182,40 +198,40 @@
               <outputVariables>
                 <variable formalParameter="OUT">
                   <connectionPointOut>
-                    <relPosition y="36" x="99"/>
+                    <relPosition y="40" x="104"/>
                   </connectionPointOut>
                 </variable>
               </outputVariables>
             </block>
-            <inVariable localId="7" width="90" height="28">
-              <position y="336" x="63"/>
-              <connectionPointOut>
-                <relPosition y="14" x="90"/>
+            <inVariable localId="7" width="88" height="32" executionOrderId="0">
+              <position y="336" x="64"/>
+              <connectionPointOut>
+                <relPosition y="16" x="88"/>
               </connectionPointOut>
               <expression>IN3</expression>
             </inVariable>
-            <block localId="8" height="87" width="99" executionOrderId="4" instanceName="" typeName="OR">
-              <position y="246" x="235"/>
+            <block localId="8" height="88" width="104" executionOrderId="4" instanceName="" typeName="OR">
+              <position y="240" x="232"/>
               <inputVariables>
                 <variable formalParameter="IN1" negated="true">
                   <connectionPointIn>
-                    <relPosition y="36" x="0"/>
+                    <relPosition y="40" x="0"/>
                     <connection refLocalId="3">
-                      <position y="282" x="235"/>
-                      <position y="282" x="190"/>
-                      <position y="217" x="190"/>
-                      <position y="217" x="153"/>
+                      <position y="280" x="232"/>
+                      <position y="280" x="192"/>
+                      <position y="216" x="192"/>
+                      <position y="216" x="152"/>
                     </connection>
                   </connectionPointIn>
                 </variable>
                 <variable formalParameter="IN2">
                   <connectionPointIn>
-                    <relPosition y="69" x="0"/>
+                    <relPosition y="72" x="0"/>
                     <connection refLocalId="7">
-                      <position y="315" x="235"/>
-                      <position y="315" x="191"/>
-                      <position y="350" x="191"/>
-                      <position y="350" x="153"/>
+                      <position y="312" x="232"/>
+                      <position y="312" x="192"/>
+                      <position y="352" x="192"/>
+                      <position y="352" x="152"/>
                     </connection>
                   </connectionPointIn>
                 </variable>
@@ -224,37 +240,37 @@
               <outputVariables>
                 <variable formalParameter="OUT">
                   <connectionPointOut>
-                    <relPosition y="36" x="99"/>
+                    <relPosition y="40" x="104"/>
                   </connectionPointOut>
                 </variable>
               </outputVariables>
             </block>
-            <comment localId="10" height="37" width="261">
-              <position y="32" x="243"/>
+            <comment localId="10" height="40" width="272">
+              <position y="24" x="240"/>
               <content><![CDATA[POU used for testing PLCOpenEditor.]]></content>
             </comment>
-            <block localId="11" height="97" width="105" executionOrderId="1" instanceName="SR1" typeName="SR">
-              <position y="159" x="418"/>
+            <block localId="11" height="96" width="104" executionOrderId="1" instanceName="SR1" typeName="SR">
+              <position y="152" x="424"/>
               <inputVariables>
                 <variable formalParameter="S1" negated="true">
                   <connectionPointIn>
-                    <relPosition y="39" x="0"/>
+                    <relPosition y="40" x="0"/>
                     <connection refLocalId="6" formalParameter="OUT">
-                      <position y="198" x="418"/>
-                      <position y="198" x="376"/>
-                      <position y="141" x="376"/>
-                      <position y="141" x="334"/>
+                      <position y="192" x="424"/>
+                      <position y="192" x="376"/>
+                      <position y="144" x="376"/>
+                      <position y="144" x="336"/>
                     </connection>
                   </connectionPointIn>
                 </variable>
                 <variable formalParameter="R">
                   <connectionPointIn>
-                    <relPosition y="77" x="0"/>
+                    <relPosition y="80" x="0"/>
                     <connection refLocalId="8" formalParameter="OUT">
-                      <position y="236" x="418"/>
-                      <position y="236" x="376"/>
-                      <position y="282" x="376"/>
-                      <position y="282" x="334"/>
+                      <position y="232" x="424"/>
+                      <position y="232" x="376"/>
+                      <position y="280" x="376"/>
+                      <position y="280" x="336"/>
                     </connection>
                   </connectionPointIn>
                 </variable>
@@ -263,7 +279,7 @@
               <outputVariables>
                 <variable formalParameter="Q1">
                   <connectionPointOut>
-                    <relPosition y="39" x="105"/>
+                    <relPosition y="40" x="104"/>
                   </connectionPointOut>
                 </variable>
               </outputVariables>
--- a/graphics/FBD_Objects.py	Fri Jan 04 17:49:17 2008 +0100
+++ b/graphics/FBD_Objects.py	Fri Jan 11 17:51:56 2008 +0100
@@ -123,19 +123,22 @@
     
     # Refresh the positions of the block connectors
     def RefreshConnectors(self):
+        scaling = self.Parent.GetScaling()
         # Calculate the size for the connector lines
         lines = max(len(self.Inputs), len(self.Outputs))
         if lines > 0:
             linesize = max((self.Size[1] - BLOCK_LINE_SIZE) / lines, BLOCK_LINE_SIZE)
-            # Update inputs positions
+            # Update inputs and outputs positions
             position = BLOCK_LINE_SIZE + linesize / 2
-            for input in self.Inputs:
-                input.SetPosition(wx.Point(0, position))
-                position += linesize
-            # Update outputs positions
-            position = BLOCK_LINE_SIZE + linesize / 2
-            for output in self.Outputs:
-                output.SetPosition(wx.Point(self.Size[0], position))
+            for i in xrange(lines):
+                if scaling is not None:
+                    ypos = round(float(self.Pos.y + position) / float(scaling[1])) * scaling[1] - self.Pos.y
+                else:
+                    ypos = position
+                if i < len(self.Inputs):
+                    self.Inputs[i].SetPosition(wx.Point(0, ypos))
+                if i < len(self.Outputs):
+                    self.Outputs[i].SetPosition(wx.Point(self.Size[0], ypos))
                 position += linesize
         self.RefreshConnected()
     
@@ -192,7 +195,7 @@
                     resulttype = outputtype
         return resulttype
     
-    # Returns all the block connectors 
+    # Returns all the block connectors
     def GetConnectors(self):
         return {"inputs" : self.Inputs, "outputs" : self.Outputs}
     
@@ -464,10 +467,15 @@
     
     # Refresh the position of the variable connector
     def RefreshConnectors(self):
+        scaling = self.Parent.GetScaling()
+        if scaling is not None:
+            position = round(float(self.Pos.y + self.Size[1] / 2) / float(scaling[1])) * scaling[1] - self.Pos.y
+        else:
+            position = self.Size[1] / 2
         if self.Input:
-            self.Input.SetPosition(wx.Point(0, self.Size[1] / 2))
+            self.Input.SetPosition(wx.Point(0, position))
         if self.Output:
-            self.Output.SetPosition(wx.Point(self.Size[0], self.Size[1] / 2))
+            self.Output.SetPosition(wx.Point(self.Size[0], position))
         self.RefreshConnected()
     
     # Refresh the position of wires connected to connector
@@ -674,10 +682,15 @@
     
     # Refresh the position of the connection connector
     def RefreshConnectors(self):
+        scaling = self.Parent.GetScaling()
+        if scaling is not None:
+            position = round(float(self.Pos.y + self.Size[1] / 2) / float(scaling[1])) * scaling[1] - self.Pos.y
+        else:
+            position = self.Size[1] / 2
         if self.Type == CONNECTOR:
-            self.Connector.SetPosition(wx.Point(0, self.Size[1] / 2))
-        else:
-            self.Connector.SetPosition(wx.Point(self.Size[0], self.Size[1] / 2))
+            self.Connector.SetPosition(wx.Point(0, position))
+        else:
+            self.Connector.SetPosition(wx.Point(self.Size[0], position))
         self.RefreshConnected()
     
     # Refresh the position of wires connected to connector
@@ -711,6 +724,9 @@
     def GetType(self):
         return self.Type
     
+    def GetConnectionResultType(self, connector, connectortype):
+        return connectortype
+    
     # Changes the connection name
     def SetName(self, name):
         self.Name = name
--- a/graphics/GraphicCommons.py	Fri Jan 04 17:49:17 2008 +0100
+++ b/graphics/GraphicCommons.py	Fri Jan 11 17:51:56 2008 +0100
@@ -379,7 +379,10 @@
         return rect
     
     def Refresh(self, rect = None):
-        self.Parent.RefreshRect(self.Parent.GetScrolledRect(self.GetRedrawRect()))
+        if rect is not None:
+            self.Parent.RefreshRect(self.Parent.GetScrolledRect(rect))
+        else:
+            self.Parent.RefreshRect(self.Parent.GetScrolledRect(self.GetRedrawRect()))
     
     # Change the variable that indicates if this element is selected
     def SetSelected(self, selected):
@@ -445,11 +448,6 @@
     def OnLeftUp(self, event, dc, scaling):
         # If a dragging have been initiated
         if self.Dragging and self.oldPos:
-            # Calculate the movement of cursor and refreshes the element state
-            pos = GetScaledEventPosition(event, dc, scaling)
-            movex = pos.x - self.oldPos.x
-            movey = pos.y - self.oldPos.y
-            self.ProcessDragging(movex, movey)
             self.RefreshModel()
             self.Parent.RefreshBuffer()
         if self.CurrentCursor != 0:
@@ -458,8 +456,18 @@
         self.SetSelected(True)
         self.oldPos = None
 
+    # Method called when a RightDown event have been generated
+    def OnRightDown(self, event, dc, scaling):
+        pass
+
     # Method called when a RightUp event have been generated
     def OnRightUp(self, event, dc, scaling):
+        if self.Dragging and self.oldPos:
+            self.RefreshModel()
+            self.Parent.RefreshBuffer()
+        if self.CurrentCursor != 0:
+            self.Parent.SetCursor(CURSORS[0])
+            self.CurrentCursor = 0
         self.SetSelected(True)
         self.oldPos = None
 
@@ -472,7 +480,7 @@
         # If the cursor is dragging and the element have been clicked
         if event.Dragging() and self.oldPos:
             # Calculate the movement of cursor
-            pos = GetScaledEventPosition(event, dc, scaling)
+            pos = event.GetLogicalPosition(dc)
             movex = pos.x - self.oldPos.x
             movey = pos.y - self.oldPos.y
             # If movement is greater than MIN_MOVE then a dragging is initiated
@@ -480,7 +488,7 @@
                 self.Dragging = True
             # If a dragging have been initiated, refreshes the element state
             if self.Dragging:
-                dragx, dragy = self.ProcessDragging(movex, movey)
+                dragx, dragy = self.ProcessDragging(movex, movey, scaling)
                 self.oldPos.x += dragx
                 self.oldPos.y += dragy
                 return dragx, dragy
@@ -510,21 +518,31 @@
         self.SetSize(width, height)
     
     # Refreshes the element state according to move defined and handle selected
-    def ProcessDragging(self, movex, movey):
+    def ProcessDragging(self, movex, movey, scaling):
         handle_type, handle = self.Handle
         # If it is a resize handle, calculate the values from resizing
         if handle_type == HANDLE_RESIZE:
             x = y = start_x = start_y = 0
             width, height = start_width, start_height = self.GetSize()
             if handle[0] == 1:
-                x = movex = max(-self.BoundingBox.x, movex)
+                movex = max(-self.BoundingBox.x, movex)
+                if scaling is not None:
+                    movex = round(float(self.Pos.x + movex) / float(scaling[0])) * scaling[0] - self.Pos.x
+                x = movex
                 width -= movex
             elif handle[0] == 3:
+                if scaling is not None:
+                    movex = round(float(self.Pos.x + width + movex) / float(scaling[0])) * scaling[0] - self.Pos.x - width
                 width += movex
             if handle[1] == 1:
-                y = movey = max(-self.BoundingBox.y, movey)
+                movey = max(-self.BoundingBox.y, movey)
+                if scaling is not None:
+                    movey = round(float(self.Pos.y + movey) / float(scaling[1])) * scaling[1] - self.Pos.y
+                y = movey
                 height -= movey
             elif handle[1] == 3:
+                if scaling is not None:
+                    movey = round(float(self.Pos.y + height + movey) / float(scaling[1])) * scaling[1] - self.Pos.y - height
                 height += movey
             # Verify that new size is not lesser than minimum
             min_width, min_height = self.GetMinSize()
@@ -545,6 +563,9 @@
         elif handle_type == HANDLE_MOVE:
             movex = max(-self.BoundingBox.x, movex)
             movey = max(-self.BoundingBox.y, movey)
+            if scaling is not None:
+                movex = round(float(self.Pos.x + movex) / float(scaling[0])) * scaling[0] - self.Pos.x
+                movey = round(float(self.Pos.y + movey) / float(scaling[1])) * scaling[1] - self.Pos.y
             self.Move(movex, movey)
             return movex, movey
         return 0, 0
@@ -1189,6 +1210,12 @@
             return self.EndConnected.GetType()
         return None
     
+    def GetOtherConnected(self, connector):
+        if self.StartConnected == connector:
+            return self.EndConnected
+        else:
+            return self.StartConnected
+    
     def GetOtherConnectedType(self, handle):
         if handle == 0:
             return self.GetEndConnectedType()
@@ -1677,6 +1704,7 @@
         if point:
             self.MoveStartPoint(point)
         self.StartConnected = connector
+        self.RefreshBoundingBox()
     
     # Unconnects wire start point
     def UnConnectStartPoint(self, delete = False):
@@ -1686,6 +1714,7 @@
         elif self.StartConnected:
             self.StartConnected.UnConnect(self, unconnect = False)
             self.StartConnected = None
+            self.RefreshBoundingBox()
     
     # Moves the wire end point and update the wire points
     def MoveEndPoint(self, point):
@@ -1710,6 +1739,7 @@
         if point:
             self.MoveEndPoint(point)
         self.EndConnected = connector
+        self.RefreshBoundingBox()
     
     # Unconnects wire end point
     def UnConnectEndPoint(self, delete = False):
@@ -1719,12 +1749,15 @@
         elif self.EndConnected:
             self.EndConnected.UnConnect(self, unconnect = False)
             self.EndConnected = None
+            self.RefreshBoundingBox()
     
     # Moves the wire segment given by its index
-    def MoveSegment(self, idx, movex, movey):
+    def MoveSegment(self, idx, movex, movey, scaling):
         if 0 < idx < len(self.Segments) - 1:
             if self.Segments[idx] in (NORTH, SOUTH):
                 start_x = self.Points[idx].x
+                if scaling is not None:
+                    movex = round(float(self.Points[idx].x + movex) / float(scaling[0])) * scaling[0] - self.Points[idx].x
                 self.Points[idx].x += movex
                 self.Points[idx + 1].x += movex
                 self.GeneratePoints()
@@ -1732,6 +1765,8 @@
                     return self.Points[idx].x - start_x, 0
             elif self.Segments[idx] in (EAST, WEST):
                 start_y = self.Points[idx].y
+                if scaling is not None:
+                    movey = round(float(self.Points[idx].y + movey) / float(scaling[1])) * scaling[1] - self.Points[idx].y
                 self.Points[idx].y += movey
                 self.Points[idx + 1].y += movey
                 self.GeneratePoints()
@@ -1836,10 +1871,12 @@
                     self.MoveEndPoint(wx.Point(avgx, self.EndPoint[0].y))
             self.Parent.RefreshBuffer()
         else:
+            rect = self.GetRedrawRect()
             self.ResetPoints()
             self.GeneratePoints()
             self.RefreshModel()
             self.Parent.RefreshBuffer()
+            self.Parent.RefreshRect(self.Parent.GetScrolledRect(rect))
         
     # Method called when a Motion event has been generated
     def OnMotion(self, event, dc, scaling):
@@ -1875,12 +1912,15 @@
             return Graphic_Element.OnMotion(self, event, dc, scaling)
     
     # Refreshes the wire state according to move defined and handle selected
-    def ProcessDragging(self, movex, movey):
+    def ProcessDragging(self, movex, movey, scaling):
         handle_type, handle = self.Handle
         # A point has been handled
         if handle_type == HANDLE_POINT:
             movex = max(-self.Points[handle].x + POINT_RADIUS, movex)
             movey = max(-self.Points[handle].y + POINT_RADIUS, movey)
+            if scaling is not None:
+                movex = round(float(self.Points[handle].x + movex) / float(scaling[0])) * scaling[0] - self.Points[handle].x
+                movey = round(float(self.Points[handle].y + movey) / float(scaling[1])) * scaling[1] - self.Points[handle].y
             # Try to connect point to a connector
             new_pos = wx.Point(self.Points[handle].x + movex, self.Points[handle].y + movey)
             connector = self.Parent.FindBlockConnector(new_pos)
@@ -1921,10 +1961,10 @@
             return movex, movey
         # A segment has been handled, move a segment
         elif handle_type == HANDLE_SEGMENT:
-            return self.MoveSegment(handle[0], movex, movey)
+            return self.MoveSegment(handle[0], movex, movey, scaling)
         # Execute the default method for a graphic element
         else:
-            return Graphic_Element.ProcessDragging(self, movex, movey)
+            return Graphic_Element.ProcessDragging(self, movex, movey, scaling)
     
     # Refreshes the wire model
     def RefreshModel(self, move=True):
@@ -1949,11 +1989,13 @@
             width = abs(self.Points[i + 1].x - self.Points[i].x) + 5
             height = abs(self.Points[i + 1].y - self.Points[i].y) + 5
             dc.DrawRectangle(posx, posy, width, height)
+        dc.SetLogicalFunction(wx.COPY)
         if self.StartConnected is not None:
             self.StartConnected.DrawHighlightment(dc)
+            self.StartConnected.Draw(dc)
         if self.EndConnected is not None:
             self.EndConnected.DrawHighlightment(dc)
-        dc.SetLogicalFunction(wx.COPY)
+            self.EndConnected.Draw(dc)
         
     # Draws the wire lines and points
     def Draw(self, dc):
@@ -1996,8 +2038,10 @@
         self.Size = wx.Size(0, 0)
     
     # Make a clone of this comment
-    def Clone(self, id = None):
+    def Clone(self, id = None, pos = None):
         comment = Comment(self.Parent, self.Content, id)
+        if pos is not None:
+            comment.SetPosition(pos.x, pos.y)
         comment.SetSize(self.Size[0], self.Size[1])
         return comment
     
--- a/graphics/LD_Objects.py	Fri Jan 04 17:49:17 2008 +0100
+++ b/graphics/LD_Objects.py	Fri Jan 11 17:51:56 2008 +0100
@@ -186,29 +186,33 @@
     
     # Refresh the positions of the power rail connectors
     def RefreshConnectors(self):
+        scaling = self.Parent.GetScaling()
         if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
             height = self.Size[1] - self.Extensions[0] - self.Extensions[1]
             interval = float(height) / float(max(len(self.Connectors) - 1, 1))
             for i, connector in enumerate(self.Connectors):
-                position = connector.GetRelPosition()
+                if self.RealConnectors:
+                    position = self.Extensions[0] + int(round(self.RealConnectors[i] * height))
+                else:
+                    position = self.Extensions[0] + int(round(i * interval))
+                if scaling is not None:
+                    position = round(float(self.Pos.y + position) / float(scaling[1])) * scaling[1] - self.Pos.y
                 if self.Type == LEFTRAIL:
-                    if self.RealConnectors:
-                        connector.SetPosition(wx.Point(self.Size[0], self.Extensions[0] + int(round(self.RealConnectors[i] * height))))
-                    else:
-                        connector.SetPosition(wx.Point(self.Size[0], self.Extensions[0] + int(round(i * interval))))
+                    connector.SetPosition(wx.Point(self.Size[0], position))
                 elif self.Type == RIGHTRAIL:
-                    if self.RealConnectors:
-                        connector.SetPosition(wx.Point(0, self.Extensions[0] + int(round(self.RealConnectors[i] * height))))
-                    else:
-                        connector.SetPosition(wx.Point(0, self.Extensions[0] + int(round(i * interval))))
+                    connector.SetPosition(wx.Point(0, position))
         else:
             position = self.Extensions[0]
             for connector in self.Connectors:
                 if connector:
+                    if scaling is not None:
+                        ypos = round(float(self.Pos.y + position) / float(scaling[1])) * scaling[1] - self.Pos.y
+                    else:
+                        ypos = position
                     if self.Type == LEFTRAIL:
-                        connector.SetPosition(wx.Point(self.Size[0], position))
+                        connector.SetPosition(wx.Point(self.Size[0], ypos))
                     elif self.Type == RIGHTRAIL:
-                        connector.SetPosition(wx.Point(0, position))
+                        connector.SetPosition(wx.Point(0, ypos))
                 position += LD_LINE_SIZE
         self.RefreshConnected()
     
@@ -262,6 +266,20 @@
     
     # Method called when a LeftDown event have been generated
     def OnLeftDown(self, event, dc, scaling):
+        self.RealConnectors = []
+        height = self.Size[1] - self.Extensions[0] - self.Extensions[1]
+        for connector in self.Connectors:
+            position = connector.GetRelPosition()
+            self.RealConnectors.append(float(position.y - self.Extensions[0])/float(max(1, height)))
+        Graphic_Element.OnLeftDown(self, event, dc, scaling)
+    
+    # Method called when a LeftUp event have been generated
+    def OnLeftUp(self, event, dc, scaling):
+        Graphic_Element.OnLeftUp(self, event, dc, scaling)
+        self.RealConnectors = None
+    
+    # Method called when a LeftDown event have been generated
+    def OnRightDown(self, event, dc, scaling):
         pos = GetScaledEventPosition(event, dc, scaling)
         # Test if a connector have been handled
         connector = self.TestConnector(pos, False)
@@ -272,15 +290,15 @@
             # Initializes the last position
             self.oldPos = GetScaledEventPosition(event, dc, scaling)
         else:
-            self.RealConnectors = []
-            height = self.Size[1] - self.Extensions[0] - self.Extensions[1]
-            for connector in self.Connectors:
-                position = connector.GetRelPosition()
-                self.RealConnectors.append(float(position.y - self.Extensions[0])/float(max(1, height)))
-            Graphic_Element.OnLeftDown(self, event, dc, scaling)
-    
-    # Method called when a LeftUp event have been generated
-    def OnLeftUp(self, event, dc, scaling):
+            Graphic_Element.OnRightDown(self, event, dc, scaling)
+    
+    # Method called when a LeftDClick event have been generated
+    def OnLeftDClick(self, event, dc, scaling):
+        # Edit the powerrail properties
+        self.Parent.EditPowerRailContent(self)
+    
+    # Method called when a RightUp event have been generated
+    def OnRightUp(self, event, dc, scaling):
         handle_type, handle = self.Handle
         if handle_type == HANDLE_CONNECTOR:
             wires = handle.GetWires()
@@ -290,28 +308,23 @@
                 else:
                     block = wires[0][0].StartConnected.GetParentBlock()
                 block.RefreshModel(False)
-        Graphic_Element.OnLeftUp(self, event, dc, scaling)
-        self.RealConnectors = None
-    
-    # Method called when a LeftDClick event have been generated
-    def OnLeftDClick(self, event, dc, scaling):
-        # Edit the powerrail properties
-        self.Parent.EditPowerRailContent(self)
-    
-    # Method called when a RightUp event have been generated
-    def OnRightUp(self, event, dc, scaling):
-        self.Parent.PopupDefaultMenu()
+            Graphic_Element.OnRightUp(self, event, dc, scaling)
+        else:
+            self.Parent.PopupDefaultMenu()
     
     # Refreshes the powerrail state according to move defined and handle selected
-    def ProcessDragging(self, movex, movey):
+    def ProcessDragging(self, movex, movey, scaling):
         handle_type, handle = self.Handle
         # A connector has been handled
         if handle_type == HANDLE_CONNECTOR:
             movey = max(-self.BoundingBox.y, movey)
+            if scaling is not None:
+                position = handle.GetRelPosition()
+                movey = round(float(self.Pos.y + position.y + movey) / float(scaling[1])) * scaling[1] - self.Pos.y - position.y
             self.MoveConnector(handle, movey)
             return 0, movey
         else:
-            return Graphic_Element.ProcessDragging(self, movex, movey)
+            return Graphic_Element.ProcessDragging(self, movex, movey, scaling)
     
     # Refreshes the power rail model
     def RefreshModel(self, move=True):
@@ -486,8 +499,12 @@
 
     # Refresh the positions of the block connectors
     def RefreshConnectors(self):
-        self.Input.SetPosition(wx.Point(0, self.Size[1] / 2 + 1))
-        self.Output.SetPosition(wx.Point(self.Size[0], self.Size[1] / 2 + 1))
+        scaling = self.Parent.GetScaling()
+        position = self.Size[1] / 2 + 1
+        if scaling is not None:
+            position = round(float(self.Pos.y + position) / float(scaling[1])) * scaling[1] - self.Pos.y
+        self.Input.SetPosition(wx.Point(0, position))
+        self.Output.SetPosition(wx.Point(self.Size[0], position))
         self.RefreshConnected()
 
     # Changes the contact name
@@ -712,8 +729,12 @@
     
     # Refresh the positions of the block connectors
     def RefreshConnectors(self):
-        self.Input.SetPosition(wx.Point(0, self.Size[1] / 2 + 1))
-        self.Output.SetPosition(wx.Point(self.Size[0], self.Size[1] / 2 + 1))
+        scaling = self.Parent.GetScaling()
+        position = self.Size[1] / 2 + 1
+        if scaling is not None:
+            position = round(float(self.Pos.y + position) / float(scaling[1])) * scaling[1] - self.Pos.y
+        self.Input.SetPosition(wx.Point(0, position))
+        self.Output.SetPosition(wx.Point(self.Size[0], position))
         self.RefreshConnected()
     
     # Changes the coil name
--- a/graphics/SFC_Objects.py	Fri Jan 04 17:49:17 2008 +0100
+++ b/graphics/SFC_Objects.py	Fri Jan 11 17:51:56 2008 +0100
@@ -125,7 +125,7 @@
     # Add output connector to step
     def AddOutput(self):
         if not self.Output:
-            self.Output = Connector(self, "", None, wx.Point(self.Size[0] / 2, self.Size[1]), SOUTH)
+            self.Output = Connector(self, "", None, wx.Point(self.Size[0] / 2, self.Size[1]), SOUTH, onlyone = True)
             self.RefreshBoundingBox()
     
     # Remove output connector from step
@@ -138,7 +138,7 @@
     # Add action connector to step
     def AddAction(self):
         if not self.Action:
-            self.Action = Connector(self, "", None, wx.Point(self.Size[0], self.Size[1] / 2), EAST)
+            self.Action = Connector(self, "", None, wx.Point(self.Size[0], self.Size[1] / 2), EAST, onlyone = True)
             self.RefreshBoundingBox()
     
     # Remove action connector from step
@@ -171,15 +171,21 @@
         
     # Refresh the positions of the step connectors
     def RefreshConnectors(self):
+        scaling = self.Parent.GetScaling()
+        horizontal_pos = self.Size[0] / 2
+        vertical_pos = self.Size[1] / 2
+        if scaling is not None:
+            horizontal_pos = round(float(self.Pos.x + horizontal_pos) / float(scaling[0])) * scaling[0] - self.Pos.x
+            vertical_pos = round(float(self.Pos.y + vertical_pos) / float(scaling[1])) * scaling[1] - self.Pos.y
         # Update input position if it exists
         if self.Input:
-            self.Input.SetPosition(wx.Point(self.Size[0] / 2, 0))
+            self.Input.SetPosition(wx.Point(horizontal_pos, 0))
         # Update output position
         if self.Output:
-            self.Output.SetPosition(wx.Point(self.Size[0] / 2, self.Size[1]))
+            self.Output.SetPosition(wx.Point(horizontal_pos, self.Size[1]))
         # Update action position if it exists
         if self.Action:
-            self.Action.SetPosition(wx.Point(self.Size[0], self.Size[1] / 2))
+            self.Action.SetPosition(wx.Point(self.Size[0], vertical_pos))
         self.RefreshConnected()
     
     # Refresh the position of wires connected to step
@@ -253,7 +259,7 @@
         if self.Input:
             wires = self.Input.GetWires()
             if len(wires) == 1:
-                return wires[0][0].EndConnected
+                return wires[0][0].GetOtherConnected(self.Input)
         return None
     
     # Returns the connector connected to output
@@ -261,7 +267,7 @@
         if self.Output:
             wires = self.Output.GetWires()
             if len(wires) == 1:
-                return wires[0][0].StartConnected
+                return wires[0][0].GetOtherConnected(self.Output)
         return None
     
     # Returns the connector connected to action
@@ -269,7 +275,7 @@
         if self.Action:
             wires = self.Action.GetWires()
             if len(wires) == 1:
-                return wires[0][0].StartConnected
+                return wires[0][0].GetOtherConnected(self.Action)
         return None
     
     # Returns the number of action line
@@ -278,7 +284,7 @@
             wires = self.Action.GetWires()
             if len(wires) != 1:
                 return 0
-            action_block = wires[0][0].StartConnected.GetParentBlock()
+            action_block = wires[0][0].GetOtherConnected(self.Action).GetParentBlock()
             return max(0, action_block.GetLineNumber() - 1)
         return 0
     
@@ -326,7 +332,7 @@
             if len(wires) != 1:
                 return
             current_pos = self.Output.GetPosition(False)
-            output = wires[0][0].StartConnected
+            output = wires[0][0].GetOtherConnected(self.Output)
             output_pos = output.GetPosition(False)
             diffx = current_pos.x - output_pos.x
             output_block = output.GetParentBlock()
@@ -365,7 +371,7 @@
             wires = self.Action.GetWires()
             if len(wires) != 1:
                 return
-            action_block = wires[0][0].StartConnected.GetParentBlock()
+            action_block = wires[0][0].GetOtherConnected(self.Action).GetParentBlock()
             action_block.Move(move[0], move[1], self.Parent.Wires)
             wires[0][0].Move(move[0], move[1], True)
     
@@ -387,11 +393,14 @@
         self.Parent.PopupDefaultMenu()
     
     # Refreshes the step state according to move defined and handle selected
-    def ProcessDragging(self, movex, movey):
+    def ProcessDragging(self, movex, movey, scaling):
         handle_type, handle = self.Handle
         if handle_type == HANDLE_MOVE:
             movex = max(-self.BoundingBox.x, movex)
             movey = max(-self.BoundingBox.y, movey)
+            if scaling is not None:
+                movex = round(float(self.Pos.x + movex) / float(scaling[0])) * scaling[0] - self.Pos.x
+                movey = round(float(self.Pos.y + movey) / float(scaling[1])) * scaling[1] - self.Pos.y
             action_block = None
             if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
                 self.Move(movex, movey)
@@ -409,7 +418,7 @@
                 self.RefreshOutputPosition()
                 return movex, 0
         else:
-            return Graphic_Element.ProcessDragging(self, movex, movey)
+            return Graphic_Element.ProcessDragging(self, movex, movey, scaling)
     
     # Refresh input element model
     def RefreshInputModel(self):
@@ -487,8 +496,8 @@
         self.Priority = 0
         self.Size = wx.Size(SFC_TRANSITION_SIZE[0], SFC_TRANSITION_SIZE[1])
         # Create an input and output connector
-        self.Input = Connector(self, "", None, wx.Point(self.Size[0] / 2, 0), NORTH)
-        self.Output = Connector(self, "", None, wx.Point(self.Size[0] / 2, self.Size[1]), SOUTH)
+        self.Input = Connector(self, "", None, wx.Point(self.Size[0] / 2, 0), NORTH, onlyone = True)
+        self.Output = Connector(self, "", None, wx.Point(self.Size[0] / 2, self.Size[1]), SOUTH, onlyone = True)
         self.SetType(type, condition)
         self.SetPriority(priority)
     
@@ -582,24 +591,30 @@
     def GetPreviousConnector(self):
         wires = self.Input.GetWires()
         if len(wires) == 1:
-            return wires[0][0].EndConnected
+            return wires[0][0].GetOtherConnected(self.Input)
         return None
     
     # Returns the connector connected to output
     def GetNextConnector(self):
         wires = self.Output.GetWires()
         if len(wires) == 1:
-            return wires[0][0].StartConnected
+            return wires[0][0].GetOtherConnected(self.Output)
         return None
     
     # Refresh the positions of the transition connectors
     def RefreshConnectors(self):
+        scaling = self.Parent.GetScaling()
+        horizontal_pos = self.Size[0] / 2
+        vertical_pos = self.Size[1] / 2
+        if scaling is not None:
+            horizontal_pos = round(float(self.Pos.x + horizontal_pos) / float(scaling[0])) * scaling[0] - self.Pos.x
+            vertical_pos = round(float(self.Pos.y + vertical_pos) / float(scaling[1])) * scaling[1] - self.Pos.y
         # Update input position
-        self.Input.SetPosition(wx.Point(self.Size[0] / 2, 0))
+        self.Input.SetPosition(wx.Point(horizontal_pos, 0))
         # Update output position
-        self.Output.SetPosition(wx.Point(self.Size[0] / 2, self.Size[1]))
+        self.Output.SetPosition(wx.Point(horizontal_pos, self.Size[1]))
         if self.Type == "connection":
-            self.Condition.SetPosition(wx.Point(0, self.Size[1] / 2))
+            self.Condition.SetPosition(wx.Point(0, vertical_pos))
         self.RefreshConnected()
     
     # Refresh the position of the wires connected to transition
@@ -722,7 +737,7 @@
         if len(wires) != 1:
             return
         current_pos = self.Output.GetPosition(False)
-        output = wires[0][0].StartConnected
+        output = wires[0][0].GetOtherConnected(self.Output)
         output_pos = output.GetPosition(False)
         diffx = current_pos.x - output_pos.x
         output_block = output.GetParentBlock()
@@ -754,15 +769,17 @@
         self.Parent.PopupDefaultMenu()
     
     # Refreshes the transition state according to move defined and handle selected
-    def ProcessDragging(self, movex, movey):
+    def ProcessDragging(self, movex, movey, scaling):
         if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
             movex = max(-self.BoundingBox.x, movex)
+            if scaling is not None:
+                movex = round(float(self.Pos.x + movex) / float(scaling[0])) * scaling[0] - self.Pos.x
             self.Move(movex, 0)
             self.RefreshInputPosition()
             self.RefreshOutputPosition()
             return movex, 0
         else:
-            return Graphic_Element.ProcessDragging(self, movex, movey)
+            return Graphic_Element.ProcessDragging(self, movex, movey, scaling)
     
     # Refresh input element model
     def RefreshInputModel(self):
@@ -845,15 +862,15 @@
             self.Size = wx.Size((number - 1) * SFC_DEFAULT_SEQUENCE_INTERVAL, 3)
         # Create an input and output connector
         if self.Type in [SELECTION_DIVERGENCE, SIMULTANEOUS_DIVERGENCE]:
-            self.Inputs = [Connector(self, "", None, wx.Point(self.Size[0] / 2, 0), NORTH)]
+            self.Inputs = [Connector(self, "", None, wx.Point(self.Size[0] / 2, 0), NORTH, onlyone = True)]
             self.Outputs = []
             for i in xrange(number):
-                self.Outputs.append(Connector(self, "", None, wx.Point(i * SFC_DEFAULT_SEQUENCE_INTERVAL, self.Size[1]), SOUTH))
+                self.Outputs.append(Connector(self, "", None, wx.Point(i * SFC_DEFAULT_SEQUENCE_INTERVAL, self.Size[1]), SOUTH, onlyone = True))
         elif self.Type in [SELECTION_CONVERGENCE, SIMULTANEOUS_CONVERGENCE]:
             self.Inputs = []
             for i in xrange(number):
-                self.Inputs.append(Connector(self, "", None, wx.Point(i * SFC_DEFAULT_SEQUENCE_INTERVAL, 0), NORTH))
-            self.Outputs = [Connector(self, "", None, wx.Point(self.Size[0] / 2, self.Size[1]), SOUTH)]
+                self.Inputs.append(Connector(self, "", None, wx.Point(i * SFC_DEFAULT_SEQUENCE_INTERVAL, 0), NORTH, onlyone = True))
+            self.Outputs = [Connector(self, "", None, wx.Point(self.Size[0] / 2, self.Size[1]), SOUTH, onlyone = True)]
     
     # Destructor
     def __del__(self):
@@ -909,7 +926,7 @@
             for output in self.Outputs:
                 pos = output.GetRelPosition()
                 maxx = max(maxx, pos.x)
-            connector = Connector(self, "", None, wx.Point(maxx + SFC_DEFAULT_SEQUENCE_INTERVAL, self.Size[1]), SOUTH)
+            connector = Connector(self, "", None, wx.Point(maxx + SFC_DEFAULT_SEQUENCE_INTERVAL, self.Size[1]), SOUTH, onlyone = True)
             self.Outputs.append(connector)
             self.MoveConnector(connector, 0)
         elif self.Type in [SELECTION_CONVERGENCE, SIMULTANEOUS_CONVERGENCE]:
@@ -917,7 +934,7 @@
             for input in self.Inputs:
                 pos = input.GetRelPosition()
                 maxx = max(maxx, pos.x)
-            connector = Connector(self, "", None, wx.Point(maxx + SFC_DEFAULT_SEQUENCE_INTERVAL, 0), NORTH)
+            connector = Connector(self, "", None, wx.Point(maxx + SFC_DEFAULT_SEQUENCE_INTERVAL, 0), NORTH, onlyone = True)
             self.Inputs.append(connector)
             self.MoveConnector(connector, SFC_DEFAULT_SEQUENCE_INTERVAL)
     
@@ -954,11 +971,11 @@
     # Refresh the divergence bounding box
     def RefreshBoundingBox(self):
         if self.Type in [SELECTION_DIVERGENCE, SELECTION_CONVERGENCE]:
-            self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y - 2, 
-                self.Size[0] + 1, self.Size[1] + 5)
+            self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, 
+                self.Size[0] + 1, self.Size[1] + 1)
         elif self.Type in [SIMULTANEOUS_DIVERGENCE, SIMULTANEOUS_CONVERGENCE]:
-            self.BoundingBox = wx.Rect(self.Pos.x - SFC_SIMULTANEOUS_SEQUENCE_EXTRA, self.Pos.y - 2, 
-                self.Size[0] + 2 * SFC_SIMULTANEOUS_SEQUENCE_EXTRA + 1, self.Size[1] + 5)
+            self.BoundingBox = wx.Rect(self.Pos.x - SFC_SIMULTANEOUS_SEQUENCE_EXTRA, self.Pos.y, 
+                self.Size[0] + 2 * SFC_SIMULTANEOUS_SEQUENCE_EXTRA + 1, self.Size[1] + 1)
     
     # Refresh the position of wires connected to divergence
     def RefreshConnected(self, exclude = []):
@@ -1073,10 +1090,7 @@
         if len(wires) != 1:
             return
         current_pos = connector.GetPosition(False)
-        if connector in self.Inputs:
-            next = wires[0][0].EndConnected
-        else:
-            next = wires[0][0].StartConnected
+        next = wires[0][0].GetOtherConnected(connector)
         next_pos = next.GetPosition(False)
         diffx = current_pos.x - next_pos.x
         next_block = next.GetParentBlock()
@@ -1096,7 +1110,7 @@
             wires = input.GetWires()
             if len(wires) != 1:
                 return
-            previous = wires[0][0].EndConnected
+            previous = wires[0][0].GetOtherConnected(input)
             previous_pos = previous.GetPosition(False)
             y = max(y, previous_pos.y + GetWireSize(previous.GetParentBlock()))
         diffy = y - self.Pos.y
@@ -1114,7 +1128,7 @@
                 if len(wires) != 1:
                     return
                 current_pos = output_connector.GetPosition(False)
-                output = wires[0][0].StartConnected
+                output = wires[0][0].GetOtherConnected(self.Output)
                 output_pos = output.GetPosition(False)
                 diffx = current_pos.x - output_pos.x
                 output_block = output.GetParentBlock()
@@ -1127,6 +1141,22 @@
     
     # Method called when a LeftDown event have been generated
     def OnLeftDown(self, event, dc, scaling):
+        self.RealConnectors = {"Inputs":[],"Outputs":[]}
+        for input in self.Inputs:
+            position = input.GetRelPosition()
+            self.RealConnectors["Inputs"].append(float(position.x)/float(self.Size[0]))
+        for output in self.Outputs:
+            position = output.GetRelPosition()
+            self.RealConnectors["Outputs"].append(float(position.x)/float(self.Size[0]))
+        Graphic_Element.OnLeftDown(self, event, dc, scaling)
+    
+    # Method called when a LeftUp event have been generated
+    def OnLeftUp(self, event, dc, scaling):
+        Graphic_Element.OnLeftUp(self, event, dc, scaling)
+        self.RealConnectors = None
+    
+    # Method called when a RightDown event have been generated
+    def OnRightDown(self, event, dc, scaling):
         pos = GetScaledEventPosition(event, dc, scaling)
         # Test if a connector have been handled
         connector = self.TestConnector(pos, False)
@@ -1137,59 +1167,48 @@
             # Initializes the last position
             self.oldPos = GetScaledEventPosition(event, dc, scaling)
         else:
-            self.RealConnectors = {"Inputs":[],"Outputs":[]}
-            for input in self.Inputs:
-                position = input.GetRelPosition()
-                self.RealConnectors["Inputs"].append(float(position.x)/float(self.Size[0]))
-            for output in self.Outputs:
-                position = output.GetRelPosition()
-                self.RealConnectors["Outputs"].append(float(position.x)/float(self.Size[0]))
-            Graphic_Element.OnLeftDown(self, event, dc, scaling)
-    
-    # Method called when a LeftUp event have been generated
-    def OnLeftUp(self, event, dc, scaling):
-        self.RealConnectors = None
+            Graphic_Element.OnRightDown(self, event, dc, scaling)
+    
+    # Method called when a RightUp event have been generated
+    def OnRightUp(self, event, dc, scaling):
         handle_type, handle = self.Handle
         if handle_type == HANDLE_CONNECTOR:
             wires = handle.GetWires()
             if len(wires) != 1:
                 return
-            if handle in self.Inputs:
-                block = wires[0][0].EndConnected.GetParentBlock()
-            else:
-                block = wires[0][0].StartConnected.GetParentBlock()
+            block = wires[0][0].GetOtherConnected(handle).GetParentBlock()
             block.RefreshModel(False)
             if not isinstance(block, SFC_Divergence):
                 if handle in self.Inputs:
                     block.RefreshInputModel()
                 else:
                     block.RefreshOutputModel()
-        Graphic_Element.OnLeftUp(self, event, dc, scaling)
-    
-    # Method called when a RightUp event have been generated
-    def OnRightUp(self, event, dc, scaling):
-        pos = GetScaledEventPosition(event, dc, scaling)
-        # Popup the menu with special items for a block and a connector if one is handled
-        connector = self.TestConnector(pos, False)
-        if connector:
-            self.Handle = (HANDLE_CONNECTOR, connector)
-            self.Parent.PopupDivergenceMenu(True)
-        else:
-            # Popup the divergence menu without delete branch
-            self.Parent.PopupDivergenceMenu(False)
+            Graphic_Element.OnRightUp(self, event, dc, scaling)
+        else:
+            pos = GetScaledEventPosition(event, dc, scaling)
+            # Popup the menu with special items for a block and a connector if one is handled
+            connector = self.TestConnector(pos, False)
+            if connector:
+                self.Handle = (HANDLE_CONNECTOR, connector)
+                self.Parent.PopupDivergenceMenu(True)
+            else:
+                # Popup the divergence menu without delete branch
+                self.Parent.PopupDivergenceMenu(False)
     
     # Refreshes the divergence state according to move defined and handle selected
-    def ProcessDragging(self, movex, movey):
+    def ProcessDragging(self, movex, movey, scaling):
         handle_type, handle = self.Handle
         # A connector has been handled
         if handle_type == HANDLE_CONNECTOR:
             movex = max(-self.BoundingBox.x, movex)
+            if scaling is not None:
+                movex = round(float(self.Pos.x + movex) / float(scaling[0])) * scaling[0] - self.Pos.x
             self.MoveConnector(handle, movex)
             if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
                 self.RefreshConnectedPosition(handle)
             return movex, 0
         elif self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
-            return Graphic_Element.ProcessDragging(self, movex, movey)
+            return Graphic_Element.ProcessDragging(self, movex, movey, scaling)
         return 0, 0
     
     # Refresh output element model
@@ -1199,7 +1218,7 @@
                 wires = output.GetWires()
                 if len(wires) != 1:
                     return
-                output_block = wires[0][0].StartConnected.GetParentBlock()
+                output_block = wires[0][0].GetOtherConnected(output).GetParentBlock()
                 output_block.RefreshModel(False)
                 if not isinstance(output_block, SFC_Divergence) or move:
                     output_block.RefreshOutputModel(move)
@@ -1266,7 +1285,7 @@
         self.Id = id
         self.Size = wx.Size(SFC_JUMP_SIZE[0], SFC_JUMP_SIZE[1])
         # Create an input and output connector
-        self.Input = Connector(self, "", None, wx.Point(self.Size[0] / 2, 0), NORTH)
+        self.Input = Connector(self, "", None, wx.Point(self.Size[0] / 2, 0), NORTH, onlyone = True)
         
     # Destructor
     def __del__(self):
@@ -1321,12 +1340,16 @@
     def GetPreviousConnector(self):
         wires = self.Input.GetWires()
         if len(wires) == 1:
-            return wires[0][0].EndConnected
+            return wires[0][0].GetOtherConnected(self.Input)
         return None
     
     # Refresh the element connectors position
     def RefreshConnectors(self):
-        self.Input.SetPosition(wx.Point(self.Size[0] / 2, 0))
+        scaling = self.Parent.GetScaling()
+        horizontal_pos = self.Size[0] / 2
+        if scaling is not None:
+            horizontal_pos = round(float(self.Pos.x + horizontal_pos) / float(scaling[0])) * scaling[0] - self.Pos.x
+        self.Input.SetPosition(wx.Point(horizontal_pos, 0))
         self.RefreshConnected()
     
     # Refresh the position of wires connected to jump
@@ -1390,14 +1413,16 @@
         self.Parent.PopupDefaultMenu()
     
     # Refreshes the jump state according to move defined and handle selected
-    def ProcessDragging(self, movex, movey):
+    def ProcessDragging(self, movex, movey, scaling):
         if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
             movex = max(-self.BoundingBox.x, movex)
+            if scaling is not None:
+                movex = round(float(self.Pos.x + movex) / float(scaling[0])) * scaling[0] - self.Pos.x
             self.Move(movex, 0)
             self.RefreshInputPosition()
             return movex, 0
         else:
-            return Graphic_Element.ProcessDragging(self, movex, movey)
+            return Graphic_Element.ProcessDragging(self, movex, movey, scaling)
     
     # Refresh input element model
     def RefreshInputModel(self):
@@ -1468,7 +1493,7 @@
         self.Size = wx.Size(SFC_ACTION_MIN_SIZE[0], SFC_ACTION_MIN_SIZE[1])
         self.MinSize = wx.Size(SFC_ACTION_MIN_SIZE[0], SFC_ACTION_MIN_SIZE[1])
         # Create an input and output connector
-        self.Input = Connector(self, "", None, wx.Point(0, SFC_ACTION_MIN_SIZE[1] / 2), WEST)
+        self.Input = Connector(self, "", None, wx.Point(0, SFC_ACTION_MIN_SIZE[1] / 2), WEST, onlyone = True)
         self.SetActions(actions)
     
     # Destructor
@@ -1539,6 +1564,15 @@
             return self.Input
         return None
     
+    # Refresh the element connectors position
+    def RefreshConnectors(self):
+        scaling = self.Parent.GetScaling()
+        vertical_pos = SFC_ACTION_MIN_SIZE[1] / 2
+        if scaling is not None:
+            vertical_pos = round(float(self.Pos.y + vertical_pos) / float(scaling[1])) * scaling[1] - self.Pos.y
+        self.Input.SetPosition(wx.Point(0, vertical_pos))
+        self.RefreshConnected()
+    
     # Changes the action block actions
     def SetActions(self, actions):
         dc = wx.ClientDC(self.Parent)
@@ -1575,7 +1609,7 @@
             if self.Input:
                 wires = self.Input.GetWires()
                 if len(wires) == 1:
-                    input_block = wires[0][0].EndConnected.GetParentBlock()
+                    input_block = wires[0][0].GetOtherConnected(self.Input).GetParentBlock()
                     input_block.RefreshOutputPosition()
                     input_block.RefreshOutputModel(True)
     
@@ -1598,22 +1632,24 @@
         self.Parent.PopupDefaultMenu()
     
     # Refreshes the action block state according to move defined and handle selected
-    def ProcessDragging(self, movex, movey):
+    def ProcessDragging(self, movex, movey, scaling):
         if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
             handle_type, handle = self.Handle
             if handle_type == HANDLE_MOVE:
                 movex = max(-self.BoundingBox.x, movex)
+                if scaling is not None:
+                    movex = round(float(self.Pos.x + movex) / float(scaling[0])) * scaling[0] - self.Pos.x
                 wires = self.Input.GetWires()
                 if len(wires) == 1:
-                    input_pos = wires[0][0].EndConnected.GetPosition(False)
+                    input_pos = wires[0][0].GetOtherConnected(self.Input).GetPosition(False)
                     if self.Pos.x - input_pos.x + movex >= SFC_WIRE_MIN_SIZE:
                         self.Move(movex, 0)
                         return movex, 0
                 return 0, 0
             else:
-                return Graphic_Element.ProcessDragging(self, movex, movey)
-        else:
-            return Graphic_Element.ProcessDragging(self, movex, movey)
+                return Graphic_Element.ProcessDragging(self, movex, movey, scaling)
+        else:
+            return Graphic_Element.ProcessDragging(self, movex, movey, scaling)
 
     
    # Refreshes the action block model
--- a/plcopen/plcopen.py	Fri Jan 04 17:49:17 2008 +0100
+++ b/plcopen/plcopen.py	Fri Jan 11 17:51:56 2008 +0100
@@ -91,6 +91,14 @@
 if cls:
     cls.singleLineAttributes = False
     
+    def setName(self, name):
+        self.contentHeader.setName(name)
+    setattr(cls, "setName", setName)
+        
+    def getName(self):
+        return self.contentHeader.getName()
+    setattr(cls, "getName", getName)
+    
     def getFileHeader(self):
         fileheader = {}
         fileheader["companyName"] = self.fileHeader.getCompanyName()
@@ -119,14 +127,40 @@
             self.fileHeader.setContentDescription(fileheader["contentDescription"])
     setattr(cls, "setFileHeader", setFileHeader)
     
-    def setName(self, name):
-        self.contentHeader.setName(name)
-    setattr(cls, "setName", setName)
-        
-    def getName(self):
-        return self.contentHeader.getName()
-    setattr(cls, "getName", getName)
-
+    def getContentHeader(self):
+        contentheader = {}
+        contentheader["projectName"] = self.contentHeader.getName()
+        if self.contentHeader.getVersion():
+            contentheader["projectVersion"] = self.contentHeader.getVersion()
+        if self.contentHeader.getModificationDateTime():
+            contentheader["modificationDateTime"] = self.contentHeader.getModificationDateTime()
+        if self.contentHeader.getOrganization():
+            contentheader["organization"] = self.contentHeader.getOrganization()
+        if self.contentHeader.getAuthor():
+            contentheader["authorName"] = self.contentHeader.getAuthor()
+        if self.contentHeader.getLanguage():
+            contentheader["language"] = self.contentHeader.getLanguage()
+        contentheader["pageSize"] = self.contentHeader.getPageSize()
+        contentheader["scaling"] = self.contentHeader.getScaling()
+        return contentheader
+    setattr(cls, "getContentHeader", getContentHeader)
+    
+    def setContentHeader(self, contentheader):
+        self.contentHeader.setName(contentheader["projectName"])
+        if "projectVersion" in contentheader:
+            self.contentHeader.setVersion(contentheader["projectVersion"])
+        if "modificationDateTime" in contentheader:
+            self.contentHeader.setModificationDateTime(contentheader["modificationDateTime"])
+        if "organization" in contentheader:
+            self.contentHeader.setOrganization(contentheader["organization"])
+        if "authorName" in contentheader:
+            self.contentHeader.setAuthor(contentheader["authorName"])
+        if "language" in contentheader:
+            self.contentHeader.setLanguage(contentheader["language"])
+        self.contentHeader.setPageSize(*contentheader["pageSize"])
+        self.contentHeader.setScaling(contentheader["scaling"])
+    setattr(cls, "setContentHeader", setContentHeader)
+    
     def getDataTypes(self):
         return self.types.getDataTypeElements()
     setattr(cls, "getDataTypes", getDataTypes)
@@ -219,7 +253,7 @@
             new_resource = PLCOpenClasses["configuration_resource"]()
             new_resource.setName(name)
             configuration.appendResource(new_resource)
-    setattr(cls, "addConfigurationResource", addConfigurationResource)    
+    setattr(cls, "addConfigurationResource", addConfigurationResource)
 
     def removeConfigurationResource(self, config_name, name):
         configuration = self.getConfiguration(config_name)
@@ -245,6 +279,71 @@
 if cls:
     cls.singleLineAttributes = False
 
+cls = PLCOpenClasses.get("project_contentHeader", None)
+if cls:
+    cls.singleLineAttributes = False
+    
+    def setPageSize(self, width, height):
+        self.coordinateInfo.setPageSize(width, height)
+    setattr(cls, "setPageSize", setPageSize)
+    
+    def getPageSize(self):
+        return self.coordinateInfo.getPageSize()
+    setattr(cls, "getPageSize", getPageSize)
+
+    def setScaling(self, scaling):
+        for language, (x, y) in scaling.items():
+            self.coordinateInfo.setScaling(language, x, y)
+    setattr(cls, "setScaling", setScaling)
+    
+    def getScaling(self):
+        scaling = {}
+        scaling["FBD"] = self.coordinateInfo.getScaling("FBD")
+        scaling["LD"] = self.coordinateInfo.getScaling("LD")
+        scaling["SFC"] = self.coordinateInfo.getScaling("SFC")
+        return scaling
+    setattr(cls, "getScaling", getScaling)
+
+cls = PLCOpenClasses.get("contentHeader_coordinateInfo", None)
+if cls:
+    def setPageSize(self, width, height):
+        if width == 0 and height == 0:
+            self.deletePageSize()
+        else:
+            if self.pageSize is None:
+                self.addPageSize()
+            self.pageSize.setX(width)
+            self.pageSize.setY(height)
+    setattr(cls, "setPageSize", setPageSize)
+    
+    def getPageSize(self):
+        if self.pageSize is not None:
+            return self.pageSize.getX(), self.pageSize.getY()
+        return 0, 0
+    setattr(cls, "getPageSize", getPageSize)
+
+    def setScaling(self, language, x, y):
+        if language == "FBD":
+            self.fbd.scaling.setX(x)
+            self.fbd.scaling.setY(y)
+        elif language == "LD":
+            self.ld.scaling.setX(x)
+            self.ld.scaling.setY(y)
+        elif language == "SFC":
+            self.sfc.scaling.setX(x)
+            self.sfc.scaling.setY(y)
+    setattr(cls, "setScaling", setScaling)
+    
+    def getScaling(self, language):
+        if language == "FBD":
+            return self.fbd.scaling.getX(), self.fbd.scaling.getY()
+        elif language == "LD":
+            return self.ld.scaling.getX(), self.ld.scaling.getY()
+        elif language == "SFC":
+            return self.sfc.scaling.getX(), self.sfc.scaling.getY()
+        return 0, 0
+    setattr(cls, "getScaling", getScaling)
+
 cls = PLCOpenClasses.get("configurations_configuration", None)
 if cls:
     def updateElementName(self, old_name, new_name):
@@ -1455,13 +1554,27 @@
         return self.content["value"].getValue()
     setattr(cls, "getValue", getValue)
 
+def extractValues(self, values):
+    items = values.split(",")
+    i = 1
+    while i < len(items):
+        opened = items[i - 1].count("(") + items[i - 1].count("[")
+        closed = items[i - 1].count(")") + items[i - 1].count("]")
+        if opened > closed:
+            items[i - 1] = ','.join([items[i - 1], items.pop(i)])
+        elif opened == closed:
+            i += 1
+        else:
+            raise ValueError, "\"%s\" is an invalid value!"%value
+    return items
+
 cls = PLCOpenClasses.get("value_arrayValue", None)
 if cls:
-    arrayValue_model = re.compile("([0-9]*)\((.*)\)")
+    arrayValue_model = re.compile("([0-9]*)\((.*)\)$")
     
     def setValue(self, value):
         self.value = []
-        for item in value[1:-1].split(","):
+        for item in extractValues(value[1:-1]):
             item = item.strip()
             element = PLCOpenClasses["arrayValue_value"]()
             result = arrayValue_model.match(item)
@@ -1491,7 +1604,7 @@
     
     def setValue(self, value):
         self.value = []
-        for item in value[1:-1].split(","):
+        for item in extractValues(value[1:-1]):
             result = arrayValue_model.match(item)
             if result is not None:
                 groups = result.groups()