Adding optimization on Viewer redrawing
authorlbessard
Fri, 04 Jan 2008 17:49:17 +0100
changeset 144 b67a5de5a24a
parent 143 015a34da60eb
child 145 4fb225afddf4
Adding optimization on Viewer redrawing
A lots of bugs fixed
LDViewer.py
PLCControler.py
PLCOpenEditor.py
SFCViewer.py
Viewer.py
graphics/FBD_Objects.py
graphics/GraphicCommons.py
graphics/LD_Objects.py
graphics/SFC_Objects.py
--- a/LDViewer.py	Fri Jan 04 17:47:58 2008 +0100
+++ b/LDViewer.py	Fri Jan 04 17:49:17 2008 +0100
@@ -332,11 +332,10 @@
                             elt.SetSelectedSegment(None)
                     self.SelectedElement.SetSelected(False)
                     self.SelectedElement = None
-                self.Refresh()
             if element:
                 self.SelectedElement = element
                 self.SelectedElement.OnLeftDown(event, dc, self.Scaling)
-                self.Refresh()
+                self.SelectedElement.Refresh()
             else:
                 self.rubberBand.Reset()
                 self.rubberBand.OnLeftDown(event, dc, self.Scaling)
@@ -353,7 +352,6 @@
                     self.SelectedElement = Graphic_Group(self)
                     self.SelectedElement.SetElements(elements)
                     self.SelectedElement.SetSelected(True)
-                    self.Refresh()
         elif self.Mode == MODE_SELECTION and self.SelectedElement:
             dc = self.GetLogicalDC() 
             if not isinstance(self.SelectedElement, Graphic_Group):
@@ -371,9 +369,8 @@
                             element.SetSelectedSegment(result[0])
                     else:
                         element.OnLeftUp(event, dc, self.Scaling)
+            self.SelectedElement.Refresh()
             wx.CallAfter(self.SetCursor, wx.NullCursor)
-            self.ReleaseMouse()
-            self.Refresh()
         event.Skip()
 
     def OnViewerRightUp(self, event):
@@ -392,9 +389,8 @@
                 else:
                     self.SelectedElement.SetSelected(True)
                     self.SelectedElement.OnRightUp(event, dc, self.Scaling)
+                    self.SelectedElement.Refresh()
                 wx.CallAfter(self.SetCursor, wx.NullCursor)
-                self.ReleaseMouse()
-                self.Refresh()
         event.Skip()
 
     def OnViewerLeftDClick(self, event):
@@ -402,7 +398,7 @@
             Viewer.OnViewerLeftDClick(self, event)
         elif self.Mode == MODE_SELECTION and self.SelectedElement:
             self.SelectedElement.OnLeftDClick(event, self.GetLogicalDC(), self.Scaling)
-            self.Refresh()
+            self.SelectedElement.Refresh()
         event.Skip()
 
     def OnViewerMotion(self, event):
@@ -1215,7 +1211,7 @@
                 contact.RefreshModel(False)
                 self.RefreshBuffer()
                 self.RefreshScrollBars()
-                self.Refresh()
+                contact.Refresh()
             dialog.Destroy()
 
     def EditCoilContent(self, coil):
@@ -1241,7 +1237,7 @@
                 coil.RefreshModel(False)
                 self.RefreshBuffer()
                 self.RefreshScrollBars()
-                self.Refresh()
+                coil.Refresh()
             dialog.Destroy()
 
     def EditPowerRailContent(self, powerrail):
--- a/PLCControler.py	Fri Jan 04 17:47:58 2008 +0100
+++ b/PLCControler.py	Fri Jan 04 17:49:17 2008 +0100
@@ -1463,9 +1463,11 @@
                     connector = {}
                     connector["position"] = connection.getRelPosition()
                     connector["links"] = []
-                    for link in connection.getConnections():
-                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
-                        connector["links"].append(dic)
+                    connections = connection.getConnections()
+                    if connections:
+                        for link in connection.getConnections():
+                            dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints(),"formalParameter":link.getFormalParameter()}
+                            connector["links"].append(dic)
                     infos["connectors"].append(connector)
             elif isinstance(instance, plcopen.contact):
                 infos["name"] = instance.getVariable()
--- a/PLCOpenEditor.py	Fri Jan 04 17:47:58 2008 +0100
+++ b/PLCOpenEditor.py	Fri Jan 04 17:49:17 2008 +0100
@@ -518,7 +518,7 @@
             notebook = self.GetNotebook()
             if notebook is not None:
                 for idx in xrange(notebook.GetPageCount()):
-                    notebook.DeletePage(idx)
+                    notebook.DeletePage(0)
         else:
             self.TabsOpened.DeleteAllPages()
 
@@ -633,7 +633,10 @@
             window = self.GetPage(selected)
             window.RefreshView()
             if variablepanel:
-                self.VariablePanelIndexer.RefreshVariablePanel(window.GetTagName())
+                self.RefreshVariablePanel(window.GetTagName())
+
+    def RefreshVariablePanel(self, tagname):
+        self.VariablePanelIndexer.RefreshVariablePanel(tagname)
 
     def ShowProperties(self):
         old_values = self.Controler.GetProjectProperties()
@@ -684,6 +687,14 @@
         event.Skip()
 
     def OnOpenProjectMenu(self, event):
+        if not self.Controler.ProjectIsSaved():
+            dialog = wx.MessageDialog(self, "There are changes, do you want to save?", "Close Application", wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION)
+            answer = dialog.ShowModal()
+            dialog.Destroy()
+            if answer == wx.ID_YES:
+                self.SaveProject()
+            elif answer == wx.ID_CANCEL:
+                return
         filepath = self.Controler.GetFilePath()
         if filepath != "":
             directory = os.path.dirname(filepath)
@@ -693,8 +704,9 @@
         if dialog.ShowModal() == wx.ID_OK:
             filepath = dialog.GetPath()
             if os.path.isfile(filepath):
+                self.DeleteAllPages()
+                self.VariablePanelIndexer.RemoveAllPanels()
                 self.Controler.OpenXMLFile(filepath)
-                self.DeleteAllPages()
                 self.RefreshProjectTree()
             self.RefreshTitle()
             self.RefreshFileMenu()
@@ -721,6 +733,14 @@
         event.Skip()
     
     def OnCloseProjectMenu(self, event):
+        if not self.Controler.ProjectIsSaved():
+            dialog = wx.MessageDialog(self, "There are changes, do you want to save?", "Close Application", wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION)
+            answer = dialog.ShowModal()
+            dialog.Destroy()
+            if answer == wx.ID_YES:
+                self.SaveProject()
+            elif answer == wx.ID_CANCEL:
+                return
         self.DeleteAllPages()
         self.VariablePanelIndexer.RemoveAllPanels()
         self.ProjectTree.DeleteAllItems()
@@ -2428,8 +2448,13 @@
         self.PouNames = []
         self.PouElementNames = []
         
-        self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetAffirmativeButton().GetId())
-        
+        if wx.VERSION >= (2, 8, 0):
+            self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(2).GetSizer().GetItem(1).GetSizer().GetAffirmativeButton().GetId())
+        elif wx.VERSION >= (2, 6, 0):
+            self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetAffirmativeButton().GetId())
+        else:
+            self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetChildren()[0].GetSizer().GetChildren()[0].GetWindow().GetId())
+    
     def OnOK(self, event):
         config_name = self.GetSizer().GetItem(1).GetWindow().GetValue()
         if config_name == "":
@@ -2486,8 +2511,13 @@
         self.PouNames = []
         self.PouElementNames = []
         
-        self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetAffirmativeButton().GetId())
-        
+        if wx.VERSION >= (2, 8, 0):
+            self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(2).GetSizer().GetItem(1).GetSizer().GetAffirmativeButton().GetId())
+        elif wx.VERSION >= (2, 6, 0):
+            self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetAffirmativeButton().GetId())
+        else:
+            self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetChildren()[0].GetSizer().GetChildren()[0].GetWindow().GetId())
+
     def OnOK(self, event):
         resource_name = self.GetSizer().GetItem(1).GetWindow().GetValue()
         if resource_name == "":
--- a/SFCViewer.py	Fri Jan 04 17:47:58 2008 +0100
+++ b/SFCViewer.py	Fri Jan 04 17:49:17 2008 +0100
@@ -212,11 +212,10 @@
                     else:
                         self.SelectedElement.SetSelected(False)
                     self.SelectedElement = None
-                    self.Refresh()
                 if element:
                     self.SelectedElement = element
                     self.SelectedElement.OnLeftDown(event, dc, self.Scaling)
-                    self.Refresh()
+                    self.SelectedElement.Refresh()
                 else:
                     self.rubberBand.Reset()
                     self.rubberBand.OnLeftDown(event, dc, self.Scaling)
@@ -234,7 +233,6 @@
             if self.SelectedElement:
                 self.SelectedElement.SetSelected(False)
             self.SelectedElement = wire
-            self.Refresh()
         event.Skip()
 
     def OnViewerLeftUp(self, event):
@@ -248,7 +246,6 @@
                     self.SelectedElement = Graphic_Group(self)
                     self.SelectedElement.SetElements(elements)
                     self.SelectedElement.SetSelected(True)
-                    self.Refresh()
             elif self.Mode == MODE_COMMENT:
                 bbox = self.rubberBand.GetCurrentExtent()
                 self.rubberBand.OnLeftUp(event, self.GetLogicalDC(), self.Scaling)
@@ -260,16 +257,14 @@
                 self.SelectedElement.SetSelectedSegment(0)
             else:
                 self.SelectedElement.OnLeftUp(event, self.GetLogicalDC(), self.Scaling)
+                self.SelectedElement.Refresh()
             wx.CallAfter(self.SetCursor, wx.NullCursor)
-            self.ReleaseMouse()
-            self.Refresh()
         elif self.Mode == MODE_WIRE and self.SelectedElement:
             self.SelectedElement.ResetPoints()
             self.SelectedElement.OnMotion(event, self.GetLogicalDC(), self.Scaling)
             self.SelectedElement.GeneratePoints()
             self.SelectedElement.RefreshModel()
             self.SelectedElement.SetSelected(True)
-            self.Refresh()
         event.Skip()
     
     def OnViewerRightUp(self, event):
@@ -288,9 +283,8 @@
                 else:
                     self.SelectedElement.SetSelected(True)
                     self.SelectedElement.OnRightUp(event, dc, self.Scaling)
+                    self.SelectedElement.Refresh()
                 wx.CallAfter(self.SetCursor, wx.NullCursor)
-                self.ReleaseMouse()
-                self.Refresh()
         event.Skip()
     
     def OnViewerLeftDClick(self, event):
@@ -310,12 +304,12 @@
             elif self.Mode == MODE_SELECTION and self.SelectedElement:
                 if not self.IsWire(self.SelectedElement) and not isinstance(self.SelectedElement, Graphic_Group):
                     self.SelectedElement.OnMotion(event, self.GetLogicalDC(), self.Scaling)
-                self.Refresh()
+                    self.SelectedElement.Refresh()
             elif self.Mode == MODE_WIRE and self.SelectedElement:
                 self.SelectedElement.ResetPoints()
                 self.SelectedElement.OnMotion(event, self.GetLogicalDC(), self.Scaling)
                 self.SelectedElement.GeneratePoints()
-                self.Refresh()
+                self.SelectedElement.Refresh()
             self.UpdateScrollPos(event)
         event.Skip()
 
@@ -348,7 +342,7 @@
                 self.SelectedElement.RefreshModel()
                 self.RefreshBuffer()
                 self.RefreshScrollBars()
-                self.Refresh()
+                self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(-scaling[0], 0)))
         elif keycode == wx.WXK_RIGHT:
             if event.ControlDown() and event.ShiftDown():
                 self.Scroll(xmax, ypos)
@@ -359,7 +353,7 @@
                 self.SelectedElement.RefreshModel()
                 self.RefreshBuffer()
                 self.RefreshScrollBars()
-                self.Refresh()
+                self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(scaling[0], 0)))
         elif keycode == wx.WXK_UP:
             if event.ControlDown() and event.ShiftDown():
                 self.Scroll(xpos, 0)
@@ -370,7 +364,7 @@
                 self.SelectedElement.RefreshModel()
                 self.RefreshBuffer()
                 self.RefreshScrollBars()
-                self.Refresh()
+                self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(0, -scaling[1])))
         elif keycode == wx.WXK_DOWN:
             if event.ControlDown() and event.ShiftDown():
                 self.Scroll(xpos, ymax)
@@ -381,7 +375,7 @@
                 self.SelectedElement.RefreshModel()
                 self.RefreshBuffer()
                 self.RefreshScrollBars()
-                self.Refresh()
+                self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(0, scaling[1])))
         else:
             event.Skip()
         
--- a/Viewer.py	Fri Jan 04 17:47:58 2008 +0100
+++ b/Viewer.py	Fri Jan 04 17:49:17 2008 +0100
@@ -104,7 +104,7 @@
                 self.ParentWindow.RefreshBlockModel(block)
                 self.ParentWindow.RefreshBuffer()
                 self.ParentWindow.RefreshScrollBars()
-                self.ParentWindow.ParentWindow.RefreshEditor()
+                self.ParentWindow.ParentWindow.RefreshVariablePanel(self.TagName)
                 self.ParentWindow.Refresh()
         elif values[1] != "location":
             if values[3] == self.ParentWindow.GetTagName():
@@ -297,9 +297,12 @@
         self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveViewer)
         self.Bind(wx.EVT_MOTION, self.OnViewerMotion)
         self.Bind(wx.EVT_CHAR, self.OnChar)
-        if wx.VERSION < (2, 7, 0):
-            self.Bind(wx.EVT_SCROLLWIN, self.OnMoveWindow)
-            self.Bind(wx.EVT_SIZE, self.OnMoveWindow)
+        self.Bind(wx.EVT_SCROLLWIN, self.OnMoveWindow)
+        self.Bind(wx.EVT_SIZE, self.OnMoveWindow)
+    
+    def GetScrolledRect(self, rect):
+        rect.x, rect.y = self.CalcScrolledPosition(rect.x, rect.y)
+        return rect
     
     def SetTagName(self, tagname):
         self.TagName = tagname
@@ -409,7 +412,6 @@
         if self.Mode != MODE_SELECTION and self.SelectedElement:
             self.SelectedElement.SetSelected(False)
             self.SelectedElement = None
-            self.Refresh(False)
     
     # Return current drawing mode
     def GetDrawingMode(self):
@@ -450,17 +452,16 @@
         for wire in to_delete:
             wire.Delete()
     
-        self.Refresh(False)
+        self.Refresh()
     
     def RefreshScrollBars(self):
         xstart, ystart = self.GetViewStart()
         window_size = self.GetClientSize()
         maxx = maxy = 0
         for element in self.GetElements():
-            posx, posy = element.GetPosition()
-            width, height = element.GetSize()
-            maxx = max(maxx, posx + width)
-            maxy = max(maxy, posy + height)
+            bbox = element.GetBoundingBox()
+            maxx = max(maxx, bbox.x + bbox.width)
+            maxy = max(maxy, bbox.y + bbox.height)
         maxx = max(maxx + WINDOW_BORDER, xstart * SCROLLBAR_UNIT + window_size[0])
         maxy = max(maxy + WINDOW_BORDER, ystart * SCROLLBAR_UNIT + window_size[1])
         if self.rubberBand.IsShown():
@@ -1017,9 +1018,10 @@
                         element = self.SelectedElement
                         self.RefreshBuffer()
                     else:
+                        rect = self.SelectedElement.GetRedrawRect()
                         self.SelectedElement.Delete()
                         element = None
-                    self.Refresh(False)
+                        self.RefreshRect(self.GetScrolledRect(rect))
                 elif connector:
                     self.DrawingWire = True
                     pos = GetScaledEventPosition(event, self.GetLogicalDC(), self.Scaling)
@@ -1035,15 +1037,15 @@
                     if self.SelectedElement:
                         self.SelectedElement.SetSelected(False)
                     self.SelectedElement = wire
+                    self.SelectedElement.Refresh()
                 else:
                     if self.SelectedElement and self.SelectedElement != element:
                         self.SelectedElement.SetSelected(False)
                         self.SelectedElement = None
-                        self.Refresh(False)
                     if element:
                         self.SelectedElement = element
                         self.SelectedElement.OnLeftDown(event, dc, self.Scaling)
-                        self.Refresh(False)
+                        self.SelectedElement.Refresh()
                     else:
                         self.rubberBand.Reset()
                         self.rubberBand.OnLeftDown(event, dc, self.Scaling)
@@ -1062,12 +1064,10 @@
                 if len(elements) == 1:
                     self.SelectedElement = elements[0]
                     self.SelectedElement.SetSelected(True)
-                    self.Refresh(False)
                 elif len(elements) > 1:
                     self.SelectedElement = Graphic_Group(self)
                     self.SelectedElement.SetElements(elements)
                     self.SelectedElement.SetSelected(True)
-                    self.Refresh(False)
             else:
                 bbox = self.rubberBand.GetCurrentExtent()
                 self.rubberBand.OnLeftUp(event, self.GetLogicalDC(), self.Scaling)                
@@ -1110,15 +1110,16 @@
                     self.SelectedElement.RefreshModel()
                     self.SelectedElement.SetSelected(True)
                     self.RefreshBuffer()
-                elif connector is None:
+                elif connector is None or self.SelectedElement.GetDragging():
                     self.DrawingWire = False
+                    rect = self.SelectedElement.GetRedrawRect()
                     self.SelectedElement.Delete()
                     self.SelectedElement = None
-                self.Refresh(False)
+                    self.RefreshRect(self.GetScrolledRect(rect))
             else:
                 self.SelectedElement.OnLeftUp(event, dc, self.Scaling)
                 wx.CallAfter(self.SetCursor, wx.NullCursor)
-                self.Refresh(False)
+                self.SelectedElement.Refresh()
         if self.Mode != MODE_SELECTION and not self.SavedMode:
             wx.CallAfter(self.ParentWindow.ResetCurrentMode)
         event.Skip()
@@ -1134,7 +1135,6 @@
             self.SelectedElement.SetSelected(True)
             self.SelectedElement.OnRightUp(event, self.GetLogicalDC(), self.Scaling)
             wx.CallAfter(self.SetCursor, wx.NullCursor)
-            self.Refresh(False)
         else:
             self.PopupDefaultMenu(False)
         event.Skip()
@@ -1145,7 +1145,6 @@
                 self.ParentWindow.EditProjectElement(ITEM_POU, self.SelectedElement.GetType())
             else:
                 self.SelectedElement.OnLeftDClick(event, self.GetLogicalDC(), self.Scaling)
-                self.Refresh(False)
         event.Skip()
     
     def OnViewerMotion(self, event):
@@ -1155,12 +1154,11 @@
         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
-                refresh = True
-            if highlighted is not None:
+            if highlighted is not None and self.HighlightedElement != highlighted:
                 highlighted.SetHighlighted(True)
-                refresh = True
             self.HighlightedElement = highlighted
         if self.rubberBand.IsShown():
             self.rubberBand.OnMotion(event, dc, self.Scaling)
@@ -1169,21 +1167,23 @@
                 connector = self.FindBlockConnector(pos, False)
                 if not connector or self.SelectedElement.EndConnected == None:
                     self.SelectedElement.ResetPoints()
-                    self.SelectedElement.OnMotion(event, dc, self.Scaling)
+                    movex, movey = self.SelectedElement.OnMotion(event, dc, self.Scaling)
                     self.SelectedElement.GeneratePoints()
-                    refresh = True
-            elif self.SelectedElement.OnMotion(event, dc, self.Scaling):
-                refresh = True
+                    if movex != 0 or movey != 0:
+                        self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(movex, movey)))
+            else:
+                movex, movey = self.SelectedElement.OnMotion(event, dc, self.Scaling)
+                if movex != 0 or movey != 0:
+                    self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(movex, movey)))
         self.UpdateScrollPos(event)
-        if refresh:
-            self.Refresh(False)
         event.Skip()
 
     def OnLeaveViewer(self, event):
-        if self.HighlightedElement is not None:
+        if self.SelectedElement and self.SelectedElement.GetDragging():
+            event.Skip()
+        elif self.HighlightedElement is not None:
             self.HighlightedElement.SetHighlighted(False)
             self.HighlightedElement = None
-            self.Refresh(False)
         event.Skip()
 
     def UpdateScrollPos(self, event):
@@ -1218,13 +1218,13 @@
         else:
             scaling = (8, 8)
         if keycode == wx.WXK_DELETE and self.SelectedElement:
-            self.SelectedElement.Clean()
+            rect = self.SelectedElement.GetRedrawRect(1, 1)
             self.SelectedElement.Delete()
             self.SelectedElement = None
             self.RefreshBuffer()
             self.RefreshScrollBars()
             self.SetCursor(wx.NullCursor)
-            self.Refresh(False)
+            self.RefreshRect(self.GetScrolledRect(rect))
         elif keycode == wx.WXK_RETURN and self.SelectedElement:
             self.SelectedElement.OnLeftDClick(event, self.GetLogicalDC(), self.Scaling)
         elif keycode == wx.WXK_LEFT:
@@ -1237,7 +1237,7 @@
                 self.SelectedElement.RefreshModel()
                 self.RefreshBuffer()
                 self.RefreshScrollBars()
-                self.Refresh(False)
+                self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(-scaling[0], 0)))
         elif keycode == wx.WXK_RIGHT:
             if event.ControlDown() and event.ShiftDown():
                 self.Scroll(xmax, ypos)
@@ -1248,7 +1248,7 @@
                 self.SelectedElement.RefreshModel()
                 self.RefreshBuffer()
                 self.RefreshScrollBars()
-                self.Refresh(False)
+                self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(scaling[0], 0)))
         elif keycode == wx.WXK_UP:
             if event.ControlDown() and event.ShiftDown():
                 self.Scroll(xpos, 0)
@@ -1259,7 +1259,7 @@
                 self.SelectedElement.RefreshModel()
                 self.RefreshBuffer()
                 self.RefreshScrollBars()
-                self.Refresh(False)
+                self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(0, -scaling[1])))
         elif keycode == wx.WXK_DOWN:
             if event.ControlDown() and event.ShiftDown():
                 self.Scroll(xpos, ymax)
@@ -1270,12 +1270,13 @@
                 self.SelectedElement.RefreshModel()
                 self.RefreshBuffer()
                 self.RefreshScrollBars()
-                self.Refresh(False)
+                self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(0, scaling[1])))
         elif keycode == wx.WXK_SPACE and self.SelectedElement is not None and self.SelectedElement.Dragging:
-            self.CopyBlock(self.SelectedElement, self.SelectedElement.Pos)
-            self.RefreshBuffer()
-            self.RefreshScrollBars()
-            self.Refresh()
+            self.CopyBlock(self.SelectedElement, wx.Point(*self.SelectedElement.GetPosition()))
+            self.RefreshBuffer()
+            self.RefreshScrollBars()
+            self.ParentWindow.RefreshVariablePanel(self.TagName)
+            self.SelectedElement.Refresh()
         else:
             event.Skip()
 
@@ -1303,8 +1304,8 @@
             self.RefreshBlockModel(block)
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.ParentWindow.RefreshEditor()
-            self.Refresh(False)
+            self.ParentWindow.RefreshVariablePanel(self.TagName)
+            block.Refresh()
         dialog.Destroy()
     
     def AddNewVariable(self, bbox):
@@ -1331,7 +1332,7 @@
             self.RefreshVariableModel(variable)
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh(False)
+            variable.Refresh()
         dialog.Destroy()
 
     def AddNewConnection(self, bbox):
@@ -1348,7 +1349,7 @@
             self.RefreshConnectionModel(connection)
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh(False)
+            connection.Refresh()
         dialog.Destroy()
 
     def AddNewComment(self, bbox):
@@ -1368,7 +1369,7 @@
             self.RefreshCommentModel(comment)
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh(False)
+            comment.Refresh()
         dialog.Destroy()
 
     def AddNewContact(self, bbox):
@@ -1393,7 +1394,7 @@
             self.RefreshContactModel(contact)
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh(False)
+            contact.Refresh()
         dialog.Destroy()
 
     def AddNewCoil(self, bbox):
@@ -1421,7 +1422,7 @@
             self.RefreshCoilModel(coil)
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh(False)
+            coil.Refresh()
         dialog.Destroy()
 
     def AddNewPowerRail(self, bbox):
@@ -1438,7 +1439,7 @@
             self.RefreshPowerRailModel(powerrail)
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh(False)
+            powerrail.Refresh()
         dialog.Destroy()
 
     def AddNewStep(self, bbox, initial = False):
@@ -1471,7 +1472,7 @@
             self.RefreshStepModel(step)
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh(False)
+            step.Refresh()
         dialog.Destroy()
 
     def AddNewTransition(self, bbox):
@@ -1489,7 +1490,7 @@
             self.RefreshTransitionModel(transition)
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh(False)
+            transition.Refresh()
         dialog.Destroy()
 
     def AddNewDivergence(self, bbox):
@@ -1507,7 +1508,7 @@
             self.RefreshDivergenceModel(divergence)
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh(False)
+            divergence.Refresh()
         dialog.Destroy()
 
     def AddNewJump(self, bbox):
@@ -1528,7 +1529,7 @@
             self.RefreshJumpModel(jump)
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh()
+            jump.Refresh()
         dialog.Destroy()
 
     def AddNewActionBlock(self, bbox):
@@ -1548,7 +1549,7 @@
             self.RefreshActionBlockModel(actionblock)
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh()
+            actionblock.Refresh()
         dialog.Destroy()
 
 #-------------------------------------------------------------------------------
@@ -1579,8 +1580,8 @@
                 self.RefreshView()
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.ParentWindow.RefreshEditor()
-            self.Refresh(False)
+            self.ParentWindow.RefreshVariablePanel(self.TagName)
+            block.Refresh()
         dialog.Destroy()
 
     def EditVariableContent(self, variable):
@@ -1614,7 +1615,7 @@
                 self.RefreshView()
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh(False)
+            variable.Refresh()
         dialog.Destroy()
 
     def EditConnectionContent(self, connection):
@@ -1635,7 +1636,7 @@
             self.RefreshConnectionModel(connection)
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh(False)
+            connection.Refresh()
         dialog.Destroy()
 
     def EditContactContent(self, contact):
@@ -1658,7 +1659,7 @@
             self.RefreshContactModel(contact)
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh(False)
+            contact.Refresh()
         dialog.Destroy()
 
     def EditCoilContent(self, coil):
@@ -1684,7 +1685,7 @@
             self.RefreshCoilModel(coil)
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh(False)
+            coil.Refresh()
         dialog.Destroy()
 
     def EditPowerRailContent(self, powerrail):
@@ -1702,7 +1703,7 @@
             self.RefreshPowerRailModel(powerrail)
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh(False)
+            powerrail.Refresh()
         dialog.Destroy()
 
     def EditStepContent(self, step):
@@ -1736,7 +1737,7 @@
             step.RefreshModel()
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh(False)
+            step.Refresh()
         
     def EditTransitionContent(self, transition):
         dialog = TransitionContentDialog(self.ParentWindow, self.GetDrawingMode() == FREEDRAWING_MODE)
@@ -1750,7 +1751,7 @@
             transition.RefreshModel()
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh(False)
+            transition.Refresh()
         dialog.Destroy()
 
     def EditJumpContent(self, jump):
@@ -1766,7 +1767,7 @@
             jump.RefreshModel()
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh(False)
+            jump.Refresh()
         dialog.Destroy()
 
     def EditActionBlockContent(self, actionblock):
@@ -1781,7 +1782,7 @@
             actionblock.RefreshModel()
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh(False)
+            actionblock.Refresh()
         dialog.Destroy()
 
     def EditCommentContent(self, comment):
@@ -1795,7 +1796,7 @@
             comment.RefreshModel()
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh(False)
+            comment.Refresh()
         dialog.Destroy()
 
 #-------------------------------------------------------------------------------
@@ -1933,7 +1934,7 @@
         self.Controler.RemoveEditedElementInstance(self.TagName, block.GetId())
         for element in elements:
             element.RefreshModel()
-        wx.CallAfter(self.ParentWindow.RefreshEditor)
+        wx.CallAfter(self.ParentWindow.RefreshVariablePanel, self.TagName)
 
     def DeleteVariable(self, variable):
         connectors = variable.GetConnectors()
@@ -2062,15 +2063,17 @@
     def Cut(self):
         if self.IsBlock(self.SelectedElement):
             self.ParentWindow.SetCopyBuffer(self.SelectedElement.Clone())
+            rect = self.SelectedElement.GetRedrawRect(1, 1)
             self.SelectedElement.Delete()
-            self.RefreshBuffer()
-            self.RefreshScrollBars()
-            self.Refresh()
+            self.SelectedElement = None
+            self.RefreshBuffer()
+            self.RefreshScrollBars()
+            self.RefreshRect(self.GetScrolledRect(rect))
         
     def Copy(self):
         if self.IsBlock(self.SelectedElement):
             self.ParentWindow.SetCopyBuffer(self.SelectedElement.Clone())
-    
+            
     def Paste(self):
         element = self.ParentWindow.GetCopyBuffer()
         if element is not None and self.CanAddBlock(element):
@@ -2081,7 +2084,7 @@
             self.SelectedElement.SetSelected(True)
             self.RefreshBuffer()
             self.RefreshScrollBars()
-            self.Refresh()
+            self.ParentWindow.RefreshVariablePanel(self.TagName)
 
     def CanAddBlock(self, block):
         if self.CurrentLanguage == "SFC":
@@ -2094,13 +2097,27 @@
 
     def CopyBlock(self, element, pos):
         id = self.GetNewId()
-        block = element.Clone(id, pos)
+        if isinstance(element, FBD_Block) and element.GetName() != "" or isinstance(element, SFC_Step):
+            if isinstance(element, FBD_Block):
+                names = [varname.upper() for varname in self.Controler.GetEditedElementVariables(self.TagName)]
+                format = "Block%d"
+            elif isinstance(element, SFC_Step):
+                names = [block.GetName().upper() for block in self.Blocks if isinstance(block, SFC_Step)]
+                format = "Step%d"
+            i = 1
+            while (format%i).upper() in names:
+                i += 1
+            name = format%i
+            block = element.Clone(id, name, pos)
+        else:
+            name = None
+            block = element.Clone(id, pos=pos)
         self.AddBlock(block)
         if isinstance(block, Comment):
             self.Controler.AddEditedElementComment(self.TagName, id)
-            self.RefreshCommentModel(comment)
+            self.RefreshCommentModel(block)
         elif isinstance(block, FBD_Block):
-            self.Controler.AddEditedElementBlock(self.TagName, id, block.GetType(), None)
+            self.Controler.AddEditedElementBlock(self.TagName, id, block.GetType(), name)
             self.RefreshBlockModel(block)
         elif isinstance(block, FBD_Variable):
             self.Controler.AddEditedElementVariable(self.TagName, id, block.GetType())
@@ -2156,14 +2173,6 @@
             for i in xrange(1, height / self.Scaling[1] + 1):
                 dc.DrawLine(0, i * self.Scaling[1], width, i * self.Scaling[1])
         
-        # Draw highlighted elements
-        for comment in self.Comments:
-            comment.DrawHighlightment(dc)
-        for wire in self.Wires:
-            wire.DrawHighlightment(dc)
-        for block in self.Blocks:
-            block.DrawHighlightment(dc)
-        
         # Draw all elements
         for comment in self.Comments:
             if comment != self.SelectedElement:
@@ -2174,6 +2183,7 @@
         for block in self.Blocks:
             if block != self.SelectedElement:
                 block.Draw(dc)
+        
         if self.SelectedElement:
             self.SelectedElement.Draw(dc)
         
--- a/graphics/FBD_Objects.py	Fri Jan 04 17:47:58 2008 +0100
+++ b/graphics/FBD_Objects.py	Fri Jan 04 17:49:17 2008 +0100
@@ -54,6 +54,8 @@
     
     # Make a clone of this FBD_Block
     def Clone(self, id = None, name = "", pos = None):
+        if self.Name != "" and name == "":
+            name = self.Name
         block = FBD_Block(self.Parent, self.Type, name, id, self.Extension)
         block.SetSize(self.Size[0], self.Size[1])
         if pos is not None:
@@ -67,6 +69,18 @@
         self.Inputs = []
         self.Outputs = []
     
+    # Returns the RedrawRect
+    def GetRedrawRect(self, movex = 0, movey = 0):
+        rect = Graphic_Element.GetRedrawRect(self, movex, movey)
+        if movex != 0 or movey != 0:
+            for input in self.Inputs:
+                if input.IsConnected():
+                    rect = rect.Union(input.GetConnectedRedrawRect(movex, movey))
+            for output in self.Outputs:
+                if output.IsConnected():
+                    rect = rect.Union(output.GetConnectedRedrawRect(movex, movey))
+        return rect
+    
     # Delete this block by calling the appropriate method
     def Delete(self):
         self.Parent.DeleteBlock(self)
@@ -172,7 +186,7 @@
                     resulttype = inputtype
         for output in self.Outputs:
             name = output.GetName()
-            if output != connector and name == "OUT":
+            if output != connector and name == "OUT" and not IsEndType(output.GetType()):
                 outputtype = output.GetConnectedType()
                 if resulttype is None or outputtype is not None and IsOfType(outputtype, resulttype):
                     resulttype = outputtype
@@ -338,6 +352,7 @@
     
     # Draws block
     def Draw(self, dc):
+        Graphic_Element.Draw(self, dc)
         dc.SetPen(self.Pen)
         dc.SetBrush(wx.WHITE_BRUSH)
         dc.SetTextForeground(self.Colour)
@@ -358,7 +373,6 @@
             dc.DrawText(str(self.ExecutionOrder), self.Pos.x + self.Size[0] - self.ExecutionOrderSize[0],
                     self.Pos.y + self.Size[1] + 2)
         dc.SetTextForeground(wx.BLACK)
-        Graphic_Element.Draw(self, dc)
         
 
 #-------------------------------------------------------------------------------
@@ -389,8 +403,10 @@
         variable.SetSize(self.Size[0], self.Size[1])
         if pos is not None:
             variable.SetPosition(pos.x, pos.y)
-        variable.Input = self.Input.Clone(variable)
-        variable.Output = self.Output.Clone(variable)
+        if self.Input:
+            variable.Input = self.Input.Clone(variable)
+        if self.Output:
+            variable.Output = self.Output.Clone(variable)
         return variable
     
     # Destructor
@@ -398,6 +414,16 @@
         self.Input = None
         self.Output = None
     
+    # Returns the RedrawRect
+    def GetRedrawRect(self, movex = 0, movey = 0):
+        rect = Graphic_Element.GetRedrawRect(self, movex, movey)
+        if movex != 0 or movey != 0:
+            if self.Input and self.Input.IsConnected():
+                rect = rect.Union(self.Input.GetConnectedRedrawRect(movex, movey))
+            if self.Output and self.Output.IsConnected():
+                rect = rect.Union(self.Output.GetConnectedRedrawRect(movex, movey))
+        return rect
+    
     # Unconnect connector
     def Clean(self):
         if self.Input:
@@ -557,6 +583,7 @@
     
     # Draws variable
     def Draw(self, dc):
+        Graphic_Element.Draw(self, dc)
         dc.SetPen(wx.BLACK_PEN)
         dc.SetBrush(wx.WHITE_BRUSH)
         # Draw a rectangle with the variable size
@@ -573,7 +600,6 @@
             # Draw variable execution order
             dc.DrawText(str(self.ExecutionOrder), self.Pos.x + self.Size[0] - self.ExecutionOrderSize[0],
                     self.Pos.y + self.Size[1] + 2)
-        Graphic_Element.Draw(self, dc)
 
 
 #-------------------------------------------------------------------------------
@@ -606,6 +632,14 @@
     def __del__(self):
         self.Connector = None
     
+    # Returns the RedrawRect
+    def GetRedrawRect(self, movex = 0, movey = 0):
+        rect = Graphic_Element.GetRedrawRect(self, movex, movey)
+        if movex != 0 or movey != 0:
+            if self.Connector and self.Connector.IsConnected():
+                rect = rect.Union(self.Connector.GetConnectedRedrawRect(movex, movey))
+        return rect
+    
     # Make a clone of this FBD_Connector
     def Clone(self, id = None, pos = None):
         connection = FBD_Connector(self.Parent, self.Type, self.Name, id)
@@ -714,6 +748,7 @@
     
     # Draws connection
     def Draw(self, dc):
+        Graphic_Element.Draw(self, dc)
         dc.SetPen(wx.BLACK_PEN)
         dc.SetBrush(wx.WHITE_BRUSH)
         # Draw a rectangle with the connection size with arrows in 
@@ -733,5 +768,4 @@
         # Draw connector
         if self.Connector:
             self.Connector.Draw(dc)
-        Graphic_Element.Draw(self, dc)
         
--- a/graphics/GraphicCommons.py	Fri Jan 04 17:47:58 2008 +0100
+++ b/graphics/GraphicCommons.py	Fri Jan 04 17:49:17 2008 +0100
@@ -48,6 +48,7 @@
 LD_ELEMENT_SIZE = (21, 15)              # Size (width, height) of a ladder element (contact or coil)
 LD_WIRE_SIZE = 30                       # Size of a wire between two contact
 LD_WIRECOIL_SIZE = 70                   # Size of a wire between a coil and a contact
+LD_POWERRAIL_WIDTH = 3                  # Width of a Powerrail
 LD_OFFSET = (10, 10)                    # Distance (x, y) between each comment and rung of the ladder
 LD_COMMENT_DEFAULTSIZE = (600, 40)      # Size (width, height) of a comment box
 
@@ -298,6 +299,9 @@
         self.CurrentCursor = 0
         ResetCursors()
     
+    def GetDragging(self):
+        return self.Dragging
+    
     # Make a clone of this element
     def Clone(self):
         return Graphic_Element(self.Parent, self.Id)
@@ -365,13 +369,27 @@
     def GetBoundingBox(self):
         return self.BoundingBox
     
+    # Returns the RedrawRect
+    def GetRedrawRect(self, movex = 0, movey = 0):
+        rect = wx.Rect()
+        rect.x = self.BoundingBox.x - HANDLE_SIZE - 2 - abs(movex)
+        rect.y = self.BoundingBox.y - HANDLE_SIZE - 2 - abs(movey)
+        rect.width = self.BoundingBox.width + 2 * (HANDLE_SIZE + abs(movex)) + 4
+        rect.height = self.BoundingBox.height + 2 * (HANDLE_SIZE + abs(movey)) + 4
+        return rect
+    
+    def Refresh(self, rect = None):
+        self.Parent.RefreshRect(self.Parent.GetScrolledRect(self.GetRedrawRect()))
+    
     # Change the variable that indicates if this element is selected
     def SetSelected(self, selected):
         self.Selected = selected
+        self.Refresh()
     
     # Change the variable that indicates if this element is highlighted
     def SetHighlighted(self, highlighted):
         self.Highlighted = highlighted
+        self.Refresh()
     
     # Test if the point is on a handle of this element
     def TestHandle(self, pt):
@@ -465,7 +483,8 @@
                 dragx, dragy = self.ProcessDragging(movex, movey)
                 self.oldPos.x += dragx
                 self.oldPos.y += dragy
-            return True
+                return dragx, dragy
+            return movex, movey
         # If cursor just pass over the element, changes the cursor if it is on a handle
         else:
             pos = event.GetLogicalPosition(dc)
@@ -476,7 +495,7 @@
             if cursor != self.CurrentCursor:
                 self.Parent.SetCursor(CURSORS[cursor])
                 self.CurrentCursor = cursor
-            return False
+            return 0, 0
 
     # Moves the element
     def Move(self, dx, dy, exclude = []):
@@ -536,13 +555,16 @@
     
     # Draws the highlightment of this element if it is highlighted (can be overwritten)
     def DrawHighlightment(self, dc):
-        if self.Highlighted:
-            dc.SetPen(wx.Pen(HIGHLIGHTCOLOR))
-            dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR))
-            dc.DrawRectangle(self.Pos.x - 2, self.Pos.y - 2, self.Size.width + 5, self.Size.height + 5)
+        dc.SetPen(wx.Pen(HIGHLIGHTCOLOR))
+        dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR))
+        dc.SetLogicalFunction(wx.AND)
+        dc.DrawRectangle(self.Pos.x - 2, self.Pos.y - 2, self.Size.width + 5, self.Size.height + 5)
+        dc.SetLogicalFunction(wx.COPY)
     
     # Draws the handles of this element if it is selected
     def Draw(self, dc):
+        if self.Highlighted:
+            self.DrawHighlightment(dc)
         if self.Selected:
             dc.SetPen(wx.BLACK_PEN)
             dc.SetBrush(wx.BLACK_BRUSH)
@@ -602,6 +624,16 @@
         clone.SetElements(elements)
         return clone
     
+    # Returns the RedrawRect
+    def GetRedrawRect(self, movex = 0, movey = 0):
+        rect = None
+        for element in self.Elements:
+            if rect is None:
+                rect = element.GetRedrawRect(movex, movey)
+            else:
+                rect = rect.Union(element.GetRedrawRect(movex, movey))
+        return rect
+    
     # Clean this group of elements
     def Clean(self):
         # Clean all the elements of the group
@@ -774,6 +806,21 @@
         self.Pen = wx.BLACK_PEN
         self.RefreshNameSize()
     
+    # Returns the RedrawRect
+    def GetRedrawRect(self, movex = 0, movey = 0):
+        parent_pos = self.ParentBlock.GetPosition()
+        x = min(parent_pos[0] + self.Pos.x, parent_pos[0] + self.Pos.x + self.Direction[0] * CONNECTOR_SIZE)
+        y = min(parent_pos[1] + self.Pos.y, parent_pos[1] + self.Pos.y + self.Direction[1] * CONNECTOR_SIZE)
+        if self.Direction[0] == 0:
+            width = 5
+        else:
+            width = CONNECTOR_SIZE
+        if self.Direction[1] == 0:
+            height = 5
+        else:
+            height = CONNECTOR_SIZE
+        return wx.Rect(x - abs(movex), y - abs(movey), width + 2 * abs(movex), height + 2 * abs(movey))
+    
     # Change the connector pen
     def SetPen(self, pen):
         self.Pen = pen
@@ -806,6 +853,16 @@
             return self.Wires[0][0].GetOtherConnectedType(self.Wires[0][1])
         return self.Type
     
+    # Returns the connector type
+    def GetConnectedRedrawRect(self, movex, movey):
+        rect = None
+        for wire, handle in self.Wires:
+            if rect is None:
+                rect = wire.GetRedrawRect()
+            else:
+                rect = rect.Union(wire.GetRedrawRect())
+        return rect
+    
     # Returns if connector type is compatible with type given
     def IsCompatible(self, type):
         reference = self.GetType()
@@ -947,6 +1004,7 @@
     # Highlight the parent block
     def HighlightParentBlock(self, highlight):
         self.ParentBlock.SetHighlighted(highlight)
+        self.ParentBlock.Refresh()
     
     # Returns all the blocks connected to this connector
     def GetConnectedBlocks(self):
@@ -1001,6 +1059,7 @@
     def DrawHighlightment(self, dc):
         dc.SetPen(wx.Pen(HIGHLIGHTCOLOR))
         dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR))
+        dc.SetLogicalFunction(wx.AND)
         parent_pos = self.ParentBlock.GetPosition()
         posx = parent_pos[0] + self.Pos.x
         posy = parent_pos[1] + self.Pos.y
@@ -1017,6 +1076,7 @@
             posy -= 2
             height = 5
         dc.DrawRectangle(posx, posy, width, height)
+        dc.SetLogicalFunction(wx.COPY)
     
     # Draws the connector
     def Draw(self, dc):
@@ -1092,6 +1152,15 @@
         self.StartConnected = None
         self.EndConnected = None
     
+    # Returns the RedrawRect
+    def GetRedrawRect(self, movex = 0, movey = 0):
+        rect = Graphic_Element.GetRedrawRect(self, movex, movey)
+        if self.StartConnected:
+            rect = rect.Union(self.StartConnected.GetRedrawRect(movex, movey))
+        if self.EndConnected:
+            rect = rect.Union(self.EndConnected.GetRedrawRect(movex, movey))
+        return rect
+    
     # Forbids to change the wire position
     def SetPosition(x, y):
         pass
@@ -1175,6 +1244,7 @@
             if self.EndConnected:
                 self.EndConnected.SetPen(wx.RED_PEN)
         self.SelectedSegment = segment
+        self.Refresh()
     
     # Reinitialize the wire points
     def ResetPoints(self):
@@ -1786,7 +1856,7 @@
                     if self.CurrentCursor != 5:
                         self.CurrentCursor = 5
                         wx.CallAfter(self.Parent.SetCursor, CURSORS[5])
-                return False
+                return 0, 0
             else:
                 # Test if a point has been handled
                 #result = self.TestPoint(pos)
@@ -1865,27 +1935,29 @@
     
     # Draws the highlightment of this element if it is highlighted
     def DrawHighlightment(self, dc):
-        if self.Highlighted:
-            dc.SetPen(wx.Pen(HIGHLIGHTCOLOR))
-            dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR))
-            # Draw the start and end points if they are not connected or the mouse is over them
-            if len(self.Points) > 0 and (not self.StartConnected or self.OverStart):
-                dc.DrawCircle(self.Points[0].x, self.Points[0].y, POINT_RADIUS + 2)
-            if len(self.Points) > 1 and (not self.EndConnected or self.OverEnd):
-                dc.DrawCircle(self.Points[-1].x, self.Points[-1].y, POINT_RADIUS + 2)
-            for i in xrange(len(self.Points) - 1):
-                posx = min(self.Points[i].x, self.Points[i + 1].x) - 2
-                posy = min(self.Points[i].y, self.Points[i + 1].y) - 2
-                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)
-            if self.StartConnected is not None:
-                self.StartConnected.DrawHighlightment(dc)
-            if self.EndConnected is not None:
-                self.EndConnected.DrawHighlightment(dc)    
+        dc.SetPen(wx.Pen(HIGHLIGHTCOLOR))
+        dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR))
+        dc.SetLogicalFunction(wx.AND)
+        # Draw the start and end points if they are not connected or the mouse is over them
+        if len(self.Points) > 0 and (not self.StartConnected or self.OverStart):
+            dc.DrawCircle(self.Points[0].x, self.Points[0].y, POINT_RADIUS + 2)
+        if len(self.Points) > 1 and (not self.EndConnected or self.OverEnd):
+            dc.DrawCircle(self.Points[-1].x, self.Points[-1].y, POINT_RADIUS + 2)
+        for i in xrange(len(self.Points) - 1):
+            posx = min(self.Points[i].x, self.Points[i + 1].x) - 2
+            posy = min(self.Points[i].y, self.Points[i + 1].y) - 2
+            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)
+        if self.StartConnected is not None:
+            self.StartConnected.DrawHighlightment(dc)
+        if self.EndConnected is not None:
+            self.EndConnected.DrawHighlightment(dc)
+        dc.SetLogicalFunction(wx.COPY)
         
     # Draws the wire lines and points
     def Draw(self, dc):
+        Graphic_Element.Draw(self, dc)
         dc.SetPen(wx.BLACK_PEN)
         dc.SetBrush(wx.BLACK_BRUSH)
         # Draw the start and end points if they are not connected or the mouse is over them
@@ -1903,7 +1975,7 @@
                         self.Points[self.SelectedSegment + 1].x, self.Points[self.SelectedSegment + 1].y)
             if self.SelectedSegment == len(self.Segments) - 1:
                 dc.DrawPoint(self.Points[-1].x, self.Points[-1].y)
-        Graphic_Element.Draw(self, dc)
+
 
 #-------------------------------------------------------------------------------
 #                           Graphic comment element
@@ -2013,18 +2085,20 @@
     
     # Draws the highlightment of this element if it is highlighted
     def DrawHighlightment(self, dc):
-        if self.Highlighted:
-            dc.SetPen(wx.Pen(HIGHLIGHTCOLOR))
-            dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR))
-            polygon = [wx.Point(self.Pos.x - 2, self.Pos.y - 2), 
-                       wx.Point(self.Pos.x + self.Size[0] - 8, self.Pos.y - 2),
-                       wx.Point(self.Pos.x + self.Size[0] + 2, self.Pos.y + 8),
-                       wx.Point(self.Pos.x + self.Size[0] + 2, self.Pos.y + self.Size[1] + 2),
-                       wx.Point(self.Pos.x - 2, self.Pos.y + self.Size[1] + 2)]
-            dc.DrawPolygon(polygon)
+        dc.SetPen(wx.Pen(HIGHLIGHTCOLOR))
+        dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR))
+        dc.SetLogicalFunction(wx.AND)
+        polygon = [wx.Point(self.Pos.x - 2, self.Pos.y - 2), 
+                   wx.Point(self.Pos.x + self.Size[0] - 8, self.Pos.y - 2),
+                   wx.Point(self.Pos.x + self.Size[0] + 2, self.Pos.y + 8),
+                   wx.Point(self.Pos.x + self.Size[0] + 2, self.Pos.y + self.Size[1] + 2),
+                   wx.Point(self.Pos.x - 2, self.Pos.y + self.Size[1] + 2)]
+        dc.DrawPolygon(polygon)
+        dc.SetLogicalFunction(wx.COPY)
         
     # Draws the comment and its content
     def Draw(self, dc):
+        Graphic_Element.Draw(self, dc)
         dc.SetPen(wx.BLACK_PEN)
         dc.SetBrush(wx.WHITE_BRUSH)
         # Draws the comment shape
@@ -2069,4 +2143,3 @@
                     y += wordheight + 5
             if y + wordheight > self.Pos.y + self.Size[1] - 10:
                 break
-        Graphic_Element.Draw(self, dc)
--- a/graphics/LD_Objects.py	Fri Jan 04 17:47:58 2008 +0100
+++ b/graphics/LD_Objects.py	Fri Jan 04 17:49:17 2008 +0100
@@ -67,6 +67,18 @@
                 powerrail.Connectors.append(None)
         return powerrail
     
+    # Returns the RedrawRect
+    def GetRedrawRect(self, movex = 0, movey = 0):
+        rect = Graphic_Element.GetRedrawRect(self, movex, movey)
+        for connector in self.Connectors:
+            if connector is not None:
+                rect = rect.Union(connector.GetRedrawRect(movex, movey))
+        if movex != 0 or movey != 0:
+            for connector in self.Connectors:
+                if connector is not None and connector.IsConnected():
+                    rect = rect.Union(connector.GetConnectedRedrawRect(movex, movey))
+        return rect
+    
     # Forbids to change the power rail size
     def SetSize(self, width, height):
         if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
@@ -98,19 +110,19 @@
     # Refresh the power rail bounding box
     def RefreshBoundingBox(self):
         dc = wx.ClientDC(self.Parent)
-        self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0], self.Size[1] + 1)
+        self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1)
     
     # Refresh the power rail size
     def RefreshSize(self):
-        self.Size = wx.Size(2, LD_LINE_SIZE * len(self.Connectors))
+        self.Size = wx.Size(LD_POWERRAIL_WIDTH, LD_LINE_SIZE * len(self.Connectors))
         self.RefreshBoundingBox()
     
     # Returns the block minimum size
     def GetMinSize(self):
         if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
-            return 2, self.Extensions[0] + self.Extensions[1]
-        else:
-            return 2, LD_LINE_SIZE * len(self.Connectors)
+            return LD_POWERRAIL_WIDTH, self.Extensions[0] + self.Extensions[1]
+        else:
+            return LD_POWERRAIL_WIDTH, LD_LINE_SIZE * len(self.Connectors)
     
     # Add a connector or a blank to this power rail at the last place
     def AddConnector(self, connector = True):
@@ -313,6 +325,7 @@
     
     # Draws power rail
     def Draw(self, dc):
+        Graphic_Element.Draw(self, dc)
         dc.SetPen(wx.BLACK_PEN)
         dc.SetBrush(wx.BLACK_BRUSH)
         # Draw a rectangle with the power rail size
@@ -321,7 +334,6 @@
         for connector in self.Connectors:
             if connector:
                 connector.Draw(dc)
-        Graphic_Element.Draw(self, dc)
         
 
 #-------------------------------------------------------------------------------
@@ -362,6 +374,18 @@
         contact.Output = self.Output.Clone(contact)
         return contact
     
+    # Returns the RedrawRect
+    def GetRedrawRect(self, movex = 0, movey = 0):
+        rect = Graphic_Element.GetRedrawRect(self, movex, movey)
+        rect = rect.Union(self.Input.GetRedrawRect(movex, movey))
+        rect = rect.Union(self.Output.GetRedrawRect(movex, movey))
+        if movex != 0 or movey != 0:
+            if self.Input.IsConnected():
+                rect = rect.Union(self.Input.GetConnectedRedrawRect(movex, movey))
+            if self.Output.IsConnected():
+                rect = rect.Union(self.Output.GetConnectedRedrawRect(movex, movey))
+        return rect
+    
     # Forbids to change the contact size
     def SetSize(self, width, height):
         if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
@@ -503,15 +527,17 @@
     
     # Draws the highlightment of this element if it is highlighted
     def DrawHighlightment(self, dc):
-        if self.Highlighted:
-            dc.SetPen(wx.Pen(HIGHLIGHTCOLOR))
-            dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR))
-            # Draw two rectangles for representing the contact
-            dc.DrawRectangle(self.Pos.x - 2, self.Pos.y - 2, 6, self.Size[1] + 5)
-            dc.DrawRectangle(self.Pos.x + self.Size[0] - 3, self.Pos.y - 2, 6, self.Size[1] + 5)
+        dc.SetPen(wx.Pen(HIGHLIGHTCOLOR))
+        dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR))
+        dc.SetLogicalFunction(wx.AND)
+        # Draw two rectangles for representing the contact
+        dc.DrawRectangle(self.Pos.x - 2, self.Pos.y - 2, 6, self.Size[1] + 5)
+        dc.DrawRectangle(self.Pos.x + self.Size[0] - 3, self.Pos.y - 2, 6, self.Size[1] + 5)
+        dc.SetLogicalFunction(wx.COPY)
     
     # Draws contact
     def Draw(self, dc):
+        Graphic_Element.Draw(self, dc)
         dc.SetPen(wx.BLACK_PEN)
         dc.SetBrush(wx.BLACK_BRUSH)
         # Draw two rectangles for representing the contact
@@ -534,7 +560,6 @@
         # Draw input and output connectors
         self.Input.Draw(dc)
         self.Output.Draw(dc)
-        Graphic_Element.Draw(self, dc)
         
 
 #-------------------------------------------------------------------------------
@@ -575,6 +600,18 @@
         coil.Output = self.Output.Clone(coil)
         return coil
     
+    # Returns the RedrawRect
+    def GetRedrawRect(self, movex = 0, movey = 0):
+        rect = Graphic_Element.GetRedrawRect(self, movex, movey)
+        rect = rect.Union(self.Input.GetRedrawRect(movex, movey))
+        rect = rect.Union(self.Output.GetRedrawRect(movex, movey))
+        if movex != 0 or movey != 0:
+            if self.Input.IsConnected():
+                rect = rect.Union(self.Input.GetConnectedRedrawRect(movex, movey))
+            if self.Output.IsConnected():
+                rect = rect.Union(self.Output.GetConnectedRedrawRect(movex, movey))
+        return rect
+    
     # Forbids to change the contact size
     def SetSize(self, width, height):
         if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
@@ -716,15 +753,17 @@
     
     # Draws the highlightment of this element if it is highlighted
     def DrawHighlightment(self, dc):
-        if self.Highlighted:
-            dc.SetPen(wx.Pen(HIGHLIGHTCOLOR, 6, wx.SOLID))
-            dc.SetBrush(wx.TRANSPARENT_BRUSH)
-            # Draw a two circle arcs for representing the coil
-            dc.DrawEllipticArc(self.Pos.x, self.Pos.y - int(self.Size[1] * (sqrt(2) - 1.) / 2.) + 1, self.Size[0], int(self.Size[1] * sqrt(2)) - 1, 135, 225)
-            dc.DrawEllipticArc(self.Pos.x, self.Pos.y - int(self.Size[1] * (sqrt(2) - 1.) / 2.) + 1, self.Size[0], int(self.Size[1] * sqrt(2)) - 1, -45, 45)
+        dc.SetPen(wx.Pen(HIGHLIGHTCOLOR, 6, wx.SOLID))
+        dc.SetBrush(wx.TRANSPARENT_BRUSH)
+        dc.SetLogicalFunction(wx.AND)
+        # Draw a two circle arcs for representing the coil
+        dc.DrawEllipticArc(self.Pos.x, self.Pos.y - int(self.Size[1] * (sqrt(2) - 1.) / 2.) + 1, self.Size[0], int(self.Size[1] * sqrt(2)) - 1, 135, 225)
+        dc.DrawEllipticArc(self.Pos.x, self.Pos.y - int(self.Size[1] * (sqrt(2) - 1.) / 2.) + 1, self.Size[0], int(self.Size[1] * sqrt(2)) - 1, -45, 45)
+        dc.SetLogicalFunction(wx.COPY)
     
     # Draws coil
     def Draw(self, dc):
+        Graphic_Element.Draw(self, dc)
         dc.SetPen(wx.Pen(wx.BLACK, 2, wx.SOLID))
         dc.SetBrush(wx.TRANSPARENT_BRUSH)
         # Draw a two circle arcs for representing the coil
@@ -749,5 +788,4 @@
         # Draw input and output connectors
         self.Input.Draw(dc)
         self.Output.Draw(dc)
-        Graphic_Element.Draw(self, dc)
         
--- a/graphics/SFC_Objects.py	Fri Jan 04 17:47:58 2008 +0100
+++ b/graphics/SFC_Objects.py	Fri Jan 04 17:49:17 2008 +0100
@@ -65,16 +65,37 @@
         self.Action = None
     
     # Make a clone of this SFC_Step
-    def Clone(self, id = None, pos = None):
-        step = SFC_Step(self.Parent, self.Type, self.Name, id)
+    def Clone(self, id = None, name = "Step", pos = None):
+        step = SFC_Step(self.Parent, name, self.Initial, id)
         step.SetSize(self.Size[0], self.Size[1])
         if pos is not None:
             step.SetPosition(pos.x, pos.y)
-        step.Input = self.Input.Clone(step)
-        step.Output = self.Output.Clone(step)
-        step.Action = self.Action.Clone(step)
+        if self.Input:
+            step.Input = self.Input.Clone(step)
+        if self.Output:
+            step.Output = self.Output.Clone(step)
+        if self.Action:
+            step.Action = self.Action.Clone(step)
         return step
     
+    # Returns the RedrawRect
+    def GetRedrawRect(self, movex = 0, movey = 0):
+        rect = Graphic_Element.GetRedrawRect(self, movex, movey)
+        if self.Input:
+            rect = rect.Union(self.Input.GetRedrawRect(movex, movey))
+        if self.Output:
+            rect = rect.Union(self.Output.GetRedrawRect(movex, movey))
+        if self.Action:
+            rect = rect.Union(self.Action.GetRedrawRect(movex, movey))
+        if movex != 0 or movey != 0:
+            if self.Input and self.Input.IsConnected():
+                rect = rect.Union(self.Input.GetConnectedRedrawRect(movex, movey))
+            if self.Output and self.Output.IsConnected():
+                rect = rect.Union(self.Output.GetConnectedRedrawRect(movex, movey))
+            if self.Action and self.Action.IsConnected():
+                rect = rect.Union(self.Action.GetConnectedRedrawRect(movex, movey))
+        return rect
+    
     # Delete this step by calling the appropriate method
     def Delete(self):
         self.Parent.DeleteStep(self)
@@ -428,6 +449,7 @@
     
     # Draws step
     def Draw(self, dc):
+        Graphic_Element.Draw(self, dc)
         dc.SetPen(wx.BLACK_PEN)
         dc.SetBrush(wx.WHITE_BRUSH)
         # Draw two rectangles for representing the step
@@ -445,7 +467,6 @@
             self.Output.Draw(dc)
         if self.Action:
             self.Action.Draw(dc)
-        Graphic_Element.Draw(self, dc)
         
 
 #-------------------------------------------------------------------------------
@@ -488,6 +509,18 @@
         transition.Output = self.Output.Clone(transition)
         return transition
     
+    # Returns the RedrawRect
+    def GetRedrawRect(self, movex = 0, movey = 0):
+        rect = Graphic_Element.GetRedrawRect(self, movex, movey)
+        rect = rect.Union(self.Input.GetRedrawRect(movex, movey))
+        rect = rect.Union(self.Output.GetRedrawRect(movex, movey))
+        if movex != 0 or movey != 0:
+            if self.Input.IsConnected():
+                rect = rect.Union(self.Input.GetConnectedRedrawRect(movex, movey))
+            if self.Output.IsConnected():
+                rect = rect.Union(self.Output.GetConnectedRedrawRect(movex, movey))
+        return rect
+    
     # Forbids to change the transition size
     def SetSize(self, width, height):
         if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
@@ -763,6 +796,7 @@
     
     # Draws transition
     def Draw(self, dc):
+        Graphic_Element.Draw(self, dc)
         dc.SetPen(wx.BLACK_PEN)
         dc.SetBrush(wx.BLACK_BRUSH)
         # Draw plain rectangle for representing the transition
@@ -785,7 +819,6 @@
         self.Output.Draw(dc)
         if self.Type == "connection":
             self.Condition.Draw(dc)
-        Graphic_Element.Draw(self, dc)
         
 
 #-------------------------------------------------------------------------------
@@ -837,6 +870,18 @@
         divergence.Outputs = [output.Clone(divergence) for output in self.Outputs]
         return divergence
     
+    # Returns the RedrawRect
+    def GetRedrawRect(self, movex = 0, movey = 0):
+        rect = Graphic_Element.GetRedrawRect(self, movex, movey)
+        if movex != 0 or movey != 0:
+            for input in self.Inputs:
+                if input.IsConnected():
+                    rect = rect.Union(input.GetConnectedRedrawRect(movex, movey))
+            for output in self.Outputs:
+                if output.IsConnected():
+                    rect = rect.Union(output.GetConnectedRedrawRect(movex, movey))
+        return rect
+    
     # Forbids to resize the divergence
     def Resize(self, x, y, width, height):
         if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
@@ -1172,19 +1217,21 @@
     
     # Draws the highlightment of this element if it is highlighted
     def DrawHighlightment(self, dc):
-        if self.Highlighted:
-            dc.SetPen(wx.Pen(HIGHLIGHTCOLOR))
-            dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR))
-            # Draw two rectangles for representing the contact
-            posx = self.Pos.x - 2
-            width = self.Size[0] + 5
-            if self.Type in [SIMULTANEOUS_DIVERGENCE, SIMULTANEOUS_CONVERGENCE]:
-                posx -= SFC_SIMULTANEOUS_SEQUENCE_EXTRA
-                width += SFC_SIMULTANEOUS_SEQUENCE_EXTRA * 2
-            dc.DrawRectangle(posx, self.Pos.y - 2, width, self.Size[1] + 5)
+        dc.SetPen(wx.Pen(HIGHLIGHTCOLOR))
+        dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR))
+        dc.SetLogicalFunction(wx.AND)
+        # Draw two rectangles for representing the contact
+        posx = self.Pos.x - 2
+        width = self.Size[0] + 5
+        if self.Type in [SIMULTANEOUS_DIVERGENCE, SIMULTANEOUS_CONVERGENCE]:
+            posx -= SFC_SIMULTANEOUS_SEQUENCE_EXTRA
+            width += SFC_SIMULTANEOUS_SEQUENCE_EXTRA * 2
+        dc.DrawRectangle(posx, self.Pos.y - 2, width, self.Size[1] + 5)
+        dc.SetLogicalFunction(wx.COPY)
         
     # Draws divergence
     def Draw(self, dc):
+        Graphic_Element.Draw(self, dc)
         dc.SetPen(wx.BLACK_PEN)
         dc.SetBrush(wx.BLACK_BRUSH)
         # Draw plain rectangle for representing the divergence
@@ -1200,7 +1247,6 @@
             input.Draw(dc)
         for output in self.Outputs:
             output.Draw(dc)
-        Graphic_Element.Draw(self, dc)
         
 
 #-------------------------------------------------------------------------------
@@ -1235,6 +1281,15 @@
         jump.Input = self.Input.Clone(jump)
         return jump
     
+    # Returns the RedrawRect
+    def GetRedrawRect(self, movex = 0, movey = 0):
+        rect = Graphic_Element.GetRedrawRect(self, movex, movey)
+        rect = rect.Union(self.Input.GetRedrawRect(movex, movey))
+        if movex != 0 or movey != 0:
+            if self.Input.IsConnected():
+                rect = rect.Union(self.Input.GetConnectedRedrawRect(movex, movey))
+        return rect
+    
     # Forbids to change the jump size
     def SetSize(self, width, height):
         if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
@@ -1367,16 +1422,18 @@
     
     # Draws the highlightment of this element if it is highlighted
     def DrawHighlightment(self, dc):
-        if self.Highlighted:
-            dc.SetPen(wx.Pen(HIGHLIGHTCOLOR))
-            dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR))
-            points = [wx.Point(self.Pos.x - 3, self.Pos.y - 2),
-                      wx.Point(self.Pos.x + self.Size[0] + 4, self.Pos.y - 2),
-                      wx.Point(self.Pos.x + self.Size[0] / 2, self.Pos.y + self.Size[1] + 4)]
-            dc.DrawPolygon(points)
+        dc.SetPen(wx.Pen(HIGHLIGHTCOLOR))
+        dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR))
+        dc.SetLogicalFunction(wx.AND)
+        points = [wx.Point(self.Pos.x - 3, self.Pos.y - 2),
+                  wx.Point(self.Pos.x + self.Size[0] + 4, self.Pos.y - 2),
+                  wx.Point(self.Pos.x + self.Size[0] / 2, self.Pos.y + self.Size[1] + 4)]
+        dc.DrawPolygon(points)
+        dc.SetLogicalFunction(wx.COPY)
     
     # Draws divergence
     def Draw(self, dc):
+        Graphic_Element.Draw(self, dc)
         dc.SetPen(wx.BLACK_PEN)
         dc.SetBrush(wx.BLACK_BRUSH)
         # Draw plain rectangle for representing the divergence
@@ -1392,7 +1449,6 @@
         # Draw input connector
         if self.Input:
             self.Input.Draw(dc)
-        Graphic_Element.Draw(self, dc)
         
 
 #-------------------------------------------------------------------------------
@@ -1427,7 +1483,16 @@
         if pos is not None:
             action_block.SetPosition(pos.x, pos.y)
         action_block.Input = self.Input.Clone(action_block)
-        return jump
+        return action_block
+    
+        # Returns the RedrawRect
+    def GetRedrawRect(self, movex = 0, movey = 0):
+        rect = Graphic_Element.GetRedrawRect(self, movex, movey)
+        rect = rect.Union(self.Input.GetRedrawRect(movex, movey))
+        if movex != 0 or movey != 0:
+            if self.Input.IsConnected():
+                rect = rect.Union(self.Input.GetConnectedRedrawRect(movex, movey))
+        return rect
     
     # Returns the number of action lines
     def GetLineNumber(self):
@@ -1457,7 +1522,7 @@
         
     # Refresh the action block bounding box
     def RefreshBoundingBox(self):
-        self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0], self.Size[1])
+        self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1)
     
     # Refresh the position of wires connected to action block
     def RefreshConnected(self, exclude = []):
@@ -1557,6 +1622,7 @@
     
     # Draws divergence
     def Draw(self, dc):
+        Graphic_Element.Draw(self, dc)
         dc.SetPen(wx.BLACK_PEN)
         dc.SetBrush(wx.WHITE_BRUSH)
         colsize = [self.ColSize[0], self.Size[0] - self.ColSize[0] - self.ColSize[2], self.ColSize[2]]
@@ -1590,5 +1656,4 @@
                         self.Pos.y + i * line_size + (line_size - text_height) / 2)
         # Draw input connector
         self.Input.Draw(dc)
-        Graphic_Element.Draw(self, dc)