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: andrej@1853: from __future__ import absolute_import Laurent@814: import wx Laurent@814: Laurent@1244: from graphics.GraphicCommons import INPUT, INOUT, OUTPUT Laurent@1244: from graphics.FBD_Objects import FBD_Variable andrej@1853: from dialogs.BlockPreviewDialog import BlockPreviewDialog Laurent@814: andrej@1782: # ------------------------------------------------------------------------------- Laurent@814: # Helpers andrej@1782: # ------------------------------------------------------------------------------- Laurent@814: Laurent@814: andrej@1782: # ------------------------------------------------------------------------------- Laurent@1244: # Set Variable Parameters Dialog andrej@1782: # ------------------------------------------------------------------------------- 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@1768: title=_('Variable Properties')) andrej@1730: andrej@2301: # Dictionaries containing correspondence between variable block class and string andrej@2301: # to be shown in Class combo box in both sense andrej@2301: self.VARIABLE_CLASSES_DICT = { andrej@2301: INPUT: _("Input"), andrej@2301: INOUT: _("InOut"), andrej@2301: OUTPUT: _("Output") andrej@2301: } andrej@2301: andrej@2301: self.VARIABLE_CLASSES_DICT_REVERSE = dict( andrej@2301: [(value, key) for key, value in self.VARIABLE_CLASSES_DICT.iteritems()]) andrej@2301: 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:')) edouard@3303: self.LeftGridSizer.Add(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) edouard@3303: self.LeftGridSizer.Add(self.Class, flag=wx.GROW) andrej@1730: Laurent@1244: # Create label for variable execution order andrej@1730: execution_order_label = wx.StaticText(self, andrej@1768: label=_('Execution Order:')) edouard@3303: self.LeftGridSizer.Add(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) edouard@3303: self.LeftGridSizer.Add(self.ExecutionOrder, flag=wx.GROW) andrej@1730: Laurent@1244: # Create label for variable expression Laurent@1182: name_label = wx.StaticText(self, label=_('Expression:')) edouard@3303: self.RightGridSizer.Add(name_label, border=5, andrej@1768: 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) edouard@3303: self.RightGridSizer.Add(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), andrej@1768: style=wx.LB_SINGLE | wx.LB_SORT) Laurent@814: self.Bind(wx.EVT_LISTBOX, self.OnNameChanged, self.VariableName) edouard@3303: self.RightGridSizer.Add(self.VariableName, border=4, flag=wx.GROW | wx.TOP) andrej@1730: Laurent@1244: # Add preview panel and associated label to sizers edouard@3303: self.MainSizer.Add(self.PreviewLabel, border=20, andrej@1768: flag=wx.GROW | wx.LEFT | wx.RIGHT) edouard@3303: self.MainSizer.Add(self.Preview, border=20, andrej@1768: flag=wx.GROW | wx.LEFT | wx.RIGHT) andrej@1730: Laurent@1244: # Add buttons sizer to sizers edouard@3303: self.MainSizer.Add( andrej@1768: self.ButtonSizer, border=20, andrej@1768: flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT) andrej@1730: Laurent@1244: # Set options that can be selected in class combo box andrej@2301: for var_class, choice in self.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 andrej@2301: var_class = self.VARIABLE_CLASSES_DICT_REVERSE[ andrej@1878: 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() andrej@1847: 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@1766: if selected != "" and 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 andrej@2301: self.Class.SetStringSelection(self.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 Edouard@2591: self.Refresh() 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 = { andrej@2301: "class": self.VARIABLE_CLASSES_DICT_REVERSE[ andrej@1878: 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: Edouard@2591: self.Refresh() 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: Edouard@2591: self.Refresh() 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: Edouard@2591: self.Refresh() 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: """ Edouard@2591: self.Refresh() Edouard@2587: event.Skip() Edouard@2587: Edouard@2587: def DrawPreview(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@1768: self.Element = FBD_Variable( andrej@1768: self.Preview, andrej@2301: self.VARIABLE_CLASSES_DICT_REVERSE[self.Class.GetStringSelection()], andrej@1768: name, andrej@1768: self.VariableList.get(name, ("", ""))[1], andrej@1768: executionOrder=self.ExecutionOrder.GetValue()) andrej@1730: Laurent@1244: # Call BlockPreviewDialog function Edouard@2587: BlockPreviewDialog.DrawPreview(self)