graphics/GraphicCommons.py
changeset 361 62570186dad4
parent 358 4eeb0129f5d2
child 364 deee68313770
equal deleted inserted replaced
360:072f9f830659 361:62570186dad4
    21 #You should have received a copy of the GNU General Public
    21 #You should have received a copy of the GNU General Public
    22 #License along with this library; if not, write to the Free Software
    22 #License along with this library; if not, write to the Free Software
    23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    24 
    24 
    25 import wx
    25 import wx
       
    26 import time
    26 from math import *
    27 from math import *
    27 from types import *
    28 from types import *
    28 
    29 
    29 #-------------------------------------------------------------------------------
    30 #-------------------------------------------------------------------------------
    30 #                               Common constants
    31 #                               Common constants
   186         return dir_target
   187         return dir_target
   187     return v_base
   188     return v_base
   188 
   189 
   189 
   190 
   190 #-------------------------------------------------------------------------------
   191 #-------------------------------------------------------------------------------
       
   192 #                            Debug Data Consumer Class
       
   193 #-------------------------------------------------------------------------------
       
   194 
       
   195 class DebugDataConsumer:
       
   196     
       
   197     def __init__(self):
       
   198         self.LastValue = None
       
   199         self.Value = None
       
   200         self.Inhibited = False
       
   201     
       
   202     def Inhibit(self, inhibit):
       
   203         self.Inhibited = inhibit
       
   204         if inhibit and self.LastValue is not None:
       
   205             self.SetValue(self.LastValue)
       
   206             self.LastValue = None
       
   207         
       
   208     def NewValue(self, tick, value):
       
   209         if self.Inhibited:
       
   210             self.LastValue = value
       
   211         else:
       
   212             self.SetValue(value)
       
   213 
       
   214     def SetValue(self, value):
       
   215         self.Value = value
       
   216 
       
   217 #-------------------------------------------------------------------------------
       
   218 #                               Debug Viewer Class
       
   219 #-------------------------------------------------------------------------------
       
   220 
       
   221 REFRESH_PERIOD = 0.1
       
   222 
       
   223 class DebugViewer:
       
   224     
       
   225     def __init__(self, producer, debug, register_tick=True):
       
   226         self.DataProducer = producer
       
   227         self.Debug = debug
       
   228         
       
   229         self.DataConsumers = {}
       
   230         
       
   231         self.LastRefreshTime = time.time()
       
   232         
       
   233         if register_tick:
       
   234             self.DataProducer.SubscribeDebugIECVariable("__tick__", self)
       
   235         
       
   236         self.RefreshTimer = wx.Timer(self, -1)
       
   237         self.Bind(wx.EVT_TIMER, self.OnRefreshTimer, self.RefreshTimer)
       
   238     
       
   239     def __del__(self):
       
   240         self.DataProducer.UnsubscribeDebugIECVariable("__tick__", self)
       
   241         self.DeleteDataConsumers()
       
   242         self.RefreshTimer.Stop()
       
   243         
       
   244     def Inhibit(self, inhibit):
       
   245         for consumer, iec_path in self.DataConsumers.iteritems():
       
   246             consumer.Inhibit(inhibit)
       
   247     
       
   248     def AddDataConsumer(self, iec_path, consumer):
       
   249         result = self.DataProducer.SubscribeDebugIECVariable(iec_path, consumer) is not None
       
   250         if result is not None and consumer != self:
       
   251             self.DataConsumers[consumer] = iec_path
       
   252         return result
       
   253     
       
   254     def RemoveDataConsumer(self, consumer):
       
   255         iec_path = self.DataConsumers.pop(consumer, None)
       
   256         if iec_path is not None:
       
   257             self.DataProducer.UnsubscribeDebugIECVariable(iec_path, consumer)
       
   258     
       
   259     def DeleteDataConsumers(self):
       
   260         for consumer, iec_path in self.DataConsumers.iteritems():
       
   261             self.DataProducer.UnsubscribeDebugIECVariable(iec_path, consumer)
       
   262         self.DataConsumers = {}
       
   263     
       
   264     def OnRefreshTimer(self, event):
       
   265         self.RefreshNewData()
       
   266         event.Skip()
       
   267     
       
   268     def NewDataAvailable(self):
       
   269         self.Inhibit(True)
       
   270         current_time = time.time()
       
   271         if current_time - self.LastRefreshTime > REFRESH_PERIOD:
       
   272             self.LastRefreshTime = current_time
       
   273             wx.CallAfter(self.RefreshViewOnNewData)
       
   274 
       
   275     def RefreshViewOnNewData(self):
       
   276         if self:
       
   277             self.RefreshNewData()
       
   278             self.RefreshTimer.Start(int(REFRESH_PERIOD * 1000), oneShot=True)
       
   279     
       
   280     def RefreshNewData(self):
       
   281         self.Inhibit(False)
       
   282 
       
   283 #-------------------------------------------------------------------------------
   191 #                               Viewer Rubberband
   284 #                               Viewer Rubberband
   192 #-------------------------------------------------------------------------------
   285 #-------------------------------------------------------------------------------
   193 
   286 
   194 """
   287 """
   195 Class that implements a rubberband
   288 Class that implements a rubberband
   291             # Draw current box
   384             # Draw current box
   292             dc.DrawRectangle(self.currentBox.x, self.currentBox.y, self.currentBox.width,
   385             dc.DrawRectangle(self.currentBox.x, self.currentBox.y, self.currentBox.width,
   293                 self.currentBox.height)
   386                 self.currentBox.height)
   294 
   387 
   295 #-------------------------------------------------------------------------------
   388 #-------------------------------------------------------------------------------
   296 #                               Viewer Rubberband
   389 #                               Viewer ToolTip
   297 #-------------------------------------------------------------------------------
   390 #-------------------------------------------------------------------------------
   298 
   391 
   299 """
   392 """
   300 Class that implements a custom tool tip
   393 Class that implements a custom tool tip
   301 """
   394 """
   310         
   403         
   311         self.Bind(wx.EVT_PAINT, self.OnPaint)
   404         self.Bind(wx.EVT_PAINT, self.OnPaint)
   312         
   405         
   313     def SetTip(self, tip):
   406     def SetTip(self, tip):
   314         self.Tip = tip
   407         self.Tip = tip
   315         dc = wx.ClientDC(self)
   408         wx.CallAfter(self.RefreshTip)
   316         w, h = dc.GetTextExtent(tip)
   409         
   317         self.SetSize(wx.Size(w + 4, h + 4))
   410     def RefreshTip(self):
   318         self.Refresh()
   411         if self:
       
   412             dc = wx.ClientDC(self)
       
   413             w, h = dc.GetTextExtent(self.Tip)
       
   414             self.SetSize(wx.Size(w + 4, h + 4))
       
   415             self.Refresh()
   319         
   416         
   320     def OnPaint(self, event):
   417     def OnPaint(self, event):
   321         dc = wx.AutoBufferedPaintDC(self)
   418         dc = wx.AutoBufferedPaintDC(self)
   322         dc.Clear()
   419         dc.Clear()
   323         dc.SetPen(wx.BLACK_PEN)
   420         dc.SetPen(wx.BLACK_PEN)
  1431 
  1528 
  1432 """
  1529 """
  1433 Class that implements a wire for connecting two blocks
  1530 Class that implements a wire for connecting two blocks
  1434 """
  1531 """
  1435 
  1532 
  1436 class Wire(Graphic_Element):
  1533 class Wire(Graphic_Element, DebugDataConsumer):
  1437     
  1534     
  1438     # Create a new wire
  1535     # Create a new wire
  1439     def __init__(self, parent, start = None, end = None):
  1536     def __init__(self, parent, start = None, end = None):
  1440         Graphic_Element.__init__(self, parent)
  1537         Graphic_Element.__init__(self, parent)
       
  1538         DebugDataConsumer.__init__(self)
  1441         self.StartPoint = start
  1539         self.StartPoint = start
  1442         self.EndPoint = end
  1540         self.EndPoint = end
  1443         self.StartConnected = None
  1541         self.StartConnected = None
  1444         self.EndConnected = None
  1542         self.EndConnected = None
  1445         # If the start and end points are defined, calculate the wire
  1543         # If the start and end points are defined, calculate the wire
  1449         else:
  1547         else:
  1450             self.Points = []
  1548             self.Points = []
  1451             self.Segments = []
  1549             self.Segments = []
  1452         self.SelectedSegment = None
  1550         self.SelectedSegment = None
  1453         self.Valid = True
  1551         self.Valid = True
  1454         self.Value = None
       
  1455         self.ValueSize = None
  1552         self.ValueSize = None
  1456         self.ComputedValue = None
  1553         self.ComputedValue = None
  1457         self.OverStart = False
  1554         self.OverStart = False
  1458         self.OverEnd = False
  1555         self.OverEnd = False
  1459         self.ComputingType = False
  1556         self.ComputingType = False
  1460         self.ToolTip = None
  1557         self.ToolTip = None
  1461         self.Font = parent.GetMiniFont()
       
  1462         
  1558         
  1463     def Flush(self):
  1559     def Flush(self):
  1464         self.StartConnected = None
  1560         self.StartConnected = None
  1465         self.EndConnected = None
  1561         self.EndConnected = None
  1466     
  1562     
  1489         if self.StartConnected:
  1585         if self.StartConnected:
  1490             rect = rect.Union(self.StartConnected.GetRedrawRect(movex, movey))
  1586             rect = rect.Union(self.StartConnected.GetRedrawRect(movex, movey))
  1491         if self.EndConnected:
  1587         if self.EndConnected:
  1492             rect = rect.Union(self.EndConnected.GetRedrawRect(movex, movey))
  1588             rect = rect.Union(self.EndConnected.GetRedrawRect(movex, movey))
  1493         if self.ValueSize is not None:
  1589         if self.ValueSize is not None:
  1494             width, height = self.ValueSize
       
  1495             width, height = self.ValueSize
  1590             width, height = self.ValueSize
  1496             if self.BoundingBox[2] > width * 4 or self.BoundingBox[3] > height * 4:
  1591             if self.BoundingBox[2] > width * 4 or self.BoundingBox[3] > height * 4:
  1497                 x = self.Points[0].x + width * self.StartPoint[1][0] / 2
  1592                 x = self.Points[0].x + width * self.StartPoint[1][0] / 2
  1498                 y = self.Points[0].y + (height * self.StartPoint[1][1] - 1) / 2
  1593                 y = self.Points[0].y + (height * self.StartPoint[1][1] - 1) / 2
  1499                 rect = rect.Union(wx.Rect(x, y, width, height))
  1594                 rect = rect.Union(wx.Rect(x, y, width, height))
  1622         elif self.EndConnected:
  1717         elif self.EndConnected:
  1623             return True
  1718             return True
  1624         return False
  1719         return False
  1625     
  1720     
  1626     def SetValue(self, value):
  1721     def SetValue(self, value):
  1627         if self.Value != value and self.Parent:
  1722         if self.Value != value:
  1628             self.Value = value
  1723             self.Value = value
  1629             if value is not None and not isinstance(value, BooleanType):
  1724             if value is not None and not isinstance(value, BooleanType):
  1630                 if isinstance(value, StringType):
  1725                 if isinstance(value, StringType):
  1631                     self.ComputedValue = "\"%s\""%value
  1726                     self.ComputedValue = "\"%s\""%value
  1632                 else:
  1727                 else:
  1634                 if self.ToolTip is not None:
  1729                 if self.ToolTip is not None:
  1635                     self.ToolTip.SetTip(self.ComputedValue)
  1730                     self.ToolTip.SetTip(self.ComputedValue)
  1636                 if len(self.ComputedValue) > 4:
  1731                 if len(self.ComputedValue) > 4:
  1637                     self.ComputedValue = self.ComputedValue[:4] + "..."
  1732                     self.ComputedValue = self.ComputedValue[:4] + "..."
  1638             if isinstance(self.ComputedValue, StringType):
  1733             if isinstance(self.ComputedValue, StringType):
  1639                 dc = wx.ClientDC(self.Parent)
  1734                 self.ValueSize = self.Parent.GetMiniTextExtent(self.ComputedValue)
  1640                 dc.SetFont(self.Font)
       
  1641                 self.ValueSize = dc.GetTextExtent(self.ComputedValue)
       
  1642             else:
  1735             else:
  1643                 self.ValueSize = None
  1736                 self.ValueSize = None
  1644             if self.StartConnected:
  1737             if self.StartConnected:
  1645                 self.StartConnected.RefreshValue()
  1738                 self.StartConnected.RefreshValue()
  1646             if self.EndConnected:
  1739             if self.EndConnected:
  1647                 self.EndConnected.RefreshValue()
  1740                 self.EndConnected.RefreshValue()
  1648             self.Refresh()
  1741             self.Parent.UpdateRefreshRect(self.GetRedrawRect())
  1649             if isinstance(value, BooleanType) and self.StartConnected is not None:
  1742             if isinstance(value, BooleanType) and self.StartConnected is not None:
  1650                 block = self.StartConnected.GetParentBlock()
  1743                 block = self.StartConnected.GetParentBlock()
  1651                 block.SpreadCurrent()
  1744                 block.SpreadCurrent()
  1652     
  1745     
  1653     def GetValue(self):
  1746     def GetValue(self):
  2512             dc.DrawLine(self.Points[self.SelectedSegment].x, self.Points[self.SelectedSegment].y,
  2605             dc.DrawLine(self.Points[self.SelectedSegment].x, self.Points[self.SelectedSegment].y,
  2513                         self.Points[self.SelectedSegment + 1].x, self.Points[self.SelectedSegment + 1].y)
  2606                         self.Points[self.SelectedSegment + 1].x, self.Points[self.SelectedSegment + 1].y)
  2514             if self.SelectedSegment == len(self.Segments) - 1:
  2607             if self.SelectedSegment == len(self.Segments) - 1:
  2515                 dc.DrawPoint(self.Points[-1].x, self.Points[-1].y)
  2608                 dc.DrawPoint(self.Points[-1].x, self.Points[-1].y)
  2516         if self.Value is not None and not isinstance(self.Value, BooleanType) and self.Value != "undefined":
  2609         if self.Value is not None and not isinstance(self.Value, BooleanType) and self.Value != "undefined":
  2517             dc.SetFont(self.Font)
  2610             dc.SetFont(self.Parent.GetMiniFont())
  2518             dc.SetTextForeground(wx.NamedColour("purple"))
  2611             dc.SetTextForeground(wx.NamedColour("purple"))
  2519             width, height = self.ValueSize
  2612             width, height = self.ValueSize
  2520             if self.BoundingBox[2] > width * 4 or self.BoundingBox[3] > height * 4:
  2613             if self.BoundingBox[2] > width * 4 or self.BoundingBox[3] > height * 4:
  2521                 x = self.Points[0].x + width * (self.StartPoint[1][0] - 1) / 2
  2614                 x = self.Points[0].x + width * (self.StartPoint[1][0] - 1) / 2
  2522                 y = self.Points[0].y + height * (self.StartPoint[1][1] - 1) / 2
  2615                 y = self.Points[0].y + height * (self.StartPoint[1][1] - 1) / 2