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) 2007: 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: Laurent@1244: from graphics.GraphicCommons import INPUT, INOUT, OUTPUT Laurent@1244: from graphics.FBD_Objects import FBD_Variable Laurent@1244: from BlockPreviewDialog import BlockPreviewDialog Laurent@814: Laurent@814: #------------------------------------------------------------------------------- Laurent@814: # Helpers Laurent@814: #------------------------------------------------------------------------------- Laurent@814: Laurent@1244: # Dictionaries containing correspondence between variable block class and string Laurent@1244: # to be shown in Class combo box in both sense andrej@1739: VARIABLE_CLASSES_DICT = { andrej@1739: INPUT: _("Input"), andrej@1739: INOUT: _("InOut"), andrej@1739: OUTPUT: _("Output") andrej@1739: } andrej@1739: Laurent@814: VARIABLE_CLASSES_DICT_REVERSE = dict( Laurent@814: [(value, key) for key, value in VARIABLE_CLASSES_DICT.iteritems()]) Laurent@814: Laurent@814: #------------------------------------------------------------------------------- Laurent@1244: # Set Variable Parameters Dialog Laurent@814: #------------------------------------------------------------------------------- Laurent@814: Laurent@1244: Laurent@1244: class FBDVariableDialog(BlockPreviewDialog): andrej@1736: """ andrej@1736: Class that implements a dialog for defining parameters of a FBD variable graphic andrej@1736: element andrej@1736: """ Laurent@1244: Laurent@1259: def __init__(self, parent, controller, tagname, exclude_input=False): Laurent@1244: """ Laurent@1244: Constructor Laurent@1244: @param parent: Parent wx.Window of dialog for modal Laurent@1244: @param controller: Reference to project controller Laurent@1244: @param tagname: Tagname of project POU edited Laurent@1259: @param exclude_input: Exclude input from variable class selection Laurent@1244: """ Laurent@1244: BlockPreviewDialog.__init__(self, parent, controller, tagname, andrej@1696: title=_('Variable Properties')) andrej@1730: Laurent@1250: # Init common sizers Laurent@1250: self._init_sizers(4, 2, 4, None, 3, 2) andrej@1730: Laurent@1244: # Create label for variable class Laurent@814: class_label = wx.StaticText(self, label=_('Class:')) Laurent@1250: self.LeftGridSizer.AddWindow(class_label, flag=wx.GROW) andrej@1730: Laurent@1244: # Create a combo box for defining variable class Laurent@814: self.Class = wx.ComboBox(self, style=wx.CB_READONLY) Laurent@814: self.Bind(wx.EVT_COMBOBOX, self.OnClassChanged, self.Class) Laurent@1250: self.LeftGridSizer.AddWindow(self.Class, flag=wx.GROW) andrej@1730: Laurent@1244: # Create label for variable execution order andrej@1730: execution_order_label = wx.StaticText(self, Laurent@1244: label=_('Execution Order:')) Laurent@1250: self.LeftGridSizer.AddWindow(execution_order_label, flag=wx.GROW) andrej@1730: Laurent@1244: # Create spin control for defining variable execution order Laurent@814: self.ExecutionOrder = wx.SpinCtrl(self, min=0, style=wx.SP_ARROW_KEYS) andrej@1730: self.Bind(wx.EVT_SPINCTRL, self.OnExecutionOrderChanged, Laurent@1244: self.ExecutionOrder) Laurent@1250: self.LeftGridSizer.AddWindow(self.ExecutionOrder, flag=wx.GROW) andrej@1730: Laurent@1244: # Create label for variable expression Laurent@1182: name_label = wx.StaticText(self, label=_('Expression:')) andrej@1730: self.RightGridSizer.AddWindow(name_label, border=5, Laurent@1250: flag=wx.GROW|wx.BOTTOM) andrej@1730: Laurent@1244: # Create text control for defining variable expression Laurent@1182: self.Expression = wx.TextCtrl(self) Laurent@1182: self.Bind(wx.EVT_TEXT, self.OnExpressionChanged, self.Expression) Laurent@1250: self.RightGridSizer.AddWindow(self.Expression, flag=wx.GROW) andrej@1730: Laurent@1244: # Create a list box to selected variable expression in the list of Laurent@1244: # variables defined in POU andrej@1740: self.VariableName = wx.ListBox(self, size=wx.Size(-1, 120), Laurent@814: style=wx.LB_SINGLE|wx.LB_SORT) Laurent@814: self.Bind(wx.EVT_LISTBOX, self.OnNameChanged, self.VariableName) andrej@1696: self.RightGridSizer.AddWindow(self.VariableName, border=4, flag=wx.GROW|wx.TOP) andrej@1730: Laurent@1244: # Add preview panel and associated label to sizers Laurent@1250: self.MainSizer.AddWindow(self.PreviewLabel, border=20, Laurent@814: flag=wx.GROW|wx.LEFT|wx.RIGHT) Laurent@1250: self.MainSizer.AddWindow(self.Preview, border=20, Laurent@814: flag=wx.GROW|wx.LEFT|wx.RIGHT) andrej@1730: Laurent@1244: # Add buttons sizer to sizers andrej@1730: self.MainSizer.AddSizer(self.ButtonSizer, border=20, Laurent@814: flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT) andrej@1730: Laurent@1244: # Set options that can be selected in class combo box Laurent@1259: for var_class, choice in VARIABLE_CLASSES_DICT.iteritems(): Laurent@1259: if not exclude_input or var_class != INPUT: Laurent@1259: self.Class.Append(choice) Laurent@1259: self.Class.SetSelection(0) andrej@1730: Laurent@1246: # Extract list of variables defined in POU Laurent@1246: self.RefreshVariableList() andrej@1730: Laurent@1244: # Refresh values in name list box Laurent@814: self.RefreshNameList() andrej@1730: andrej@1696: self.Preview.SetInitialSize(wx.Size(-1, 60)) andrej@1696: self.Fit() andrej@1696: Laurent@1244: # Class combo box is default control having keyboard focus Laurent@814: self.Class.SetFocus() Laurent@814: Laurent@814: def RefreshNameList(self): Laurent@1244: """ Laurent@1244: Called to refresh names in name list box Laurent@1244: """ Laurent@1244: # Get variable class to select POU variable applicable Laurent@1244: var_class = VARIABLE_CLASSES_DICT_REVERSE[ Laurent@1244: self.Class.GetStringSelection()] andrej@1730: Laurent@1244: # Refresh names in name list box by selecting variables in POU variables Laurent@1244: # list that can be applied to variable class Laurent@814: self.VariableName.Clear() Laurent@1246: for name, (var_type, value_type) in self.VariableList.iteritems(): Laurent@814: if var_type != "Input" or var_class == INPUT: Laurent@814: self.VariableName.Append(name) andrej@1730: Laurent@1244: # Get variable expression and select corresponding value in name list Laurent@1244: # box if it exists Laurent@1244: selected = self.Expression.GetValue() andrej@1730: if (selected != "" and Laurent@1244: self.VariableName.FindString(selected) != wx.NOT_FOUND): Laurent@814: self.VariableName.SetStringSelection(selected) Laurent@814: else: Laurent@1182: self.VariableName.SetSelection(wx.NOT_FOUND) andrej@1730: Laurent@1244: # Disable name list box if no name present inside Laurent@814: self.VariableName.Enable(self.VariableName.GetCount() > 0) andrej@1730: Laurent@814: def SetValues(self, values): Laurent@1244: """ Laurent@1244: Set default variable parameters Laurent@1244: @param values: Variable parameters values Laurent@1244: """ andrej@1730: Laurent@1244: # Get class parameter value Laurent@1244: var_class = values.get("class", None) Laurent@1244: if var_class is not None: Laurent@1244: # Set class selected in class combo box Laurent@1244: self.Class.SetStringSelection(VARIABLE_CLASSES_DICT[var_class]) Laurent@1244: # Refresh names in name list box according to var class Laurent@814: self.RefreshNameList() andrej@1730: Laurent@1244: # For each parameters defined, set corresponding control value Laurent@1244: for name, value in values.items(): andrej@1730: Laurent@1244: # Parameter is variable expression Laurent@1244: if name == "expression": Laurent@1244: # Set expression text control value Laurent@1244: self.Expression.ChangeValue(value) Laurent@1244: # Select corresponding text in name list box if it exists Laurent@1244: if self.VariableName.FindString(value) != wx.NOT_FOUND: Laurent@1244: self.VariableName.SetStringSelection(value) Laurent@1244: else: Laurent@1244: self.VariableName.SetSelection(wx.NOT_FOUND) andrej@1730: Laurent@1244: # Parameter is variable execution order Laurent@1244: elif name == "executionOrder": Laurent@1244: self.ExecutionOrder.SetValue(value) andrej@1730: Laurent@1244: # Refresh preview panel Laurent@814: self.RefreshPreview() andrej@1696: self.Fit() andrej@1730: Laurent@814: def GetValues(self): Laurent@1244: """ Laurent@1244: Return block parameters defined in dialog Laurent@1244: @return: {parameter_name: parameter_value,...} Laurent@1244: """ Laurent@1244: expression = self.Expression.GetValue() Laurent@1244: values = { Laurent@1244: "class": VARIABLE_CLASSES_DICT_REVERSE[ Laurent@1244: self.Class.GetStringSelection()], Laurent@1244: "expression": expression, Laurent@1246: "var_type": self.VariableList.get(expression, (None, None))[1], Laurent@1244: "executionOrder": self.ExecutionOrder.GetValue()} Laurent@1244: values["width"], values["height"] = self.Element.GetSize() Laurent@814: return values Laurent@814: Laurent@814: def OnOK(self, event): Laurent@1244: """ Laurent@1244: Called when dialog OK button is pressed Laurent@1244: Test if parameters defined are valid Laurent@1244: @param event: wx.Event from OK button Laurent@1244: """ Laurent@814: message = None andrej@1730: Laurent@1244: # Test that an expression have been selected or typed by user Laurent@1182: value = self.Expression.GetValue() Laurent@814: if value == "": Laurent@814: message = _("At least a variable or an expression must be selected!") andrej@1730: Laurent@1244: # Show error message if an error is detected Laurent@814: if message is not None: Laurent@1244: self.ShowErrorMessage(message) andrej@1730: Laurent@814: else: Laurent@1244: # Call BlockPreviewDialog function Laurent@1244: BlockPreviewDialog.OnOK(self, event) Laurent@814: Laurent@814: def OnClassChanged(self, event): Laurent@1244: """ Laurent@1244: Called when variable class value changed Laurent@1244: @param event: wx.ComboBoxEvent Laurent@1244: """ Laurent@1244: # Refresh name list box values Laurent@814: self.RefreshNameList() andrej@1730: Laurent@814: self.RefreshPreview() Laurent@814: event.Skip() Laurent@814: Laurent@814: def OnNameChanged(self, event): Laurent@1244: """ Laurent@1244: Called when name selected in name list box changed Laurent@1244: @param event: wx.ListBoxEvent Laurent@1244: """ Laurent@1244: # Change expression test control value to the value selected in name Laurent@1244: # list box if value selected is valid Laurent@1244: if self.VariableName.GetSelection() != wx.NOT_FOUND: Laurent@1244: self.Expression.ChangeValue(self.VariableName.GetStringSelection()) andrej@1730: andrej@1730: self.RefreshPreview() andrej@1730: event.Skip() andrej@1730: Laurent@814: def OnExpressionChanged(self, event): Laurent@1244: """ Laurent@1244: Called when expression text control is changed by user Laurent@1244: @param event: wx.ListBoxEvent Laurent@1244: """ Laurent@1244: # Select the corresponding value in name list box if it exists Laurent@1182: self.VariableName.SetSelection( Laurent@1244: self.VariableName.FindString(self.Expression.GetValue())) andrej@1730: andrej@1730: self.RefreshPreview() andrej@1730: event.Skip() andrej@1730: Laurent@814: def OnExecutionOrderChanged(self, event): Laurent@1244: """ Laurent@1244: Called when block execution control value changed Laurent@1244: @param event: wx.SpinEvent Laurent@1244: """ Laurent@814: self.RefreshPreview() Laurent@814: event.Skip() andrej@1730: Laurent@814: def RefreshPreview(self): Laurent@1244: """ Laurent@1244: Refresh preview panel of graphic element Laurent@1244: Override BlockPreviewDialog function Laurent@1244: """ Laurent@1244: # Get expression value to put in FBD variable element Laurent@1182: name = self.Expression.GetValue() andrej@1730: Laurent@1244: # Set graphic element displayed, creating a FBD variable element andrej@1730: self.Element = FBD_Variable(self.Preview, Laurent@1244: VARIABLE_CLASSES_DICT_REVERSE[ andrej@1730: self.Class.GetStringSelection()], andrej@1730: name, andrej@1730: self.VariableList.get(name, ("", ""))[1], Laurent@1244: executionOrder = self.ExecutionOrder.GetValue()) andrej@1730: Laurent@1244: # Call BlockPreviewDialog function Laurent@1244: BlockPreviewDialog.RefreshPreview(self)