# HG changeset patch # User Edouard Tisserant # Date 1658091215 -7200 # Node ID f5850ce25cafa95272b7b567d81811ca13ec736b # Parent ffe4e46a31631c7594292070b93aa13f1c1c6b49# Parent 59158e360b8c1335c6eb4f6539cc9d9f103dc299 Merge from default branch + fix traffic light example SVG missing background + update generated XSLT diff -r 59158e360b8c -r f5850ce25caf .github/workflows/run_tests_in_docker.yml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.github/workflows/run_tests_in_docker.yml Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,68 @@ +name: Docker Image CI + +on: + push: + branches: [ wxPython4 ] + +jobs: + + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + path: beremiz + + - uses: actions/checkout@v3 + with: + repository: beremiz/matiec + ref: 2a25f4dbf4e2b1e017a3a583db7dede4771fe523 + path: matiec + + - uses: actions/checkout@v3 + with: + repository: open62541/open62541 + ref: v3.0.2 + path: open62541 + submodules: recursive + + - name: Cache docker image + id: cache-docker + uses: actions/cache@v3 + env: + cache-name: cache-docker + with: + path: /tmp/latest.tar + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('beremiz/tests/tools/Docker/beremiz-sikuli') }} + + - if: ${{ steps.cache-docker.outputs.cache-hit == false }} + name: Create docker image + run: | + cd beremiz/tests/tools/Docker/beremiz-sikuli + ./build_docker_image.sh + docker image save --output="/tmp/latest.tar" beremiz_sikuli + + - if: ${{ steps.cache-docker.outputs.cache-hit != false }} + name: Re-use docker image + run: | + docker image load --input="/tmp/latest.tar" + + - name: Create docker container + run: | + cd beremiz/tests/tools/Docker/beremiz-sikuli + ./create_docker_container.sh ${{ github.workspace }}/test + + - name: Run tests in docker + run: | + cd beremiz/tests/tools/Docker/beremiz-sikuli + ./do_test_in_docker.sh + + - name: Upload test resuts artifact + uses: actions/upload-artifact@v3 + if: failure() + with: + name: test_results + path: ${{ github.workspace }}/test + retention-days: 5 diff -r 59158e360b8c -r f5850ce25caf .hgignore --- a/.hgignore Thu Jul 14 11:40:27 2022 +0200 +++ b/.hgignore Sun Jul 17 22:53:35 2022 +0200 @@ -24,3 +24,5 @@ doc/_build doc/locale + +^.*\$py.class$ diff -r 59158e360b8c -r f5850ce25caf Beremiz.py --- a/Beremiz.py Thu Jul 14 11:40:27 2022 +0200 +++ b/Beremiz.py Sun Jul 17 22:53:35 2022 +0200 @@ -50,6 +50,7 @@ self.modules = ["BeremizIDE"] self.debug = os.path.exists("BEREMIZ_DEBUG") self.handle_exception = None + self.logf = None def Bpath(self, *args): return os.path.join(self.app_dir, *args) @@ -62,12 +63,13 @@ print("-h --help Print this help") print("-u --updatecheck URL Retrieve update information by checking URL") print("-e --extend PathToExtension Extend IDE functionality by loading at start additional extensions") + print("-l --log path write content of console tab to given file") print("") print("") def SetCmdOptions(self): - self.shortCmdOpts = "hu:e:" - self.longCmdOpts = ["help", "updatecheck=", "extend="] + self.shortCmdOpts = "hu:e:l:" + self.longCmdOpts = ["help", "updatecheck=", "extend=", "log="] def ProcessOption(self, o, a): if o in ("-h", "--help"): @@ -77,6 +79,8 @@ self.updateinfo_url = a if o in ("-e", "--extend"): self.extensions.append(a) + if o in ("-l", "--log"): + self.logf = open(a, 'a') def ProcessCommandLineArgs(self): self.SetCmdOptions() @@ -182,10 +186,10 @@ def InstallExceptionHandler(self): import version import util.ExceptionHandler - self.handle_exception = util.ExceptionHandler.AddExceptHook(version.app_version) + self.handle_exception = util.ExceptionHandler.AddExceptHook(version.app_version, logf=self.logf) def CreateUI(self): - self.frame = self.BeremizIDE.Beremiz(None, self.projectOpen, self.buildpath) + self.frame = self.BeremizIDE.Beremiz(None, self.projectOpen, self.buildpath, logf=self.logf) def CloseSplash(self): if self.splash: diff -r 59158e360b8c -r f5850ce25caf BeremizIDE.py --- a/BeremizIDE.py Thu Jul 14 11:40:27 2022 +0200 +++ b/BeremizIDE.py Sun Jul 17 22:53:35 2022 +0200 @@ -28,9 +28,7 @@ from __future__ import print_function import os import sys -import tempfile import shutil -import random import time from time import time as gettime from threading import Lock, Timer, currentThread @@ -47,9 +45,8 @@ from editors.TextViewer import TextViewer from editors.ResourceEditor import ConfigurationEditor, ResourceEditor from editors.DataTypeEditor import DataTypeEditor -from util import paths as paths +from util.paths import Bpath from util.MiniTextControler import MiniTextControler -from util.ProcessLogger import ProcessLogger from util.BitmapLibrary import GetBitmap from controls.LogViewer import LogViewer from controls.CustomStyledTextCtrl import CustomStyledTextCtrl @@ -84,15 +81,11 @@ EncodeFileSystemPath, \ DecodeFileSystemPath - -beremiz_dir = paths.AbsDir(__file__) - - -def Bpath(*args): - return os.path.join(beremiz_dir, *args) +from LocalRuntimeMixin import LocalRuntimeMixin + def AppendMenu(parent, help, id, kind, text): - return parent.Append(help=help, id=id, kind=kind, text=text) + return parent.Append(wx.MenuItem(helpString=help, id=id, kind=kind, text=text)) MAX_RECENT_PROJECTS = 9 @@ -115,7 +108,7 @@ class LogPseudoFile(object): """ Base class for file like objects to facilitate StdOut for the Shell.""" - def __init__(self, output, risecall): + def __init__(self, output, risecall, logf): self.red_white = 1 self.red_yellow = 2 self.black_white = wx.stc.STC_STYLE_DEFAULT @@ -131,8 +124,12 @@ self.LastRefreshTime = gettime() self.LastRefreshTimer = None self.refreshPending = False + self.logf = logf def write(self, s, style=None): + if self.logf is not None: + self.logf.write(s) + self.logf.flush() self.StackLock.acquire() self.stack.append((s, style)) self.StackLock.release() @@ -179,7 +176,7 @@ if style is None: style = self.black_white if style != self.black_white: - self.output.StartStyling(self.output.GetLength(), 0xff) + self.output.StartStyling(self.output.GetLength()) # Temporary deactivate read only mode on StyledTextCtrl for # adding text. It seems that text modifications, even @@ -236,7 +233,7 @@ ID_FILEMENURECENTPROJECTS = wx.NewId() -class Beremiz(IDEFrame): +class Beremiz(IDEFrame, LocalRuntimeMixin): def _init_utils(self): self.ConfNodeMenu = wx.Menu(title='') @@ -250,9 +247,9 @@ kind=wx.ITEM_NORMAL, text=_(u'New') + '\tCTRL+N') AppendMenu(parent, help='', id=wx.ID_OPEN, kind=wx.ITEM_NORMAL, text=_(u'Open') + '\tCTRL+O') - parent.AppendMenu(ID_FILEMENURECENTPROJECTS, _("&Recent Projects"), self.RecentProjectsMenu) + parent.Append(ID_FILEMENURECENTPROJECTS, _("&Recent Projects"), self.RecentProjectsMenu) parent.AppendSeparator() - parent.AppendMenu(wx.ID_ANY, _("&Tutorials and Examples"), self.TutorialsProjectsMenu) + parent.Append(wx.ID_ANY, _("&Tutorials and Examples"), self.TutorialsProjectsMenu) exemples_dir = Bpath("exemples") project_list = sorted(os.listdir(exemples_dir)) @@ -314,10 +311,10 @@ for name, text, helpstr, children in items: if len(children) > 0: new_menu = wx.Menu(title='') - menu.AppendMenu(wx.ID_ANY, text, new_menu) + menu.AppendSubMenu(new_menu, text) self._RecursiveAddMenuItems(new_menu, children) else: - item = menu.Append(wx.ID_ANY, text, helpstr) + item = menu.Append(wx.MenuItem(text=text, helpString=helpstr, kind=wx.ITEM_NORMAL, id=wx.ID_ANY)) self.Bind(wx.EVT_MENU, self.GetAddConfNodeFunction(name), item) def _init_coll_AddMenu_Items(self, parent): @@ -334,16 +331,16 @@ item = parent.Append(wx.ID_ANY, _(u'Community support'), '') self.Bind(wx.EVT_MENU, handler, item) - parent.Append(help='', id=wx.ID_ABOUT, - kind=wx.ITEM_NORMAL, text=_(u'About')) + parent.Append(wx.MenuItem(helpString='', id=wx.ID_ABOUT, + kind=wx.ITEM_NORMAL, text=_(u'About'))) self.Bind(wx.EVT_MENU, self.OnAboutMenu, id=wx.ID_ABOUT) def _init_coll_ConnectionStatusBar_Fields(self, parent): parent.SetFieldsCount(3) - parent.SetStatusText(number=0, text='') - parent.SetStatusText(number=1, text='') - parent.SetStatusText(number=2, text='') + parent.SetStatusText(i=0, text='') + parent.SetStatusText(i=1, text='') + parent.SetStatusText(i=2, text='') parent.SetStatusWidths([-1, 300, 200]) @@ -356,6 +353,8 @@ self.Bind(wx.EVT_MENU, self.OnOpenWidgetInspector, id=inspectorID) accels = [wx.AcceleratorEntry(wx.ACCEL_CTRL | wx.ACCEL_ALT, ord('I'), inspectorID)] + self.methodLock = Lock() + for method, shortcut in [("Stop", wx.WXK_F4), ("Run", wx.WXK_F5), ("Transfer", wx.WXK_F6), @@ -365,8 +364,15 @@ def OnMethodGen(obj, meth): def OnMethod(evt): if obj.CTR is not None: - obj.CTR.CallMethod('_'+meth) - wx.CallAfter(self.RefreshStatusToolBar) + if obj.methodLock.acquire(False): + obj.CTR.CallMethod('_'+meth) + obj.methodLock.release() + wx.CallAfter(obj.RefreshStatusToolBar) + else: + # Postpone call if one of method already running + # can happen because of long method using log, + # itself calling wx.Yield + wx.CallLater(50, OnMethod, evt) return OnMethod newid = wx.NewId() self.Bind(wx.EVT_MENU, OnMethodGen(self, method), id=newid) @@ -395,6 +401,7 @@ self.LogConsole.MarkerDefine(0, wx.stc.STC_MARK_CIRCLE, "BLACK", "RED") self.LogConsole.SetModEventMask(wx.stc.STC_MOD_INSERTTEXT) + self.LogConsole.SetCaretPeriod(0) self.LogConsole.Bind(wx.stc.EVT_STC_MARGINCLICK, self.OnLogConsoleMarginClick) self.LogConsole.Bind(wx.stc.EVT_STC_MODIFIED, self.OnLogConsoleModified) @@ -420,7 +427,7 @@ self.AUIManager.Update() - self.ConnectionStatusBar = esb.EnhancedStatusBar(self, style=wx.ST_SIZEGRIP) + self.ConnectionStatusBar = esb.EnhancedStatusBar(self, style=wx.STB_SIZEGRIP) self._init_coll_ConnectionStatusBar_Fields(self.ConnectionStatusBar) self.ProgressStatusBar = wx.Gauge(self.ConnectionStatusBar, -1, range=100) self.ConnectionStatusBar.AddWidget(self.ProgressStatusBar, esb.ESB_EXACT_FIT, esb.ESB_EXACT_FIT, 2) @@ -436,17 +443,16 @@ # found here. os.environ["PATH"] = os.getcwd()+';'+os.environ["PATH"] - def __init__(self, parent, projectOpen=None, buildpath=None, ctr=None, debug=True): + def __init__(self, parent, projectOpen=None, buildpath=None, ctr=None, debug=True, logf=None): + # Add beremiz's icon in top left corner of the frame self.icon = wx.Icon(Bpath("images", "brz.ico"), wx.BITMAP_TYPE_ICO) self.__init_execute_path() IDEFrame.__init__(self, parent, debug) - self.Log = LogPseudoFile(self.LogConsole, self.SelectTab) - - self.local_runtime = None - self.runtime_port = None - self.local_runtime_tmpdir = None + self.Log = LogPseudoFile(self.LogConsole, self.SelectTab, logf) + + LocalRuntimeMixin.__init__(self, self.Log) self.LastPanelSelected = None @@ -511,37 +517,6 @@ else: self.SetTitle(name) - def StartLocalRuntime(self, taskbaricon=True): - if (self.local_runtime is None) or (self.local_runtime.exitcode is not None): - # create temporary directory for runtime working directory - self.local_runtime_tmpdir = tempfile.mkdtemp() - # choose an arbitrary random port for runtime - self.runtime_port = int(random.random() * 1000) + 61131 - self.Log.write(_("Starting local runtime...\n")) - # launch local runtime - self.local_runtime = ProcessLogger( - self.Log, - "\"%s\" \"%s\" -p %s -i localhost %s %s" % ( - sys.executable, - Bpath("Beremiz_service.py"), - self.runtime_port, - {False: "-x 0", True: "-x 1"}[taskbaricon], - self.local_runtime_tmpdir), - no_gui=False, - timeout=500, keyword=self.local_runtime_tmpdir, - cwd=self.local_runtime_tmpdir) - self.local_runtime.spin() - return self.runtime_port - - def KillLocalRuntime(self): - if self.local_runtime is not None: - # shutdown local runtime - self.local_runtime.kill(gently=False) - # clear temp dir - shutil.rmtree(self.local_runtime_tmpdir) - - self.local_runtime = None - def OnOpenWidgetInspector(self, evt): # Activate the widget inspection tool from wx.lib.inspection import InspectionTool @@ -722,7 +697,7 @@ while self.RecentProjectsMenu.GetMenuItemCount() > 0: item = self.RecentProjectsMenu.FindItemByPosition(0) - self.RecentProjectsMenu.RemoveItem(item) + self.RecentProjectsMenu.Remove(item) self.FileMenu.Enable(ID_FILEMENURECENTPROJECTS, len(recent_projects) > 0) for idx, projectpath in enumerate(recent_projects): @@ -769,9 +744,9 @@ for confnode_method in self.CTR.StatusMethods: if "method" in confnode_method and confnode_method.get("shown", True): - tool = StatusToolBar.AddSimpleTool( - wx.ID_ANY, GetBitmap(confnode_method.get("bitmap", "Unknown")), - confnode_method["tooltip"]) + tool = StatusToolBar.AddTool( + wx.ID_ANY, confnode_method["tooltip"], + GetBitmap(confnode_method.get("bitmap", "Unknown"))) self.Bind(wx.EVT_MENU, self.GetMenuCallBackFunction(confnode_method["method"]), tool) StatusToolBar.Realize() @@ -821,7 +796,7 @@ else: self.EditMenu.Delete(item.GetId()) self.LastPanelSelected = None - self.MenuBar.UpdateMenus() + self.MenuBar.Refresh() def RefreshAll(self): self.RefreshStatusToolBar() diff -r 59158e360b8c -r f5850ce25caf Beremiz_cli.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Beremiz_cli.py Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,118 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os +import posixpath +import sys +import time +from functools import wraps + +import click +from importlib import import_module + + +class CLISession(object): + def __init__(self, **kwargs): + self.__dict__.update(kwargs) + self.controller = None + +pass_session = click.make_pass_decorator(CLISession) + + +@click.group(chain=True) +@click.option( + "--project-home", + envvar="PROJECT_HOME", + default=".", + metavar="PATH", + help="Changes the project folder location.", +) +@click.option( + "--config", + nargs=2, + multiple=True, + metavar="KEY VALUE", + help="Overrides a config key/value pair.", +) +@click.option( + "--keep", "-k", is_flag=True, + help="Keep local runtime, do not kill it after executing commands.", +) +@click.option("--verbose", "-v", is_flag=True, help="Enables verbose mode.") +@click.option( + "--buildpath", "-b", help="Where to store files created during build." +) +@click.option( + "--uri", "-u", help="URI to reach remote PLC." +) +@click.version_option("0.1") +@click.pass_context +def cli(ctx, **kwargs): + """Beremiz CLI manipulates beremiz projects and runtimes. """ + + ctx.obj = CLISession(**kwargs) + +def ensure_controller(func): + @wraps(func) + def func_wrapper(session, *args, **kwargs): + if session.controller is None: + session.controller = import_module("CLIController").CLIController(session) + ret = func(session, *args, **kwargs) + return ret + + return func_wrapper + +@cli.command() +@click.option( + "--target", "-t", help="Target system triplet." +) +@pass_session +@ensure_controller +def build(session, target): + """Builds project. """ + def processor(): + return session.controller.build_project(target) + return processor + +@cli.command() +@pass_session +@ensure_controller +def transfer(session): + """Transfer program to PLC runtim.""" + def processor(): + return session.controller.transfer_project() + return processor + +@cli.command() +@pass_session +@ensure_controller +def run(session): + """Run program already present in PLC. """ + def processor(): + return session.controller.run_project() + return processor + + +@cli.resultcallback() +@pass_session +def process_pipeline(session, processors, **kwargs): + ret = 0 + for processor in processors: + ret = processor() + if ret != 0: + if len(processors) > 1 : + click.echo("Command sequence aborted") + break + + session.controller.finish() + + if session.keep: + click.echo("Press Ctrl+C to quit") + while True: + time.sleep(1) + + return ret + +if __name__ == '__main__': + cli() + diff -r 59158e360b8c -r f5850ce25caf Beremiz_service.py --- a/Beremiz_service.py Thu Jul 14 11:40:27 2022 +0200 +++ b/Beremiz_service.py Sun Jul 17 22:53:35 2022 +0200 @@ -233,6 +233,7 @@ if havewx: import re + import wx.adv if wx.VERSION >= (3, 0, 0): app = wx.App(redirect=False) @@ -274,7 +275,7 @@ def SetTests(self, tests): self.Tests = tests - class BeremizTaskBarIcon(wx.TaskBarIcon): + class BeremizTaskBarIcon(wx.adv.TaskBarIcon): TBMENU_START = wx.NewId() TBMENU_STOP = wx.NewId() TBMENU_CHANGE_NAME = wx.NewId() @@ -286,7 +287,7 @@ TBMENU_QUIT = wx.NewId() def __init__(self, pyroserver): - wx.TaskBarIcon.__init__(self) + wx.adv.TaskBarIcon.__init__(self) self.pyroserver = pyroserver # Set the image self.UpdateIcon(None) @@ -334,7 +335,7 @@ elif "wxGTK" in wx.PlatformInfo: img = img.Scale(22, 22) # wxMac can be any size upto 128x128, so leave the source img alone.... - icon = wx.IconFromBitmap(img.ConvertToBitmap()) + icon = wx.Icon(img.ConvertToBitmap()) return icon def OnTaskBarStartPLC(self, evt): diff -r 59158e360b8c -r f5850ce25caf CLIController.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CLIController.py Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,121 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os +import sys +from functools import wraps + +import click + +import fake_wx + +from ProjectController import ProjectController +from LocalRuntimeMixin import LocalRuntimeMixin + +class Log: + + def __init__(self): + self.crlfpending = False + + def write(self, s): + if s: + if self.crlfpending: + sys.stdout.write("\n") + sys.stdout.write(s) + sys.stdout.flush() + self.crlfpending = 0 + + def write_error(self, s): + if s: + self.write("Error: "+s) + + def write_warning(self, s): + if s: + self.write("Warning: "+s) + + def flush(self): + sys.stdout.flush() + + def isatty(self): + return False + + def progress(self, s): + if s: + sys.stdout.write(s+"\r") + self.crlfpending = True + + +def with_project_loaded(func): + @wraps(func) + def func_wrapper(self, *args, **kwargs): + if not self.HasOpenedProject(): + if self.check_and_load_project(): + return 1 + self.apply_config() + return func(self, *args, **kwargs) + + return func_wrapper + +def connected(func): + @wraps(func) + def func_wrapper(self, *args, **kwargs): + if self._connector is None: + if self.session.uri: + self.BeremizRoot.setURI_location(self.session.uri) + if not self._Connect(): + return 1 + return func(self, *args, **kwargs) + + return func_wrapper + +class CLIController(LocalRuntimeMixin, ProjectController): + def __init__(self, session): + self.session = session + log = Log() + LocalRuntimeMixin.__init__(self, log, use_gui=False) + ProjectController.__init__(self, None, log) + + def check_and_load_project(self): + if not os.path.isdir(self.session.project_home): + self.logger.write_error( + _("\"%s\" is not a valid Beremiz project\n") % self.session.project_home) + return True + + errmsg, error = self.LoadProject(self.session.project_home, self.session.buildpath) + if error: + self.logger.write_error(errmsg) + return True + + def apply_config(self): + for k,v in self.session.config: + self.SetParamsAttribute("BeremizRoot."+k, v) + + @with_project_loaded + def build_project(self, target): + + if target: + self.SetParamsAttribute("BeremizRoot.TargetType", target) + + return 0 if self._Build() else 1 + + @with_project_loaded + @connected + def transfer_project(self): + + return 0 if self._Transfer() else 1 + + @with_project_loaded + @connected + def run_project(self): + + return 0 if self._Run() else 1 + + + def finish(self): + + self._Disconnect() + + if not self.session.keep: + self.KillLocalRuntime() + + diff -r 59158e360b8c -r f5850ce25caf IDEFrame.py --- a/IDEFrame.py Thu Jul 14 11:40:27 2022 +0200 +++ b/IDEFrame.py Sun Jul 17 22:53:35 2022 +0200 @@ -115,7 +115,7 @@ def AppendMenu(parent, help, kind, text, id=wx.ID_ANY): - return parent.Append(help=help, kind=kind, text=text, id=id) + return parent.Append(wx.MenuItem(helpString=help, kind=kind, text=text, id=id)) [ @@ -391,7 +391,7 @@ parent.AppendSeparator() add_menu = wx.Menu(title='') self._init_coll_AddMenu_Items(add_menu) - parent.AppendMenu(wx.ID_ADD, _(u"&Add Element"), add_menu) + parent.Append(wx.ID_ADD, _(u"&Add Element"), add_menu) AppendMenu(parent, help='', id=wx.ID_SELECTALL, kind=wx.ITEM_NORMAL, text=_(u'Select All') + '\tCTRL+A') AppendMenu(parent, help='', id=wx.ID_DELETE, @@ -442,7 +442,7 @@ kind=wx.ITEM_NORMAL, text=_(u'Clear Errors') + '\tCTRL+K') parent.AppendSeparator() zoommenu = wx.Menu(title='') - parent.AppendMenu(wx.ID_ZOOM_FIT, _("Zoom"), zoommenu) + parent.Append(wx.ID_ZOOM_FIT, _("Zoom"), zoommenu) for idx, value in enumerate(ZOOM_FACTORS): new_item = AppendMenu(zoommenu, help='', kind=wx.ITEM_RADIO, text=str(int(round(value * 100))) + "%") @@ -569,8 +569,8 @@ self.ProjectPanel = wx.SplitterWindow( id=ID_PLCOPENEDITORPROJECTPANEL, - name='ProjectPanel', parent=self.LeftNoteBook, point=wx.Point(0, 0), - size=wx.Size(0, 0), style=wx.SP_3D) + name='ProjectPanel', parent=self.LeftNoteBook, + size=wx.Size(0, 0)) self.ProjectTree = CustomTree(id=ID_PLCOPENEDITORPROJECTTREE, name='ProjectTree', @@ -631,9 +631,9 @@ wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER) EditorToolBar.SetToolBitmapSize(wx.Size(25, 25)) EditorToolBar.AddRadioTool(ID_PLCOPENEDITOREDITORTOOLBARSELECTION, + _("Select an object"), GetBitmap("select"), - wx.NullBitmap, - _("Select an object")) + wx.NullBitmap) EditorToolBar.Realize() self.Panes["EditorToolBar"] = EditorToolBar self.AUIManager.AddPane(EditorToolBar, wx.aui.AuiPaneInfo(). @@ -921,12 +921,8 @@ :param elements: List of elements to refresh. """ - try: - for element in elements: - self.RefreshFunctions[element]() - except wx.PyDeadObjectError: - # ignore exceptions caused by refresh while quitting - pass + for element in elements: + self.RefreshFunctions[element]() def OnPageClose(self, event): """Callback function when AUINotebook Page closed with CloseButton @@ -1418,7 +1414,8 @@ self.AuiTabCtrl = auitabctrl if self.TabsOpened.GetPageCount() == 0: pane = self.AUIManager.GetPane(self.TabsOpened) - if pane.IsMaximized(): + # on wxPython 4.1.0, AuiPaneInfo has no "IsMaximized" attribute... + if (not hasattr(pane, "IsMaximized")) or pane.IsMaximized(): self.AUIManager.RestorePane(pane) self.AUIManager.Update() @@ -1499,17 +1496,23 @@ def GetTabsOpenedDClickFunction(self, tabctrl): def OnTabsOpenedDClick(event): pos = event.GetPosition() - if tabctrl.TabHitTest(pos.x, pos.y, None): + if tabctrl.TabHitTest(pos.x, pos.y): self.SwitchPerspective(event) event.Skip() return OnTabsOpenedDClick def SwitchPerspective(self, evt): pane = self.AUIManager.GetPane(self.TabsOpened) - if pane.IsMaximized(): + # on wxPython 4.1.0, AuiPaneInfo has no "IsMaximized" attribute... + IsMaximized = pane.IsMaximized() if hasattr(pane, "IsMaximized") \ + else (self.TabBookIsMaximized if hasattr(self, "TabBookIsMaximized") \ + else False) + if IsMaximized: self.AUIManager.RestorePane(pane) + self.TabBookIsMaximized = False else: self.AUIManager.MaximizePane(pane) + self.TabBookIsMaximized = True self.AUIManager.Update() def SwitchFullScrMode(self, evt): @@ -1808,7 +1811,7 @@ else: block_type = "Action" self.LastToolTipItem = item - wx.CallAfter(self.ProjectTree.SetToolTipString, + wx.CallAfter(self.ProjectTree.SetToolTip, "%s : %s : %s" % ( block_type, bodytype, item_infos["name"])) elif self.LastToolTipItem is not None: @@ -2118,7 +2121,7 @@ MenuToolBar.AddSeparator() else: id, bitmap, help, callback = toolbar_item - MenuToolBar.AddSimpleTool(id=id, shortHelpString=help, bitmap=GetBitmap(bitmap)) + MenuToolBar.AddTool(id, help, GetBitmap(bitmap)) if callback is not None: self.Bind(wx.EVT_TOOL, callback, id=id) MenuToolBar.Realize() @@ -2158,9 +2161,9 @@ for radio, modes, id, method, picture, help in self.EditorToolBarItems[menu]: if modes & self.DrawingMode: if radio or self.DrawingMode == FREEDRAWING_MODE: - EditorToolBar.AddRadioTool(id, GetBitmap(picture), wx.NullBitmap, help) + EditorToolBar.AddRadioTool(id, help, GetBitmap(picture), wx.NullBitmap) else: - EditorToolBar.AddSimpleTool(id, GetBitmap(picture), help) + EditorToolBar.AddTool(id, help, GetBitmap(picture)) self.Bind(wx.EVT_MENU, getattr(self, method), id=id) self.CurrentEditorToolBar.append(id) EditorToolBar.Realize() diff -r 59158e360b8c -r f5850ce25caf LocalRuntimeMixin.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LocalRuntimeMixin.py Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import sys +import tempfile +import random +import shutil +from util.ProcessLogger import ProcessLogger +from util.paths import Bpath + +class LocalRuntimeMixin(): + + def __init__(self, log, use_gui=True): + self.local_runtime_log = log + self.local_runtime = None + self.runtime_port = None + self.local_runtime_tmpdir = None + self.use_gui = use_gui + + def StartLocalRuntime(self): + if (self.local_runtime is None) or (self.local_runtime.exitcode is not None): + # create temporary directory for runtime working directory + self.local_runtime_tmpdir = tempfile.mkdtemp() + # choose an arbitrary random port for runtime + self.runtime_port = int(random.random() * 1000) + 61131 + self.local_runtime_log.write(_("Starting local runtime...\n")) + # launch local runtime + self.local_runtime = ProcessLogger( + self.local_runtime_log, + "\"%s\" \"%s\" -p %s -i localhost %s %s" % ( + sys.executable, + Bpath("Beremiz_service.py"), + self.runtime_port, + {False: "-x 0", True: "-x 1"}[self.use_gui], + self.local_runtime_tmpdir), + no_gui=False, + timeout=500, keyword=self.local_runtime_tmpdir, + cwd=self.local_runtime_tmpdir) + self.local_runtime.spin() + return self.runtime_port + + def KillLocalRuntime(self): + if self.local_runtime is not None: + # shutdown local runtime + self.local_runtime.kill(gently=False) + # clear temp dir + shutil.rmtree(self.local_runtime_tmpdir) + + self.local_runtime = None + diff -r 59158e360b8c -r f5850ce25caf ProjectController.py --- a/ProjectController.py Thu Jul 14 11:40:27 2022 +0200 +++ b/ProjectController.py Sun Jul 17 22:53:35 2022 +0200 @@ -1526,7 +1526,8 @@ # clear previous_plcstate to restore status # in UpdateMethodsFromPLCStatus() self.previous_plcstate = "" - self.AppFrame.ProgressStatusBar.Hide() + if self.AppFrame is not None: + self.AppFrame.ProgressStatusBar.Hide() self.UpdateMethodsFromPLCStatus() def PullPLCStatusProc(self, event): @@ -1785,13 +1786,16 @@ """ Start PLC """ + success = False if self.GetIECProgramsAndVariables(): self._connector.StartPLC() self.logger.write(_("Starting PLC\n")) self._connect_debug() + success = True else: self.logger.write_error(_("Couldn't start PLC !\n")) wx.CallAfter(self.UpdateMethodsFromPLCStatus) + return success def _Stop(self): """ @@ -1805,6 +1809,10 @@ wx.CallAfter(self.UpdateMethodsFromPLCStatus) + def StartLocalRuntime(self): + if self.AppFrame: + return self.AppFrame.StartLocalRuntime() + def _SetConnector(self, connector, update_status=True): self._connector = connector if self.AppFrame is not None: @@ -1821,6 +1829,7 @@ wx.CallAfter(self.UpdateMethodsFromPLCStatus) def _Connect(self): + success = False # don't accept re-connetion if already connected if self._connector is not None: self.logger.write_error( @@ -1882,6 +1891,8 @@ else: self.logger.write_warning( _("Debug does not match PLC - stop/transfert/start to re-enable\n")) + success = True + return success def CompareLocalAndRemotePLC(self): if self._connector is None: @@ -1905,6 +1916,7 @@ self._SetConnector(None) def _Transfer(self): + success = False if self.IsPLCStarted(): dialog = wx.MessageDialog( self.AppFrame, @@ -1967,16 +1979,19 @@ if self.GetIECProgramsAndVariables(): self.UnsubscribeAllDebugIECVariable() self.ProgramTransferred() - self.AppFrame.CloseObsoleteDebugTabs() - self.AppFrame.RefreshPouInstanceVariablesPanel() - self.AppFrame.LogViewer.ResetLogCounters() + if self.AppFrame is not None: + self.AppFrame.CloseObsoleteDebugTabs() + self.AppFrame.RefreshPouInstanceVariablesPanel() + self.AppFrame.LogViewer.ResetLogCounters() self.logger.write(_("PLC installed successfully.\n")) + success = True else: self.logger.write_error(_("Missing debug data\n")) else: self.logger.write_error(_("PLC couldn't be installed\n")) wx.CallAfter(self.UpdateMethodsFromPLCStatus) + return success def _Repair(self): dialog = wx.MessageDialog( diff -r 59158e360b8c -r f5850ce25caf README.md --- a/README.md Thu Jul 14 11:40:27 2022 +0200 +++ b/README.md Sun Jul 17 22:53:35 2022 +0200 @@ -10,8 +10,8 @@ Beremiz consists of two components: -* Integrated Development Environment (IDE), [Beremiz.py](https://bitbucket.org/automforge/beremiz/src/tip/Beremiz.py?at=default). It's running on user's computer and is used to write/compile/debug PLC programs and control PLC runtime. -* Reference runtime implementation in python, [Beremiz_service.py](https://bitbucket.org/automforge/beremiz/src/tip/Beremiz_service.py?at=default). It's running on target platform, communicates with I/O and executes PLC program. +* Integrated Development Environment (IDE), Beremiz.py. It is running on user's computer and is used to write/compile/debug PLC programs and control PLC runtime. +* Reference runtime implementation in python, Beremiz_service.py. It's running on target platform, communicates with I/O and executes PLC program. See official [Beremiz website](http://www.beremiz.org/) for more information. @@ -77,6 +77,52 @@ cd ~/Beremiz/beremiz python Beremiz.py +## Build documentation + +Source code for Beremiz user manual is stored in +[doc](tree/default/doc) +directory in project's source tree. +It's written in reStructuredText (ReST) and uses Sphinx to build documentation in different formats. + + +To build documentation you need following packages on Ubuntu/Debian: + +``` +sudo apt-get install build-essential python-sphynx +``` + +### Documentation in HTML + +Build documentation + +``` +cd ~/Beremiz/doc +make all + +``` + +Result documentation is stored in directories 'doc/\_build/dirhtml\*'. + +### Documentation in PDF + +To build pdf documentation you have to install additional packages on Ubuntu/Debian: + +``` +sudo apt-get install textlive-latex-base texlive-latex-recommended \ + texlive-fonts-recommended texlive-latex-extra + +``` + +Build documentation + +``` +cd ~/Beremiz/doc +make latexpdf + +``` + +Result documentation is stored in 'doc/\_build/latex/Beremiz.pdf'. + ## Run standalone Beremiz runtime ## Runtime implementation can be different on different platforms. @@ -89,14 +135,11 @@ * Start standalone Beremiz service - cd ~/Beremiz - mkdir beremiz_workdir - cd ~/beremiz - python Beremiz_service.py -p 61194 -i localhost -x 0 -a 1 ~/Beremiz/beremiz_workdir + mkdir ~/beremiz_workdir + python Beremiz_service.py -p 61194 -i localhost -x 0 -a 1 ~/beremiz_workdir * Launch Beremiz IDE - cd ~/Beremiz/beremiz python Beremiz.py * Open/Create PLC project in Beremiz IDE. @@ -105,7 +148,8 @@ ## Examples ## -Almost for all functionality exists example in ['tests'](https://bitbucket.org/automforge/beremiz/src/tip/tests/?at=default) directory. +Almost for all functionality exists example in ['tests'](tree/default/tests/projects) and ['exemples'](tree/default/tests/projects) directories. + Most of examples are shown on [Beremiz youtube channel](https://www.youtube.com/channel/UCcE4KYI0p1f6CmSwtzyg-ZA). ## Documentation ## diff -r 59158e360b8c -r f5850ce25caf bacnet/BacnetSlaveEditor.py --- a/bacnet/BacnetSlaveEditor.py Thu Jul 14 11:40:27 2022 +0200 +++ b/bacnet/BacnetSlaveEditor.py Sun Jul 17 22:53:35 2022 +0200 @@ -367,8 +367,7 @@ "Engineering Units": {"GridCellEditor": wx.grid.GridCellChoiceEditor, # use string renderer with choice editor! "GridCellRenderer": wx.grid.GridCellStringRenderer, - # syntax for GridCellChoiceEditor -> comma separated values - "GridCellEditorParam": ','.join([x[0] for x in BACnetEngineeringUnits])} + "GridCellEditorConstructorArgs": [x[0] for x in BACnetEngineeringUnits]} } # obj_properties should be a dictionary, with keys "Object Identifier", @@ -576,7 +575,10 @@ PropertyName = self.BACnetObjectType.PropertyNames[col] PropertyConfig = self.BACnetObjectType.PropertyConfig[PropertyName] grid.SetReadOnly(row, col, False) - grid.SetCellEditor(row, col, PropertyConfig["GridCellEditor"]()) + GridCellEditorConstructorArgs = \ + PropertyConfig["GridCellEditorConstructorArgs"] + if "GridCellEditorConstructorArgs" in PropertyConfig else [] + grid.SetCellEditor(row, col, PropertyConfig["GridCellEditor"](*GridCellEditorConstructorArgs)) grid.SetCellRenderer(row, col, PropertyConfig["GridCellRenderer"]()) grid.SetCellBackgroundColour(row, col, wx.WHITE) grid.SetCellTextColour(row, col, wx.BLACK) @@ -816,7 +818,7 @@ self, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) - button.SetToolTipString(help) + button.SetToolTip(help) setattr(self, name, button) controls_sizer.Add(button) @@ -826,7 +828,7 @@ # use only to enable drag'n'drop # self.VariablesGrid.SetDropTarget(VariableDropTarget(self)) self.VariablesGrid.Bind( - wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange) + wx.grid.EVT_GRID_CELL_CHANGING, self.OnVariablesGridCellChange) # self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick) # self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown) self.MainSizer.Add(self.VariablesGrid, flag=wx.GROW) diff -r 59158e360b8c -r f5850ce25caf canfestival/NetworkEditor.py --- a/canfestival/NetworkEditor.py Thu Jul 14 11:40:27 2022 +0200 +++ b/canfestival/NetworkEditor.py Sun Jul 17 22:53:35 2022 +0200 @@ -68,7 +68,7 @@ main_sizer.AddGrowableCol(0) main_sizer.AddGrowableRow(0) - main_sizer.AddWindow(self.NetworkNodes, 0, border=5, flag=wx.GROW | wx.ALL) + main_sizer.Add(self.NetworkNodes, 0, border=5, flag=wx.GROW | wx.ALL) self.NetworkEditor.SetSizer(main_sizer) diff -r 59158e360b8c -r f5850ce25caf connectors/SchemeEditor.py --- a/connectors/SchemeEditor.py Thu Jul 14 11:40:27 2022 +0200 +++ b/connectors/SchemeEditor.py Sun Jul 17 22:53:35 2022 +0200 @@ -28,19 +28,19 @@ (wx.StaticText(self, label=label), wx.ALIGN_CENTER_VERTICAL), (txtctrl, wx.GROW)]: - self.fieldsizer.AddWindow(win, flag=flag) + self.fieldsizer.Add(win, flag=flag) self.fieldsizer.AddSpacer(20) if self.EnableIDSelector: self.mainsizer = wx.FlexGridSizer(cols=2, hgap=10, vgap=10) - self.mainsizer.AddSizer(self.fieldsizer) + self.mainsizer.Add(self.fieldsizer) self.idselector = IDBrowser( self, parent.ctr, # use a callafter, as editor can be deleted by calling SetURI partial(wx.CallAfter, parent.SetURI), self.txtctrls["ID"].SetValue) - self.mainsizer.AddWindow(self.idselector) + self.mainsizer.Add(self.idselector) self.SetSizer(self.mainsizer) else: self.SetSizer(self.fieldsizer) diff -r 59158e360b8c -r f5850ce25caf connectors/__init__.py --- a/connectors/__init__.py Thu Jul 14 11:40:27 2022 +0200 +++ b/connectors/__init__.py Sun Jul 17 22:53:35 2022 +0200 @@ -76,8 +76,7 @@ # pyro connection to local runtime # started on demand, listening on random port scheme = "PYRO" - runtime_port = confnodesroot.AppFrame.StartLocalRuntime( - taskbaricon=True) + runtime_port = confnodesroot.StartLocalRuntime() uri = "PYROLOC://127.0.0.1:" + str(runtime_port) # commented code to enable for MDNS:// support diff -r 59158e360b8c -r f5850ce25caf controls/CustomEditableListBox.py --- a/controls/CustomEditableListBox.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/CustomEditableListBox.py Sun Jul 17 22:53:35 2022 +0200 @@ -25,13 +25,13 @@ from __future__ import absolute_import import wx -import wx.gizmos +import wx.adv -class CustomEditableListBox(wx.gizmos.EditableListBox): +class CustomEditableListBox(wx.adv.EditableListBox): def __init__(self, *args, **kwargs): - wx.gizmos.EditableListBox.__init__(self, *args, **kwargs) + wx.adv.EditableListBox.__init__(self, *args, **kwargs) listbox = self.GetListCtrl() listbox.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) @@ -44,7 +44,7 @@ (self.GetDelButton(), _("Delete item"), "_OnDelButton"), (self.GetUpButton(), _("Move up"), "_OnUpButton"), (self.GetDownButton(), _("Move down"), "_OnDownButton")]: - button.SetToolTipString(tooltip) + button.SetToolTip(tooltip) button.Bind(wx.EVT_BUTTON, self.GetButtonPressedFunction(call_function)) self.Editing = False diff -r 59158e360b8c -r f5850ce25caf controls/CustomStyledTextCtrl.py --- a/controls/CustomStyledTextCtrl.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/CustomStyledTextCtrl.py Sun Jul 17 22:53:35 2022 +0200 @@ -105,9 +105,9 @@ [self.GetMarginWidth(i) for i in xrange(3)], 0) if x <= margin_width: - self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW)) + self.SetCursor(wx.Cursor(wx.CURSOR_ARROW)) else: - self.SetCursor(wx.StockCursor(wx.CURSOR_IBEAM)) + self.SetCursor(wx.Cursor(wx.CURSOR_IBEAM)) else: event.Skip() else: diff -r 59158e360b8c -r f5850ce25caf controls/CustomTable.py --- a/controls/CustomTable.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/CustomTable.py Sun Jul 17 22:53:35 2022 +0200 @@ -40,7 +40,7 @@ """ def __init__(self, parent, data, colnames): # The base class must be initialized *first* - wx.grid.PyGridTableBase.__init__(self) + wx.grid.GridTableBase.__init__(self) self.data = data self.colnames = colnames self.Highlights = {} @@ -64,7 +64,7 @@ return self.colnames[col] def GetRowLabelValue(self, row, translate=True): - return row + return str(row) def GetValue(self, row, col): if row < self.GetNumberRows(): diff -r 59158e360b8c -r f5850ce25caf controls/CustomToolTip.py --- a/controls/CustomToolTip.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/CustomToolTip.py Sun Jul 17 22:53:35 2022 +0200 @@ -137,7 +137,7 @@ max_width = max_height = 0 # Create a memory DC for calculating text extent - dc = wx.MemoryDC(wx.EmptyBitmap(1, 1)) + dc = wx.MemoryDC(wx.Bitmap(1, 1)) dc.SetFont(self.Font) # Compute max tip text size @@ -175,7 +175,6 @@ dc.SetFont(self.Font) # Draw Tool tip - dc.BeginDrawing() tip_width, tip_height = self.GetToolTipSize() # Draw background rectangle @@ -188,6 +187,5 @@ _line_width, line_height = dc.GetTextExtent(line) line_offset += line_height - dc.EndDrawing() event.Skip() diff -r 59158e360b8c -r f5850ce25caf controls/CustomTree.py --- a/controls/CustomTree.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/CustomTree.py Sun Jul 17 22:53:35 2022 +0200 @@ -120,9 +120,9 @@ _item, flags = self.HitTest(pos) bitmap_rect = self.GetBitmapRect() - if ((bitmap_rect.InsideXY(pos.x, pos.y) or + if ((bitmap_rect.Contains(pos.x, pos.y) or flags & wx.TREE_HITTEST_NOWHERE) and self.AddMenu is not None): - wx.CallAfter(self.PopupMenuXY, self.AddMenu, pos.x, pos.y) + wx.CallAfter(self.PopupMenu, self.AddMenu, pos.x, pos.y) event.Skip() def OnEraseBackground(self, event): diff -r 59158e360b8c -r f5850ce25caf controls/DebugVariablePanel/DebugVariableGraphicViewer.py --- a/controls/DebugVariablePanel/DebugVariableGraphicViewer.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/DebugVariablePanel/DebugVariableGraphicViewer.py Sun Jul 17 22:53:35 2022 +0200 @@ -174,7 +174,7 @@ # If mouse is dropped in graph canvas bounding box and graph is # not 3D canvas, graphs will be merged rect = self.ParentControl.GetAxesBoundingBox() - if not self.ParentControl.Is3DCanvas() and rect.InsideXY(x, y): + if not self.ParentControl.Is3DCanvas() and rect.Contains(x, y): # Default merge type is parallel merge_type = GRAPH_PARALLEL @@ -182,7 +182,7 @@ # wall be merged orthogonally merge_rect = wx.Rect(rect.x, rect.y, rect.width / 2., rect.height) - if merge_rect.InsideXY(x, y): + if merge_rect.Contains(x, y): merge_type = GRAPH_ORTHOGONAL # Merge graphs @@ -625,7 +625,7 @@ (x0, y0), (x1, y1) = t.get_window_extent().get_points() rect = wx.Rect(x0, height - y1, x1 - x0, y1 - y0) # Check if mouse was over label - if rect.InsideXY(x, y): + if rect.Contains(x, y): item_idx = i break @@ -736,7 +736,7 @@ (x0, y0), (x1, y1) = t.get_window_extent().get_points() rect = wx.Rect(x0, height - y1, x1 - x0, y1 - y0) # Check if mouse was over label - if rect.InsideXY(event.x, height - event.y): + if rect.Contains(event.x, height - event.y): item_idx = i menu_direction = dir break @@ -756,7 +756,7 @@ # Update resize highlight if event.y <= 5: if self.SetHighlight(HIGHLIGHT_RESIZE): - self.SetCursor(wx.StockCursor(wx.CURSOR_SIZENS)) + self.SetCursor(wx.Cursor(wx.CURSOR_SIZENS)) self.ParentWindow.ForceRefresh() else: if self.SetHighlight(HIGHLIGHT_NONE): @@ -832,7 +832,7 @@ # Check that double click was done inside figure pos = event.GetPosition() rect = self.GetAxesBoundingBox() - if rect.InsideXY(pos.x, pos.y): + if rect.Contains(pos.x, pos.y): # Reset Cursor tick to value before starting clicking self.ParentWindow.SetCursorTick(self.StartCursorTick) # Toggle to text Viewer(s) @@ -926,10 +926,10 @@ # Mouse is over Viewer figure and graph is not 3D bbox = self.GetAxesBoundingBox() - if bbox.InsideXY(x, y) and not self.Is3DCanvas(): + if bbox.Contains(x, y) and not self.Is3DCanvas(): rect = wx.Rect(bbox.x, bbox.y, bbox.width // 2, bbox.height) # Mouse is over Viewer left part of figure - if rect.InsideXY(x, y): + if rect.Contains(x, y): self.SetHighlight(HIGHLIGHT_LEFT) # Mouse is over Viewer right part of figure @@ -1381,8 +1381,6 @@ # rendering destGC = wx.GCDC(destDC) - destGC.BeginDrawing() - # Get canvas size and figure bounding box in canvas width, height = self.GetSize() bbox = self.GetAxesBoundingBox() @@ -1409,7 +1407,5 @@ # Draw other Viewer common elements self.DrawCommonElements(destGC, self.GetButtons()) - destGC.EndDrawing() - self._isDrawn = True self.gui_repaint(drawDC=drawDC) diff -r 59158e360b8c -r f5850ce25caf controls/DebugVariablePanel/DebugVariablePanel.py --- a/controls/DebugVariablePanel/DebugVariablePanel.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/DebugVariablePanel/DebugVariablePanel.py Sun Jul 17 22:53:35 2022 +0200 @@ -221,14 +221,14 @@ self.GraphicPanels = [] graphics_button_sizer = wx.BoxSizer(wx.HORIZONTAL) - main_sizer.AddSizer(graphics_button_sizer, border=5, flag=wx.GROW | wx.ALL) + main_sizer.Add(graphics_button_sizer, border=5, flag=wx.GROW | wx.ALL) range_label = wx.StaticText(self, label=_('Range:')) - graphics_button_sizer.AddWindow(range_label, flag=wx.ALIGN_CENTER_VERTICAL) + graphics_button_sizer.Add(range_label, flag=wx.ALIGN_CENTER_VERTICAL) self.CanvasRange = wx.ComboBox(self, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnRangeChanged, self.CanvasRange) - graphics_button_sizer.AddWindow(self.CanvasRange, 1, + graphics_button_sizer.Add(self.CanvasRange, 1, border=5, flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL) @@ -246,10 +246,10 @@ button = wx.lib.buttons.GenBitmapButton( self, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) - button.SetToolTipString(help) + button.SetToolTip(help) setattr(self, name, button) self.Bind(wx.EVT_BUTTON, getattr(self, "On" + name), button) - graphics_button_sizer.AddWindow(button, border=5, flag=wx.LEFT) + graphics_button_sizer.Add(button, border=5, flag=wx.LEFT) self.CanvasPosition = wx.ScrollBar( self, size=wx.Size(0, 16), style=wx.SB_HORIZONTAL) @@ -263,19 +263,19 @@ self.OnPositionChanging, self.CanvasPosition) self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEDOWN, self.OnPositionChanging, self.CanvasPosition) - main_sizer.AddWindow(self.CanvasPosition, border=5, flag=wx.GROW | wx.LEFT | wx.RIGHT | wx.BOTTOM) + main_sizer.Add(self.CanvasPosition, border=5, flag=wx.GROW | wx.LEFT | wx.RIGHT | wx.BOTTOM) self.TickSizer = wx.BoxSizer(wx.HORIZONTAL) - main_sizer.AddSizer(self.TickSizer, border=5, flag=wx.ALL | wx.GROW) + main_sizer.Add(self.TickSizer, border=5, flag=wx.ALL | wx.GROW) self.TickLabel = wx.StaticText(self) - self.TickSizer.AddWindow(self.TickLabel, border=5, flag=wx.RIGHT) + self.TickSizer.Add(self.TickLabel, border=5, flag=wx.RIGHT) self.MaskLabel = wx.TextCtrl(self, style=wx.TE_READONLY | wx.TE_CENTER | wx.NO_BORDER) - self.TickSizer.AddWindow(self.MaskLabel, 1, border=5, flag=wx.RIGHT | wx.GROW) + self.TickSizer.Add(self.MaskLabel, 1, border=5, flag=wx.RIGHT | wx.GROW) self.TickTimeLabel = wx.StaticText(self) - self.TickSizer.AddWindow(self.TickTimeLabel) + self.TickSizer.Add(self.TickTimeLabel) self.GraphicsWindow = wx.ScrolledWindow(self, style=wx.HSCROLL | wx.VSCROLL) self.GraphicsWindow.SetBackgroundColour(wx.WHITE) @@ -284,7 +284,7 @@ self.GraphicsWindow.Bind(wx.EVT_SIZE, self.OnGraphicsWindowResize) self.GraphicsWindow.Bind(wx.EVT_MOUSEWHEEL, self.OnGraphicsWindowMouseWheel) - main_sizer.AddWindow(self.GraphicsWindow, 1, flag=wx.GROW) + main_sizer.Add(self.GraphicsWindow, 1, flag=wx.GROW) self.GraphicsSizer = wx.BoxSizer(wx.VERTICAL) self.GraphicsWindow.SetSizer(self.GraphicsSizer) @@ -441,7 +441,7 @@ x, y = panel.GetPosition() width, height = panel.GetSize() rect = wx.Rect(x, y, width, height) - if rect.InsideXY(x_mouse, y_mouse) or \ + if rect.Contains(x_mouse, y_mouse) or \ idx == 0 and y_mouse < 0 or \ idx == len(self.GraphicPanels) - 1 and y_mouse > panel.GetPosition()[1]: panel.RefreshHighlight(x_mouse - x, y_mouse - y) @@ -488,7 +488,7 @@ xw, yw = panel.GetPosition() width, height = panel.GetSize() bbox = wx.Rect(xw, yw, width, height) - if bbox.InsideXY(x_mouse, y_mouse): + if bbox.Contains(x_mouse, y_mouse): panel.ShowButtons(True) merge_type = GRAPH_PARALLEL if isinstance(panel, DebugVariableTextViewer) or panel.Is3DCanvas(): @@ -497,9 +497,9 @@ wx.CallAfter(self.MoveValue, variable, idx, True) else: rect = panel.GetAxesBoundingBox(True) - if rect.InsideXY(x_mouse, y_mouse): + if rect.Contains(x_mouse, y_mouse): merge_rect = wx.Rect(rect.x, rect.y, rect.width // 2, rect.height) - if merge_rect.InsideXY(x_mouse, y_mouse): + if merge_rect.Contains(x_mouse, y_mouse): merge_type = GRAPH_ORTHOGONAL wx.CallAfter(self.MergeGraphs, variable, idx, merge_type, force=True) else: @@ -510,7 +510,7 @@ return width, height = self.GraphicsWindow.GetVirtualSize() rect = wx.Rect(0, 0, width, height) - if rect.InsideXY(x_mouse, y_mouse): + if rect.Contains(x_mouse, y_mouse): wx.CallAfter(self.MoveValue, variable, len(self.GraphicPanels), True) self.ForceRefresh() @@ -518,7 +518,7 @@ self.GraphicsSizer.Clear() for panel in self.GraphicPanels: - self.GraphicsSizer.AddWindow(panel, flag=wx.GROW) + self.GraphicsSizer.Add(panel, flag=wx.GROW) self.GraphicsSizer.Layout() self.RefreshGraphicsWindowScrollbars() diff -r 59158e360b8c -r f5850ce25caf controls/DebugVariablePanel/DebugVariableTextViewer.py --- a/controls/DebugVariablePanel/DebugVariableTextViewer.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/DebugVariablePanel/DebugVariableTextViewer.py Sun Jul 17 22:53:35 2022 +0200 @@ -195,7 +195,7 @@ # Create buffered DC for drawing in panel width, height = self.GetSize() - bitmap = wx.EmptyBitmap(width, height) + bitmap = wx.Bitmap(width, height) dc = wx.BufferedDC(wx.PaintDC(self), bitmap) dc.Clear() @@ -203,8 +203,6 @@ # rendering gc = wx.GCDC(dc) - gc.BeginDrawing() - # Get first item item = self.ItemsDict.values()[0] @@ -232,8 +230,6 @@ # Draw other Viewer common elements self.DrawCommonElements(gc) - gc.EndDrawing() - def OnLeftDown(self, event): """ Function called when mouse left button is pressed @@ -252,7 +248,7 @@ # start a move drag'n drop of item variable x, y = event.GetPosition() item_path_bbox = wx.Rect(20, (height - h) / 2, w, h) - if item_path_bbox.InsideXY(x, y): + if item_path_bbox.Contains(x, y): self.ShowButtons(False) data = wx.TextDataObject(str((item.GetVariable(), "debug", "move"))) dragSource = wx.DropSource(self) diff -r 59158e360b8c -r f5850ce25caf controls/DebugVariablePanel/GraphButton.py --- a/controls/DebugVariablePanel/GraphButton.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/DebugVariablePanel/GraphButton.py Sun Jul 17 22:53:35 2022 +0200 @@ -146,7 +146,7 @@ # Test if point is inside button w, h = self.Bitmap.GetSize() rect = wx.Rect(self.Position.x, self.Position.y, w, h) - return rect.InsideXY(x, y) + return rect.Contains(x, y) def ProcessCallback(self): """ diff -r 59158e360b8c -r f5850ce25caf controls/DiscoveryPanel.py --- a/controls/DiscoveryPanel.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/DiscoveryPanel.py Sun Jul 17 22:53:35 2022 +0200 @@ -44,17 +44,17 @@ class DiscoveryPanel(wx.Panel, listmix.ColumnSorterMixin): def _init_coll_MainSizer_Items(self, parent): - parent.AddWindow(self.staticText1, 0, border=20, flag=wx.TOP | wx.LEFT | wx.RIGHT | wx.GROW) - parent.AddWindow(self.ServicesList, 0, border=20, flag=wx.LEFT | wx.RIGHT | wx.GROW) - parent.AddSizer(self.ButtonGridSizer, 0, border=20, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.GROW) + parent.Add(self.staticText1, 0, border=20, flag=wx.TOP | wx.LEFT | wx.RIGHT | wx.GROW) + parent.Add(self.ServicesList, 0, border=20, flag=wx.LEFT | wx.RIGHT | wx.GROW) + parent.Add(self.ButtonGridSizer, 0, border=20, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.GROW) def _init_coll_MainSizer_Growables(self, parent): parent.AddGrowableCol(0) parent.AddGrowableRow(1) def _init_coll_ButtonGridSizer_Items(self, parent): - parent.AddWindow(self.RefreshButton, 0, border=0, flag=0) - # parent.AddWindow(self.ByIPCheck, 0, border=0, flag=0) + parent.Add(self.RefreshButton, 0, border=0, flag=0) + # parent.Add(self.ByIPCheck, 0, border=0, flag=0) def _init_coll_ButtonGridSizer_Growables(self, parent): parent.AddGrowableCol(0) diff -r 59158e360b8c -r f5850ce25caf controls/DurationCellEditor.py --- a/controls/DurationCellEditor.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/DurationCellEditor.py Sun Jul 17 22:53:35 2022 +0200 @@ -46,12 +46,12 @@ self.Duration = wx.TextCtrl(self, size=wx.Size(0, -1), style=wx.TE_PROCESS_ENTER) self.Duration.Bind(wx.EVT_KEY_DOWN, self.OnDurationChar) - main_sizer.AddWindow(self.Duration, flag=wx.GROW) + main_sizer.Add(self.Duration, flag=wx.GROW) # create browse button self.EditButton = wx.Button(self, label='...', size=wx.Size(30, -1)) self.Bind(wx.EVT_BUTTON, self.OnEditButtonClick, self.EditButton) - main_sizer.AddWindow(self.EditButton, flag=wx.GROW) + main_sizer.Add(self.EditButton, flag=wx.GROW) self.Bind(wx.EVT_SIZE, self.OnSize) @@ -98,12 +98,12 @@ self.Duration.SetFocus() -class DurationCellEditor(wx.grid.PyGridCellEditor): +class DurationCellEditor(wx.grid.GridCellEditor): ''' Grid cell editor that uses DurationCellControl to display an edit button. ''' def __init__(self, table, colname): - wx.grid.PyGridCellEditor.__init__(self) + wx.grid.GridCellEditor.__init__(self) self.Table = table self.Colname = colname diff -r 59158e360b8c -r f5850ce25caf controls/EnhancedStatusBar.py --- a/controls/EnhancedStatusBar.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/EnhancedStatusBar.py Sun Jul 17 22:53:35 2022 +0200 @@ -85,12 +85,12 @@ class EnhancedStatusBar(wx.StatusBar): - def __init__(self, parent, id=wx.ID_ANY, style=wx.ST_SIZEGRIP, + def __init__(self, parent, id=wx.ID_ANY, style=wx.STB_SIZEGRIP, name="EnhancedStatusBar"): """Default Class Constructor. EnhancedStatusBar.__init__(self, parent, id=wx.ID_ANY, - style=wx.ST_SIZEGRIP, + style=wx.STB_SIZEGRIP, name="EnhancedStatusBar") """ @@ -100,7 +100,7 @@ self._curPos = 0 self._parent = parent - wx.EVT_SIZE(self, self.OnSize) + self.Bind(wx.EVT_SIZE, self.OnSize) wx.CallAfter(self.OnSize, None) def OnSize(self, event): diff -r 59158e360b8c -r f5850ce25caf controls/FolderTree.py --- a/controls/FolderTree.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/FolderTree.py Sun Jul 17 22:53:35 2022 +0200 @@ -74,12 +74,12 @@ self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnTreeItemCollapsed, self.Tree) self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnTreeBeginLabelEdit, self.Tree) self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnTreeEndLabelEdit, self.Tree) - main_sizer.AddWindow(self.Tree, 1, flag=wx.GROW) + main_sizer.Add(self.Tree, 1, flag=wx.GROW) if filter is not None: self.Filter = wx.ComboBox(self, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnFilterChanged, self.Filter) - main_sizer.AddWindow(self.Filter, flag=wx.GROW) + main_sizer.Add(self.Filter, flag=wx.GROW) else: self.Filter = None diff -r 59158e360b8c -r f5850ce25caf controls/LibraryPanel.py --- a/controls/LibraryPanel.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/LibraryPanel.py Sun Jul 17 22:53:35 2022 +0200 @@ -77,12 +77,12 @@ search_textctrl = self.SearchCtrl.GetChildren()[0] search_textctrl.Bind(wx.EVT_CHAR, self.OnKeyDown) - main_sizer.AddWindow(self.SearchCtrl, flag=wx.GROW) + main_sizer.Add(self.SearchCtrl, flag=wx.GROW) # Add Splitter window for tree and block comment to main sizer splitter_window = wx.SplitterWindow(self) splitter_window.SetSashGravity(1.0) - main_sizer.AddWindow(splitter_window, flag=wx.GROW) + main_sizer.Add(splitter_window, flag=wx.GROW) # Add TreeCtrl for functions and function blocks library in splitter # window @@ -216,7 +216,7 @@ # Set data associated to tree item (only save that item is a # category) - self.Tree.SetPyData(category_item, {"type": CATEGORY}) + self.Tree.SetItemData(category_item, {"type": CATEGORY}) # Iterate over functions and function blocks defined in library # category add a tree item to category tree item for each of @@ -253,7 +253,7 @@ if blocktype["extensible"] else None), "comment": _(comment) + blocktype.get("usage", "") } - self.Tree.SetPyData(blocktype_item, block_data) + self.Tree.SetItemData(blocktype_item, block_data) # Select block tree item in tree if it corresponds to # previously selected one diff -r 59158e360b8c -r f5850ce25caf controls/LocationCellEditor.py --- a/controls/LocationCellEditor.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/LocationCellEditor.py Sun Jul 17 22:53:35 2022 +0200 @@ -46,12 +46,12 @@ self.Location = wx.TextCtrl(self, size=wx.Size(0, -1), style=wx.TE_PROCESS_ENTER) self.Location.Bind(wx.EVT_KEY_DOWN, self.OnLocationChar) - main_sizer.AddWindow(self.Location, flag=wx.GROW) + main_sizer.Add(self.Location, flag=wx.GROW) # create browse button self.BrowseButton = wx.Button(self, label='...', size=wx.Size(30, -1)) self.BrowseButton.Bind(wx.EVT_BUTTON, self.OnBrowseButtonClick) - main_sizer.AddWindow(self.BrowseButton, flag=wx.GROW) + main_sizer.Add(self.BrowseButton, flag=wx.GROW) self.Bind(wx.EVT_SIZE, self.OnSize) @@ -150,12 +150,12 @@ self.Location.SetFocus() -class LocationCellEditor(wx.grid.PyGridCellEditor): +class LocationCellEditor(wx.grid.GridCellEditor): ''' Grid cell editor that uses LocationCellControl to display a browse button. ''' def __init__(self, table, controller): - wx.grid.PyGridCellEditor.__init__(self) + wx.grid.GridCellEditor.__init__(self) self.Table = table self.Controller = controller @@ -178,7 +178,7 @@ self.CellControl.SetVarType(self.Table.GetValueByName(row, 'Type')) self.CellControl.SetFocus() - def EndEditInternal(self, row, col, grid, old_loc): + def EndEdit(self, row, col, grid, old_loc): loc = self.CellControl.GetValue() changed = loc != old_loc if changed: @@ -201,13 +201,8 @@ self.CellControl.Disable() return changed - if wx.VERSION >= (3, 0, 0): - def EndEdit(self, row, col, grid, oldval): - return self.EndEditInternal(row, col, grid, oldval) - else: - def EndEdit(self, row, col, grid): - old_loc = self.Table.GetValueByName(row, 'Location') - return self.EndEditInternal(row, col, grid, old_loc) + def ApplyEdit(self, row, col, grid): + pass def SetSize(self, rect): self.CellControl.SetDimensions(rect.x + 1, rect.y, diff -r 59158e360b8c -r f5850ce25caf controls/LogViewer.py --- a/controls/LogViewer.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/LogViewer.py Sun Jul 17 22:53:35 2022 +0200 @@ -99,8 +99,8 @@ width, height = self.GetClientSize() range_rect = self.GetRangeRect() thumb_rect = self.GetThumbRect() - if range_rect.InsideXY(posx, posy): - if thumb_rect.InsideXY(posx, posy): + if range_rect.Contains(posx, posy): + if thumb_rect.Contains(posx, posy): self.ThumbScrollingStartPos = wx.Point(posx, posy) elif posy < thumb_rect.y: self.Parent.ScrollToLast() @@ -139,7 +139,6 @@ def OnPaint(self, event): dc = wx.BufferedPaintDC(self) dc.Clear() - dc.BeginDrawing() gc = wx.GCDC(dc) @@ -179,7 +178,6 @@ gc.DrawRectangle(thumb_rect.x, thumb_rect.y, thumb_rect.width, thumb_rect.height) - dc.EndDrawing() event.Skip() @@ -207,7 +205,7 @@ def HitTest(self, x, y): rect = wx.Rect(self.Position.x, self.Position.y, self.Size.width, self.Size.height) - if rect.InsideXY(x, y): + if rect.Contains(x, y): return True return False @@ -303,7 +301,7 @@ main_sizer.AddGrowableRow(1) filter_sizer = wx.BoxSizer(wx.HORIZONTAL) - main_sizer.AddSizer(filter_sizer, border=5, flag=wx.TOP | wx.LEFT | wx.RIGHT | wx.GROW) + main_sizer.Add(filter_sizer, border=5, flag=wx.TOP | wx.LEFT | wx.RIGHT | wx.GROW) self.MessageFilter = wx.ComboBox(self, style=wx.CB_READONLY) self.MessageFilter.Append(_("All")) @@ -312,7 +310,7 @@ for level in levels: self.MessageFilter.Append(_(level)) self.Bind(wx.EVT_COMBOBOX, self.OnMessageFilterChanged, self.MessageFilter) - filter_sizer.AddWindow(self.MessageFilter, 1, border=5, flag=wx.RIGHT | wx.ALIGN_CENTER_VERTICAL) + filter_sizer.Add(self.MessageFilter, 1, border=5, flag=wx.RIGHT | wx.ALIGN_CENTER_VERTICAL) self.SearchMessage = wx.SearchCtrl(self, style=wx.TE_PROCESS_ENTER) self.SearchMessage.ShowSearchButton(True) @@ -322,18 +320,18 @@ self.OnSearchMessageSearchButtonClick, self.SearchMessage) self.Bind(wx.EVT_SEARCHCTRL_CANCEL_BTN, self.OnSearchMessageCancelButtonClick, self.SearchMessage) - filter_sizer.AddWindow(self.SearchMessage, 3, border=5, flag=wx.RIGHT | wx.ALIGN_CENTER_VERTICAL) + filter_sizer.Add(self.SearchMessage, 3, border=5, flag=wx.RIGHT | wx.ALIGN_CENTER_VERTICAL) self.CleanButton = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap("Clean"), size=wx.Size(28, 28), style=wx.NO_BORDER) - self.CleanButton.SetToolTipString(_("Clean log messages")) + self.CleanButton.SetToolTip(_("Clean log messages")) self.Bind(wx.EVT_BUTTON, self.OnCleanButton, self.CleanButton) - filter_sizer.AddWindow(self.CleanButton) + filter_sizer.Add(self.CleanButton) message_panel_sizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0) message_panel_sizer.AddGrowableCol(0) message_panel_sizer.AddGrowableRow(0) - main_sizer.AddSizer(message_panel_sizer, border=5, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.GROW) + main_sizer.Add(message_panel_sizer, border=5, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.GROW) self.MessagePanel = wx.Panel(self) if wx.Platform == '__WXMSW__': @@ -349,10 +347,10 @@ self.MessagePanel.Bind(wx.EVT_ERASE_BACKGROUND, self.OnMessagePanelEraseBackground) self.MessagePanel.Bind(wx.EVT_PAINT, self.OnMessagePanelPaint) self.MessagePanel.Bind(wx.EVT_SIZE, self.OnMessagePanelResize) - message_panel_sizer.AddWindow(self.MessagePanel, flag=wx.GROW) + message_panel_sizer.Add(self.MessagePanel, flag=wx.GROW) self.MessageScrollBar = LogScrollBar(self, wx.Size(16, -1)) - message_panel_sizer.AddWindow(self.MessageScrollBar, flag=wx.GROW) + message_panel_sizer.Add(self.MessageScrollBar, flag=wx.GROW) self.SetSizer(main_sizer) @@ -534,10 +532,9 @@ def RefreshView(self): width, height = self.MessagePanel.GetClientSize() - bitmap = wx.EmptyBitmap(width, height) + bitmap = wx.Bitmap(width, height) dc = wx.BufferedDC(wx.ClientDC(self.MessagePanel), bitmap) dc.Clear() - dc.BeginDrawing() if self.CurrentMessage is not None: @@ -559,8 +556,6 @@ draw_date = message.Date != previous_message.Date message = previous_message - dc.EndDrawing() - self.MessageScrollBar.RefreshThumbPosition() def IsPLCLogEmpty(self): diff -r 59158e360b8c -r f5850ce25caf controls/PouInstanceVariablesPanel.py --- a/controls/PouInstanceVariablesPanel.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/PouInstanceVariablesPanel.py Sun Jul 17 22:53:35 2022 +0200 @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#.!/usr/bin/env python # -*- coding: utf-8 -*- # This file is part of Beremiz, a Integrated Development Environment for @@ -93,7 +93,7 @@ rect = wx.Rect(images_bbx.x + 4, images_bbx.y + 4, r_image_w, r_image_h) for r_image in rightimages: - if rect.Inside(point): + if rect.Contains(point): return r_image rect.x += r_image_w + 4 @@ -132,7 +132,7 @@ self.ParentButton = wx.lib.buttons.GenBitmapButton( self, bitmap=GetBitmap("top"), size=wx.Size(28, 28), style=wx.NO_BORDER) - self.ParentButton.SetToolTipString(_("Parent instance")) + self.ParentButton.SetToolTip(_("Parent instance")) self.Bind(wx.EVT_BUTTON, self.OnParentButtonClick, self.ParentButton) @@ -142,7 +142,7 @@ self.DebugButton = wx.lib.buttons.GenBitmapButton( self, bitmap=GetBitmap("debug_instance"), size=wx.Size(28, 28), style=wx.NO_BORDER) - self.DebugButton.SetToolTipString(_("Debug instance")) + self.DebugButton.SetToolTip(_("Debug instance")) self.Bind(wx.EVT_BUTTON, self.OnDebugButtonClick, self.DebugButton) @@ -175,15 +175,15 @@ self.DebugButtonCallback, self.DebugButtonDClickCallback)} buttons_sizer = wx.FlexGridSizer(cols=3, hgap=0, rows=1, vgap=0) - buttons_sizer.AddWindow(self.ParentButton) - buttons_sizer.AddWindow(self.InstanceChoice, flag=wx.GROW) - buttons_sizer.AddWindow(self.DebugButton) + buttons_sizer.Add(self.ParentButton) + buttons_sizer.Add(self.InstanceChoice, flag=wx.GROW) + buttons_sizer.Add(self.DebugButton) buttons_sizer.AddGrowableCol(1) buttons_sizer.AddGrowableRow(0) main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) - main_sizer.AddSizer(buttons_sizer, flag=wx.GROW) - main_sizer.AddWindow(self.VariablesList, flag=wx.GROW) + main_sizer.Add(buttons_sizer, flag=wx.GROW) + main_sizer.Add(self.VariablesList, flag=wx.GROW) main_sizer.AddGrowableCol(0) main_sizer.AddGrowableRow(1) diff -r 59158e360b8c -r f5850ce25caf controls/ProjectPropertiesPanel.py --- a/controls/ProjectPropertiesPanel.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/ProjectPropertiesPanel.py Sun Jul 17 22:53:35 2022 +0200 @@ -57,7 +57,7 @@ border |= wx.BOTTOM st = wx.StaticText(parent, label=label) - sizer.AddWindow(st, border=10, + sizer.Add(st, border=10, flag=wx.ALIGN_CENTER_VERTICAL | border | wx.LEFT) tc = wx.TextCtrl(parent, style=wx.TE_PROCESS_ENTER) @@ -65,7 +65,7 @@ callback = self.GetTextCtrlChangedFunction(tc, name) self.Bind(wx.EVT_TEXT_ENTER, callback, tc) tc.Bind(wx.EVT_KILL_FOCUS, callback) - sizer.AddWindow(tc, border=10, + sizer.Add(tc, border=10, flag=wx.GROW | border | wx.RIGHT) def __init__(self, parent, controller=None, window=None, enable_required=True, scrolling=True): @@ -125,19 +125,19 @@ pageSize_st = wx.StaticText(self.GraphicsPanel, label=_('Page Size (optional):')) - graphicpanel_sizer.AddWindow( + graphicpanel_sizer.Add( pageSize_st, border=10, flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.LEFT | wx.RIGHT) pageSize_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5) pageSize_sizer.AddGrowableCol(1) - graphicpanel_sizer.AddSizer(pageSize_sizer, border=10, + graphicpanel_sizer.Add(pageSize_sizer, border=10, flag=wx.GROW | wx.LEFT | wx.RIGHT) for name, label in [('PageWidth', _('Width:')), ('PageHeight', _('Height:'))]: st = wx.StaticText(self.GraphicsPanel, label=label) - pageSize_sizer.AddWindow(st, border=12, + pageSize_sizer.Add(st, border=12, flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT) sp = wx.SpinCtrl(self.GraphicsPanel, @@ -146,15 +146,15 @@ callback = self.GetPageSizeChangedFunction(sp, name) self.Bind(wx.EVT_TEXT_ENTER, callback, sp) sp.Bind(wx.EVT_KILL_FOCUS, callback) - pageSize_sizer.AddWindow(sp, flag=wx.GROW) + pageSize_sizer.Add(sp, flag=wx.GROW) scaling_st = wx.StaticText(self.GraphicsPanel, label=_('Grid Resolution:')) - graphicpanel_sizer.AddWindow(scaling_st, border=10, + graphicpanel_sizer.Add(scaling_st, border=10, flag=wx.GROW | wx.LEFT | wx.RIGHT) scaling_nb = wx.Notebook(self.GraphicsPanel) - graphicpanel_sizer.AddWindow(scaling_nb, border=10, + graphicpanel_sizer.Add(scaling_nb, border=10, flag=wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT) self.Scalings = {} @@ -173,7 +173,7 @@ border = wx.BOTTOM st = wx.StaticText(scaling_panel, label=label) - scalingpanel_sizer.AddWindow( + scalingpanel_sizer.Add( st, border=10, flag=wx.ALIGN_CENTER_VERTICAL | border | wx.LEFT) @@ -183,7 +183,7 @@ callback = self.GetScalingChangedFunction(sp, language, name) self.Bind(wx.EVT_TEXT_ENTER, callback, sp) sp.Bind(wx.EVT_KILL_FOCUS, callback) - scalingpanel_sizer.AddWindow(sp, border=10, + scalingpanel_sizer.Add(sp, border=10, flag=wx.GROW | border | wx.RIGHT) self.Scalings[language] = scaling_controls @@ -206,18 +206,18 @@ language_label = wx.StaticText(self.MiscellaneousPanel, label=_('Language (optional):')) - miscellaneouspanel_sizer.AddWindow(language_label, border=10, + miscellaneouspanel_sizer.Add(language_label, border=10, flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.LEFT) self.Language = wx.ComboBox(self.MiscellaneousPanel, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnLanguageChanged, self.Language) - miscellaneouspanel_sizer.AddWindow(self.Language, border=10, + miscellaneouspanel_sizer.Add(self.Language, border=10, flag=wx.GROW | wx.TOP | wx.RIGHT) description_label = wx.StaticText( self.MiscellaneousPanel, label=_('Content Description (optional):')) - miscellaneouspanel_sizer.AddWindow(description_label, border=10, + miscellaneouspanel_sizer.Add(description_label, border=10, flag=wx.BOTTOM | wx.LEFT) self.ContentDescription = wx.TextCtrl( @@ -227,7 +227,7 @@ self.ContentDescription) self.ContentDescription.Bind(wx.EVT_KILL_FOCUS, self.OnContentDescriptionChanged) - miscellaneouspanel_sizer.AddWindow(self.ContentDescription, border=10, + miscellaneouspanel_sizer.Add(self.ContentDescription, border=10, flag=wx.GROW | wx.BOTTOM | wx.RIGHT) self.AddPage(self.MiscellaneousPanel, _("Miscellaneous")) diff -r 59158e360b8c -r f5850ce25caf controls/SearchResultPanel.py --- a/controls/SearchResultPanel.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/SearchResultPanel.py Sun Jul 17 22:53:35 2022 +0200 @@ -52,16 +52,16 @@ class SearchResultPanel(wx.Panel): def _init_coll_MainSizer_Items(self, parent): - parent.AddSizer(self.HeaderSizer, 0, border=0, flag=wx.GROW) - parent.AddWindow(self.SearchResultsTree, 1, border=0, flag=wx.GROW) + parent.Add(self.HeaderSizer, 0, border=0, flag=wx.GROW) + parent.Add(self.SearchResultsTree, 1, border=0, flag=wx.GROW) def _init_coll_MainSizer_Growables(self, parent): parent.AddGrowableCol(0) parent.AddGrowableRow(1) def _init_coll_HeaderSizer_Items(self, parent): - parent.AddWindow(self.HeaderLabel, 1, border=5, flag=wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER_VERTICAL) - parent.AddWindow(self.ResetButton, 0, border=0, flag=0) + parent.Add(self.HeaderLabel, 1, border=5, flag=wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER_VERTICAL) + parent.Add(self.ResetButton, 0, border=0, flag=0) def _init_coll_HeaderSizer_Growables(self, parent): parent.AddGrowableCol(0) @@ -90,7 +90,7 @@ self.ResetButton = wx.lib.buttons.GenBitmapButton( self, bitmap=GetBitmap("reset"), size=wx.Size(28, 28), style=wx.NO_BORDER) - self.ResetButton.SetToolTipString(_("Reset search result")) + self.ResetButton.SetToolTip(_("Reset search result")) self.Bind(wx.EVT_BUTTON, self.OnResetButton, self.ResetButton) self._init_sizers() diff -r 59158e360b8c -r f5850ce25caf controls/TextCtrlAutoComplete.py --- a/controls/TextCtrlAutoComplete.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/TextCtrlAutoComplete.py Sun Jul 17 22:53:35 2022 +0200 @@ -97,7 +97,7 @@ parent_rect = wx.Rect(0, -parent_size[1], parent_size[0], parent_size[1]) if selected != wx.NOT_FOUND: wx.CallAfter(self.Parent.SetValueFromSelected, self.ListBox.GetString(selected)) - elif parent_rect.InsideXY(event.GetX(), event.GetY()): + elif parent_rect.Contains(event.GetX(), event.GetY()): result, x, y = self.Parent.HitTest(wx.Point(event.GetX(), event.GetY() + parent_size[1])) if result != wx.TE_HT_UNKNOWN: self.Parent.SetInsertionPoint(self.Parent.XYToPosition(x, y)) diff -r 59158e360b8c -r f5850ce25caf controls/VariablePanel.py --- a/controls/VariablePanel.py Thu Jul 14 11:40:27 2022 +0200 +++ b/controls/VariablePanel.py Sun Jul 17 22:53:35 2022 +0200 @@ -200,8 +200,7 @@ retain=self.Parent.ElementType != "function" and var_class in ["Local", "Input", "Output", "Global"], non_retain=self.Parent.ElementType != "function" and var_class in ["Local", "Input", "Output"]) if len(options) > 1: - editor = wx.grid.GridCellChoiceEditor() - editor.SetParameters(",".join(map(_, options))) + editor = wx.grid.GridCellChoiceEditor(map(_, options)) else: grid.SetReadOnly(row, col, True) elif col != 0 and self._GetRowEdit(row): @@ -212,8 +211,7 @@ elif colname == "Initial Value": if var_class not in ["External", "InOut"]: if self.Parent.Controler.IsEnumeratedType(var_type): - editor = wx.grid.GridCellChoiceEditor() - editor.SetParameters(",".join([""] + self.Parent.Controler.GetEnumeratedDataValues(var_type))) + editor = wx.grid.GridCellChoiceEditor([""] + self.Parent.Controler.GetEnumeratedDataValues(var_type)) else: editor = wx.grid.GridCellTextEditor() renderer = wx.grid.GridCellStringRenderer() @@ -229,11 +227,10 @@ if len(self.Parent.ClassList) == 1: grid.SetReadOnly(row, col, True) else: - editor = wx.grid.GridCellChoiceEditor() excluded = [] if self.Parent.IsFunctionBlockType(var_type): excluded.extend(["Local", "Temp"]) - editor.SetParameters(",".join([_(choice) for choice in self.Parent.ClassList if choice not in excluded])) + editor = wx.grid.GridCellChoiceEditor([_(choice) for choice in self.Parent.ClassList if choice not in excluded]) elif colname != "Documentation": grid.SetReadOnly(row, col, True) @@ -456,32 +453,32 @@ controls_sizer = wx.FlexGridSizer(cols=10, hgap=5, rows=1, vgap=5) controls_sizer.AddGrowableCol(5) controls_sizer.AddGrowableRow(0) - self.MainSizer.AddSizer(controls_sizer, border=5, flag=wx.GROW | wx.ALL) + self.MainSizer.Add(controls_sizer, border=5, flag=wx.GROW | wx.ALL) self.ReturnTypeLabel = wx.StaticText(self, label=_('Return Type:')) - controls_sizer.AddWindow(self.ReturnTypeLabel, flag=wx.ALIGN_CENTER_VERTICAL) + controls_sizer.Add(self.ReturnTypeLabel, flag=wx.ALIGN_CENTER_VERTICAL) self.ReturnType = wx.ComboBox(self, size=wx.Size(145, -1), style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnReturnTypeChanged, self.ReturnType) - controls_sizer.AddWindow(self.ReturnType) + controls_sizer.Add(self.ReturnType) self.DescriptionLabel = wx.StaticText(self, label=_('Description:')) - controls_sizer.AddWindow(self.DescriptionLabel, flag=wx.ALIGN_CENTER_VERTICAL) + controls_sizer.Add(self.DescriptionLabel, flag=wx.ALIGN_CENTER_VERTICAL) self.Description = wx.TextCtrl(self, size=wx.Size(250, -1), style=wx.TE_PROCESS_ENTER) self.Bind(wx.EVT_TEXT_ENTER, self.OnDescriptionChanged, self.Description) self.Description.Bind(wx.EVT_KILL_FOCUS, self.OnDescriptionChanged) - controls_sizer.AddWindow(self.Description) + controls_sizer.Add(self.Description) class_filter_label = wx.StaticText(self, label=_('Class Filter:')) - controls_sizer.AddWindow(class_filter_label, flag=wx.ALIGN_CENTER_VERTICAL) + controls_sizer.Add(class_filter_label, flag=wx.ALIGN_CENTER_VERTICAL) self.ClassFilter = wx.ComboBox(self, size=wx.Size(145, -1), style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnClassFilter, self.ClassFilter) - controls_sizer.AddWindow(self.ClassFilter) + controls_sizer.Add(self.ClassFilter) for name, bitmap, help in [ ("AddButton", "add_element", _("Add variable")), @@ -490,19 +487,19 @@ ("DownButton", "down", _("Move variable down"))]: button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) - button.SetToolTipString(help) + button.SetToolTip(help) setattr(self, name, button) - controls_sizer.AddWindow(button) + controls_sizer.Add(button) self.VariablesGrid = CustomGrid(self, style=wx.VSCROLL | wx.HSCROLL) self.VariablesGrid.SetDropTarget(VariableDropTarget(self)) - self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, + self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGED, self.OnVariablesGridCellChange) self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick) self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown) - self.MainSizer.AddWindow(self.VariablesGrid, flag=wx.GROW) + self.MainSizer.Add(self.VariablesGrid, flag=wx.GROW) self.SetSizer(self.MainSizer) @@ -848,7 +845,7 @@ # build a submenu containing standard IEC types base_menu = wx.Menu(title='') for base_type in self.Controler.GetBaseTypes(): - item = base_menu.Append(wx.ID_ANY, help='', kind=wx.ITEM_NORMAL, text=base_type) + item = base_menu.Append(wx.ID_ANY, helpString='', kind=wx.ITEM_NORMAL, item=base_type) self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(base_type), item) type_menu.AppendMenu(wx.ID_ANY, _("Base Types"), base_menu) @@ -858,7 +855,7 @@ datatype_menu = wx.Menu(title='') datatypes = self.Controler.GetDataTypes(basetypes=False, confnodetypes=False) for datatype in datatypes: - item = datatype_menu.Append(wx.ID_ANY, help='', kind=wx.ITEM_NORMAL, text=datatype) + item = datatype_menu.Append(wx.ID_ANY, helpString='', kind=wx.ITEM_NORMAL, item=datatype) self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(datatype), item) type_menu.AppendMenu(wx.ID_ANY, _("User Data Types"), datatype_menu) @@ -869,7 +866,7 @@ # build a submenu containing confnode types confnode_datatype_menu = wx.Menu(title='') for datatype in category["list"]: - item = confnode_datatype_menu.Append(wx.ID_ANY, help='', kind=wx.ITEM_NORMAL, text=datatype) + item = confnode_datatype_menu.Append(wx.ID_ANY, helpString='', kind=wx.ITEM_NORMAL, item=datatype) self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(datatype), item) type_menu.AppendMenu(wx.ID_ANY, category["name"], confnode_datatype_menu) @@ -883,13 +880,13 @@ functionblock_menu = wx.Menu(title='') fbtypes = self.Controler.GetFunctionBlockTypes(self.TagName) for functionblock_type in fbtypes: - item = functionblock_menu.Append(wx.ID_ANY, help='', kind=wx.ITEM_NORMAL, text=functionblock_type) + item = functionblock_menu.Append(wx.ID_ANY, helpString='', kind=wx.ITEM_NORMAL, item=functionblock_type) self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(functionblock_type), item) type_menu.AppendMenu(wx.ID_ANY, _("Function Block Types"), functionblock_menu) def BuildArrayTypesMenu(self, type_menu): - item = type_menu.Append(wx.ID_ANY, help='', kind=wx.ITEM_NORMAL, text=_("Array")) + item = type_menu.Append(wx.ID_ANY, helpString='', kind=wx.ITEM_NORMAL, item=_("Array")) self.Bind(wx.EVT_MENU, self.VariableArrayTypeFunction, item) def OnVariablesGridEditorShown(self, event): @@ -916,7 +913,7 @@ corner_y = rect.y + self.VariablesGrid.GetColLabelSize() # pop up this new menu - self.VariablesGrid.PopupMenuXY(type_menu, corner_x, corner_y) + self.VariablesGrid.PopupMenu(type_menu, corner_x, corner_y) type_menu.Destroy() event.Veto() value = self.Values[row].Type diff -r 59158e360b8c -r f5850ce25caf dialogs/ActionBlockDialog.py --- a/dialogs/ActionBlockDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/ActionBlockDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -85,29 +85,24 @@ readonly = False colname = self.GetColLabelValue(col, False) if colname == "Qualifier": - editor = wx.grid.GridCellChoiceEditor() - editor.SetParameters(self.Parent.QualifierList) + editor = wx.grid.GridCellChoiceEditor(self.Parent.QualifierList) if colname == "Duration": editor = wx.grid.GridCellTextEditor() renderer = wx.grid.GridCellStringRenderer() readonly = not self.Parent.DurationList[self.data[row].qualifier] elif colname == "Type": - editor = wx.grid.GridCellChoiceEditor() - editor.SetParameters(self.Parent.TypeList) + editor = wx.grid.GridCellChoiceEditor(self.Parent.TypeList) elif colname == "Value": value_type = self.data[row].type if value_type == "Action": - editor = wx.grid.GridCellChoiceEditor() - editor.SetParameters(self.Parent.ActionList) + editor = wx.grid.GridCellChoiceEditor(self.Parent.ActionList) elif value_type == "Variable": - editor = wx.grid.GridCellChoiceEditor() - editor.SetParameters(self.Parent.VariableList) + editor = wx.grid.GridCellChoiceEditor(self.Parent.VariableList) elif value_type == "Inline": editor = wx.grid.GridCellTextEditor() renderer = wx.grid.GridCellStringRenderer() elif colname == "Indicator": - editor = wx.grid.GridCellChoiceEditor() - editor.SetParameters(self.Parent.VariableList) + editor = wx.grid.GridCellChoiceEditor(self.Parent.VariableList) grid.SetCellEditor(row, col, editor) grid.SetCellRenderer(row, col, renderer) @@ -133,11 +128,11 @@ top_sizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0) top_sizer.AddGrowableCol(0) top_sizer.AddGrowableRow(0) - main_sizer.AddSizer(top_sizer, border=20, + main_sizer.Add(top_sizer, border=20, flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT) actions_label = wx.StaticText(self, label=_('Actions:')) - top_sizer.AddWindow(actions_label, flag=wx.ALIGN_BOTTOM) + top_sizer.Add(actions_label, flag=wx.ALIGN_BOTTOM) for name, bitmap, help in [ ("AddButton", "add_element", _("Add action")), @@ -147,21 +142,21 @@ button = wx.lib.buttons.GenBitmapButton( self, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) - button.SetToolTipString(help) + button.SetToolTip(help) setattr(self, name, button) - top_sizer.AddWindow(button) + top_sizer.Add(button) self.ActionsGrid = CustomGrid(self, size=wx.Size(-1, 250), style=wx.VSCROLL) self.ActionsGrid.DisableDragGridSize() self.ActionsGrid.EnableScrolling(False, True) - self.ActionsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, + self.ActionsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGING, self.OnActionsGridCellChange) - main_sizer.AddSizer(self.ActionsGrid, border=20, + main_sizer.Add(self.ActionsGrid, border=20, flag=wx.GROW | wx.LEFT | wx.RIGHT) button_sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE) - self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton()) - main_sizer.AddSizer(button_sizer, border=20, + self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetAffirmativeId()) + main_sizer.Add(button_sizer, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT) self.SetSizer(main_sizer) diff -r 59158e360b8c -r f5850ce25caf dialogs/ArrayTypeDialog.py --- a/dialogs/ArrayTypeDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/ArrayTypeDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -50,31 +50,31 @@ main_sizer.AddGrowableRow(1) top_sizer = wx.BoxSizer(wx.HORIZONTAL) - main_sizer.AddSizer(top_sizer, border=20, + main_sizer.Add(top_sizer, border=20, flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT) basetype_label = wx.StaticText(self, label=_('Base Type:')) - top_sizer.AddWindow(basetype_label, 1, flag=wx.ALIGN_BOTTOM) + top_sizer.Add(basetype_label, 1, flag=wx.ALIGN_BOTTOM) self.BaseType = wx.ComboBox(self, style=wx.CB_READONLY) - top_sizer.AddWindow(self.BaseType, 1, flag=wx.GROW) + top_sizer.Add(self.BaseType, 1, flag=wx.GROW) self.Dimensions = CustomEditableListBox(self, label=_("Dimensions:"), - style=(wx.gizmos.EL_ALLOW_NEW | - wx.gizmos.EL_ALLOW_EDIT | - wx.gizmos.EL_ALLOW_DELETE)) + style=(wx.adv.EL_ALLOW_NEW | + wx.adv.EL_ALLOW_EDIT | + wx.adv.EL_ALLOW_DELETE)) for func in ["_OnLabelEndEdit", "_OnAddButton", "_OnDelButton", "_OnUpButton", "_OnDownButton"]: setattr(self.Dimensions, func, self.OnDimensionsChanged) - main_sizer.AddSizer(self.Dimensions, border=20, + main_sizer.Add(self.Dimensions, border=20, flag=wx.GROW | wx.LEFT | wx.RIGHT) button_sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE) - self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton()) - main_sizer.AddSizer(button_sizer, border=20, + self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetAffirmativeId()) + main_sizer.Add(button_sizer, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT) self.SetSizer(main_sizer) diff -r 59158e360b8c -r f5850ce25caf dialogs/BlockPreviewDialog.py --- a/dialogs/BlockPreviewDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/BlockPreviewDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -75,8 +75,7 @@ # Add default dialog buttons sizer self.ButtonSizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE) - self.Bind(wx.EVT_BUTTON, self.OnOK, - self.ButtonSizer.GetAffirmativeButton()) + self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetAffirmativeId()) self.Element = None # Graphic element to display in preview self.MinElementSize = None # Graphic element minimal size @@ -120,7 +119,7 @@ # Create a sizer for dividing parameters in two columns self.ColumnSizer = wx.BoxSizer(wx.HORIZONTAL) - self.MainSizer.AddSizer(self.ColumnSizer, border=20, + self.MainSizer.Add(self.ColumnSizer, border=20, flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT) # Create a sizer for left column @@ -129,7 +128,7 @@ self.LeftGridSizer.AddGrowableCol(0) if left_growable_row is not None: self.LeftGridSizer.AddGrowableRow(left_growable_row) - self.ColumnSizer.AddSizer(self.LeftGridSizer, 1, border=5, + self.ColumnSizer.Add(self.LeftGridSizer, 1, border=5, flag=wx.GROW | wx.RIGHT | wx.EXPAND) # Create a sizer for right column @@ -138,7 +137,7 @@ self.RightGridSizer.AddGrowableCol(0) if right_growable_row is not None: self.RightGridSizer.AddGrowableRow(right_growable_row) - self.ColumnSizer.AddSizer(self.RightGridSizer, 1, border=5, + self.ColumnSizer.Add(self.RightGridSizer, 1, border=5, flag=wx.GROW | wx.LEFT) self.SetSizer(self.MainSizer) diff -r 59158e360b8c -r f5850ce25caf dialogs/BrowseLocationsDialog.py --- a/dialogs/BrowseLocationsDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/BrowseLocationsDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -76,7 +76,7 @@ main_sizer.AddGrowableRow(1) locations_label = wx.StaticText(self, label=_('Locations available:')) - main_sizer.AddWindow(locations_label, border=20, + main_sizer.Add(locations_label, border=20, flag=wx.TOP | wx.LEFT | wx.RIGHT | wx.GROW) self.LocationsTree = wx.TreeCtrl(self, @@ -88,7 +88,7 @@ self.LocationsTree.SetInitialSize(wx.Size(-1, 300)) self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnLocationsTreeItemActivated, self.LocationsTree) - main_sizer.AddWindow(self.LocationsTree, border=20, + main_sizer.Add(self.LocationsTree, border=20, flag=wx.LEFT | wx.RIGHT | wx.GROW) self.RenameCheckBox = wx.CheckBox(self, label=_("Rename variable to signal name")) @@ -97,37 +97,37 @@ self.RenameCheckBox.SetValue(default_checked) self.do_rename = default_checked - main_sizer.AddWindow(self.RenameCheckBox, border=20, + main_sizer.Add(self.RenameCheckBox, border=20, flag=wx.LEFT | wx.RIGHT | wx.GROW) button_gridsizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0) button_gridsizer.AddGrowableCol(1) button_gridsizer.AddGrowableCol(3) button_gridsizer.AddGrowableRow(0) - main_sizer.AddSizer(button_gridsizer, border=20, + main_sizer.Add(button_gridsizer, border=20, flag=wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.GROW) direction_label = wx.StaticText(self, label=_('Direction:')) - button_gridsizer.AddWindow(direction_label, + button_gridsizer.Add(direction_label, flag=wx.ALIGN_CENTER_VERTICAL) self.DirFilterChoice = wx.ComboBox(self, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnFilterChoice, self.DirFilterChoice) - button_gridsizer.AddWindow(self.DirFilterChoice, + button_gridsizer.Add(self.DirFilterChoice, flag=wx.GROW | wx.ALIGN_CENTER_VERTICAL) filter_label = wx.StaticText(self, label=_('Type:')) - button_gridsizer.AddWindow(filter_label, + button_gridsizer.Add(filter_label, flag=wx.ALIGN_CENTER_VERTICAL) self.TypeFilterChoice = wx.ComboBox(self, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnFilterChoice, self.TypeFilterChoice) - button_gridsizer.AddWindow(self.TypeFilterChoice, + button_gridsizer.Add(self.TypeFilterChoice, flag=wx.GROW | wx.ALIGN_CENTER_VERTICAL) button_sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE) - self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton()) - button_gridsizer.AddSizer(button_sizer, flag=wx.ALIGN_RIGHT) + self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetAffirmativeId()) + button_gridsizer.Add(button_sizer, flag=wx.ALIGN_RIGHT) self.SetSizer(main_sizer) diff -r 59158e360b8c -r f5850ce25caf dialogs/BrowseValuesLibraryDialog.py --- a/dialogs/BrowseValuesLibraryDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/BrowseValuesLibraryDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -51,13 +51,13 @@ self.ButtonSizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE) - self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetAffirmativeButton().GetId()) + self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetAffirmativeId()) self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10) - self.flexGridSizer1.AddWindow(self.staticText1, 0, border=20, flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT) - self.flexGridSizer1.AddWindow(self.ValuesLibrary, 0, border=20, flag=wx.GROW | wx.LEFT | wx.RIGHT) - self.flexGridSizer1.AddSizer(self.ButtonSizer, 0, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT) + self.flexGridSizer1.Add(self.staticText1, 0, border=20, flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT) + self.flexGridSizer1.Add(self.ValuesLibrary, 0, border=20, flag=wx.GROW | wx.LEFT | wx.RIGHT) + self.flexGridSizer1.Add(self.ButtonSizer, 0, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT) self.flexGridSizer1.AddGrowableCol(0) self.flexGridSizer1.AddGrowableRow(1) diff -r 59158e360b8c -r f5850ce25caf dialogs/ConnectionDialog.py --- a/dialogs/ConnectionDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/ConnectionDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -59,7 +59,7 @@ # Create label for connection type type_label = wx.StaticText(self, label=_('Type:')) - self.LeftGridSizer.AddWindow(type_label, flag=wx.GROW) + self.LeftGridSizer.Add(type_label, flag=wx.GROW) # Create radio buttons for selecting connection type self.TypeRadioButtons = {} @@ -70,39 +70,39 @@ style=(wx.RB_GROUP if first else 0)) radio_button.SetValue(first) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, radio_button) - self.LeftGridSizer.AddWindow(radio_button, flag=wx.GROW) + self.LeftGridSizer.Add(radio_button, flag=wx.GROW) self.TypeRadioButtons[type] = radio_button first = False # Create label for connection name name_label = wx.StaticText(self, label=_('Name:')) - self.LeftGridSizer.AddWindow(name_label, flag=wx.GROW) + self.LeftGridSizer.Add(name_label, flag=wx.GROW) # Create text control for defining connection name self.ConnectionName = wx.TextCtrl(self) self.ConnectionName.SetMinSize(wx.Size(200, -1)) self.Bind(wx.EVT_TEXT, self.OnNameChanged, self.ConnectionName) - self.LeftGridSizer.AddWindow(self.ConnectionName, flag=wx.GROW) + self.LeftGridSizer.Add(self.ConnectionName, flag=wx.GROW) # Add preview panel and associated label to sizers self.Preview.SetMinSize(wx.Size(-1, 100)) - self.LeftGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW) - self.LeftGridSizer.AddWindow(self.Preview, flag=wx.GROW) + self.LeftGridSizer.Add(self.PreviewLabel, flag=wx.GROW) + self.LeftGridSizer.Add(self.Preview, flag=wx.GROW) # Add buttons sizer to sizers - self.MainSizer.AddSizer( + self.MainSizer.Add( self.ButtonSizer, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT) - self.ColumnSizer.RemoveSizer(self.RightGridSizer) + self.ColumnSizer.Remove(self.RightGridSizer) # Add button for applying connection name modification to all connection # of POU if apply_button: self.ApplyToAllButton = wx.Button(self, label=_("Propagate Name")) - self.ApplyToAllButton.SetToolTipString( + self.ApplyToAllButton.SetToolTip( _("Apply name modification to all continuations with the same name")) self.Bind(wx.EVT_BUTTON, self.OnApplyToAll, self.ApplyToAllButton) - self.ButtonSizer.AddWindow(self.ApplyToAllButton, flag=wx.LEFT) + self.ButtonSizer.Add(self.ApplyToAllButton, flag=wx.LEFT) else: self.ConnectionName.ChangeValue( controller.GenerateNewName( diff -r 59158e360b8c -r f5850ce25caf dialogs/DurationEditorDialog.py --- a/dialogs/DurationEditorDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/DurationEditorDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -68,7 +68,7 @@ main_sizer.AddGrowableRow(0) controls_sizer = wx.FlexGridSizer(cols=len(CONTROLS), hgap=10, rows=2, vgap=10) - main_sizer.AddSizer(controls_sizer, border=20, + main_sizer.Add(controls_sizer, border=20, flag=wx.TOP | wx.LEFT | wx.RIGHT | wx.GROW) controls = [] @@ -85,14 +85,14 @@ controls.append((st, txtctrl)) for st, txtctrl in controls: - controls_sizer.AddWindow(st, flag=wx.GROW) + controls_sizer.Add(st, flag=wx.GROW) for st, txtctrl in controls: - controls_sizer.AddWindow(txtctrl, flag=wx.GROW) + controls_sizer.Add(txtctrl, flag=wx.GROW) button_sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE) - self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton()) - main_sizer.AddSizer(button_sizer, border=20, + self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetAffirmativeId()) + main_sizer.Add(button_sizer, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT) self.SetSizer(main_sizer) @@ -153,6 +153,7 @@ return duration def OnOK(self, event): + event.Skip() self.OnCloseDialog() def OnCloseDialog(self): diff -r 59158e360b8c -r f5850ce25caf dialogs/FBDBlockDialog.py --- a/dialogs/FBDBlockDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/FBDBlockDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -68,7 +68,7 @@ # Create static box around library panel type_staticbox = wx.StaticBox(self, label=_('Type:')) left_staticboxsizer = wx.StaticBoxSizer(type_staticbox, wx.VERTICAL) - self.LeftGridSizer.AddSizer(left_staticboxsizer, border=5, flag=wx.GROW) + self.LeftGridSizer.Add(left_staticboxsizer, border=5, flag=wx.GROW) # Create Library panel and add it to static box self.LibraryPanel = LibraryPanel(self) @@ -77,65 +77,65 @@ # Set function to call when selection in Library panel changed setattr(self.LibraryPanel, "_OnTreeItemSelected", self.OnLibraryTreeItemSelected) - left_staticboxsizer.AddWindow(self.LibraryPanel, 1, border=5, + left_staticboxsizer.Add(self.LibraryPanel, 1, border=5, flag=wx.GROW | wx.TOP) # Create sizer for other block parameters top_right_gridsizer = wx.FlexGridSizer(cols=2, hgap=0, rows=4, vgap=5) top_right_gridsizer.AddGrowableCol(1) - self.RightGridSizer.AddSizer(top_right_gridsizer, flag=wx.GROW) + self.RightGridSizer.Add(top_right_gridsizer, flag=wx.GROW) # Create label for block name name_label = wx.StaticText(self, label=_('Name:')) - top_right_gridsizer.AddWindow(name_label, + top_right_gridsizer.Add(name_label, flag=wx.ALIGN_CENTER_VERTICAL) # Create text control for defining block name self.BlockName = wx.TextCtrl(self) self.Bind(wx.EVT_TEXT, self.OnNameChanged, self.BlockName) - top_right_gridsizer.AddWindow(self.BlockName, flag=wx.GROW) + top_right_gridsizer.Add(self.BlockName, flag=wx.GROW) # Create label for extended block input number inputs_label = wx.StaticText(self, label=_('Inputs:')) - top_right_gridsizer.AddWindow(inputs_label, + top_right_gridsizer.Add(inputs_label, flag=wx.ALIGN_CENTER_VERTICAL) # Create spin control for defining extended block input number self.Inputs = wx.SpinCtrl(self, min=2, max=20, style=wx.SP_ARROW_KEYS) self.Bind(wx.EVT_SPINCTRL, self.OnInputsChanged, self.Inputs) - top_right_gridsizer.AddWindow(self.Inputs, flag=wx.GROW) + top_right_gridsizer.Add(self.Inputs, flag=wx.GROW) # Create label for block execution order execution_order_label = wx.StaticText(self, label=_('Execution Order:')) - top_right_gridsizer.AddWindow(execution_order_label, + top_right_gridsizer.Add(execution_order_label, flag=wx.ALIGN_CENTER_VERTICAL) # Create spin control for defining block execution order self.ExecutionOrder = wx.SpinCtrl(self, min=0, style=wx.SP_ARROW_KEYS) self.Bind(wx.EVT_SPINCTRL, self.OnExecutionOrderChanged, self.ExecutionOrder) - top_right_gridsizer.AddWindow(self.ExecutionOrder, flag=wx.GROW) + top_right_gridsizer.Add(self.ExecutionOrder, flag=wx.GROW) # Create label for block execution control execution_control_label = wx.StaticText(self, label=_('Execution Control:')) - top_right_gridsizer.AddWindow(execution_control_label, + top_right_gridsizer.Add(execution_control_label, flag=wx.ALIGN_CENTER_VERTICAL) # Create check box to enable block execution control self.ExecutionControl = wx.CheckBox(self) self.Bind(wx.EVT_CHECKBOX, self.OnExecutionOrderChanged, self.ExecutionControl) - top_right_gridsizer.AddWindow(self.ExecutionControl, flag=wx.GROW) + top_right_gridsizer.Add(self.ExecutionControl, flag=wx.GROW) # Add preview panel and associated label to sizers - self.RightGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW) - self.RightGridSizer.AddWindow(self.Preview, flag=wx.GROW) + self.RightGridSizer.Add(self.PreviewLabel, flag=wx.GROW) + self.RightGridSizer.Add(self.Preview, flag=wx.GROW) # Add buttons sizer to sizers - self.MainSizer.AddSizer(self.ButtonSizer, border=20, + self.MainSizer.Add(self.ButtonSizer, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT) # Dictionary containing correspondence between parameter exchanged and diff -r 59158e360b8c -r f5850ce25caf dialogs/FBDVariableDialog.py --- a/dialogs/FBDVariableDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/FBDVariableDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -73,49 +73,49 @@ # Create label for variable class class_label = wx.StaticText(self, label=_('Class:')) - self.LeftGridSizer.AddWindow(class_label, flag=wx.GROW) + self.LeftGridSizer.Add(class_label, flag=wx.GROW) # Create a combo box for defining variable class self.Class = wx.ComboBox(self, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnClassChanged, self.Class) - self.LeftGridSizer.AddWindow(self.Class, flag=wx.GROW) + self.LeftGridSizer.Add(self.Class, flag=wx.GROW) # Create label for variable execution order execution_order_label = wx.StaticText(self, label=_('Execution Order:')) - self.LeftGridSizer.AddWindow(execution_order_label, flag=wx.GROW) + self.LeftGridSizer.Add(execution_order_label, flag=wx.GROW) # Create spin control for defining variable execution order self.ExecutionOrder = wx.SpinCtrl(self, min=0, style=wx.SP_ARROW_KEYS) self.Bind(wx.EVT_SPINCTRL, self.OnExecutionOrderChanged, self.ExecutionOrder) - self.LeftGridSizer.AddWindow(self.ExecutionOrder, flag=wx.GROW) + self.LeftGridSizer.Add(self.ExecutionOrder, flag=wx.GROW) # Create label for variable expression name_label = wx.StaticText(self, label=_('Expression:')) - self.RightGridSizer.AddWindow(name_label, border=5, + self.RightGridSizer.Add(name_label, border=5, flag=wx.GROW | wx.BOTTOM) # Create text control for defining variable expression self.Expression = wx.TextCtrl(self) self.Bind(wx.EVT_TEXT, self.OnExpressionChanged, self.Expression) - self.RightGridSizer.AddWindow(self.Expression, flag=wx.GROW) + self.RightGridSizer.Add(self.Expression, flag=wx.GROW) # Create a list box to selected variable expression in the list of # variables defined in POU self.VariableName = wx.ListBox(self, size=wx.Size(-1, 120), style=wx.LB_SINGLE | wx.LB_SORT) self.Bind(wx.EVT_LISTBOX, self.OnNameChanged, self.VariableName) - self.RightGridSizer.AddWindow(self.VariableName, border=4, flag=wx.GROW | wx.TOP) + self.RightGridSizer.Add(self.VariableName, border=4, flag=wx.GROW | wx.TOP) # Add preview panel and associated label to sizers - self.MainSizer.AddWindow(self.PreviewLabel, border=20, + self.MainSizer.Add(self.PreviewLabel, border=20, flag=wx.GROW | wx.LEFT | wx.RIGHT) - self.MainSizer.AddWindow(self.Preview, border=20, + self.MainSizer.Add(self.Preview, border=20, flag=wx.GROW | wx.LEFT | wx.RIGHT) # Add buttons sizer to sizers - self.MainSizer.AddSizer( + self.MainSizer.Add( self.ButtonSizer, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT) diff -r 59158e360b8c -r f5850ce25caf dialogs/FindInPouDialog.py --- a/dialogs/FindInPouDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/FindInPouDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -48,76 +48,76 @@ main_sizer.AddGrowableRow(0) controls_sizer = wx.BoxSizer(wx.VERTICAL) - main_sizer.AddSizer(controls_sizer, border=20, + main_sizer.Add(controls_sizer, border=20, flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT) patterns_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=1, vgap=5) patterns_sizer.AddGrowableCol(1) - controls_sizer.AddSizer(patterns_sizer, border=5, flag=wx.GROW | wx.BOTTOM) + controls_sizer.Add(patterns_sizer, border=5, flag=wx.GROW | wx.BOTTOM) find_label = wx.StaticText(panel, label=_("Find:")) - patterns_sizer.AddWindow(find_label, flag=wx.ALIGN_CENTER_VERTICAL) + patterns_sizer.Add(find_label, flag=wx.ALIGN_CENTER_VERTICAL) self.FindPattern = wx.TextCtrl(panel) self.Bind(wx.EVT_TEXT, self.OnFindPatternChanged, self.FindPattern) self.Bind(wx.EVT_CHAR_HOOK, self.OnEscapeKey) - patterns_sizer.AddWindow(self.FindPattern, flag=wx.GROW) + patterns_sizer.Add(self.FindPattern, flag=wx.GROW) params_sizer = wx.BoxSizer(wx.HORIZONTAL) - controls_sizer.AddSizer(params_sizer, border=5, flag=wx.GROW | wx.BOTTOM) + controls_sizer.Add(params_sizer, border=5, flag=wx.GROW | wx.BOTTOM) direction_staticbox = wx.StaticBox(panel, label=_("Direction")) direction_staticboxsizer = wx.StaticBoxSizer( direction_staticbox, wx.VERTICAL) - params_sizer.AddSizer(direction_staticboxsizer, 1, border=5, + params_sizer.Add(direction_staticboxsizer, 1, border=5, flag=wx.GROW | wx.RIGHT) self.Forward = wx.RadioButton(panel, label=_("Forward"), style=wx.RB_GROUP) - direction_staticboxsizer.AddWindow(self.Forward, border=5, + direction_staticboxsizer.Add(self.Forward, border=5, flag=wx.ALL | wx.GROW) self.Backward = wx.RadioButton(panel, label=_("Backward")) - direction_staticboxsizer.AddWindow(self.Backward, border=5, + direction_staticboxsizer.Add(self.Backward, border=5, flag=wx.ALL | wx.GROW) options_staticbox = wx.StaticBox(panel, label=_("Options")) options_staticboxsizer = wx.StaticBoxSizer( options_staticbox, wx.VERTICAL) - params_sizer.AddSizer(options_staticboxsizer, 1, flag=wx.GROW) + params_sizer.Add(options_staticboxsizer, 1, flag=wx.GROW) self.CaseSensitive = wx.CheckBox(panel, label=_("Case sensitive")) self.CaseSensitive.SetValue(True) - options_staticboxsizer.AddWindow(self.CaseSensitive, border=5, + options_staticboxsizer.Add(self.CaseSensitive, border=5, flag=wx.ALL | wx.GROW) self.WrapSearch = wx.CheckBox(panel, label=_("Wrap search")) self.WrapSearch.SetValue(True) - options_staticboxsizer.AddWindow(self.WrapSearch, border=5, + options_staticboxsizer.Add(self.WrapSearch, border=5, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.GROW) self.RegularExpressions = wx.CheckBox(panel, label=_("Regular expressions")) - options_staticboxsizer.AddWindow(self.RegularExpressions, border=5, + options_staticboxsizer.Add(self.RegularExpressions, border=5, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.GROW) buttons_sizer = wx.BoxSizer(wx.HORIZONTAL) - main_sizer.AddSizer(buttons_sizer, border=20, + main_sizer.Add(buttons_sizer, border=20, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.ALIGN_RIGHT) self.FindButton = wx.Button(panel, label=_("Find")) self.FindButton.SetDefault() self.Bind(wx.EVT_BUTTON, self.OnFindButton, self.FindButton) - buttons_sizer.AddWindow(self.FindButton, border=5, flag=wx.RIGHT) + buttons_sizer.Add(self.FindButton, border=5, flag=wx.RIGHT) self.CloseButton = wx.Button(panel, label=_("Close")) self.Bind(wx.EVT_BUTTON, self.OnCloseButton, self.CloseButton) - buttons_sizer.AddWindow(self.CloseButton) + buttons_sizer.Add(self.CloseButton) # set the longest message here, to use it length to calculate # optimal size of dialog window self.RegExpSyntaxErrMsg = _("Syntax error in regular expression of pattern to search!") self.StatusLabel = wx.StaticText(panel, label=self.RegExpSyntaxErrMsg) - controls_sizer.AddWindow(self.StatusLabel, flag=wx.ALIGN_CENTER_VERTICAL) + controls_sizer.Add(self.StatusLabel) panel.SetSizer(main_sizer) main_sizer.Fit(self) diff -r 59158e360b8c -r f5850ce25caf dialogs/ForceVariableDialog.py --- a/dialogs/ForceVariableDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/ForceVariableDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -189,7 +189,7 @@ info_sizer = wx.BoxSizer(wx.VERTICAL) message_label = wx.StaticText(self, label=_("Forcing Variable Value")) - info_sizer.AddWindow(message_label, border=10, + info_sizer.Add(message_label, border=10, flag=wx.ALIGN_LEFT | wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT) if GetTypeValue[self.IEC_Type] in [getinteger, getfloat]: @@ -201,8 +201,8 @@ self.GetEnteredValue = self.GetValueDefault button_sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE) - self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton()) - info_sizer.AddSizer(button_sizer, border=10, flag=wx.ALIGN_RIGHT | wx.ALL) + self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetAffirmativeId()) + info_sizer.Add(button_sizer, border=10, flag=wx.ALIGN_RIGHT | wx.ALL) self.SetSizer(info_sizer) self.Fit() @@ -216,7 +216,7 @@ """Add simple text control to change variable of any type""" self.ValueCtrl = wx.TextCtrl(self) self.ValueCtrl.SetValue(defaultValue) - info_sizer.AddWindow(self.ValueCtrl, border=10, proportion=1, + info_sizer.Add(self.ValueCtrl, border=10, proportion=1, flag=wx.ALIGN_LEFT | wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT) def GetValueDefault(self): @@ -235,11 +235,11 @@ sizer = wx.BoxSizer(wx.HORIZONTAL) self.InitCtrlDefault(sizer, defaultValue) self.SpinButtonCtrl = wx.SpinButton(self, style=wx.HORIZONTAL | wx.SP_WRAP) - sizer.AddWindow(self.SpinButtonCtrl, border=10, + sizer.Add(self.SpinButtonCtrl, border=10, flag=wx.ALIGN_LEFT | wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT | wx.EXPAND) self.Bind(wx.EVT_SPIN_UP, self.SpinButtonChanged) self.Bind(wx.EVT_SPIN_DOWN, self.SpinButtonChanged) - info_sizer.AddWindow(sizer, proportion=1, flag=wx.EXPAND) + info_sizer.Add(sizer, proportion=1, flag=wx.EXPAND) def SpinButtonChanged(self, evt): """Increment/decrement variable value""" @@ -261,7 +261,7 @@ if value is not None: self.ValueCtrl.SetValue(value) - info_sizer.AddWindow(self.ValueCtrl, border=10, + info_sizer.Add(self.ValueCtrl, border=10, flag=wx.ALIGN_LEFT | wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT | wx.GROW) def OnOK(self, event): diff -r 59158e360b8c -r f5850ce25caf dialogs/IDMergeDialog.py --- a/dialogs/IDMergeDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/IDMergeDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -15,11 +15,11 @@ main_sizer = wx.BoxSizer(wx.VERTICAL) message = wx.StaticText(self, label=question) - main_sizer.AddWindow(message, border=20, + main_sizer.Add(message, border=20, flag=wx.ALIGN_CENTER_HORIZONTAL | wx.TOP | wx.LEFT | wx.RIGHT) self.check = wx.CheckBox(self, label=optiontext) - main_sizer.AddWindow(self.check, border=20, + main_sizer.Add(self.check, border=20, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.ALIGN_CENTER_HORIZONTAL) buttons_sizer = wx.BoxSizer(wx.HORIZONTAL) @@ -30,9 +30,9 @@ return lambda event: self.EndModal(_wxID) self.Bind(wx.EVT_BUTTON, OnButtonFactory(wxID), Button) - buttons_sizer.AddWindow(Button) + buttons_sizer.Add(Button) - main_sizer.AddSizer(buttons_sizer, border=20, + main_sizer.Add(buttons_sizer, border=20, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.ALIGN_RIGHT) self.SetSizer(main_sizer) diff -r 59158e360b8c -r f5850ce25caf dialogs/LDElementDialog.py --- a/dialogs/LDElementDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/LDElementDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -63,7 +63,7 @@ # Create label for LD element modifier modifier_label = wx.StaticText(self, label=_('Modifier:')) - self.LeftGridSizer.AddWindow(modifier_label, border=5, + self.LeftGridSizer.Add(modifier_label, border=5, flag=wx.GROW | wx.BOTTOM) # Create radio buttons for selecting LD element modifier @@ -84,13 +84,13 @@ style=(wx.RB_GROUP if first else 0)) radio_button.SetValue(first) self.Bind(wx.EVT_RADIOBUTTON, self.OnModifierChanged, radio_button) - self.LeftGridSizer.AddWindow(radio_button, flag=wx.GROW) + self.LeftGridSizer.Add(radio_button, flag=wx.GROW) self.ModifierRadioButtons[modifier] = radio_button first = False # Create label for LD element variable element_variable_label = wx.StaticText(self, label=_('Variable:')) - self.LeftGridSizer.AddWindow(element_variable_label, border=5, + self.LeftGridSizer.Add(element_variable_label, border=5, flag=wx.GROW | wx.TOP) # Create a combo box for defining LD element variable @@ -99,15 +99,15 @@ self.ElementVariable) self.Bind(wx.EVT_TEXT, self.OnVariableChanged, self.ElementVariable) - self.LeftGridSizer.AddWindow(self.ElementVariable, border=5, + self.LeftGridSizer.Add(self.ElementVariable, border=5, flag=wx.GROW | wx.TOP) # Add preview panel and associated label to sizers - self.RightGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW) - self.RightGridSizer.AddWindow(self.Preview, flag=wx.GROW) + self.RightGridSizer.Add(self.PreviewLabel, flag=wx.GROW) + self.RightGridSizer.Add(self.Preview, flag=wx.GROW) # Add buttons sizer to sizers - self.MainSizer.AddSizer(self.ButtonSizer, border=20, + self.MainSizer.Add(self.ButtonSizer, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT) # Save LD element class @@ -198,8 +198,9 @@ self.GetElementModifier(), value) - button = self.ButtonSizer.GetAffirmativeButton() - button.Enable(value != "") + # FIXME : how to disable OK button when content is not valid + # button = self.ButtonSizer.GetAffirmativeButton() + # button.Enable(value != "") # Call BlockPreviewDialog function BlockPreviewDialog.DrawPreview(self) diff -r 59158e360b8c -r f5850ce25caf dialogs/LDPowerRailDialog.py --- a/dialogs/LDPowerRailDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/LDPowerRailDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -56,7 +56,7 @@ # Create label for connection type type_label = wx.StaticText(self, label=_('Type:')) - self.LeftGridSizer.AddWindow(type_label, flag=wx.GROW) + self.LeftGridSizer.Add(type_label, flag=wx.GROW) # Create radio buttons for selecting power rail type self.TypeRadioButtons = {} @@ -67,27 +67,27 @@ style=(wx.RB_GROUP if first else 0)) radio_button.SetValue(first) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, radio_button) - self.LeftGridSizer.AddWindow(radio_button, flag=wx.GROW) + self.LeftGridSizer.Add(radio_button, flag=wx.GROW) self.TypeRadioButtons[type] = radio_button first = False # Create label for power rail pin number pin_number_label = wx.StaticText(self, label=_('Pin number:')) - self.LeftGridSizer.AddWindow(pin_number_label, flag=wx.GROW) + self.LeftGridSizer.Add(pin_number_label, flag=wx.GROW) # Create spin control for defining power rail pin number self.PinNumber = wx.SpinCtrl(self, min=1, max=50, style=wx.SP_ARROW_KEYS) self.PinNumber.SetValue(1) self.Bind(wx.EVT_SPINCTRL, self.OnPinNumberChanged, self.PinNumber) - self.LeftGridSizer.AddWindow(self.PinNumber, flag=wx.GROW) + self.LeftGridSizer.Add(self.PinNumber, flag=wx.GROW) # Add preview panel and associated label to sizers - self.RightGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW) - self.RightGridSizer.AddWindow(self.Preview, flag=wx.GROW) + self.RightGridSizer.Add(self.PreviewLabel, flag=wx.GROW) + self.RightGridSizer.Add(self.Preview, flag=wx.GROW) # Add buttons sizer to sizers - self.MainSizer.AddSizer( + self.MainSizer.Add( self.ButtonSizer, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT) self.Fit() diff -r 59158e360b8c -r f5850ce25caf dialogs/PouActionDialog.py --- a/dialogs/PouActionDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/PouActionDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -50,27 +50,26 @@ infos_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=3, vgap=15) infos_sizer.AddGrowableCol(1) - main_sizer.AddSizer(infos_sizer, border=20, + main_sizer.Add(infos_sizer, border=20, flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT) actionname_label = wx.StaticText(self, label=_('Action Name:')) - infos_sizer.AddWindow(actionname_label, border=4, + infos_sizer.Add(actionname_label, border=4, flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP) self.ActionName = wx.TextCtrl(self, size=wx.Size(180, -1)) - infos_sizer.AddWindow(self.ActionName, flag=wx.GROW) + infos_sizer.Add(self.ActionName, flag=wx.GROW) language_label = wx.StaticText(self, label=_('Language:')) - infos_sizer.AddWindow(language_label, border=4, + infos_sizer.Add(language_label, border=4, flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP) self.Language = wx.ComboBox(self, style=wx.CB_READONLY) - infos_sizer.AddWindow(self.Language, flag=wx.GROW) + infos_sizer.Add(self.Language, flag=wx.GROW) button_sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE) - self.Bind(wx.EVT_BUTTON, self.OnOK, - button_sizer.GetAffirmativeButton()) - main_sizer.AddSizer(button_sizer, border=20, + self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetAffirmativeId()) + main_sizer.Add(button_sizer, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT) self.SetSizer(main_sizer) diff -r 59158e360b8c -r f5850ce25caf dialogs/PouDialog.py --- a/dialogs/PouDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/PouDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -58,34 +58,34 @@ infos_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=3, vgap=15) infos_sizer.AddGrowableCol(1) - main_sizer.AddSizer(infos_sizer, border=20, + main_sizer.Add(infos_sizer, border=20, flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT) pouname_label = wx.StaticText(self, label=_('POU Name:')) - infos_sizer.AddWindow(pouname_label, border=4, + infos_sizer.Add(pouname_label, border=4, flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP) self.PouName = wx.TextCtrl(self) - infos_sizer.AddWindow(self.PouName, flag=wx.GROW) + infos_sizer.Add(self.PouName, flag=wx.GROW) poutype_label = wx.StaticText(self, label=_('POU Type:')) - infos_sizer.AddWindow(poutype_label, border=4, + infos_sizer.Add(poutype_label, border=4, flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP) self.PouType = wx.ComboBox(self, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnTypeChanged, self.PouType) - infos_sizer.AddWindow(self.PouType, flag=wx.GROW) + infos_sizer.Add(self.PouType, flag=wx.GROW) language_label = wx.StaticText(self, label=_('Language:')) - infos_sizer.AddWindow(language_label, border=4, + infos_sizer.Add(language_label, border=4, flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP) self.Language = wx.ComboBox(self, style=wx.CB_READONLY) - infos_sizer.AddWindow(self.Language, flag=wx.GROW) + infos_sizer.Add(self.Language, flag=wx.GROW) button_sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE) - self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton()) - main_sizer.AddSizer(button_sizer, border=20, + self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetAffirmativeId()) + main_sizer.Add(button_sizer, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT) self.SetSizer(main_sizer) diff -r 59158e360b8c -r f5850ce25caf dialogs/PouNameDialog.py --- a/dialogs/PouNameDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/PouNameDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -40,8 +40,7 @@ self.PouNames = [] - self.Bind(wx.EVT_BUTTON, self.OnOK, - self.GetSizer().GetItem(2).GetSizer().GetItem(1).GetSizer().GetAffirmativeButton()) + self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetAffirmativeId()) def OnOK(self, event): message = None diff -r 59158e360b8c -r f5850ce25caf dialogs/PouTransitionDialog.py --- a/dialogs/PouTransitionDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/PouTransitionDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -53,26 +53,26 @@ infos_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=3, vgap=10) infos_sizer.AddGrowableCol(1) - main_sizer.AddSizer(infos_sizer, border=20, + main_sizer.Add(infos_sizer, border=20, flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT) transitionname_label = wx.StaticText(self, label=_('Transition Name:')) - infos_sizer.AddWindow(transitionname_label, border=4, + infos_sizer.Add(transitionname_label, border=4, flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP) self.TransitionName = wx.TextCtrl(self, size=wx.Size(180, -1)) - infos_sizer.AddWindow(self.TransitionName, flag=wx.GROW) + infos_sizer.Add(self.TransitionName, flag=wx.GROW) language_label = wx.StaticText(self, label=_('Language:')) - infos_sizer.AddWindow(language_label, border=4, + infos_sizer.Add(language_label, border=4, flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP) self.Language = wx.ComboBox(self, style=wx.CB_READONLY) - infos_sizer.AddWindow(self.Language, flag=wx.GROW) + infos_sizer.Add(self.Language, flag=wx.GROW) button_sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE) - self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton()) - main_sizer.AddSizer(button_sizer, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM) + self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetAffirmativeId()) + main_sizer.Add(button_sizer, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM) self.SetSizer(main_sizer) diff -r 59158e360b8c -r f5850ce25caf dialogs/ProjectDialog.py --- a/dialogs/ProjectDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/ProjectDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -42,12 +42,11 @@ self.ProjectProperties = ProjectPropertiesPanel( self, enable_required=enable_required, scrolling=False) - main_sizer.AddWindow(self.ProjectProperties, flag=wx.GROW) + main_sizer.Add(self.ProjectProperties, flag=wx.GROW) self.ButtonSizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE) - self.Bind(wx.EVT_BUTTON, self.OnOK, - self.ButtonSizer.GetAffirmativeButton()) - main_sizer.AddSizer(self.ButtonSizer, border=20, + self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetAffirmativeId()) + main_sizer.Add(self.ButtonSizer, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT) self.SetSizer(main_sizer) diff -r 59158e360b8c -r f5850ce25caf dialogs/SFCDivergenceDialog.py --- a/dialogs/SFCDivergenceDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/SFCDivergenceDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -58,7 +58,7 @@ # Create label for divergence type type_label = wx.StaticText(self, label=_('Type:')) - self.LeftGridSizer.AddWindow(type_label, flag=wx.GROW) + self.LeftGridSizer.Add(type_label, flag=wx.GROW) # Create radio buttons for selecting divergence type divergence_buttons = [ @@ -80,7 +80,7 @@ style=(wx.RB_GROUP if first else 0)) radio_button.SetValue(first) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, radio_button) - self.LeftGridSizer.AddWindow(radio_button, flag=wx.GROW) + self.LeftGridSizer.Add(radio_button, flag=wx.GROW) self.TypeRadioButtons[type] = radio_button if first: focusbtn = type @@ -89,19 +89,19 @@ # Create label for number of divergence sequences sequences_label = wx.StaticText(self, label=_('Number of sequences:')) - self.LeftGridSizer.AddWindow(sequences_label, flag=wx.GROW) + self.LeftGridSizer.Add(sequences_label, flag=wx.GROW) # Create spin control for defining number of divergence sequences self.Sequences = wx.SpinCtrl(self, min=2, max=20, initial=2) self.Bind(wx.EVT_SPINCTRL, self.OnSequencesChanged, self.Sequences) - self.LeftGridSizer.AddWindow(self.Sequences, flag=wx.GROW) + self.LeftGridSizer.Add(self.Sequences, flag=wx.GROW) # Add preview panel and associated label to sizers - self.RightGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW) - self.RightGridSizer.AddWindow(self.Preview, flag=wx.GROW) + self.RightGridSizer.Add(self.PreviewLabel, flag=wx.GROW) + self.RightGridSizer.Add(self.Preview, flag=wx.GROW) # Add buttons sizer to sizers - self.MainSizer.AddSizer( + self.MainSizer.Add( self.ButtonSizer, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT) diff -r 59158e360b8c -r f5850ce25caf dialogs/SFCStepDialog.py --- a/dialogs/SFCStepDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/SFCStepDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -57,16 +57,16 @@ # Create label for SFC step name name_label = wx.StaticText(self, label=_('Name:')) - self.LeftGridSizer.AddWindow(name_label, flag=wx.GROW) + self.LeftGridSizer.Add(name_label, flag=wx.GROW) # Create text control for defining SFC step name self.StepName = wx.TextCtrl(self) self.Bind(wx.EVT_TEXT, self.OnNameChanged, self.StepName) - self.LeftGridSizer.AddWindow(self.StepName, flag=wx.GROW) + self.LeftGridSizer.Add(self.StepName, flag=wx.GROW) # Create label for SFC step connectors connectors_label = wx.StaticText(self, label=_('Connectors:')) - self.LeftGridSizer.AddWindow(connectors_label, flag=wx.GROW) + self.LeftGridSizer.Add(connectors_label, flag=wx.GROW) # Create check boxes for defining connectors available on SFC step self.ConnectorsCheckBox = {} @@ -77,15 +77,15 @@ if name == "output" or (name == "input" and not initial): check_box.SetValue(True) self.Bind(wx.EVT_CHECKBOX, self.OnConnectorsChanged, check_box) - self.LeftGridSizer.AddWindow(check_box, flag=wx.GROW) + self.LeftGridSizer.Add(check_box, flag=wx.GROW) self.ConnectorsCheckBox[name] = check_box # Add preview panel and associated label to sizers - self.RightGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW) - self.RightGridSizer.AddWindow(self.Preview, flag=wx.GROW) + self.RightGridSizer.Add(self.PreviewLabel, flag=wx.GROW) + self.RightGridSizer.Add(self.Preview, flag=wx.GROW) # Add buttons sizer to sizers - self.MainSizer.AddSizer( + self.MainSizer.Add( self.ButtonSizer, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT) diff -r 59158e360b8c -r f5850ce25caf dialogs/SFCStepNameDialog.py --- a/dialogs/SFCStepNameDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/SFCStepNameDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -42,8 +42,7 @@ self.Variables = [] self.StepNames = [] - self.Bind(wx.EVT_BUTTON, self.OnOK, - self.GetSizer().GetItem(2).GetSizer().GetItem(1).GetSizer().GetAffirmativeButton()) + self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetAffirmativeId()) def OnOK(self, event): message = None diff -r 59158e360b8c -r f5850ce25caf dialogs/SFCTransitionDialog.py --- a/dialogs/SFCTransitionDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/SFCTransitionDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -57,7 +57,7 @@ # Create label for transition type type_label = wx.StaticText(self, label=_('Type:')) - self.LeftGridSizer.AddWindow(type_label, flag=wx.GROW) + self.LeftGridSizer.Add(type_label, flag=wx.GROW) # Create combo box for selecting reference value reference = wx.ComboBox(self, style=wx.CB_READONLY) @@ -80,28 +80,28 @@ style=(wx.RB_GROUP if first else 0)) radio_button.SetValue(first) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, radio_button) - self.LeftGridSizer.AddWindow(radio_button, flag=wx.GROW) + self.LeftGridSizer.Add(radio_button, flag=wx.GROW) if control is not None: control.Enable(first) - self.LeftGridSizer.AddWindow(control, flag=wx.GROW) + self.LeftGridSizer.Add(control, flag=wx.GROW) self.TypeRadioButtons[type] = (radio_button, control) first = False # Create label for transition priority priority_label = wx.StaticText(self, label=_('Priority:')) - self.LeftGridSizer.AddWindow(priority_label, flag=wx.GROW) + self.LeftGridSizer.Add(priority_label, flag=wx.GROW) # Create spin control for defining priority value self.Priority = wx.SpinCtrl(self, min=0, style=wx.SP_ARROW_KEYS) self.Bind(wx.EVT_TEXT, self.OnPriorityChanged, self.Priority) - self.LeftGridSizer.AddWindow(self.Priority, flag=wx.GROW) + self.LeftGridSizer.Add(self.Priority, flag=wx.GROW) # Add preview panel and associated label to sizers - self.RightGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW) - self.RightGridSizer.AddWindow(self.Preview, flag=wx.GROW) + self.RightGridSizer.Add(self.PreviewLabel, flag=wx.GROW) + self.RightGridSizer.Add(self.Preview, flag=wx.GROW) # Add buttons sizer to sizers - self.MainSizer.AddSizer( + self.MainSizer.Add( self.ButtonSizer, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT) diff -r 59158e360b8c -r f5850ce25caf dialogs/SearchInProjectDialog.py --- a/dialogs/SearchInProjectDialog.py Thu Jul 14 11:40:27 2022 +0200 +++ b/dialogs/SearchInProjectDialog.py Sun Jul 17 22:53:35 2022 +0200 @@ -54,59 +54,59 @@ pattern_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5) pattern_sizer.AddGrowableCol(0) - main_sizer.AddSizer(pattern_sizer, border=20, + main_sizer.Add(pattern_sizer, border=20, flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT) pattern_label = wx.StaticText(self, label=_('Pattern to search:')) - pattern_sizer.AddWindow(pattern_label, flag=wx.ALIGN_BOTTOM) + pattern_sizer.Add(pattern_label, flag=wx.ALIGN_BOTTOM) self.CaseSensitive = wx.CheckBox(self, label=_('Case sensitive')) - pattern_sizer.AddWindow(self.CaseSensitive, flag=wx.GROW) + pattern_sizer.Add(self.CaseSensitive, flag=wx.GROW) self.Pattern = wx.TextCtrl(self, size=wx.Size(250, -1)) self.Bind(wx.EVT_TEXT, self.FindPatternChanged, self.Pattern) - pattern_sizer.AddWindow(self.Pattern, flag=wx.GROW) + pattern_sizer.Add(self.Pattern, flag=wx.GROW) self.Bind(wx.EVT_CHAR_HOOK, self.OnEscapeKey) self.RegularExpression = wx.CheckBox(self, label=_('Regular expression')) - pattern_sizer.AddWindow(self.RegularExpression, flag=wx.GROW) + pattern_sizer.Add(self.RegularExpression, flag=wx.GROW) scope_staticbox = wx.StaticBox(self, label=_('Scope')) scope_sizer = wx.StaticBoxSizer(scope_staticbox, wx.HORIZONTAL) - main_sizer.AddSizer(scope_sizer, border=20, + main_sizer.Add(scope_sizer, border=20, flag=wx.GROW | wx.LEFT | wx.RIGHT) scope_selection_sizer = wx.BoxSizer(wx.VERTICAL) - scope_sizer.AddSizer(scope_selection_sizer, 1, border=5, + scope_sizer.Add(scope_selection_sizer, 1, border=5, flag=wx.GROW | wx.TOP | wx.LEFT | wx.BOTTOM) self.WholeProject = wx.RadioButton(self, label=_('Whole Project'), style=wx.RB_GROUP) self.WholeProject.SetValue(True) self.Bind(wx.EVT_RADIOBUTTON, self.OnScopeChanged, self.WholeProject) - scope_selection_sizer.AddWindow(self.WholeProject, border=5, + scope_selection_sizer.Add(self.WholeProject, border=5, flag=wx.GROW | wx.BOTTOM) self.OnlyElements = wx.RadioButton(self, label=_('Only Elements')) self.Bind(wx.EVT_RADIOBUTTON, self.OnScopeChanged, self.OnlyElements) self.OnlyElements.SetValue(False) - scope_selection_sizer.AddWindow(self.OnlyElements, flag=wx.GROW) + scope_selection_sizer.Add(self.OnlyElements, flag=wx.GROW) self.ElementsList = wx.CheckListBox(self) self.ElementsList.Enable(False) - scope_sizer.AddWindow(self.ElementsList, 1, border=5, + scope_sizer.Add(self.ElementsList, 1, border=5, flag=wx.GROW | wx.TOP | wx.RIGHT | wx.BOTTOM) buttons_sizer = wx.BoxSizer(wx.HORIZONTAL) - main_sizer.AddSizer(buttons_sizer, border=20, + main_sizer.Add(buttons_sizer, border=20, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.ALIGN_RIGHT) self.FindButton = wx.Button(self, label=_("Find")) self.FindButton.SetDefault() self.Bind(wx.EVT_BUTTON, self.OnFindButton, self.FindButton) - buttons_sizer.AddWindow(self.FindButton, border=5, flag=wx.RIGHT) + buttons_sizer.Add(self.FindButton, border=5, flag=wx.RIGHT) self.CloseButton = wx.Button(self, label=_("Close")) self.Bind(wx.EVT_BUTTON, self.OnCloseButton, self.CloseButton) - buttons_sizer.AddWindow(self.CloseButton) + buttons_sizer.Add(self.CloseButton) self.SetSizer(main_sizer) diff -r 59158e360b8c -r f5850ce25caf editors/CodeFileEditor.py --- a/editors/CodeFileEditor.py Thu Jul 14 11:40:27 2022 +0200 +++ b/editors/CodeFileEditor.py Sun Jul 17 22:53:35 2022 +0200 @@ -291,17 +291,16 @@ doc_end_pos = self.GetLength() for section in self.Controler.SECTIONS_NAMES: section_comments = self.SectionsComments[section] - start_pos = self.FindText(0, doc_end_pos, section_comments["comment"]) - end_pos = start_pos + len(section_comments["comment"]) - self.StartStyling(start_pos, 0xff) + start_pos, end_pos = self.FindText(0, doc_end_pos, section_comments["comment"]) + self.StartStyling(start_pos) self.SetStyling(end_pos - start_pos, STC_CODE_SECTION) self.SetLineState(self.LineFromPosition(start_pos), 1) - self.StartStyling(end_pos, 0x00) + self.StartStyling(end_pos) self.SetStyling(doc_end_pos - end_pos, stc.STC_STYLE_DEFAULT) def DoGetBestSize(self): - return self.ParentWindow.GetPanelBestSize() + return self.ParentWindow.GetBestSize() def RefreshModel(self): text = self.GetText() @@ -597,9 +596,9 @@ highlight_end_pos = end[1] + 1 else: highlight_end_pos = self.GetLineEndPosition(end[0] - 1) + end[1] + 2 - self.StartStyling(highlight_start_pos, 0xff) + self.StartStyling(highlight_start_pos) self.SetStyling(highlight_end_pos - highlight_start_pos, highlight_type) - self.StartStyling(highlight_end_pos, 0x00) + self.StartStyling(highlight_end_pos) self.SetStyling(len(self.GetText()) - highlight_end_pos, stc.STC_STYLE_DEFAULT) @@ -614,8 +613,7 @@ class ClassGridCellEditor(wx.grid.GridCellChoiceEditor): def __init__(self, table, row, col): - wx.grid.GridCellChoiceEditor.__init__(self) - self.SetParameters("input,memory,output") + wx.grid.GridCellChoiceEditor.__init__(self,["input","memory","output"]) class VariablesTable(CustomTable): @@ -678,7 +676,7 @@ main_sizer.AddGrowableRow(0) controls_sizer = wx.BoxSizer(wx.VERTICAL) - main_sizer.AddSizer(controls_sizer, border=5, flag=wx.ALL) + main_sizer.Add(controls_sizer, border=5, flag=wx.ALL) for name, bitmap, help in [ ("AddVariableButton", "add_element", _("Add variable")), @@ -687,15 +685,15 @@ ("DownVariableButton", "down", _("Move variable down"))]: button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) - button.SetToolTipString(help) + button.SetToolTip(help) setattr(self, name, button) - controls_sizer.AddWindow(button, border=5, flag=wx.BOTTOM) + controls_sizer.Add(button, border=5, flag=wx.BOTTOM) self.VariablesGrid = CustomGrid(self, style=wx.VSCROLL) - self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange) + self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGING, self.OnVariablesGridCellChange) self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick) self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown) - main_sizer.AddWindow(self.VariablesGrid, flag=wx.GROW) + main_sizer.Add(self.VariablesGrid, flag=wx.GROW) self.SetSizer(main_sizer) @@ -785,7 +783,7 @@ self.VariablesGrid.RefreshButtons() def DoGetBestSize(self): - return self.ParentWindow.GetPanelBestSize() + return self.ParentWindow.GetBestSize() def ShowErrorMessage(self, message): dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR) @@ -836,7 +834,7 @@ type_menu.AppendMenu(wx.ID_ANY, "User Data Types", datatype_menu) rect = self.VariablesGrid.BlockToDeviceRect((row, col), (row, col)) - self.VariablesGrid.PopupMenuXY(type_menu, rect.x + rect.width, rect.y + self.VariablesGrid.GetColLabelSize()) + self.VariablesGrid.PopupMenu(type_menu, rect.x + rect.width, rect.y + self.VariablesGrid.GetColLabelSize()) type_menu.Destroy() event.Veto() else: diff -r 59158e360b8c -r f5850ce25caf editors/ConfTreeNodeEditor.py --- a/editors/ConfTreeNodeEditor.py Thu Jul 14 11:40:27 2022 +0200 +++ b/editors/ConfTreeNodeEditor.py Sun Jul 17 22:53:35 2022 +0200 @@ -120,7 +120,7 @@ bitmap = GetBitmap(bitmapname) if bitmap is None: - bitmap = wx.EmptyBitmap(0, 0) + bitmap = wx.Bitmap() wx.StaticBitmap.__init__(self, parent, ID, bitmap, @@ -148,18 +148,18 @@ if self.SHOW_BASE_PARAMS: baseparamseditor_sizer = wx.BoxSizer(wx.HORIZONTAL) - self.MainSizer.AddSizer(baseparamseditor_sizer, border=5, + self.MainSizer.Add(baseparamseditor_sizer, border=5, flag=wx.GROW | wx.ALL) self.FullIECChannel = wx.StaticText(self.Editor, -1) self.FullIECChannel.SetFont( wx.Font(faces["size"], wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName=faces["helv"])) - baseparamseditor_sizer.AddWindow(self.FullIECChannel, + baseparamseditor_sizer.Add(self.FullIECChannel, flag=wx.ALIGN_CENTER_VERTICAL) updownsizer = wx.BoxSizer(wx.VERTICAL) - baseparamseditor_sizer.AddSizer(updownsizer, border=5, + baseparamseditor_sizer.Add(updownsizer, border=5, flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL) self.IECCUpButton = wx.lib.buttons.GenBitmapTextButton( @@ -169,14 +169,14 @@ style=wx.NO_BORDER) self.IECCUpButton.Bind(wx.EVT_BUTTON, self.GetItemChannelChangedFunction(1), self.IECCUpButton) - updownsizer.AddWindow(self.IECCUpButton, flag=wx.ALIGN_LEFT) + updownsizer.Add(self.IECCUpButton, flag=wx.ALIGN_LEFT) self.IECCDownButton = wx.lib.buttons.GenBitmapButton( self.Editor, bitmap=GetBitmap('IECCUp'), size=wx.Size(16, 16), style=wx.NO_BORDER) self.IECCDownButton.Bind(wx.EVT_BUTTON, self.GetItemChannelChangedFunction(-1), self.IECCDownButton) - updownsizer.AddWindow(self.IECCDownButton, flag=wx.ALIGN_LEFT) + updownsizer.Add(self.IECCDownButton, flag=wx.ALIGN_LEFT) self.ConfNodeName = wx.TextCtrl(self.Editor, size=wx.Size(150, 25)) @@ -187,17 +187,17 @@ wx.EVT_TEXT, self.GetTextCtrlCallBackFunction(self.ConfNodeName, "BaseParams.Name", True), self.ConfNodeName) - baseparamseditor_sizer.AddWindow( + baseparamseditor_sizer.Add( self.ConfNodeName, border=5, flag=wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER_VERTICAL) buttons_sizer = self.GenerateMethodButtonSizer() - baseparamseditor_sizer.AddSizer(buttons_sizer, flag=wx.ALIGN_CENTER) + baseparamseditor_sizer.Add(buttons_sizer, flag=wx.ALIGN_CENTER) if tabs_num > 1: self.ConfNodeNoteBook = wx.Notebook(self.Editor) parent = self.ConfNodeNoteBook - self.MainSizer.AddWindow(self.ConfNodeNoteBook, 1, flag=wx.GROW) + self.MainSizer.Add(self.ConfNodeNoteBook, 1, flag=wx.GROW) else: parent = self.Editor self.ConfNodeNoteBook = None @@ -212,7 +212,7 @@ if self.ConfNodeNoteBook is not None: self.ConfNodeNoteBook.AddPage(editor, title) elif self.SHOW_BASE_PARAMS: - self.MainSizer.AddWindow(editor, 1, flag=wx.GROW) + self.MainSizer.Add(editor, 1, flag=wx.GROW) else: self.Editor = editor @@ -232,7 +232,7 @@ self.ParamsEditor.SetSizer(self.ParamsEditorSizer) self.ConfNodeParamsSizer = wx.BoxSizer(wx.VERTICAL) - self.ParamsEditorSizer.AddSizer(self.ConfNodeParamsSizer, border=5, + self.ParamsEditorSizer.Add(self.ConfNodeParamsSizer, border=5, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM) self.RefreshConfNodeParamsSizer() @@ -240,7 +240,7 @@ if self.ConfNodeNoteBook is not None: self.ConfNodeNoteBook.AddPage(self.ParamsEditor, _("Config")) elif self.SHOW_BASE_PARAMS: - self.MainSizer.AddWindow(self.ParamsEditor, 1, flag=wx.GROW) + self.MainSizer.Add(self.ParamsEditor, 1, flag=wx.GROW) else: self.Editor = self.ParamsEditor else: @@ -317,7 +317,7 @@ label=confnode_method["name"], style=wx.NO_BORDER) button.SetFont(normal_bt_font) - button.SetToolTipString(confnode_method["tooltip"]) + button.SetToolTip(confnode_method["tooltip"]) if confnode_method.get("push", False): button.Bind(wx.EVT_LEFT_DOWN, self.GetButtonCallBackFunction(confnode_method["method"], True)) else: @@ -335,7 +335,7 @@ # hack to force size to mini if not confnode_method.get("enabled", True): button.Disable() - msizer.AddWindow(button, flag=wx.ALIGN_CENTER) + msizer.Add(button, flag=wx.ALIGN_CENTER) return msizer def UriOptions(self, event): @@ -380,32 +380,32 @@ flags = (wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT) if first: flags |= wx.TOP - sizer.AddSizer(staticboxsizer, border=5, flag=flags) + sizer.Add(staticboxsizer, border=5, flag=flags) self.GenerateSizerElements(staticboxsizer, element_infos["children"], element_path) else: - boxsizer = wx.FlexGridSizer(cols=4, rows=1) + boxsizer = wx.FlexGridSizer(cols=4, rows=1, gap=wx.Size(0,0)) boxsizer.AddGrowableCol(1) flags = (wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT) if first: flags |= wx.TOP - sizer.AddSizer(boxsizer, border=5, flag=flags) + sizer.Add(boxsizer, border=5, flag=flags) staticbitmap = GenStaticBitmap( ID=-1, bitmapname=element_infos["name"], name="%s_bitmap" % element_infos["name"], parent=self.ParamsEditor, pos=wx.Point(0, 0), size=wx.Size(24, 24), style=0) - boxsizer.AddWindow(staticbitmap, border=5, flag=wx.RIGHT) + boxsizer.Add(staticbitmap, border=5, flag=wx.RIGHT) statictext = wx.StaticText(self.ParamsEditor, label="%s:" % _(element_infos["name"])) - boxsizer.AddWindow(statictext, border=5, + boxsizer.Add(statictext, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT) if isinstance(element_infos["type"], list): if isinstance(element_infos["value"], tuple): browse_boxsizer = wx.BoxSizer(wx.HORIZONTAL) - boxsizer.AddSizer(browse_boxsizer) + boxsizer.Add(browse_boxsizer) textctrl = wx.TextCtrl(self.ParamsEditor, size=wx.Size(275, -1), style=wx.TE_READONLY) @@ -414,10 +414,10 @@ value_infos = element_infos["value"][1] else: value_infos = None - browse_boxsizer.AddWindow(textctrl) + browse_boxsizer.Add(textctrl) button = wx.Button(self.ParamsEditor, label="...") - browse_boxsizer.AddWindow(button) + browse_boxsizer.Add(button) button.Bind(wx.EVT_BUTTON, self.GetBrowseCallBackFunction(element_infos["name"], textctrl, element_infos["type"], value_infos, element_path), @@ -425,7 +425,7 @@ else: combobox = wx.ComboBox(self.ParamsEditor, size=wx.Size(300, -1), style=wx.CB_READONLY) - boxsizer.AddWindow(combobox) + boxsizer.Add(combobox) if element_infos["use"] == "optional": combobox.Append("") @@ -439,7 +439,7 @@ label="%s - %s" % (_(name), _(value)), size=wx.Size(10, 0)) staticboxsizer = wx.StaticBoxSizer(staticbox, wx.VERTICAL) - sizer.AddSizer(staticboxsizer, border=5, flag=wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT) + sizer.Add(staticboxsizer, border=5, flag=wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT) self.GenerateSizerElements(staticboxsizer, element_infos["children"], element_path) callback = self.GetChoiceContentCallBackFunction(combobox, staticboxsizer, element_path) else: @@ -463,7 +463,7 @@ size=wx.Size(300, -1), style=wx.SP_ARROW_KEYS | wx.ALIGN_RIGHT) spinctrl.SetRange(scmin, scmax) - boxsizer.AddWindow(spinctrl) + boxsizer.Add(spinctrl) if element_infos["value"] is not None: spinctrl.SetValue(element_infos["value"]) spinctrl.Bind(wx.EVT_SPINCTRL, @@ -473,7 +473,7 @@ else: if element_infos["type"] == "boolean": checkbox = wx.CheckBox(self.ParamsEditor) - boxsizer.AddWindow(checkbox, flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT) + boxsizer.Add(checkbox, flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT) if element_infos["value"] is not None: checkbox.SetValue(element_infos["value"]) checkbox.Bind(wx.EVT_CHECKBOX, @@ -490,7 +490,7 @@ size=wx.Size(300, -1), style=wx.SP_ARROW_KEYS | wx.ALIGN_RIGHT) spinctrl.SetRange(scmin, scmax) - boxsizer.AddWindow(spinctrl) + boxsizer.Add(spinctrl) if element_infos["value"] is not None: spinctrl.SetValue(element_infos["value"]) spinctrl.Bind(wx.EVT_SPINCTRL, @@ -513,12 +513,12 @@ self.EditButton = wx.Button(self.ParamsEditor, label='...', size=wx.Size(30, -1)) self.Bind(wx.EVT_BUTTON, self.UriOptions, self.EditButton) - uriSizer.AddWindow(textctrl, flag=wx.GROW) - uriSizer.AddWindow(self.EditButton, flag=wx.GROW) - - boxsizer.AddWindow(uriSizer) + uriSizer.Add(textctrl, flag=wx.GROW) + uriSizer.Add(self.EditButton, flag=wx.GROW) + + boxsizer.Add(uriSizer) else: - boxsizer.AddWindow(textctrl) + boxsizer.Add(textctrl) if element_infos["value"] is not None: textctrl.ChangeValue(str(element_infos["value"])) @@ -535,7 +535,7 @@ self.GetResetFunction(element_path), bt) - boxsizer.AddWindow(bt, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT) + boxsizer.Add(bt, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT) first = False sizer.Layout() self.RefreshScrollbars() diff -r 59158e360b8c -r f5850ce25caf editors/DataTypeEditor.py --- a/editors/DataTypeEditor.py Thu Jul 14 11:40:27 2022 +0200 +++ b/editors/DataTypeEditor.py Sun Jul 17 22:53:35 2022 +0200 @@ -47,7 +47,7 @@ def AppendMenu(parent, help, kind, text): - return parent.Append(help=help, id=wx.ID_ANY, kind=kind, text=text) + return parent.Append(wx.MenuItem(helpString=help, id=wx.ID_ANY, kind=kind, text=text)) def GetElementsTableColnames(): @@ -155,49 +155,49 @@ self.MainSizer.AddGrowableRow(1) top_sizer = wx.BoxSizer(wx.HORIZONTAL) - self.MainSizer.AddSizer(top_sizer, border=5, + self.MainSizer.Add(top_sizer, border=5, flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT) derivation_type_label = wx.StaticText(self.Editor, label=_('Derivation Type:')) - top_sizer.AddWindow(derivation_type_label, border=5, + top_sizer.Add(derivation_type_label, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT) self.DerivationType = wx.ComboBox(self.Editor, size=wx.Size(200, -1), style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnDerivationTypeChanged, self.DerivationType) - top_sizer.AddWindow(self.DerivationType, border=5, flag=wx.GROW | wx.RIGHT) + top_sizer.Add(self.DerivationType, border=5, flag=wx.GROW | wx.RIGHT) typeinfos_staticbox = wx.StaticBox(self.Editor, label=_('Type infos:')) typeinfos_sizer = wx.StaticBoxSizer(typeinfos_staticbox, wx.HORIZONTAL) - self.MainSizer.AddSizer(typeinfos_sizer, border=5, + self.MainSizer.Add(typeinfos_sizer, border=5, flag=wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT) # Panel for Directly derived data types self.DirectlyPanel = wx.Panel(self.Editor, style=wx.TAB_TRAVERSAL) - typeinfos_sizer.AddWindow(self.DirectlyPanel, 1) + typeinfos_sizer.Add(self.DirectlyPanel, 1) directly_panel_sizer = wx.BoxSizer(wx.HORIZONTAL) directly_basetype_label = wx.StaticText(self.DirectlyPanel, label=_('Base Type:')) - directly_panel_sizer.AddWindow(directly_basetype_label, 1, border=5, + directly_panel_sizer.Add(directly_basetype_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) self.DirectlyBaseType = wx.ComboBox(self.DirectlyPanel, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnInfosChanged, self.DirectlyBaseType) - directly_panel_sizer.AddWindow(self.DirectlyBaseType, 1, border=5, + directly_panel_sizer.Add(self.DirectlyBaseType, 1, border=5, flag=wx.GROW | wx.ALL) directly_initialvalue_label = wx.StaticText(self.DirectlyPanel, label=_('Initial Value:')) - directly_panel_sizer.AddWindow(directly_initialvalue_label, 1, border=5, + directly_panel_sizer.Add(directly_initialvalue_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) self.DirectlyInitialValue = wx.TextCtrl(self.DirectlyPanel, style=wx.TE_PROCESS_ENTER | wx.TE_RICH) self.Bind(wx.EVT_TEXT_ENTER, self.OnReturnKeyPressed, self.DirectlyInitialValue) - directly_panel_sizer.AddWindow(self.DirectlyInitialValue, 1, border=5, + directly_panel_sizer.Add(self.DirectlyInitialValue, 1, border=5, flag=wx.ALL) self.DirectlyPanel.SetSizer(directly_panel_sizer) @@ -205,52 +205,52 @@ # Panel for Subrange data types self.SubrangePanel = wx.Panel(self.Editor, style=wx.TAB_TRAVERSAL) - typeinfos_sizer.AddWindow(self.SubrangePanel, 1) + typeinfos_sizer.Add(self.SubrangePanel, 1) subrange_panel_sizer = wx.GridSizer(cols=4, hgap=5, rows=3, vgap=0) subrange_basetype_label = wx.StaticText(self.SubrangePanel, label=_('Base Type:')) - subrange_panel_sizer.AddWindow(subrange_basetype_label, 1, border=5, + subrange_panel_sizer.Add(subrange_basetype_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) self.SubrangeBaseType = wx.ComboBox(self.SubrangePanel, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnSubrangeBaseTypeChanged, self.SubrangeBaseType) - subrange_panel_sizer.AddWindow(self.SubrangeBaseType, 1, border=5, + subrange_panel_sizer.Add(self.SubrangeBaseType, 1, border=5, flag=wx.GROW | wx.ALL) subrange_initialvalue_label = wx.StaticText(self.SubrangePanel, label=_('Initial Value:')) - subrange_panel_sizer.AddWindow(subrange_initialvalue_label, 1, border=5, + subrange_panel_sizer.Add(subrange_initialvalue_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) self.SubrangeInitialValue = CustomIntCtrl(self.SubrangePanel, style=wx.TAB_TRAVERSAL) self.SubrangeInitialValue.Bind(CustomIntCtrl.EVT_CUSTOM_INT, self.OnInfosChanged) - subrange_panel_sizer.AddWindow(self.SubrangeInitialValue, 1, border=5, + subrange_panel_sizer.Add(self.SubrangeInitialValue, 1, border=5, flag=wx.GROW | wx.ALL) subrange_minimum_label = wx.StaticText(self.SubrangePanel, label=_('Minimum:')) - subrange_panel_sizer.AddWindow(subrange_minimum_label, 1, border=5, + subrange_panel_sizer.Add(subrange_minimum_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) self.SubrangeMinimum = CustomIntCtrl(self.SubrangePanel, style=wx.TAB_TRAVERSAL) self.SubrangeMinimum.Bind(CustomIntCtrl.EVT_CUSTOM_INT, self.OnSubrangeMinimumChanged) - subrange_panel_sizer.AddWindow(self.SubrangeMinimum, 1, border=5, + subrange_panel_sizer.Add(self.SubrangeMinimum, 1, border=5, flag=wx.GROW | wx.ALL) for dummy in xrange(2): - subrange_panel_sizer.AddWindow(wx.Size(0, 0), 1) + subrange_panel_sizer.Add(wx.Size(0, 0), 1) subrange_maximum_label = wx.StaticText(self.SubrangePanel, label=_('Maximum:')) - subrange_panel_sizer.AddWindow(subrange_maximum_label, 1, border=5, + subrange_panel_sizer.Add(subrange_maximum_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) self.SubrangeMaximum = CustomIntCtrl(self.SubrangePanel, style=wx.TAB_TRAVERSAL) self.SubrangeMaximum.Bind(CustomIntCtrl.EVT_CUSTOM_INT, self.OnSubrangeMaximumChanged) - subrange_panel_sizer.AddWindow(self.SubrangeMaximum, 1, border=5, + subrange_panel_sizer.Add(self.SubrangeMaximum, 1, border=5, flag=wx.GROW | wx.ALL) self.SubrangePanel.SetSizer(subrange_panel_sizer) @@ -258,35 +258,35 @@ # Panel for Enumerated data types self.EnumeratedPanel = wx.Panel(self.Editor, style=wx.TAB_TRAVERSAL) - typeinfos_sizer.AddWindow(self.EnumeratedPanel, 1) + typeinfos_sizer.Add(self.EnumeratedPanel, 1) enumerated_panel_sizer = wx.BoxSizer(wx.HORIZONTAL) self.EnumeratedValues = CustomEditableListBox( self.EnumeratedPanel, label=_("Values:"), - style=(wx.gizmos.EL_ALLOW_NEW | - wx.gizmos.EL_ALLOW_EDIT | - wx.gizmos.EL_ALLOW_DELETE)) + style=(wx.adv.EL_ALLOW_NEW | + wx.adv.EL_ALLOW_EDIT | + wx.adv.EL_ALLOW_DELETE)) setattr(self.EnumeratedValues, "_OnLabelEndEdit", self.OnEnumeratedValueEndEdit) for func in ["_OnAddButton", "_OnDelButton", "_OnUpButton", "_OnDownButton"]: setattr(self.EnumeratedValues, func, self.OnEnumeratedValuesChanged) - enumerated_panel_sizer.AddWindow(self.EnumeratedValues, 1, border=5, + enumerated_panel_sizer.Add(self.EnumeratedValues, 1, border=5, flag=wx.GROW | wx.ALL) enumerated_panel_rightsizer = wx.BoxSizer(wx.HORIZONTAL) - enumerated_panel_sizer.AddSizer(enumerated_panel_rightsizer, 1) + enumerated_panel_sizer.Add(enumerated_panel_rightsizer, 1) enumerated_initialvalue_label = wx.StaticText(self.EnumeratedPanel, label=_('Initial Value:')) - enumerated_panel_rightsizer.AddWindow(enumerated_initialvalue_label, 1, + enumerated_panel_rightsizer.Add(enumerated_initialvalue_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) self.EnumeratedInitialValue = wx.ComboBox(self.EnumeratedPanel, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnInfosChanged, self.EnumeratedInitialValue) - enumerated_panel_rightsizer.AddWindow(self.EnumeratedInitialValue, 1, + enumerated_panel_rightsizer.Add(self.EnumeratedInitialValue, 1, border=5, flag=wx.ALL) self.EnumeratedPanel.SetSizer(enumerated_panel_sizer) @@ -294,7 +294,7 @@ # Panel for Array data types self.ArrayPanel = wx.Panel(self.Editor, style=wx.TAB_TRAVERSAL) - typeinfos_sizer.AddWindow(self.ArrayPanel, 1) + typeinfos_sizer.Add(self.ArrayPanel, 1) array_panel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=0) array_panel_sizer.AddGrowableCol(0) @@ -302,41 +302,41 @@ array_panel_sizer.AddGrowableRow(1) array_panel_leftSizer = wx.BoxSizer(wx.HORIZONTAL) - array_panel_sizer.AddSizer(array_panel_leftSizer, flag=wx.GROW) + array_panel_sizer.Add(array_panel_leftSizer, flag=wx.GROW) array_basetype_label = wx.StaticText(self.ArrayPanel, label=_('Base Type:')) - array_panel_leftSizer.AddWindow(array_basetype_label, 1, border=5, + array_panel_leftSizer.Add(array_basetype_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) self.ArrayBaseType = wx.ComboBox(self.ArrayPanel, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnInfosChanged, self.ArrayBaseType) - array_panel_leftSizer.AddWindow(self.ArrayBaseType, 1, border=5, + array_panel_leftSizer.Add(self.ArrayBaseType, 1, border=5, flag=wx.GROW | wx.ALL) array_panel_rightsizer = wx.BoxSizer(wx.HORIZONTAL) - array_panel_sizer.AddSizer(array_panel_rightsizer, flag=wx.GROW) + array_panel_sizer.Add(array_panel_rightsizer, flag=wx.GROW) array_initialvalue_label = wx.StaticText(self.ArrayPanel, label=_('Initial Value:')) - array_panel_rightsizer.AddWindow(array_initialvalue_label, 1, border=5, + array_panel_rightsizer.Add(array_initialvalue_label, 1, border=5, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL) self.ArrayInitialValue = wx.TextCtrl(self.ArrayPanel, style=wx.TE_PROCESS_ENTER | wx.TE_RICH) self.Bind(wx.EVT_TEXT_ENTER, self.OnReturnKeyPressed, self.ArrayInitialValue) - array_panel_rightsizer.AddWindow(self.ArrayInitialValue, 1, border=5, + array_panel_rightsizer.Add(self.ArrayInitialValue, 1, border=5, flag=wx.ALL) self.ArrayDimensions = CustomEditableListBox( self.ArrayPanel, label=_("Dimensions:"), - style=(wx.gizmos.EL_ALLOW_NEW | - wx.gizmos.EL_ALLOW_EDIT | - wx.gizmos.EL_ALLOW_DELETE)) + style=(wx.adv.EL_ALLOW_NEW | + wx.adv.EL_ALLOW_EDIT | + wx.adv.EL_ALLOW_DELETE)) for func in ["_OnLabelEndEdit", "_OnAddButton", "_OnDelButton", "_OnUpButton", "_OnDownButton"]: setattr(self.ArrayDimensions, func, self.OnDimensionsChanged) - array_panel_sizer.AddWindow(self.ArrayDimensions, 0, border=5, + array_panel_sizer.Add(self.ArrayDimensions, 0, border=5, flag=wx.GROW | wx.ALL) self.ArrayPanel.SetSizer(array_panel_sizer) @@ -344,7 +344,7 @@ # Panel for Structure data types self.StructurePanel = wx.Panel(self.Editor, style=wx.TAB_TRAVERSAL) - typeinfos_sizer.AddWindow(self.StructurePanel, 1) + typeinfos_sizer.Add(self.StructurePanel, 1) structure_panel_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) structure_panel_sizer.AddGrowableCol(0) @@ -353,12 +353,12 @@ structure_button_sizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0) structure_button_sizer.AddGrowableCol(0) structure_button_sizer.AddGrowableRow(0) - structure_panel_sizer.AddSizer(structure_button_sizer, 0, border=5, + structure_panel_sizer.Add(structure_button_sizer, 0, border=5, flag=wx.ALL | wx.GROW) structure_elements_label = wx.StaticText(self.StructurePanel, label=_('Elements :')) - structure_button_sizer.AddWindow(structure_elements_label, flag=wx.ALIGN_BOTTOM) + structure_button_sizer.Add(structure_elements_label, flag=wx.ALIGN_BOTTOM) for name, bitmap, help in [ ("StructureAddButton", "add_element", _("Add element")), @@ -369,17 +369,17 @@ bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) - button.SetToolTipString(help) + button.SetToolTip(help) setattr(self, name, button) - structure_button_sizer.AddWindow(button) + structure_button_sizer.Add(button) self.StructureElementsGrid = CustomGrid(self.StructurePanel, size=wx.Size(0, 150), style=wx.VSCROLL) - self.StructureElementsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, + self.StructureElementsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGED, self.OnStructureElementsGridCellChange) self.StructureElementsGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnStructureElementsGridEditorShown) - structure_panel_sizer.AddWindow(self.StructureElementsGrid, flag=wx.GROW) + structure_panel_sizer.Add(self.StructureElementsGrid, flag=wx.GROW) self.StructurePanel.SetSizer(structure_panel_sizer) @@ -647,7 +647,7 @@ self.Bind(wx.EVT_MENU, self.ElementArrayTypeFunction, new_entry) rect = self.StructureElementsGrid.BlockToDeviceRect((row, col), (row, col)) - self.StructureElementsGrid.PopupMenuXY(type_menu, rect.x + rect.width, rect.y + self.StructureElementsGrid.GetColLabelSize()) + self.StructureElementsGrid.PopupMenu(type_menu, rect.x + rect.width, rect.y + self.StructureElementsGrid.GetColLabelSize()) type_menu.Destroy() event.Veto() else: @@ -786,7 +786,7 @@ value = control.GetValueStr() if isinstance(control, CustomIntCtrl) else \ control.GetValue() control.SetStyle(0, len(value), wx.TextAttr(wx.NullColour)) - elif isinstance(control, wx.gizmos.EditableListBox): + elif isinstance(control, wx.adv.EditableListBox): listctrl = control.GetListCtrl() for i in xrange(listctrl.GetItemCount()): listctrl.SetItemBackgroundColour(i, wx.NullColour) @@ -811,7 +811,7 @@ control.SetForegroundColour(highlight_type[1]) elif isinstance(control, wx.TextCtrl): control.SetStyle(start[1], end[1] + 1, wx.TextAttr(highlight_type[1], highlight_type[0])) - elif isinstance(control, wx.gizmos.EditableListBox): + elif isinstance(control, wx.adv.EditableListBox): listctrl = control.GetListCtrl() listctrl.SetItemBackgroundColour(infos[1], highlight_type[0]) listctrl.SetItemTextColour(infos[1], highlight_type[1]) diff -r 59158e360b8c -r f5850ce25caf editors/FileManagementPanel.py --- a/editors/FileManagementPanel.py Thu Jul 14 11:40:27 2022 +0200 +++ b/editors/FileManagementPanel.py Sun Jul 17 22:53:35 2022 +0200 @@ -43,14 +43,14 @@ main_sizer = wx.BoxSizer(wx.HORIZONTAL) left_sizer = wx.BoxSizer(wx.VERTICAL) - main_sizer.AddSizer(left_sizer, 1, border=5, flag=wx.GROW | wx.ALL) + main_sizer.Add(left_sizer, 1, border=5, flag=wx.GROW | wx.ALL) managed_dir_label = wx.StaticText(self.Editor, label=_(self.TagName) + ":") - left_sizer.AddWindow(managed_dir_label, border=5, flag=wx.GROW | wx.BOTTOM) + left_sizer.Add(managed_dir_label, border=5, flag=wx.GROW | wx.BOTTOM) FILTER = _("All files (*.*)|*.*|CSV files (*.csv)|*.csv") self.ManagedDir = FolderTree(self.Editor, self.Folder, FILTER) - left_sizer.AddWindow(self.ManagedDir, 1, flag=wx.GROW) + left_sizer.Add(self.ManagedDir, 1, flag=wx.GROW) managed_treectrl = self.ManagedDir.GetTreeCtrl() self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTreeItemChanged, managed_treectrl) @@ -58,7 +58,7 @@ self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnTreeBeginDrag, managed_treectrl) button_sizer = wx.BoxSizer(wx.VERTICAL) - main_sizer.AddSizer(button_sizer, border=5, + main_sizer.Add(button_sizer, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL) for idx, (name, bitmap, help) in enumerate([ @@ -70,26 +70,26 @@ self.Editor, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) - button.SetToolTipString(help) + button.SetToolTip(help) setattr(self, name, button) if idx > 0: flag = wx.TOP else: flag = 0 self.Bind(wx.EVT_BUTTON, getattr(self, "On" + name), button) - button_sizer.AddWindow(button, border=20, flag=flag) + button_sizer.Add(button, border=20, flag=flag) right_sizer = wx.BoxSizer(wx.VERTICAL) - main_sizer.AddSizer(right_sizer, 1, border=5, flag=wx.GROW | wx.ALL) + main_sizer.Add(right_sizer, 1, border=5, flag=wx.GROW | wx.ALL) if wx.Platform == '__WXMSW__': system_dir_label = wx.StaticText(self.Editor, label=_("My Computer:")) else: system_dir_label = wx.StaticText(self.Editor, label=_("Home Directory:")) - right_sizer.AddWindow(system_dir_label, border=5, flag=wx.GROW | wx.BOTTOM) + right_sizer.Add(system_dir_label, border=5, flag=wx.GROW | wx.BOTTOM) self.SystemDir = FolderTree(self.Editor, self.HomeDirectory, FILTER, False) - right_sizer.AddWindow(self.SystemDir, 1, flag=wx.GROW) + right_sizer.Add(self.SystemDir, 1, flag=wx.GROW) system_treectrl = self.SystemDir.GetTreeCtrl() self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTreeItemChanged, system_treectrl) diff -r 59158e360b8c -r f5850ce25caf editors/ProjectNodeEditor.py --- a/editors/ProjectNodeEditor.py Thu Jul 14 11:40:27 2022 +0200 +++ b/editors/ProjectNodeEditor.py Sun Jul 17 22:53:35 2022 +0200 @@ -60,7 +60,7 @@ ConfTreeNodeEditor.__init__(self, parent, controler, window, tagname) buttons_sizer = self.GenerateMethodButtonSizer() - self.MainSizer.InsertSizer(0, buttons_sizer, 0, border=5, flag=wx.ALL) + self.MainSizer.Insert(0, buttons_sizer, 0, border=5, flag=wx.ALL) self.MainSizer.Layout() self.VariableEditor = self.VariableEditorPanel diff -r 59158e360b8c -r f5850ce25caf editors/ResourceEditor.py --- a/editors/ResourceEditor.py Thu Jul 14 11:40:27 2022 +0200 +++ b/editors/ResourceEditor.py Sun Jul 17 22:53:35 2022 +0200 @@ -76,10 +76,6 @@ return [_("Interrupt"), _("Cyclic")] -def SingleCellEditor(*x): - return wx.grid.GridCellChoiceEditor() - - def CheckSingle(single, varlist): return single in varlist @@ -162,25 +158,21 @@ if interval != "" and IEC_TIME_MODEL.match(interval.upper()) is None: error = True elif colname == "Single": - editor = SingleCellEditor(self, colname) - editor.SetParameters(self.Parent.VariableList) + editor = wx.grid.GridCellChoiceEditor(self.Parent.VariableList) if self.GetValueByName(row, "Triggering") != "Interrupt": grid.SetReadOnly(row, col, True) single = self.GetValueByName(row, colname) if single != "" and not CheckSingle(single, self.Parent.VariableList): error = True elif colname == "Triggering": - editor = wx.grid.GridCellChoiceEditor() - editor.SetParameters(",".join(map(_, GetTaskTriggeringOptions()))) + editor = wx.grid.GridCellChoiceEditor(map(_, GetTaskTriggeringOptions())) elif colname == "Type": - editor = wx.grid.GridCellChoiceEditor() - editor.SetParameters(self.Parent.TypeList) + editor = wx.grid.GridCellChoiceEditor(self.Parent.TypeList) elif colname == "Priority": editor = wx.grid.GridCellNumberEditor() editor.SetParameters("0,65535") elif colname == "Task": - editor = wx.grid.GridCellChoiceEditor() - editor.SetParameters(self.Parent.TaskList) + editor = wx.grid.GridCellChoiceEditor(self.Parent.TaskList) grid.SetCellEditor(row, col, editor) grid.SetCellRenderer(row, col, renderer) @@ -230,16 +222,16 @@ tasks_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5) tasks_sizer.AddGrowableCol(0) tasks_sizer.AddGrowableRow(1) - main_sizer.AddSizer(tasks_sizer, border=5, + main_sizer.Add(tasks_sizer, border=5, flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT) tasks_buttons_sizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0) tasks_buttons_sizer.AddGrowableCol(0) tasks_buttons_sizer.AddGrowableRow(0) - tasks_sizer.AddSizer(tasks_buttons_sizer, flag=wx.GROW) + tasks_sizer.Add(tasks_buttons_sizer, flag=wx.GROW) tasks_label = wx.StaticText(self.Editor, label=_(u'Tasks:')) - tasks_buttons_sizer.AddWindow(tasks_label, flag=wx.ALIGN_BOTTOM) + tasks_buttons_sizer.Add(tasks_label, flag=wx.ALIGN_BOTTOM) for name, bitmap, help in [ ("AddTaskButton", "add_element", _("Add task")), @@ -250,27 +242,27 @@ bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) - button.SetToolTipString(help) + button.SetToolTip(help) setattr(self, name, button) - tasks_buttons_sizer.AddWindow(button) + tasks_buttons_sizer.Add(button) self.TasksGrid = CustomGrid(self.Editor, style=wx.VSCROLL) - self.TasksGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnTasksGridCellChange) - tasks_sizer.AddWindow(self.TasksGrid, flag=wx.GROW) + self.TasksGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGED, self.OnTasksGridCellChange) + tasks_sizer.Add(self.TasksGrid, flag=wx.GROW) instances_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5) instances_sizer.AddGrowableCol(0) instances_sizer.AddGrowableRow(1) - main_sizer.AddSizer(instances_sizer, border=5, + main_sizer.Add(instances_sizer, border=5, flag=wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT) instances_buttons_sizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0) instances_buttons_sizer.AddGrowableCol(0) instances_buttons_sizer.AddGrowableRow(0) - instances_sizer.AddSizer(instances_buttons_sizer, flag=wx.GROW) + instances_sizer.Add(instances_buttons_sizer, flag=wx.GROW) instances_label = wx.StaticText(self.Editor, label=_(u'Instances:')) - instances_buttons_sizer.AddWindow(instances_label, flag=wx.ALIGN_BOTTOM) + instances_buttons_sizer.Add(instances_label, flag=wx.ALIGN_BOTTOM) for name, bitmap, help in [ ("AddInstanceButton", "add_element", _("Add instance")), @@ -280,13 +272,13 @@ button = wx.lib.buttons.GenBitmapButton( self.Editor, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) - button.SetToolTipString(help) + button.SetToolTip(help) setattr(self, name, button) - instances_buttons_sizer.AddWindow(button) + instances_buttons_sizer.Add(button) self.InstancesGrid = CustomGrid(self.Editor, style=wx.VSCROLL) - self.InstancesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnInstancesGridCellChange) - instances_sizer.AddWindow(self.InstancesGrid, flag=wx.GROW) + self.InstancesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGED, self.OnInstancesGridCellChange) + instances_sizer.Add(self.InstancesGrid, flag=wx.GROW) self.Editor.SetSizer(main_sizer) @@ -405,20 +397,20 @@ self.RefreshHighlightsTimer.Stop() def RefreshTypeList(self): - self.TypeList = "" + self.TypeList = [] blocktypes = self.Controler.GetBlockResource() for blocktype in blocktypes: - self.TypeList += ",%s" % blocktype + self.TypeList.append(blocktype) def RefreshTaskList(self): - self.TaskList = "" + self.TaskList = [] for row in xrange(self.TasksTable.GetNumberRows()): - self.TaskList += ",%s" % self.TasksTable.GetValueByName(row, "Name") + self.TaskList.append(self.TasksTable.GetValueByName(row, "Name")) def RefreshVariableList(self): - self.VariableList = "" + self.VariableList = [] for variable in self.Controler.GetEditedResourceVariables(self.TagName): - self.VariableList += ",%s" % variable + self.VariableList.append(variable) def RefreshModel(self): self.Controler.SetEditedResourceInfos(self.TagName, self.TasksTable.GetData(), self.InstancesTable.GetData()) @@ -481,7 +473,7 @@ wx.CallAfter(self.ShowErrorMessage, message) return - tasklist = [name for name in self.TaskList.split(",") if name != ""] + tasklist = [name for name in self.TaskList if name != ""] for i in xrange(self.TasksTable.GetNumberRows()): task = self.TasksTable.GetValueByName(i, "Name") if task in tasklist: diff -r 59158e360b8c -r f5850ce25caf editors/TextViewer.py --- a/editors/TextViewer.py Thu Jul 14 11:40:27 2022 +0200 +++ b/editors/TextViewer.py Sun Jul 17 22:53:35 2022 +0200 @@ -198,12 +198,20 @@ def Colourise(self, start, end): self.Editor.Colourise(start, end) - def StartStyling(self, pos, mask): - self.Editor.StartStyling(pos, mask) + def StartStyling(self, pos): + self.Editor.StartStyling(pos) + + INDIC0 = 0 + INDIC1 = 1 + INDIC2 = 2 def SetStyling(self, length, style): self.Editor.SetStyling(length, style) + def SetIndicatorCurrentFillRange(self, start, length, indic): + self.Editor.SetIndicatorCurrent(indic) + self.Editor.IndicatorFillRange(start, length) + def GetCurrentPos(self): return self.Editor.GetCurrentPos() @@ -560,7 +568,7 @@ start_pos = last_styled_pos = self.Editor.GetLineEndPosition(line_number - 1) + 1 self.RefreshLineFolding(line_number) end_pos = event.GetPosition() - self.StartStyling(start_pos, 0xff) + self.StartStyling(start_pos) current_context = self.Variables current_call = None @@ -595,9 +603,8 @@ else: self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY) if word not in ["]", ")"] and (self.GetCurrentPos() < last_styled_pos or self.GetCurrentPos() > current_pos): - self.StartStyling(last_styled_pos, wx.stc.STC_INDICS_MASK) - self.SetStyling(current_pos - last_styled_pos, wx.stc.STC_INDIC0_MASK) - self.StartStyling(current_pos, 0xff) + self.SetIndicatorCurrentFillRange(last_styled_pos, current_pos - last_styled_pos, self.INDIC0) + self.StartStyling(current_pos) else: self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY) last_styled_pos = current_pos @@ -698,9 +705,8 @@ else: self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY) if word not in ["]", ")"] and (self.GetCurrentPos() < last_styled_pos or self.GetCurrentPos() > current_pos): - self.StartStyling(last_styled_pos, wx.stc.STC_INDICS_MASK) - self.SetStyling(current_pos - last_styled_pos, wx.stc.STC_INDIC0_MASK) - self.StartStyling(current_pos, 0xff) + self.SetIndicatorCurrentFillRange(last_styled_pos, current_pos - last_styled_pos, self.INDIC0) + self.StartStyling(current_pos) if char == '.': if word != "]": if current_context is not None: @@ -956,8 +962,8 @@ else: highlight_end_pos = self.Editor.GetLineEndPosition(end[0] - 1) + end[1] - indent + 2 if highlight_start_pos < end_pos and highlight_end_pos > start_pos: - self.StartStyling(highlight_start_pos, 0xff) + self.StartStyling(highlight_start_pos) self.SetStyling(highlight_end_pos - highlight_start_pos, highlight_type) - self.StartStyling(highlight_start_pos, 0x00) + self.StartStyling(highlight_start_pos) until_end = max(0, len(self.Editor.GetText()) - highlight_end_pos) self.SetStyling(until_end, wx.stc.STC_STYLE_DEFAULT) diff -r 59158e360b8c -r f5850ce25caf editors/Viewer.py --- a/editors/Viewer.py Thu Jul 14 11:40:27 2022 +0200 +++ b/editors/Viewer.py Sun Jul 17 22:53:35 2022 +0200 @@ -60,11 +60,11 @@ global CURSORS if CURSORS is None: CURSORS = [wx.NullCursor, - wx.StockCursor(wx.CURSOR_HAND), - wx.StockCursor(wx.CURSOR_SIZENWSE), - wx.StockCursor(wx.CURSOR_SIZENESW), - wx.StockCursor(wx.CURSOR_SIZEWE), - wx.StockCursor(wx.CURSOR_SIZENS)] + wx.Cursor(wx.CURSOR_HAND), + wx.Cursor(wx.CURSOR_SIZENWSE), + wx.Cursor(wx.CURSOR_SIZENESW), + wx.Cursor(wx.CURSOR_SIZEWE), + wx.Cursor(wx.CURSOR_SIZENS)] if wx.Platform == '__WXMSW__': @@ -317,7 +317,7 @@ selected = None dialog.Destroy() if selected is None: - return + return False if selected == 0: location = "%I" + location elif selected == 1: @@ -333,7 +333,7 @@ var_name = dlg.GetValue() if dlg.ShowModal() == wx.ID_OK else None dlg.Destroy() if var_name is None: - return + return False elif var_name.upper() in [name.upper() for name in self.ParentWindow.Controler.GetProjectPouNames(self.ParentWindow.Debug)]: message = _("\"%s\" pou already exists!") % var_name elif not var_name.upper() in [name.upper() for name in self.ParentWindow.Controler.GetEditedElementVariables(tagname, self.ParentWindow.Debug)]: @@ -363,7 +363,7 @@ var_name = dlg.GetValue() if dlg.ShowModal() == wx.ID_OK else None dlg.Destroy() if var_name is None: - return + return False elif var_name.upper() in [name.upper() for name in self.ParentWindow.Controler.GetProjectPouNames(self.ParentWindow.Debug)]: message = _("\"%s\" pou already exists!") % var_name elif not var_name.upper() in [name.upper() for name in self.ParentWindow.Controler.GetEditedElementVariables(tagname, self.ParentWindow.Debug)]: @@ -385,7 +385,7 @@ var_name = dlg.GetValue() if dlg.ShowModal() == wx.ID_OK else None dlg.Destroy() if var_name is None: - return + return False elif var_name.upper() in [name.upper() for name in self.ParentWindow.Controler.GetProjectPouNames(self.ParentWindow.Debug)]: message = _("\"%s\" pou already exists!") % var_name elif not var_name.upper() in [name.upper() for name in self.ParentWindow.Controler.GetEditedElementVariables(tagname, self.ParentWindow.Debug)]: @@ -410,7 +410,7 @@ if len(tree[0]) > 0: menu = wx.Menu(title='') self.GenerateTreeMenu(x, y, scaling, menu, "", var_class, [(values[0], values[2], tree)]) - self.ParentWindow.PopupMenuXY(menu) + self.ParentWindow.PopupMenu(menu) else: self.ParentWindow.AddVariableBlock(x, y, scaling, var_class, values[0], values[2]) else: @@ -419,6 +419,8 @@ message = _("Variable don't belong to this POU!") if message is not None: wx.CallAfter(self.ShowMessage, message) + return False + return True def GenerateTreeMenu(self, x, y, scaling, menu, base_path, var_class, tree): for child_name, child_type, (child_tree, child_dimensions) in tree: @@ -429,8 +431,10 @@ if len(child_dimensions) > 0: child_path += "[%s]" % ",".join([str(dimension[0]) for dimension in child_dimensions]) child_name += "[]" - item = menu.Append(wx.ID_ANY, help='', kind=wx.ITEM_NORMAL, text=child_name) - self.ParentWindow.Bind(wx.EVT_MENU, self.GetAddVariableBlockFunction(x, y, scaling, var_class, child_path, child_type), item) + + item = self.AppendItem(menu, + child_name, + self.GetAddVariableBlockFunction(x, y, scaling, var_class, child_path, child_type)) if len(child_tree) > 0: child_menu = wx.Menu(title='') self.GenerateTreeMenu(x, y, scaling, child_menu, child_path, var_class, child_tree) @@ -712,7 +716,7 @@ break faces["size"] -= 1 self.Editor.SetFont(font) - self.MiniTextDC = wx.MemoryDC(wx.EmptyBitmap(1, 1)) + self.MiniTextDC = wx.MemoryDC(wx.Bitmap(1, 1)) self.MiniTextDC.SetFont(wx.Font(faces["size"] * 0.75, wx.SWISS, wx.NORMAL, wx.NORMAL, faceName=faces["helv"])) self.CurrentScale = None @@ -825,15 +829,14 @@ def GetViewScale(self): return self.ViewScale - def GetLogicalDC(self, buffered=False): - if buffered: - bitmap = wx.EmptyBitmap(*self.Editor.GetClientSize()) - dc = wx.MemoryDC(bitmap) - else: - dc = wx.ClientDC(self.Editor) + def PrepareDC(self, dc): dc.SetFont(self.GetFont()) self.Editor.DoPrepareDC(dc) dc.SetUserScale(self.ViewScale[0], self.ViewScale[1]) + + def GetLogicalDC(self): + dc = wx.ClientDC(self.Editor) + self.PrepareDC(dc) return dc def RefreshRect(self, rect, eraseBackground=True): @@ -1058,7 +1061,7 @@ self.SelectedElement.SetSelected(False) self.SelectedElement = None if self.Mode == MODE_MOTION: - wx.CallAfter(self.Editor.SetCursor, wx.StockCursor(wx.CURSOR_HAND)) + wx.CallAfter(self.Editor.SetCursor, wx.Cursor(wx.CURSOR_HAND)) self.SavedMode = True # Return current drawing mode @@ -1116,13 +1119,13 @@ if self.DrawGrid: width = max(2, int(scaling[0] * self.ViewScale[0])) height = max(2, int(scaling[1] * self.ViewScale[1])) - bitmap = wx.EmptyBitmap(width, height) + bitmap = wx.Bitmap(width, height) dc = wx.MemoryDC(bitmap) dc.SetBackground(wx.Brush(self.Editor.GetBackgroundColour())) dc.Clear() dc.SetPen(MiterPen(wx.Colour(180, 180, 180))) dc.DrawPoint(0, 0) - self.GridBrush = wx.BrushFromBitmap(bitmap) + self.GridBrush = wx.Brush(bitmap) else: self.GridBrush = wx.TRANSPARENT_BRUSH else: @@ -1572,10 +1575,15 @@ iec_path = self.GetElementIECPath(self.SelectedElement) if iec_path is not None: menu = wx.Menu(title='') - item = menu.Append(wx.ID_ANY, help='', kind=wx.ITEM_NORMAL, text=_("Force value")) - self.Bind(wx.EVT_MENU, self.GetForceVariableMenuFunction(iec_path.upper(), self.SelectedElement), item) - ritem = menu.Append(wx.ID_ANY, help='', kind=wx.ITEM_NORMAL, text=_("Release value")) - self.Bind(wx.EVT_MENU, self.GetReleaseVariableMenuFunction(iec_path.upper()), ritem) + item = self.AppendItem(menu, + _("Force value"), + self.GetForceVariableMenuFunction( + iec_path.upper(), + self.SelectedElement)) + + ritem = self.AppendItem(menu, + _("Release value"), + self.GetReleaseVariableMenuFunction(iec_path.upper())) if self.SelectedElement.IsForced(): ritem.Enable(True) else: @@ -1903,9 +1911,9 @@ def OnViewerMouseEvent(self, event): self.ResetBuffer() - if event.Leaving() and self.ToolTipElement is not None: + if (event.Leaving() or event.RightUp()) and self.ToolTipElement is not None: self.ToolTipElement.DestroyToolTip() - elif (not event.Entering() and + elif (not event.Entering() and not event.RightUp() and gettime() - self.LastToolTipCheckTime > REFRESH_PERIOD): self.LastToolTipCheckTime = gettime() element = None @@ -3379,7 +3387,7 @@ element = self.ParentWindow.GetCopyBuffer() if bbx is None: mouse_pos = self.Editor.ScreenToClient(wx.GetMousePosition()) - middle = wx.Rect(0, 0, *self.Editor.GetClientSize()).InsideXY(mouse_pos.x, mouse_pos.y) + middle = wx.Rect(0, 0, *self.Editor.GetClientSize()).Contains(mouse_pos.x, mouse_pos.y) if middle: x, y = self.CalcUnscrolledPosition(mouse_pos.x, mouse_pos.y) else: @@ -3633,7 +3641,6 @@ else: dc.SetBackground(wx.Brush(self.Editor.GetBackgroundColour())) dc.Clear() - dc.BeginDrawing() if self.Scaling is not None and self.DrawGrid and not printing: dc.SetPen(wx.TRANSPARENT_PEN) dc.SetBrush(self.GridBrush) @@ -3680,12 +3687,15 @@ self.InstanceName.Draw(dc) if self.rubberBand.IsShown(): self.rubberBand.Draw(dc) - dc.EndDrawing() def OnPaint(self, event): - dc = self.GetLogicalDC(True) + event.Skip() + sx,sy = self.Editor.GetClientSize() + if sx <= 0 or sy <= 0 : + return + dc = wx.MemoryDC(wx.Bitmap(sx,sy)) + self.PrepareDC(dc) self.DoDrawing(dc) wx.BufferedPaintDC(self.Editor, dc.GetAsBitmap()) if self.Debug: DebugViewer.RefreshNewData(self) - event.Skip() diff -r 59158e360b8c -r f5850ce25caf etherlab/ConfigEditor.py --- a/etherlab/ConfigEditor.py Thu Jul 14 11:40:27 2022 +0200 +++ b/etherlab/ConfigEditor.py Sun Jul 17 22:53:35 2022 +0200 @@ -16,7 +16,7 @@ import wx import wx.grid -import wx.gizmos +import wx.adv import wx.lib.buttons from plcopen.structures import IEC_KEYWORDS, TestIdentifier @@ -81,9 +81,9 @@ self.VariablesFilter.Bind(wx.EVT_COMBOBOX, self.OnVariablesFilterChanged) self.VariablesFilter.Bind(wx.EVT_TEXT_ENTER, self.OnVariablesFilterChanged) self.VariablesFilter.Bind(wx.EVT_CHAR, self.OnVariablesFilterKeyDown) - self.AddWindow(self.VariablesFilter, flag=wx.GROW) - - self.VariablesGrid = wx.gizmos.TreeListCtrl(parent, + self.Add(self.VariablesFilter, flag=wx.GROW) + + self.VariablesGrid = wx.adv.TreeListCtrl(parent, style=wx.TR_DEFAULT_STYLE | wx.TR_ROW_LINES | wx.TR_COLUMN_LINES | @@ -91,7 +91,7 @@ wx.TR_FULL_ROW_HIGHLIGHT) self.VariablesGrid.GetMainWindow().Bind(wx.EVT_LEFT_DOWN, self.OnVariablesGridLeftClick) - self.AddWindow(self.VariablesGrid, flag=wx.GROW) + self.Add(self.VariablesGrid, flag=wx.GROW) self.Filters = [] for desc, value in VARIABLES_FILTERS: @@ -274,10 +274,10 @@ variables_label = wx.StaticText(self.EthercatNodeEditor, label=_('Variable entries:')) - main_sizer.AddWindow(variables_label, border=10, flag=wx.TOP | wx.LEFT | wx.RIGHT) + main_sizer.Add(variables_label, border=10, flag=wx.TOP | wx.LEFT | wx.RIGHT) self.NodeVariables = NodeVariablesSizer(self.EthercatNodeEditor, self.Controler) - main_sizer.AddSizer(self.NodeVariables, border=10, + main_sizer.Add(self.NodeVariables, border=10, flag=wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT) self.EthercatNodeEditor.SetSizer(main_sizer) @@ -310,7 +310,7 @@ self.EtherCATManagementTreebook = EtherCATManagementTreebook(self.EtherCATManagementEditor, self.Controler, self) - self.EtherCATManagermentEditor_Main_Sizer.AddSizer(self.EtherCATManagementTreebook, border=10, flag=wx.GROW) + self.EtherCATManagermentEditor_Main_Sizer.Add(self.EtherCATManagementTreebook, border=10, flag=wx.GROW) self.EtherCATManagementEditor.SetSizer(self.EtherCATManagermentEditor_Main_Sizer) return self.EtherCATManagementEditor @@ -617,7 +617,7 @@ self.MasterStateEditor_Panel = MasterStatePanelClass(self.MasterStateEditor, self.Controler) - self.MasterStateEditor_Panel_Main_Sizer.AddSizer(self.MasterStateEditor_Panel, border=10, flag=wx.GROW) + self.MasterStateEditor_Panel_Main_Sizer.Add(self.MasterStateEditor_Panel, border=10, flag=wx.GROW) self.MasterStateEditor.SetSizer(self.MasterStateEditor_Panel_Main_Sizer) return self.MasterStateEditor @@ -651,7 +651,7 @@ process_variables_label = wx.StaticText(self.EthercatMasterEditor, label=_("Process variables mapped between nodes:")) - process_variables_header.AddWindow(process_variables_label, 1, + process_variables_header.Add(process_variables_label, 1, flag=wx.ALIGN_CENTER_VERTICAL) for name, bitmap, help in [ @@ -661,14 +661,14 @@ ("DownVariableButton", "down", _("Move process variable down"))]: button = wx.lib.buttons.GenBitmapButton(self.EthercatMasterEditor, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) - button.SetToolTipString(help) + button.SetToolTip(help) setattr(self, name, button) - process_variables_header.AddWindow(button, border=5, flag=wx.LEFT) + process_variables_header.Add(button, border=5, flag=wx.LEFT) self.ProcessVariablesGrid = CustomGrid(self.EthercatMasterEditor, style=wx.VSCROLL) self.ProcessVariablesGrid.SetMinSize(wx.Size(0, 150)) self.ProcessVariablesGrid.SetDropTarget(ProcessVariableDropTarget(self)) - self.ProcessVariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, + self.ProcessVariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGING, self.OnProcessVariablesGridCellChange) self.ProcessVariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnProcessVariablesGridCellLeftClick) @@ -678,7 +678,7 @@ startup_commands_label = wx.StaticText(self.EthercatMasterEditor, label=_("Startup service variables assignments:")) - startup_commands_header.AddWindow(startup_commands_label, 1, + startup_commands_header.Add(startup_commands_label, 1, flag=wx.ALIGN_CENTER_VERTICAL) for name, bitmap, help in [ @@ -686,14 +686,14 @@ ("DeleteCommandButton", "remove_element", _("Remove startup service variable"))]: button = wx.lib.buttons.GenBitmapButton(self.EthercatMasterEditor, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) - button.SetToolTipString(help) + button.SetToolTip(help) setattr(self, name, button) - startup_commands_header.AddWindow(button, border=5, flag=wx.LEFT) + startup_commands_header.Add(button, border=5, flag=wx.LEFT) self.StartupCommandsGrid = CustomGrid(self.EthercatMasterEditor, style=wx.VSCROLL) self.StartupCommandsGrid.SetDropTarget(StartupCommandDropTarget(self)) self.StartupCommandsGrid.SetMinSize(wx.Size(0, 150)) - self.StartupCommandsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, + self.StartupCommandsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGING, self.OnStartupCommandsGridCellChange) self.StartupCommandsGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnStartupCommandsGridEditorShow) @@ -702,29 +702,29 @@ main_staticbox = wx.StaticBox(self.EthercatMasterEditor, label=_("Node filter:")) staticbox_sizer = wx.StaticBoxSizer(main_staticbox, wx.VERTICAL) - self.EthercatMasterEditorSizer.AddSizer(staticbox_sizer, 0, border=10, flag=wx.GROW | wx.ALL) + self.EthercatMasterEditorSizer.Add(staticbox_sizer, 0, border=10, flag=wx.GROW | wx.ALL) main_staticbox_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=6, vgap=0) main_staticbox_sizer.AddGrowableCol(0) main_staticbox_sizer.AddGrowableRow(2) main_staticbox_sizer.AddGrowableRow(4) main_staticbox_sizer.AddGrowableRow(5) - staticbox_sizer.AddSizer(main_staticbox_sizer, 1, flag=wx.GROW) - main_staticbox_sizer.AddWindow(self.NodesFilter, border=5, flag=wx.GROW | wx.ALL) - main_staticbox_sizer.AddSizer(process_variables_header, border=5, + staticbox_sizer.Add(main_staticbox_sizer, 1, flag=wx.GROW) + main_staticbox_sizer.Add(self.NodesFilter, border=5, flag=wx.GROW | wx.ALL) + main_staticbox_sizer.Add(process_variables_header, border=5, flag=wx.GROW | wx.LEFT | wx.RIGHT | wx.BOTTOM) - main_staticbox_sizer.AddWindow(self.ProcessVariablesGrid, 1, + main_staticbox_sizer.Add(self.ProcessVariablesGrid, 1, border=5, flag=wx.GROW | wx.LEFT | wx.RIGHT | wx.BOTTOM) - main_staticbox_sizer.AddSizer(startup_commands_header, + main_staticbox_sizer.Add(startup_commands_header, border=5, flag=wx.GROW | wx.LEFT | wx.RIGHT | wx.BOTTOM) - main_staticbox_sizer.AddWindow(self.StartupCommandsGrid, 1, + main_staticbox_sizer.Add(self.StartupCommandsGrid, 1, border=5, flag=wx.GROW | wx.LEFT | wx.RIGHT | wx.BOTTOM) second_staticbox = wx.StaticBox(self.EthercatMasterEditor, label=_("Nodes variables filter:")) second_staticbox_sizer = wx.StaticBoxSizer(second_staticbox, wx.VERTICAL) - second_staticbox_sizer.AddSizer(self.NodesVariables, 1, border=5, flag=wx.GROW | wx.ALL) - - main_staticbox_sizer.AddSizer(second_staticbox_sizer, 1, + second_staticbox_sizer.Add(self.NodesVariables, 1, border=5, flag=wx.GROW | wx.ALL) + + main_staticbox_sizer.Add(second_staticbox_sizer, 1, border=5, flag=wx.GROW | wx.LEFT | wx.RIGHT | wx.BOTTOM) self.EthercatMasterEditor.SetSizer(self.EthercatMasterEditorSizer) @@ -1113,21 +1113,21 @@ ESI_files_label = wx.StaticText(parent, label=_("ESI Files:")) - self.AddWindow(ESI_files_label, border=10, + self.Add(ESI_files_label, border=10, flag=wx.TOP | wx.LEFT | wx.RIGHT) folder_tree_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=1, vgap=0) folder_tree_sizer.AddGrowableCol(0) folder_tree_sizer.AddGrowableRow(0) - self.AddSizer(folder_tree_sizer, border=10, + self.Add(folder_tree_sizer, border=10, flag=wx.GROW | wx.LEFT | wx.RIGHT) self.ESIFiles = FolderTree(parent, self.GetPath(), editable=False) self.ESIFiles.SetFilter(".xml") - folder_tree_sizer.AddWindow(self.ESIFiles, flag=wx.GROW) + folder_tree_sizer.Add(self.ESIFiles, flag=wx.GROW) buttons_sizer = wx.BoxSizer(wx.VERTICAL) - folder_tree_sizer.AddSizer(buttons_sizer, + folder_tree_sizer.Add(buttons_sizer, flag=wx.ALIGN_CENTER_VERTICAL) for idx, (name, bitmap, help, callback) in enumerate(buttons): @@ -1135,7 +1135,7 @@ bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) - button.SetToolTipString(help) + button.SetToolTip(help) setattr(self, name, button) if idx > 0: flag = wx.TOP @@ -1145,14 +1145,14 @@ callback = getattr(self, "On" + name, None) if callback is not None: parent.Bind(wx.EVT_BUTTON, callback, button) - buttons_sizer.AddWindow(button, border=10, flag=flag) + buttons_sizer.Add(button, border=10, flag=flag) modules_label = wx.StaticText(parent, label=_("Modules library:")) - self.AddSizer(modules_label, border=10, + self.Add(modules_label, border=10, flag=wx.LEFT | wx.RIGHT) - self.ModulesGrid = wx.gizmos.TreeListCtrl(parent, + self.ModulesGrid = wx.adv.TreeListCtrl(parent, style=wx.TR_DEFAULT_STYLE | wx.TR_ROW_LINES | wx.TR_COLUMN_LINES | @@ -1166,7 +1166,7 @@ self.OnModulesGridEndLabelEdit) self.ModulesGrid.GetHeaderWindow().Bind(wx.EVT_MOTION, self.OnModulesGridHeaderMotion) - self.AddWindow(self.ModulesGrid, border=10, + self.Add(self.ModulesGrid, border=10, flag=wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT) for colname, colsize, colalign in zip( @@ -1335,7 +1335,7 @@ if col > 0 and self.LastToolTipCol != col: self.LastToolTipCol = col _param, param_infos = self.ModuleLibrary.MODULES_EXTRA_PARAMS[col - 1] - wx.CallAfter(self.ModulesGrid.GetHeaderWindow().SetToolTipString, + wx.CallAfter(self.ModulesGrid.GetHeaderWindow().SetToolTip, param_infos["description"]) event.Skip() @@ -1359,13 +1359,14 @@ ("DeleteButton", "remove_element", _("Remove file from database"), None) ]) self.DatabaseSizer.SetControlMinSize(wx.Size(0, 0)) - main_sizer.AddSizer(self.DatabaseSizer, border=10, + main_sizer.Add(self.DatabaseSizer, border=10, flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT) button_sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE) - button_sizer.GetAffirmativeButton().SetLabel(_("Add file to project")) - button_sizer.GetCancelButton().SetLabel(_("Close")) - main_sizer.AddSizer(button_sizer, border=10, + # FIXME: find a way to change buttons label compatible with wxPython 4.x + # button_sizer.GetAffirmativeButton().SetLabel(_("Add file to project")) + # button_sizer.GetCancelButton().SetLabel(_("Close")) + main_sizer.Add(button_sizer, border=10, flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT) self.SetSizer(main_sizer) diff -r 59158e360b8c -r f5850ce25caf etherlab/EtherCATManagementEditor.py --- a/etherlab/EtherCATManagementEditor.py Thu Jul 14 11:40:27 2022 +0200 +++ b/etherlab/EtherCATManagementEditor.py Sun Jul 17 22:53:35 2022 +0200 @@ -15,7 +15,7 @@ import wx import wx.grid -import wx.gizmos +import wx.adv import wx.lib.buttons # -------------------------------------------------------------------- @@ -135,7 +135,7 @@ self.SizerDic["SlaveInfosDetailsInnerSizer"].AddMany([self.StaticTextDic[statictext_name], self.TextCtrlDic[textctrl_name]]) - self.SizerDic["SlaveInfosDetailsBox"].AddSizer(self.SizerDic["SlaveInfosDetailsInnerSizer"]) + self.SizerDic["SlaveInfosDetailsBox"].Add(self.SizerDic["SlaveInfosDetailsInnerSizer"]) self.SyncManagersGrid = CustomGrid(self, size=wx.Size(605, 155), style=wx.VSCROLL) @@ -153,7 +153,7 @@ for button_name, button_id, button_label, button_tooltipstring, event_method, sub_item in buttons: self.ButtonDic[button_name] = wx.Button(self, id=button_id, label=_(button_label)) self.ButtonDic[button_name].Bind(wx.EVT_BUTTON, event_method) - self.ButtonDic[button_name].SetToolTipString(button_tooltipstring) + self.ButtonDic[button_name].SetToolTip(button_tooltipstring) self.SizerDic["SlaveState_up_sizer"].Add(self.ButtonDic[button_name]) for statictext_name, statictext_label, textctrl_name in sub_item: self.StaticTextDic[statictext_name] = wx.StaticText(self, label=_(statictext_label)) @@ -166,7 +166,7 @@ ("StopTimerButton", "Stop State Monitoring", "Slave State Update Stop", self.CurrentStateThreadStop)]: self.ButtonDic[button_name] = wx.Button(self, label=_(button_label)) self.ButtonDic[button_name].Bind(wx.EVT_BUTTON, event_method) - self.ButtonDic[button_name].SetToolTipString(button_tooltipstring) + self.ButtonDic[button_name].SetToolTip(button_tooltipstring) self.SizerDic["SlaveState_down_sizer"].Add(self.ButtonDic[button_name]) self.SizerDic["SlaveState_sizer"].AddMany([self.SizerDic["SlaveState_up_sizer"], @@ -1729,7 +1729,7 @@ wx.Panel.__init__(self, parent, -1, size=(350, 500)) - self.Tree = wx.gizmos.TreeListCtrl(self, -1, size=(350, 500), + self.Tree = wx.adv.TreeListCtrl(self, -1, size=(350, 500), style=(wx.TR_DEFAULT_STYLE | wx.TR_FULL_ROW_HIGHLIGHT | wx.TR_HIDE_ROOT | @@ -2692,7 +2692,7 @@ self.TextCtrl[key] = wx.TextCtrl(self, size=wx.Size(130, 24), style=wx.TE_READONLY) self.MasterStateSizer['innerMasterState'].AddMany([self.StaticText[key], self.TextCtrl[key]]) - self.MasterStateSizer['masterState'].AddSizer(self.MasterStateSizer['innerMasterState']) + self.MasterStateSizer['masterState'].Add(self.MasterStateSizer['innerMasterState']) # ----------------------- Ethernet Network Card Information --------------------------------------- for key, label in [ @@ -2705,7 +2705,7 @@ self.TextCtrl[key] = wx.TextCtrl(self, size=wx.Size(130, 24), style=wx.TE_READONLY) self.MasterStateSizer['innerDeviceInfo'].AddMany([self.StaticText[key], self.TextCtrl[key]]) - self.MasterStateSizer['deviceInfo'].AddSizer(self.MasterStateSizer['innerDeviceInfo']) + self.MasterStateSizer['deviceInfo'].Add(self.MasterStateSizer['innerDeviceInfo']) # ----------------------- Network Frame Information ----------------------------------------------- for key, label in [ @@ -2722,13 +2722,13 @@ self.TextCtrl[key][index] = wx.TextCtrl(self, size=wx.Size(130, 24), style=wx.TE_READONLY) self.MasterStateSizer['innerFrameInfo'].Add(self.TextCtrl[key][index]) - self.MasterStateSizer['frameInfo'].AddSizer(self.MasterStateSizer['innerFrameInfo']) + self.MasterStateSizer['frameInfo'].Add(self.MasterStateSizer['innerFrameInfo']) # ------------------------------- Slave Information ----------------------------------------------- self.SITreeListCtrl = SITreeListCtrl(self, self.Controler) self.MasterStateSizer["innerSlaveInfo"].AddMany([self.SIUpdateButton, self.SITreeListCtrl]) - self.MasterStateSizer["slaveInfo"].AddSizer( + self.MasterStateSizer["slaveInfo"].Add( self.MasterStateSizer["innerSlaveInfo"]) # --------------------------------- Main Sizer ---------------------------------------------------- @@ -2743,7 +2743,7 @@ ("main", [ "innerTop", "innerMiddle", "innerBottom"])]: for key2 in sub: - self.MasterStateSizer[key].AddSizer(self.MasterStateSizer[key2]) + self.MasterStateSizer[key].Add(self.MasterStateSizer[key2]) self.SetSizer(self.MasterStateSizer["main"]) @@ -2798,7 +2798,7 @@ self.Controler=controler - self.Tree = wx.gizmos.TreeListCtrl(self, -1, size=wx.Size(750,350), + self.Tree = wx.adv.TreeListCtrl(self, -1, size=wx.Size(750,350), style=wx.TR_HAS_BUTTONS |wx.TR_HIDE_ROOT |wx.TR_ROW_LINES diff -r 59158e360b8c -r f5850ce25caf exemples/python/plc.xml --- a/exemples/python/plc.xml Thu Jul 14 11:40:27 2022 +0200 +++ b/exemples/python/plc.xml Sun Jul 17 22:53:35 2022 +0200 @@ -1,7 +1,7 @@ - + @@ -269,12 +269,12 @@ - - - - - - '666' + + + + + + 'sys.stdout.write("Hello world\n")' @@ -293,9 +293,11 @@ - + - + + + @@ -739,12 +741,6 @@ Happy hacking! ]]> - - - - - - @@ -1443,10 +1439,10 @@ Test_Python_Var - + - + 23 @@ -1464,6 +1460,44 @@ SomeVarName + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 59158e360b8c -r f5850ce25caf exemples/svghmi_traffic_light/svghmi_0@svghmi/svghmi.svg --- a/exemples/svghmi_traffic_light/svghmi_0@svghmi/svghmi.svg Thu Jul 14 11:40:27 2022 +0200 +++ b/exemples/svghmi_traffic_light/svghmi_0@svghmi/svghmi.svg Sun Jul 17 22:53:35 2022 +0200 @@ -1251,14 +1251,14 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="1.979899" - inkscape:cx="205.65994" - inkscape:cy="103.00174" + inkscape:cx="52.116754" + inkscape:cy="96.940825" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" units="px" - inkscape:window-width="1600" - inkscape:window-height="836" + inkscape:window-width="3840" + inkscape:window-height="2096" inkscape:window-x="0" inkscape:window-y="27" inkscape:window-maximized="1" @@ -1274,7 +1274,7 @@ image/svg+xml - + @@ -1283,6 +1283,14 @@ inkscape:groupmode="layer" id="layer1" transform="translate(37.474617,-760.93329)"> + ON - diff -r 59158e360b8c -r f5850ce25caf fake_wx.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fake_wx.py Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,111 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sys +import new +from types import ModuleType + +# TODO use gettext instead +def get_translation(txt): + return txt + + +class FakeObject: + def __init__(self, *args, **kwargs): + self.__classname__ = kwargs["__classname__"] + + def __getattr__(self,name): + if name.startswith('__'): + raise AttributeError, name + return FakeObject(__classname__=self.__classname__+"."+name) + + def __call__(self, *args, **kwargs): + return FakeObject(__classname__=self.__classname__+"()") + + def __getitem__(self, key): + raise IndexError, key + + def __str__(self): + return self.__classname__ + + def __or__(self, other): + return FakeObject(__classname__=self.__classname__+"|"+other.__classname__) + + +class FakeClass: + def __init__(self, *args, **kwargs): + print("DUMMY Class __init__ !",self.__name__,args,kwargs) + + +class FakeModule(ModuleType): + def __init__(self, name, classes): + self.__modname__ = name + self.__objects__ = dict(map(lambda desc: + (desc, new.classobj(desc, (FakeClass,), {})) + if type(desc)==str else desc, classes)) + ModuleType(name) + + def __getattr__(self,name): + if name.startswith('__'): + raise AttributeError, name + + if self.__objects__.has_key(name): + return self.__objects__[name] + + obj = FakeObject(__classname__=self.__modname__+"."+name) + self.__objects__[name] = obj + return obj + + +# Keep track of already faked modules to catch those +# that are already present in sys.modules from start +# (i.e. mpl_toolkits for exemple) +already_patched = {} + +for name, classes in [ + # list given for each module name contains name string for a FakeClass, + # otherwise a tuple (name, object) for arbitrary object/function/class + ('wx',[ + 'Panel', 'PyCommandEvent', 'Dialog', 'PopupWindow', 'TextEntryDialog', + 'Notebook', 'ListCtrl', 'TextDropTarget', 'PyControl', 'TextCtrl', + 'SplitterWindow', 'Frame', 'Printout', 'StaticBitmap', 'DropTarget', + ('GetTranslation', get_translation)]), + ('wx.lib.agw.advancedsplash',[]), + ('wx.dataview',['DataViewIndexListModel', 'PyDataViewIndexListModel']), + ('wx.lib.buttons',['GenBitmapTextButton']), + ('wx.adv',['EditableListBox']), + ('wx.grid',[ + 'Grid', 'PyGridTableBase', 'GridCellEditor', 'GridCellTextEditor', + 'GridCellChoiceEditor']), + ('wx.lib.agw.customtreectrl',['CustomTreeCtrl']), + ('wx.lib.gizmos',[]), + ('wx.lib.intctrl',['IntCtrl']), + ('matplotlib.pyplot',[]), + ('matplotlib.backends.backend_wxagg',['FigureCanvasWxAgg']), + ('wx.stc',['StyledTextCtrl']), + ('wx.lib.scrolledpanel',[]), + ('wx.lib.mixins.listctrl',['ColumnSorterMixin', 'ListCtrlAutoWidthMixin']), + ('wx.dataview',['PyDataViewIndexListModel']), + ('matplotlib.backends.backend_agg',[]), + ('wx.aui',[]), + ('mpl_toolkits.mplot3d',[])]: + modpath = None + parentmod = None + for identifier in name.split("."): + modpath = (modpath + "." + identifier) if modpath else identifier + mod = sys.modules.get(modpath, None) + + if mod is None or modpath not in already_patched: + mod = FakeModule(modpath, classes) + sys.modules[modpath] = mod + already_patched[modpath] = True + + if parentmod is not None: + parentmod.__objects__[identifier] = mod + + parentmod = mod + +from six.moves import builtins + +builtins.__dict__['_'] = get_translation + diff -r 59158e360b8c -r f5850ce25caf graphics/FBD_Objects.py --- a/graphics/FBD_Objects.py Thu Jul 14 11:40:27 2022 +0200 +++ b/graphics/FBD_Objects.py Sun Jul 17 22:53:35 2022 +0200 @@ -122,10 +122,10 @@ # Returns if the point given is in the bounding box def HitTest(self, pt, connectors=True): if self.Name != "": - test_text = self.GetTextBoundingBox().InsideXY(pt.x, pt.y) + test_text = self.GetTextBoundingBox().Contains(pt.x, pt.y) else: test_text = False - test_block = self.GetBlockBoundingBox(connectors).InsideXY(pt.x, pt.y) + test_block = self.GetBlockBoundingBox(connectors).Contains(pt.x, pt.y) return test_text or test_block # Returns the bounding box of the name outside the block @@ -392,7 +392,7 @@ # pos = event.GetLogicalPosition(dc) # for input in self.Inputs: # rect = input.GetRedrawRect() -# if rect.InsideXY(pos.x, pos.y): +# if rect.Contains(pos.x, pos.y): # print "Find input" # tip = wx.TipWindow(self.Parent, "Test") # tip.SetBoundingRect(rect) @@ -771,6 +771,7 @@ Graphic_Element.Draw(self, dc) dc.SetPen(MiterPen(wx.BLACK)) dc.SetBrush(wx.WHITE_BRUSH) + dc.SetTextForeground(wx.BLACK) if getattr(dc, "printing", False): name_size = dc.GetTextExtent(self.Name) @@ -1011,6 +1012,7 @@ Graphic_Element.Draw(self, dc) dc.SetPen(MiterPen(wx.BLACK)) dc.SetBrush(wx.WHITE_BRUSH) + dc.SetTextForeground(wx.BLACK) if getattr(dc, "printing", False): name_size = dc.GetTextExtent(self.Name) diff -r 59158e360b8c -r f5850ce25caf graphics/GraphicCommons.py --- a/graphics/GraphicCommons.py Thu Jul 14 11:40:27 2022 +0200 +++ b/graphics/GraphicCommons.py Sun Jul 17 22:53:35 2022 +0200 @@ -388,11 +388,11 @@ rect = self.BoundingBox else: rect = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0], self.Size[1]) - return rect.InsideXY(pt.x, pt.y) + return rect.Contains(pt.x, pt.y) # Returns if the point given is in the bounding box def IsInSelection(self, rect): - return rect.InsideXY(self.BoundingBox.x, self.BoundingBox.y) and rect.InsideXY(self.BoundingBox.x + self.BoundingBox.width, self.BoundingBox.y + self.BoundingBox.height) + return rect.Contains(self.BoundingBox.x, self.BoundingBox.y) and rect.Contains(self.BoundingBox.x + self.BoundingBox.width, self.BoundingBox.y + self.BoundingBox.height) # Override this method for refreshing the bounding box def RefreshBoundingBox(self): @@ -448,7 +448,7 @@ intern_rect = wx.Rect(left + HANDLE_SIZE, top + HANDLE_SIZE, right - left - HANDLE_SIZE, bottom - top - HANDLE_SIZE) # Verify that this element is selected - if self.Selected and extern_rect.InsideXY(pt.x, pt.y) and not intern_rect.InsideXY(pt.x, pt.y): + if self.Selected and extern_rect.Contains(pt.x, pt.y) and not intern_rect.Contains(pt.x, pt.y): # Find if point is on a handle horizontally if left <= pt.x < left + HANDLE_SIZE: handle_x = 1 @@ -1401,7 +1401,7 @@ width = ANCHOR_DISTANCE * 2 + abs(self.Direction[0]) * CONNECTOR_SIZE height = ANCHOR_DISTANCE * 2 + abs(self.Direction[1]) * CONNECTOR_SIZE rect = wx.Rect(x, y, width, height) - inside = rect.InsideXY(pt.x, pt.y) + inside = rect.Contains(pt.x, pt.y) return inside @@ -1933,7 +1933,7 @@ # Calculate a rectangle around the segment rect = wx.Rect(min(x1, x2) - ANCHOR_DISTANCE, min(y1, y2) - ANCHOR_DISTANCE, abs(x1 - x2) + 2 * ANCHOR_DISTANCE, abs(y1 - y2) + 2 * ANCHOR_DISTANCE) - test |= rect.InsideXY(pt.x, pt.y) + test |= rect.Contains(pt.x, pt.y) return test # Returns the wire start or end point if the point given is on one of them @@ -1941,13 +1941,13 @@ # Test the wire start point rect = wx.Rect(self.Points[0].x - ANCHOR_DISTANCE, self.Points[0].y - ANCHOR_DISTANCE, 2 * ANCHOR_DISTANCE, 2 * ANCHOR_DISTANCE) - if rect.InsideXY(pt.x, pt.y): + if rect.Contains(pt.x, pt.y): return 0 # Test the wire end point if len(self.Points) > 1: rect = wx.Rect(self.Points[-1].x - ANCHOR_DISTANCE, self.Points[-1].y - ANCHOR_DISTANCE, 2 * ANCHOR_DISTANCE, 2 * ANCHOR_DISTANCE) - if rect.InsideXY(pt.x, pt.y): + if rect.Contains(pt.x, pt.y): return -1 return None @@ -1961,7 +1961,7 @@ # Calculate a rectangle around the segment rect = wx.Rect(min(x1, x2) - ANCHOR_DISTANCE, min(y1, y2) - ANCHOR_DISTANCE, abs(x1 - x2) + 2 * ANCHOR_DISTANCE, abs(y1 - y2) + 2 * ANCHOR_DISTANCE) - if rect.InsideXY(pt.x, pt.y): + if rect.Contains(pt.x, pt.y): return i, self.Segments[i] return None diff -r 59158e360b8c -r f5850ce25caf graphics/RubberBand.py --- a/graphics/RubberBand.py Thu Jul 14 11:40:27 2022 +0200 +++ b/graphics/RubberBand.py Sun Jul 17 22:53:35 2022 +0200 @@ -94,7 +94,7 @@ # Change viewer mouse cursor to reflect a rubberband bounding box is # edited - self.DrawingSurface.SetCursor(wx.StockCursor(wx.CURSOR_CROSS)) + self.DrawingSurface.SetCursor(wx.Cursor(wx.CURSOR_CROSS)) self.Redraw() @@ -195,3 +195,25 @@ """ # Erase last bbox and draw current bbox self.DrawBoundingBoxes([self.CurrentBBox], dc) + + +def PatchRubberBandForGTK3(): + """ + GTK3 implementation of DC doesn't support SetLogicalFuntion(XOR) + Then Rubberband can't be erased by just redrawing it on the same place + So this is a complete refresh instead, eating a lot of CPU. + """ + def Redraw(self, dc=None): + self.Viewer.Refresh() + self.Draw() + + RubberBand.Redraw = Redraw + + def Erase(self, dc=None): + self.Viewer.Refresh() + + RubberBand.Erase = Erase + + +if "gtk3" in wx.PlatformInfo: + PatchRubberBandForGTK3() diff -r 59158e360b8c -r f5850ce25caf graphics/SFC_Objects.py --- a/graphics/SFC_Objects.py Thu Jul 14 11:40:27 2022 +0200 +++ b/graphics/SFC_Objects.py Sun Jul 17 22:53:35 2022 +0200 @@ -719,7 +719,7 @@ self.Pos.y + (self.Size[1] - text_height) // 2, text_width, text_height) - test_text = text_bbx.InsideXY(pt.x, pt.y) + test_text = text_bbx.Contains(pt.x, pt.y) else: test_text = False return test_text or Graphic_Element.HitTest(self, pt, connectors) @@ -1204,7 +1204,7 @@ # Returns if the point given is in the bounding box def HitTest(self, pt, connectors=True): - return self.BoundingBox.InsideXY(pt.x, pt.y) or self.TestConnector(pt, exclude=False) is not None + return self.BoundingBox.Contains(pt.x, pt.y) or self.TestConnector(pt, exclude=False) is not None # Refresh the divergence bounding box def RefreshBoundingBox(self): @@ -1592,7 +1592,7 @@ self.Pos.y + (self.Size[1] - text_height) // 2, text_width, text_height) - return text_bbx.InsideXY(pt.x, pt.y) or Graphic_Element.HitTest(self, pt, connectors) + return text_bbx.Contains(pt.x, pt.y) or Graphic_Element.HitTest(self, pt, connectors) # Refresh the jump bounding box def RefreshBoundingBox(self): diff -r 59158e360b8c -r f5850ce25caf opc_ua/opcua_client_maker.py --- a/opc_ua/opcua_client_maker.py Thu Jul 14 11:40:27 2022 +0200 +++ b/opc_ua/opcua_client_maker.py Sun Jul 17 22:53:35 2022 +0200 @@ -7,7 +7,7 @@ from opcua import ua import wx -from wx.lib.agw.hypertreelist import HyperTreeList as TreeListCtrl +import wx.lib.gizmos as gizmos # Formerly wx.gizmos in Classic import wx.dataview as dv @@ -38,9 +38,9 @@ directions = ["input", "output"] -class OPCUASubListModel(dv.PyDataViewIndexListModel): +class OPCUASubListModel(dv.DataViewIndexListModel): def __init__(self, data, log): - dv.PyDataViewIndexListModel.__init__(self, len(data)) + dv.DataViewIndexListModel.__init__(self, len(data)) self.data = data self.log = log @@ -283,10 +283,10 @@ self.tree_sizer.AddGrowableCol(0) self.tree_sizer.AddGrowableRow(0) - self.tree = TreeListCtrl(self.tree_panel, -1, style=0, agwStyle= - wx.TR_DEFAULT_STYLE - | wx.TR_MULTIPLE - | wx.TR_FULL_ROW_HIGHLIGHT + self.tree = gizmos.TreeListCtrl(self.tree_panel, -1, style=0, agwStyle= + gizmos.TR_DEFAULT_STYLE + | gizmos.TR_MULTIPLE + | gizmos.TR_FULL_ROW_HIGHLIGHT ) prepare_image_list() diff -r 59158e360b8c -r f5850ce25caf svghmi/gen_index_xhtml.xslt --- a/svghmi/gen_index_xhtml.xslt Thu Jul 14 11:40:27 2022 +0200 +++ b/svghmi/gen_index_xhtml.xslt Sun Jul 17 22:53:35 2022 +0200 @@ -5600,12 +5600,6 @@ this.disabled = !Number(value); - - - // TODO : use RequestAnimate and animate() - - - this.update_state(); } @@ -6353,8 +6347,6 @@ } - // TODO : use RequestAnimate and animate() - } diff -r 59158e360b8c -r f5850ce25caf svghmi/ui.py --- a/svghmi/ui.py Thu Jul 14 11:40:27 2022 +0200 +++ b/svghmi/ui.py Sun Jul 17 22:53:35 2022 +0200 @@ -58,13 +58,13 @@ display_name = ('{} (class={})'.format(c.name, c.hmiclass)) \ if c.hmiclass is not None else c.name tc_child = self.AppendItem(current_tc_root, display_name) - self.SetPyData(tc_child, c) + self.SetItemData(tc_child, c) self._recurseTree(c,tc_child) else: display_name = '{} {}'.format(c.nodetype[4:], c.name) tc_child = self.AppendItem(current_tc_root, display_name) - self.SetPyData(tc_child, c) + self.SetItemData(tc_child, c) def OnTreeNodeSelection(self, event): items = self.GetSelections() @@ -106,7 +106,7 @@ root_display_name = _("Please build to see HMI Tree") \ if hmi_tree_root is None else "HMI" self.root = self.AddRoot(root_display_name) - self.SetPyData(self.root, hmi_tree_root) + self.SetItemData(self.root, hmi_tree_root) if hmi_tree_root is not None: self._recurseTree(hmi_tree_root, self.root) @@ -146,11 +146,11 @@ for d in dirlist: current_tc_root = self.AppendItem(current_tc_root, d) res.append(current_tc_root) - self.SetPyData(current_tc_root, None) + self.SetItemData(current_tc_root, None) dirlist = [] res.pop() tc_child = self.AppendItem(current_tc_root, f) - self.SetPyData(tc_child, p) + self.SetItemData(tc_child, p) return res def MakeTree(self, lib_dir = None): @@ -163,7 +163,7 @@ root_display_name = _("Please select widget library directory") \ if lib_dir is None else os.path.basename(lib_dir) self.root = self.AddRoot(root_display_name) - self.SetPyData(self.root, None) + self.SetItemData(self.root, None) if lib_dir is not None and os.path.exists(lib_dir): self._recurseTree(lib_dir, self.root, []) diff -r 59158e360b8c -r f5850ce25caf tests/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/Makefile Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,227 @@ +#! gmake + +# beremiz/tests/Makefile : +# +# Makefile to prepare and run Beremiz tests. +# +# For developper to: +# - quickly run a test (TDD) on current code +# - write new tests, debug existing tests +# +# Use cases : +# +# run given tests +# $ make run_python_exemple.sikuli +# +# run tests from particular test classes +# $ make ide_tests +# +# run one particular test in a Xnest window +# $ make xnest_run_python_exemple.sikuli +# +# run Xnest window with just xterm +# $ make xnest_xterm +# +# run Xnest window with sikuli IDE and xterm +# $ make xnest_sikuli +# +# build minimal beremiz and matiec to run tests +# $ make built_apps +# +# For CI/CD scripts to catch and report all failures. Use cases : +# +# run all tests +# $ make +# +# +# Test results, and other test byproducts are in $(test_dir), +# $(test_dir) defaults to $(HOME)/test and can be overloaded: +# $ make test_dir=${HOME}/other_test_dir +# +# Makefile attemps to use xvfb-run to run each test individually with its own +# X server instance. This behavior can be overloaded +# $ DISPLAY=:42 make xserver_command='echo "Using $DISPLAY X Server !";' +# +# Matiec and Beremiz code are expected to be clean, ready to build +# Any change in Matiec directory triggers rebuild of matiec. +# Any change in Matiec and Beremiz directory triggers copy of source code +# to $(test_dir)/build. +# +# BEREMIZPYTHONPATH is expected to be absolute path to python interpreter +# +# Please note: +# In order to run asside a freshly build Matiec, tested beremiz instance +# needs to run on code from $(test_dir)/build/beremiz, a fresh copy +# of the Beremiz directory $(src)/beremiz, where we run tests from. +# + +all: source_check cli_tests ide_tests runtime_tests + +# Variable $(src) is directory such that executed +# $(src)/Makefile is this file. +src := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) + +# $(workspace) is directory containing this project +workspace ?= $(abspath $(src)/../..) + +test_dir ?= $(HOME)/test +build_dir = $(test_dir)/build + +# +# SOURCE and BUILD +# + +BUILT_PROJECTS=beremiz matiec open62541 + +tar_opts=--absolute-names --exclude=.hg --exclude=.git --exclude=.*.pyc --exclude=.*.swp + +# sha1 checksum of source is used to force copy/compile on each change + +define make_checksum_assign +$(1)_checksum = $(shell tar $(tar_opts) -c $(workspace)/$(1) | sha1sum | cut -d ' ' -f 1) +endef +$(foreach project,$(BUILT_PROJECTS),$(eval $(call make_checksum_assign,$(project)))) + +$(build_dir): + mkdir -p $(build_dir) + +define make_src_rule +$(build_dir)/$(1)/$($(1)_checksum).sha1: | $(build_dir) $(workspace)/$(1) + rm -rf $(build_dir)/$(1) + tar -C $(workspace) $(tar_opts) -c $(1) | tar -C $(build_dir) -x + touch $$@ +endef +$(foreach project,$(BUILT_PROJECTS),$(eval $(call make_src_rule,$(project)))) + +$(build_dir)/matiec/iec2c: $(build_dir)/matiec/$(matiec_checksum).sha1 + cd $(build_dir)/matiec && \ + autoreconf -i && \ + ./configure && \ + make + +$(build_dir)/open62541/build/bin/libopen62541.a: $(build_dir)/open62541/$(open62541_checksum).sha1 + cd $(build_dir)/open62541 && \ + rm -rf build && mkdir build && cd build && \ + cmake .. && \ + make + +built_apps: $(build_dir)/matiec/iec2c $(build_dir)/beremiz/$(beremiz_checksum).sha1 $(build_dir)/open62541/build/bin/libopen62541.a + touch $@ + +define log_command + $(call $(1),$(2)) | tee test_stdout.txt; exit $$$${PIPESTATUS[0]} +endef + +define prep_test + rm -rf $(test_dir)/$(1)_results + mkdir $(test_dir)/$(1)_results + cd $(test_dir)/$(1)_results +endef + +# +# IDE TESTS +# + +ide_test_dir = $(src)/ide_tests +sikuli_ide_tests = $(subst $(ide_test_dir)/,,$(wildcard $(ide_test_dir)/*.sikuli)) +pytest_ide_tests = $(subst $(ide_test_dir)/,,$(wildcard $(ide_test_dir)/*.pytest)) + +define sikuli_idetest_command + (fluxbox >/dev/null 2>&1 &); BEREMIZPATH=$(build_dir)/beremiz sikulix -r $(src)/ide_tests/$(1) +endef + + +DELAY=400 +KILL_DELAY=430 +PYTEST=$(dir $(BEREMIZPYTHONPATH))/pytest +define pytest_idetest_command + (fluxbox >/dev/null 2>&1 &); PYTHONPATH=$(ide_test_dir) timeout -k $(KILL_DELAY) $(DELAY) $(PYTEST) --maxfail=1 --timeout=100 $(src)/ide_tests/$(1) +endef + +# Xnest based interactive sessions for tests edit and debug. +# Would be nice with something equivalent to xvfb-run, waiting for USR1. +# Arbitrary "sleep 1" is probably enough for interactive use +define xnest_run + Xnest :42 -geometry 1920x1080+0+0 & export xnestpid=$$!; sleep 1; DISPLAY=:42 $(1); export res=$$?; kill $${xnestpid} 2>/dev/null; exit $${res} +endef + +xserver_command ?= xvfb-run -s '-screen 0 1920x1080x24' + +define make_idetest_rule +$(test_dir)/$(1)_results/.passed: built_apps + $(call prep_test,$(1)); $(xserver_command) bash -c '$(call log_command,$(2),$(1))' + touch $$@ + +# Manually invoked rule {testname}.sikuli +$(1): $(test_dir)/$(1)_results/.passed + +# Manually invoked rule xnest_{testname}.sikuli +# runs test in xnest so that one can see what happens +xnest_$(1): built_apps + $(call prep_test,$(1)); $$(call xnest_run, bash -c '$(call log_command,$(2),$(1))') + +ide_tests_targets += $(test_dir)/$(1)_results/.passed +endef +$(foreach idetest,$(sikuli_ide_tests),$(eval $(call make_idetest_rule,$(idetest),sikuli_idetest_command))) +$(foreach idetest,$(pytest_ide_tests),$(eval $(call make_idetest_rule,$(idetest),pytest_idetest_command))) + +ide_tests : $(ide_tests_targets) + echo "$(ide_tests_targets) : Passed" + +xnest_xterm: built_apps + $(call xnest_run, bash -c '(fluxbox &);xterm') + +xnest_sikuli: built_apps + $(call xnest_run, bash -c '(fluxbox &);(BEREMIZPATH=$(build_dir)/beremiz xterm -e sikulix &);xterm') + +xvfb_sikuli: built_apps + echo "******************************************" + echo "On host, run 'xvncviewer 127.0.0.1:5900' to see sikuli X session" + echo "Docker container must be created with TESTDEBUG=YES. For example :" + echo "./clean_docker_container.sh && ./build_docker_image.sh && TESTDEBUG=YES ./create_docker_container.sh && ./do_test_in_docker.sh xvfb_sikuli" + echo "******************************************" + $(xserver_command) bash -c '(fluxbox &);(x11vnc &);(BEREMIZPATH=$(build_dir)/beremiz xterm -e sikulix &);xterm' + +# +# CLI TESTS +# + +cli_test_dir = $(src)/cli_tests +cli_tests = $(subst $(cli_test_dir)/,,$(wildcard $(cli_test_dir)/*.bash)) + +define clitest_command + BEREMIZPATH=$(build_dir)/beremiz source $(src)/cli_tests/$(1) +endef + +define make_clitest_rule +$(test_dir)/$(1)_results/.passed: built_apps + $(call prep_test,$(1)); bash -c '$(call log_command,$(2),$(1))' + touch $$@ + +# Manually invoked rule +$(1): $(test_dir)/$(1)_results/.passed + +cli_tests_targets += $(test_dir)/$(1)_results/.passed +endef +$(foreach clitest,$(cli_tests),$(eval $(call make_clitest_rule,$(clitest),clitest_command))) + +cli_tests: $(cli_tests_targets) + echo "$(cli_tests_targets) : Passed" + +clean_results: + rm -rf $(test_dir)/*_results + +clean: clean_results + rm -rf $(build_dir) + + +# TODOs + +source_check: + echo TODO $@ + +runtime_tests: + echo TODO $@ + + + diff -r 59158e360b8c -r f5850ce25caf tests/cli_tests/opcua_test.bash --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/cli_tests/opcua_test.bash Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,84 @@ +#!/bin/bash + +rm -f ./SRVOK ./PLCOK + +# Run server +$BEREMIZPYTHONPATH - > >( + echo "Start SRV loop" + while read line; do + # Wait for server to print modified value + echo "SRV>> $line" + if [[ "$line" == 3.4 ]]; then + echo "PLC could write value" + touch ./SRVOK + fi + done + echo "End SRV loop" +) << EOF & + +import sys +import time + +from opcua import ua, Server + +server = Server() +server.set_endpoint("opc.tcp://127.0.0.1:4840/freeopcua/server/") + +uri = "http://beremiz.github.io" +idx = server.register_namespace(uri) + +objects = server.get_objects_node() + +testobj = objects.add_object(idx, "TestObject") +testvarout = testobj.add_variable(idx, "TestOut", 1.2) +testvar = testobj.add_variable(idx, "TestIn", 5.6) +testvar.set_writable() + +server.start() + +try: + while True: + time.sleep(1) + print testvar.get_value() + sys.stdout.flush() +finally: + server.stop() +EOF +SERVER_PID=$! + +# Start PLC with opcua test +setsid $BEREMIZPYTHONPATH $BEREMIZPATH/Beremiz_cli.py -k \ + --project-home $BEREMIZPATH/tests/projects/opcua_client build transfer run > >( +echo "Start PLC loop" +while read line; do + # Wait for PLC runtime to output expected value on stdout + echo "PLC>> $line" + if [[ "$line" == 1.2 ]]; then + echo "PLC could read value" + touch ./PLCOK + fi +done +echo "End PLC loop" +) & +PLC_PID=$! + +echo all subprocess started, start polling results +res=110 # default to ETIMEDOUT +c=30 +while ((c--)); do + if [[ -a ./SRVOK && -a ./PLCOK ]]; then + echo got results. + res=0 # OK success + break + else + echo waiting.... $c + sleep 1 + fi +done + +# Kill PLC and subprocess +echo will kill PLC:$PLC_PID and SERVER:$SERVER_PID +pkill -s $PLC_PID +kill $SERVER_PID + +exit $res diff -r 59158e360b8c -r f5850ce25caf tests/cli_tests/run_python_example.bash --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/cli_tests/run_python_example.bash Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,15 @@ +#!/bin/bash + +# Run python example throug command line, and check usual output + +coproc setsid $BEREMIZPYTHONPATH $BEREMIZPATH/Beremiz_cli.py -k --project-home ~/src/beremiz/exemples/python build transfer run; + +while read -u ${COPROC[0]} line; do + echo "$line" + if [[ "$line" == *Grumpf* ]]; then + pkill -9 -s $COPROC_PID + exit 0 + fi +done + +exit 42 diff -r 59158e360b8c -r f5850ce25caf tests/ide_tests/conftest.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/ide_tests/conftest.py Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# This file is part of Beremiz, a Integrated Development Environment for +# programming IEC 61131-3 automates supporting plcopen standard and CanFestival. +# +# Copyright (C) 2017: Andrey Skvortsov +# +# See COPYING file for copyrights details. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +from __future__ import absolute_import +import os +import sys + +# import pytest +# import xvfbwrapper + + +def init_environment(): + """Append module root directory to sys.path""" + try: + import Beremiz as _Beremiz + except ImportError: + sys.path.append( + os.path.abspath( + os.path.join( + os.path.dirname(__file__), '..', '..') + ) + ) + + +init_environment() + +# +# Something seems to be broken in Beremiz application, +# because after tests in test_application.py during Xvfb shutdown +# pytest returns error message: +# pytest: Fatal IO error 11 (Die Ressource ist zur Zeit nicht verfügbar) on X server :2821. +# +# As a result of that pytest returns code 1 as some tests were failed, +# but they aren't. +# +# To avoid this Xvfb is launched and killed not by pytest. +# $ Xvfb :42 -screen 0 1280x1024x24 & +# $ export DISPLAY=:42 +# $ pytest --timeout=10 ./tests/tools +# $ pkill -9 Xvfb +# +# TODO: find root of this problem. + + +# vdisplay = None +# +# @pytest.fixture(scope="session", autouse=True) +# def start_xvfb_server(request): +# global vdisplay +# vdisplay = xvfbwrapper.Xvfb(width=1280, height=720) +# vdisplay.start() +# request.addfinalizer(stop_xvfb_server) +# +# def stop_xvfb_server(): +# if vdisplay is not None: +# vdisplay.stop() diff -r 59158e360b8c -r f5850ce25caf tests/ide_tests/debug_project.sikuli/1646062660770.png Binary file tests/ide_tests/debug_project.sikuli/1646062660770.png has changed diff -r 59158e360b8c -r f5850ce25caf tests/ide_tests/debug_project.sikuli/1646066996789.png Binary file tests/ide_tests/debug_project.sikuli/1646066996789.png has changed diff -r 59158e360b8c -r f5850ce25caf tests/ide_tests/debug_project.sikuli/1646066996790.png Binary file tests/ide_tests/debug_project.sikuli/1646066996790.png has changed diff -r 59158e360b8c -r f5850ce25caf tests/ide_tests/debug_project.sikuli/debug_project.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/ide_tests/debug_project.sikuli/debug_project.py Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,68 @@ +""" This test opens, modifies, builds and runs exemple project named "python". +Test succeeds if runtime's stdout behaves as expected +""" + +import os +import time + +# allow module import from current test directory's parent +addImportPath(os.path.dirname(getBundlePath())) + +# common test definitions module +from sikuliberemiz import run_test + +def test(app): + + app.k.Clean() + + app.waitForChangeAndIdleStdout() + + app.k.Build() + + app.waitForChangeAndIdleStdout() + + app.k.Connect() + + app.waitForChangeAndIdleStdout() + + app.k.Transfer() + + app.waitForChangeAndIdleStdout() + + app.click("1646062660770.png") + + app.WaitIdleUI() + + app.click("1646066996789.png") + + app.WaitIdleUI() + + app.click("example") + + app.WaitIdleUI() + + app.type(Key.DOWN * 10, Key.CTRL) + + app.WaitIdleUI() + + app.k.Run() + + # wait up to 10 seconds for 10 Grumpfs + app.waitPatternInStdout("Grumpf", 10, 10) + + app.rightClick("1646066996790.png") + + app.click("Force value") + + #app.type("a", Key.CTRL) + + app.type(Key.BACKSPACE) + + app.type("'sys.stdout.write(\"DEBUG TEST OK\\n\")'") + + app.type(Key.ENTER) + + # wait 10 seconds for 10 patterns + return app.waitPatternInStdout("DEBUG TEST OK", 10) + +run_test(test, exemple="python") diff -r 59158e360b8c -r f5850ce25caf tests/ide_tests/edit_project.sikuli/1646062660770.png Binary file tests/ide_tests/edit_project.sikuli/1646062660770.png has changed diff -r 59158e360b8c -r f5850ce25caf tests/ide_tests/edit_project.sikuli/edit_project.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/ide_tests/edit_project.sikuli/edit_project.py Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,61 @@ +""" This test opens, modifies, builds and runs exemple project named "python". +Test succeeds if runtime's stdout behaves as expected +""" + +import os +import time + +# allow module import from current test directory's parent +addImportPath(os.path.dirname(getBundlePath())) + +# common test definitions module +from sikuliberemiz import run_test + +def test(app): + + app.doubleClick("1646062660770.png") + + app.WaitIdleUI() + + app.click("example") + + app.WaitIdleUI() + + app.type(Key.DOWN * 10, Key.CTRL) + + app.WaitIdleUI() + + app.doubleClick("Hello world") + + app.WaitIdleUI() + + app.type(Key.TAB*3) # select text content + + app.type("'sys.stdout.write(\"EDIT TEST OK\\n\")'") + + app.type(Key.ENTER) + + app.WaitIdleUI() + + app.k.Clean() + + app.waitForChangeAndIdleStdout() + + app.k.Build() + + app.waitForChangeAndIdleStdout() + + app.k.Connect() + + app.waitForChangeAndIdleStdout() + + app.k.Transfer() + + app.waitForChangeAndIdleStdout() + + app.k.Run() + + # wait 10 seconds for 10 patterns + return app.waitPatternInStdout("EDIT TEST OK", 10) + +run_test(test, exemple="python") diff -r 59158e360b8c -r f5850ce25caf tests/ide_tests/load_and_build_tests.pytest/test_application.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/ide_tests/load_and_build_tests.pytest/test_application.py Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,232 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# This file is part of Beremiz, a Integrated Development Environment for +# programming IEC 61131-3 automates supporting plcopen standard and CanFestival. +# +# Copyright (C) 2017: Andrey Skvortsov +# +# See COPYING file for copyrights details. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +from __future__ import absolute_import +from __future__ import print_function +import os +import sys +import unittest +import time + +import six +import pytest +import wx +import ddt + +import conftest +import Beremiz +import PLCOpenEditor + + +class UserApplicationTest(unittest.TestCase): + def InstallExceptionHandler(self): + def handle_exception(e_type, e_value, e_traceback, exit=False): + # traceback.print_exception(e_type, e_value, e_traceback) + self.exc_info = [e_type, e_value, e_traceback] + self.exc_info = None + self.old_excepthook = sys.excepthook + sys.excepthook = handle_exception + + def StartApp(self): + self.app = None + + def FinishApp(self): + wx.CallAfter(self.app.frame.Close) + self.app.MainLoop() + self.app = None + + def setUp(self): + self.app = None + + def tearDown(self): + if self.app is not None and self.app.frame is not None: + self.FinishApp() + + def RunUIActions(self, actions): + for act in actions: + wx.CallAfter(*act) + self.ProcessEvents() + + def CheckForErrors(self): + if self.exc_info is not None: + # reraise catched previously exception + exc_type = self.exc_info[0] + exc_value = self.exc_info[1] + exc_traceback = self.exc_info[2] + six.reraise(exc_type, exc_value, exc_traceback) + + def ProcessEvents(self): + for dummy in range(0, 30): + self.CheckForErrors() + wx.Yield() + time.sleep(0.01) + + +@ddt.ddt +class BeremizApplicationTest(UserApplicationTest): + """Test Beremiz as whole application""" + + def StartApp(self): + self.app = Beremiz.BeremizIDELauncher() + # disable default exception handler in Beremiz + self.app.InstallExceptionHandler = lambda: None + self.InstallExceptionHandler() + self.app.handle_exception = sys.excepthook + self.app.PreStart() + self.ProcessEvents() + self.app.frame.Show() + self.ProcessEvents() + self.app.frame.ShowFullScreen(True) + self.ProcessEvents() + + def FinishApp(self): + wx.CallAfter(self.app.frame.Close) + self.app.MainLoop() + time.sleep(1) + self.app = None + + def GetSkippedProjectTreeItems(self): + """ + Returns the list of skipped items in the project tree. + + Beremiz test don't need to skip any elemnts in the project tree. + """ + return [] + + def OpenAllProjectElements(self): + """Open editor for every object in the project tree""" + self.app.frame.ProjectTree.ExpandAll() + self.ProcessEvents() + item = self.app.frame.ProjectTree.GetRootItem() + skip = self.GetSkippedProjectTreeItems() + tree_id = self.app.frame.ProjectTree.GetId() + while item is not None: + self.app.frame.ProjectTree.SelectItem(item, True) + self.ProcessEvents() + if item not in skip: + event = wx.lib.agw.customtreectrl.TreeEvent( + wx.lib.agw.customtreectrl.wxEVT_TREE_ITEM_ACTIVATED, + tree_id, item) + self.app.frame.OnProjectTreeItemActivated(event) + self.ProcessEvents() + item = self.app.frame.ProjectTree.GetNextVisible(item) + + def CheckTestProject(self, project): + sys.argv = ["", project] + self.StartApp() + self.OpenAllProjectElements() + user_actions = self.GetUserActions() + self.RunUIActions(user_actions) + self.FinishApp() + + def GetProjectPath(self, project): + return os.path.abspath(os.path.join(os.path.dirname(__file__), "..","..","projects", project)) + + def GetUserActions(self): + """ + Returns list of user actions that will be executed + on every test project by testCheckProject test. + """ + user_actions = [ + [self.app.frame.SwitchFullScrMode, None], + [self.app.frame.SwitchFullScrMode, None], + [self.app.frame.CTR._Clean], + [self.app.frame.CTR._Build], + [self.app.frame.CTR._Connect], + [self.app.frame.CTR._Transfer], + [self.app.frame.CTR._Run], + [self.app.frame.CTR._Stop], + [self.app.frame.CTR._Disconnect], + [self.app.frame.CTR._Clean], + ] + return user_actions + + def testStartUp(self): + """Checks whether the app starts and finishes correctly""" + sys.argv = [""] + self.StartApp() + self.FinishApp() + + # TODO: also use "exemples/*" projects + @ddt.data( + #"first_steps", + "logging", + #"traffic_lights", + #"wxGlade", + #"python", + #"wiimote", + # "wxHMI", + ) + @pytest.mark.timeout(300) + def testCheckProject(self, name): + """ + Checks that test PLC project can be open, + compiled and run on SoftPLC. + """ + project = self.GetProjectPath(name) + print("Testing example " + name) + self.CheckTestProject(project) + + +# class PLCOpenEditorApplicationTest(BeremizApplicationTest): +# """Test PLCOpenEditor as whole application""" +# +# def StartApp(self): +# self.app = PLCOpenEditor.PLCOpenEditorApp() +# # disable default exception handler in application +# self.app.InstallExceptionHandler = lambda: None +# self.InstallExceptionHandler() +# self.app.Show() +# self.ProcessEvents() +# self.app.frame.ShowFullScreen(True) +# self.ProcessEvents() +# +# def FinishApp(self): +# wx.CallAfter(self.app.frame.Close) +# self.app.MainLoop() +# time.sleep(1) +# self.app = None +# +# def GetSkippedProjectTreeItems(self): +# """ +# Returns the list of skipped items in the project tree. +# +# Root item opens dialog window for project settings. +# To avoid code that handles closing dialog windows just skip this item. +# """ +# return [self.app.frame.ProjectTree.GetRootItem()] +# +# def GetUserActions(self): +# return [] +# +# def GetProjectPath(self, project): +# """Open PLC program in every Beremiz test project""" +# project_dir = BeremizApplicationTest.GetProjectPath(self, project) +# return os.path.join(project_dir, "plc.xml") +# + +if __name__ == '__main__': + conftest.init_environment() + unittest.main() diff -r 59158e360b8c -r f5850ce25caf tests/ide_tests/new_project.sikuli/new_project.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/ide_tests/new_project.sikuli/new_project.py Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,132 @@ +""" This test opens, builds and runs a new project. +Test succeeds if runtime's stdout behaves as expected +""" + +import os +import time + +# allow module import from current test directory's parent +addImportPath(os.path.dirname(getBundlePath())) + +# common test definitions module +from sikuliberemiz import * + +def test(app): + + new_project_path = os.path.join(os.path.abspath(os.path.curdir), "new_test_project") + + # New project path must exist (usually created in directory selection dialog) + os.mkdir(new_project_path) + + app.WaitIdleUI() + + # Create new project (opens new project directory selection dialog) + app.k.New() + + app.WaitIdleUI() + + # Move to "Home" section of file selecor, otherwise address is + # "file ignored" at first run + app.type("f", Key.CTRL) + app.type(Key.ESC) + app.type(Key.TAB) + + # Enter directory by name + app.k.Address() + + # Fill address bar + app.type(new_project_path + Key.ENTER) + + app.WaitIdleUI() + + # When prompted for creating first program select type ST + app.type(Key.TAB*4) # go to lang dropdown + app.type(Key.DOWN*2) # change selected language + app.type(Key.ENTER) # validate + + app.WaitIdleUI() + + # Name created program + app.type("Test program") + + app.WaitIdleUI() + + # Focus on Variable grid + app.type(Key.TAB*4) + + # Add 2 variables + app.type(Key.ADD*2) + + # Focus on ST text + app.WaitIdleUI() + + app.type(Key.TAB*8) + + app.type("""\ + LocalVar0 := LocalVar1; + {printf("Test OK\\n");fflush(stdout);} + """) + + app.k.Save() + + # Close ST POU + app.type("w", Key.CTRL) + + app.WaitIdleUI() + + # Focus project tree and select root item + app.type(Key.TAB) + + app.type(Key.LEFT) + + app.type(Key.UP) + + # Edit root item + app.type(Key.ENTER) + + app.WaitIdleUI() + + # Switch to config tab + app.type(Key.RIGHT*2) + + # Focus on URI + app.type(Key.TAB) + + # Set URI + app.type("LOCAL://") + + # FIXME: Select other field to ensure URI is validated + app.type(Key.TAB) + + app.k.Save() + + # Close project config editor + app.type("w", Key.CTRL) + + app.WaitIdleUI() + + # Focus seems undefined at that time (FIXME) + # Force focussing on "something" so that next shortcut is taken + app.type(Key.TAB) + + app.waitIdleStdout() + + app.k.Build() + + app.waitIdleStdout(5,30) + + app.k.Connect() + + app.waitIdleStdout() + + app.k.Transfer() + + app.waitIdleStdout() + + app.k.Run() + + # wait 10 seconds + return app.waitPatternInStdout("Test OK", 10) + + +run_test(test) diff -r 59158e360b8c -r f5850ce25caf tests/ide_tests/run_python_exemple.sikuli/run_python_exemple.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/ide_tests/run_python_exemple.sikuli/run_python_exemple.py Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,39 @@ +""" This test opens, builds and runs exemple project named "python". +Test succeeds if runtime's stdout behaves as expected +""" + +import os +import time + +# allow module import from current test directory's parent +addImportPath(os.path.dirname(getBundlePath())) + +# common test definitions module +from sikuliberemiz import * + +def test(app): + # Start the app + + app.k.Clean() + + app.waitForChangeAndIdleStdout() + + app.k.Build() + + app.waitForChangeAndIdleStdout() + + app.k.Connect() + + app.waitForChangeAndIdleStdout() + + app.k.Transfer() + + app.waitForChangeAndIdleStdout() + + app.k.Run() + + # wait 10 seconds for 10 Grumpfs + return app.waitPatternInStdout("Grumpf", 10, 10) + +run_test(test, exemple="python") + diff -r 59158e360b8c -r f5850ce25caf tests/ide_tests/sikuliberemiz.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/ide_tests/sikuliberemiz.py Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,335 @@ +"Commons definitions for sikuli based beremiz IDE GUI tests" + +import os +import sys +import subprocess +import traceback +from threading import Thread, Event, Lock +from time import time as timesec + +import sikuli + +beremiz_path = os.environ["BEREMIZPATH"] +python_bin = os.environ.get("BEREMIZPYTHONPATH", "/usr/bin/python") + +opj = os.path.join + + +class KBDShortcut: + """Send shortut to app by calling corresponding methods. + + example: + k = KBDShortcut() + k.Clean() + """ + + fkeys = {"Stop": sikuli.Key.F4, + "Run": sikuli.Key.F5, + "Transfer": sikuli.Key.F6, + "Connect": sikuli.Key.F7, + "Clean": sikuli.Key.F9, + "Build": sikuli.Key.F11, + "Save": ("s",sikuli.Key.CTRL), + "New": ("n",sikuli.Key.CTRL), + "Address": ("l",sikuli.Key.CTRL)} # to reach address bar in GTK's file selector + + def __init__(self, app): + self.app = app + + def __getattr__(self, name): + fkey = self.fkeys[name] + if type(fkey) != tuple: + fkey = (fkey,) + + def PressShortCut(): + self.app.sikuliapp.focus() + sikuli.type(*fkey) + self.app.ReportText("Sending " + name + " shortcut") + + return PressShortCut + + +class IDEIdleObserver: + "Detects when IDE is idle. This is particularly handy when staring an operation and witing for the en of it." + + def __init__(self): + """ + Parameters: + app (class BeremizApp) + """ + self.r = sikuli.Region(self.sikuliapp.window()) + + self.idechanged = False + + # 200 was selected because default 50 was still catching cursor blinking in console + # FIXME : remove blinking cursor in console + self.r.onChange(200,self._OnIDEWindowChange) + self.r.observeInBackground() + + def __del__(self): + self.r.stopObserver() + + def _OnIDEWindowChange(self, event): + self.idechanged = True + + def WaitIdleUI(self, period=1, timeout=15): + """ + Wait for IDE to stop changing + Parameters: + period (int): how many seconds with no change to consider idle + timeout (int): how long to wait for idle, in seconds + """ + c = max(timeout/period,1) + while c > 0: + self.idechanged = False + sikuli.wait(period) + if not self.idechanged: + break + c = c - 1 + + self.ReportScreenShot("UI is idle" if c != 0 else "UI is not idle") + + if c == 0: + raise Exception("Window did not idle before timeout") + + +class stdoutIdleObserver: + "Detects when IDE's stdout is idle. Can be more reliable than pixel based version (false changes ?)" + + def __init__(self): + """ + Parameters: + app (class BeremizApp) + """ + self.stdoutchanged = False + + self.event = Event() + + self.pattern = None + self.success_event = Event() + + self.thread = Thread(target = self._waitStdoutProc).start() + + def __del__(self): + pass # self.thread.join() ? + + def _waitStdoutProc(self): + while True: + a = self.proc.stdout.readline() + if len(a) == 0 or a is None: + break + sys.stdout.write(a) + self.ReportOutput(a) + self.event.set() + if self.pattern is not None and a.find(self.pattern) >= 0: + sys.stdout.write("found pattern in '" + a +"'") + self.success_event.set() + + def waitForChangeAndIdleStdout(self, period=2, timeout=15): + """ + Wait for IDE'stdout to start changing + Parameters: + timeout (int): how long to wait for change, in seconds + """ + start_time = timesec() + + wait_result = self.event.wait(timeout) + + self.ReportScreenShot("stdout changed" if wait_result else "stdout didn't change") + + if wait_result: + self.event.clear() + else: + raise Exception("Stdout didn't become active before timeout") + + self.waitIdleStdout(period, timeout - (timesec() - start_time)) + + def waitIdleStdout(self, period=2, timeout=15): + """ + Wait for IDE'stdout to stop changing + Parameters: + period (int): how many seconds with no change to consider idle + timeout (int): how long to wait for idle, in seconds + """ + end_time = timesec() + timeout + self.event.clear() + while timesec() < end_time: + if self.event.wait(period): + # no timeout -> got event -> not idle -> loop again + self.event.clear() + else: + # timeout -> no event -> idle -> exit + self.ReportScreenShot("stdout is idle") + return True + + self.ReportScreenShot("stdout did not idle") + + raise Exception("Stdout did not idle before timeout") + + def waitPatternInStdout(self, pattern, timeout, count=1): + found = 0 + self.pattern = pattern + end_time = timesec() + timeout + self.event.clear() + while True: + remain = end_time - timesec() + if remain <= 0 : + res = False + break + + res = self.success_event.wait(remain) + if res: + self.success_event.clear() + found = found + 1 + if found >= count: + break + self.pattern = None + self.ReportScreenShot("found pattern" if res else "pattern not found") + return res + +class BeremizApp(IDEIdleObserver, stdoutIdleObserver): + def __init__(self, projectpath=None, exemple=None): + """ + Starts Beremiz IDE, waits for main window to appear, maximize it. + + Parameters: + projectpath (str): path to project to open + exemple (str): path relative to exemples directory + + Returns: + Sikuli App class instance + """ + + self.screenshotnum = 0 + self.starttime = timesec() + self.screen = sikuli.Screen() + + self.report = open("report.html", "w") + self.report.write(""" + + + + + Test report + + +""") + + command = [python_bin, opj(beremiz_path,"Beremiz.py"), "--log=/dev/stdout"] + + if exemple is not None: + command.append(opj(beremiz_path,"exemples",exemple)) + elif projectpath is not None: + command.append(projectpath) + + # App class is broken in Sikuli 2.0.5: can't start process with arguments. + # + # Workaround : - use subprocess module to spawn IDE process, + # - use wmctrl to find IDE window details and maximize it + # - pass exact window title to App class constructor + + self.ReportText("Launching " + repr(command)) + + self.proc = subprocess.Popen(command, stdout=subprocess.PIPE, bufsize=0) + + # Window are macthed against process' PID + ppid = self.proc.pid + + # Timeout 5s + c = 50 + while c > 0: + # equiv to "wmctrl -l -p | grep $pid" + try: + wlist = filter(lambda l:(len(l)>2 and l[2]==str(ppid)), map(lambda s:s.split(None,4), subprocess.check_output(["wmctrl", "-l", "-p"]).splitlines())) + except subprocess.CalledProcessError: + wlist = [] + + # window with no title only has 4 fields do describe it + # beremiz splashcreen has no title + # wait until main window is visible + if len(wlist) == 1 and len(wlist[0]) == 5: + windowID,_zero,wpid,_XID,wtitle = wlist[0] + break + + sikuli.wait(0.1) + c = c - 1 + + if c == 0: + raise Exception("Couldn't find Beremiz window") + + # Maximize window x and y + subprocess.check_call(["wmctrl", "-i", "-r", windowID, "-b", "add,maximized_vert,maximized_horz"]) + + # switchApp creates an App object by finding window by title, is not supposed to spawn a process + self.sikuliapp = sikuli.switchApp(wtitle) + self.k = KBDShortcut(self) + + IDEIdleObserver.__init__(self) + stdoutIdleObserver.__init__(self) + + # stubs for common sikuli calls to allow adding hooks later + for name in ["click","doubleClick","type","rightClick","wait"]: + def makeMyMeth(n): + def myMeth(*args, **kwargs): + self.ReportScreenShot("Begin: " + n + "(" + repr(args) + "," + repr(kwargs) + ")") + try: + getattr(sikuli, n)(*args, **kwargs) + finally: + self.ReportScreenShot("end: " + n + "(" + repr(args) + "," + repr(kwargs) + ")") + return myMeth + setattr(self, name, makeMyMeth(name)) + + def close(self): + self.sikuliapp.close() + self.sikuliapp = None + self.report.write(""" + +""") + self.report.close() + + def __del__(self): + if self.sikuliapp is not None: + self.sikuliapp.close() + IDEIdleObserver.__del__(self) + stdoutIdleObserver.__del__(self) + + def ReportScreenShot(self, msg): + elapsed = "%.3fs: "%(timesec() - self.starttime) + fname = "capture"+str(self.screenshotnum)+".png" + cap = self.screen.capture(self.r) + cap.save(".", fname) + self.screenshotnum = self.screenshotnum + 1 + self.report.write( "

" + elapsed + msg + "
" + "

") + + def ReportText(self, text): + elapsed = "%.3fs: "%(timesec() - self.starttime) + self.report.write("

" + elapsed + text + "

") + + def ReportOutput(self, text): + elapsed = "%.3fs: "%(timesec() - self.starttime) + self.report.write("
" + elapsed + text + "
") + + +def run_test(func, *args, **kwargs): + app = BeremizApp(*args, **kwargs) + try: + success = func(app) + except: + # sadly, sys.excepthook is broken in sikuli/jython + # purpose of this run_test function is to work around it. + # and catch exception cleanly anyhow + e_type, e_value, e_traceback = sys.exc_info() + err_msg = "\n".join(traceback.format_exception(e_type, e_value, e_traceback)) + sys.stdout.write(err_msg) + app.ReportOutput(err_msg) + success = False + + app.close() + + if success: + sikuli.exit(0) + else: + sikuli.exit(1) + + + diff -r 59158e360b8c -r f5850ce25caf tests/ide_tests/wx_widgets.pytest/test_CustomIntCtrl.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/ide_tests/wx_widgets.pytest/test_CustomIntCtrl.py Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# This file is part of Beremiz, a Integrated Development Environment for +# programming IEC 61131-3 automates supporting plcopen standard and CanFestival. +# +# Copyright (C) 2017: Andrey Skvortsov +# +# See COPYING file for copyrights details. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +from __future__ import absolute_import +from __future__ import division +import unittest +import time + +import wx +import conftest +import controls.CustomIntCtrl + + +class TestCustomIntCtrl(unittest.TestCase): + def setUp(self): + self.app = wx.App() + self.frame = wx.Frame(None) + + def tearDown(self): + self.frame.Destroy() + wx.CallAfter(wx.Exit) + self.app.MainLoop() + + def testMaxLimit(self): + """Test working upper bound""" + self.AddControls() + self.int_ctrl.SetValue(self.max_val + 100) + self.ProcessEvents() + + self.txt_ctrl.SetFocus() + self.ProcessEvents() + self.assertEqual(self.int_ctrl.GetValue(), self.max_val) + + def testMinLimit(self): + """Test working lower bound""" + self.AddControls() + self.int_ctrl.SetValue(self.min_val - 100) + self.ProcessEvents() + + self.txt_ctrl.SetFocus() + self.ProcessEvents() + + self.assertEqual(self.int_ctrl.GetValue(), self.min_val) + + def testCorrectValue(self): + """Test case if no limiting is necessary""" + self.AddControls() + val = (self.max_val + self.min_val) // 2 + self.int_ctrl.SetValue(val) + self.ProcessEvents() + + self.txt_ctrl.SetFocus() + self.ProcessEvents() + + self.assertEqual(self.int_ctrl.GetValue(), val) + + def testEventBinding(self): + """Test event sending after edit and bound checks are done""" + self.AddControls() + self.event_happend = False + + def EventHandler(event): + self.event_happend = True + event.Skip() + + self.int_ctrl.Bind(controls.CustomIntCtrl.EVT_CUSTOM_INT, EventHandler) + + val = (self.max_val + self.min_val) // 2 + + self.int_ctrl.SetValue(val) + self.ProcessEvents() + self.txt_ctrl.SetFocus() + + self.ProcessEvents() + self.txt_ctrl.SetFocus() + self.ProcessEvents() + + self.assertEqual(self.int_ctrl.GetValue(), val) + self.assertTrue(self.event_happend) + + def testLongNumbers(self): + """Test support of long integer""" + self.AddControls() + val = 40000000000 + self.int_ctrl.SetMax(val) + self.int_ctrl.SetValue(val) + self.ProcessEvents() + + self.txt_ctrl.SetFocus() + self.ProcessEvents() + + self.assertEqual(val, val) + + def ProcessEvents(self): + for dummy in range(0, 10): + wx.Yield() + time.sleep(0.01) + + def AddControls(self): + vs = wx.BoxSizer(wx.VERTICAL) + self.int_ctrl = controls.CustomIntCtrl(self.frame) + self.txt_ctrl = wx.TextCtrl(self.frame) + vs.Add(self.int_ctrl, 0, wx.ALIGN_CENTRE | wx.ALL, 5) + vs.Add(self.txt_ctrl, 0, wx.ALIGN_CENTRE | wx.ALL, 5) + self.frame.SetSizer(vs) + vs.Fit(self.frame) + self.frame.Show() + self.frame.Raise() + + self.min_val = 50 + self.max_val = 100 + self.int_ctrl.SetBounds(self.min_val, self.max_val) + self.ProcessEvents() + + +if __name__ == '__main__': + conftest.init_environment() + unittest.main() diff -r 59158e360b8c -r f5850ce25caf tests/tools/Docker/beremiz-sikuli/Dockerfile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/tools/Docker/beremiz-sikuli/Dockerfile Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,73 @@ +# +# Dockerfile for Beremiz +# This container is used to run tests for Beremiz +# +FROM ubuntu:focal + +ENV TERM xterm-256color + +ENV LANG en_US.UTF-8 +ENV LANGUAGE en_US:en +ENV LC_ALL en_US.UTF-8 + +ARG UNAME=testing +ENV UNAME ${UNAME} +ARG UID=1000 +ARG GID=1000 +RUN groupadd -g $GID $UNAME +RUN useradd -m -u $UID -g $GID -s /bin/bash $UNAME + +RUN set -xe \ + && apt-get update \ + && TZ="America/Paris" \ + DEBIAN_FRONTEND="noninteractive" \ + apt-get install -y --no-install-recommends \ + `# run sikuli` \ + wget \ + libopencv4.2-java \ + openjdk-11-jre \ + \ + `# run X based tests` \ + fluxbox \ + wmctrl xdotool xvfb \ + x11vnc xterm xnest \ + \ + `# to build tested apps` \ + build-essential automake flex bison mercurial \ + libgtk-3-dev libgl1-mesa-dev libglu1-mesa-dev \ + libpython2.7-dev libssl-dev \ + python2 virtualenv cmake + +# link obtained from https://raiman.github.io/SikuliX1/downloads.html +RUN set -xe && \ + wget -qP /usr/local/bin \ + https://launchpad.net/sikuli/sikulix/2.0.5/+download/sikulixide-2.0.5.jar && \ + echo 0795f1e0866ee5a7a84e4c89793ea78c /usr/local/bin/sikulixide-2.0.5.jar | md5sum -c && \ + ( echo '#!/bin/sh' && \ + echo "exec java -jar /usr/local/bin/sikulixide-*.jar \"\$@\"" \ + ) | install /dev/stdin /usr/local/bin/sikulix + + +RUN env echo -e '#!/bin/bash\nmake -f /home/testing/src/beremiz/tests/Makefile $*' > /usr/local/bin/do_tests +RUN chmod +x /usr/local/bin/do_tests + +USER $UNAME + +RUN mkdir /home/$UNAME/build /home/$UNAME/src /home/$UNAME/test + +RUN virtualenv --python=$(which python2) ~/beremizenv + +RUN ~/beremizenv/bin/pip install \ + pytest pytest-timeout ddt \ + lxml future matplotlib zeroconf2 enum34 pyro sslpsk posix_spawn \ + twisted nevow autobahn click opcua \ + wxPython==4.1.1 + +# Point to python binary test scripts will use +ENV BEREMIZPYTHONPATH /home/$UNAME/beremizenv/bin/python + +# easy to remember 'do_tests' alias to invoke main makefile +ARG OWNDIRBASENAME=beremiz +ENV OWNDIRBASENAME ${OWNDIRBASENAME} + + diff -r 59158e360b8c -r f5850ce25caf tests/tools/Docker/beremiz-sikuli/build_docker_image.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/tools/Docker/beremiz-sikuli/build_docker_image.sh Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,10 @@ +#!/bin/bash + +set -e + +echo "Building docker image" +docker build \ + --build-arg UID=$(id -u) \ + --build-arg GID=$(id -g) \ + -t beremiz_sikuli . + diff -r 59158e360b8c -r f5850ce25caf tests/tools/Docker/beremiz-sikuli/clean_docker_container.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/tools/Docker/beremiz-sikuli/clean_docker_container.sh Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,5 @@ +#!/bin/bash + +# delete container +docker rm beremiz_sikuli_current + diff -r 59158e360b8c -r f5850ce25caf tests/tools/Docker/beremiz-sikuli/clean_docker_image.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/tools/Docker/beremiz-sikuli/clean_docker_image.sh Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,5 @@ +#!/bin/bash + +# delete image +docker rmi beremiz_sikuli + diff -r 59158e360b8c -r f5850ce25caf tests/tools/Docker/beremiz-sikuli/create_docker_container.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/tools/Docker/beremiz-sikuli/create_docker_container.sh Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,30 @@ +#!/bin/bash + +set -e + +# source directory containing beremiz, matiec, etc.. +SRCDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd ../../../../.. && pwd )" +echo "SOURCE direcory : $SRCDIR" + +# absolute path to test directory. ~/test if not given as only argument +TESTDIR=${1:-~/test} +mkdir -p $TESTDIR +echo "TEST direcory : $TESTDIR" + +UNAME=testing +UHOME=/home/$UNAME + +# define TESTDEBUG in env to enable dev-mode. This enables : +# - debug pasthrough for Xnest +# - VNC port passthrough +DEBUGARGS="-v /tmp/.X11-unix/X0:/tmp/.X11-unix/X0 -e DISPLAY=$DISPLAY -p 5900:5900" + +echo "Creating docker container" +docker create \ + --name beremiz_sikuli_current \ + -v $SRCDIR:$UHOME/src \ + -v $TESTDIR:$UHOME/test \ + `if [ "$TESTDEBUG" == "YES" ]; then echo $DEBUGARGS; fi` \ + -w $UHOME/test \ + -i -t beremiz_sikuli /bin/bash + diff -r 59158e360b8c -r f5850ce25caf tests/tools/Docker/beremiz-sikuli/do_test_in_docker.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/tools/Docker/beremiz-sikuli/do_test_in_docker.sh Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,11 @@ +#!/bin/bash + +set -e + +CONTAINER=beremiz_sikuli_current + +docker stop $CONTAINER +docker start $CONTAINER +docker exec $CONTAINER bash -c "do_tests $1" +docker stop $CONTAINER + diff -r 59158e360b8c -r f5850ce25caf tests/tools/Docker/beremiz-sikuli/enter_docker.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/tools/Docker/beremiz-sikuli/enter_docker.sh Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,5 @@ +#!/bin/bash + +CONTAINER=beremiz_sikuli_current + +docker start -i $CONTAINER diff -r 59158e360b8c -r f5850ce25caf tests/tools/Docker/beremiz-sikuli/enter_docker_as_root.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/tools/Docker/beremiz-sikuli/enter_docker_as_root.sh Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,7 @@ +#!/bin/bash + +CONTAINER=beremiz_sikuli_current + +docker start $CONTAINER +docker exec -i -t -u root $CONTAINER bash +docker stop $CONTAINER diff -r 59158e360b8c -r f5850ce25caf tests/tools/Docker/beremiz-sikuli/rebuild_docker.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/tools/Docker/beremiz-sikuli/rebuild_docker.sh Sun Jul 17 22:53:35 2022 +0200 @@ -0,0 +1,9 @@ +#!/bin/bash + +set -e + +./clean_docker_container.sh || true +./clean_docker_image.sh || true +./build_docker_image.sh +./create_docker_container.sh $1 + diff -r 59158e360b8c -r f5850ce25caf tests/tools/conftest.py --- a/tests/tools/conftest.py Thu Jul 14 11:40:27 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# This file is part of Beremiz, a Integrated Development Environment for -# programming IEC 61131-3 automates supporting plcopen standard and CanFestival. -# -# Copyright (C) 2017: Andrey Skvortsov -# -# See COPYING file for copyrights details. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - -from __future__ import absolute_import -import os -import sys - -# import pytest -# import xvfbwrapper - - -def init_environment(): - """Append module root directory to sys.path""" - try: - import Beremiz as _Beremiz - except ImportError: - sys.path.append( - os.path.abspath( - os.path.join( - os.path.dirname(__file__), '..', '..') - ) - ) - - -init_environment() - -# -# Something seems to be broken in Beremiz application, -# because after tests in test_application.py during Xvfb shutdown -# pytest returns error message: -# pytest: Fatal IO error 11 (Die Ressource ist zur Zeit nicht verfügbar) on X server :2821. -# -# As a result of that pytest returns code 1 as some tests were failed, -# but they aren't. -# -# To avoid this Xvfb is launched and killed not by pytest. -# $ Xvfb :42 -screen 0 1280x1024x24 & -# $ export DISPLAY=:42 -# $ pytest --timeout=10 ./tests/tools -# $ pkill -9 Xvfb -# -# TODO: find root of this problem. - - -# vdisplay = None -# -# @pytest.fixture(scope="session", autouse=True) -# def start_xvfb_server(request): -# global vdisplay -# vdisplay = xvfbwrapper.Xvfb(width=1280, height=720) -# vdisplay.start() -# request.addfinalizer(stop_xvfb_server) -# -# def stop_xvfb_server(): -# if vdisplay is not None: -# vdisplay.stop() diff -r 59158e360b8c -r f5850ce25caf tests/tools/run_python_tests.sh --- a/tests/tools/run_python_tests.sh Thu Jul 14 11:40:27 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -#!/bin/sh - - - -cleanup() -{ - find $PYTEST_DIR -name '*.pyc' -delete -} - - - -print_help() -{ - echo "Usage: run_python_tests.sh [--on-local-xserver]" - echo "" - echo "--on-local-xserver" - echo " all tests are run on local X-server. " - echo " User can see test in action." - echo " Any interaction (mouse, keyboard) should be avoided" - echo " By default without arguments script runs pytest on virtual X serverf." - echo "" - - exit 1 -} - -main() -{ - LC_ALL=ru_RU.utf-8 - PYTEST_DIR=./tests/tools - - if [ ! -d $PYTEST_DIR ]; then - echo "Script should be run from top directory in repository" - exit 1; - fi - - use_xvfb=0 - if [ "$1" != "--on-local-xserver" ]; then - export DISPLAY=:42 - use_xvfb=1 - Xvfb $DISPLAY -screen 0 1280x1024x24 & - sleep 1 - fi - - - cleanup - - ret=0 - DELAY=400 - KILL_DELAY=$(($DELAY + 30)) - timeout -k $KILL_DELAY $DELAY pytest --timeout=10 ./tests/tools - ret=$? - - cleanup - - [ $use_xvfb = 1 ] && pkill -9 Xvfb - exit $ret -} - - -[ "$1" = "--help" -o "$1" = "-h" ] && print_help -main $@ diff -r 59158e360b8c -r f5850ce25caf tests/tools/test_CustomIntCtrl.py --- a/tests/tools/test_CustomIntCtrl.py Thu Jul 14 11:40:27 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# This file is part of Beremiz, a Integrated Development Environment for -# programming IEC 61131-3 automates supporting plcopen standard and CanFestival. -# -# Copyright (C) 2017: Andrey Skvortsov -# -# See COPYING file for copyrights details. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - -from __future__ import absolute_import -from __future__ import division -import unittest -import time - -import wx -import conftest -import controls.CustomIntCtrl - - -class TestCustomIntCtrl(unittest.TestCase): - def setUp(self): - self.app = wx.App() - self.frame = wx.Frame(None) - - def tearDown(self): - self.frame.Destroy() - wx.CallAfter(self.app.Exit) - self.app.MainLoop() - - def testMaxLimit(self): - """Test working upper bound""" - self.AddControls() - self.int_ctrl.SetValue(self.max_val + 100) - self.ProcessEvents() - - self.txt_ctrl.SetFocus() - self.ProcessEvents() - self.assertEqual(self.int_ctrl.GetValue(), self.max_val) - - def testMinLimit(self): - """Test working lower bound""" - self.AddControls() - self.int_ctrl.SetValue(self.min_val - 100) - self.ProcessEvents() - - self.txt_ctrl.SetFocus() - self.ProcessEvents() - - self.assertEqual(self.int_ctrl.GetValue(), self.min_val) - - def testCorrectValue(self): - """Test case if no limiting is necessary""" - self.AddControls() - val = (self.max_val + self.min_val) // 2 - self.int_ctrl.SetValue(val) - self.ProcessEvents() - - self.txt_ctrl.SetFocus() - self.ProcessEvents() - - self.assertEqual(self.int_ctrl.GetValue(), val) - - def testEventBinding(self): - """Test event sending after edit and bound checks are done""" - self.AddControls() - self.event_happend = False - - def EventHandler(event): - self.event_happend = True - event.Skip() - - self.int_ctrl.Bind(controls.CustomIntCtrl.EVT_CUSTOM_INT, EventHandler) - - val = (self.max_val + self.min_val) // 2 - - self.int_ctrl.SetValue(val) - self.ProcessEvents() - self.txt_ctrl.SetFocus() - - self.ProcessEvents() - self.txt_ctrl.SetFocus() - self.ProcessEvents() - - self.assertEqual(self.int_ctrl.GetValue(), val) - self.assertTrue(self.event_happend) - - def testLongNumbers(self): - """Test support of long integer""" - self.AddControls() - val = 40000000000 - self.int_ctrl.SetMax(val) - self.int_ctrl.SetValue(val) - self.ProcessEvents() - - self.txt_ctrl.SetFocus() - self.ProcessEvents() - - self.assertEqual(val, val) - - def ProcessEvents(self): - for dummy in range(0, 10): - wx.Yield() - time.sleep(0.01) - - def AddControls(self): - vs = wx.BoxSizer(wx.VERTICAL) - self.int_ctrl = controls.CustomIntCtrl(self.frame) - self.txt_ctrl = wx.TextCtrl(self.frame) - vs.Add(self.int_ctrl, 0, wx.ALIGN_CENTRE | wx.ALL, 5) - vs.Add(self.txt_ctrl, 0, wx.ALIGN_CENTRE | wx.ALL, 5) - self.frame.SetSizer(vs) - vs.Fit(self.frame) - self.frame.Show() - self.frame.Raise() - - self.min_val = 50 - self.max_val = 100 - self.int_ctrl.SetBounds(self.min_val, self.max_val) - self.ProcessEvents() - - -if __name__ == '__main__': - conftest.init_environment() - unittest.main() diff -r 59158e360b8c -r f5850ce25caf tests/tools/test_application.py --- a/tests/tools/test_application.py Thu Jul 14 11:40:27 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,231 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# This file is part of Beremiz, a Integrated Development Environment for -# programming IEC 61131-3 automates supporting plcopen standard and CanFestival. -# -# Copyright (C) 2017: Andrey Skvortsov -# -# See COPYING file for copyrights details. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - -from __future__ import absolute_import -from __future__ import print_function -import os -import sys -import unittest -import time - -import six -import pytest -import wx -import ddt - -import conftest -import Beremiz -import PLCOpenEditor - - -class UserApplicationTest(unittest.TestCase): - def InstallExceptionHandler(self): - def handle_exception(e_type, e_value, e_traceback, exit=False): - # traceback.print_exception(e_type, e_value, e_traceback) - self.exc_info = [e_type, e_value, e_traceback] - self.exc_info = None - self.old_excepthook = sys.excepthook - sys.excepthook = handle_exception - - def StartApp(self): - self.app = None - - def FinishApp(self): - wx.CallAfter(self.app.frame.Close) - self.app.MainLoop() - self.app = None - - def setUp(self): - self.app = None - - def tearDown(self): - if self.app is not None and self.app.frame is not None: - self.FinishApp() - - def RunUIActions(self, actions): - for act in actions: - wx.CallAfter(*act) - self.ProcessEvents() - - def CheckForErrors(self): - if self.exc_info is not None: - # reraise catched previously exception - exc_type = self.exc_info[0] - exc_value = self.exc_info[1] - exc_traceback = self.exc_info[2] - six.reraise(exc_type, exc_value, exc_traceback) - - def ProcessEvents(self): - for dummy in range(0, 30): - self.CheckForErrors() - wx.Yield() - time.sleep(0.01) - - -@ddt.ddt -class BeremizApplicationTest(UserApplicationTest): - """Test Beremiz as whole application""" - - def StartApp(self): - self.app = Beremiz.BeremizIDELauncher() - # disable default exception handler in Beremiz - self.app.InstallExceptionHandler = lambda: None - self.InstallExceptionHandler() - self.app.handle_exception = sys.excepthook - self.app.PreStart() - self.ProcessEvents() - self.app.frame.Show() - self.ProcessEvents() - self.app.frame.ShowFullScreen(True) - self.ProcessEvents() - - def FinishApp(self): - wx.CallAfter(self.app.frame.Close) - self.app.MainLoop() - time.sleep(1) - self.app = None - - def GetSkippedProjectTreeItems(self): - """ - Returns the list of skipped items in the project tree. - - Beremiz test don't need to skip any elemnts in the project tree. - """ - return [] - - def OpenAllProjectElements(self): - """Open editor for every object in the project tree""" - self.app.frame.ProjectTree.ExpandAll() - self.ProcessEvents() - item = self.app.frame.ProjectTree.GetRootItem() - skip = self.GetSkippedProjectTreeItems() - tree_id = self.app.frame.ProjectTree.GetId() - while item is not None: - self.app.frame.ProjectTree.SelectItem(item, True) - self.ProcessEvents() - if item not in skip: - event = wx.lib.agw.customtreectrl.TreeEvent( - wx.lib.agw.customtreectrl.wxEVT_TREE_ITEM_ACTIVATED, - tree_id, item) - self.app.frame.OnProjectTreeItemActivated(event) - self.ProcessEvents() - item = self.app.frame.ProjectTree.GetNextVisible(item) - - def CheckTestProject(self, project): - sys.argv = ["", project] - self.StartApp() - self.OpenAllProjectElements() - user_actions = self.GetUserActions() - self.RunUIActions(user_actions) - self.FinishApp() - - def GetProjectPath(self, project): - return os.path.abspath(os.path.join(os.path.dirname(__file__), "..", project)) - - def GetUserActions(self): - """ - Returns list of user actions that will be executed - on every test project by testCheckProject test. - """ - user_actions = [ - [self.app.frame.SwitchFullScrMode, None], - [self.app.frame.SwitchFullScrMode, None], - [self.app.frame.CTR._Clean], - [self.app.frame.CTR._Build], - [self.app.frame.CTR._Connect], - [self.app.frame.CTR._Transfer], - [self.app.frame.CTR._Run], - [self.app.frame.CTR._Stop], - [self.app.frame.CTR._Disconnect], - [self.app.frame.CTR._Clean], - ] - return user_actions - - def testStartUp(self): - """Checks whether the app starts and finishes correctly""" - sys.argv = [""] - self.StartApp() - self.FinishApp() - - @ddt.data( - "first_steps", - "logging", - "traffic_lights", - "wxGlade", - "python", - "wiimote", - "wxHMI", - ) - @pytest.mark.timeout(30) - def testCheckProject(self, name): - """ - Checks that test PLC project can be open, - compiled and run on SoftPLC. - """ - project = self.GetProjectPath(name) - print("Testing example " + name) - self.CheckTestProject(project) - - -class PLCOpenEditorApplicationTest(BeremizApplicationTest): - """Test PLCOpenEditor as whole application""" - - def StartApp(self): - self.app = PLCOpenEditor.PLCOpenEditorApp() - # disable default exception handler in application - self.app.InstallExceptionHandler = lambda: None - self.InstallExceptionHandler() - self.app.Show() - self.ProcessEvents() - self.app.frame.ShowFullScreen(True) - self.ProcessEvents() - - def FinishApp(self): - wx.CallAfter(self.app.frame.Close) - self.app.MainLoop() - time.sleep(1) - self.app = None - - def GetSkippedProjectTreeItems(self): - """ - Returns the list of skipped items in the project tree. - - Root item opens dialog window for project settings. - To avoid code that handles closing dialog windows just skip this item. - """ - return [self.app.frame.ProjectTree.GetRootItem()] - - def GetUserActions(self): - return [] - - def GetProjectPath(self, project): - """Open PLC program in every Beremiz test project""" - project_dir = BeremizApplicationTest.GetProjectPath(self, project) - return os.path.join(project_dir, "plc.xml") - - -if __name__ == '__main__': - conftest.init_environment() - unittest.main() diff -r 59158e360b8c -r f5850ce25caf util/BitmapLibrary.py --- a/util/BitmapLibrary.py Thu Jul 14 11:40:27 2022 +0200 +++ b/util/BitmapLibrary.py Sun Jul 17 22:53:35 2022 +0200 @@ -71,7 +71,7 @@ height = max(bmp1.GetHeight(), bmp2.GetHeight()) # Create bitmap with both icons - bmp = wx.EmptyBitmap(width, height) + bmp = wx.Bitmap(width, height) dc = wx.MemoryDC() dc.SelectObject(bmp) dc.Clear() diff -r 59158e360b8c -r f5850ce25caf util/ExceptionHandler.py --- a/util/ExceptionHandler.py Thu Jul 14 11:40:27 2022 +0200 +++ b/util/ExceptionHandler.py Sun Jul 17 22:53:35 2022 +0200 @@ -49,7 +49,7 @@ trcbck_lst.append(trcbck) # Allow clicking.... - cap = wx.Window_GetCapture() + cap = wx.Window.GetCapture() if cap: cap.ReleaseMouse() @@ -81,8 +81,14 @@ def get_last_traceback(tb): - while tb.tb_next: - tb = tb.tb_next + while True: + if not hasattr(tb, "tb_next"): + break + if tb.tb_next: + tb = tb.tb_next + else: + break + return tb @@ -93,7 +99,7 @@ ignored_exceptions = [] # a problem with a line in a module is only reported once per session -def AddExceptHook(app_version='[No version]'): +def AddExceptHook(app_version='[No version]', logf = None): def save_bug_report(e_type, e_value, e_traceback, bug_report_path, date): info = { @@ -111,7 +117,8 @@ if e_traceback: info['traceback'] = ''.join(traceback.format_tb(e_traceback)) + '%s: %s' % (e_type, e_value) last_tb = get_last_traceback(e_traceback) - exception_locals = last_tb.tb_frame.f_locals # the locals at the level of the stack trace where the exception actually occurred + # save locals at the level of the stack trace where the exception actually occurred + exception_locals = last_tb.tb_frame.f_locals if last_tb else {}; info['locals'] = format_namespace(exception_locals) if 'self' in exception_locals: try: @@ -125,13 +132,17 @@ lst = info.keys() lst.sort() for a in lst: - output.write(a + ":\n" + str(info[a]) + "\n\n") + line = a + ":\n" + str(info[a]) + "\n\n" + output.write(line) + if logf is not None: + logf.write(line) output.close() def handle_exception(e_type, e_value, e_traceback, exit=False): traceback.print_exception(e_type, e_value, e_traceback) # this is very helpful when there's an exception in the rest of this func last_tb = get_last_traceback(e_traceback) - ex = (last_tb.tb_frame.f_code.co_filename, last_tb.tb_frame.f_lineno) + ex = (last_tb.tb_frame.f_code.co_filename if last_tb else "unknown", + last_tb.tb_frame.f_lineno if last_tb else None) if ex not in ignored_exceptions: ignored_exceptions.append(ex) date = time.ctime() diff -r 59158e360b8c -r f5850ce25caf util/paths.py --- a/util/paths.py Thu Jul 14 11:40:27 2022 +0200 +++ b/util/paths.py Sun Jul 17 22:53:35 2022 +0200 @@ -55,3 +55,8 @@ """ return os.path.join(AbsParentDir(__file__, 2), name) +def Bpath(*names): + """ + Return path of files in Beremiz project + """ + return os.path.join(AbsParentDir(__file__, 1), *names)