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.
Laurent@814: #
andrej@1571: # Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
andrej@1696: # Copyright (C) 2017: Andrey Skvortsov <andrej.skvortzov@gmail.com>
Laurent@814: #
andrej@1571: # See COPYING file for copyrights details.
Laurent@814: #
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.
Laurent@814: #
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.
Laurent@814: #
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: 
andrej@1853: from __future__ import absolute_import
Laurent@814: import wx
Laurent@814: 
Laurent@1246: from graphics.GraphicCommons import CONTACT_NORMAL, CONTACT_REVERSE, \
Laurent@1246:     CONTACT_RISING, CONTACT_FALLING, COIL_NORMAL, COIL_REVERSE, COIL_SET, \
Laurent@1246:     COIL_RESET, COIL_RISING, COIL_FALLING
Laurent@1246: from graphics.LD_Objects import LD_Contact, LD_Coil
andrej@1853: from dialogs.BlockPreviewDialog import BlockPreviewDialog
Laurent@814: 
andrej@1782: # -------------------------------------------------------------------------------
Laurent@1246: #                       Set Ladder Element Parmeters Dialog
andrej@1782: # -------------------------------------------------------------------------------
Laurent@814: 
Laurent@1246: 
Laurent@1246: class LDElementDialog(BlockPreviewDialog):
andrej@1736:     """
andrej@1736:     Class that implements a dialog for defining parameters of a LD contact or coil
andrej@1736:     graphic element
andrej@1736:     """
andrej@1730: 
Laurent@1246:     def __init__(self, parent, controller, tagname, type):
Laurent@1246:         """
Laurent@1246:         Constructor
Laurent@1246:         @param parent: Parent wx.Window of dialog for modal
Laurent@1246:         @param controller: Reference to project controller
Laurent@1246:         @param tagname: Tagname of project POU edited
Laurent@1246:         @param type: Type of LD element ('contact or 'coil')
Laurent@1246:         """
andrej@1730:         BlockPreviewDialog.__init__(self, parent, controller, tagname,
andrej@1768:                                     title=(_("Edit Contact Values")
andrej@1768:                                            if type == "contact"
andrej@1768:                                            else _("Edit Coil Values")))
andrej@1730: 
Laurent@1250:         # Init common sizers
andrej@1768:         self._init_sizers(2, 0, (7 if type == "contact" else 9),
andrej@1768:                           None, 2, 1)
andrej@1730: 
Laurent@1246:         # Create label for LD element modifier
Laurent@814:         modifier_label = wx.StaticText(self, label=_('Modifier:'))
andrej@1730:         self.LeftGridSizer.AddWindow(modifier_label, border=5,
andrej@1768:                                      flag=wx.GROW | wx.BOTTOM)
andrej@1730: 
Laurent@1246:         # Create radio buttons for selecting LD element modifier
Laurent@1246:         self.ModifierRadioButtons = {}
Laurent@1246:         first = True
andrej@1730:         element_modifiers = ([CONTACT_NORMAL, CONTACT_REVERSE,
Laurent@1246:                               CONTACT_RISING, CONTACT_FALLING]
Laurent@1246:                              if type == "contact"
Laurent@1246:                              else [COIL_NORMAL, COIL_REVERSE, COIL_SET,
Laurent@1246:                                    COIL_RESET, COIL_RISING, COIL_FALLING])
andrej@1767:         modifiers_label = \
andrej@1767:             [_("Normal"), _("Negated")] + \
andrej@1767:             ([_("Set"), _("Reset")] if type == "coil" else []) + \
andrej@1767:             [_("Rising Edge"), _("Falling Edge")]
andrej@1730: 
Laurent@1246:         for modifier, label in zip(element_modifiers, modifiers_label):
andrej@1730:             radio_button = wx.RadioButton(self, label=label,
andrej@1768:                                           style=(wx.RB_GROUP if first else 0))
Laurent@1246:             radio_button.SetValue(first)
Laurent@1246:             self.Bind(wx.EVT_RADIOBUTTON, self.OnModifierChanged, radio_button)
Laurent@1250:             self.LeftGridSizer.AddWindow(radio_button, flag=wx.GROW)
Laurent@1246:             self.ModifierRadioButtons[modifier] = radio_button
Laurent@1246:             first = False
andrej@1730: 
Laurent@1246:         # Create label for LD element variable
Laurent@1246:         element_variable_label = wx.StaticText(self, label=_('Variable:'))
Laurent@1250:         self.LeftGridSizer.AddWindow(element_variable_label, border=5,
andrej@1768:                                      flag=wx.GROW | wx.TOP)
andrej@1730: 
Laurent@1246:         # Create a combo box for defining LD element variable
Laurent@1370:         self.ElementVariable = wx.ComboBox(self, style=wx.CB_SORT)
andrej@1730:         self.Bind(wx.EVT_COMBOBOX, self.OnVariableChanged,
Laurent@1246:                   self.ElementVariable)
andrej@1730:         self.Bind(wx.EVT_TEXT, self.OnVariableChanged,
andrej@1730:                   self.ElementVariable)
Laurent@1250:         self.LeftGridSizer.AddWindow(self.ElementVariable, border=5,
andrej@1768:                                      flag=wx.GROW | wx.TOP)
andrej@1730: 
Laurent@1246:         # Add preview panel and associated label to sizers
Laurent@1250:         self.RightGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW)
Laurent@1250:         self.RightGridSizer.AddWindow(self.Preview, flag=wx.GROW)
andrej@1730: 
Laurent@1246:         # Add buttons sizer to sizers
andrej@1730:         self.MainSizer.AddSizer(self.ButtonSizer, border=20,
andrej@1768:                                 flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT)
andrej@1730: 
Laurent@1246:         # Save LD element class
Laurent@1246:         self.ElementClass = (LD_Contact if type == "contact" else LD_Coil)
andrej@1730: 
Laurent@1246:         # Extract list of variables defined in POU
Laurent@1246:         self.RefreshVariableList()
andrej@1730: 
Laurent@1246:         # Set values in ElementVariable
Laurent@1246:         for name, (var_type, value_type) in self.VariableList.iteritems():
Laurent@1246:             # Only select BOOL variable and avoid input for coil
Laurent@1246:             if (type == "contact" or var_type != "Input") and \
Laurent@1246:                value_type == "BOOL":
Laurent@1246:                 self.ElementVariable.Append(name)
andrej@1730: 
andrej@1696:         self.Fit()
Laurent@1246:         # Normal radio button is default control having keyboard focus
Laurent@1246:         self.ModifierRadioButtons[element_modifiers[0]].SetFocus()
andrej@1730: 
Laurent@1246:     def GetElementModifier(self):
Laurent@1246:         """
Laurent@1246:         Return modifier selected for LD element
Laurent@1246:         @return: Modifier selected (None if not found)
Laurent@1246:         """
Laurent@1246:         # Go through radio buttons and return modifier associated to the one
Laurent@1246:         # that is selected
Laurent@1246:         for modifier, control in self.ModifierRadioButtons.iteritems():
Laurent@1246:             if control.GetValue():
Laurent@1246:                 return modifier
Laurent@1246:         return None
Laurent@814: 
Laurent@814:     def SetValues(self, values):
Laurent@1246:         """
Laurent@1246:         Set default LD element parameters
Laurent@1252:         @param values: LD element parameters values
Laurent@1246:         """
Laurent@1246:         # For each parameters defined, set corresponding control value
Laurent@814:         for name, value in values.items():
andrej@1730: 
Laurent@1246:             # Parameter is LD element variable
Laurent@1246:             if name == "variable":
Laurent@1370:                 self.ElementVariable.SetValue(value)
andrej@1730: 
Laurent@1246:             # Set value of other controls
Laurent@1246:             elif name == "modifier":
Laurent@1246:                 self.ModifierRadioButtons[value].SetValue(True)
andrej@1730: 
Laurent@1246:         # Refresh preview panel
Edouard@2591:         self.RefreshPreview()
Laurent@814: 
Laurent@814:     def GetValues(self):
Laurent@1246:         """
Laurent@1246:         Return LD element parameters defined in dialog
Laurent@1246:         @return: {parameter_name: parameter_value,...}
Laurent@1246:         """
Laurent@1246:         values = {
Laurent@1246:             "variable": self.ElementVariable.GetValue(),
Laurent@1246:             "modifier": self.GetElementModifier()}
Laurent@814:         values["width"], values["height"] = self.Element.GetSize()
Laurent@814:         return values
Laurent@814: 
Laurent@1246:     def OnModifierChanged(self, event):
Laurent@1246:         """
Laurent@1246:         Called when LD element modifier changed
Laurent@1246:         @param event: wx.RadioButtonEvent
Laurent@1246:         """
Edouard@2591:         self.RefreshPreview()
Laurent@814:         event.Skip()
Laurent@814: 
Laurent@1246:     def OnVariableChanged(self, event):
Laurent@1246:         """
Laurent@1246:         Called when LD element associated variable changed
Laurent@1246:         @param event: wx.ComboBoxEvent
Laurent@1246:         """
Edouard@2591:         self.RefreshPreview()
Laurent@814:         event.Skip()
Laurent@814: 
Edouard@2587:     def DrawPreview(self):
Laurent@1246:         """
Laurent@1246:         Refresh preview panel of graphic element
Laurent@1246:         Override BlockPreviewDialog function
Laurent@1246:         """
andrej@1698:         value = self.ElementVariable.GetValue()
andrej@1730: 
Laurent@1246:         # Set graphic element displayed, creating a LD element
Laurent@1246:         self.Element = self.ElementClass(
andrej@1878:             self.Preview,
andrej@1878:             self.GetElementModifier(),
andrej@1878:             value)
andrej@1698: 
andrej@1698:         button = self.ButtonSizer.GetAffirmativeButton()
andrej@1698:         button.Enable(value != "")
andrej@1730: 
Laurent@1246:         # Call BlockPreviewDialog function
Edouard@2587:         BlockPreviewDialog.DrawPreview(self)
andrej@1730: 
andrej@1698:     def OnOK(self, event):
andrej@1698:         if self.ElementVariable.GetValue() != "":
andrej@1698:             self.EndModal(wx.ID_OK)