Laurent@700: #!/usr/bin/env python Laurent@700: # -*- coding: utf-8 -*- Laurent@700: Laurent@700: #This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor Laurent@700: #based on the plcopen standard. Laurent@700: # Laurent@700: #Copyright (C) 2012: Edouard TISSERANT and Laurent BESSARD Laurent@700: # Laurent@700: #See COPYING file for copyrights details. Laurent@700: # Laurent@700: #This library is free software; you can redistribute it and/or Laurent@700: #modify it under the terms of the GNU General Public Laurent@700: #License as published by the Free Software Foundation; either Laurent@700: #version 2.1 of the License, or (at your option) any later version. Laurent@700: # Laurent@700: #This library is distributed in the hope that it will be useful, Laurent@700: #but WITHOUT ANY WARRANTY; without even the implied warranty of Laurent@700: #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Laurent@700: #General Public License for more details. Laurent@700: # Laurent@700: #You should have received a copy of the GNU General Public Laurent@700: #License along with this library; if not, write to the Free Software Laurent@700: #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Laurent@700: Laurent@700: import wx Laurent@700: Laurent@714: #------------------------------------------------------------------------------- Laurent@714: # Helpers Laurent@714: #------------------------------------------------------------------------------- Laurent@714: Laurent@700: REQUIRED_PARAMS = ["projectName", "productName", "productVersion", "companyName"] Laurent@700: Laurent@714: [TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE, Laurent@714: POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES Laurent@714: ] = range(10) Laurent@714: Laurent@714: #------------------------------------------------------------------------------- Laurent@714: # Project Properties Panel Laurent@714: #------------------------------------------------------------------------------- Laurent@714: Laurent@700: class ProjectPropertiesPanel(wx.Notebook): Laurent@700: Laurent@700: def AddSizerParams(self, parent, sizer, params): Laurent@700: for idx, (name, label) in enumerate(params): Laurent@700: border = 0 Laurent@700: if idx == 0: Laurent@700: border |= wx.TOP Laurent@700: elif idx == len(params) - 1: Laurent@700: border |= wx.BOTTOM Laurent@700: Laurent@714: st = wx.StaticText(parent, label=label) Laurent@714: sizer.AddWindow(st, border=10, Laurent@714: flag=wx.ALIGN_CENTER_VERTICAL|border|wx.LEFT) Laurent@700: Laurent@714: tc = wx.TextCtrl(parent, style=wx.TE_PROCESS_ENTER) Laurent@700: setattr(self, name, tc) Laurent@700: callback = self.GetTextCtrlChangedFunction(tc, name) Laurent@714: self.Bind(wx.EVT_TEXT_ENTER, callback, tc) Laurent@700: tc.Bind(wx.EVT_KILL_FOCUS, callback) Laurent@714: sizer.AddWindow(tc, border=10, Laurent@714: flag=wx.GROW|border|wx.RIGHT) Laurent@700: Laurent@700: def __init__(self, parent, controller=None, window=None, enable_required=True): Laurent@714: wx.Notebook.__init__(self, parent, size=wx.Size(500, 300)) Laurent@700: Laurent@700: self.Controller = controller Laurent@700: self.ParentWindow = window Laurent@700: self.Values = None Laurent@700: Laurent@700: # Project Panel elements Laurent@700: Laurent@714: self.ProjectPanel = wx.Panel(self, style=wx.TAB_TRAVERSAL) Laurent@700: projectpanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=5, vgap=15) Laurent@700: projectpanel_sizer.AddGrowableCol(1) Laurent@700: self.ProjectPanel.SetSizer(projectpanel_sizer) Laurent@700: Laurent@700: self.AddSizerParams(self.ProjectPanel, projectpanel_sizer, Laurent@700: [("projectName", _('Project Name (required):')), Laurent@700: ("projectVersion", _('Project Version (optional):')), Laurent@700: ("productName", _('Product Name (required):')), Laurent@700: ("productVersion", _('Product Version (required):')), Laurent@700: ("productRelease", _('Product Release (optional):'))]) Laurent@700: Laurent@700: self.AddPage(self.ProjectPanel, _("Project")) Laurent@700: Laurent@700: # Author Panel elements Laurent@700: Laurent@714: self.AuthorPanel = wx.Panel(self, style=wx.TAB_TRAVERSAL) Laurent@700: authorpanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=4, vgap=15) Laurent@700: authorpanel_sizer.AddGrowableCol(1) Laurent@700: self.AuthorPanel.SetSizer(authorpanel_sizer) Laurent@700: Laurent@700: self.AddSizerParams(self.AuthorPanel, authorpanel_sizer, Laurent@700: [("companyName", _('Company Name (required):')), Laurent@700: ("companyURL", _('Company URL (optional):')), Laurent@700: ("authorName", _('Author Name (optional):')), Laurent@700: ("organization", _('Organization (optional):'))]) Laurent@700: Laurent@700: self.AddPage(self.AuthorPanel, _("Author")) Laurent@700: Laurent@700: # Graphics Panel elements Laurent@700: Laurent@714: self.GraphicsPanel = wx.Panel(self, style=wx.TAB_TRAVERSAL) Laurent@700: graphicpanel_sizer = wx.FlexGridSizer(cols=1, hgap=5, rows=4, vgap=5) Laurent@700: graphicpanel_sizer.AddGrowableCol(0) Laurent@700: graphicpanel_sizer.AddGrowableRow(3) Laurent@700: self.GraphicsPanel.SetSizer(graphicpanel_sizer) Laurent@700: Laurent@714: pageSize_st = wx.StaticText(self.GraphicsPanel, Laurent@714: label=_('Page Size (optional):')) Laurent@714: graphicpanel_sizer.AddWindow(pageSize_st, border=10, Laurent@714: flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP|wx.LEFT|wx.RIGHT) Laurent@700: Laurent@700: pageSize_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5) Laurent@700: pageSize_sizer.AddGrowableCol(1) Laurent@714: graphicpanel_sizer.AddSizer(pageSize_sizer, border=10, Laurent@714: flag=wx.GROW|wx.LEFT|wx.RIGHT) Laurent@700: Laurent@700: for name, label in [('PageWidth', _('Width:')), Laurent@700: ('PageHeight', _('Height:'))]: Laurent@714: st = wx.StaticText(self.GraphicsPanel, label=label) Laurent@714: pageSize_sizer.AddWindow(st, border=12, Laurent@714: flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT) Laurent@700: Laurent@714: sp = wx.SpinCtrl(self.GraphicsPanel, Laurent@714: min=0, max=2**16, style=wx.TE_PROCESS_ENTER) Laurent@700: setattr(self, name, sp) Laurent@700: callback = self.GetPageSizeChangedFunction(sp, name) Laurent@714: self.Bind(wx.EVT_TEXT_ENTER, callback, sp) Laurent@700: sp.Bind(wx.EVT_KILL_FOCUS, callback) Laurent@714: pageSize_sizer.AddWindow(sp, flag=wx.GROW) Laurent@714: Laurent@714: scaling_st = wx.StaticText(self.GraphicsPanel, Laurent@714: label=_('Grid Resolution:')) Laurent@714: graphicpanel_sizer.AddWindow(scaling_st, border=10, Laurent@714: flag=wx.GROW|wx.LEFT|wx.RIGHT) Laurent@714: Laurent@714: scaling_nb = wx.Notebook(self.GraphicsPanel) Laurent@714: graphicpanel_sizer.AddWindow(scaling_nb, border=10, Laurent@714: flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT) Laurent@700: Laurent@700: self.Scalings = {} Laurent@700: for language, translation in [("FBD",_("FBD")), ("LD",_("LD")), ("SFC",_("SFC"))]: Laurent@714: scaling_panel = wx.Panel(scaling_nb, style=wx.TAB_TRAVERSAL) Laurent@700: scalingpanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5) Laurent@700: scalingpanel_sizer.AddGrowableCol(1) Laurent@700: scaling_panel.SetSizer(scalingpanel_sizer) Laurent@700: Laurent@700: scaling_controls = [] Laurent@700: for idx, (name, label) in enumerate([('XScale', _('Horizontal:')), Laurent@700: ('YScale', _('Vertical:'))]): Laurent@700: if idx == 0: Laurent@700: border = wx.TOP Laurent@700: else: Laurent@700: border = wx.BOTTOM Laurent@700: Laurent@714: st = wx.StaticText(scaling_panel, label=label) Laurent@714: scalingpanel_sizer.AddWindow(st, border=10, Laurent@714: flag=wx.ALIGN_CENTER_VERTICAL|border|wx.LEFT) Laurent@700: Laurent@714: sp = wx.SpinCtrl(scaling_panel, Laurent@714: min=0, max=2**16, style=wx.TE_PROCESS_ENTER) Laurent@700: scaling_controls.append(sp) Laurent@700: callback = self.GetScalingChangedFunction(sp, language, name) Laurent@714: self.Bind(wx.EVT_TEXT_ENTER, callback, sp) Laurent@700: sp.Bind(wx.EVT_KILL_FOCUS, callback) Laurent@714: scalingpanel_sizer.AddWindow(sp, border=10, Laurent@714: flag=wx.GROW|border|wx.RIGHT) Laurent@700: Laurent@700: self.Scalings[language] = scaling_controls Laurent@700: scaling_nb.AddPage(scaling_panel, translation) Laurent@700: Laurent@700: self.AddPage(self.GraphicsPanel, _("Graphics")) Laurent@700: Laurent@700: # Miscellaneous Panel elements Laurent@700: Laurent@700: self.MiscellaneousPanel = wx.Panel(id=-1, parent=self, Laurent@700: name='MiscellaneousPanel', pos=wx.Point(0, 0), Laurent@700: size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) Laurent@700: miscellaneouspanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=15) Laurent@700: miscellaneouspanel_sizer.AddGrowableCol(1) Laurent@700: miscellaneouspanel_sizer.AddGrowableRow(1) Laurent@700: self.MiscellaneousPanel.SetSizer(miscellaneouspanel_sizer) Laurent@700: Laurent@714: language_label = wx.StaticText(self.MiscellaneousPanel, Laurent@714: label=_('Language (optional):')) Laurent@714: miscellaneouspanel_sizer.AddWindow(language_label, border=10, Laurent@714: flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP|wx.LEFT) Laurent@714: Laurent@714: self.Language = wx.ComboBox(self.MiscellaneousPanel, Laurent@714: style=wx.CB_READONLY) Laurent@714: self.Bind(wx.EVT_COMBOBOX, self.OnLanguageChanged, self.Language) Laurent@714: miscellaneouspanel_sizer.AddWindow(self.Language, border=10, Laurent@714: flag=wx.GROW|wx.TOP|wx.RIGHT) Laurent@714: Laurent@714: description_label = wx.StaticText(self.MiscellaneousPanel, Laurent@714: label=_('Content Description (optional):')) Laurent@714: miscellaneouspanel_sizer.AddWindow(description_label, border=10, Laurent@714: flag=wx.BOTTOM|wx.LEFT) Laurent@714: Laurent@714: self.ContentDescription = wx.TextCtrl(self.MiscellaneousPanel, Laurent@714: style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) Laurent@714: self.Bind(wx.EVT_TEXT_ENTER, self.OnContentDescriptionChanged, Laurent@714: self.ContentDescription) Laurent@714: self.ContentDescription.Bind(wx.EVT_KILL_FOCUS, Laurent@714: self.OnContentDescriptionChanged) Laurent@714: miscellaneouspanel_sizer.AddWindow(self.ContentDescription, border=10, Laurent@714: flag=wx.GROW|wx.BOTTOM|wx.RIGHT) Laurent@700: Laurent@700: self.AddPage(self.MiscellaneousPanel, _("Miscellaneous")) Laurent@700: Laurent@700: for param in REQUIRED_PARAMS: Laurent@700: getattr(self, param).Enable(enable_required) Laurent@700: Laurent@700: languages = ["", "en-US", "fr-FR", "zh-CN"] Laurent@700: Laurent@700: for language in languages: Laurent@700: self.Language.Append(language) Laurent@700: Laurent@700: def RefreshView(self): Laurent@700: if self.Controller is not None: Laurent@700: self.SetValues(self.Controller.GetProjectProperties()) Laurent@700: Laurent@700: def SetValues(self, values): Laurent@700: self.Values = values Laurent@700: for item, value in values.items(): Laurent@700: if item == "language": Laurent@700: self.Language.SetStringSelection(value) Laurent@700: elif item == "contentDescription": Laurent@700: self.ContentDescription.SetValue(value) Laurent@700: elif item == "pageSize": Laurent@700: self.PageWidth.SetValue(value[0]) Laurent@700: self.PageHeight.SetValue(value[1]) Laurent@700: elif item == "scaling": Laurent@700: for language, (x, y) in value.items(): Laurent@700: if language in self.Scalings: Laurent@700: self.Scalings[language][0].SetValue(x) Laurent@700: self.Scalings[language][1].SetValue(y) Laurent@700: else: Laurent@700: tc = getattr(self, item, None) Laurent@700: if tc is not None: Laurent@700: tc.SetValue(value) Laurent@700: Laurent@700: def GetValues(self): Laurent@700: values = {} Laurent@700: for param in ["projectName", "projectVersion", Laurent@700: "productName", "productVersion", Laurent@700: "productRelease", "companyName", Laurent@700: "companyURL", "authorName", Laurent@700: "organization"]: Laurent@700: value = getattr(self, param).GetValue() Laurent@700: if param in REQUIRED_PARAMS or value != "": Laurent@700: values[param] = value Laurent@702: else: Laurent@702: values[param] = None Laurent@702: language = self.Language.GetStringSelection() Laurent@702: if language != "": Laurent@702: values["language"] = language Laurent@702: else: Laurent@702: values["language"] = None Laurent@702: content_description = self.ContentDescription.GetValue() Laurent@702: if content_description != "": Laurent@702: values["contentDescription"] = content_description Laurent@702: else: Laurent@702: values["contentDescription"] = None Laurent@700: values["pageSize"] = (self.PageWidth.GetValue(), self.PageHeight.GetValue()) Laurent@700: values["scaling"] = {} Laurent@700: for language in ["FBD", "LD", "SFC"]: Laurent@700: values["scaling"][language] = (self.Scalings[language][0].GetValue(), Laurent@700: self.Scalings[language][1].GetValue()) Laurent@700: return values Laurent@700: Laurent@700: def GetTextCtrlChangedFunction(self, textctrl, name): Laurent@700: def TextCtrlChangedFunction(event): Laurent@700: if self.Controller is not None: Laurent@700: if self.Values is not None: Laurent@700: old_value = self.Values.get(name) Laurent@700: else: Laurent@700: old_value = None Laurent@700: new_value = textctrl.GetValue() Laurent@702: if name not in REQUIRED_PARAMS and new_value == "": Laurent@702: new_value = None Laurent@700: if old_value != new_value: Laurent@700: self.Controller.SetProjectProperties(properties={name: new_value}) Laurent@714: self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, Laurent@714: PROJECTTREE, PAGETITLES) Laurent@700: wx.CallAfter(self.RefreshView) Laurent@700: event.Skip() Laurent@700: return TextCtrlChangedFunction Laurent@700: Laurent@700: def GetPageSizeChangedFunction(self, spinctrl, name): Laurent@700: def PageSizeChangedFunction(event): Laurent@700: if self.Controller is not None: Laurent@700: if self.Values is not None: Laurent@700: old_value = self.Values.get("pageSize") Laurent@700: else: Laurent@700: old_value = (0, 0) Laurent@700: if name == 'PageWidth': Laurent@700: new_value = (spinctrl.GetValue(), old_value[1]) Laurent@700: else: Laurent@700: new_value = (old_value[0], spinctrl.GetValue()) Laurent@700: if old_value != new_value: Laurent@700: self.Controller.SetProjectProperties(properties={"pageSize": new_value}) Laurent@714: self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, Laurent@714: PAGETITLES, SCALING) Laurent@700: wx.CallAfter(self.RefreshView) Laurent@700: event.Skip() Laurent@700: return PageSizeChangedFunction Laurent@700: Laurent@700: def GetScalingChangedFunction(self, spinctrl, language, name): Laurent@700: def ScalingChangedFunction(event): Laurent@700: if self.Controller is not None: Laurent@700: old_value = (0, 0) Laurent@700: if self.Values is not None: Laurent@700: scaling = self.Values.get("scaling") Laurent@700: if scaling is not None: Laurent@700: old_value = scaling.get(language) Laurent@700: if name == 'XScale': Laurent@700: new_value = (spinctrl.GetValue(), old_value[1]) Laurent@700: else: Laurent@700: new_value = (old_value[0], spinctrl.GetValue()) Laurent@700: if old_value != new_value: Laurent@700: self.Controller.SetProjectProperties(properties={"scaling": {language: new_value}}) Laurent@714: self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, Laurent@714: PAGETITLES, SCALING) Laurent@700: wx.CallAfter(self.RefreshView) Laurent@700: event.Skip() Laurent@700: return ScalingChangedFunction Laurent@700: Laurent@700: def OnLanguageChanged(self, event): Laurent@700: if self.Controller is not None: Laurent@700: if self.Values is not None: Laurent@700: old_value = self.Values.get("language") Laurent@700: else: Laurent@700: old_value = None Laurent@700: new_value = self.Language.GetStringSelection() Laurent@702: if new_value == "": Laurent@702: new_value = None Laurent@700: if old_value != new_value: Laurent@700: self.Controller.SetProjectProperties(properties={"language": new_value}) Laurent@714: self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES) Laurent@700: wx.CallAfter(self.RefreshView) Laurent@700: event.Skip() Laurent@700: Laurent@700: def OnContentDescriptionChanged(self, event): Laurent@700: if self.Controller is not None: Laurent@700: if self.Values is not None: Laurent@700: old_value = self.Values.get("contentDescription") Laurent@700: else: Laurent@700: old_value = None Laurent@700: new_value = self.ContentDescription.GetValue() Laurent@702: if new_value == "": Laurent@702: new_value = None Laurent@700: if old_value != new_value: Laurent@700: self.Controller.SetProjectProperties(properties={"contentDescription": new_value}) Laurent@714: self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES) Laurent@700: wx.CallAfter(self.RefreshView) Laurent@700: event.Skip()