Adding support for synchronize refreshing with tick and limit it to a defined period
authorgreg
Sat, 30 May 2009 17:15:22 +0200
changeset 361 62570186dad4
parent 360 072f9f830659
child 362 f56181aa99ea
Adding support for synchronize refreshing with tick and limit it to a defined period
GraphicViewer.py
PLCOpenEditor.py
Viewer.py
graphics/GraphicCommons.py
graphics/LD_Objects.py
graphics/SFC_Objects.py
--- a/GraphicViewer.py	Thu May 28 08:10:18 2009 +0200
+++ b/GraphicViewer.py	Sat May 30 17:15:22 2009 +0200
@@ -24,6 +24,7 @@
 
 import wx
 import wx.lib.plot as plot
+from graphics.GraphicCommons import DebugViewer
 
 
 colours = ['blue', 'red', 'green', 'yellow', 'orange', 'purple', 'brown', 'cyan',
@@ -44,7 +45,7 @@
  ID_GRAPHICVIEWERSTATICTEXT1, ID_GRAPHICVIEWERSTATICTEXT2,
 ] = [wx.NewId() for _init_ctrls in range(8)]
 
-class GraphicViewer(wx.Panel):
+class GraphicViewer(wx.Panel, DebugViewer):
 
     def _init_coll_MainGridSizer_Items(self, parent):
         # generated method, don't edit
@@ -145,7 +146,8 @@
 
     def __init__(self, parent, window, controler, instancepath = ""):
         self._init_ctrls(parent)
-
+        DebugViewer.__init__(self, controler, True, False)
+        
         self.ParentWindow = window
         self.Controler = controler
         self.InstancePath = instancepath
@@ -154,35 +156,41 @@
         self.CurrentValue = 0
         self.CurrentRange = 25
         
-        self.Controler.SubscribeDebugIECVariable(self.InstancePath.upper(), self)
+        self.AddDataConsumer(self.InstancePath.upper(), self)
     
     def __del__(self):
-        self.Controler.UnsubscribeDebugIECVariable(self.InstancePath.upper(), self)
+        DebugViewer.__del__(self)
+        self.RemoveDataConsumer(self)
     
     def ResetView(self):
         self.Datas = []
         self.CurrentValue = 0
         self.RefreshView()
     
-    def RefreshView(self):
-        var_name = self.InstancePath.split(".")[-1]
-        
-        self.VariableGraphic = plot.PolyLine(self.Datas[self.CurrentValue:self.CurrentValue + self.CurrentRange], 
-                                             legend=var_name, colour=colours[0])
-        self.GraphicsObject = plot.PlotGraphics([self.VariableGraphic], "%s Graphics" % var_name, "Tick", "Values")
-        datas_length = len(self.Datas)
-        if datas_length > 1:
-            start = self.Datas[self.CurrentValue][0]
-            if self.CurrentValue + self.CurrentRange > datas_length:
-                end = start + (self.Datas[datas_length - 1][0] - start) * self.CurrentRange / (datas_length - self.CurrentValue - 1)
+    def RefreshNewData(self):
+        self.RefreshView(False)
+    
+    def RefreshView(self, force=True):
+        self.Freeze()
+        if force or self.CurrentValue + self.CurrentRange == len(self.Datas) or self.CurrentValue + len(self.Datas) < self.CurrentRange:
+            var_name = self.InstancePath.split(".")[-1]
+            
+            self.VariableGraphic = plot.PolyLine(self.Datas[self.CurrentValue:self.CurrentValue + self.CurrentRange], 
+                                                 legend=var_name, colour=colours[0])
+            self.GraphicsObject = plot.PlotGraphics([self.VariableGraphic], "%s Graphics" % var_name, "Tick", "Values")
+            datas_length = len(self.Datas)
+            if datas_length > 1:
+                start = self.Datas[self.CurrentValue][0]
+                if self.CurrentValue + self.CurrentRange > datas_length:
+                    end = start + (self.Datas[datas_length - 1][0] - start) * self.CurrentRange / (datas_length - self.CurrentValue - 1)
+                else:
+                    end = self.Datas[self.CurrentValue + self.CurrentRange - 1][0]
             else:
-                end = self.Datas[self.CurrentValue + self.CurrentRange - 1][0]
-        else:
-            start = 0.
-            end = 25.
-        self.Canvas.Draw(self.GraphicsObject, xAxis=(start, end))
-        
+                start = 0.
+                end = 25.
+            self.Canvas.Draw(self.GraphicsObject, xAxis=(start, end))
         self.RefreshScrollBar()
+        self.Thaw()
     
     def SetMode(self, mode):
         pass
@@ -205,17 +213,12 @@
     def SelectAll(self):
         pass
     
-    def AddPoint(self, tick, value):
-        if self:
-            self.Datas.append((float(tick), {True:1., False:0.}.get(value, float(value))))
-            if self.CurrentValue + self.CurrentRange == len(self.Datas) - 1:
-                self.CurrentValue += 1
-                self.RefreshView()
-            elif len(self.Datas) < self.CurrentValue + self.CurrentRange:
-                self.RefreshView()
-            else:
-                self.RefreshScrollBar()
-            
+    def NewValue(self, tick, value):
+        self.Datas.append((float(tick), {True:1., False:0.}.get(value, float(value))))
+        if self.CurrentValue + self.CurrentRange == len(self.Datas) - 1:
+            self.CurrentValue += 1
+        self.NewDataAvailable()
+    
     def RefreshScrollBar(self):
         self.CanvasPosition.SetScrollbar(self.CurrentValue, self.CurrentRange, len(self.Datas), self.CurrentRange)
 
--- a/PLCOpenEditor.py	Thu May 28 08:10:18 2009 +0200
+++ b/PLCOpenEditor.py	Sat May 30 17:15:22 2009 +0200
@@ -1295,6 +1295,8 @@
             if selected != -1:
                 window = self.TabsOpened.GetPage(selected)
                 window.SetScale(idx)
+                window.RefreshVisibleElements()
+                window.RefreshScrollBars()
             event.Skip()
         return ZoomFunction
 
@@ -4534,9 +4536,10 @@
 #                            Variables Editor Panel
 #-------------------------------------------------------------------------------
 
-class VariableTableItem:
+class VariableTableItem(DebugDataConsumer):
     
     def __init__(self, parent, variable, value):
+        DebugDataConsumer.__init__(self)
         self.Parent = parent
         self.Variable = variable
         self.Value = value
@@ -4553,12 +4556,12 @@
         return self.Variable
     
     def SetValue(self, value):
-        if self.Parent and self.Value != value:
+        if self.Value != value:
             self.Value = value
-            self.Parent.RefreshGrid()
+            self.Parent.NewDataAvailable()
     
     def GetValue(self):
-        return self.Value    
+        return self.Value
 
 class DebugVariableTable(wx.grid.PyGridTableBase):
     
@@ -4716,10 +4719,10 @@
 
 [ID_DEBUGVARIABLEPANEL, ID_DEBUGVARIABLEPANELVARIABLESGRID, 
  ID_DEBUGVARIABLEPANELUPBUTTON, ID_DEBUGVARIABLEPANELDOWNBUTTON, 
- ID_DEBUGVARIABLEPANELDELETEBUTTON, 
+ ID_DEBUGVARIABLEPANELDELETEBUTTON,
 ] = [wx.NewId() for _init_ctrls in range(5)]
 
-class DebugVariablePanel(wx.Panel):
+class DebugVariablePanel(wx.Panel, DebugViewer):
     
     if wx.VERSION < (2, 6, 0):
         def Bind(self, event, function, id = None):
@@ -4786,9 +4789,10 @@
     
     def __init__(self, parent, controler):
         self._init_ctrls(parent)
+        DebugViewer.__init__(self, controler, True)
         self.Controler = controler
         
-        self.Table = DebugVariableTable(self, [], ["Variable", "Value"])    
+        self.Table = DebugVariableTable(self, [], ["Variable", "Value"])
         self.VariablesGrid.SetTable(self.Table)
         self.VariablesGrid.SetRowLabelSize(0)
         
@@ -4797,20 +4801,21 @@
             attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTER)
             self.VariablesGrid.SetColAttr(col, attr)
             self.VariablesGrid.SetColSize(col, 100)
-    
+        
         self.Table.ResetView(self.VariablesGrid)
     
-    def __del__(self):
-        for item in self.Table.GetData():
-            self.Controler.UnsubscribeDebugIECVariable(item.GetVariable().upper(), item)
+    def RefreshNewData(self):
+        self.RefreshGrid()
     
     def RefreshGrid(self):
+        self.Freeze()
         self.Table.ResetView(self.VariablesGrid)
+        self.Thaw()
     
     def OnDeleteButton(self, event):
         idx = self.VariablesGrid.GetGridCursorRow()
         item = self.Table.GetItem(idx)
-        self.Controler.UnsubscribeDebugIECVariable(item.GetVariable().upper(), item)
+        self.RemoveDataConsumer(item)
         self.Table.RemoveItem(idx)
         self.RefreshGrid()
         event.Skip()
@@ -4828,7 +4833,7 @@
             if iec_path == item.GetVariable():
                 return
         item = VariableTableItem(self, iec_path, "")
-        result = self.Controler.SubscribeDebugIECVariable(iec_path.upper(), item)
+        result = self.AddDataConsumer(iec_path.upper(), item)
         if result is not None:
             self.Table.InsertItem(idx, item)
             self.RefreshGrid()
--- a/Viewer.py	Thu May 28 08:10:18 2009 +0200
+++ b/Viewer.py	Sat May 30 17:15:22 2009 +0200
@@ -234,7 +234,7 @@
 manipulating graphic elements
 """
 
-class Viewer(wx.ScrolledWindow):
+class Viewer(wx.ScrolledWindow, DebugViewer):
     
     if wx.VERSION < (2, 6, 0):
         def Bind(self, event, function, id = None):
@@ -344,6 +344,7 @@
     def __init__(self, parent, tagname, window, controler, debug = False, instancepath = ""):
         wx.ScrolledWindow.__init__(self, parent, pos=wx.Point(0, 0), size=wx.Size(0, 0), 
             style=wx.HSCROLL | wx.VSCROLL | wx.ALWAYS_SHOW_SB)
+        DebugViewer.__init__(self, controler, debug)
         self._init_menus()
         # Adding a rubberband to Viewer
         self.rubberBand = RubberBand(drawingSurface=self)
@@ -359,7 +360,6 @@
         self.current_id = 0
         self.TagName = tagname
         self.Errors = []
-        self.Debug = debug
         self.InstancePath = instancepath
         self.StartMousePos = None
         self.StartScreenPos = None
@@ -378,6 +378,8 @@
         if not self.Debug:
             self.SetDropTarget(ViewerDropTarget(self))
         
+        self.NewDataRefreshRect = None
+        
         dc = wx.ClientDC(self)
         font = wx.Font(faces["size"], wx.SWISS, wx.NORMAL, wx.NORMAL, faceName = faces["mono"])
         dc.SetFont(font)
@@ -388,6 +390,8 @@
             dc.SetFont(font)
             width, height = dc.GetTextExtent("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
         self.SetFont(font)
+        self.MiniTextDC = wx.MemoryDC()
+        self.MiniTextDC.SetFont(wx.Font(faces["size"] * 0.75, wx.SWISS, wx.NORMAL, wx.NORMAL, faceName = faces["helv"]))
         
         self.SetScale(len(ZOOM_FACTORS) / 2)
         
@@ -442,6 +446,7 @@
     
     # Destructor
     def __del__(self):
+        DebugViewer.__del__(self)
         self.Flush()
         self.ResetView()
     
@@ -467,10 +472,12 @@
         dc.SetUserScale(self.ViewScale[0], self.ViewScale[1])
         return dc
 
+    def GetMiniTextExtent(self, text):
+        return self.MiniTextDC.GetTextExtent(text)
+    
     def GetMiniFont(self):
-        font = self.GetFont()
-        return wx.Font(font.GetPointSize() * 0.75, wx.SWISS, wx.NORMAL, wx.NORMAL, faceName = faces["helv"])
-
+        return self.MiniTextDC.GetFont()
+    
 #-------------------------------------------------------------------------------
 #                         Element management functions
 #-------------------------------------------------------------------------------
@@ -549,7 +556,7 @@
                         iec_path = "%s.%s%d_%s"%(self.InstancePath, block.GetType(), block.GetId(), connectorname)
             elif isinstance(block, FBD_Variable):
                 iec_path = "%s.%s"%(self.InstancePath, block.GetName())
-        elif isinstance(element, (LD_Contact, LD_Coil)):
+        elif isinstance(element, LD_Contact):
             iec_path = "%s.%s"%(self.InstancePath, element.GetName())
         elif isinstance(element, SFC_Step):
             iec_path = "%s.%s.X"%(self.InstancePath, element.GetName())
@@ -574,8 +581,7 @@
         self.HighlightedElement = None
     
     def Flush(self):
-        for element, iec_path in self.Subscribed.iteritems():
-            self.Controler.UnsubscribeDebugIECVariable(iec_path, element)
+        self.DeleteDataConsumers()
         for block in self.Blocks:
             block.Flush()
     
@@ -643,6 +649,18 @@
 #                          Refresh functions
 #-------------------------------------------------------------------------------
 
+    def UpdateRefreshRect(self, refresh_rect):
+        if self.NewDataRefreshRect is None:
+            self.NewDataRefreshRect = refresh_rect
+        else:
+            self.NewDataRefreshRect.Union(refresh_rect)
+
+    def RefreshNewData(self):
+        if self.NewDataRefreshRect is not None:
+            refresh_rect, self.NewDataRefreshRect = self.NewDataRefreshRect, None
+            self.RefreshRect(self.GetScrolledRect(refresh_rect), False)
+        DebugViewer.RefreshNewData(self)
+
     def ResetBuffer(self):
         pass
 
@@ -679,15 +697,11 @@
                             iec_path = "%s.%s%d"%(self.InstancePath, block.GetType(), block.GetId())
                         else:
                             iec_path = "%s.%s%d_%s"%(self.InstancePath, block.GetType(), block.GetId(), connectorname)
-                    if self.Controler.SubscribeDebugIECVariable(iec_path.upper(), wire) is not None:
-                        self.Subscribed[wire] = iec_path.upper()
-                    else:
+                    if self.AddDataConsumer(iec_path.upper(), wire) is None:
                         wire.SetValue("undefined")
                 elif isinstance(block, FBD_Variable):
                     iec_path = "%s.%s"%(self.InstancePath, block.GetName())
-                    if self.Controler.SubscribeDebugIECVariable(iec_path.upper(), wire) is not None:
-                        self.Subscribed[wire] = iec_path.upper()
-                    else:
+                    if self.AddDataConsumer(iec_path.upper(), wire) is None:
                         wire.SetValue("undefined")
                 elif isinstance(block, FBD_Connector):
                     wire.SetValue("undefined")
@@ -697,10 +711,8 @@
                 block.SpreadCurrent()
                 iec_path = self.GetElementIECPath(block)
                 if iec_path is not None:
-                    result = self.Controler.SubscribeDebugIECVariable(iec_path.upper(), block)
-                    if result is not None:
-                        self.Subscribed[block] = iec_path.upper()
-                
+                    self.AddDataConsumer(iec_path.upper(), block)
+        
         self.RefreshVisibleElements()
         self.ShowErrors()
         self.Refresh(False)
@@ -2687,7 +2699,7 @@
             names.update(dict([(varname.upper(), True) for varname in self.Controler.GetEditedElementVariables(self.TagName, self.Debug)]))
             format = "Block%d"
         elif isinstance(element, SFC_Step):
-            names.update(dict([block.GetName().upper() for block in self.Blocks if isinstance(block, SFC_Step)]))
+            names.update(dict([(block.GetName().upper(), True) for block in self.Blocks if isinstance(block, SFC_Step)]))
             format = "Step%d"
         i = 1
         while names.get((format%i).upper(), False):
--- a/graphics/GraphicCommons.py	Thu May 28 08:10:18 2009 +0200
+++ b/graphics/GraphicCommons.py	Sat May 30 17:15:22 2009 +0200
@@ -23,6 +23,7 @@
 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 import wx
+import time
 from math import *
 from types import *
 
@@ -188,6 +189,98 @@
 
 
 #-------------------------------------------------------------------------------
+#                            Debug Data Consumer Class
+#-------------------------------------------------------------------------------
+
+class DebugDataConsumer:
+    
+    def __init__(self):
+        self.LastValue = None
+        self.Value = None
+        self.Inhibited = False
+    
+    def Inhibit(self, inhibit):
+        self.Inhibited = inhibit
+        if inhibit and self.LastValue is not None:
+            self.SetValue(self.LastValue)
+            self.LastValue = None
+        
+    def NewValue(self, tick, value):
+        if self.Inhibited:
+            self.LastValue = value
+        else:
+            self.SetValue(value)
+
+    def SetValue(self, value):
+        self.Value = value
+
+#-------------------------------------------------------------------------------
+#                               Debug Viewer Class
+#-------------------------------------------------------------------------------
+
+REFRESH_PERIOD = 0.1
+
+class DebugViewer:
+    
+    def __init__(self, producer, debug, register_tick=True):
+        self.DataProducer = producer
+        self.Debug = debug
+        
+        self.DataConsumers = {}
+        
+        self.LastRefreshTime = time.time()
+        
+        if register_tick:
+            self.DataProducer.SubscribeDebugIECVariable("__tick__", self)
+        
+        self.RefreshTimer = wx.Timer(self, -1)
+        self.Bind(wx.EVT_TIMER, self.OnRefreshTimer, self.RefreshTimer)
+    
+    def __del__(self):
+        self.DataProducer.UnsubscribeDebugIECVariable("__tick__", self)
+        self.DeleteDataConsumers()
+        self.RefreshTimer.Stop()
+        
+    def Inhibit(self, inhibit):
+        for consumer, iec_path in self.DataConsumers.iteritems():
+            consumer.Inhibit(inhibit)
+    
+    def AddDataConsumer(self, iec_path, consumer):
+        result = self.DataProducer.SubscribeDebugIECVariable(iec_path, consumer) is not None
+        if result is not None and consumer != self:
+            self.DataConsumers[consumer] = iec_path
+        return result
+    
+    def RemoveDataConsumer(self, consumer):
+        iec_path = self.DataConsumers.pop(consumer, None)
+        if iec_path is not None:
+            self.DataProducer.UnsubscribeDebugIECVariable(iec_path, consumer)
+    
+    def DeleteDataConsumers(self):
+        for consumer, iec_path in self.DataConsumers.iteritems():
+            self.DataProducer.UnsubscribeDebugIECVariable(iec_path, consumer)
+        self.DataConsumers = {}
+    
+    def OnRefreshTimer(self, event):
+        self.RefreshNewData()
+        event.Skip()
+    
+    def NewDataAvailable(self):
+        self.Inhibit(True)
+        current_time = time.time()
+        if current_time - self.LastRefreshTime > REFRESH_PERIOD:
+            self.LastRefreshTime = current_time
+            wx.CallAfter(self.RefreshViewOnNewData)
+
+    def RefreshViewOnNewData(self):
+        if self:
+            self.RefreshNewData()
+            self.RefreshTimer.Start(int(REFRESH_PERIOD * 1000), oneShot=True)
+    
+    def RefreshNewData(self):
+        self.Inhibit(False)
+
+#-------------------------------------------------------------------------------
 #                               Viewer Rubberband
 #-------------------------------------------------------------------------------
 
@@ -293,7 +386,7 @@
                 self.currentBox.height)
 
 #-------------------------------------------------------------------------------
-#                               Viewer Rubberband
+#                               Viewer ToolTip
 #-------------------------------------------------------------------------------
 
 """
@@ -312,10 +405,14 @@
         
     def SetTip(self, tip):
         self.Tip = tip
-        dc = wx.ClientDC(self)
-        w, h = dc.GetTextExtent(tip)
-        self.SetSize(wx.Size(w + 4, h + 4))
-        self.Refresh()
+        wx.CallAfter(self.RefreshTip)
+        
+    def RefreshTip(self):
+        if self:
+            dc = wx.ClientDC(self)
+            w, h = dc.GetTextExtent(self.Tip)
+            self.SetSize(wx.Size(w + 4, h + 4))
+            self.Refresh()
         
     def OnPaint(self, event):
         dc = wx.AutoBufferedPaintDC(self)
@@ -1433,11 +1530,12 @@
 Class that implements a wire for connecting two blocks
 """
 
-class Wire(Graphic_Element):
+class Wire(Graphic_Element, DebugDataConsumer):
     
     # Create a new wire
     def __init__(self, parent, start = None, end = None):
         Graphic_Element.__init__(self, parent)
+        DebugDataConsumer.__init__(self)
         self.StartPoint = start
         self.EndPoint = end
         self.StartConnected = None
@@ -1451,14 +1549,12 @@
             self.Segments = []
         self.SelectedSegment = None
         self.Valid = True
-        self.Value = None
         self.ValueSize = None
         self.ComputedValue = None
         self.OverStart = False
         self.OverEnd = False
         self.ComputingType = False
         self.ToolTip = None
-        self.Font = parent.GetMiniFont()
         
     def Flush(self):
         self.StartConnected = None
@@ -1492,7 +1588,6 @@
             rect = rect.Union(self.EndConnected.GetRedrawRect(movex, movey))
         if self.ValueSize is not None:
             width, height = self.ValueSize
-            width, height = self.ValueSize
             if self.BoundingBox[2] > width * 4 or self.BoundingBox[3] > height * 4:
                 x = self.Points[0].x + width * self.StartPoint[1][0] / 2
                 y = self.Points[0].y + (height * self.StartPoint[1][1] - 1) / 2
@@ -1624,7 +1719,7 @@
         return False
     
     def SetValue(self, value):
-        if self.Value != value and self.Parent:
+        if self.Value != value:
             self.Value = value
             if value is not None and not isinstance(value, BooleanType):
                 if isinstance(value, StringType):
@@ -1636,16 +1731,14 @@
                 if len(self.ComputedValue) > 4:
                     self.ComputedValue = self.ComputedValue[:4] + "..."
             if isinstance(self.ComputedValue, StringType):
-                dc = wx.ClientDC(self.Parent)
-                dc.SetFont(self.Font)
-                self.ValueSize = dc.GetTextExtent(self.ComputedValue)
+                self.ValueSize = self.Parent.GetMiniTextExtent(self.ComputedValue)
             else:
                 self.ValueSize = None
             if self.StartConnected:
                 self.StartConnected.RefreshValue()
             if self.EndConnected:
                 self.EndConnected.RefreshValue()
-            self.Refresh()
+            self.Parent.UpdateRefreshRect(self.GetRedrawRect())
             if isinstance(value, BooleanType) and self.StartConnected is not None:
                 block = self.StartConnected.GetParentBlock()
                 block.SpreadCurrent()
@@ -2514,7 +2607,7 @@
             if self.SelectedSegment == len(self.Segments) - 1:
                 dc.DrawPoint(self.Points[-1].x, self.Points[-1].y)
         if self.Value is not None and not isinstance(self.Value, BooleanType) and self.Value != "undefined":
-            dc.SetFont(self.Font)
+            dc.SetFont(self.Parent.GetMiniFont())
             dc.SetTextForeground(wx.NamedColour("purple"))
             width, height = self.ValueSize
             if self.BoundingBox[2] > width * 4 or self.BoundingBox[3] > height * 4:
--- a/graphics/LD_Objects.py	Thu May 28 08:10:18 2009 +0200
+++ b/graphics/LD_Objects.py	Sat May 30 17:15:22 2009 +0200
@@ -379,11 +379,12 @@
 Class that implements the graphic representation of a contact
 """
 
-class LD_Contact(Graphic_Element):
+class LD_Contact(Graphic_Element, DebugDataConsumer):
     
     # Create a new contact
     def __init__(self, parent, type, name, id = None):
         Graphic_Element.__init__(self, parent)
+        DebugDataConsumer.__init__(self)
         self.Type = type
         self.Name = name
         self.Id = id
@@ -392,7 +393,6 @@
         # Create an input and output connector
         self.Input = Connector(self, "", "BOOL", wx.Point(0, self.Size[1] / 2 + 1), WEST)
         self.Output = Connector(self, "", "BOOL", wx.Point(self.Size[0], self.Size[1] / 2 + 1), EAST)
-        self.Value = None
         self.PreviousValue = False
         self.PreviousSpreading = False
         self.RefreshNameSize()
@@ -410,7 +410,7 @@
         self.PreviousValue = self.Value
         self.Value = value
         if self.Value != self.PreviousValue:
-            self.Refresh()
+            self.Parent.UpdateRefreshRect(self.GetRedrawRect())
             self.SpreadCurrent()
     
     def SpreadCurrent(self):
@@ -717,7 +717,7 @@
             elif not self.Value and self.PreviousValue:
                 self.Output.SpreadCurrent(False)
             if self.Value != self.PreviousValue:
-                self.Refresh()
+                self.Parent.UpdateRefreshRect(self.GetRedrawRect())
     
     # Make a clone of this LD_Coil
     def Clone(self, parent, id = None, pos = None):
--- a/graphics/SFC_Objects.py	Thu May 28 08:10:18 2009 +0200
+++ b/graphics/SFC_Objects.py	Sat May 30 17:15:22 2009 +0200
@@ -41,11 +41,12 @@
 Class that implements the graphic representation of a step
 """
 
-class SFC_Step(Graphic_Element):
+class SFC_Step(Graphic_Element, DebugDataConsumer):
     
     # Create a new step
     def __init__(self, parent, name, initial = False, id = None):
         Graphic_Element.__init__(self, parent)
+        DebugDataConsumer.__init__(self)
         self.SetName(name)
         self.Initial = initial
         self.Id = id
@@ -58,7 +59,6 @@
             self.Input = None
         self.Output = None
         self.Action = None
-        self.Value = None
         self.PreviousValue = None
         self.PreviousSpreading = False
     
@@ -77,7 +77,7 @@
         self.PreviousValue = self.Value
         self.Value = value
         if self.Value != self.PreviousValue:
-            self.Refresh()
+            self.Parent.UpdateRefreshRect(self.GetRedrawRect())
             self.SpreadCurrent()
     
     def SpreadCurrent(self):
@@ -547,11 +547,12 @@
 Class that implements the graphic representation of a transition
 """
 
-class SFC_Transition(Graphic_Element):
+class SFC_Transition(Graphic_Element, DebugDataConsumer):
     
     # Create a new transition
     def __init__(self, parent, type = "reference", condition = None, priority = 0, id = None):
         Graphic_Element.__init__(self, parent)
+        DebugDataConsumer.__init__(self)
         self.Type = None
         self.Id = id
         self.Priority = 0
@@ -562,7 +563,6 @@
         self.SetType(type, condition)
         self.SetPriority(priority)
         self.Errors = {}
-        self.Value = None
         self.PreviousValue = None
         self.PreviousSpreading = False
     
@@ -581,7 +581,7 @@
         self.PreviousValue = self.Value
         self.Value = value
         if self.Value != self.PreviousValue:
-            self.Refresh()
+            self.Parent.UpdateRefreshRect(self.GetRedrawRect())
             self.SpreadCurrent()
     
     def SpreadCurrent(self):
@@ -1029,11 +1029,11 @@
             else:
                 self.Value = False
             if self.Value and not self.PreviousValue:
-                self.Refresh()
+                self.Parent.UpdateRefreshRect(self.GetRedrawRect())
                 for output in self.Outputs:
                     output.SpreadCurrent(True)
             elif not self.Value and self.PreviousValue:
-                self.Refresh()
+                self.Parent.UpdateRefreshRect(self.GetRedrawRect())
                 for output in self.Outputs:
                     output.SpreadCurrent(False)
     
@@ -1469,7 +1469,7 @@
             self.PreviousValue = self.Value
             self.Value = self.Input.ReceivingCurrent()
             if self.Value != self.PreviousValue:
-                self.Refresh()
+                self.Parent.UpdateRefreshRect(self.GetRedrawRect())
     
     # Make a clone of this SFC_Jump
     def Clone(self, parent, id = None, pos = None):
@@ -1714,7 +1714,7 @@
             self.PreviousValue = self.Value
             self.Value = self.Input.ReceivingCurrent()
             if self.Value != self.PreviousValue:
-                self.Refresh()
+                self.Parent.UpdateRefreshRect(self.GetRedrawRect())
     
     # Make a clone of this SFC_ActionBlock
     def Clone(self, parent, id = None, pos = None):