graphics/LD_Objects.py
changeset 814 5743cbdff669
child 1176 f4b434672204
equal deleted inserted replaced
813:1460273f40ed 814:5743cbdff669
       
     1 #!/usr/bin/env python
       
     2 # -*- coding: utf-8 -*-
       
     3 
       
     4 #This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor
       
     5 #based on the plcopen standard. 
       
     6 #
       
     7 #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
       
     8 #
       
     9 #See COPYING file for copyrights details.
       
    10 #
       
    11 #This library is free software; you can redistribute it and/or
       
    12 #modify it under the terms of the GNU General Public
       
    13 #License as published by the Free Software Foundation; either
       
    14 #version 2.1 of the License, or (at your option) any later version.
       
    15 #
       
    16 #This library is distributed in the hope that it will be useful,
       
    17 #but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    18 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    19 #General Public License for more details.
       
    20 #
       
    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
       
    23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    24 
       
    25 import wx
       
    26 
       
    27 from GraphicCommons import *
       
    28 from plcopen.structures import *
       
    29 
       
    30 #-------------------------------------------------------------------------------
       
    31 #                         Ladder Diagram PowerRail
       
    32 #-------------------------------------------------------------------------------
       
    33 
       
    34 """
       
    35 Class that implements the graphic representation of a power rail
       
    36 """
       
    37 
       
    38 class LD_PowerRail(Graphic_Element):
       
    39     
       
    40     # Create a new power rail
       
    41     def __init__(self, parent, type, id=None, connectors=1):
       
    42         Graphic_Element.__init__(self, parent)
       
    43         self.Type = None
       
    44         self.Connectors = []
       
    45         self.RealConnectors = None
       
    46         self.Id = id
       
    47         self.Extensions = [LD_LINE_SIZE / 2, LD_LINE_SIZE / 2]
       
    48         self.SetType(type, connectors)
       
    49         
       
    50     def Flush(self):
       
    51         for connector in self.Connectors:
       
    52             connector.Flush()
       
    53         self.Connectors = []
       
    54     
       
    55     # Make a clone of this LD_PowerRail
       
    56     def Clone(self, parent, id = None, pos = None):
       
    57         powerrail = LD_PowerRail(parent, self.Type, id)
       
    58         powerrail.SetSize(self.Size[0], self.Size[1])
       
    59         if pos is not None:
       
    60             powerrail.SetPosition(pos.x, pos.y)
       
    61         else:
       
    62             powerrail.SetPosition(self.Pos.x, self.Pos.y)
       
    63         powerrail.Connectors = []
       
    64         for connector in self.Connectors:
       
    65             powerrail.Connectors.append(connector.Clone(powerrail))
       
    66         return powerrail
       
    67     
       
    68     def GetConnectorTranslation(self, element):
       
    69         return dict(zip([connector for connector in self.Connectors],
       
    70                         [connector for connector in element.Connectors]))
       
    71     
       
    72     # Returns the RedrawRect
       
    73     def GetRedrawRect(self, movex = 0, movey = 0):
       
    74         rect = Graphic_Element.GetRedrawRect(self, movex, movey)
       
    75         for connector in self.Connectors:
       
    76             rect = rect.Union(connector.GetRedrawRect(movex, movey))
       
    77         if movex != 0 or movey != 0:
       
    78             for connector in self.Connectors:
       
    79                 if connector.IsConnected():
       
    80                     rect = rect.Union(connector.GetConnectedRedrawRect(movex, movey))
       
    81         return rect
       
    82     
       
    83     # Forbids to change the power rail size
       
    84     def SetSize(self, width, height):
       
    85         if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
       
    86             Graphic_Element.SetSize(self, width, height)
       
    87         else:
       
    88             Graphic_Element.SetSize(self, LD_POWERRAIL_WIDTH, height)
       
    89         self.RefreshConnectors()
       
    90     
       
    91     # Forbids to select a power rail
       
    92     def HitTest(self, pt, connectors=True):
       
    93         if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
       
    94             return Graphic_Element.HitTest(self, pt, connectors) or self.TestConnector(pt, exclude=False) != None
       
    95         return False
       
    96     
       
    97     # Forbids to select a power rail
       
    98     def IsInSelection(self, rect):
       
    99         if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
       
   100             return Graphic_Element.IsInSelection(self, rect)
       
   101         return False
       
   102     
       
   103     # Deletes this power rail by calling the appropriate method
       
   104     def Delete(self):
       
   105         self.Parent.DeletePowerRail(self)
       
   106     
       
   107     # Unconnect all connectors
       
   108     def Clean(self):
       
   109         for connector in self.Connectors:
       
   110             connector.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
       
   111                 
       
   112     # Refresh the power rail bounding box
       
   113     def RefreshBoundingBox(self):
       
   114         self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1)
       
   115     
       
   116     # Refresh the power rail size
       
   117     def RefreshSize(self):
       
   118         self.Size = wx.Size(LD_POWERRAIL_WIDTH, max(LD_LINE_SIZE * len(self.Connectors), self.Size[1]))
       
   119         self.RefreshBoundingBox()
       
   120     
       
   121     # Returns the block minimum size
       
   122     def GetMinSize(self):
       
   123         return LD_POWERRAIL_WIDTH, self.Extensions[0] + self.Extensions[1]
       
   124     
       
   125     # Add a connector or a blank to this power rail at the last place
       
   126     def AddConnector(self):
       
   127         self.InsertConnector(len(self.Connectors))
       
   128     
       
   129     # Add a connector or a blank to this power rail at the place given
       
   130     def InsertConnector(self, idx):
       
   131         if self.Type == LEFTRAIL:
       
   132             connector = Connector(self, "", "BOOL", wx.Point(self.Size[0], 0), EAST)
       
   133         elif self.Type == RIGHTRAIL:
       
   134             connector = Connector(self, "", "BOOL", wx.Point(0, 0), WEST)
       
   135         self.Connectors.insert(idx, connector)
       
   136         self.RefreshSize()
       
   137         self.RefreshConnectors()
       
   138     
       
   139     # Moves the divergence connector given
       
   140     def MoveConnector(self, connector, movey):
       
   141         position = connector.GetRelPosition()
       
   142         connector.SetPosition(wx.Point(position.x, position.y + movey))
       
   143         miny = self.Size[1]
       
   144         maxy = 0
       
   145         for connect in self.Connectors:
       
   146             connect_pos = connect.GetRelPosition()
       
   147             miny = min(miny, connect_pos.y - self.Extensions[0])
       
   148             maxy = max(maxy, connect_pos.y - self.Extensions[0])
       
   149         min_pos = self.Pos.y + miny
       
   150         self.Pos.y = min(min_pos, self.Pos.y)
       
   151         if min_pos == self.Pos.y:
       
   152             for connect in self.Connectors:
       
   153                 connect_pos = connect.GetRelPosition()
       
   154                 connect.SetPosition(wx.Point(connect_pos.x, connect_pos.y - miny))
       
   155         self.Connectors.sort(lambda x, y: cmp(x.Pos.y, y.Pos.y))
       
   156         maxy = 0
       
   157         for connect in self.Connectors:
       
   158             connect_pos = connect.GetRelPosition()
       
   159             maxy = max(maxy, connect_pos.y)
       
   160         self.Size[1] = max(maxy + self.Extensions[1], self.Size[1])
       
   161         connector.MoveConnected()
       
   162         self.RefreshBoundingBox()
       
   163     
       
   164     # Returns the index in connectors list for the connector given
       
   165     def GetConnectorIndex(self, connector):
       
   166         if connector in self.Connectors:
       
   167             return self.Connectors.index(connector)
       
   168         return None
       
   169     
       
   170     # Delete the connector or blank from connectors list at the index given
       
   171     def DeleteConnector(self, idx):
       
   172         self.Connectors.pop(idx)
       
   173         self.RefreshConnectors()
       
   174         self.RefreshSize()
       
   175     
       
   176     # Refresh the positions of the power rail connectors
       
   177     def RefreshConnectors(self):
       
   178         scaling = self.Parent.GetScaling()
       
   179         height = self.Size[1] - self.Extensions[0] - self.Extensions[1]
       
   180         interval = float(height) / float(max(len(self.Connectors) - 1, 1))
       
   181         for i, connector in enumerate(self.Connectors):
       
   182             if self.RealConnectors:
       
   183                 position = self.Extensions[0] + int(round(self.RealConnectors[i] * height))
       
   184             else:
       
   185                 position = self.Extensions[0] + int(round(i * interval))
       
   186             if scaling is not None:
       
   187                 position = round(float(self.Pos.y + position) / float(scaling[1])) * scaling[1] - self.Pos.y
       
   188             if self.Type == LEFTRAIL:
       
   189                 connector.SetPosition(wx.Point(self.Size[0], position))
       
   190             elif self.Type == RIGHTRAIL:
       
   191                 connector.SetPosition(wx.Point(0, position))
       
   192         self.RefreshConnected()
       
   193     
       
   194     # Refresh the position of wires connected to power rail
       
   195     def RefreshConnected(self, exclude = []):
       
   196         for connector in self.Connectors:
       
   197             connector.MoveConnected(exclude)
       
   198     
       
   199     # Returns the power rail connector that starts with the point given if it exists 
       
   200     def GetConnector(self, position, name = None):
       
   201         # if a name is given
       
   202         if name is not None:
       
   203             # Test each connector if it exists
       
   204             for connector in self.Connectors:
       
   205                 if name == connector.GetName():
       
   206                     return connector
       
   207         return self.FindNearestConnector(position, [connector for connector in self.Connectors if connector is not None])
       
   208     
       
   209     # Returns all the power rail connectors 
       
   210     def GetConnectors(self):
       
   211         connectors = [connector for connector in self.Connectors if connector]
       
   212         if self.Type == LEFTRAIL:
       
   213             return {"inputs": [], "outputs": connectors}
       
   214         else:
       
   215             return {"inputs": connectors, "outputs": []}
       
   216     
       
   217     # Test if point given is on one of the power rail connectors
       
   218     def TestConnector(self, pt, direction = None, exclude = True):
       
   219         for connector in self.Connectors:
       
   220             if connector.TestPoint(pt, direction, exclude):
       
   221                 return connector
       
   222         return None
       
   223     
       
   224     # Returns the power rail type
       
   225     def SetType(self, type, connectors):
       
   226         if type != self.Type or len(self.Connectors) != connectors:
       
   227             # Create a connector or a blank according to 'connectors' and add it in
       
   228             # the connectors list
       
   229             self.Type = type
       
   230             self.Clean()
       
   231             self.Connectors = []
       
   232             for connector in xrange(connectors):
       
   233                 self.AddConnector()
       
   234             self.RefreshSize()
       
   235     
       
   236     # Returns the power rail type
       
   237     def GetType(self):
       
   238         return self.Type
       
   239     
       
   240     # Method called when a LeftDown event have been generated
       
   241     def OnLeftDown(self, event, dc, scaling):
       
   242         self.RealConnectors = []
       
   243         height = self.Size[1] - self.Extensions[0] - self.Extensions[1]
       
   244         if height > 0:
       
   245             for connector in self.Connectors:
       
   246                 position = connector.GetRelPosition()
       
   247                 self.RealConnectors.append(max(0., min(float(position.y - self.Extensions[0]) / float(height), 1.)))
       
   248         elif len(self.Connectors) > 1:
       
   249             self.RealConnectors = map(lambda x : x * 1 / (len(self.Connectors) - 1), xrange(len(self.Connectors)))
       
   250         else:
       
   251             self.RealConnectors = [0.5]
       
   252         Graphic_Element.OnLeftDown(self, event, dc, scaling)
       
   253     
       
   254     # Method called when a LeftUp event have been generated
       
   255     def OnLeftUp(self, event, dc, scaling):
       
   256         Graphic_Element.OnLeftUp(self, event, dc, scaling)
       
   257         self.RealConnectors = None
       
   258     
       
   259     # Method called when a LeftDown event have been generated
       
   260     def OnRightDown(self, event, dc, scaling):
       
   261         pos = GetScaledEventPosition(event, dc, scaling)
       
   262         # Test if a connector have been handled
       
   263         connector = self.TestConnector(pos, exclude=False)
       
   264         if connector:
       
   265             self.Handle = (HANDLE_CONNECTOR, connector)
       
   266             wx.CallAfter(self.Parent.SetCurrentCursor, 1)
       
   267             self.Selected = False
       
   268             # Initializes the last position
       
   269             self.oldPos = GetScaledEventPosition(event, dc, scaling)
       
   270         else:
       
   271             Graphic_Element.OnRightDown(self, event, dc, scaling)
       
   272     
       
   273     # Method called when a LeftDClick event have been generated
       
   274     def OnLeftDClick(self, event, dc, scaling):
       
   275         # Edit the powerrail properties
       
   276         self.Parent.EditPowerRailContent(self)
       
   277     
       
   278     # Method called when a RightUp event have been generated
       
   279     def OnRightUp(self, event, dc, scaling):
       
   280         handle_type, handle = self.Handle
       
   281         if handle_type == HANDLE_CONNECTOR:
       
   282             wires = handle.GetWires()
       
   283             if len(wires) == 1:
       
   284                 if handle == wires[0][0].StartConnected:
       
   285                     block = wires[0][0].EndConnected.GetParentBlock()
       
   286                 else:
       
   287                     block = wires[0][0].StartConnected.GetParentBlock()
       
   288                 block.RefreshModel(False)
       
   289             Graphic_Element.OnRightUp(self, event, dc, scaling)
       
   290         else:
       
   291             self.Parent.PopupDefaultMenu()
       
   292     
       
   293     def Resize(self, x, y, width, height):
       
   294         self.Move(x, y)
       
   295         if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
       
   296             self.SetSize(width, height)
       
   297         else:
       
   298             self.SetSize(LD_POWERRAIL_WIDTH, height)
       
   299 
       
   300     # Refreshes the powerrail state according to move defined and handle selected
       
   301     def ProcessDragging(self, movex, movey, event, scaling):
       
   302         handle_type, handle = self.Handle
       
   303         # A connector has been handled
       
   304         if handle_type == HANDLE_CONNECTOR:
       
   305             movey = max(-self.BoundingBox.y, movey)
       
   306             if scaling is not None:
       
   307                 position = handle.GetRelPosition()
       
   308                 movey = round(float(self.Pos.y + position.y + movey) / float(scaling[1])) * scaling[1] - self.Pos.y - position.y
       
   309             self.MoveConnector(handle, movey)
       
   310             return 0, movey
       
   311         elif self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
       
   312             return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling)
       
   313         return 0, 0
       
   314     
       
   315     # Refreshes the power rail model
       
   316     def RefreshModel(self, move=True):
       
   317         self.Parent.RefreshPowerRailModel(self)
       
   318         # If power rail has moved and power rail is of type LEFT, refresh the model 
       
   319         # of wires connected to connectors
       
   320         if move and self.Type == LEFTRAIL:
       
   321             for connector in self.Connectors:
       
   322                 connector.RefreshWires()
       
   323     
       
   324     # Draws power rail
       
   325     def Draw(self, dc):
       
   326         Graphic_Element.Draw(self, dc)
       
   327         dc.SetPen(MiterPen(wx.BLACK))
       
   328         dc.SetBrush(wx.BLACK_BRUSH)
       
   329         # Draw a rectangle with the power rail size
       
   330         if self.Type == LEFTRAIL:
       
   331             dc.DrawRectangle(self.Pos.x + self.Size[0] - LD_POWERRAIL_WIDTH, self.Pos.y, LD_POWERRAIL_WIDTH + 1, self.Size[1] + 1)
       
   332         else:
       
   333             dc.DrawRectangle(self.Pos.x, self.Pos.y, LD_POWERRAIL_WIDTH + 1, self.Size[1] + 1)
       
   334         # Draw connectors
       
   335         for connector in self.Connectors:
       
   336             connector.Draw(dc)
       
   337         
       
   338 
       
   339 #-------------------------------------------------------------------------------
       
   340 #                         Ladder Diagram Contact
       
   341 #-------------------------------------------------------------------------------
       
   342 
       
   343 """
       
   344 Class that implements the graphic representation of a contact
       
   345 """
       
   346 
       
   347 class LD_Contact(Graphic_Element, DebugDataConsumer):
       
   348     
       
   349     # Create a new contact
       
   350     def __init__(self, parent, type, name, id = None):
       
   351         Graphic_Element.__init__(self, parent)
       
   352         DebugDataConsumer.__init__(self)
       
   353         self.Type = type
       
   354         self.Name = name
       
   355         self.Id = id
       
   356         self.Size = wx.Size(LD_ELEMENT_SIZE[0], LD_ELEMENT_SIZE[1])
       
   357         self.Highlights = {}
       
   358         # Create an input and output connector
       
   359         self.Input = Connector(self, "", "BOOL", wx.Point(0, self.Size[1] / 2 + 1), WEST)
       
   360         self.Output = Connector(self, "", "BOOL", wx.Point(self.Size[0], self.Size[1] / 2 + 1), EAST)
       
   361         self.PreviousValue = False
       
   362         self.PreviousSpreading = False
       
   363         self.RefreshNameSize()
       
   364         self.RefreshTypeSize()
       
   365     
       
   366     def Flush(self):
       
   367         if self.Input is not None:
       
   368             self.Input.Flush()
       
   369             self.Input = None
       
   370         if self.Output is not None:
       
   371             self.Output.Flush()
       
   372             self.Output = None
       
   373     
       
   374     def SetForced(self, forced):
       
   375         if self.Forced != forced:
       
   376             self.Forced = forced
       
   377             if self.Visible:
       
   378                 self.Parent.ElementNeedRefresh(self)
       
   379     
       
   380     def SetValue(self, value):
       
   381         if self.Type == CONTACT_RISING:
       
   382             refresh = self.Value and not self.PreviousValue
       
   383         elif self.Type == CONTACT_FALLING:
       
   384             refresh = not self.Value and self.PreviousValue
       
   385         else:
       
   386             refresh = False
       
   387         self.PreviousValue = self.Value
       
   388         self.Value = value
       
   389         if self.Value != self.PreviousValue or refresh:
       
   390             if self.Visible:
       
   391                 self.Parent.ElementNeedRefresh(self)
       
   392             self.SpreadCurrent()
       
   393     
       
   394     def SpreadCurrent(self):
       
   395         if self.Parent.Debug:
       
   396             if self.Value is None:
       
   397                 self.Value = False
       
   398             spreading = self.Input.ReceivingCurrent()
       
   399             if self.Type == CONTACT_NORMAL:
       
   400                 spreading &= self.Value
       
   401             elif self.Type == CONTACT_REVERSE:
       
   402                 spreading &= not self.Value
       
   403             elif self.Type == CONTACT_RISING:
       
   404                 spreading &= self.Value and not self.PreviousValue
       
   405             elif self.Type == CONTACT_FALLING:
       
   406                 spreading &= not self.Value and self.PreviousValue
       
   407             else:
       
   408                 spreading = False
       
   409             if spreading and not self.PreviousSpreading:
       
   410                 self.Output.SpreadCurrent(True)
       
   411             elif not spreading and self.PreviousSpreading:
       
   412                 self.Output.SpreadCurrent(False)
       
   413             self.PreviousSpreading = spreading
       
   414     
       
   415     # Make a clone of this LD_Contact
       
   416     def Clone(self, parent, id = None, pos = None):
       
   417         contact = LD_Contact(parent, self.Type, self.Name, id)
       
   418         contact.SetSize(self.Size[0], self.Size[1])
       
   419         if pos is not None:
       
   420             contact.SetPosition(pos.x, pos.y)
       
   421         else:
       
   422             contact.SetPosition(self.Pos.x, self.Pos.y)
       
   423         contact.Input = self.Input.Clone(contact)
       
   424         contact.Output = self.Output.Clone(contact)
       
   425         return contact
       
   426     
       
   427     def GetConnectorTranslation(self, element):
       
   428         return {self.Input : element.Input, self.Output : element.Output}
       
   429     
       
   430     # Returns the RedrawRect
       
   431     def GetRedrawRect(self, movex = 0, movey = 0):
       
   432         rect = Graphic_Element.GetRedrawRect(self, movex, movey)
       
   433         rect = rect.Union(self.Input.GetRedrawRect(movex, movey))
       
   434         rect = rect.Union(self.Output.GetRedrawRect(movex, movey))
       
   435         if movex != 0 or movey != 0:
       
   436             if self.Input.IsConnected():
       
   437                 rect = rect.Union(self.Input.GetConnectedRedrawRect(movex, movey))
       
   438             if self.Output.IsConnected():
       
   439                 rect = rect.Union(self.Output.GetConnectedRedrawRect(movex, movey))
       
   440         return rect
       
   441 
       
   442     def ProcessDragging(self, movex, movey, event, scaling):
       
   443         if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
       
   444             movex = movey = 0
       
   445         return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling, height_fac = 2)
       
   446     
       
   447     # Forbids to change the contact size
       
   448     def SetSize(self, width, height):
       
   449         if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
       
   450             Graphic_Element.SetSize(self, width, height)
       
   451             self.RefreshConnectors()
       
   452     
       
   453     # Delete this contact by calling the appropriate method
       
   454     def Delete(self):
       
   455         self.Parent.DeleteContact(self)
       
   456     
       
   457     # Unconnect input and output
       
   458     def Clean(self):
       
   459         self.Input.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
       
   460         self.Output.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
       
   461     
       
   462     # Refresh the size of text for name
       
   463     def RefreshNameSize(self):
       
   464         if self.Name != "":
       
   465             self.NameSize = self.Parent.GetTextExtent(self.Name)
       
   466         else:
       
   467             self.NameSize = 0, 0
       
   468     
       
   469     # Refresh the size of text for type
       
   470     def RefreshTypeSize(self):
       
   471         typetext = ""
       
   472         if self.Type == CONTACT_REVERSE:
       
   473             typetext = "/"
       
   474         elif self.Type == CONTACT_RISING:
       
   475             typetext = "P"
       
   476         elif self.Type == CONTACT_FALLING:
       
   477             typetext = "N"
       
   478         if typetext != "":
       
   479             self.TypeSize = self.Parent.GetTextExtent(typetext)
       
   480         else:
       
   481             self.TypeSize = 0, 0
       
   482     
       
   483     # Refresh the contact bounding box
       
   484     def RefreshBoundingBox(self):
       
   485         # Calculate the size of the name outside the contact
       
   486         text_width, text_height = self.Parent.GetTextExtent(self.Name)
       
   487         # Calculate the bounding box size
       
   488         if self.Name != "":
       
   489             bbx_x = self.Pos.x - max(0, (text_width - self.Size[0]) / 2)
       
   490             bbx_width = max(self.Size[0], text_width)
       
   491             bbx_y = self.Pos.y - (text_height + 2)
       
   492             bbx_height = self.Size[1] + (text_height + 2)
       
   493         else:
       
   494             bbx_x = self.Pos.x
       
   495             bbx_width = self.Size[0]
       
   496             bbx_y = self.Pos.y
       
   497             bbx_height = self.Size[1]
       
   498         self.BoundingBox = wx.Rect(bbx_x, bbx_y, bbx_width + 1, bbx_height + 1)
       
   499     
       
   500     # Returns the block minimum size
       
   501     def GetMinSize(self):
       
   502         return LD_ELEMENT_SIZE
       
   503     
       
   504     # Refresh the position of wire connected to contact
       
   505     def RefreshConnected(self, exclude = []):
       
   506         self.Input.MoveConnected(exclude)
       
   507         self.Output.MoveConnected(exclude)
       
   508     
       
   509     # Returns the contact connector that starts with the point given if it exists 
       
   510     def GetConnector(self, position, name = None):
       
   511         # if a name is given
       
   512         if name is not None:
       
   513             # Test input and output connector
       
   514             #if name == self.Input.GetName():
       
   515             #    return self.Input
       
   516             if name == self.Output.GetName():
       
   517                 return self.Output
       
   518         return self.FindNearestConnector(position, [self.Input, self.Output])
       
   519     
       
   520     # Returns input and output contact connectors 
       
   521     def GetConnectors(self):
       
   522         return {"inputs": [self.Input], "outputs": [self.Output]}
       
   523     
       
   524     # Test if point given is on contact input or output connector
       
   525     def TestConnector(self, pt, direction = None, exclude=True):
       
   526         # Test input connector
       
   527         if self.Input.TestPoint(pt, direction, exclude):
       
   528             return self.Input
       
   529         # Test output connector
       
   530         if self.Output.TestPoint(pt, direction, exclude):
       
   531             return self.Output
       
   532         return None
       
   533 
       
   534     # Refresh the positions of the block connectors
       
   535     def RefreshConnectors(self):
       
   536         scaling = self.Parent.GetScaling()
       
   537         position = self.Size[1] / 2 + 1
       
   538         if scaling is not None:
       
   539             position = round(float(self.Pos.y + position) / float(scaling[1])) * scaling[1] - self.Pos.y
       
   540         self.Input.SetPosition(wx.Point(0, position))
       
   541         self.Output.SetPosition(wx.Point(self.Size[0], position))
       
   542         self.RefreshConnected()
       
   543 
       
   544     # Changes the contact name
       
   545     def SetName(self, name):
       
   546         self.Name = name
       
   547         self.RefreshNameSize()
       
   548 
       
   549     # Returns the contact name
       
   550     def GetName(self):
       
   551         return self.Name
       
   552 
       
   553     # Changes the contact type
       
   554     def SetType(self, type):
       
   555         self.Type = type
       
   556         self.RefreshTypeSize()
       
   557 
       
   558     # Returns the contact type
       
   559     def GetType(self):
       
   560         return self.Type
       
   561     
       
   562     # Method called when a LeftDClick event have been generated
       
   563     def OnLeftDClick(self, event, dc, scaling):
       
   564         # Edit the contact properties
       
   565         self.Parent.EditContactContent(self)
       
   566     
       
   567     # Method called when a RightUp event have been generated
       
   568     def OnRightUp(self, event, dc, scaling):
       
   569         # Popup the default menu
       
   570         self.Parent.PopupDefaultMenu()
       
   571     
       
   572     # Refreshes the contact model
       
   573     def RefreshModel(self, move=True):
       
   574         self.Parent.RefreshContactModel(self)
       
   575         # If contact has moved, refresh the model of wires connected to output
       
   576         if move:
       
   577             self.Output.RefreshWires()
       
   578     
       
   579     # Draws the highlightment of this element if it is highlighted
       
   580     def DrawHighlightment(self, dc):
       
   581         scalex, scaley = dc.GetUserScale()
       
   582         dc.SetUserScale(1, 1)
       
   583         dc.SetPen(MiterPen(HIGHLIGHTCOLOR))
       
   584         dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR))
       
   585         dc.SetLogicalFunction(wx.AND)
       
   586         # Draw two rectangles for representing the contact
       
   587         left_left = (self.Pos.x - 1) * scalex - 2
       
   588         right_left = (self.Pos.x + self.Size[0] - 2) * scalex - 2
       
   589         top = (self.Pos.y - 1) * scaley - 2
       
   590         width = 4 * scalex + 5
       
   591         height = (self.Size[1] + 3) * scaley + 5
       
   592         
       
   593         dc.DrawRectangle(left_left, top, width, height)
       
   594         dc.DrawRectangle(right_left, top, width, height)
       
   595         dc.SetLogicalFunction(wx.COPY)
       
   596         dc.SetUserScale(scalex, scaley)
       
   597     
       
   598     # Adds an highlight to the connection
       
   599     def AddHighlight(self, infos, start, end, highlight_type):
       
   600         highlights = self.Highlights.setdefault(infos[0], [])
       
   601         if infos[0] == "reference":
       
   602             if start[0] == 0 and end[0] == 0:
       
   603                 AddHighlight(highlights, (start, end, highlight_type))
       
   604         else:
       
   605             AddHighlight(highlights, ((0, 0), (0, 1), highlight_type))
       
   606     
       
   607     # Removes an highlight from the connection
       
   608     def RemoveHighlight(self, infos, start, end, highlight_type):
       
   609         highlights = self.Highlights.get(infos[0], [])
       
   610         if RemoveHighlight(highlights, (start, end, highlight_type)) and len(highlights) == 0:
       
   611             self.Highlights.pop(infos[0])
       
   612     
       
   613     # Removes all the highlights of one particular type from the connection
       
   614     def ClearHighlight(self, highlight_type=None):
       
   615         if highlight_type is None:
       
   616             self.Highlights = {}
       
   617         else:
       
   618             highlight_items = self.Highlights.items()
       
   619             for name, highlights in highlight_items:
       
   620                 highlights = ClearHighlights(highlight, highlight_type)
       
   621                 if len(highlights) == 0:
       
   622                     self.Highlights.pop(name)
       
   623     
       
   624     # Draws contact
       
   625     def Draw(self, dc):
       
   626         Graphic_Element.Draw(self, dc)
       
   627         if self.Value is not None:            
       
   628             if self.Type == CONTACT_NORMAL and self.Value or \
       
   629                self.Type == CONTACT_REVERSE and not self.Value or \
       
   630                self.Type == CONTACT_RISING and self.Value and not self.PreviousValue or \
       
   631                self.Type == CONTACT_RISING and not self.Value and self.PreviousValue:
       
   632                 if self.Forced:
       
   633                     dc.SetPen(MiterPen(wx.CYAN))
       
   634                 else:
       
   635                     dc.SetPen(MiterPen(wx.GREEN))
       
   636             elif self.Forced:
       
   637                 dc.SetPen(MiterPen(wx.BLUE))
       
   638             else:
       
   639                 dc.SetPen(MiterPen(wx.BLACK))
       
   640         else:
       
   641             dc.SetPen(MiterPen(wx.BLACK))
       
   642         dc.SetBrush(wx.BLACK_BRUSH)
       
   643         
       
   644         # Compiling contact type modifier symbol
       
   645         typetext = ""
       
   646         if self.Type == CONTACT_REVERSE:
       
   647             typetext = "/"
       
   648         elif self.Type == CONTACT_RISING:
       
   649             typetext = "P"
       
   650         elif self.Type == CONTACT_FALLING:
       
   651             typetext = "N"
       
   652         
       
   653         if getattr(dc, "printing", False):
       
   654             name_size = dc.GetTextExtent(self.Name)
       
   655             if typetext != "":
       
   656                 type_size = dc.GetTextExtent(typetext)
       
   657         else:
       
   658             name_size = self.NameSize
       
   659             if typetext != "":
       
   660                 type_size = self.TypeSize
       
   661         
       
   662         # Draw two rectangles for representing the contact
       
   663         dc.DrawRectangle(self.Pos.x, self.Pos.y, 2, self.Size[1] + 1)
       
   664         dc.DrawRectangle(self.Pos.x + self.Size[0] - 1, self.Pos.y, 2, self.Size[1] + 1)
       
   665         # Draw contact name
       
   666         name_pos = (self.Pos.x + (self.Size[0] - name_size[0]) / 2,
       
   667                     self.Pos.y - (name_size[1] + 2))
       
   668         dc.DrawText(self.Name, name_pos[0], name_pos[1])
       
   669         # Draw the modifier symbol in the middle of contact
       
   670         if typetext != "":
       
   671             type_pos = (self.Pos.x + (self.Size[0] - type_size[0]) / 2 + 1,
       
   672                         self.Pos.y + (self.Size[1] - type_size[1]) / 2)
       
   673             dc.DrawText(typetext, type_pos[0], type_pos[1])
       
   674         # Draw input and output connectors
       
   675         self.Input.Draw(dc)
       
   676         self.Output.Draw(dc)
       
   677         
       
   678         if not getattr(dc, "printing", False):
       
   679             for name, highlights in self.Highlights.iteritems():
       
   680                 if name == "reference":
       
   681                     DrawHighlightedText(dc, self.Name, highlights, name_pos[0], name_pos[1])
       
   682                 elif typetext != "":
       
   683                     DrawHighlightedText(dc, typetext, highlights, type_pos[0], type_pos[1])
       
   684 
       
   685 #-------------------------------------------------------------------------------
       
   686 #                         Ladder Diagram Coil
       
   687 #-------------------------------------------------------------------------------
       
   688 
       
   689 """
       
   690 Class that implements the graphic representation of a coil
       
   691 """
       
   692 
       
   693 class LD_Coil(Graphic_Element):
       
   694     
       
   695     # Create a new coil
       
   696     def __init__(self, parent, type, name, id = None):
       
   697         Graphic_Element.__init__(self, parent)
       
   698         self.Type = type
       
   699         self.Name = name
       
   700         self.Id = id
       
   701         self.Size = wx.Size(LD_ELEMENT_SIZE[0], LD_ELEMENT_SIZE[1])
       
   702         self.Highlights = {}
       
   703         # Create an input and output connector
       
   704         self.Input = Connector(self, "", "BOOL", wx.Point(0, self.Size[1] / 2 + 1), WEST)
       
   705         self.Output = Connector(self, "", "BOOL", wx.Point(self.Size[0], self.Size[1] / 2 + 1), EAST)
       
   706         self.Value = None
       
   707         self.PreviousValue = False
       
   708         self.RefreshNameSize()
       
   709         self.RefreshTypeSize()
       
   710         
       
   711     def Flush(self):
       
   712         if self.Input is not None:
       
   713             self.Input.Flush()
       
   714             self.Input = None
       
   715         if self.Output is not None:
       
   716             self.Output.Flush()
       
   717             self.Output = None
       
   718     
       
   719     def SpreadCurrent(self):
       
   720         if self.Parent.Debug:
       
   721             self.PreviousValue = self.Value
       
   722             self.Value = self.Input.ReceivingCurrent()
       
   723             if self.Value and not self.PreviousValue:
       
   724                 self.Output.SpreadCurrent(True)
       
   725             elif not self.Value and self.PreviousValue:
       
   726                 self.Output.SpreadCurrent(False)
       
   727             if self.Value != self.PreviousValue and self.Visible:
       
   728                 self.Parent.ElementNeedRefresh(self)
       
   729     
       
   730     # Make a clone of this LD_Coil
       
   731     def Clone(self, parent, id = None, pos = None):
       
   732         coil = LD_Coil(parent, self.Type, self.Name, id)
       
   733         coil.SetSize(self.Size[0], self.Size[1])
       
   734         if pos is not None:
       
   735             coil.SetPosition(pos.x, pos.y)
       
   736         else:
       
   737             coil.SetPosition(self.Pos.x, self.Pos.y)
       
   738         coil.Input = self.Input.Clone(coil)
       
   739         coil.Output = self.Output.Clone(coil)
       
   740         return coil
       
   741     
       
   742     def GetConnectorTranslation(self, element):
       
   743         return {self.Input : element.Input, self.Output : element.Output}
       
   744     
       
   745     # Returns the RedrawRect
       
   746     def GetRedrawRect(self, movex = 0, movey = 0):
       
   747         rect = Graphic_Element.GetRedrawRect(self, movex, movey)
       
   748         rect = rect.Union(self.Input.GetRedrawRect(movex, movey))
       
   749         rect = rect.Union(self.Output.GetRedrawRect(movex, movey))
       
   750         if movex != 0 or movey != 0:
       
   751             if self.Input.IsConnected():
       
   752                 rect = rect.Union(self.Input.GetConnectedRedrawRect(movex, movey))
       
   753             if self.Output.IsConnected():
       
   754                 rect = rect.Union(self.Output.GetConnectedRedrawRect(movex, movey))
       
   755         return rect
       
   756     
       
   757     def ProcessDragging(self, movex, movey, event, scaling):
       
   758         if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
       
   759             movex = movey = 0
       
   760         return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling, height_fac = 2)    
       
   761     
       
   762     # Forbids to change the Coil size
       
   763     def SetSize(self, width, height):
       
   764         if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
       
   765             Graphic_Element.SetSize(self, width, height)
       
   766             self.RefreshConnectors()
       
   767     
       
   768     # Delete this coil by calling the appropriate method
       
   769     def Delete(self):
       
   770         self.Parent.DeleteCoil(self)
       
   771     
       
   772     # Unconnect input and output
       
   773     def Clean(self):
       
   774         self.Input.UnConnect()
       
   775         self.Output.UnConnect()
       
   776                 
       
   777     # Refresh the size of text for name
       
   778     def RefreshNameSize(self):
       
   779         if self.Name != "":
       
   780             self.NameSize = self.Parent.GetTextExtent(self.Name)
       
   781         else:
       
   782             self.NameSize = 0, 0
       
   783     
       
   784     # Refresh the size of text for type
       
   785     def RefreshTypeSize(self):
       
   786         typetext = ""
       
   787         if self.Type == COIL_REVERSE:
       
   788             typetext = "/"
       
   789         elif self.Type == COIL_SET:
       
   790             typetext = "S"
       
   791         elif self.Type == COIL_RESET:
       
   792             typetext = "R"
       
   793         elif self.Type == COIL_RISING:
       
   794             typetext = "P"
       
   795         elif self.Type == COIL_FALLING:
       
   796             typetext = "N"
       
   797         if typetext != "":
       
   798             self.TypeSize = self.Parent.GetTextExtent(typetext)
       
   799         else:
       
   800             self.TypeSize = 0, 0
       
   801     
       
   802     # Refresh the coil bounding box
       
   803     def RefreshBoundingBox(self):
       
   804         # Calculate the size of the name outside the coil
       
   805         text_width, text_height = self.Parent.GetTextExtent(self.Name)
       
   806         # Calculate the bounding box size
       
   807         if self.Name != "":
       
   808             bbx_x = self.Pos.x - max(0, (text_width - self.Size[0]) / 2)
       
   809             bbx_width = max(self.Size[0], text_width)
       
   810             bbx_y = self.Pos.y - (text_height + 2)
       
   811             bbx_height = self.Size[1] + (text_height + 2)
       
   812         else:
       
   813             bbx_x = self.Pos.x
       
   814             bbx_width = self.Size[0]
       
   815             bbx_y = self.Pos.y
       
   816             bbx_height = self.Size[1]
       
   817         self.BoundingBox = wx.Rect(bbx_x, bbx_y, bbx_width + 1, bbx_height + 1)
       
   818         
       
   819     # Returns the block minimum size
       
   820     def GetMinSize(self):
       
   821         return LD_ELEMENT_SIZE
       
   822     
       
   823     # Refresh the position of wire connected to coil
       
   824     def RefreshConnected(self, exclude = []):
       
   825         self.Input.MoveConnected(exclude)
       
   826         self.Output.MoveConnected(exclude)
       
   827     
       
   828     # Returns the coil connector that starts with the point given if it exists 
       
   829     def GetConnector(self, position, name = None):
       
   830         # if a name is given
       
   831         if name is not None:
       
   832             # Test input and output connector
       
   833             #if self.Input and name == self.Input.GetName():
       
   834             #    return self.Input
       
   835             if self.Output and name == self.Output.GetName():
       
   836                 return self.Output
       
   837         return self.FindNearestConnector(position, [self.Input, self.Output])
       
   838     
       
   839     # Returns input and output coil connectors 
       
   840     def GetConnectors(self):
       
   841         return {"inputs": [self.Input], "outputs": [self.Output]}
       
   842     
       
   843     # Test if point given is on coil input or output connector
       
   844     def TestConnector(self, pt, direction = None, exclude=True):
       
   845         # Test input connector
       
   846         if self.Input.TestPoint(pt, direction, exclude):
       
   847             return self.Input
       
   848         # Test output connector
       
   849         if self.Output.TestPoint(pt, direction, exclude):
       
   850             return self.Output
       
   851         return None
       
   852     
       
   853     # Refresh the positions of the block connectors
       
   854     def RefreshConnectors(self):
       
   855         scaling = self.Parent.GetScaling()
       
   856         position = self.Size[1] / 2 + 1
       
   857         if scaling is not None:
       
   858             position = round(float(self.Pos.y + position) / float(scaling[1])) * scaling[1] - self.Pos.y
       
   859         self.Input.SetPosition(wx.Point(0, position))
       
   860         self.Output.SetPosition(wx.Point(self.Size[0], position))
       
   861         self.RefreshConnected()
       
   862     
       
   863     # Changes the coil name
       
   864     def SetName(self, name):
       
   865         self.Name = name
       
   866         self.RefreshNameSize()
       
   867 
       
   868     # Returns the coil name
       
   869     def GetName(self):
       
   870         return self.Name
       
   871     
       
   872     # Changes the coil type
       
   873     def SetType(self, type):
       
   874         self.Type = type
       
   875         self.RefreshTypeSize()
       
   876     
       
   877     # Returns the coil type
       
   878     def GetType(self):
       
   879         return self.Type
       
   880     
       
   881     # Method called when a LeftDClick event have been generated
       
   882     def OnLeftDClick(self, event, dc, scaling):
       
   883         # Edit the coil properties
       
   884         self.Parent.EditCoilContent(self)
       
   885     
       
   886     # Method called when a RightUp event have been generated
       
   887     def OnRightUp(self, event, dc, scaling):
       
   888         # Popup the default menu
       
   889         self.Parent.PopupDefaultMenu()
       
   890     
       
   891     # Refreshes the coil model
       
   892     def RefreshModel(self, move=True):
       
   893         self.Parent.RefreshCoilModel(self)
       
   894         # If coil has moved, refresh the model of wires connected to output
       
   895         if move:
       
   896             self.Output.RefreshWires()
       
   897     
       
   898     # Draws the highlightment of this element if it is highlighted
       
   899     def DrawHighlightment(self, dc):
       
   900         scalex, scaley = dc.GetUserScale()
       
   901         dc.SetUserScale(1, 1)
       
   902         dc.SetPen(MiterPen(HIGHLIGHTCOLOR, (3 * scalex + 5), wx.SOLID))
       
   903         dc.SetBrush(wx.TRANSPARENT_BRUSH)
       
   904         dc.SetLogicalFunction(wx.AND)
       
   905         # Draw a two circle arcs for representing the coil
       
   906         dc.DrawEllipticArc(round(self.Pos.x * scalex), 
       
   907                            round((self.Pos.y - int(self.Size[1] * (sqrt(2) - 1.) / 2.) + 1) * scaley), 
       
   908                            round(self.Size[0] * scalex), 
       
   909                            round((int(self.Size[1] * sqrt(2)) - 1) * scaley),
       
   910                            135, 225)
       
   911         dc.DrawEllipticArc(round(self.Pos.x * scalex), 
       
   912                            round((self.Pos.y - int(self.Size[1] * (sqrt(2) - 1.) / 2.) + 1) * scaley), 
       
   913                            round(self.Size[0] * scalex), 
       
   914                            round((int(self.Size[1] * sqrt(2)) - 1) * scaley),
       
   915                            -45, 45)
       
   916         dc.SetLogicalFunction(wx.COPY)
       
   917         dc.SetUserScale(scalex, scaley)
       
   918     
       
   919     # Adds an highlight to the connection
       
   920     def AddHighlight(self, infos, start, end, highlight_type):
       
   921         highlights = self.Highlights.setdefault(infos[0], [])
       
   922         if infos[0] == "reference":
       
   923             if start[0] == 0 and end[0] == 0:
       
   924                 AddHighlight(highlights, (start, end, highlight_type))
       
   925         else:
       
   926             AddHighlight(highlights, ((0, 0), (0, 1), highlight_type))
       
   927     
       
   928     # Removes an highlight from the connection
       
   929     def RemoveHighlight(self, infos, start, end, highlight_type):
       
   930         highlights = self.Highlights.get(infos[0], [])
       
   931         if RemoveHighlight(highlights, (start, end, highlight_type)) and len(highlights) == 0:
       
   932             self.Highlights.pop(infos[0])
       
   933     
       
   934     # Removes all the highlights of one particular type from the connection
       
   935     def ClearHighlight(self, highlight_type=None):
       
   936         if highlight_type is None:
       
   937             self.Highlights = {}
       
   938         else:
       
   939             highlight_items = self.Highlights.items()
       
   940             for name, highlights in highlight_items:
       
   941                 highlights = ClearHighlights(highlight, highlight_type)
       
   942                 if len(highlights) == 0:
       
   943                     self.Highlights.pop(name)
       
   944     
       
   945     # Draws coil
       
   946     def Draw(self, dc):
       
   947         Graphic_Element.Draw(self, dc)
       
   948         if self.Value is not None and self.Value:
       
   949             dc.SetPen(MiterPen(wx.GREEN, 2, wx.SOLID))
       
   950         else:
       
   951             dc.SetPen(MiterPen(wx.BLACK, 2, wx.SOLID))
       
   952         dc.SetBrush(wx.TRANSPARENT_BRUSH)
       
   953         
       
   954         # Compiling coil type modifier symbol 
       
   955         typetext = ""
       
   956         if self.Type == COIL_REVERSE:
       
   957             typetext = "/"
       
   958         elif self.Type == COIL_SET:
       
   959             typetext = "S"
       
   960         elif self.Type == COIL_RESET:
       
   961             typetext = "R"
       
   962         elif self.Type == COIL_RISING:
       
   963             typetext = "P"
       
   964         elif self.Type == COIL_FALLING:
       
   965             typetext = "N"
       
   966         
       
   967         if getattr(dc, "printing", False) and not isinstance(dc, wx.PostScriptDC):
       
   968             # Draw an clipped ellipse for representing the coil
       
   969             clipping_box = dc.GetClippingBox()
       
   970             dc.SetClippingRegion(self.Pos.x - 1, self.Pos.y, self.Size[0] + 2, self.Size[1] + 1)
       
   971             dc.DrawEllipse(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)
       
   972             dc.DestroyClippingRegion()
       
   973             if clipping_box != (0, 0, 0, 0):
       
   974                 dc.SetClippingRegion(*clipping_box)
       
   975             name_size = dc.GetTextExtent(self.Name)
       
   976             if typetext != "":
       
   977                 type_size = dc.GetTextExtent(typetext)
       
   978         else:
       
   979             # Draw a two ellipse arcs for representing the coil
       
   980             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)
       
   981             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)
       
   982             # Draw a point to avoid hole in left arc
       
   983             if not getattr(dc, "printing", False):
       
   984                 if self.Value is not None and self.Value:
       
   985                     dc.SetPen(MiterPen(wx.GREEN))
       
   986                 else:
       
   987                     dc.SetPen(MiterPen(wx.BLACK))
       
   988                 dc.DrawPoint(self.Pos.x + 1, self.Pos.y + self.Size[1] / 2 + 1)
       
   989             name_size = self.NameSize
       
   990             if typetext != "":
       
   991                 type_size = self.TypeSize
       
   992             
       
   993         # Draw coil name
       
   994         name_pos = (self.Pos.x + (self.Size[0] - name_size[0]) / 2,
       
   995                     self.Pos.y - (name_size[1] + 2))
       
   996         dc.DrawText(self.Name, name_pos[0], name_pos[1])
       
   997         # Draw the modifier symbol in the middle of coil
       
   998         if typetext != "":
       
   999             type_pos = (self.Pos.x + (self.Size[0] - type_size[0]) / 2 + 1,
       
  1000                         self.Pos.y + (self.Size[1] - type_size[1]) / 2)
       
  1001             dc.DrawText(typetext, type_pos[0], type_pos[1])
       
  1002         # Draw input and output connectors
       
  1003         self.Input.Draw(dc)
       
  1004         self.Output.Draw(dc)
       
  1005 
       
  1006         if not getattr(dc, "printing", False):
       
  1007             for name, highlights in self.Highlights.iteritems():
       
  1008                 if name == "reference":
       
  1009                     DrawHighlightedText(dc, self.Name, highlights, name_pos[0], name_pos[1])
       
  1010                 elif typetext != "":
       
  1011                     DrawHighlightedText(dc, typetext, highlights, type_pos[0], type_pos[1])
       
  1012             
       
  1013