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 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: Laurent@814: import re Laurent@864: from types import TupleType Laurent@814: Laurent@814: import wx Laurent@814: import wx.grid Laurent@814: import wx.lib.buttons Laurent@814: Edouard@1412: from plcopen.structures import IEC_KEYWORDS, TestIdentifier, DefaultType Laurent@814: from graphics.GraphicCommons import REFRESH_HIGHLIGHT_PERIOD Laurent@814: from controls import CustomEditableListBox, CustomGrid, CustomTable Laurent@864: from dialogs import ArrayTypeDialog Laurent@814: from EditorPanel import EditorPanel Laurent@814: from util.BitmapLibrary import GetBitmap andrej@1762: from util.TranslationCatalogs import NoTranslate Laurent@814: andrej@1782: # ------------------------------------------------------------------------------- Laurent@814: # Helpers andrej@1782: # ------------------------------------------------------------------------------- Laurent@814: Laurent@814: DIMENSION_MODEL = re.compile("([0-9]+)\.\.([0-9]+)$") Laurent@814: andrej@1736: Laurent@814: def AppendMenu(parent, help, id, kind, text): Laurent@814: parent.Append(help=help, id=id, kind=kind, text=text) Laurent@814: andrej@1736: Laurent@814: def GetElementsTableColnames(): andrej@1762: _ = NoTranslate Laurent@814: return ["#", _("Name"), _("Type"), _("Initial Value")] Laurent@814: andrej@1736: Laurent@814: def GetDatatypeTypes(): andrej@1762: _ = NoTranslate Laurent@814: return [_("Directly"), _("Subrange"), _("Enumerated"), _("Array"), _("Structure")] andrej@1749: andrej@1749: Laurent@814: DATATYPE_TYPES_DICT = dict([(_(datatype), datatype) for datatype in GetDatatypeTypes()]) Laurent@814: andrej@1782: # ------------------------------------------------------------------------------- Laurent@814: # Structure Elements Table andrej@1782: # ------------------------------------------------------------------------------- Laurent@814: andrej@1736: Laurent@814: class ElementsTable(CustomTable): Edouard@1412: Laurent@814: """ Laurent@814: A custom wx.grid.Grid Table using user supplied data Laurent@814: """ Laurent@814: def __init__(self, parent, data, colnames): Laurent@814: # The base class must be initialized *first* Laurent@814: CustomTable.__init__(self, parent, data, colnames) Laurent@814: self.old_value = None Edouard@1412: Laurent@814: def GetValue(self, row, col): Laurent@814: if row < self.GetNumberRows(): Laurent@814: if col == 0: Laurent@814: return row + 1 Laurent@864: colname = self.GetColLabelValue(col, False) Laurent@864: value = self.data[row].get(colname, "") andrej@1735: Laurent@864: if colname == "Type" and isinstance(value, TupleType): Laurent@864: if value[0] == "array": andrej@1739: return "ARRAY [%s] OF %s" % (",".join(map(lambda x: "..".join(x), value[2])), value[1]) andrej@1508: return value Edouard@1412: Laurent@814: def SetValue(self, row, col, value): Laurent@814: if col < len(self.colnames): Laurent@814: colname = self.GetColLabelValue(col, False) Laurent@814: if colname == "Name": Laurent@814: self.old_value = self.data[row][colname] Laurent@814: self.data[row][colname] = value Edouard@1412: Laurent@814: def GetOldValue(self): Laurent@814: return self.old_value Edouard@1412: Laurent@814: def _updateColAttrs(self, grid): Laurent@814: """ Laurent@814: wx.grid.Grid -> update the column attributes to add the Laurent@814: appropriate renderer given the column name. Laurent@814: Laurent@814: Otherwise default to the default renderer. Laurent@814: """ Edouard@1412: Laurent@814: for row in range(self.GetNumberRows()): Laurent@814: row_highlights = self.Highlights.get(row, {}) Laurent@814: for col in range(self.GetNumberCols()): Laurent@814: editor = None Laurent@814: renderer = None Laurent@814: colname = self.GetColLabelValue(col, False) Laurent@814: if col != 0: Laurent@814: grid.SetReadOnly(row, col, False) Laurent@814: if colname == "Name": Laurent@814: editor = wx.grid.GridCellTextEditor() Laurent@814: renderer = wx.grid.GridCellStringRenderer() Laurent@814: elif colname == "Initial Value": Laurent@814: editor = wx.grid.GridCellTextEditor() Laurent@814: renderer = wx.grid.GridCellStringRenderer() Laurent@814: elif colname == "Type": Laurent@814: editor = wx.grid.GridCellTextEditor() Laurent@814: else: Laurent@814: grid.SetReadOnly(row, col, True) Edouard@1412: Laurent@814: grid.SetCellEditor(row, col, editor) Laurent@814: grid.SetCellRenderer(row, col, renderer) Edouard@1412: Laurent@814: highlight_colours = row_highlights.get(colname.lower(), [(wx.WHITE, wx.BLACK)])[-1] Laurent@814: grid.SetCellBackgroundColour(row, col, highlight_colours[0]) Laurent@814: grid.SetCellTextColour(row, col, highlight_colours[1]) Laurent@814: self.ResizeRow(grid, row) Edouard@1412: Laurent@814: def AddHighlight(self, infos, highlight_type): Laurent@814: row_highlights = self.Highlights.setdefault(infos[0], {}) Laurent@814: if infos[1] == "initial": Laurent@814: col_highlights = row_highlights.setdefault("initial value", []) Laurent@814: else: Laurent@814: col_highlights = row_highlights.setdefault(infos[1], []) Laurent@814: col_highlights.append(highlight_type) Laurent@814: andrej@1782: # ------------------------------------------------------------------------------- Laurent@814: # Datatype Editor class andrej@1782: # ------------------------------------------------------------------------------- Laurent@814: andrej@1736: Laurent@814: class DataTypeEditor(EditorPanel): Edouard@1412: Laurent@814: def _init_Editor(self, parent): Laurent@814: self.Editor = wx.Panel(parent, style=wx.SUNKEN_BORDER) Edouard@1412: Laurent@814: self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10) Laurent@814: self.MainSizer.AddGrowableCol(0) Laurent@814: self.MainSizer.AddGrowableRow(1) Edouard@1412: Laurent@814: top_sizer = wx.BoxSizer(wx.HORIZONTAL) Edouard@1412: self.MainSizer.AddSizer(top_sizer, border=5, andrej@1768: flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT) Edouard@1412: Laurent@814: derivation_type_label = wx.StaticText(self.Editor, label=_('Derivation Type:')) Edouard@1412: top_sizer.AddWindow(derivation_type_label, border=5, andrej@1768: flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT) Edouard@1412: Laurent@814: self.DerivationType = wx.ComboBox(self.Editor, andrej@1768: size=wx.Size(200, -1), style=wx.CB_READONLY) Laurent@814: self.Bind(wx.EVT_COMBOBOX, self.OnDerivationTypeChanged, self.DerivationType) andrej@1745: top_sizer.AddWindow(self.DerivationType, border=5, flag=wx.GROW | wx.RIGHT) Edouard@1412: Laurent@814: typeinfos_staticbox = wx.StaticBox(self.Editor, label=_('Type infos:')) Laurent@814: typeinfos_sizer = wx.StaticBoxSizer(typeinfos_staticbox, wx.HORIZONTAL) Edouard@1412: self.MainSizer.AddSizer(typeinfos_sizer, border=5, andrej@1768: flag=wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT) Edouard@1412: Laurent@814: # Panel for Directly derived data types Laurent@814: Laurent@814: self.DirectlyPanel = wx.Panel(self.Editor, style=wx.TAB_TRAVERSAL) Laurent@814: typeinfos_sizer.AddWindow(self.DirectlyPanel, 1) Edouard@1412: Laurent@814: directly_panel_sizer = wx.BoxSizer(wx.HORIZONTAL) Edouard@1412: Edouard@1412: directly_basetype_label = wx.StaticText(self.DirectlyPanel, andrej@1768: label=_('Base Type:')) Edouard@1412: directly_panel_sizer.AddWindow(directly_basetype_label, 1, border=5, andrej@1768: flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) Edouard@1412: Laurent@814: self.DirectlyBaseType = wx.ComboBox(self.DirectlyPanel, style=wx.CB_READONLY) Laurent@947: self.Bind(wx.EVT_COMBOBOX, self.OnInfosChanged, self.DirectlyBaseType) Edouard@1412: directly_panel_sizer.AddWindow(self.DirectlyBaseType, 1, border=5, andrej@1768: flag=wx.GROW | wx.ALL) Edouard@1412: Laurent@814: directly_initialvalue_label = wx.StaticText(self.DirectlyPanel, andrej@1768: label=_('Initial Value:')) Edouard@1412: directly_panel_sizer.AddWindow(directly_initialvalue_label, 1, border=5, andrej@1768: flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) Edouard@1412: Edouard@1412: self.DirectlyInitialValue = wx.TextCtrl(self.DirectlyPanel, andrej@1768: style=wx.TE_PROCESS_ENTER | wx.TE_RICH) Laurent@814: self.Bind(wx.EVT_TEXT_ENTER, self.OnReturnKeyPressed, self.DirectlyInitialValue) Edouard@1412: directly_panel_sizer.AddWindow(self.DirectlyInitialValue, 1, border=5, andrej@1768: flag=wx.ALL) Edouard@1412: Laurent@814: self.DirectlyPanel.SetSizer(directly_panel_sizer) Edouard@1412: Laurent@814: # Panel for Subrange data types Laurent@814: Laurent@814: self.SubrangePanel = wx.Panel(self.Editor, style=wx.TAB_TRAVERSAL) Laurent@814: typeinfos_sizer.AddWindow(self.SubrangePanel, 1) Edouard@1412: Laurent@814: subrange_panel_sizer = wx.GridSizer(cols=4, hgap=5, rows=3, vgap=0) Edouard@1412: Laurent@814: subrange_basetype_label = wx.StaticText(self.SubrangePanel, andrej@1768: label=_('Base Type:')) Edouard@1412: subrange_panel_sizer.AddWindow(subrange_basetype_label, 1, border=5, andrej@1768: flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) Edouard@1412: Laurent@814: self.SubrangeBaseType = wx.ComboBox(self.SubrangePanel, style=wx.CB_READONLY) Edouard@1412: self.Bind(wx.EVT_COMBOBOX, self.OnSubrangeBaseTypeChanged, andrej@1768: self.SubrangeBaseType) Edouard@1412: subrange_panel_sizer.AddWindow(self.SubrangeBaseType, 1, border=5, andrej@1768: flag=wx.GROW | wx.ALL) Edouard@1412: Laurent@814: subrange_initialvalue_label = wx.StaticText(self.SubrangePanel, andrej@1768: label=_('Initial Value:')) Edouard@1412: subrange_panel_sizer.AddWindow(subrange_initialvalue_label, 1, border=5, andrej@1768: flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) Edouard@1412: Edouard@1412: self.SubrangeInitialValue = wx.SpinCtrl(self.SubrangePanel, andrej@1768: style=wx.TAB_TRAVERSAL) Laurent@814: self.Bind(wx.EVT_SPINCTRL, self.OnInfosChanged, self.SubrangeInitialValue) Edouard@1412: subrange_panel_sizer.AddWindow(self.SubrangeInitialValue, 1, border=5, andrej@1768: flag=wx.GROW | wx.ALL) Edouard@1412: Laurent@814: subrange_minimum_label = wx.StaticText(self.SubrangePanel, label=_('Minimum:')) Edouard@1412: subrange_panel_sizer.AddWindow(subrange_minimum_label, 1, border=5, andrej@1768: flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) Edouard@1412: Laurent@814: self.SubrangeMinimum = wx.SpinCtrl(self.SubrangePanel, style=wx.TAB_TRAVERSAL) Laurent@814: self.Bind(wx.EVT_SPINCTRL, self.OnSubrangeMinimumChanged, self.SubrangeMinimum) Edouard@1412: subrange_panel_sizer.AddWindow(self.SubrangeMinimum, 1, border=5, andrej@1768: flag=wx.GROW | wx.ALL) Edouard@1412: Laurent@814: for i in xrange(2): Laurent@814: subrange_panel_sizer.AddWindow(wx.Size(0, 0), 1) Edouard@1412: Laurent@814: subrange_maximum_label = wx.StaticText(self.SubrangePanel, andrej@1768: label=_('Maximum:')) Edouard@1412: subrange_panel_sizer.AddWindow(subrange_maximum_label, 1, border=5, andrej@1768: flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) Edouard@1412: Laurent@814: self.SubrangeMaximum = wx.SpinCtrl(self.SubrangePanel, style=wx.TAB_TRAVERSAL) Laurent@814: self.Bind(wx.EVT_SPINCTRL, self.OnSubrangeMaximumChanged, self.SubrangeMaximum) Edouard@1412: Edouard@1412: subrange_panel_sizer.AddWindow(self.SubrangeMaximum, 1, border=5, andrej@1768: flag=wx.GROW | wx.ALL) Edouard@1412: Laurent@814: self.SubrangePanel.SetSizer(subrange_panel_sizer) Edouard@1412: Laurent@814: # Panel for Enumerated data types Edouard@1412: Laurent@814: self.EnumeratedPanel = wx.Panel(self.Editor, style=wx.TAB_TRAVERSAL) Laurent@814: typeinfos_sizer.AddWindow(self.EnumeratedPanel, 1) Edouard@1412: Laurent@814: enumerated_panel_sizer = wx.BoxSizer(wx.HORIZONTAL) Edouard@1412: andrej@1768: self.EnumeratedValues = CustomEditableListBox( andrej@1768: self.EnumeratedPanel, andrej@1768: label=_("Values:"), andrej@1768: style=(wx.gizmos.EL_ALLOW_NEW | andrej@1768: wx.gizmos.EL_ALLOW_EDIT | andrej@1768: wx.gizmos.EL_ALLOW_DELETE)) Laurent@814: setattr(self.EnumeratedValues, "_OnLabelEndEdit", self.OnEnumeratedValueEndEdit) Laurent@814: for func in ["_OnAddButton", "_OnDelButton", "_OnUpButton", "_OnDownButton"]: Laurent@814: setattr(self.EnumeratedValues, func, self.OnEnumeratedValuesChanged) Edouard@1412: enumerated_panel_sizer.AddWindow(self.EnumeratedValues, 1, border=5, andrej@1768: flag=wx.GROW | wx.ALL) Edouard@1412: Laurent@814: enumerated_panel_rightsizer = wx.BoxSizer(wx.HORIZONTAL) Laurent@814: enumerated_panel_sizer.AddSizer(enumerated_panel_rightsizer, 1) Edouard@1412: Laurent@814: enumerated_initialvalue_label = wx.StaticText(self.EnumeratedPanel, andrej@1768: label=_('Initial Value:')) Edouard@1412: enumerated_panel_rightsizer.AddWindow(enumerated_initialvalue_label, 1, andrej@1768: border=5, andrej@1768: flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) Edouard@1412: Edouard@1412: self.EnumeratedInitialValue = wx.ComboBox(self.EnumeratedPanel, andrej@1768: style=wx.CB_READONLY) Laurent@814: self.Bind(wx.EVT_COMBOBOX, self.OnInfosChanged, self.EnumeratedInitialValue) Edouard@1412: enumerated_panel_rightsizer.AddWindow(self.EnumeratedInitialValue, 1, andrej@1768: border=5, flag=wx.ALL) Edouard@1412: Laurent@814: self.EnumeratedPanel.SetSizer(enumerated_panel_sizer) Edouard@1412: Laurent@814: # Panel for Array data types Laurent@814: Laurent@814: self.ArrayPanel = wx.Panel(self.Editor, style=wx.TAB_TRAVERSAL) Laurent@814: typeinfos_sizer.AddWindow(self.ArrayPanel, 1) Edouard@1412: Laurent@814: array_panel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=0) Laurent@814: array_panel_sizer.AddGrowableCol(0) Laurent@814: array_panel_sizer.AddGrowableCol(1) Laurent@814: array_panel_sizer.AddGrowableRow(1) Edouard@1412: Laurent@814: array_panel_leftSizer = wx.BoxSizer(wx.HORIZONTAL) Laurent@814: array_panel_sizer.AddSizer(array_panel_leftSizer, flag=wx.GROW) Edouard@1412: Laurent@814: array_basetype_label = wx.StaticText(self.ArrayPanel, label=_('Base Type:')) Edouard@1412: array_panel_leftSizer.AddWindow(array_basetype_label, 1, border=5, andrej@1768: flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) Edouard@1412: Laurent@814: self.ArrayBaseType = wx.ComboBox(self.ArrayPanel, style=wx.CB_READONLY) Laurent@814: self.Bind(wx.EVT_COMBOBOX, self.OnInfosChanged, self.ArrayBaseType) Edouard@1412: array_panel_leftSizer.AddWindow(self.ArrayBaseType, 1, border=5, andrej@1768: flag=wx.GROW | wx.ALL) Edouard@1412: Laurent@814: array_panel_rightsizer = wx.BoxSizer(wx.HORIZONTAL) Laurent@814: array_panel_sizer.AddSizer(array_panel_rightsizer, flag=wx.GROW) Edouard@1412: Laurent@814: array_initialvalue_label = wx.StaticText(self.ArrayPanel, andrej@1768: label=_('Initial Value:')) Edouard@1412: array_panel_rightsizer.AddWindow(array_initialvalue_label, 1, border=5, andrej@1768: flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) Edouard@1412: Laurent@814: self.ArrayInitialValue = wx.TextCtrl(self.ArrayPanel, andrej@1768: style=wx.TE_PROCESS_ENTER | wx.TE_RICH) Laurent@814: self.Bind(wx.EVT_TEXT_ENTER, self.OnReturnKeyPressed, self.ArrayInitialValue) Edouard@1412: array_panel_rightsizer.AddWindow(self.ArrayInitialValue, 1, border=5, andrej@1768: flag=wx.ALL) andrej@1768: andrej@1768: self.ArrayDimensions = CustomEditableListBox( andrej@1768: self.ArrayPanel, andrej@1768: label=_("Dimensions:"), andrej@1768: style=(wx.gizmos.EL_ALLOW_NEW | andrej@1768: wx.gizmos.EL_ALLOW_EDIT | andrej@1768: wx.gizmos.EL_ALLOW_DELETE)) Edouard@1412: for func in ["_OnLabelEndEdit", "_OnAddButton", "_OnDelButton", Laurent@814: "_OnUpButton", "_OnDownButton"]: Laurent@814: setattr(self.ArrayDimensions, func, self.OnDimensionsChanged) Edouard@1412: array_panel_sizer.AddWindow(self.ArrayDimensions, 0, border=5, andrej@1768: flag=wx.GROW | wx.ALL) Edouard@1412: Laurent@814: self.ArrayPanel.SetSizer(array_panel_sizer) Edouard@1412: Laurent@814: # Panel for Structure data types Edouard@1412: Laurent@814: self.StructurePanel = wx.Panel(self.Editor, style=wx.TAB_TRAVERSAL) Laurent@814: typeinfos_sizer.AddWindow(self.StructurePanel, 1) Edouard@1412: Laurent@814: structure_panel_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) Laurent@814: structure_panel_sizer.AddGrowableCol(0) Laurent@814: structure_panel_sizer.AddGrowableRow(1) Edouard@1412: Laurent@814: structure_button_sizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0) Laurent@814: structure_button_sizer.AddGrowableCol(0) Laurent@814: structure_button_sizer.AddGrowableRow(0) Edouard@1412: structure_panel_sizer.AddSizer(structure_button_sizer, 0, border=5, andrej@1768: flag=wx.ALL | wx.GROW) Edouard@1412: Laurent@814: structure_elements_label = wx.StaticText(self.StructurePanel, andrej@1768: label=_('Elements :')) Laurent@814: structure_button_sizer.AddWindow(structure_elements_label, flag=wx.ALIGN_BOTTOM) Edouard@1412: Laurent@814: for name, bitmap, help in [ Laurent@814: ("StructureAddButton", "add_element", _("Add element")), Laurent@814: ("StructureDeleteButton", "remove_element", _("Remove element")), Laurent@814: ("StructureUpButton", "up", _("Move element up")), Laurent@814: ("StructureDownButton", "down", _("Move element down"))]: Laurent@814: button = wx.lib.buttons.GenBitmapButton(self.StructurePanel, andrej@1768: bitmap=GetBitmap(bitmap), andrej@1768: size=wx.Size(28, 28), andrej@1768: style=wx.NO_BORDER) Laurent@814: button.SetToolTipString(help) Laurent@814: setattr(self, name, button) Laurent@814: structure_button_sizer.AddWindow(button) Edouard@1412: Edouard@1412: self.StructureElementsGrid = CustomGrid(self.StructurePanel, andrej@1768: size=wx.Size(0, 150), style=wx.VSCROLL) Edouard@1412: self.StructureElementsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, andrej@1768: self.OnStructureElementsGridCellChange) Edouard@1412: self.StructureElementsGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, andrej@1768: self.OnStructureElementsGridEditorShown) Laurent@814: structure_panel_sizer.AddWindow(self.StructureElementsGrid, flag=wx.GROW) Edouard@1412: Laurent@814: self.StructurePanel.SetSizer(structure_panel_sizer) Edouard@1412: Laurent@814: self.Editor.SetSizer(self.MainSizer) Edouard@1412: Laurent@814: def __init__(self, parent, tagname, window, controler): Laurent@814: EditorPanel.__init__(self, parent, tagname, window, controler) Edouard@1412: andrej@1739: self.StructureElementDefaultValue = {"Name": "", "Type": DefaultType, "Initial Value": ""} Laurent@814: self.StructureElementsTable = ElementsTable(self, [], GetElementsTableColnames()) Laurent@814: self.StructureColSizes = [40, 150, 100, 250] Laurent@814: self.StructureColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT] Edouard@1412: Laurent@814: self.StructureElementsGrid.SetTable(self.StructureElementsTable) Laurent@814: self.StructureElementsGrid.SetButtons({"Add": self.StructureAddButton, Laurent@814: "Delete": self.StructureDeleteButton, Laurent@814: "Up": self.StructureUpButton, Laurent@814: "Down": self.StructureDownButton}) Edouard@1412: Laurent@814: def _AddStructureElement(new_row): Laurent@814: self.StructureElementsTable.InsertRow(new_row, self.StructureElementDefaultValue.copy()) Laurent@814: self.RefreshTypeInfos() Laurent@814: self.StructureElementsTable.ResetView(self.StructureElementsGrid) Laurent@814: return new_row Laurent@814: setattr(self.StructureElementsGrid, "_AddRow", _AddStructureElement) Edouard@1412: Laurent@814: def _DeleteStructureElement(row): Laurent@814: self.StructureElementsTable.RemoveRow(row) Laurent@814: self.RefreshTypeInfos() Laurent@814: self.StructureElementsTable.ResetView(self.StructureElementsGrid) Laurent@814: setattr(self.StructureElementsGrid, "_DeleteRow", _DeleteStructureElement) Edouard@1412: Laurent@814: def _MoveStructureElement(row, move): Laurent@814: new_row = self.StructureElementsTable.MoveRow(row, move) Laurent@814: if new_row != row: Laurent@814: self.RefreshTypeInfos() Laurent@814: self.StructureElementsTable.ResetView(self.StructureElementsGrid) Laurent@814: return new_row Laurent@814: setattr(self.StructureElementsGrid, "_MoveRow", _MoveStructureElement) Edouard@1412: Laurent@814: self.StructureElementsGrid.SetRowLabelSize(0) Laurent@814: for col in range(self.StructureElementsTable.GetNumberCols()): Laurent@814: attr = wx.grid.GridCellAttr() Laurent@814: attr.SetAlignment(self.StructureColAlignements[col], wx.ALIGN_CENTRE) Laurent@814: self.StructureElementsGrid.SetColAttr(col, attr) Laurent@814: self.StructureElementsGrid.SetColMinimalWidth(col, self.StructureColSizes[col]) Laurent@814: self.StructureElementsGrid.AutoSizeColumn(col, False) Laurent@814: self.StructureElementsGrid.RefreshButtons() Edouard@1412: Laurent@814: for datatype in GetDatatypeTypes(): Laurent@814: self.DerivationType.Append(_(datatype)) Laurent@814: self.SubrangePanel.Hide() Laurent@814: self.EnumeratedPanel.Hide() Laurent@814: self.ArrayPanel.Hide() Laurent@814: self.StructurePanel.Hide() Laurent@814: self.CurrentPanel = "Directly" Laurent@814: self.Highlights = [] Laurent@814: self.Initializing = False Edouard@1412: Laurent@814: self.HighlightControls = { Laurent@814: ("Directly", "base"): self.DirectlyBaseType, Laurent@814: ("Directly", "initial"): self.DirectlyInitialValue, Laurent@814: ("Subrange", "base"): self.SubrangeBaseType, Laurent@814: ("Subrange", "lower"): self.SubrangeMinimum, Laurent@814: ("Subrange", "upper"): self.SubrangeMaximum, Laurent@814: ("Subrange", "initial"): self.SubrangeInitialValue, Laurent@814: ("Enumerated", "value"): self.EnumeratedValues, Laurent@814: ("Enumerated", "initial"): self.EnumeratedInitialValue, Laurent@814: ("Array", "initial"): self.ArrayInitialValue, Laurent@814: ("Array", "base"): self.ArrayBaseType, Laurent@814: ("Array", "range"): self.ArrayDimensions, Laurent@814: } Edouard@1412: Laurent@814: self.RefreshHighlightsTimer = wx.Timer(self, -1) Laurent@814: self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer) Edouard@1412: Laurent@814: def __del__(self): Laurent@814: self.RefreshHighlightsTimer.Stop() Edouard@1412: Laurent@814: def GetBufferState(self): Laurent@814: return self.Controler.GetBufferState() Edouard@1412: Laurent@814: def Undo(self): Laurent@814: self.Controler.LoadPrevious() Laurent@814: self.ParentWindow.CloseTabsWithoutModel() Edouard@1412: Laurent@814: def Redo(self): Laurent@814: self.Controler.LoadNext() Laurent@814: self.ParentWindow.CloseTabsWithoutModel() Edouard@1412: Laurent@814: def HasNoModel(self): Laurent@814: return self.Controler.GetEditedElement(self.TagName) is None Edouard@1412: Laurent@814: def RefreshView(self): Laurent@814: self.Initializing = True Laurent@814: self.DirectlyBaseType.Clear() Laurent@814: self.ArrayBaseType.Clear() Laurent@814: for datatype in self.Controler.GetDataTypes(self.TagName): Laurent@814: self.DirectlyBaseType.Append(datatype) Laurent@814: self.ArrayBaseType.Append(datatype) Laurent@814: self.DirectlyBaseType.SetSelection(0) Laurent@814: self.SubrangeBaseType.Clear() Laurent@814: words = self.TagName.split("::") Laurent@814: for base_type in self.Controler.GetSubrangeBaseTypes(words[1]): Laurent@814: self.SubrangeBaseType.Append(base_type) Laurent@814: self.SubrangeBaseType.SetSelection(0) Laurent@814: self.RefreshBoundsRange() Laurent@814: type_infos = self.Controler.GetDataTypeInfos(self.TagName) Laurent@814: if type_infos is not None: Laurent@814: datatype = type_infos["type"] Laurent@814: self.DerivationType.SetStringSelection(_(datatype)) Laurent@814: if type_infos["type"] == "Directly": Laurent@814: self.DirectlyBaseType.SetStringSelection(type_infos["base_type"]) Laurent@814: self.DirectlyInitialValue.SetValue(type_infos["initial"]) Laurent@814: elif type_infos["type"] == "Subrange": Laurent@814: self.SubrangeBaseType.SetStringSelection(type_infos["base_type"]) Laurent@814: self.RefreshBoundsRange() Laurent@814: self.SubrangeMinimum.SetValue(int(type_infos["min"])) Laurent@814: self.SubrangeMaximum.SetValue(int(type_infos["max"])) Laurent@814: self.RefreshSubrangeInitialValueRange() Laurent@814: if type_infos["initial"] != "": Laurent@814: self.SubrangeInitialValue.SetValue(int(type_infos["initial"])) Laurent@814: else: Laurent@814: self.SubrangeInitialValue.SetValue(type_infos["min"]) Laurent@814: elif type_infos["type"] == "Enumerated": Laurent@814: self.EnumeratedValues.SetStrings(type_infos["values"]) Laurent@814: self.RefreshEnumeratedValues() Laurent@814: self.EnumeratedInitialValue.SetStringSelection(type_infos["initial"]) Laurent@814: elif type_infos["type"] == "Array": Laurent@814: self.ArrayBaseType.SetStringSelection(type_infos["base_type"]) andrej@1739: self.ArrayDimensions.SetStrings(map(lambda x: "..".join(x), type_infos["dimensions"])) Laurent@814: self.ArrayInitialValue.SetValue(type_infos["initial"]) Laurent@814: elif type_infos["type"] == "Structure": Laurent@814: self.StructureElementsTable.SetData(type_infos["elements"]) Laurent@814: self.RefreshDisplayedInfos() Laurent@814: self.ShowHighlights() Laurent@814: self.StructureElementsTable.ResetView(self.StructureElementsGrid) Laurent@814: self.StructureElementsGrid.RefreshButtons() Laurent@814: self.Initializing = False Edouard@1412: Laurent@814: def OnDerivationTypeChanged(self, event): Laurent@814: wx.CallAfter(self.RefreshDisplayedInfos) Laurent@814: wx.CallAfter(self.RefreshTypeInfos) Laurent@814: event.Skip() Laurent@814: Laurent@814: def OnReturnKeyPressed(self, event): Laurent@814: self.RefreshTypeInfos() Edouard@1412: Laurent@814: def OnInfosChanged(self, event): Laurent@814: self.RefreshTypeInfos() Laurent@814: event.Skip() Laurent@814: Laurent@814: def OnSubrangeBaseTypeChanged(self, event): Laurent@814: self.RefreshBoundsRange() Laurent@814: self.RefreshTypeInfos() Laurent@814: event.Skip() Laurent@814: Laurent@814: def OnSubrangeMinimumChanged(self, event): Laurent@814: if not self.Initializing: Laurent@814: wx.CallAfter(self.SubrangeMinimum.SetValue, min(self.SubrangeMaximum.GetValue(), self.SubrangeMinimum.GetValue())) Laurent@814: wx.CallAfter(self.RefreshSubrangeInitialValueRange) Laurent@814: wx.CallAfter(self.RefreshTypeInfos) Laurent@814: event.Skip() Laurent@814: Laurent@814: def OnSubrangeMaximumChanged(self, event): Laurent@814: if not self.Initializing: Laurent@814: wx.CallAfter(self.SubrangeMaximum.SetValue, max(self.SubrangeMinimum.GetValue(), self.SubrangeMaximum.GetValue())) Laurent@814: wx.CallAfter(self.RefreshSubrangeInitialValueRange) Laurent@814: wx.CallAfter(self.RefreshTypeInfos) Laurent@814: event.Skip() Laurent@814: Laurent@814: def OnDimensionsChanged(self, event): Laurent@814: wx.CallAfter(self.RefreshTypeInfos) Laurent@814: event.Skip() Laurent@814: Laurent@814: def OnEnumeratedValueEndEdit(self, event): Laurent@814: text = event.GetText() Laurent@814: values = self.EnumeratedValues.GetStrings() Laurent@814: index = event.GetIndex() Laurent@814: if index >= len(values) or values[index].upper() != text.upper(): Laurent@814: if text.upper() in [value.upper() for value in values]: andrej@1745: message = wx.MessageDialog(self, _("\"%s\" value already defined!") % text, _("Error"), wx.OK | wx.ICON_ERROR) Laurent@814: message.ShowModal() Laurent@814: message.Destroy() Laurent@814: event.Veto() Laurent@814: elif text.upper() in IEC_KEYWORDS: andrej@1745: message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!") % text, _("Error"), wx.OK | wx.ICON_ERROR) Laurent@814: message.ShowModal() Laurent@814: message.Destroy() Laurent@814: else: Laurent@814: initial_selected = None Laurent@814: if index < len(values) and self.EnumeratedInitialValue.GetStringSelection() == values[index]: Laurent@814: initial_selected = text Laurent@814: wx.CallAfter(self.RefreshEnumeratedValues, initial_selected) Laurent@814: wx.CallAfter(self.RefreshTypeInfos) Laurent@814: event.Skip() Laurent@814: else: Laurent@814: event.Skip() Edouard@1412: Laurent@814: def OnEnumeratedValuesChanged(self, event): Laurent@814: wx.CallAfter(self.RefreshEnumeratedValues) Laurent@814: wx.CallAfter(self.RefreshTypeInfos) Laurent@814: event.Skip() Edouard@1412: andrej@1658: def ShowErrorMessage(self, message): andrej@1745: dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR) andrej@1658: dialog.ShowModal() andrej@1658: dialog.Destroy() andrej@1735: Laurent@814: def OnStructureElementsGridCellChange(self, event): Laurent@814: row, col = event.GetRow(), event.GetCol() Laurent@947: colname = self.StructureElementsTable.GetColLabelValue(col, False) Laurent@814: value = self.StructureElementsTable.GetValue(row, col) Laurent@814: if colname == "Name": andrej@1658: message = None Laurent@814: if not TestIdentifier(value): andrej@1734: message = _("\"%s\" is not a valid identifier!") % value Laurent@814: elif value.upper() in IEC_KEYWORDS: andrej@1734: message = _("\"%s\" is a keyword. It can't be used!") % value andrej@1753: # elif value.upper() in self.PouNames: andrej@1753: # message = _("A pou with \"%s\" as name exists!")%value Laurent@814: elif value.upper() in [var["Name"].upper() for idx, var in enumerate(self.StructureElementsTable.GetData()) if idx != row]: andrej@1734: message = _("An element named \"%s\" already exists in this structure!") % value Laurent@814: else: Laurent@814: self.RefreshTypeInfos() Laurent@814: wx.CallAfter(self.StructureElementsTable.ResetView, self.StructureElementsGrid) andrej@1753: # old_value = self.Table.GetOldValue() andrej@1753: # if old_value != "": andrej@1753: # self.Controler.UpdateEditedElementUsedVariable(self.TagName, old_value, value) andrej@1753: # self.Controler.BufferProject() Laurent@814: event.Skip() andrej@1658: andrej@1658: if message is not None: andrej@1658: event.Veto() andrej@1658: wx.CallAfter(self.ShowErrorMessage, message) Laurent@814: else: Laurent@814: self.RefreshTypeInfos() Laurent@814: wx.CallAfter(self.StructureElementsTable.ResetView, self.StructureElementsGrid) Laurent@814: event.Skip() Edouard@1412: Laurent@814: def OnStructureElementsGridSelectCell(self, event): Laurent@814: wx.CallAfter(self.RefreshStructureButtons) Laurent@814: event.Skip() Edouard@1412: Laurent@814: def OnStructureElementsGridEditorShown(self, event): Edouard@1412: row, col = event.GetRow(), event.GetCol() Laurent@947: if self.StructureElementsTable.GetColLabelValue(col, False) == "Type": Laurent@814: type_menu = wx.Menu(title='') Edouard@1412: Laurent@814: base_menu = wx.Menu(title='') Laurent@814: for base_type in self.Controler.GetBaseTypes(): Laurent@814: new_id = wx.NewId() Laurent@814: AppendMenu(base_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=base_type) Laurent@814: self.Bind(wx.EVT_MENU, self.GetElementTypeFunction(base_type), id=new_id) Laurent@814: type_menu.AppendMenu(wx.NewId(), _("Base Types"), base_menu) Edouard@1412: Laurent@814: datatype_menu = wx.Menu(title='') Laurent@814: for datatype in self.Controler.GetDataTypes(self.TagName, False): Laurent@814: new_id = wx.NewId() Laurent@814: AppendMenu(datatype_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype) Laurent@814: self.Bind(wx.EVT_MENU, self.GetElementTypeFunction(datatype), id=new_id) Laurent@814: type_menu.AppendMenu(wx.NewId(), _("User Data Types"), datatype_menu) Edouard@1412: Laurent@864: new_id = wx.NewId() Laurent@864: AppendMenu(type_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Array")) Laurent@864: self.Bind(wx.EVT_MENU, self.ElementArrayTypeFunction, id=new_id) Edouard@1412: andrej@1753: # functionblock_menu = wx.Menu(title='') andrej@1753: # bodytype = self.Controler.GetEditedElementBodyType(self.TagName) andrej@1753: # pouname, poutype = self.Controler.GetEditedElementType(self.TagName) andrej@1753: # if classtype in ["Input","Output","InOut","External","Global"] or poutype != "function" and bodytype in ["ST", "IL"]: andrej@1753: # for functionblock_type in self.Controler.GetFunctionBlockTypes(self.TagName): andrej@1753: # new_id = wx.NewId() andrej@1753: # AppendMenu(functionblock_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=functionblock_type) andrej@1753: # self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(functionblock_type), id=new_id) andrej@1753: # type_menu.AppendMenu(wx.NewId(), _("Function Block Types"), functionblock_menu) Laurent@864: Laurent@814: rect = self.StructureElementsGrid.BlockToDeviceRect((row, col), (row, col)) Laurent@814: self.StructureElementsGrid.PopupMenuXY(type_menu, rect.x + rect.width, rect.y + self.StructureElementsGrid.GetColLabelSize()) Laurent@814: type_menu.Destroy() Laurent@814: event.Veto() Laurent@814: else: Laurent@814: event.Skip() Laurent@814: Laurent@814: def GetElementTypeFunction(self, base_type): Laurent@814: def ElementTypeFunction(event): Laurent@814: row = self.StructureElementsGrid.GetGridCursorRow() Laurent@814: self.StructureElementsTable.SetValueByName(row, "Type", base_type) Laurent@814: self.RefreshTypeInfos() Laurent@814: self.StructureElementsTable.ResetView(self.StructureElementsGrid) Laurent@814: return ElementTypeFunction Laurent@814: Laurent@864: def ElementArrayTypeFunction(self, event): Laurent@864: row = self.StructureElementsGrid.GetGridCursorRow() Edouard@1412: dialog = ArrayTypeDialog(self, Edouard@1412: self.Controler.GetDataTypes(self.TagName), Laurent@864: self.StructureElementsTable.GetValueByName(row, "Type")) Laurent@864: if dialog.ShowModal() == wx.ID_OK: Laurent@864: self.StructureElementsTable.SetValueByName(row, "Type", dialog.GetValue()) Laurent@864: self.RefreshTypeInfos() Laurent@864: self.StructureElementsTable.ResetView(self.StructureElementsGrid) Laurent@864: dialog.Destroy() Laurent@864: Laurent@814: def RefreshDisplayedInfos(self): Laurent@814: selected = DATATYPE_TYPES_DICT[self.DerivationType.GetStringSelection()] Laurent@814: if selected != self.CurrentPanel: Laurent@814: if self.CurrentPanel == "Directly": Laurent@814: self.DirectlyPanel.Hide() Laurent@814: elif self.CurrentPanel == "Subrange": Laurent@814: self.SubrangePanel.Hide() Laurent@814: elif self.CurrentPanel == "Enumerated": Laurent@814: self.EnumeratedPanel.Hide() Laurent@814: elif self.CurrentPanel == "Array": Laurent@814: self.ArrayPanel.Hide() Laurent@814: elif self.CurrentPanel == "Structure": Laurent@814: self.StructurePanel.Hide() Laurent@814: self.CurrentPanel = selected Laurent@814: if selected == "Directly": Laurent@814: self.DirectlyPanel.Show() Laurent@814: elif selected == "Subrange": Laurent@814: self.SubrangePanel.Show() Laurent@814: elif selected == "Enumerated": Laurent@814: self.EnumeratedPanel.Show() Laurent@814: elif selected == "Array": Laurent@814: self.ArrayPanel.Show() Laurent@814: elif selected == "Structure": Laurent@814: self.StructurePanel.Show() Laurent@814: self.MainSizer.Layout() Laurent@814: Laurent@814: def RefreshEnumeratedValues(self, initial_selected=None): Laurent@814: if initial_selected is None: Laurent@814: initial_selected = self.EnumeratedInitialValue.GetStringSelection() Laurent@814: self.EnumeratedInitialValue.Clear() Laurent@814: self.EnumeratedInitialValue.Append("") Laurent@814: for value in self.EnumeratedValues.GetStrings(): Laurent@814: self.EnumeratedInitialValue.Append(value) Laurent@814: self.EnumeratedInitialValue.SetStringSelection(initial_selected) Laurent@814: Laurent@814: def RefreshBoundsRange(self): Laurent@814: range = self.Controler.GetDataTypeRange(self.SubrangeBaseType.GetStringSelection()) Laurent@814: if range is not None: Laurent@814: min_value, max_value = range Laurent@814: self.SubrangeMinimum.SetRange(min_value, max_value) Laurent@814: self.SubrangeMinimum.SetValue(min(max(min_value, self.SubrangeMinimum.GetValue()), max_value)) Laurent@814: self.SubrangeMaximum.SetRange(min_value, max_value) Laurent@814: self.SubrangeMaximum.SetValue(min(max(min_value, self.SubrangeMaximum.GetValue()), max_value)) Laurent@814: Laurent@814: def RefreshSubrangeInitialValueRange(self): Laurent@814: self.SubrangeInitialValue.SetRange(self.SubrangeMinimum.GetValue(), self.SubrangeMaximum.GetValue()) Laurent@814: Laurent@814: def RefreshTypeInfos(self): Laurent@814: selected = DATATYPE_TYPES_DICT[self.DerivationType.GetStringSelection()] andrej@1739: infos = {"type": selected} Laurent@814: if selected == "Directly": Laurent@814: infos["base_type"] = self.DirectlyBaseType.GetStringSelection() Laurent@814: infos["initial"] = self.DirectlyInitialValue.GetValue() Laurent@814: elif selected == "Subrange": Laurent@814: infos["base_type"] = self.SubrangeBaseType.GetStringSelection() Laurent@814: infos["min"] = str(self.SubrangeMinimum.GetValue()) Laurent@814: infos["max"] = str(self.SubrangeMaximum.GetValue()) Laurent@814: initial_value = self.SubrangeInitialValue.GetValue() Laurent@814: if initial_value == infos["min"]: Laurent@814: infos["initial"] = "" Laurent@814: else: Laurent@814: infos["initial"] = str(initial_value) Laurent@814: elif selected == "Enumerated": Laurent@814: infos["values"] = self.EnumeratedValues.GetStrings() Laurent@814: infos["initial"] = self.EnumeratedInitialValue.GetStringSelection() Laurent@814: elif selected == "Array": Laurent@814: infos["base_type"] = self.ArrayBaseType.GetStringSelection() Laurent@814: infos["dimensions"] = [] Laurent@814: for dimensions in self.ArrayDimensions.GetStrings(): Laurent@814: result = DIMENSION_MODEL.match(dimensions) Laurent@814: if result is None: andrej@1745: message = wx.MessageDialog(self, _("\"%s\" value isn't a valid array dimension!") % dimensions, _("Error"), wx.OK | wx.ICON_ERROR) Laurent@814: message.ShowModal() Laurent@814: message.Destroy() Laurent@814: self.RefreshView() Laurent@814: return Laurent@814: bounds = result.groups() Laurent@814: if int(bounds[0]) >= int(bounds[1]): andrej@1745: message = wx.MessageDialog(self, _("\"%s\" value isn't a valid array dimension!\nRight value must be greater than left value.") % dimensions, _("Error"), wx.OK | wx.ICON_ERROR) Laurent@814: message.ShowModal() Laurent@814: message.Destroy() Laurent@814: self.RefreshView() Laurent@814: return Laurent@814: infos["dimensions"].append(bounds) Laurent@814: infos["initial"] = self.ArrayInitialValue.GetValue() Laurent@814: elif selected == "Structure": Laurent@814: infos["elements"] = self.StructureElementsTable.GetData() Laurent@814: infos["initial"] = "" Laurent@814: self.Controler.SetDataTypeInfos(self.TagName, infos) Laurent@814: self.ParentWindow.RefreshTitle() Laurent@814: self.ParentWindow.RefreshFileMenu() Laurent@814: self.ParentWindow.RefreshEditMenu() Laurent@814: andrej@1782: # ------------------------------------------------------------------------------- andrej@1782: # Highlights showing functions andrej@1782: # ------------------------------------------------------------------------------- Laurent@814: Laurent@814: def OnRefreshHighlightsTimer(self, event): Laurent@814: self.RefreshView() Laurent@814: event.Skip() Laurent@814: Laurent@814: def ClearHighlights(self, highlight_type=None): Laurent@814: if highlight_type is None: Laurent@814: self.Highlights = [] Laurent@814: else: Laurent@814: self.Highlights = [(infos, start, end, highlight) for (infos, start, end, highlight) in self.Highlights if highlight != highlight_type] Laurent@814: for control in self.HighlightControls.itervalues(): Laurent@814: if isinstance(control, (wx.ComboBox, wx.SpinCtrl)): Laurent@814: control.SetBackgroundColour(wx.NullColour) Laurent@814: control.SetForegroundColour(wx.NullColour) Laurent@814: elif isinstance(control, wx.TextCtrl): Laurent@814: value = control.GetValue() Laurent@814: control.SetStyle(0, len(value), wx.TextAttr(wx.NullColour)) Laurent@814: elif isinstance(control, wx.gizmos.EditableListBox): Laurent@814: listctrl = control.GetListCtrl() Laurent@814: for i in xrange(listctrl.GetItemCount()): Laurent@814: listctrl.SetItemBackgroundColour(i, wx.NullColour) Laurent@814: listctrl.SetItemTextColour(i, wx.NullColour) Laurent@814: self.StructureElementsTable.ClearHighlights(highlight_type) Laurent@814: self.RefreshView() Laurent@814: andrej@1739: def AddHighlight(self, infos, start, end, highlight_type): Laurent@814: self.Highlights.append((infos, start, end, highlight_type)) Laurent@814: self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True) Laurent@814: Laurent@814: def ShowHighlights(self): Laurent@814: type_infos = self.Controler.GetDataTypeInfos(self.TagName) Laurent@814: for infos, start, end, highlight_type in self.Highlights: Laurent@814: if infos[0] == "struct": Laurent@814: self.StructureElementsTable.AddHighlight(infos[1:], highlight_type) Laurent@814: else: Laurent@814: control = self.HighlightControls.get((type_infos["type"], infos[0]), None) Laurent@814: if control is not None: Laurent@814: if isinstance(control, (wx.ComboBox, wx.SpinCtrl)): Laurent@814: control.SetBackgroundColour(highlight_type[0]) Laurent@814: control.SetForegroundColour(highlight_type[1]) Laurent@814: elif isinstance(control, wx.TextCtrl): Laurent@814: control.SetStyle(start[1], end[1] + 1, wx.TextAttr(highlight_type[1], highlight_type[0])) Laurent@814: elif isinstance(control, wx.gizmos.EditableListBox): Laurent@814: listctrl = control.GetListCtrl() Laurent@814: listctrl.SetItemBackgroundColour(infos[1], highlight_type[0]) Laurent@814: listctrl.SetItemTextColour(infos[1], highlight_type[1]) Laurent@814: listctrl.Select(listctrl.FocusedItem, False)