diff --git a/bindings/pyroot/pythonizations/CMakeLists.txt b/bindings/pyroot/pythonizations/CMakeLists.txt index 221c9da549230..1230f18ca47f8 100644 --- a/bindings/pyroot/pythonizations/CMakeLists.txt +++ b/bindings/pyroot/pythonizations/CMakeLists.txt @@ -92,6 +92,7 @@ set(py_sources ROOT/_pythonization/_rvec.py ROOT/_pythonization/_stl_vector.py ROOT/_pythonization/_tarray.py + ROOT/_pythonization/_tbrowser.py ROOT/_pythonization/_tclass.py ROOT/_pythonization/_tclonesarray.py ROOT/_pythonization/_tcollection.py diff --git a/bindings/pyroot/pythonizations/python/ROOT/_pythonization/__init__.py b/bindings/pyroot/pythonizations/python/ROOT/_pythonization/__init__.py index 07fea57b052a4..4332daec4b940 100644 --- a/bindings/pyroot/pythonizations/python/ROOT/_pythonization/__init__.py +++ b/bindings/pyroot/pythonizations/python/ROOT/_pythonization/__init__.py @@ -337,4 +337,66 @@ def _register_pythonizations(): importlib.import_module(__name__ + "." + module_name) +def _wait_press_windows(): + from ROOT import gSystem + import msvcrt + import time + + while not gSystem.ProcessEvents(): + if msvcrt.kbhit(): + k = msvcrt.getch() + if k[0] == 32: + break + else: + time.sleep(0.01) + + +def _wait_press_posix(): + from ROOT import gSystem + import sys + import select + import tty + import termios + import time + + old_settings = termios.tcgetattr(sys.stdin) + + tty.setcbreak(sys.stdin.fileno()) + + try: + + while not gSystem.ProcessEvents(): + c = '' + if select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []): + c = sys.stdin.read(1) + if (c == '\x20'): + break + time.sleep(0.01) + + finally: + termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings) + + +def _run_root_event_loop(): + from ROOT import gROOT + import os + import sys + + # no special handling in batch mode + if gROOT.IsBatch(): + return + + # no special handling in case of notebooks + if 'IPython' in sys.modules and sys.modules['IPython'].version_info[0] >= 5: + return + + print("Press key to continue") + + if os.name == 'nt': + _wait_press_windows() + else: + _wait_press_posix() + + # \endcond + diff --git a/bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tbrowser.py b/bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tbrowser.py new file mode 100644 index 0000000000000..e07664d9bf142 --- /dev/null +++ b/bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tbrowser.py @@ -0,0 +1,72 @@ +# Author: Sergey Linev GSI 11/2025 + +################################################################################ +# Copyright (C) 1995-2025, Rene Brun and Fons Rademakers. # +# All rights reserved. # +# # +# For the licensing terms see $ROOTSYS/LICENSE. # +# For the list of contributors see $ROOTSYS/README/CREDITS. # +################################################################################ + +r''' +\pythondoc TBrowser + +Functionality of constructor and Draw() methods were extended to support interactive +work in the python scripts. If extra block parameter is True, script execution +will be suspended until key pressed by user. Simple example: + +\code{.py} +\endcode +import ROOT + +# block until space is pressed +br = ROOT.TBrowser(block = True) + +# continue work to load new files + +# block here again until space is pressed +br.Draw(block = True) + +# continues after is pressed +\endpythondoc +''' + +from . import pythonization, _run_root_event_loop + + +def _TBrowser_constructor(self, *args, block: bool = False): + + self._original_constructor(*args) + + if block: + _run_root_event_loop() + + +def _TBrowser_Draw(self, option: str = "", block: bool = False): + """ + Draw the browser. + Also blocks script execution and runs the ROOT graphics event loop until the keyword is pressed, + but only if the following conditions are met: + * The `block` optional argument is set to `True`. + * ROOT graphics are enabled, i.e. `ROOT.gROOT.IsBatch() == False`. + * The script is running not in ipython notebooks. + """ + + self._Draw(option) + + # run loop if block flag is set + if block: + _run_root_event_loop() + + +@pythonization('TBrowser') +def pythonize_tbrowser(klass): + # Parameters: + # klass: class to be pythonized + + klass._original_constructor = klass.__init__ + klass.__init__ = _TBrowser_constructor + + klass._Draw = klass.Draw + klass.Draw = _TBrowser_Draw + diff --git a/bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tcanvas.py b/bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tcanvas.py index 095686093ba8c..61d366c4fd70f 100644 --- a/bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tcanvas.py +++ b/bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tcanvas.py @@ -32,67 +32,7 @@ \endpythondoc ''' -from . import pythonization - -def wait_press_windows(): - from ROOT import gSystem - import msvcrt - import time - - while not gSystem.ProcessEvents(): - if msvcrt.kbhit(): - k = msvcrt.getch() - if k[0] == 32: - break - else: - time.sleep(0.01) - - -def wait_press_posix(): - from ROOT import gSystem - import sys - import select - import tty - import termios - import time - - old_settings = termios.tcgetattr(sys.stdin) - - tty.setcbreak(sys.stdin.fileno()) - - try: - - while not gSystem.ProcessEvents(): - c = '' - if select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []): - c = sys.stdin.read(1) - if (c == '\x20'): - break - time.sleep(0.01) - - finally: - termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings) - -def run_root_event_loop(): - from ROOT import gROOT - import os - import sys - - # no special handling in batch mode - if gROOT.IsBatch(): - return - - # no special handling in case of notebooks - if 'IPython' in sys.modules and sys.modules['IPython'].version_info[0] >= 5: - return - - print("Press key to continue") - - if os.name == 'nt': - wait_press_windows() - else: - wait_press_posix() - +from . import pythonization, _run_root_event_loop def _TCanvas_Update(self, block = False): """ @@ -108,7 +48,7 @@ def _TCanvas_Update(self, block = False): # run loop if block flag is set if block: - run_root_event_loop() + _run_root_event_loop() def _TCanvas_Draw(self, option: str = "", block: bool = False): @@ -126,7 +66,7 @@ def _TCanvas_Draw(self, option: str = "", block: bool = False): # run loop if block flag is set if block: self._Update() - run_root_event_loop() + _run_root_event_loop() @pythonization('TCanvas')