Laurent@1236: #!/usr/bin/env python Laurent@1236: # -*- coding: utf-8 -*- Laurent@1236: Laurent@1236: #This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor Laurent@1236: #based on the plcopen standard. Laurent@1236: # Laurent@1236: #Copyright (C) 2013: Edouard TISSERANT and Laurent BESSARD Laurent@1236: # Laurent@1236: #See COPYING file for copyrights details. Laurent@1236: # Laurent@1236: #This library is free software; you can redistribute it and/or Laurent@1236: #modify it under the terms of the GNU General Public Laurent@1236: #License as published by the Free Software Foundation; either Laurent@1236: #version 2.1 of the License, or (at your option) any later version. Laurent@1236: # Laurent@1236: #This library is distributed in the hope that it will be useful, Laurent@1236: #but WITHOUT ANY WARRANTY; without even the implied warranty of Laurent@1236: #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Laurent@1236: #General Public License for more details. Laurent@1236: # Laurent@1236: #You should have received a copy of the GNU General Public Laurent@1236: #License along with this library; if not, write to the Free Software Laurent@1236: #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Laurent@1236: Laurent@1236: import wx Laurent@1236: Laurent@1236: from plcopen.structures import TestIdentifier, IEC_KEYWORDS Laurent@1236: from graphics.GraphicCommons import FREEDRAWING_MODE Laurent@1236: Laurent@1236: #------------------------------------------------------------------------------- Laurent@1236: # Dialog with preview for graphic block Laurent@1236: #------------------------------------------------------------------------------- Laurent@1236: Laurent@1236: """ Laurent@1236: Class that implements a generic dialog containing a preview panel for displaying Laurent@1236: graphic created by dialog Laurent@1236: """ Laurent@1236: Laurent@1236: class BlockPreviewDialog(wx.Dialog): Laurent@1236: Laurent@1236: def __init__(self, parent, controller, tagname, size, title): Laurent@1242: """ Laurent@1242: Constructor Laurent@1242: @param parent: Parent wx.Window of dialog for modal Laurent@1242: @param controller: Reference to project controller Laurent@1242: @param tagname: Tagname of project POU edited Laurent@1242: @param size: wx.Size object containing size of dialog Laurent@1242: @param title: Title of dialog frame Laurent@1242: """ Laurent@1236: wx.Dialog.__init__(self, parent, size=size, title=title) Laurent@1236: Laurent@1242: # Save reference to Laurent@1236: self.Controller = controller Laurent@1236: self.TagName = tagname Laurent@1236: Laurent@1242: # Label for preview Laurent@1236: self.PreviewLabel = wx.StaticText(self, label=_('Preview:')) Laurent@1236: Laurent@1242: # Create Preview panel Laurent@1236: self.Preview = wx.Panel(self, style=wx.SIMPLE_BORDER) Laurent@1236: self.Preview.SetBackgroundColour(wx.WHITE) Laurent@1242: Laurent@1242: # Add function to preview panel so that it answers to graphic elements Laurent@1242: # like Viewer Laurent@1236: setattr(self.Preview, "GetDrawingMode", lambda:FREEDRAWING_MODE) Laurent@1236: setattr(self.Preview, "GetScaling", lambda:None) Laurent@1236: setattr(self.Preview, "GetBlockType", controller.GetBlockType) Laurent@1236: setattr(self.Preview, "IsOfType", controller.IsOfType) Laurent@1242: Laurent@1242: # Bind paint event on Preview panel Laurent@1236: self.Preview.Bind(wx.EVT_PAINT, self.OnPaint) Laurent@1236: Laurent@1242: # Add default dialog buttons sizer Laurent@1236: self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE) Laurent@1236: self.Bind(wx.EVT_BUTTON, self.OnOK, Laurent@1236: self.ButtonSizer.GetAffirmativeButton()) Laurent@1236: Laurent@1242: self.Block = None # Graphic element to display in preview Laurent@1242: self.MinBlockSize = None # Graphic element minimal size Laurent@1242: self.DefaultBlockName = None # Graphic element name when opening dialog Laurent@1242: Laurent@1236: def __del__(self): Laurent@1242: """ Laurent@1242: Destructor Laurent@1242: """ Laurent@1242: # Remove reference to project controller Laurent@1236: self.Controller = None Laurent@1236: Laurent@1236: def SetMinBlockSize(self, size): Laurent@1242: """ Laurent@1242: Define minimal graphic element size Laurent@1242: @param size: wx.Size object containing minimal size Laurent@1242: """ Laurent@1236: self.MinBlockSize = size Laurent@1236: Laurent@1236: def SetPreviewFont(self, font): Laurent@1242: """ Laurent@1242: Set font of Preview panel Laurent@1242: @param font: wx.Font object containing font style Laurent@1242: """ Laurent@1236: self.Preview.SetFont(font) Laurent@1236: Laurent@1236: def TestBlockName(self, block_name): Laurent@1242: """ Laurent@1242: Text displayed graphic element name Laurent@1242: @param block_name: Graphic element name Laurent@1242: """ Laurent@1242: # Variable containing error message format Laurent@1242: message_format = None Laurent@1242: # Get graphic element name in upper case Laurent@1236: uppercase_block_name = block_name.upper() Laurent@1242: Laurent@1242: # Test if graphic element name is a valid identifier Laurent@1236: if not TestIdentifier(block_name): Laurent@1242: message_format = _("\"%s\" is not a valid identifier!") Laurent@1242: Laurent@1242: # Test that graphic element name isn't a keyword Laurent@1236: elif uppercase_block_name in IEC_KEYWORDS: Laurent@1242: message_format = _("\"%s\" is a keyword. It can't be used!") Laurent@1242: Laurent@1242: # Test that graphic element name isn't a POU name Laurent@1236: elif uppercase_block_name in self.Controller.GetProjectPouNames(): Laurent@1242: message_format = _("\"%s\" pou already exists!") Laurent@1242: Laurent@1242: # Test that graphic element name isn't already used in POU by a variable Laurent@1242: # or another graphic element Laurent@1237: elif ((self.DefaultBlockName is None or Laurent@1237: self.DefaultBlockName.upper() != uppercase_block_name) and Laurent@1236: uppercase_block_name in self.Controller.GetEditedElementVariables( Laurent@1236: self.TagName)): Laurent@1242: message_format = _("\"%s\" element for this pou already exists!") Laurent@1242: Laurent@1242: # If an error have been identify, show error message dialog Laurent@1242: if message_format is not None: Laurent@1242: self.ShowErrorMessage(message_format % block_name) Laurent@1242: # Test failed Laurent@1236: return False Laurent@1236: Laurent@1242: # Test succeed Laurent@1236: return True Laurent@1236: Laurent@1236: def ShowErrorMessage(self, message): Laurent@1242: """ Laurent@1242: Show an error message dialog over this dialog Laurent@1242: @param message: Error message to display Laurent@1242: """ Laurent@1236: dialog = wx.MessageDialog(self, message, Laurent@1236: _("Error"), Laurent@1236: wx.OK|wx.ICON_ERROR) Laurent@1236: dialog.ShowModal() Laurent@1236: dialog.Destroy() Laurent@1236: Laurent@1236: def OnOK(self, event): Laurent@1242: """ Laurent@1242: Called when dialog OK button is pressed Laurent@1242: Need to be overridden by inherited classes to check that dialog values Laurent@1242: are valid Laurent@1242: @param event: wx.Event from OK button Laurent@1242: """ Laurent@1242: # Close dialog Laurent@1236: self.EndModal(wx.ID_OK) Laurent@1236: Laurent@1236: def RefreshPreview(self): Laurent@1242: """ Laurent@1242: Refresh preview panel of graphic element Laurent@1242: May be overridden by inherited classes Laurent@1242: """ Laurent@1242: # Init preview panel paint device context Laurent@1236: dc = wx.ClientDC(self.Preview) Laurent@1236: dc.SetFont(self.Preview.GetFont()) Laurent@1236: dc.Clear() Laurent@1236: Laurent@1242: # Return immediately if no graphic element defined Laurent@1242: if self.Block is None: Laurent@1242: return Laurent@1242: Laurent@1242: # Calculate block size according to graphic element min size due to its Laurent@1242: # parameters and graphic element min size defined Laurent@1242: min_width, min_height = self.Block.GetMinSize() Laurent@1242: width = max(self.MinBlockSize[0], min_width) Laurent@1242: height = max(self.MinBlockSize[1], min_height) Laurent@1242: self.Block.SetSize(width, height) Laurent@1242: Laurent@1242: # Get Preview panel size Laurent@1242: client_size = self.Preview.GetClientSize() Laurent@1242: Laurent@1242: # If graphic element is too big to be displayed in preview panel, Laurent@1242: # calculate preview panel scale so that graphic element fit inside Laurent@1242: scale = (max(float(width) / client_size.width, Laurent@1242: float(height) / client_size.height) * 1.2 Laurent@1242: if width * 1.2 > client_size.width or Laurent@1242: height * 1.2 > client_size.height Laurent@1242: else 1.0) Laurent@1242: dc.SetUserScale(1.0 / scale, 1.0 / scale) Laurent@1242: Laurent@1242: # Center graphic element in preview panel Laurent@1242: x = int(client_size.width * scale - width) / 2 Laurent@1242: y = int(client_size.height * scale - height) / 2 Laurent@1242: self.Block.SetPosition(x, y) Laurent@1242: Laurent@1242: # Draw graphic element Laurent@1242: self.Block.Draw(dc) Laurent@1236: Laurent@1236: def OnPaint(self, event): Laurent@1242: """ Laurent@1242: Called when Preview panel need to be redraw Laurent@1242: @param event: wx.PaintEvent Laurent@1242: """ Laurent@1236: self.RefreshPreview() Laurent@1236: event.Skip() Laurent@1236: