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