Adding support for printing graphical languages
authorlbessard
Mon, 23 Jun 2008 18:48:49 +0200
changeset 213 4931959ea256
parent 212 e36ba4f15fc8
child 214 a88b377f75cb
Adding support for printing graphical languages
PLCOpenEditor.py
Viewer.py
examples/example.xml
graphics/FBD_Objects.py
graphics/GraphicCommons.py
graphics/LD_Objects.py
graphics/SFC_Objects.py
--- a/PLCOpenEditor.py	Wed Jun 04 17:48:26 2008 +0200
+++ b/PLCOpenEditor.py	Mon Jun 23 18:48:49 2008 +0200
@@ -221,6 +221,13 @@
         AppendMenu(parent, help='', id=ID_PLCOPENEDITORFILEMENUGENERATE,
               kind=wx.ITEM_NORMAL, text=u'Generate Program\tCTRL+G')
         parent.AppendSeparator()
+        AppendMenu(parent, help='', id=wx.ID_PAGE_SETUP,
+              kind=wx.ITEM_NORMAL, text=u'Page Setup')
+        AppendMenu(parent, help='', id=wx.ID_PREVIEW,
+              kind=wx.ITEM_NORMAL, text=u'Preview')
+        AppendMenu(parent, help='', id=wx.ID_PRINT,
+              kind=wx.ITEM_NORMAL, text=u'Print')
+        parent.AppendSeparator()
         AppendMenu(parent, help='', id=wx.ID_PROPERTIES,
               kind=wx.ITEM_NORMAL, text=u'Properties')
         parent.AppendSeparator()
@@ -234,6 +241,9 @@
         self.Bind(wx.EVT_MENU, self.OnSaveProjectAsMenu, id=wx.ID_SAVEAS)
         self.Bind(wx.EVT_MENU, self.OnGenerateProgramMenu,
               id=ID_PLCOPENEDITORFILEMENUGENERATE)
+        self.Bind(wx.EVT_MENU, self.OnPageSetupMenu, id=wx.ID_PAGE_SETUP)
+        self.Bind(wx.EVT_MENU, self.OnPreviewMenu, id=wx.ID_PREVIEW)
+        self.Bind(wx.EVT_MENU, self.OnPrintMenu, id=wx.ID_PRINT)
         self.Bind(wx.EVT_MENU, self.OnPropertiesMenu, id=wx.ID_PROPERTIES)
         self.Bind(wx.EVT_MENU, self.OnQuitMenu, id=wx.ID_EXIT)
     
@@ -477,6 +487,13 @@
         self.DrawingMode = FREEDRAWING_MODE
         #self.DrawingMode = DRIVENDRAWING_MODE
         
+        self.PrintData = wx.PrintData()
+        self.PrintData.SetPaperId(wx.PAPER_A4)
+        self.PrintData.SetPrintMode(wx.PRINT_MODE_PRINTER)
+        self.PageSetupData = wx.PageSetupDialogData(self.PrintData)
+        self.PageSetupData.SetMarginTopLeft(wx.Point(10, 15))
+        self.PageSetupData.SetMarginBottomRight(wx.Point(10, 20))
+        
         if not self.ModeSolo or fileOpen is not None:
             self.RefreshProjectTree()
         
@@ -652,14 +669,28 @@
     def RefreshFileMenu(self):
         if self.FileMenu:
             if self.Controler.HasOpenedProject():
+                selected = self.GetPageSelection()
+                if selected >= 0:
+                    graphic_viewer = isinstance(self.GetPage(selected), Viewer)
+                else:
+                    graphic_viewer = False
                 if self.GetPageCount() > 0:
                     self.FileMenu.Enable(wx.ID_CLOSE, True)
+                    if graphic_viewer:
+                        self.FileMenu.Enable(wx.ID_PREVIEW, True)
+                        self.FileMenu.Enable(wx.ID_PRINT, True)
+                    else:
+                        self.FileMenu.Enable(wx.ID_PREVIEW, False)
+                        self.FileMenu.Enable(wx.ID_PRINT, False)
                 else:
                     self.FileMenu.Enable(wx.ID_CLOSE, False)
+                    self.FileMenu.Enable(wx.ID_PREVIEW, False)
+                    self.FileMenu.Enable(wx.ID_PRINT, False)
                 self.FileMenu.Enable(wx.ID_CLOSE_ALL, True)
                 self.FileMenu.Enable(wx.ID_SAVE, True)
                 self.FileMenu.Enable(wx.ID_SAVEAS, True)
                 self.FileMenu.Enable(ID_PLCOPENEDITORFILEMENUGENERATE, True)
+                self.FileMenu.Enable(wx.ID_PAGE_SETUP, True)
                 self.FileMenu.Enable(wx.ID_PROPERTIES, True)
             else:
                 self.FileMenu.Enable(wx.ID_CLOSE, False)
@@ -667,6 +698,9 @@
                 self.FileMenu.Enable(wx.ID_SAVE, False)
                 self.FileMenu.Enable(wx.ID_SAVEAS, False)
                 self.FileMenu.Enable(ID_PLCOPENEDITORFILEMENUGENERATE, False)
+                self.FileMenu.Enable(wx.ID_PAGE_SETUP, False)
+                self.FileMenu.Enable(wx.ID_PREVIEW, False)
+                self.FileMenu.Enable(wx.ID_PRINT, False)
                 self.FileMenu.Enable(wx.ID_PROPERTIES, False)
 
     def OnNewProjectMenu(self, event):
@@ -806,6 +840,49 @@
             self.RefreshTitle()
         dialog.Destroy()
 
+    def OnPageSetupMenu(self, event):
+        dialog = wx.PageSetupDialog(self, self.PageSetupData)
+        if dialog.ShowModal() == wx.ID_OK:
+            self.PageSetupData = wx.PageSetupDialogData(dialog.GetPageSetupData())
+            self.PrintData = wx.PrintData(self.PageSetupData.GetPrintData())
+        dialog.Destroy()
+        event.Skip()
+
+    def OnPreviewMenu(self, event):
+        selected = self.GetPageSelection()        
+        if selected != -1:
+            data = wx.PrintDialogData(self.PrintData)
+            properties = self.Controler.GetProjectProperties()
+            page_size = map(int, properties["pageSize"])
+            margins = (self.PageSetupData.GetMarginTopLeft(), self.PageSetupData.GetMarginBottomRight())
+            printout = GraphicPrintout(self.GetPage(selected), page_size, margins, True)
+            printout2 = GraphicPrintout(self.GetPage(selected), page_size, margins, True)
+            preview = wx.PrintPreview(printout, printout2, data)
+
+            if preview.Ok():
+                preview_frame = wx.PreviewFrame(preview, frame, "Print preview")
+
+                preview_frame.Initialize()
+                
+                preview_frame.Show(True)
+        event.Skip()
+
+    def OnPrintMenu(self, event):
+        selected = self.GetPageSelection()        
+        if selected != -1:
+            dialog_data = wx.PrintDialogData(self.PrintData)
+            dialog_data.SetToPage(1)
+            properties = self.Controler.GetProjectProperties()
+            page_size = map(int, properties["pageSize"])
+            margins = (self.PageSetupData.GetMarginTopLeft(), self.PageSetupData.GetMarginBottomRight())
+            printer = wx.Printer(dialog_data)
+            printout = GraphicPrintout(self.GetPage(selected), page_size, margins)
+            
+            if not printer.Print(self, printout, True):
+                wx.MessageBox("There was a problem printing.\nPerhaps your current printer is not set correctly?", "Printing", wx.OK)
+            printout.Destroy()
+        event.Skip()
+
     def OnPropertiesMenu(self, event):
         self.ShowProperties()
         event.Skip()
@@ -3804,6 +3881,86 @@
             self.ParentWindow.RefreshTitle()
             self.ParentWindow.RefreshEditMenu()
 
+UPPER_DIV = lambda x, y: (x / y) + {True : 0, False : 1}[(x % y) == 0]
+
+class GraphicPrintout(wx.Printout):
+    def __init__(self, viewer, page_size, margins, preview = False):
+        wx.Printout.__init__(self)
+        self.Viewer = viewer
+        self.PageSize = page_size
+        self.Preview = preview
+        self.Margins = margins
+        self.FontSize = 14
+        self.TextMargin = 5
+        
+        maxx, maxy = viewer.GetMaxSize()
+        self.PageGrid = (UPPER_DIV(maxx, page_size[0]), UPPER_DIV(maxy, page_size[1]))
+        
+    def GetPageNumber(self):
+        return self.PageGrid[0] * self.PageGrid[1]
+    
+    def HasPage(self, page):
+        return page <= self.GetPageNumber()
+        
+    def GetPageInfo(self):
+        page_number = self.GetPageNumber()
+        return (1, page_number, 1, page_number)
+
+    def OnBeginDocument(self, startPage, endPage):
+        dc = self.GetDC()
+        if not self.Preview and isinstance(dc, wx.PostScriptDC):
+            dc.SetResolution(720)
+            self.FontSize = 140
+            self.TextMargin = 50
+        super(GraphicPrintout, self).OnBeginDocument(startPage, endPage)
+
+    def OnPrintPage(self, page):
+        dc = self.GetDC()
+        dc.printing = not self.Preview
+        
+        # Get the size of the DC in pixels
+        ppiPrinterX, ppiPrinterY = self.GetPPIPrinter()
+        ppiScreenX, ppiScreenY = self.GetPPIScreen()
+        pw, ph = self.GetPageSizePixels()
+        dw, dh = dc.GetSizeTuple()
+        Xscale = (float(dw) * float(ppiPrinterX)) / (float(pw) * 25.4)
+        Yscale = (float(dh) * float(ppiPrinterY)) / (float(ph) * 25.4)
+        
+        margin_left = self.Margins[0].x * Xscale
+        margin_top = self.Margins[0].y * Yscale
+        area_width = dw - self.Margins[1].x * Xscale - margin_left
+        area_height = dh - self.Margins[1].y * Yscale - margin_top
+        
+        dc.SetPen(wx.BLACK_PEN)
+        dc.SetBrush(wx.TRANSPARENT_BRUSH)    
+        dc.DrawRectangle(margin_left, margin_top, area_width, area_height)
+        
+        dc.SetFont(wx.Font(self.FontSize, wx.DEFAULT, wx.NORMAL, wx.NORMAL))
+        dc.SetTextForeground(wx.BLACK)
+        block_name = " - ".join(self.Viewer.GetTagName().split("::")[1:])
+        text_width, text_height = dc.GetTextExtent(block_name)
+        dc.DrawText(block_name, margin_left, margin_top - text_height - self.TextMargin)
+        dc.DrawText("Page: %d" % page, margin_left, margin_top + area_height + self.TextMargin)
+        
+        # Calculate the position on the DC for centering the graphic
+        posX = area_width * ((page - 1) % self.PageGrid[0])
+        posY = area_height * ((page - 1) / self.PageGrid[0])
+
+        scaleX = float(area_width) / float(self.PageSize[0])
+        scaleY = float(area_height) / float(self.PageSize[1])
+        scale = min(scaleX, scaleY)
+
+        # Set the scale and origin
+        dc.SetDeviceOrigin(-posX + margin_left, -posY + margin_top)
+        dc.SetUserScale(scale, scale)
+        dc.SetClippingRegion(posX, posY, self.PageSize[0], self.PageSize[1])
+        
+        #-------------------------------------------
+        
+        self.Viewer.DoDrawing(dc, True)
+        
+        return True
+
 #-------------------------------------------------------------------------------
 #                               Exception Handler
 #-------------------------------------------------------------------------------
--- a/Viewer.py	Wed Jun 04 17:48:26 2008 +0200
+++ b/Viewer.py	Mon Jun 23 18:48:49 2008 +0200
@@ -306,6 +306,8 @@
         self.Scaling = None
         self.DrawGrid = True
         self.GridBrush = wx.TRANSPARENT_BRUSH
+        self.PageSize = None
+        self.PagePen = wx.TRANSPARENT_PEN
         self.DrawingWire = False
         self.current_id = 0
         self.TagName = tagname
@@ -324,12 +326,12 @@
         self.SetDropTarget(ViewerDropTarget(self))
         
         dc = wx.ClientDC(self)
-        font = wx.Font(faces["size"], wx.DEFAULT, wx.NORMAL, wx.NORMAL, faceName = faces["mono"])
+        font = wx.Font(faces["size"], wx.SWISS, wx.NORMAL, wx.NORMAL, faceName = faces["mono"])
         dc.SetFont(font)
         width, height = dc.GetTextExtent("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
         while width > 260:
             faces["size"] -= 1
-            font = wx.Font(faces["size"], wx.DEFAULT, wx.NORMAL, wx.NORMAL, faceName = faces["mono"])
+            font = wx.Font(faces["size"], wx.SWISS, wx.NORMAL, wx.NORMAL, faceName = faces["mono"])
             dc.SetFont(font)
             width, height = dc.GetTextExtent("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
         self.SetFont(font)
@@ -344,7 +346,7 @@
         self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveViewer)
         self.Bind(wx.EVT_MOTION, self.OnViewerMotion)
         self.Bind(wx.EVT_CHAR, self.OnChar)
-        self.Bind(wx.EVT_SCROLLWIN, self.OnMoveWindow)
+        #self.Bind(wx.EVT_SCROLLWIN, self.OnMoveWindow)
         self.Bind(wx.EVT_SIZE, self.OnMoveWindow)
     
     def GetScrolledRect(self, rect):
@@ -374,7 +376,7 @@
 
     def GetLogicalDC(self, buffered=False):
         if buffered:
-            dc = wx.BufferedPaintDC(self)
+            dc = wx.AutoBufferedPaintDC(self)
         else:
             dc = wx.ClientDC(self)
         dc.SetFont(self.GetFont())
@@ -489,6 +491,13 @@
         else:
             self.Scaling = None
             self.GridBrush = wx.TRANSPARENT_BRUSH
+        page_size = properties["pageSize"]
+        if page_size != (0, 0):
+            self.PageSize = map(int, page_size)
+            self.PagePen = wx.Pen(wx.Colour(180, 180, 180))
+        else:
+            self.PageSize = None
+            self.PagePen = wx.TRANSPARENT_PEN
         if refresh:
             self.Refresh(False)
         
@@ -524,14 +533,18 @@
     
         self.Refresh(False)
     
-    def RefreshScrollBars(self):
-        xstart, ystart = self.GetViewStart()
-        window_size = self.GetClientSize()
+    def GetMaxSize(self):
         maxx = maxy = 0
         for element in self.GetElements():
             bbox = element.GetBoundingBox()
             maxx = max(maxx, bbox.x + bbox.width)
             maxy = max(maxy, bbox.y + bbox.height)
+        return maxx, maxy
+    
+    def RefreshScrollBars(self):
+        xstart, ystart = self.GetViewStart()
+        window_size = self.GetClientSize()
+        maxx, maxy = self.GetMaxSize()
         maxx = max(maxx + WINDOW_BORDER, xstart * SCROLLBAR_UNIT + window_size[0])
         maxy = max(maxy + WINDOW_BORDER, ystart * SCROLLBAR_UNIT + window_size[1])
         if self.rubberBand.IsShown():
@@ -539,7 +552,8 @@
             maxx = max(maxx, extent.x + extent.width)
             maxy = max(maxy, extent.y + extent.height)
         self.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, 
-            maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, xstart, ystart, True)
+            round(maxx / SCROLLBAR_UNIT), round(maxy / SCROLLBAR_UNIT), 
+            xstart, ystart, True)
         
     # Load instance from given informations
     def loadInstance(self, instance, ids):
@@ -2320,16 +2334,36 @@
         self.RefreshScrollBars()
         event.Skip()
 
-    def OnPaint(self, event):
-        dc = self.GetLogicalDC(True)
-        dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
-        dc.Clear()
-        dc.BeginDrawing()
-        if self.Scaling and self.DrawGrid:
+    def DoDrawing(self, dc, printing = False):
+        if printing:
+            if getattr(dc, "printing", False):
+                font = wx.Font(self.GetFont().GetPointSize(), wx.MODERN, wx.NORMAL, wx.NORMAL)
+                dc.SetFont(font)
+            else:
+                dc.SetFont(self.GetFont())
+        else:
+            dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
+            dc.Clear()
+            dc.BeginDrawing()
+        if self.Scaling is not None and self.DrawGrid and not printing:
             dc.SetPen(wx.TRANSPARENT_PEN)
             dc.SetBrush(self.GridBrush)
+            xstart, ystart = self.GetViewStart()
+            window_size = self.GetClientSize()
             width, height = self.GetVirtualSize()
+            width = max(width, xstart * SCROLLBAR_UNIT + window_size[0])
+            height = max(height, ystart * SCROLLBAR_UNIT + window_size[1])
             dc.DrawRectangle(0, 0, width, height)
+        if self.PageSize is not None and not printing:
+            dc.SetPen(self.PagePen)
+            xstart, ystart = self.GetViewStart()
+            window_size = self.GetClientSize()
+            for x in xrange(self.PageSize[0] - (xstart * SCROLLBAR_UNIT) % self.PageSize[0], window_size[0], self.PageSize[0]):
+                dc.DrawLine(xstart * SCROLLBAR_UNIT + x + 1, ystart * SCROLLBAR_UNIT, 
+                            xstart * SCROLLBAR_UNIT + x + 1, ystart * SCROLLBAR_UNIT + window_size[1])
+            for y in xrange(self.PageSize[1] - (ystart * SCROLLBAR_UNIT) % self.PageSize[1], window_size[1], self.PageSize[1]):
+                dc.DrawLine(xstart * SCROLLBAR_UNIT, ystart * SCROLLBAR_UNIT + y + 1, 
+                            xstart * SCROLLBAR_UNIT + window_size[0], ystart * SCROLLBAR_UNIT + y + 1)
         
         # Draw all elements
         for comment in self.Comments:
@@ -2343,11 +2377,15 @@
                 block.Draw(dc)
         
         if self.SelectedElement:
-            self.SelectedElement.Draw(dc)
-        
-        if self.rubberBand.IsShown():
-            self.rubberBand.Draw(dc)
-        dc.EndDrawing()
-        event.Skip()
-
-
+                self.SelectedElement.Draw(dc)
+        
+        if not printing:
+            if self.rubberBand.IsShown():
+                self.rubberBand.Draw(dc)
+            dc.EndDrawing()
+
+    def OnPaint(self, event):
+        self.DoDrawing(self.GetLogicalDC(True))
+        event.Skip()
+
+
--- a/examples/example.xml	Wed Jun 04 17:48:26 2008 +0200
+++ b/examples/example.xml	Mon Jun 23 18:48:49 2008 +0200
@@ -12,11 +12,11 @@
               contentDescription="Example of PLCOpenEditor usage"/>
   <contentHeader name="Test"
                  version="1"
-                 modificationDateTime="2008-01-28 11:02:45"
+                 modificationDateTime="2008-06-19 11:14:11"
                  author="Laurent Bessard"
                  language="en-US">
     <coordinateInfo>
-      <pageSize x="1000" y="2000"/>
+      <pageSize x="1050" y="1485"/>
       <fbd>
         <scaling x="8" y="8"/>
       </fbd>
@@ -245,7 +245,7 @@
                 </variable>
               </outputVariables>
             </block>
-            <comment localId="10" height="40" width="376">
+            <comment localId="10" height="48" width="376">
               <position x="240" y="24"/>
               <content>
 <![CDATA[POU used for testing PLCOpenEditor.]]>
--- a/graphics/FBD_Objects.py	Wed Jun 04 17:48:26 2008 +0200
+++ b/graphics/FBD_Objects.py	Mon Jun 23 18:48:49 2008 +0200
@@ -356,12 +356,22 @@
         dc.SetPen(self.Pen)
         dc.SetBrush(wx.WHITE_BRUSH)
         dc.SetTextForeground(self.Colour)
+        
+        if getattr(dc, "printing", False):
+            name_size = dc.GetTextExtent(self.Name)
+            type_size = dc.GetTextExtent(self.Type)
+            executionorder_size = dc.GetTextExtent(str(self.ExecutionOrder))
+        else:
+            name_size = self.NameSize
+            type_size = self.TypeSize
+            executionorder_size = self.ExecutionOrderSize
+            
         # Draw a rectangle with the block size
         dc.DrawRectangle(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1)
         # Draw block name and block type
-        dc.DrawText(self.Name, self.Pos.x + (self.Size[0] - self.NameSize[0]) / 2,
-                self.Pos.y - (self.NameSize[1] + 2))
-        dc.DrawText(self.Type, self.Pos.x + (self.Size[0] - self.TypeSize[0]) / 2,
+        dc.DrawText(self.Name, self.Pos.x + (self.Size[0] - name_size[0]) / 2,
+                self.Pos.y - (name_size[1] + 2))
+        dc.DrawText(self.Type, self.Pos.x + (self.Size[0] - type_size[0]) / 2,
                 self.Pos.y + 5)
         # Draw inputs and outputs connectors
         for input in self.Inputs:
@@ -370,7 +380,7 @@
             output.Draw(dc)
         if self.ExecutionOrder != 0:
             # Draw block execution order
-            dc.DrawText(str(self.ExecutionOrder), self.Pos.x + self.Size[0] - self.ExecutionOrderSize[0],
+            dc.DrawText(str(self.ExecutionOrder), self.Pos.x + self.Size[0] - executionorder_size[0],
                     self.Pos.y + self.Size[1] + 2)
         dc.SetTextForeground(wx.BLACK)
         
@@ -589,11 +599,19 @@
         Graphic_Element.Draw(self, dc)
         dc.SetPen(wx.BLACK_PEN)
         dc.SetBrush(wx.WHITE_BRUSH)
+        
+        if getattr(dc, "printing", False):
+            name_size = dc.GetTextExtent(self.Name)
+            executionorder_size = dc.GetTextExtent(str(self.ExecutionOrder))
+        else:
+            name_size = self.NameSize
+            executionorder_size = self.ExecutionOrderSize
+        
         # Draw a rectangle with the variable size
         dc.DrawRectangle(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1)
         # Draw variable name
-        dc.DrawText(self.Name, self.Pos.x + (self.Size[0] - self.NameSize[0]) / 2,
-                self.Pos.y + (self.Size[1] - self.NameSize[1]) / 2)
+        dc.DrawText(self.Name, self.Pos.x + (self.Size[0] - name_size[0]) / 2,
+                self.Pos.y + (self.Size[1] - name_size[1]) / 2)
         # Draw connectors
         if self.Input:
             self.Input.Draw(dc)
@@ -601,7 +619,7 @@
             self.Output.Draw(dc)
         if self.ExecutionOrder != 0:
             # Draw variable execution order
-            dc.DrawText(str(self.ExecutionOrder), self.Pos.x + self.Size[0] - self.ExecutionOrderSize[0],
+            dc.DrawText(str(self.ExecutionOrder), self.Pos.x + self.Size[0] - executionorder_size[0],
                     self.Pos.y + self.Size[1] + 2)
 
 
@@ -761,9 +779,15 @@
         Graphic_Element.Draw(self, dc)
         dc.SetPen(wx.BLACK_PEN)
         dc.SetBrush(wx.WHITE_BRUSH)
+        
+        if getattr(dc, "printing", False):
+            name_size = dc.GetTextExtent(self.Name)
+        else:
+            name_size = self.NameSize
+        
         # Draw a rectangle with the connection size with arrows in 
         dc.DrawRectangle(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1)
-        arrowsize = min(self.Size[1] / 2, (self.Size[0] - self.NameSize[0] - 10) / 2)
+        arrowsize = min(self.Size[1] / 2, (self.Size[0] - name_size[0] - 10) / 2)
         dc.DrawLine(self.Pos.x, self.Pos.y, self.Pos.x + arrowsize, 
                 self.Pos.y + self.Size[1] / 2)
         dc.DrawLine(self.Pos.x + arrowsize, self.Pos.y + self.Size[1] / 2, 
@@ -773,8 +797,8 @@
         dc.DrawLine(self.Pos.x + self.Size[0], self.Pos.y + self.Size[1] / 2, 
                 self.Pos.x + self.Size[0] - arrowsize, self.Pos.y + self.Size[1])
         # Draw connection name
-        dc.DrawText(self.Name, self.Pos.x + (self.Size[0] - self.NameSize[0]) / 2,
-                self.Pos.y + (self.Size[1] - self.NameSize[1]) / 2)
+        dc.DrawText(self.Name, self.Pos.x + (self.Size[0] - name_size[0]) / 2,
+                self.Pos.y + (self.Size[1] - name_size[1]) / 2)
         # Draw connector
         if self.Connector:
             self.Connector.Draw(dc)
--- a/graphics/GraphicCommons.py	Wed Jun 04 17:48:26 2008 +0200
+++ b/graphics/GraphicCommons.py	Mon Jun 23 18:48:49 2008 +0200
@@ -1120,6 +1120,12 @@
         dc.SetPen(self.Pen)
         dc.SetBrush(wx.WHITE_BRUSH)
         parent_pos = self.ParentBlock.GetPosition()
+        
+        if getattr(dc, "printing", False):
+            name_size = dc.GetTextExtent(self.Name)
+        else:
+            name_size = self.NameSize
+        
         if self.Negated:
             # If connector is negated, draw a circle
             xcenter = parent_pos[0] + self.Pos.x + (CONNECTOR_SIZE * self.Direction[0]) / 2
@@ -1140,17 +1146,17 @@
             yend = ystart + CONNECTOR_SIZE * self.Direction[1]
             dc.DrawLine(xstart + self.Direction[0], ystart + self.Direction[1], xend, yend)
         if self.Direction[0] != 0:
-            ytext = parent_pos[1] + self.Pos.y - self.NameSize[1] / 2
+            ytext = parent_pos[1] + self.Pos.y - name_size[1] / 2
             if self.Direction[0] < 0:
                 xtext = parent_pos[0] + self.Pos.x + 5
             else:
-                xtext = parent_pos[0] + self.Pos.x - (self.NameSize[0] + 5)
+                xtext = parent_pos[0] + self.Pos.x - (name_size[0] + 5)
         if self.Direction[1] != 0:
-            xtext = parent_pos[0] + self.Pos.x - self.NameSize[0] / 2
+            xtext = parent_pos[0] + self.Pos.x - name_size[0] / 2
             if self.Direction[1] < 0:
                 ytext = parent_pos[1] + self.Pos.y + 5
             else:
-                ytext = parent_pos[1] + self.Pos.y - (self.NameSize[1] + 5)
+                ytext = parent_pos[1] + self.Pos.y - (name_size[1] + 5)
         # Draw the text
         dc.DrawText(self.Name, xtext, ytext)
 
--- a/graphics/LD_Objects.py	Wed Jun 04 17:48:26 2008 +0200
+++ b/graphics/LD_Objects.py	Mon Jun 23 18:48:49 2008 +0200
@@ -563,13 +563,8 @@
         Graphic_Element.Draw(self, dc)
         dc.SetPen(wx.BLACK_PEN)
         dc.SetBrush(wx.BLACK_BRUSH)
-        # Draw two rectangles for representing the contact
-        dc.DrawRectangle(self.Pos.x, self.Pos.y, 2, self.Size[1] + 1)
-        dc.DrawRectangle(self.Pos.x + self.Size[0] - 1, self.Pos.y, 2, self.Size[1] + 1)
-        # Draw contact name
-        dc.DrawText(self.Name, self.Pos.x + (self.Size[0] - self.NameSize[0]) / 2,
-                self.Pos.y - (self.NameSize[1] + 2))
-        # Draw the modifier symbol in the middle of contact
+        
+        # Compiling contact type modifier symbol
         typetext = ""
         if self.Type == CONTACT_REVERSE:
             typetext = "/"
@@ -577,9 +572,26 @@
             typetext = "P"
         elif self.Type == CONTACT_FALLING:
             typetext = "N"
+        
+        if getattr(dc, "printing", False):
+            name_size = dc.GetTextExtent(self.Name)
+            if typetext != "":
+                type_size = dc.GetTextExtent(typetext)
+        else:
+            name_size = self.NameSize
+            if typetext != "":
+                type_size = self.TypeSize
+        
+        # Draw two rectangles for representing the contact
+        dc.DrawRectangle(self.Pos.x, self.Pos.y, 2, self.Size[1] + 1)
+        dc.DrawRectangle(self.Pos.x + self.Size[0] - 1, self.Pos.y, 2, self.Size[1] + 1)
+        # Draw contact name
+        dc.DrawText(self.Name, self.Pos.x + (self.Size[0] - name_size[0]) / 2,
+                self.Pos.y - (name_size[1] + 2))
+        # Draw the modifier symbol in the middle of contact
         if typetext != "":
-            dc.DrawText(typetext, self.Pos.x + (self.Size[0] - self.TypeSize[0]) / 2 + 1,
-                    self.Pos.y + (self.Size[1] - self.TypeSize[1]) / 2)
+            dc.DrawText(typetext, self.Pos.x + (self.Size[0] - type_size[0]) / 2 + 1,
+                    self.Pos.y + (self.Size[1] - type_size[1]) / 2)
         # Draw input and output connectors
         self.Input.Draw(dc)
         self.Output.Draw(dc)
@@ -793,15 +805,8 @@
         Graphic_Element.Draw(self, dc)
         dc.SetPen(wx.Pen(wx.BLACK, 2, wx.SOLID))
         dc.SetBrush(wx.TRANSPARENT_BRUSH)
-        # Draw a two circle arcs for representing the coil
-        dc.DrawEllipticArc(self.Pos.x, self.Pos.y - int(self.Size[1] * (sqrt(2) - 1.) / 2.) + 1, self.Size[0], int(self.Size[1] * sqrt(2)) - 1, 135, 225)
-        dc.DrawEllipticArc(self.Pos.x, self.Pos.y - int(self.Size[1] * (sqrt(2) - 1.) / 2.) + 1, self.Size[0], int(self.Size[1] * sqrt(2)) - 1, -45, 45)
-        dc.SetPen(wx.BLACK_PEN)
-        dc.DrawPoint(self.Pos.x + 1, self.Pos.y + self.Size[1] / 2 + 1)
-        # Draw coil name
-        dc.DrawText(self.Name, self.Pos.x + (self.Size[0] - self.NameSize[0]) / 2,
-                self.Pos.y - (self.NameSize[1] + 2))
-        # Draw the modifier symbol in the middle of coil
+        
+        # Compiling coil type modifier symbol 
         typetext = ""
         if self.Type == COIL_REVERSE:
             typetext = "/"
@@ -809,9 +814,37 @@
             typetext = "S"
         elif self.Type == COIL_RESET:
             typetext = "R"
+        
+        if getattr(dc, "printing", False) and not isinstance(dc, wx.PostScriptDC):
+            # Draw an clipped ellipse for representing the coil
+            clipping_box = dc.GetClippingBox()
+            dc.SetClippingRegion(self.Pos.x - 1, self.Pos.y, self.Size[0] + 2, self.Size[1] + 1)
+            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)
+            dc.DestroyClippingRegion()
+            if clipping_box != (0, 0, 0, 0):
+                dc.SetClippingRegion(*clipping_box)
+            name_size = dc.GetTextExtent(self.Name)
+            if typetext != "":
+                type_size = dc.GetTextExtent(typetext)
+        else:
+            # Draw a two ellipse arcs for representing the coil
+            dc.DrawEllipticArc(self.Pos.x, self.Pos.y - int(self.Size[1] * (sqrt(2) - 1.) / 2.) + 1, self.Size[0], int(self.Size[1] * sqrt(2)) - 1, 135, 225)
+            dc.DrawEllipticArc(self.Pos.x, self.Pos.y - int(self.Size[1] * (sqrt(2) - 1.) / 2.) + 1, self.Size[0], int(self.Size[1] * sqrt(2)) - 1, -45, 45)
+            # Draw a point to avoid hole in left arc
+            if not getattr(dc, "printing", False):
+                dc.SetPen(wx.BLACK_PEN)
+                dc.DrawPoint(self.Pos.x + 1, self.Pos.y + self.Size[1] / 2 + 1)
+            name_size = self.NameSize
+            if typetext != "":
+                type_size = self.TypeSize
+            
+        # Draw coil name
+        dc.DrawText(self.Name, self.Pos.x + (self.Size[0] - name_size[0]) / 2,
+                self.Pos.y - (name_size[1] + 2))
+        # Draw the modifier symbol in the middle of coil
         if typetext != "":
-            dc.DrawText(typetext, self.Pos.x + (self.Size[0] - self.TypeSize[0]) / 2 + 1,
-                    self.Pos.y + (self.Size[1] - self.TypeSize[1]) / 2)
+            dc.DrawText(typetext, self.Pos.x + (self.Size[0] - type_size[0]) / 2 + 1,
+                    self.Pos.y + (self.Size[1] - type_size[1]) / 2)
         # Draw input and output connectors
         self.Input.Draw(dc)
         self.Output.Draw(dc)
--- a/graphics/SFC_Objects.py	Wed Jun 04 17:48:26 2008 +0200
+++ b/graphics/SFC_Objects.py	Mon Jun 23 18:48:49 2008 +0200
@@ -46,7 +46,7 @@
     # Create a new step
     def __init__(self, parent, name, initial = False, id = None):
         Graphic_Element.__init__(self, parent)
-        self.Name = name
+        self.SetName(name)
         self.Initial = initial
         self.Id = id
         self.Size = wx.Size(SFC_STEP_DEFAULT_SIZE[0], SFC_STEP_DEFAULT_SIZE[1])
@@ -109,6 +109,10 @@
         if self.Action:
             self.Action.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
     
+    # Refresh the size of text for name
+    def RefreshNameSize(self):
+        self.NameSize = self.Parent.GetTextExtent(self.Name)
+    
     # Add output connector to step
     def AddInput(self):
         if not self.Input:
@@ -244,6 +248,7 @@
     # Changes the step name
     def SetName(self, name):
         self.Name = name
+        self.RefreshNameSize()
 
     # Returns the step name
     def GetName(self):
@@ -459,14 +464,19 @@
         Graphic_Element.Draw(self, dc)
         dc.SetPen(wx.BLACK_PEN)
         dc.SetBrush(wx.WHITE_BRUSH)
+        
+        if getattr(dc, "printing", False):
+            name_size = dc.GetTextExtent(self.Name)
+        else:
+            name_size = self.NameSize
+        
         # Draw two rectangles for representing the step
         dc.DrawRectangle(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1)
         if self.Initial:
             dc.DrawRectangle(self.Pos.x + 2, self.Pos.y + 2, self.Size[0] - 3, self.Size[1] - 3)
         # Draw step name
-        namewidth, nameheight = dc.GetTextExtent(self.Name)
-        dc.DrawText(self.Name, self.Pos.x + (self.Size[0] - namewidth) / 2,
-                    self.Pos.y + (self.Size[1] - nameheight) / 2)
+        dc.DrawText(self.Name, self.Pos.x + (self.Size[0] - name_size[0]) / 2,
+                    self.Pos.y + (self.Size[1] - name_size[1]) / 2)
         # Draw input and output connectors
         if self.Input:
             self.Input.Draw(dc)
@@ -815,6 +825,18 @@
         Graphic_Element.Draw(self, dc)
         dc.SetPen(wx.BLACK_PEN)
         dc.SetBrush(wx.BLACK_BRUSH)
+        
+        if getattr(dc, "printing", False):
+            if self.Type != "connection":
+                condition_size = dc.GetTextExtent(self.Condition)
+            if self.Priority != 0:
+                priority_size = dc.GetTextExtent(str(self.Priority))
+        else:
+            if self.Type != "connection":
+                condition_size = self.ConditionSize
+            if self.Priority != 0:
+                priority_size = self.PrioritySize
+        
         # Draw plain rectangle for representing the transition
         dc.DrawRectangle(self.Pos.x, 
                          self.Pos.y + (self.Size[1] - SFC_TRANSITION_SIZE[1])/2, 
@@ -824,17 +846,15 @@
         dc.DrawLine(vertical_line_x, self.Pos.y, vertical_line_x, self.Pos.y + self.Size[1] + 1) 
         # Draw transition condition
         if self.Type != "connection":
-            text_width, text_height = self.ConditionSize
             if self.Condition != "":
                 condition = self.Condition
             else:
                 condition = "Transition"
             dc.DrawText(condition, self.Pos.x + self.Size[0] + 5,
-                        self.Pos.y + (self.Size[1] - text_height) / 2)
+                        self.Pos.y + (self.Size[1] - condition_size[1]) / 2)
         # Draw priority number
         if self.Priority != 0:
-            priority_width, priority_height = self.PrioritySize
-            dc.DrawText(str(self.Priority), self.Pos.x, self.Pos.y - self.PrioritySize[1] - 2)
+            dc.DrawText(str(self.Priority), self.Pos.x, self.Pos.y - priority_size[1] - 2)
         # Draw input and output connectors
         self.Input.Draw(dc)
         self.Output.Draw(dc)
@@ -1283,7 +1303,7 @@
     # Create a new jump
     def __init__(self, parent, target, id = None):
         Graphic_Element.__init__(self, parent)
-        self.Target = target
+        self.SetTarget(target)
         self.Id = id
         self.Size = wx.Size(SFC_JUMP_SIZE[0], SFC_JUMP_SIZE[1])
         # Create an input and output connector
@@ -1329,6 +1349,10 @@
     def Clean(self):
         self.Input.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
     
+    # Refresh the size of text for target
+    def RefreshTargetSize(self):
+        self.TargetSize = self.Parent.GetTextExtent(self.Target)
+    
     # Refresh the jump bounding box
     def RefreshBoundingBox(self):
         text_width, text_height = self.Parent.GetTextExtent(self.Target)
@@ -1372,6 +1396,7 @@
     # Changes the jump target
     def SetTarget(self, target):
         self.Target = target
+        self.RefreshTargetSize()
         self.RefreshBoundingBox()
     
     # Returns the jump target
@@ -1462,6 +1487,12 @@
         Graphic_Element.Draw(self, dc)
         dc.SetPen(wx.BLACK_PEN)
         dc.SetBrush(wx.BLACK_BRUSH)
+        
+        if getattr(dc, "printing", False):
+            target_size = dc.GetTextExtent(self.Target)
+        else:
+            target_size = self.TargetSize
+        
         # Draw plain rectangle for representing the divergence
         dc.DrawLine(self.Pos.x + self.Size[0] / 2, self.Pos.y, self.Pos.x + self.Size[0] / 2, self.Pos.y + self.Size[1])
         points = [wx.Point(self.Pos.x, self.Pos.y),
@@ -1469,9 +1500,8 @@
                   wx.Point(self.Pos.x + self.Size[0], self.Pos.y),
                   wx.Point(self.Pos.x + self.Size[0] / 2, self.Pos.y + self.Size[1])]
         dc.DrawPolygon(points)
-        text_width, text_height = dc.GetTextExtent(self.Target)
         dc.DrawText(self.Target, self.Pos.x + self.Size[0] + 2,
-                    self.Pos.y + (self.Size[1] - text_height) / 2)
+                    self.Pos.y + (self.Size[1] - target_size[1]) / 2)
         # Draw input connector
         if self.Input:
             self.Input.Draw(dc)