├── oasys ├── tests │ ├── __init__.py │ └── test_addons.py ├── util │ ├── __init__.py │ ├── script │ │ ├── __init__.py │ │ └── value.py │ ├── oasys_objects.py │ ├── oasys_registry.py │ ├── custom_distribution.py │ └── external_command.py ├── application │ ├── __init__.py │ └── data │ │ ├── INTERNAL_LIBRARIES_PY37.txt │ │ ├── OFFICIAL_ADDONS.txt │ │ └── INTERNAL_LIBRARIES_PY38.txt ├── widgets │ ├── abstract │ │ ├── __init__.py │ │ └── scanning │ │ │ ├── __init__.py │ │ │ ├── abstract_scan_file_node_point.py │ │ │ └── abstract_scan_variable_node_point.py │ ├── __init__.py │ ├── tools │ │ ├── icons │ │ │ ├── hdf5.png │ │ │ ├── tools.png │ │ │ ├── github.png │ │ │ ├── histogram.png │ │ │ ├── python_script.png │ │ │ ├── surface_merger.png │ │ │ └── surface_reader.png │ │ ├── __init__.py │ │ ├── ow_hdf5_file_reader.py │ │ ├── ow_surface_file_reader.py │ │ └── ow_surface_file_merger.py │ ├── loop_management │ │ ├── icons │ │ │ ├── pin.png │ │ │ ├── cycle.png │ │ │ └── loop_management.png │ │ ├── __init__.py │ │ ├── ow_pin.py │ │ └── ow_node_point.py │ ├── scanning │ │ ├── icons │ │ │ ├── cycle_file.png │ │ │ ├── scanning.png │ │ │ └── cycle_variable.png │ │ ├── __init__.py │ │ ├── ow_scan_file_node_point.py │ │ └── ow_scan_variable_node_point.py │ ├── exchange.py │ ├── congruence.py │ └── widget.py ├── menus │ ├── __init__.py │ └── menu.py ├── canvas │ ├── styles │ │ ├── __init__.py │ │ ├── orange │ │ │ ├── Dropdown.svg │ │ │ ├── Pause.svg │ │ │ ├── Arrow.svg │ │ │ ├── Text Size.svg │ │ │ ├── Document Info.svg │ │ │ ├── Search.svg │ │ │ ├── Grid.svg │ │ │ └── Info.svg │ │ └── orange.qss │ ├── icons │ │ ├── doc.png │ │ ├── error.png │ │ ├── exit.png │ │ ├── frame.png │ │ ├── oasys.png │ │ ├── open.png │ │ ├── print.png │ │ ├── save.png │ │ ├── text.png │ │ ├── delete.png │ │ ├── folders.png │ │ ├── frame2.png │ │ ├── options.png │ │ ├── orange.icns │ │ ├── output.png │ │ ├── splash.png │ │ ├── update.png │ │ ├── update1.png │ │ ├── warning.png │ │ ├── categories.png │ │ ├── folders2.png │ │ ├── leftEdge.png │ │ ├── leftEdgeG.png │ │ ├── leftEdgeR.png │ │ ├── moveleft.png │ │ ├── moveright.png │ │ ├── rightEdge.png │ │ ├── rightEdgeG.png │ │ ├── rightEdgeR.png │ │ ├── application.png │ │ ├── delete_gray.png │ │ ├── information.png │ │ ├── triangle-red.png │ │ ├── triangle-blue.png │ │ ├── triangle-orange.png │ │ ├── oasys-splash-screen.png │ │ ├── arrow-right.svg │ │ ├── Dropdown.svg │ │ ├── Arrow.svg │ │ ├── Pause.svg │ │ ├── Maximize Toolbar.svg │ │ ├── Minimize Toolbar.svg │ │ ├── Back.svg │ │ ├── Install.svg │ │ ├── default-category.svg │ │ ├── Text Size.svg │ │ ├── default-widget.svg │ │ ├── New.svg │ │ ├── Recent.svg │ │ ├── Document Info.svg │ │ ├── Search.svg │ │ ├── Update.svg │ │ ├── Grid.svg │ │ ├── Tutorials.svg │ │ ├── Info.svg │ │ ├── Open.svg │ │ ├── Documentation.svg │ │ └── orange-canvas.svg │ ├── __init__.py │ ├── discovery.py │ ├── conf.py │ └── widgetsscheme.py └── __init__.py ├── scripts └── macos │ ├── skeleton.app │ └── Contents │ │ ├── PkgInfo │ │ ├── Resources │ │ ├── oasys1.icns │ │ └── schema.icns │ │ ├── Frameworks │ │ ├── lib │ │ │ ├── libxrl.7.dylib │ │ │ ├── libgcc_s.1.dylib │ │ │ ├── libxrlf03.7.dylib │ │ │ ├── libgfortran.3.dylib │ │ │ └── libquadmath.0.dylib │ │ └── xraylib │ │ │ ├── _xraylib.la │ │ │ ├── xraylib_np.la │ │ │ ├── xrayhelp.py │ │ │ └── xraymessages.py │ │ ├── MacOS │ │ └── ENV │ │ └── Info.plist.in │ ├── dmg-resources │ ├── DS_Store │ ├── VolumeIcon.icns │ ├── background.png │ ├── wonder_volume.icns │ └── README.txt │ ├── requirements.txt │ ├── README.txt │ ├── sign-app.sh │ ├── sign-dmg.sh │ ├── create-dmg-installer.sh │ ├── build-macos-app.sh │ └── python-framework.sh ├── .travis.yml ├── .gitignore ├── MANIFEST.in ├── README.md ├── .gitattributes └── setup.py /oasys/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /oasys/util/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /oasys/application/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /oasys/util/script/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /oasys/widgets/abstract/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /oasys/widgets/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | """ 3 | -------------------------------------------------------------------------------- /oasys/widgets/abstract/scanning/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /oasys/menus/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'labx' 2 | -------------------------------------------------------------------------------- /scripts/macos/skeleton.app/Contents/PkgInfo: -------------------------------------------------------------------------------- 1 | APPLOrng -------------------------------------------------------------------------------- /oasys/canvas/styles/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | QSS style sheets. 3 | 4 | """ 5 | -------------------------------------------------------------------------------- /oasys/canvas/icons/doc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/doc.png -------------------------------------------------------------------------------- /oasys/canvas/icons/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/error.png -------------------------------------------------------------------------------- /oasys/canvas/icons/exit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/exit.png -------------------------------------------------------------------------------- /oasys/canvas/icons/frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/frame.png -------------------------------------------------------------------------------- /oasys/canvas/icons/oasys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/oasys.png -------------------------------------------------------------------------------- /oasys/canvas/icons/open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/open.png -------------------------------------------------------------------------------- /oasys/canvas/icons/print.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/print.png -------------------------------------------------------------------------------- /oasys/canvas/icons/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/save.png -------------------------------------------------------------------------------- /oasys/canvas/icons/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/text.png -------------------------------------------------------------------------------- /oasys/canvas/icons/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/delete.png -------------------------------------------------------------------------------- /oasys/canvas/icons/folders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/folders.png -------------------------------------------------------------------------------- /oasys/canvas/icons/frame2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/frame2.png -------------------------------------------------------------------------------- /oasys/canvas/icons/options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/options.png -------------------------------------------------------------------------------- /oasys/canvas/icons/orange.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/orange.icns -------------------------------------------------------------------------------- /oasys/canvas/icons/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/output.png -------------------------------------------------------------------------------- /oasys/canvas/icons/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/splash.png -------------------------------------------------------------------------------- /oasys/canvas/icons/update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/update.png -------------------------------------------------------------------------------- /oasys/canvas/icons/update1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/update1.png -------------------------------------------------------------------------------- /oasys/canvas/icons/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/warning.png -------------------------------------------------------------------------------- /oasys/canvas/icons/categories.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/categories.png -------------------------------------------------------------------------------- /oasys/canvas/icons/folders2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/folders2.png -------------------------------------------------------------------------------- /oasys/canvas/icons/leftEdge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/leftEdge.png -------------------------------------------------------------------------------- /oasys/canvas/icons/leftEdgeG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/leftEdgeG.png -------------------------------------------------------------------------------- /oasys/canvas/icons/leftEdgeR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/leftEdgeR.png -------------------------------------------------------------------------------- /oasys/canvas/icons/moveleft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/moveleft.png -------------------------------------------------------------------------------- /oasys/canvas/icons/moveright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/moveright.png -------------------------------------------------------------------------------- /oasys/canvas/icons/rightEdge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/rightEdge.png -------------------------------------------------------------------------------- /oasys/canvas/icons/rightEdgeG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/rightEdgeG.png -------------------------------------------------------------------------------- /oasys/canvas/icons/rightEdgeR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/rightEdgeR.png -------------------------------------------------------------------------------- /oasys/canvas/icons/application.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/application.png -------------------------------------------------------------------------------- /oasys/canvas/icons/delete_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/delete_gray.png -------------------------------------------------------------------------------- /oasys/canvas/icons/information.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/information.png -------------------------------------------------------------------------------- /oasys/canvas/icons/triangle-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/triangle-red.png -------------------------------------------------------------------------------- /oasys/widgets/tools/icons/hdf5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/widgets/tools/icons/hdf5.png -------------------------------------------------------------------------------- /oasys/widgets/tools/icons/tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/widgets/tools/icons/tools.png -------------------------------------------------------------------------------- /oasys/canvas/icons/triangle-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/triangle-blue.png -------------------------------------------------------------------------------- /oasys/canvas/icons/triangle-orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/triangle-orange.png -------------------------------------------------------------------------------- /oasys/widgets/tools/icons/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/widgets/tools/icons/github.png -------------------------------------------------------------------------------- /scripts/macos/dmg-resources/DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/scripts/macos/dmg-resources/DS_Store -------------------------------------------------------------------------------- /oasys/widgets/tools/icons/histogram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/widgets/tools/icons/histogram.png -------------------------------------------------------------------------------- /oasys/canvas/icons/oasys-splash-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/canvas/icons/oasys-splash-screen.png -------------------------------------------------------------------------------- /oasys/widgets/loop_management/icons/pin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/widgets/loop_management/icons/pin.png -------------------------------------------------------------------------------- /oasys/widgets/scanning/icons/cycle_file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/widgets/scanning/icons/cycle_file.png -------------------------------------------------------------------------------- /oasys/widgets/scanning/icons/scanning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/widgets/scanning/icons/scanning.png -------------------------------------------------------------------------------- /oasys/widgets/tools/icons/python_script.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/widgets/tools/icons/python_script.png -------------------------------------------------------------------------------- /scripts/macos/dmg-resources/VolumeIcon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/scripts/macos/dmg-resources/VolumeIcon.icns -------------------------------------------------------------------------------- /scripts/macos/dmg-resources/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/scripts/macos/dmg-resources/background.png -------------------------------------------------------------------------------- /oasys/widgets/loop_management/icons/cycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/widgets/loop_management/icons/cycle.png -------------------------------------------------------------------------------- /oasys/widgets/tools/icons/surface_merger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/widgets/tools/icons/surface_merger.png -------------------------------------------------------------------------------- /oasys/widgets/tools/icons/surface_reader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/widgets/tools/icons/surface_reader.png -------------------------------------------------------------------------------- /oasys/widgets/scanning/icons/cycle_variable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/widgets/scanning/icons/cycle_variable.png -------------------------------------------------------------------------------- /scripts/macos/dmg-resources/wonder_volume.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/scripts/macos/dmg-resources/wonder_volume.icns -------------------------------------------------------------------------------- /oasys/widgets/loop_management/icons/loop_management.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/oasys/widgets/loop_management/icons/loop_management.png -------------------------------------------------------------------------------- /scripts/macos/skeleton.app/Contents/Resources/oasys1.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/scripts/macos/skeleton.app/Contents/Resources/oasys1.icns -------------------------------------------------------------------------------- /scripts/macos/skeleton.app/Contents/Resources/schema.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/scripts/macos/skeleton.app/Contents/Resources/schema.icns -------------------------------------------------------------------------------- /scripts/macos/skeleton.app/Contents/Frameworks/lib/libxrl.7.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/scripts/macos/skeleton.app/Contents/Frameworks/lib/libxrl.7.dylib -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: xenial 2 | language: python 3 | python: 4 | - 3.5 5 | - 3.6 6 | - 3.7 7 | 8 | install: 9 | - pip install . 10 | 11 | script: 12 | pytest oasys/tests -------------------------------------------------------------------------------- /scripts/macos/skeleton.app/Contents/Frameworks/lib/libgcc_s.1.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/scripts/macos/skeleton.app/Contents/Frameworks/lib/libgcc_s.1.dylib -------------------------------------------------------------------------------- /scripts/macos/skeleton.app/Contents/Frameworks/lib/libxrlf03.7.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/scripts/macos/skeleton.app/Contents/Frameworks/lib/libxrlf03.7.dylib -------------------------------------------------------------------------------- /scripts/macos/skeleton.app/Contents/Frameworks/lib/libgfortran.3.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/scripts/macos/skeleton.app/Contents/Frameworks/lib/libgfortran.3.dylib -------------------------------------------------------------------------------- /scripts/macos/skeleton.app/Contents/Frameworks/lib/libquadmath.0.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasys-kit/OASYS1/HEAD/scripts/macos/skeleton.app/Contents/Frameworks/lib/libquadmath.0.dylib -------------------------------------------------------------------------------- /oasys/application/data/INTERNAL_LIBRARIES_PY37.txt: -------------------------------------------------------------------------------- 1 | numpy==1.21.6 2 | fabio==0.11.0 3 | scipy==1.7.3 4 | srxraylib 5 | syned 6 | wofry 7 | OASYS1 8 | silx==0.15.0 9 | PyQt5==5.15.2 10 | pip==22.2.2 11 | -------------------------------------------------------------------------------- /oasys/application/data/OFFICIAL_ADDONS.txt: -------------------------------------------------------------------------------- 1 | OASYS1-ShadowOui 2 | OASYS1-ShadowOui-Advanced-Tools 3 | OASYS1-SHADOW4 4 | OASYS1-SHADOW4-Advanced 5 | OASYS1-SRW 6 | OASYS1-XOPPY 7 | OASYS1-XRayServer 8 | OASYS1-SYNED 9 | OASYS1-WOFRY 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build files 2 | build 3 | dist 4 | *.egg-info 5 | MANIFEST 6 | oasys/version.py 7 | doc/build 8 | ENV/ 9 | 10 | *.so 11 | *.pyd 12 | *.pyc 13 | 14 | __pycache__ 15 | 16 | # Hidden files 17 | .* 18 | 19 | # Editor files 20 | *~ 21 | 22 | -------------------------------------------------------------------------------- /oasys/application/data/INTERNAL_LIBRARIES_PY38.txt: -------------------------------------------------------------------------------- 1 | numpy==1.22.4 2 | fabio==0.11.0 3 | scipy==1.9.1 4 | srxraylib 5 | syned 6 | syned-gui 7 | wofry 8 | wofryimpl 9 | shadow-hybrid-methods 10 | OASYS1 11 | silx==0.15.0 12 | PyQt5==5.15.2 13 | pip==23.3.1 14 | 15 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include oasys *.py 2 | recursive-include oasys/canvas/styles *.qss 3 | recursive-include oasys/canvas *.png *.svg *.ico 4 | recursive-include oasys/application/data *.txt 5 | 6 | recursive-include oasys/widgets *.png *.svg 7 | 8 | include LICENSE 9 | -------------------------------------------------------------------------------- /oasys/__init__.py: -------------------------------------------------------------------------------- 1 | try: 2 | from .import version 3 | # Always use short_version here (see PEP 386) 4 | __version__ = version.short_version 5 | __git_revision__ = version.git_revision 6 | except ImportError: 7 | __version__ = "unknown" 8 | __git_revision__ = "unknown" 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OASYS 1.3 2 | OASYS (OrAnge SYnchrotron Suite) is a graphical environment 3 | for optic simulation software used in synchrotron facilities, 4 | based on Orange 3. 5 | 6 | OASYS package requires Python 3.8 or newer. 7 | 8 | Instructions to install OASYS are here: https://github.com/oasys-kit/oasys-installation-scripts/wiki 9 | -------------------------------------------------------------------------------- /scripts/macos/requirements.txt: -------------------------------------------------------------------------------- 1 | # Fixed requirements file for creating a python environment for 2 | # macOS Orange.app. 3 | 4 | # Prebuild dependencies that themself do not publish wheels (e.g. bottleneck) 5 | --find-links=https://orange.biolab.si/download/files/wheelhouse 6 | 7 | requests 8 | numpy 9 | scipy 10 | matplotlib>=3.0.3 11 | pyqt5>=5.12 12 | pyqtwebengine 13 | -------------------------------------------------------------------------------- /oasys/widgets/tools/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'labx' 2 | 3 | """ 4 | ========= 5 | Tools 6 | ========= 7 | 8 | Widgets for common tools. 9 | 10 | """ 11 | 12 | # Category description for the widget registry 13 | 14 | NAME = "Tools" 15 | 16 | DESCRIPTION = "Widgets for Common Tools." 17 | 18 | BACKGROUND = "#FAAC58" 19 | 20 | ICON = "icons/tools.png" 21 | 22 | PRIORITY = 1 23 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behaviour, in case users don't have core.autocrlf set. 2 | * text=auto 3 | 4 | # Explicitly declare text files we want to always be normalized and converted 5 | # to native line endings on checkout. 6 | *.py text 7 | *.pyx text 8 | 9 | # Denote all files that are truly binary and should not be modified. 10 | *.png binary 11 | *.jpg binary 12 | *.svg binary 13 | -------------------------------------------------------------------------------- /oasys/canvas/__init__.py: -------------------------------------------------------------------------------- 1 | # pkg_resources selects a suitable resource loader based on the modules's 2 | # __loader__ attribute. In python2 it defaults to None, which maps to the 3 | # default resource loader, but it python3 it does not. As a result, 4 | # pkg_resources is unable to select a resource loader and load resources. 5 | # By settings __loader__ to None, we workaround the pkg_resources bug. 6 | __loader__ = None 7 | -------------------------------------------------------------------------------- /oasys/widgets/loop_management/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'labx' 2 | 3 | """ 4 | ========= 5 | Loop Management 6 | ========= 7 | 8 | Widgets for loop management 9 | 10 | """ 11 | 12 | # Category description for the widget registry 13 | 14 | NAME = "Basic Loops" 15 | 16 | DESCRIPTION = "Widgets for Loop Management." 17 | 18 | BACKGROUND = "#FAAC58" 19 | 20 | ICON = "icons/loop_management.png" 21 | 22 | PRIORITY = 2 23 | -------------------------------------------------------------------------------- /oasys/widgets/scanning/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'labx' 2 | 3 | """ 4 | ========= 5 | Scanning Loop Management 6 | ========= 7 | 8 | Widgets for loop management 9 | 10 | """ 11 | 12 | # Category description for the widget registry 13 | 14 | NAME = "Scanning Loops" 15 | 16 | DESCRIPTION = "Widgets for Loop Management." 17 | 18 | BACKGROUND = "#FAAC58" 19 | 20 | ICON = "icons/scanning.png" 21 | 22 | PRIORITY = 2.1 23 | -------------------------------------------------------------------------------- /oasys/canvas/icons/arrow-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /scripts/macos/README.txt: -------------------------------------------------------------------------------- 1 | Orange macOS application (.app) build scripts 2 | --------------------------------------------- 3 | 4 | Contents: 5 | 6 | python-framework.sh 7 | Download, unpack and make relocatable the official python.org framework 8 | installers (used by build-macos-app.sh) 9 | 10 | build-macos-app.sh 11 | Build an Orange.app application bundle from scratch 12 | 13 | create-dmg-installer.sh 14 | Pack the Orange.app applicaiton into a .dmg installer disk image 15 | -------------------------------------------------------------------------------- /oasys/canvas/icons/Dropdown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /oasys/canvas/styles/orange/Dropdown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /oasys/canvas/icons/Arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /oasys/canvas/icons/Pause.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /oasys/canvas/styles/orange/Pause.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /oasys/canvas/icons/Maximize Toolbar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /oasys/canvas/icons/Minimize Toolbar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /oasys/canvas/styles/orange/Arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /oasys/canvas/icons/Back.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /scripts/macos/skeleton.app/Contents/MacOS/ENV: -------------------------------------------------------------------------------- 1 | # Create an environment for running python from the bundle 2 | # Should be run as "source ENV" 3 | 4 | BUNDLE_DIR=`dirname "$0"`/../ 5 | BUNDLE_DIR=`perl -MCwd=realpath -e 'print realpath($ARGV[0])' "$BUNDLE_DIR"`/ 6 | FRAMEWORKS_DIR="$BUNDLE_DIR"Frameworks/ 7 | RESOURCES_DIR="$BUNDLE_DIR"Resources/ 8 | 9 | PYVERSION=“3.7” 10 | PYTHONEXECUTABLE="$FRAMEWORKS_DIR"Python.framework/Resources/Python.app/Contents/MacOS/Python 11 | PYTHONHOME="$FRAMEWORKS_DIR"Python.framework/Versions/"$PYVERSION"/ 12 | DYLD_FRAMEWORK_PATH="$FRAMEWORKS_DIR"${DYLD_FRAMEWORK_PATH:+:$DYLD_FRAMEWORK_PATH} 13 | 14 | export PYTHONNOUSERSITE=1 15 | 16 | # Some non framework libraries are put in $FRAMEWORKS_DIR by machlib standalone 17 | export DYLD_LIBRARY_PATH="$FRAMEWORKS_DIR"${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}lib 18 | -------------------------------------------------------------------------------- /oasys/canvas/icons/Install.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | image/svg+xml 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /oasys/tests/test_addons.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import Mock 2 | import pytest 3 | from oasys.application.addons import is_updatable, Available, Installed, Installable 4 | 5 | 6 | @pytest.mark.parametrize('items,expected', [ 7 | (Available(installable=True), False), 8 | (Installed(installable=None, local=Mock()), False), 9 | (Installed(installable=Installable(name='mock_name', 10 | version='2.0.0', 11 | summary='mock_summary', 12 | description='mock_description', 13 | package_url='mock_package_url', 14 | release_urls='mock_release_urls'), 15 | local=Mock(version='1.0.0')), True), 16 | ]) 17 | def test_is_updatable(items, expected): 18 | assert is_updatable(items) == expected 19 | -------------------------------------------------------------------------------- /oasys/canvas/icons/default-category.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 10 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /oasys/canvas/icons/Text Size.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /oasys/canvas/styles/orange/Text Size.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /oasys/canvas/icons/default-widget.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /oasys/canvas/icons/New.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /oasys/canvas/icons/Recent.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 10 | 12 | 13 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /oasys/canvas/icons/Document Info.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 10 | 13 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /oasys/canvas/styles/orange/Document Info.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 10 | 13 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /scripts/macos/skeleton.app/Contents/Frameworks/xraylib/_xraylib.la: -------------------------------------------------------------------------------- 1 | # _xraylib.la - a libtool library file 2 | # Generated by libtool (GNU libtool) 2.4.6 3 | # 4 | # Please DO NOT delete this file! 5 | # It is necessary for linking the library. 6 | 7 | # The name that we can dlopen(3). 8 | dlname='_xraylib.cpython-37m-darwin.so' 9 | 10 | # Names of this library. 11 | library_names='_xraylib.cpython-37m-darwin.so _xraylib.cpython-37m-darwin.so' 12 | 13 | # The name of the static archive. 14 | old_library='' 15 | 16 | # Linker flags that cannot go in dependency_libs. 17 | inherited_linker_flags=' ' 18 | 19 | # Libraries that this one depends upon. 20 | dependency_libs=' /usr/local/lib/libxrl.la -lm' 21 | 22 | # Names of additional weak libraries provided by this library 23 | weak_library_names='' 24 | 25 | # Version information for _xraylib. 26 | current=0 27 | age=0 28 | revision=0 29 | 30 | # Is this an already installed library? 31 | installed=yes 32 | 33 | # Should we warn about portability when linking against -modules? 34 | shouldnotlink=yes 35 | 36 | # Files to dlopen/dlpreopen 37 | dlopen='' 38 | dlpreopen='' 39 | 40 | # Directory that this library needs to be installed in: 41 | libdir='/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages' 42 | -------------------------------------------------------------------------------- /scripts/macos/skeleton.app/Contents/Frameworks/xraylib/xraylib_np.la: -------------------------------------------------------------------------------- 1 | # xraylib_np.la - a libtool library file 2 | # Generated by libtool (GNU libtool) 2.4.6 3 | # 4 | # Please DO NOT delete this file! 5 | # It is necessary for linking the library. 6 | 7 | # The name that we can dlopen(3). 8 | dlname='xraylib_np.cpython-37m-darwin.so' 9 | 10 | # Names of this library. 11 | library_names='xraylib_np.cpython-37m-darwin.so xraylib_np.cpython-37m-darwin.so' 12 | 13 | # The name of the static archive. 14 | old_library='' 15 | 16 | # Linker flags that cannot go in dependency_libs. 17 | inherited_linker_flags=' ' 18 | 19 | # Libraries that this one depends upon. 20 | dependency_libs=' /usr/local/lib/libxrl.la -lm' 21 | 22 | # Names of additional weak libraries provided by this library 23 | weak_library_names='' 24 | 25 | # Version information for xraylib_np. 26 | current=0 27 | age=0 28 | revision=0 29 | 30 | # Is this an already installed library? 31 | installed=yes 32 | 33 | # Should we warn about portability when linking against -modules? 34 | shouldnotlink=yes 35 | 36 | # Files to dlopen/dlpreopen 37 | dlopen='' 38 | dlpreopen='' 39 | 40 | # Directory that this library needs to be installed in: 41 | libdir='/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages' 42 | -------------------------------------------------------------------------------- /oasys/canvas/icons/Search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 12 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /oasys/canvas/icons/Update.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | image/svg+xml 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /oasys/canvas/styles/orange/Search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 12 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /oasys/widgets/loop_management/ow_pin.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from oasys.widgets import widget 4 | 5 | from orangewidget import gui 6 | 7 | from PyQt5 import QtGui 8 | 9 | from oasys.util.oasys_util import TriggerOut 10 | 11 | class Pin(widget.OWWidget): 12 | 13 | name = "Pin" 14 | description = "Tools: Pin" 15 | icon = "icons/pin.png" 16 | maintainer = "Luca Rebuffi" 17 | maintainer_email = "lrebuffi(@at@)anl.gov" 18 | priority = 3 19 | category = "User Defined" 20 | keywords = ["data", "file", "load", "read"] 21 | 22 | inputs = [("Trigger", TriggerOut, "passTrigger")] 23 | 24 | outputs = [{"name":"Trigger", 25 | "type":TriggerOut, 26 | "doc":"Trigger", 27 | "id":"Trigger"}] 28 | 29 | want_main_area = 0 30 | want_control_area = 1 31 | 32 | def __init__(self): 33 | 34 | self.setFixedWidth(300) 35 | self.setFixedHeight(100) 36 | 37 | gui.separator(self.controlArea, height=20) 38 | gui.label(self.controlArea, self, " SIMPLE PASSAGE POINT", orientation="horizontal") 39 | gui.rubber(self.controlArea) 40 | 41 | def passTrigger(self, trigger): 42 | self.send("Trigger", trigger) 43 | 44 | if __name__ == "__main__": 45 | a = QtGui.QApplication(sys.argv) 46 | ow = Pin() 47 | ow.show() 48 | a.exec_() 49 | ow.saveSettings() 50 | -------------------------------------------------------------------------------- /oasys/canvas/icons/Grid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 17 | 19 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /oasys/canvas/icons/Tutorials.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /scripts/macos/sign-app.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | usage() { 6 | echo 'usage: sign-app.sh -s IDENTITY PATH 7 | 8 | Sign an Orange.app application at PATH and create a signed .dmg installer. 9 | 10 | OPTIONS 11 | --sign -s IDENTITY 12 | Signing identity to use. The \`identity\` must name a signing 13 | certificate in a macOS keychain (see \`man codesign\` SIGNING 14 | IDENTITIES section for details). 15 | 16 | --help -h 17 | Print this help. 18 | ' 19 | } 20 | 21 | SCRIPTS=$( cd "$(dirname "$0")" ; pwd -P ) 22 | DIST=$( cd "$(dirname "$0")/../../dist" ; pwd -P ) 23 | 24 | IDENTITY="Developer ID" 25 | 26 | while true; do 27 | case "${1}" in 28 | -s|--sign) IDENTITY="${2:?"no identity provided"}"; shift 2;; 29 | -h|--help) usage; exit 0;; 30 | -*) echo "unrecognized parameter: ${1}" >&2; usage >&2; exit 1;; 31 | *) break;; 32 | esac 33 | done 34 | 35 | APPPATH=${1} 36 | if [ ! "${APPPATH}" ]; then 37 | APPPATH=${DIST}/Orange3.app 38 | echo "No path supplied; using default ${APPPATH}" 39 | fi 40 | 41 | VERSION=$( 42 | "${APPPATH}"/Contents/MacOS/python -c ' 43 | import pkg_resources 44 | print(pkg_resources.get_distribution("Orange3").version) 45 | ' 46 | ) 47 | 48 | # Create disk image 49 | "${SCRIPTS}"/create-dmg-installer.sh --app "${APPPATH}" \ 50 | --sign "${IDENTITY}" \ 51 | "${DIST}/Orange3-${VERSION}.dmg" 52 | 53 | -------------------------------------------------------------------------------- /oasys/canvas/styles/orange/Grid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 17 | 19 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /oasys/canvas/icons/Info.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 15 | 16 | -------------------------------------------------------------------------------- /oasys/canvas/icons/Open.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 14 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /oasys/canvas/styles/orange/Info.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 15 | 16 | -------------------------------------------------------------------------------- /oasys/widgets/exchange.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | 3 | class DataExchangeObject(object): 4 | _content = None 5 | 6 | PROGRAM_NAME = "PROGRAM_NAME" 7 | WIDGET_NAME = "WIDGET_NAME" 8 | 9 | def __init__(self, program_name, widget_name): 10 | super().__init__() 11 | 12 | self._content = {DataExchangeObject.PROGRAM_NAME: program_name, DataExchangeObject.WIDGET_NAME: widget_name} 13 | 14 | def get_program_name(self): 15 | return self.get_content(DataExchangeObject.PROGRAM_NAME) 16 | 17 | def get_widget_name(self): 18 | return self.get_content(DataExchangeObject.WIDGET_NAME) 19 | 20 | def add_content(self, content_key="KEY", content_value=""): 21 | self._content[content_key] = content_value 22 | 23 | def get_content(self, content_key="KEY"): 24 | return self._content[content_key] 25 | 26 | def add_contents(self, content_keys=numpy.array(["KEY"]), content_values=numpy.array([""])): 27 | v_add_content = numpy.vectorize(self.add_content) 28 | v_add_content(content_keys, content_values) 29 | 30 | def get_contents(self, content_keys=numpy.array(["KEY"])): 31 | v_get_content = numpy.vectorize(self.get_content) 32 | return v_get_content(content_keys) 33 | 34 | def has_content_key(self, content_key): 35 | try: 36 | self._content[content_key] 37 | return True 38 | except: 39 | return False 40 | 41 | def content_keys(self): 42 | return self._content.keys() 43 | -------------------------------------------------------------------------------- /oasys/canvas/discovery.py: -------------------------------------------------------------------------------- 1 | import pkgutil 2 | import inspect 3 | import logging 4 | 5 | from orangecanvas.registry import discovery 6 | 7 | from oasys.menus.menu import OMenu 8 | 9 | log = logging.getLogger(__name__) 10 | 11 | 12 | class MenuRegistry(object): 13 | 14 | def __init__(self, menus=None): 15 | self.registry = menus if menus is not None else [] 16 | 17 | def menus(self): 18 | return self.registry 19 | 20 | def addMenu(self, menu): 21 | self.registry.append(menu) 22 | 23 | 24 | def omenus_from_package(package): 25 | try: 26 | package = discovery.asmodule(package) 27 | except ImportError: 28 | return 29 | for path in package.__path__: 30 | for _, mod_name, ispkg in pkgutil.iter_modules([path]): 31 | if ispkg: 32 | continue 33 | 34 | name = package.__name__ + "." + mod_name 35 | try: 36 | menu_module = discovery.asmodule(name) 37 | except ImportError: 38 | log.error("Error importing '%s'", name, exc_info=True) 39 | return 40 | 41 | for name, menu_class in inspect.getmembers(menu_module): 42 | if inspect.isclass(menu_class) and \ 43 | issubclass(menu_class, OMenu) and not name == "OMenu": 44 | try: 45 | yield menu_class() 46 | except Exception: 47 | log.error("Error creating menu instance from '%s'", 48 | menu_class, exc_info=True) 49 | -------------------------------------------------------------------------------- /oasys/util/oasys_objects.py: -------------------------------------------------------------------------------- 1 | class OasysSurfaceData(object): 2 | def __init__(self, 3 | xx=None, 4 | yy=None, 5 | zz=None, 6 | surface_data_file=None): 7 | self.xx = xx 8 | self.yy = yy 9 | self.zz = zz 10 | self.surface_data_file=surface_data_file 11 | 12 | class OasysErrorProfileData(object): 13 | 14 | def __init__(self, 15 | surface_data=None, 16 | error_profile_x_dim=0.0, 17 | error_profile_y_dim=0.0): 18 | self.surface_data = surface_data 19 | self.error_profile_x_dim = error_profile_x_dim 20 | self.error_profile_y_dim = error_profile_y_dim 21 | 22 | class OasysPreProcessorData(object): 23 | 24 | def __init__(self, error_profile_data=None, reflectivity_data=None): 25 | super().__init__() 26 | 27 | self.error_profile_data = error_profile_data 28 | self.reflectivity_data = reflectivity_data 29 | self.additional_data = None 30 | 31 | def set_additional_data(self, key, value): 32 | if self._additional_data is None: 33 | self._additional_data = {key : value} 34 | else: 35 | self._additional_data[key] = value 36 | 37 | def get_additional_data(self, key): 38 | return self._additional_data[key] 39 | 40 | def has_additional_data(self, key): 41 | return key in self._additional_data 42 | 43 | class OasysThicknessErrorsData(object): 44 | def __init__(self, thickness_error_profile_data_files=[]): 45 | self.thickness_error_profile_data_files = thickness_error_profile_data_files 46 | -------------------------------------------------------------------------------- /scripts/macos/skeleton.app/Contents/Info.plist.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleName 6 | Oasys1 7 | CFBundleExecutable 8 | Oasys1 9 | CFBundleIdentifier 10 | oasys1.anl.gov 11 | CFBundleGetInfoString 12 | OASYS (OrAnge SYnchrotron Suite) 13 | CFBundleVersion 14 | __VERSION__ 15 | CFBundleShortVersionString 16 | __VERSION__ 17 | CFBundleIconFile 18 | oasys1.icns 19 | CFBundlePackageType 20 | APPL 21 | CFBundleSignature 22 | Orng 23 | CFBundleDocumentTypes 24 | 25 | 26 | CFBundleTypeName 27 | OASYS Canvas Schema 28 | CFBundleTypeExtensions 29 | 30 | ows 31 | 32 | CFBundleTypeIconFile 33 | schema.icns 34 | CFBundleTypeRole 35 | Editor 36 | LSHandlerRank 37 | Default 38 | 39 | 40 | CFBundleInfoDictionaryVersion 41 | 6.0 42 | NSPrincipalClass 43 | NSApplication 44 | NSHighResolutionCapable 45 | 46 | LSMinimumSystemVersion 47 | 10.12.0 48 | 49 | 50 | -------------------------------------------------------------------------------- /oasys/util/oasys_registry.py: -------------------------------------------------------------------------------- 1 | class AlreadyInitializedError(ValueError): 2 | def __init__(self, message=None): super(AlreadyInitializedError, self).__init__(message) 3 | 4 | class GenericRegistry(object): 5 | _NO_APPLICATION = "" 6 | 7 | def __init__(self, registry_name): 8 | self.__registry_name = registry_name 9 | self.__registry = {self._NO_APPLICATION: None} 10 | 11 | def register_instance(self, instance, application_name=None, replace=False): 12 | if instance is None: raise ValueError(self.__registry_name + " Instance is None") 13 | 14 | application_name = self.__get_application_name(application_name) 15 | 16 | if application_name in self.__registry.keys(): 17 | if self.__registry[application_name] is None or replace==True: self.__registry[application_name] = instance 18 | else: raise AlreadyInitializedError(self.__registry_name + " Instance already initialized") 19 | else: self.__registry[application_name] = instance 20 | 21 | def reset(self, application_name=None): 22 | application_name = self.__get_application_name(application_name) 23 | 24 | if application_name in self.__registry.keys(): self.__registry[self.__get_application_name(application_name)] = None 25 | else: raise ValueError(self.__registry_name + " Instance not existing") 26 | 27 | def get_instance(self, application_name=None): 28 | application_name = self.__get_application_name(application_name) 29 | 30 | if application_name in self.__registry.keys(): return self.__registry[self.__get_application_name(application_name)] 31 | else: raise ValueError(self.__registry_name + " Instance not existing") 32 | 33 | def __get_application_name(self, application_name): 34 | return self._NO_APPLICATION if application_name is None else application_name 35 | -------------------------------------------------------------------------------- /scripts/macos/dmg-resources/README.txt: -------------------------------------------------------------------------------- 1 | OSX dmg installer resources 2 | =========================== 3 | 4 | This directory contains the binary resources to create an 5 | Orange dmg installer. 6 | 7 | 8 | DS_Store 9 | OSX Desktop Services folder settings. 10 | Defined the folder background selection, icon positions and size, 11 | Finder window position and size, ... 12 | This gets copied to DMGROOT/.DS_Store 13 | 14 | VolumeIcon.icns 15 | Volume icon. 16 | This gets copied to DMGROOT/.VolumeIcon.icns 17 | 18 | background.png 19 | The background folder image. 20 | This gets copied to DMGROOT/.background/background.png 21 | as specified by DS_Store. 22 | Note if you change the path of the background image on the 23 | dmg you must also update the create-dmg-installer.sh script 24 | so it is moved to the proper place. 25 | 26 | 27 | Modifying the installer folder 28 | ------------------------------ 29 | 30 | The installer is nothing more then a Finder folder view 31 | with hidden sidebar, toolbar and statusbar. 32 | 33 | Mount an disk image in RW mode (pass the --keep-temp option to 34 | create-dmg-installer.sh to keep the temporary uncompressed image) 35 | and open the Show View Options. 36 | Select the Picture background you want (from the dmg itself). Hint: use 37 | Command-Shift-. to show hidden files in the Open dialog. From the 38 | View Options also select the proper icon size to match the background 39 | position indicators. Then move the .app and /Applications symlink 40 | icons to their specified place on the background. 41 | 42 | Resize the finder window (without the toolbar, sidebar, ...) so it 43 | fits the background. Position the window somewhere on the top left 44 | in the 1024, 768 rect so it can fit on small monitors. 45 | 46 | Eject the image so .DS_Store is flushed. Then re-mount it and copy the 47 | .DS_Store, and background image to this directory. 48 | -------------------------------------------------------------------------------- /oasys/canvas/icons/Documentation.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 11 | 12 | 14 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /scripts/macos/skeleton.app/Contents/Frameworks/xraylib/xrayhelp.py: -------------------------------------------------------------------------------- 1 | #Copyright (c) 2009, Bruno Golosio, Antonio Brunetti, Manuel Sanchez del Rio, Tom Schoonjans and Teemu Ikonen 2 | #All rights reserved. 3 | 4 | #Redistribution and use in source and binary forms, with or without 5 | #modification, are permitted provided that the following conditions are met: 6 | # * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | # * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | # * The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission. 9 | 10 | #THIS SOFTWARE IS PROVIDED BY Bruno Golosio, Antonio Brunetti, Manuel Sanchez del Rio, Tom Schoonjans and Teemu Ikonen ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Bruno Golosio, Antonio Brunetti, Manuel Sanchez del Rio, Tom Schoonjans and Teemu Ikonen BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 11 | 12 | 13 | from __future__ import print_function 14 | import string 15 | 16 | def display_func(func_name): 17 | fp = open('/usr/local/share/xraylib/xrayhelp.txt', 'r') 18 | file_lines = fp.readlines() 19 | fp.close() 20 | for i in range(len(file_lines)): 21 | line = file_lines[i].strip() 22 | if (line == func_name): 23 | while (line != ""): 24 | i = i + 1 25 | line = file_lines[i].strip() 26 | print (line) 27 | return 28 | print () 29 | print ("Function not recognized") 30 | print () 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /oasys/util/custom_distribution.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | 3 | class CustomDistribution(object): 4 | """ 5 | draws samples from a one dimensional probability distribution, 6 | by means of inversion of a discrete inverstion of a cumulative density function 7 | 8 | the pdf can be sorted first to prevent numerical error in the cumulative sum 9 | this is set as default; for big density functions with high contrast, 10 | it is absolutely necessary, and for small density functions, 11 | the overhead is minimal 12 | 13 | a call to this distibution object returns indices into density array 14 | """ 15 | def __init__(self, pdf, sort = False, interpolation = False, transform = lambda x: x, seed=0): 16 | self.shape = pdf.shape 17 | self.pdf = pdf.ravel() 18 | self.sort = sort 19 | self.interpolation = interpolation 20 | self.transform = transform 21 | self.seed = seed 22 | 23 | #a pdf can not be negative 24 | assert(numpy.all(pdf>=0)) 25 | 26 | #sort the pdf by magnitude 27 | if self.sort: 28 | self.sortindex = numpy.argsort(self.pdf, axis=None) 29 | self.pdf = self.pdf[self.sortindex] 30 | #construct the cumulative distribution function 31 | self.cdf = numpy.cumsum(self.pdf) 32 | @property 33 | def ndim(self): 34 | return len(self.shape) 35 | @property 36 | def sum(self): 37 | """cached sum of all pdf values; the pdf need not sum to one, and is imlpicitly normalized""" 38 | return self.cdf[-1] 39 | def __call__(self, N): 40 | if self.seed > 0: numpy.random.seed(self.seed) 41 | 42 | """draw """ 43 | #pick numbers which are uniformly random over the cumulative distribution function 44 | choice = numpy.random.uniform(high = self.sum, size = N) 45 | #find the indices corresponding to this point on the CDF 46 | index = numpy.searchsorted(self.cdf, choice) 47 | #if necessary, map the indices back to their original ordering 48 | if self.sort: 49 | index = self.sortindex[index] 50 | #map back to multi-dimensional indexing 51 | index = numpy.unravel_index(index, self.shape) 52 | index = numpy.vstack(index) 53 | #is this a discrete or piecewise continuous distribution? 54 | if self.interpolation: 55 | index = index + numpy.random.uniform(size=index.shape) 56 | return self.transform(index) 57 | -------------------------------------------------------------------------------- /scripts/macos/skeleton.app/Contents/Frameworks/xraylib/xraymessages.py: -------------------------------------------------------------------------------- 1 | 2 | #Copyright (c) 2009, Bruno Golosio, Antonio Brunetti, Manuel Sanchez del Rio, Tom Schoonjans and Teemu Ikonen 3 | #All rights reserved. 4 | 5 | #Redistribution and use in source and binary forms, with or without 6 | #modification, are permitted provided that the following conditions are met: 7 | # * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | # * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | # * The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | #THIS SOFTWARE IS PROVIDED BY Bruno Golosio, Antonio Brunetti, Manuel Sanchez del Rio, Tom Schoonjans and Teemu Ikonen ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Bruno Golosio, Antonio Brunetti, Manuel Sanchez del Rio, Tom Schoonjans and Teemu Ikonen BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | 13 | from __future__ import print_function 14 | import sys 15 | 16 | def display_banner(): 17 | print () 18 | fp = open('/usr/local/share/xraylib/xraybanner.txt', 'r') 19 | for line in fp.readlines(): 20 | print (line, end="") 21 | fp.close() 22 | print () 23 | 24 | def display_options(): 25 | print () 26 | print (" - Type 'xraylib -h' to see a list of the available functions") 27 | print (" - Type 'xraylib -d' to see the X-ray data documentation") 28 | print (" - Type 'xraylib -f function-name' to get help on a" \ 29 | " specific function") 30 | 31 | def display_usage(): 32 | print () 33 | print (" usage: xraylib 'expression'") 34 | print (" where 'expression' is any mathematical expression") 35 | print (" that can contain X-ray library functions.") 36 | display_options() 37 | 38 | def display_help(): 39 | print () 40 | print ("Available X-ray library functions") 41 | print () 42 | fp = open('/usr/local/share/xraylib/xrayfunc.txt', 'r') 43 | for line in fp.readlines(): 44 | print (line, end="") 45 | fp.close() 46 | display_usage() 47 | 48 | def display_doc(): 49 | print () 50 | print ("X-ray data documentation") 51 | print () 52 | fp = open('/usr/local/share/xraylib/xraydoc.txt', 'r') 53 | for line in fp.readlines(): 54 | print (line, end="") 55 | fp.close() 56 | print () 57 | 58 | -------------------------------------------------------------------------------- /oasys/util/external_command.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import logging 4 | import errno 5 | import shlex 6 | import subprocess 7 | 8 | log = logging.getLogger(__name__) 9 | 10 | class CommandFailed(Exception): 11 | def __init__(self, cmd, retcode, output): 12 | if not isinstance(cmd, str): 13 | cmd = " ".join(map(shlex.quote, cmd)) 14 | self.cmd = cmd 15 | self.retcode = retcode 16 | self.output = output 17 | 18 | def run_command(command, raise_on_fail=True, wait_for_output=True): 19 | """Run command in a subprocess. 20 | 21 | Return `process` return code and output once it completes. 22 | """ 23 | log.info("Running %s", " ".join(command)) 24 | 25 | if command[0] == "python": process = python_process(command[1:]) 26 | else:process = create_process(command) 27 | 28 | if wait_for_output: 29 | output = [] 30 | while process.poll() is None: 31 | try: 32 | line = process.stdout.readline() 33 | except IOError as ex: 34 | if ex.errno != errno.EINTR: 35 | raise 36 | else: 37 | output.append(line) 38 | print(line, end="") 39 | # Read remaining output if any 40 | line = process.stdout.read() 41 | if line: 42 | output.append(line) 43 | print(line, end="") 44 | 45 | if process.returncode != 0: 46 | log.info("Command %s failed with %s", 47 | " ".join(command), process.returncode) 48 | log.debug("Output:\n%s", "\n".join(output)) 49 | if raise_on_fail: 50 | raise CommandFailed(command, process.returncode, output) 51 | 52 | return process.returncode, output 53 | 54 | 55 | def python_process(args, script_name=None, **kwargs): 56 | """ 57 | Run a `sys.executable` in a subprocess with `args`. 58 | """ 59 | executable = sys.executable 60 | if os.name == "nt" and os.path.basename(executable) == "pythonw.exe": 61 | # Don't run the script with a 'gui' (detached) process. 62 | dirname = os.path.dirname(executable) 63 | executable = os.path.join(dirname, "python.exe") 64 | 65 | if script_name is not None: 66 | script = script_name 67 | else: 68 | script = executable 69 | 70 | return create_process( 71 | [script] + args, 72 | executable=executable 73 | ) 74 | 75 | 76 | def create_process(cmd, executable=None, **kwargs): 77 | if hasattr(subprocess, "STARTUPINFO"): 78 | # do not open a new console window for command on windows 79 | startupinfo = subprocess.STARTUPINFO() 80 | startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW 81 | kwargs["startupinfo"] = startupinfo 82 | 83 | return subprocess.Popen( 84 | cmd, 85 | executable=executable, 86 | cwd=None, 87 | stderr=subprocess.STDOUT, 88 | stdout=subprocess.PIPE, 89 | bufsize=-1, 90 | universal_newlines=True, 91 | **kwargs 92 | ) 93 | -------------------------------------------------------------------------------- /scripts/macos/sign-dmg.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | shopt -s failglob 5 | 6 | usage() { 7 | echo "sign-dmg.sh [-s IDENTITY] [-o OUTPUT] PATH 8 | 9 | Sign a .dmg application installer at 'path'. 10 | 11 | \`path\` must name a .dmg image. 12 | 13 | OPTIONS 14 | --sign -s IDENTITY 15 | Signing identity to use. The \`identity\` must name a signing 16 | certificate in a macOS keychain (see \`man codesign\` SIGNING 17 | IDENTITIES section for details) 18 | 19 | --output -o PATH 20 | Specify the output path for the resulting .dmg installer. If not 21 | supplied, then the signed dmg image is placed next to the input path 22 | with the same name and .signed appended at the end. 23 | 24 | --help -h 25 | Show this help. 26 | 27 | EXAMPLES 28 | $ ./sign-dmg.sh -s \"Developer ID\" SupperApp.dmg 29 | " 30 | } 31 | 32 | IDENTITY="Developer ID" 33 | OUTPUT= 34 | 35 | while true; do 36 | case "${1}" in 37 | -s|--sign) IDENTITY=${2:?"no identity provided"}; shift 2;; 38 | -o|--output) OUTPUT=${2:?"${1} requires a path parameter"}; shift 2;; 39 | -h|--help) usage; exit 0 ;; 40 | -*) echo "Unrecognized parameter: ${1}" >&2; echo; usage >&2; exit 1;; 41 | *) break;; 42 | esac 43 | done 44 | 45 | DMG="${1:?"Missing positional argument: PATH"}" 46 | 47 | if [ ! -f "${DMG}" ]; then 48 | echo "${DMG} does not exist or is not a file." >&2; 49 | exit 1 50 | fi 51 | 52 | # Temporary work directory 53 | WORKDIR= 54 | # Temporary mount point for the dmg 55 | MOUNT= 56 | 57 | cleanup() { 58 | if [ -d "${MOUNT}" ]; then hdiutil detach "${MOUNT}" -force || true; fi 59 | if [ -d "${WORKDIR}" ]; then rm -rf "${WORKDIR}"; fi 60 | return 61 | } 62 | trap cleanup EXIT 63 | 64 | BASENAME=$(basename "${DMG}") 65 | WORKDIR=$(mktemp -d -t "${BASENAME}") 66 | MOUNT=${WORKDIR}/mnt 67 | 68 | IMGRW=${WORKDIR}/image 69 | IMG=${WORKDIR}/${BASENAME} 70 | 71 | # convert the input dmg to a read write growable uncompressed image 72 | # NOTE: hdiutil convert always appends the extension on the output even if 73 | # already present (the ext for UDSB is .sparsebundle so the actual filename 74 | # is ${IMGRW}.sparsebundle) 75 | hdiutil convert -format UDSB -o "${IMGRW}" "${DMG}" 76 | # 'resize' the sparse image allowing growth for signing data 77 | # (1GB should be enough for everybody) 78 | hdiutil resize -size 1g "${IMGRW}".sparsebundle 79 | # mount it R/W for modification 80 | mkdir "${MOUNT}" 81 | hdiutil attach "${IMGRW}".sparsebundle -readwrite -noverify -noautoopen \ 82 | -mountpoint "${MOUNT}" 83 | 84 | codesign --sign "${IDENTITY}" --deep --verbose "${MOUNT}"/*.app 85 | 86 | # detach/unmount to sync 87 | hdiutil detach "${MOUNT}" -force 88 | # resize the image to minimum required size 89 | hdiutil resize -sectors min "${IMGRW}".sparsebundle 90 | # convert back to compressed read only image 91 | hdiutil convert -format UDZO -imagekey zlib-level=9 \ 92 | -o "${IMG}" "${IMGRW}.sparsebundle" 93 | codesign -s "${IDENTITY}" "${IMG}" 94 | 95 | if [ ! "${OUTPUT}" ]; then 96 | OUTPUT=${DMG}.signed 97 | fi 98 | 99 | mv "${IMG}" "${OUTPUT}" 100 | -------------------------------------------------------------------------------- /oasys/menus/menu.py: -------------------------------------------------------------------------------- 1 | __author__ = 'labx' 2 | __menu__="just for discovery" 3 | 4 | SEPARATOR = "OMENU_SEPARATOR" 5 | OPEN_CONTAINER = "OPEN_CONTAINER" 6 | CLOSE_CONTAINER = "CLOSE_CONTAINER" 7 | 8 | 9 | from PyQt5 import QtWidgets 10 | from orangecanvas.scheme.link import SchemeLink 11 | 12 | class OMenu(): 13 | 14 | def __init__(self, name="NewMenu"): 15 | self.name = name 16 | self.canvas_main_window=None 17 | self.sub_menu_names = [] 18 | 19 | def setCanvasMainWindow(self, canvas_main_window): 20 | self.canvas_main_window = canvas_main_window 21 | 22 | def addSubMenu(self, name): 23 | self.sub_menu_names.append(name) 24 | 25 | def addSeparator(self): 26 | self.sub_menu_names.append(SEPARATOR) 27 | 28 | def openContainer(self): 29 | self.sub_menu_names.append(OPEN_CONTAINER) 30 | 31 | def closeContainer(self): 32 | self.sub_menu_names.append(CLOSE_CONTAINER) 33 | 34 | def addContainer(self, name): 35 | self.sub_menu_names.append(name) 36 | 37 | def isSeparator(self, name): 38 | return name == SEPARATOR 39 | 40 | def isOpenContainer(self, name): 41 | return name == OPEN_CONTAINER 42 | 43 | def isCloseContainer(self, name): 44 | return name == CLOSE_CONTAINER 45 | 46 | def getSubMenuNamesList(self): 47 | return self.sub_menu_names 48 | 49 | def showConfirmMessage(self, message, informative_text=None): 50 | msgBox = QtWidgets.QMessageBox() 51 | msgBox.setIcon(QtWidgets.QMessageBox.Question) 52 | msgBox.setText(message) 53 | msgBox.setInformativeText(message if informative_text is None else informative_text) 54 | msgBox.setStandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) 55 | msgBox.setDefaultButton(QtWidgets.QMessageBox.No) 56 | ret = msgBox.exec_() 57 | return ret 58 | 59 | def showWarningMessage(self, message): 60 | msgBox = QtWidgets.QMessageBox() 61 | msgBox.setIcon(QtWidgets.QMessageBox.Warning) 62 | msgBox.setText(message) 63 | msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok) 64 | msgBox.exec_() 65 | 66 | def showCriticalMessage(self, message): 67 | msgBox = QtWidgets.QMessageBox() 68 | msgBox.setIcon(QtWidgets.QMessageBox.Critical) 69 | msgBox.setText(message) 70 | msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok) 71 | msgBox.exec_() 72 | 73 | def getWidgetFromNode(self, node): 74 | return self.canvas_main_window.current_document().scheme().widget_for_node(node) 75 | 76 | def createLinks(self, nodes, excluded_names=[], source_channel="In", sink_channel="Out"): 77 | previous_node = None 78 | for node in nodes: 79 | if not (isinstance(node, str) and node in excluded_names): 80 | if not previous_node is None : 81 | if not (isinstance(previous_node, str) and previous_node in excluded_names): 82 | link = SchemeLink(source_node=previous_node, source_channel=source_channel, sink_node=node, sink_channel=sink_channel) 83 | self.canvas_main_window.current_document().addLink(link=link) 84 | previous_node = node 85 | 86 | def getWidgetDesc(self, widget_name, excluded_names=[]): 87 | if widget_name in excluded_names: return widget_name 88 | else: return self.canvas_main_window.widget_registry.widget(widget_name) 89 | 90 | def createNewNode(self, widget_desc): 91 | return self.canvas_main_window.current_document().createNewNode(widget_desc) 92 | 93 | 94 | -------------------------------------------------------------------------------- /oasys/widgets/congruence.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | def checkNumber(value, field_name): 4 | try: 5 | float(value) 6 | except ValueError: 7 | raise Exception(str(field_name) + " is not a number") 8 | 9 | return value 10 | 11 | def checkPositiveNumber(value, field_name): 12 | value = checkNumber(value, field_name) 13 | if (value < 0): raise Exception(field_name + " should be >= 0") 14 | 15 | return value 16 | 17 | def checkStrictlyPositiveNumber(value, field_name): 18 | value = checkNumber(value, field_name) 19 | if (value <= 0): raise Exception(field_name + " should be > 0") 20 | 21 | return value 22 | 23 | def checkAngle(value, field_name): 24 | value = checkNumber(value, field_name) 25 | if value < -360 or value > 360: raise Exception(field_name + " should be >= -360 and <= 360 deg") 26 | 27 | return value 28 | 29 | def checkPositiveAngle(value, field_name): 30 | value = checkNumber(value, field_name) 31 | if value < 0 or value > 360: raise Exception(field_name + " should be >= 0 and <= 360 deg") 32 | 33 | return value 34 | 35 | def checkStrictlyPositiveAngle(value, field_name): 36 | value = checkNumber(value, field_name) 37 | if value <= 0 or value >= 360: raise Exception(field_name + " should be > 0 and < 360 deg") 38 | 39 | return value 40 | 41 | def checkEmptyString(string, field_name): 42 | if string is None: raise Exception(field_name + " should not be an empty string") 43 | if string.strip() == "": raise Exception(field_name + " should not be an empty string") 44 | 45 | return string 46 | 47 | def checkGreaterThan(number1, number2, field_name1, field_name_2): 48 | if number1 <= number2: raise Exception(field_name1 + " should be greater than " + field_name_2) 49 | 50 | def checkGreaterOrEqualThan(number1, number2, field_name1, field_name_2): 51 | if number1 < number2: raise Exception(field_name1 + " should be greater or equal than " + field_name_2) 52 | 53 | def checkLessThan(number1, number2, field_name1, field_name_2): 54 | if number1 >= number2: raise Exception(field_name1 + " should be less than " + field_name_2) 55 | 56 | def checkLessOrEqualThan(number1, number2, field_name1, field_name_2): 57 | if number1 > number2: raise Exception(field_name1 + " should be less or equal than " + field_name_2) 58 | 59 | def checkEqualTo(number1, number2, field_name1, field_name_2): 60 | if number1 != number2: raise Exception(field_name1 + " should be equal to " + field_name_2) 61 | 62 | def checkFileName(fileName): 63 | if isinstance(fileName, bytes): fileName = fileName.decode('utf-8') 64 | 65 | if fileName is None: raise Exception("File name is Empty") 66 | if fileName.strip() == "": raise Exception("File name is Empty") 67 | 68 | if os.path.isabs(fileName): 69 | filePath = fileName 70 | else: 71 | if fileName.startswith(os.path.sep): 72 | filePath = os.getcwd() + fileName 73 | else: 74 | filePath = os.getcwd() + os.path.sep + fileName 75 | 76 | return filePath 77 | 78 | def checkDir(fileName): 79 | if isinstance(fileName, bytes): fileName = fileName.decode('utf-8') 80 | 81 | filePath = checkFileName(fileName) 82 | 83 | container_dir = os.path.dirname(filePath) 84 | 85 | if not os.path.exists(container_dir): 86 | raise Exception("Directory " + container_dir + " not existing") 87 | 88 | return filePath 89 | 90 | def checkFile(fileName): 91 | if isinstance(fileName, bytes): fileName = fileName.decode('utf-8') 92 | 93 | filePath = checkDir(fileName) 94 | 95 | if not os.path.exists(filePath): 96 | raise Exception("File " + fileName + " not existing") 97 | 98 | return filePath 99 | 100 | 101 | def checkUrl(myfileurl): 102 | from urllib.request import urlopen 103 | try: 104 | u = urlopen(myfileurl) 105 | except: 106 | try: 107 | return checkFile(myfileurl) 108 | except: 109 | raise Exception("URL or File not accessible: "+myfileurl) 110 | 111 | return myfileurl 112 | -------------------------------------------------------------------------------- /oasys/widgets/scanning/ow_scan_file_node_point.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # ######################################################################### 4 | # Copyright (c) 2020, UChicago Argonne, LLC. All rights reserved. # 5 | # # 6 | # Copyright 2020. UChicago Argonne, LLC. This software was produced # 7 | # under U.S. Government contract DE-AC02-06CH11357 for Argonne National # 8 | # Laboratory (ANL), which is operated by UChicago Argonne, LLC for the # 9 | # U.S. Department of Energy. The U.S. Government has rights to use, # 10 | # reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR # 11 | # UChicago Argonne, LLC MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR # 12 | # ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE. If software is # 13 | # modified to produce derivative works, such modified software should # 14 | # be clearly marked, so as not to confuse it with the version available # 15 | # from ANL. # 16 | # # 17 | # Additionally, redistribution and use in source and binary forms, with # 18 | # or without modification, are permitted provided that the following # 19 | # conditions are met: # 20 | # # 21 | # * Redistributions of source code must retain the above copyright # 22 | # notice, this list of conditions and the following disclaimer. # 23 | # # 24 | # * Redistributions in binary form must reproduce the above copyright # 25 | # notice, this list of conditions and the following disclaimer in # 26 | # the documentation and/or other materials provided with the # 27 | # distribution. # 28 | # # 29 | # * Neither the name of UChicago Argonne, LLC, Argonne National # 30 | # Laboratory, ANL, the U.S. Government, nor the names of its # 31 | # contributors may be used to endorse or promote products derived # 32 | # from this software without specific prior written permission. # 33 | # # 34 | # THIS SOFTWARE IS PROVIDED BY UChicago Argonne, LLC AND CONTRIBUTORS # 35 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # 36 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # 37 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UChicago # 38 | # Argonne, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # 39 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # 40 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # 41 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # 42 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # 43 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # 44 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # 45 | # POSSIBILITY OF SUCH DAMAGE. # 46 | # ######################################################################### 47 | 48 | from oasys.widgets.abstract.scanning.abstract_scan_file_node_point import AbstractScanFileLoopPoint 49 | 50 | class ScanFileLoopPoint(AbstractScanFileLoopPoint): 51 | 52 | name = "Scanning File Loop Point" 53 | description = "Tools: LoopPoint" 54 | icon = "icons/cycle_file.png" 55 | maintainer = "Luca Rebuffi" 56 | maintainer_email = "lrebuffi(@at@)anl.gov" 57 | priority = 2 58 | category = "User Defined" 59 | keywords = ["data", "file", "load", "read"] 60 | 61 | def __init__(self): 62 | super(ScanFileLoopPoint, self).__init__() 63 | 64 | import sys 65 | from PyQt5.QtWidgets import QApplication 66 | 67 | if __name__ == "__main__": 68 | a = QApplication(sys.argv) 69 | ow = ScanFileLoopPoint() 70 | ow.show() 71 | a.exec_() 72 | ow.saveSettings() 73 | -------------------------------------------------------------------------------- /oasys/widgets/scanning/ow_scan_variable_node_point.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # ######################################################################### 4 | # Copyright (c) 2020, UChicago Argonne, LLC. All rights reserved. # 5 | # # 6 | # Copyright 2020. UChicago Argonne, LLC. This software was produced # 7 | # under U.S. Government contract DE-AC02-06CH11357 for Argonne National # 8 | # Laboratory (ANL), which is operated by UChicago Argonne, LLC for the # 9 | # U.S. Department of Energy. The U.S. Government has rights to use, # 10 | # reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR # 11 | # UChicago Argonne, LLC MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR # 12 | # ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE. If software is # 13 | # modified to produce derivative works, such modified software should # 14 | # be clearly marked, so as not to confuse it with the version available # 15 | # from ANL. # 16 | # # 17 | # Additionally, redistribution and use in source and binary forms, with # 18 | # or without modification, are permitted provided that the following # 19 | # conditions are met: # 20 | # # 21 | # * Redistributions of source code must retain the above copyright # 22 | # notice, this list of conditions and the following disclaimer. # 23 | # # 24 | # * Redistributions in binary form must reproduce the above copyright # 25 | # notice, this list of conditions and the following disclaimer in # 26 | # the documentation and/or other materials provided with the # 27 | # distribution. # 28 | # # 29 | # * Neither the name of UChicago Argonne, LLC, Argonne National # 30 | # Laboratory, ANL, the U.S. Government, nor the names of its # 31 | # contributors may be used to endorse or promote products derived # 32 | # from this software without specific prior written permission. # 33 | # # 34 | # THIS SOFTWARE IS PROVIDED BY UChicago Argonne, LLC AND CONTRIBUTORS # 35 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # 36 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # 37 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UChicago # 38 | # Argonne, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # 39 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # 40 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # 41 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # 42 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # 43 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # 44 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # 45 | # POSSIBILITY OF SUCH DAMAGE. # 46 | # ######################################################################### 47 | 48 | from oasys.widgets.abstract.scanning.abstract_scan_variable_node_point import AbstractScanVariableLoopPoint 49 | 50 | class ScanVariableLoopPoint(AbstractScanVariableLoopPoint): 51 | 52 | name = "Scanning Variable Loop Point" 53 | description = "Tools: LoopPoint" 54 | icon = "icons/cycle_variable.png" 55 | maintainer = "Luca Rebuffi" 56 | maintainer_email = "lrebuffi(@at@)anl.gov" 57 | priority = 1 58 | category = "User Defined" 59 | keywords = ["data", "file", "load", "read"] 60 | 61 | def __init__(self): 62 | super(ScanVariableLoopPoint, self).__init__() 63 | 64 | import sys 65 | from PyQt5.QtWidgets import QApplication 66 | 67 | if __name__ == "__main__": 68 | a = QApplication(sys.argv) 69 | ow = ScanVariableLoopPoint() 70 | ow.show() 71 | a.exec_() 72 | ow.saveSettings() 73 | -------------------------------------------------------------------------------- /scripts/macos/create-dmg-installer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | function print_usage() { 6 | echo 'create-dmg-installer.sh --app BUILD_APP_PATH OUTPUT_BUNDLE.dmg 7 | 8 | Create an disk image installer (.dmg) for Orange OSX application. 9 | 10 | Options: 11 | -a --app PATH 12 | Path to a build Orange3.app to include in the disk image 13 | (default dist/Orange3.app) 14 | 15 | -s --sign IDENTITY 16 | Sign the application and the .dmg image using the signing identity 17 | provided (see `man codesign` SIGNING IDENTITIES section for details) 18 | 19 | -k --keep-temp 20 | Keep the temporary files after creating the final image. 21 | 22 | -h --help 23 | Print this help 24 | ' 25 | } 26 | 27 | 28 | DIRNAME=$(dirname "$0") 29 | 30 | # Path to dmg resources (volume icon, background, ...) 31 | RES="${DIRNAME}"/dmg-resources 32 | 33 | APP=dist/Oasys1.2.app 34 | 35 | KEEP_TEMP=0 36 | IDENTITY= 37 | 38 | while [[ "${1:0:1}" = "-" ]]; do 39 | case "${1}" in 40 | -a|--app) 41 | APP=${2:?"BUILD_APP_PATH is missing"} 42 | shift 2 ;; 43 | -k|--keep-temp) 44 | KEEP_TEMP=1 45 | shift 1 ;; 46 | -s|--sign) 47 | IDENTITY=${2:?"${1} is missing a parameter"} 48 | shift 2;; 49 | -h|--help) 50 | print_usage 51 | exit 0 ;; 52 | -*) 53 | echo "Unknown option $1" >&2 54 | print_usage 55 | exit 1 56 | ;; 57 | esac 58 | done 59 | 60 | DMG=${1?"Output bundle dmg path not specified"} 61 | 62 | 63 | if [[ ! -d "${APP}" ]]; then 64 | echo "$APP path does not exits or is not a directory." 65 | print_usage 66 | exit 1 67 | fi 68 | 69 | TMP_DIR=$(mktemp -d -t create-dmg-installer) 70 | TMP_TEMPLATE="${TMP_DIR}"/template 71 | TMP_DMG="${TMP_DIR}"/Oasys1.2.dmg 72 | TMP_MOUNT="${TMP_DIR}"/mnt 73 | 74 | echo "Preparing an image template in ${TMP_TEMPLATE}" 75 | echo "=============================================" 76 | 77 | # Copy necessary resources into the template 78 | 79 | mkdir -p "${TMP_TEMPLATE}"/.background 80 | 81 | cp -a "${RES}"/background.png "${TMP_TEMPLATE}"/.background 82 | cp -a "${RES}"/VolumeIcon.icns "${TMP_TEMPLATE}"/.VolumeIcon.icns 83 | cp -a "${RES}"/DS_Store "${TMP_TEMPLATE}"/.DS_Store 84 | 85 | # Create a link to the Applications folder. 86 | ln -s /Applications/ "${TMP_TEMPLATE}"/Applications 87 | 88 | # Copy the .app directory in place 89 | cp -a "${APP}" "${TMP_TEMPLATE}"/Oasys1.2.app 90 | 91 | if [[ "${IDENTITY}" ]]; then 92 | codesign -s "${IDENTITY}" --deep --verbose \ 93 | "${TMP_TEMPLATE}"/Oasys1.2.app 94 | fi 95 | 96 | # Create a regular .fseventsd/no_log file 97 | # (see http://hostilefork.com/2009/12/02/trashes-fseventsd-and-spotlight-v100/ ) 98 | 99 | mkdir "${TMP_TEMPLATE}"/.fseventsd 100 | touch "${TMP_TEMPLATE}"/.fseventsd/no_log 101 | 102 | 103 | echo "Creating a temporary disk image" 104 | hdiutil create -format UDRW -volname Oasys1.2 -fs HFS+ \ 105 | -fsargs "-c c=64,a=16,e=16" \ 106 | -srcfolder "${TMP_TEMPLATE}" \ 107 | "${TMP_DMG}" 108 | 109 | mkdir "${TMP_MOUNT}" 110 | 111 | # Mount in RW mode 112 | echo "Mounting temporary disk image" 113 | hdiutil attach -readwrite -noverify -noautoopen -mountpoint "${TMP_MOUNT}" \ 114 | "${TMP_DMG}" 115 | 116 | echo "Fixing permissions" 117 | chmod -Rf go-w "${TMP_TEMPLATE}" || true 118 | 119 | # Makes the disk image window open automatically when mounted 120 | bless -openfolder "${TMP_MOUNT}" 121 | 122 | # Hides background directory even more 123 | SetFile -a V "${TMP_MOUNT}/.background/" 124 | 125 | # Sets the custom icon volume flag so that volume has nice 126 | # Orange icon after mount (.VolumeIcon.icns) 127 | SetFile -a C "${TMP_MOUNT}" 128 | 129 | echo "Unmouting the temporary image" 130 | sync 131 | hdiutil detach "${TMP_MOUNT}" -verbose -force 132 | 133 | echo "Converting temporary image to a compressed image." 134 | 135 | if [[ -e "${DMG}" ]]; then rm -f "${DMG}"; fi 136 | 137 | mkdir -p "$(dirname "${DMG}")" 138 | hdiutil convert "${TMP_DMG}" -format UDZO -imagekey zlib-level=9 -o "${DMG}" 139 | 140 | if [[ "${IDENTITY}" ]]; then 141 | codesign -s "${IDENTITY}" "${DMG}" 142 | fi 143 | 144 | if [ ! ${KEEP_TEMP} ]; then 145 | echo "Cleaning up." 146 | rm -rf "${TMP_DIR}" 147 | fi 148 | -------------------------------------------------------------------------------- /oasys/util/script/value.py: -------------------------------------------------------------------------------- 1 | from numbers import Real 2 | from math import isnan 3 | 4 | #: A constant representing unknown value (NaN). Use this for storing unknowns, 5 | #: but not for checking for unknowns. 6 | Unknown = float("nan") 7 | 8 | 9 | class Value(float): 10 | """ 11 | The class representing a value. The class is not used to store values but 12 | only to return them in contexts in which we want the value to be accompanied 13 | with the descriptor, for instance to print the symbolic value of discrete 14 | variables. 15 | 16 | The class is derived from `float`, with an additional attribute `variable` 17 | which holds the descriptor of type :obj:`Orange.data.Variable`. If the 18 | value continuous or discrete, it is stored as a float. Other types of 19 | values, like strings, are stored in the attribute `value`. 20 | 21 | The class overloads the methods for printing out the value: 22 | `variable.repr_val` and `variable.str_val` are used to get a suitable 23 | representation of the value. 24 | 25 | Equivalence operator is overloaded as follows: 26 | 27 | - unknown values are equal; if one value is unknown and the other is not, 28 | they are different; 29 | 30 | - if the value is compared with the string, the value is converted to a 31 | string using `variable.str_val` and the two strings are compared 32 | 33 | - if the value is stored in attribute `value`, it is compared with the 34 | given other value 35 | 36 | - otherwise, the inherited comparison operator for `float` is called. 37 | 38 | Finally, value defines a hash, so values can be put in sets and appear as 39 | keys in dictionaries. 40 | 41 | .. attribute:: variable (:obj:`Orange.data.Variable`) 42 | 43 | Descriptor; used for printing out and for comparing with strings 44 | 45 | .. attribute:: value 46 | 47 | Value; the value can be of arbitrary type and is used only for variables 48 | that are neither discrete nor continuous. If `value` is `None`, the 49 | derived `float` value is used. 50 | """ 51 | __slots__ = "variable", "_value" 52 | 53 | def __new__(cls, variable, value=Unknown): 54 | """ 55 | Construct a new instance of Value with the given descriptor and value. 56 | If the argument `value` can be converted to float, it is stored as 57 | `float` and the attribute `value` is set to `None`. Otherwise, the 58 | inherited float is set to `Unknown` and the value is held by the 59 | attribute `value`. 60 | 61 | :param variable: descriptor 62 | :type variable: Orange.data.Variable 63 | :param value: value 64 | """ 65 | if not isinstance(value, str): 66 | try: 67 | self = super().__new__(cls, value) 68 | self.variable = variable 69 | return self 70 | except: 71 | pass 72 | self = super().__new__(cls, -1) 73 | self._value = value 74 | self.variable = variable 75 | return self 76 | 77 | def __init__(self, _, __=Unknown): 78 | pass 79 | 80 | def __repr__(self): 81 | return "Value('%s', %s)" % (self.variable.name, 82 | self.variable.repr_val(self)) 83 | 84 | def __str__(self): 85 | return self.variable.str_val(self) 86 | 87 | def __eq__(self, other): 88 | if isinstance(self, Real) and isnan(self): 89 | return (isinstance(other, Real) and isnan(other) 90 | or other in self.variable.unknown_str) 91 | if isinstance(other, str): 92 | return self.variable.str_val(self) == other 93 | if isinstance(other, Value): 94 | return self.value == other.value 95 | return super().__eq__(other) 96 | 97 | def __contains__(self, other): 98 | if (self.value is not None 99 | and isinstance(self.value, str) 100 | and isinstance(other, str)): 101 | return other in self.value 102 | raise TypeError("invalid operation on Value()") 103 | 104 | def __hash__(self): 105 | if self.value is None: 106 | return super().__hash__(self) 107 | else: 108 | return super().__hash__(self) ^ hash(self.value) 109 | 110 | @property 111 | def value(self): 112 | from . import DiscreteVariable, StringVariable 113 | if isinstance(self.variable, DiscreteVariable): 114 | return self.variable.values[int(self)] 115 | if isinstance(self.variable, StringVariable): 116 | return self._value 117 | return float(self) 118 | 119 | def __getnewargs__(self): 120 | return self.variable, float(self) 121 | 122 | def __getstate__(self): 123 | return dict(value=getattr(self, '_value', None)) 124 | 125 | def __setstate__(self, state): 126 | self._value = state.get('value', None) 127 | -------------------------------------------------------------------------------- /oasys/canvas/conf.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import sys 3 | # 17 Jan 2025: replaced pkg_resources with importlib (for now the third party version) 4 | # because of deprecation 5 | #import pkg_resources 6 | import importlib_resources 7 | import importlib_metadata 8 | 9 | from PyQt5.QtGui import QPixmap, QFont, QFontMetrics, QColor, QPainter, QIcon 10 | from PyQt5.QtCore import Qt, QCoreApplication, QPoint, QRect 11 | 12 | from orangewidget.canvas import config as owconfig 13 | from orangecanvas import config 14 | 15 | from . import discovery, widgetsscheme 16 | 17 | 18 | WIDGETS_ENTRY = "oasys.widgets" 19 | MENU_ENTRY = "oasys.menus" 20 | 21 | #: Parameters for searching add-on packages in PyPi using xmlrpc api. 22 | ADDON_PYPI_SEARCH_SPEC = {"keywords": "oasys1", "owner" : "lucarebuffi"} 23 | #: Entry points by which add-ons register with pkg_resources. 24 | ADDONS_ENTRY = "oasys.addons" 25 | 26 | # Add a default for our extra default-working-dir setting. 27 | config.spec += [ 28 | config.config_slot("output/default-working-dir", str, "", 29 | "Default working directory"), 30 | config.config_slot("oasys/addon-update-check-period", int, 1, 31 | "Check for updates every (in days)") 32 | ] 33 | 34 | class oasysconf(owconfig.orangeconfig): 35 | OrganizationDomain = "" 36 | ApplicationName = "OASYS1" 37 | 38 | if sys.platform == 'darwin' and sys.version_info[1] <= 6: 39 | ApplicationVersion = "1.1" 40 | else: 41 | if sys.version[:3]=="3.8": 42 | ApplicationVersion = "1.3" 43 | else: 44 | ApplicationVersion = "1.2" 45 | 46 | @staticmethod 47 | def splash_screen(): 48 | ref = importlib_resources.files(__name__).joinpath("icons/oasys-splash-screen.png") 49 | with importlib_resources.as_file(ref) as path: pm = QPixmap(str(path)) 50 | 51 | version = QCoreApplication.applicationVersion() 52 | size = 21 if len(version) < 5 else 16 53 | font = QFont("Helvetica") 54 | font.setPixelSize(size) 55 | font.setBold(True) 56 | font.setItalic(True) 57 | font.setLetterSpacing(QFont.AbsoluteSpacing, 2) 58 | metrics = QFontMetrics(font) 59 | br = metrics.boundingRect(version).adjusted(-5, 0, 5, 0) 60 | br.moveCenter(QPoint(436, 224)) 61 | 62 | p = QPainter(pm) 63 | p.setRenderHint(QPainter.Antialiasing) 64 | p.setRenderHint(QPainter.TextAntialiasing) 65 | p.setFont(font) 66 | p.setPen(QColor("#231F20")) 67 | p.drawText(br, Qt.AlignCenter, version) 68 | p.end() 69 | return pm, QRect(88, 193, 200, 20) 70 | 71 | @staticmethod 72 | def application_icon(): 73 | """ 74 | Return the main application icon. 75 | """ 76 | ref = importlib_resources.files(__name__).joinpath("icons/oasys.png") 77 | with importlib_resources.as_file(ref) as path: return QIcon(str(path)) 78 | 79 | @staticmethod 80 | def widgets_entry_points(): 81 | # 17 Jan 2025: replaced pkg_resources with importlib (for now the third party version) 82 | # because of deprecation 83 | return importlib_metadata.entry_points(group=WIDGETS_ENTRY) 84 | #return pkg_resources.iter_entry_points(WIDGETS_ENTRY) 85 | 86 | @staticmethod 87 | def addon_entry_points(): 88 | # 17 Jan 2025: replaced pkg_resources with importlib (for now the third party version) 89 | # because of deprecation 90 | return importlib_metadata.entry_points(group=ADDONS_ENTRY) 91 | #return pkg_resources.iter_entry_points(ADDONS_ENTRY) 92 | 93 | @staticmethod 94 | def addon_pypi_search_spec(): 95 | return dict(ADDON_PYPI_SEARCH_SPEC) 96 | 97 | @staticmethod 98 | def tutorials_entry_points(): 99 | # 17 Jan 2025: replaced pkg_resources with importlib (for now the third party version) 100 | # because of deprecation 101 | return importlib_metadata.entry_points(group="oasys.tutorials") 102 | #return pkg_resources.iter_entry_points("oasys.tutorials") 103 | 104 | workflow_constructor = widgetsscheme.OASYSWidgetsScheme 105 | 106 | 107 | def omenus(): 108 | """ 109 | Return an iterator of oasys.menu.OMenu instances registered 110 | by 'orange.menu' pkg_resources entry point. 111 | """ 112 | log = logging.getLogger(__name__) 113 | # 17 Jan 2025: replaced pkg_resources with importlib (for now the third party version) 114 | # because of deprecation 115 | #for ep in pkg_resources.iter_entry_points(MENU_ENTRY): 116 | for ep in importlib_metadata.entry_points(group=MENU_ENTRY): 117 | try: 118 | menu = ep.load() 119 | #except pkg_resources.ResolutionError: 120 | # log.info("Error loading a '%s' entry point.", MENU_ENTRY, exc_info=True) 121 | except Exception: 122 | log.exception("Error loading a '%s' entry point.", MENU_ENTRY) 123 | else: 124 | if "MENU" in menu.__dict__: 125 | yield from discovery.omenus_from_package(menu) 126 | 127 | 128 | def menu_registry(): 129 | """ 130 | Return the the OASYS extension menu registry. 131 | """ 132 | return discovery.MenuRegistry(list(omenus())) 133 | -------------------------------------------------------------------------------- /oasys/widgets/tools/ow_hdf5_file_reader.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | 3 | from PyQt5.QtCore import QRect 4 | from PyQt5.QtWidgets import QApplication, QMessageBox 5 | 6 | from orangewidget import gui 7 | from orangewidget.settings import Setting 8 | 9 | from oasys.widgets.widget import OWWidget 10 | from oasys.widgets import gui as oasysgui 11 | from oasys.widgets import congruence 12 | 13 | from silx.gui import qt 14 | import silx.gui.hdf5 15 | from silx.gui.data.DataViewerFrame import DataViewerFrame 16 | 17 | class Hdf5TreeViewWidget(qt.QWidget): 18 | def __init__(self, file_names=None): 19 | qt.QWidget.__init__(self) 20 | 21 | self.__treeview = silx.gui.hdf5.Hdf5TreeView(self) 22 | self.__text = qt.QTextEdit(self) 23 | self.__dataViewer = DataViewerFrame(self) 24 | 25 | vSplitter = qt.QSplitter(qt.Qt.Vertical) 26 | vSplitter.addWidget(self.__dataViewer) 27 | vSplitter.addWidget(self.__text) 28 | vSplitter.setSizes([10, 0]) 29 | 30 | splitter = qt.QSplitter(self) 31 | splitter.addWidget(self.__treeview) 32 | splitter.addWidget(vSplitter) 33 | splitter.setStretchFactor(1, 1) 34 | 35 | layout = qt.QVBoxLayout() 36 | layout.addWidget(splitter) 37 | layout.setStretchFactor(splitter, 1) 38 | self.setLayout(layout) 39 | 40 | # append all files to the tree 41 | if not file_names is None: 42 | for file_name in file_names: 43 | self.__treeview.findHdf5TreeModel().appendFile(file_name) 44 | 45 | self.__treeview.activated.connect(self.displayData) 46 | 47 | def displayData(self): 48 | """Called to update the dataviewer with the selected data. 49 | """ 50 | selected = list(self.__treeview.selectedH5Nodes()) 51 | if len(selected) == 1: 52 | # Update the viewer for a single selection 53 | data = selected[0] 54 | self.__dataViewer.setData(data) 55 | 56 | def load_file(self, filename): 57 | self.__treeview.findHdf5TreeModel().insertFile(filename) 58 | 59 | def set_text(self, text): 60 | self.__text.setText(text) 61 | 62 | def __hdf5ComboChanged(self, index): 63 | function = self.__hdf5Combo.itemData(index) 64 | self.__createHdf5Button.setCallable(function) 65 | 66 | def __edfComboChanged(self, index): 67 | function = self.__edfCombo.itemData(index) 68 | self.__createEdfButton.setCallable(function) 69 | 70 | 71 | class OWHDF5FileReader(OWWidget): 72 | name = "HDF5 File Reader" 73 | id = "hdf5_file_reader" 74 | description = "HDF5 File Reader" 75 | icon = "icons/hdf5.png" 76 | author = "Luca Rebuffi" 77 | maintainer_email = "lrebuffi@anl.gov" 78 | priority = 2 79 | category = "" 80 | keywords = ["hdf5_file_reader"] 81 | 82 | want_main_area = 1 83 | want_control_area = 1 84 | 85 | MAX_WIDTH = 1320 86 | MAX_HEIGHT = 700 87 | 88 | IMAGE_WIDTH = 860 89 | IMAGE_HEIGHT = 645 90 | 91 | CONTROL_AREA_WIDTH = 405 92 | TABS_AREA_HEIGHT = 618 93 | 94 | hdf5_file_name = Setting('file.hdf5') 95 | 96 | def __init__(self): 97 | super().__init__() 98 | 99 | geom = QApplication.desktop().availableGeometry() 100 | self.setGeometry(QRect(round(geom.width() * 0.05), 101 | round(geom.height() * 0.05), 102 | round(min(geom.width() * 0.98, self.MAX_WIDTH)), 103 | round(min(geom.height() * 0.95, self.MAX_HEIGHT)))) 104 | 105 | self.setMaximumHeight(self.geometry().height()) 106 | self.setMaximumWidth(self.geometry().width()) 107 | 108 | gui.separator(self.controlArea) 109 | 110 | button_box = oasysgui.widgetBox(self.controlArea, "", addSpace=False, orientation="horizontal") 111 | 112 | button = gui.button(button_box, self, "Load HDF5 file", callback=self.load_file) 113 | button.setFixedHeight(45) 114 | 115 | input_box_l = oasysgui.widgetBox(self.controlArea, "Input", addSpace=True, orientation="horizontal", height=self.TABS_AREA_HEIGHT) 116 | 117 | self.le_hdf5_file_name = oasysgui.lineEdit(input_box_l, self, "hdf5_file_name", "HDF5 File Name", 118 | labelWidth=120, valueType=str, orientation="horizontal") 119 | 120 | gui.button(input_box_l, self, "...", callback=self.selectPlotXYFile) 121 | 122 | self.tree_view = Hdf5TreeViewWidget() 123 | 124 | self.mainArea.layout().addWidget(self.tree_view) 125 | 126 | gui.rubber(self.mainArea) 127 | 128 | 129 | def load_file(self): 130 | try: 131 | hdf5_file_name = congruence.checkDir(self.hdf5_file_name) 132 | 133 | self.tree_view.load_file(hdf5_file_name) 134 | self.tree_view.set_text("Loaded File: " + hdf5_file_name) 135 | 136 | except Exception as exception: 137 | QMessageBox.critical(self, "Error", exception.args[0], QMessageBox.Ok) 138 | 139 | if self.IS_DEVELOP: raise exception 140 | 141 | def selectPlotXYFile(self): 142 | self.le_hdf5_file_name.setText(oasysgui.selectFileFromDialog(self, self.hdf5_file_name, "Select Input File", file_extension_filter="HDF5 Files (*.hdf5 *.h5 *.hdf)")) 143 | 144 | 145 | -------------------------------------------------------------------------------- /oasys/widgets/tools/ow_surface_file_reader.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | 3 | import numpy 4 | from PyQt5.QtCore import QRect 5 | from PyQt5.QtWidgets import QApplication, QMessageBox 6 | 7 | from matplotlib import cm 8 | from oasys.widgets.gui import FigureCanvas3D 9 | from matplotlib.figure import Figure 10 | 11 | from orangewidget import gui 12 | from orangewidget.settings import Setting 13 | 14 | from oasys.widgets.widget import OWWidget 15 | from oasys.widgets import gui as oasysgui 16 | from oasys.widgets import congruence 17 | 18 | from oasys.util.oasys_objects import OasysSurfaceData 19 | 20 | import oasys.util.oasys_util as OU 21 | 22 | try: 23 | from mpl_toolkits.mplot3d import Axes3D # necessario per caricare i plot 3D 24 | except: 25 | pass 26 | 27 | class OWSurfaceFileReader(OWWidget): 28 | name = "Surface File Reader" 29 | id = "surface_file_reader" 30 | description = "Surface File Reader" 31 | icon = "icons/surface_reader.png" 32 | author = "Luca Rebuffi" 33 | maintainer_email = "lrebuffi@anl.gov" 34 | priority = 3 35 | category = "" 36 | keywords = ["surface_file_reader"] 37 | 38 | outputs = [{"name": "Surface Data", 39 | "type": OasysSurfaceData, 40 | "doc": "Surface Data", 41 | "id": "Surface Data"}] 42 | 43 | want_main_area = 1 44 | want_control_area = 1 45 | 46 | MAX_WIDTH = 1320 47 | MAX_HEIGHT = 700 48 | 49 | IMAGE_WIDTH = 860 50 | IMAGE_HEIGHT = 645 51 | 52 | CONTROL_AREA_WIDTH = 405 53 | TABS_AREA_HEIGHT = 618 54 | 55 | xx = None 56 | yy = None 57 | zz = None 58 | 59 | surface_file_name = Setting('surface.hdf5') 60 | 61 | negate = Setting(0) 62 | 63 | def __init__(self): 64 | super().__init__() 65 | 66 | geom = QApplication.desktop().availableGeometry() 67 | self.setGeometry(QRect(round(geom.width() * 0.05), 68 | round(geom.height() * 0.05), 69 | round(min(geom.width() * 0.98, self.MAX_WIDTH)), 70 | round(min(geom.height() * 0.95, self.MAX_HEIGHT)))) 71 | 72 | self.setMaximumHeight(self.geometry().height()) 73 | self.setMaximumWidth(self.geometry().width()) 74 | 75 | gui.separator(self.controlArea) 76 | 77 | button_box = oasysgui.widgetBox(self.controlArea, "", addSpace=False, orientation="horizontal") 78 | 79 | button = gui.button(button_box, self, "Read Surface", callback=self.read_surface) 80 | button.setFixedHeight(45) 81 | 82 | button = gui.button(button_box, self, "Render Surface", callback=self.render_surface) 83 | button.setFixedHeight(45) 84 | 85 | input_box_l = oasysgui.widgetBox(self.controlArea, "Input", addSpace=True, orientation="vertical", height=self.TABS_AREA_HEIGHT) 86 | 87 | box = oasysgui.widgetBox(input_box_l, "", addSpace=False, orientation="horizontal") 88 | 89 | self.le_surface_file_name = oasysgui.lineEdit(box, self, "surface_file_name", "Surface File Name", 90 | labelWidth=120, valueType=str, orientation="horizontal") 91 | 92 | gui.button(box, self, "...", callback=self.selectSurfaceFile) 93 | 94 | gui.comboBox(input_box_l, self, "negate", label="Invert Surface", labelWidth=350, 95 | items=["No", "Yes"], sendSelectedValue=False, orientation="horizontal") 96 | 97 | self.figure = Figure(figsize=(600, 600)) 98 | self.figure.patch.set_facecolor('white') 99 | 100 | self.axis = self.figure.add_subplot(111, projection='3d') 101 | 102 | self.axis.set_zlabel("Z [m]") 103 | 104 | self.figure_canvas = FigureCanvas3D(ax=self.axis, fig=self.figure) 105 | 106 | self.mainArea.layout().addWidget(self.figure_canvas) 107 | 108 | gui.rubber(self.mainArea) 109 | 110 | def read_surface(self): 111 | try: 112 | self.surface_file_name = congruence.checkDir(self.surface_file_name) 113 | 114 | xx, yy, zz = OU.read_surface_file(self.surface_file_name) 115 | zz = zz if self.negate==0 else -1.0*zz 116 | 117 | self.xx = xx 118 | self.yy = yy 119 | self.zz = zz 120 | 121 | self.send("Surface Data", OasysSurfaceData(xx=self.xx, yy=self.yy, zz=self.zz, surface_data_file=self.surface_file_name)) 122 | except Exception as exception: 123 | QMessageBox.critical(self, "Error", 124 | exception.args[0], 125 | QMessageBox.Ok) 126 | 127 | if self.IS_DEVELOP: raise exception 128 | 129 | def render_surface(self): 130 | try: 131 | self.surface_file_name = congruence.checkDir(self.surface_file_name) 132 | 133 | xx, yy, zz = OU.read_surface_file(self.surface_file_name) 134 | zz = zz if self.negate==0 else -1.0*zz 135 | 136 | self.xx = xx 137 | self.yy = yy 138 | self.zz = zz 139 | 140 | self.axis.clear() 141 | 142 | x_to_plot, y_to_plot = numpy.meshgrid(self.xx, self.yy) 143 | 144 | self.axis.plot_surface(x_to_plot, y_to_plot, zz, 145 | rstride=1, cstride=1, cmap=cm.autumn, linewidth=0.5, antialiased=True) 146 | 147 | self.axis.set_xlabel("X [m]") 148 | self.axis.set_ylabel("Y [m]") 149 | self.axis.set_zlabel("Z [m]") 150 | self.axis.mouse_init() 151 | 152 | self.figure_canvas.draw() 153 | 154 | self.send("Surface Data", OasysSurfaceData(xx=self.xx, yy=self.yy, zz=self.zz, surface_data_file=self.surface_file_name)) 155 | 156 | except Exception as exception: 157 | QMessageBox.critical(self, "Error", 158 | exception.args[0], 159 | QMessageBox.Ok) 160 | 161 | if self.IS_DEVELOP: raise exception 162 | 163 | def selectSurfaceFile(self): 164 | self.le_surface_file_name.setText(oasysgui.selectFileFromDialog(self, self.surface_file_name, "Select Input File", file_extension_filter="HDF5 Files (*.hdf5 *.h5 *.hdf)")) 165 | 166 | 167 | -------------------------------------------------------------------------------- /scripts/macos/build-macos-app.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | echo 3 | set -e 4 | 5 | usage() { 6 | echo 'usage: build-macos-app.sh [--python-version VER] [--pip-arg ARG] APPPATH 7 | Create (build) an macOS application bundle 8 | 9 | Options: 10 | --python-version VERSION 11 | Python version to install in the application bundle (default: 3.7.5) 12 | 13 | --pip-arg ARG 14 | Pip install arguments to populate the python environemnt in the 15 | application bundle. Can be used multiple times. 16 | If not supplied then by default the latest PyPi published Orange3 is 17 | used. 18 | 19 | -h|--help 20 | Print this help 21 | 22 | Examples 23 | build-macos-app.sh ~/Applications/Oasys1.2.app 24 | Build the application using the latest published version on pypi 25 | 26 | build-macos-app.sh --pip-arg={Oasys1.2==3.3.12,PyQt5} ~/Applications/Oasys1.2.app 27 | Build the application using the specified Orange version 28 | 29 | build-macos-app.sh --pip-arg=path-tolocal-checkout ~/Applications/Oasys1.2-Dev.app 30 | Build the application using a local source checkout 31 | 32 | build-macos-app.sh --pip-arg={-e,path-tolocal-checkout} ~/Applications/Oasys1.2-Dev.app 33 | Build the application and install orange in editable mode 34 | 35 | buils-macos-app.sh --pip-arg={-r,requirements.txt} /Applications/Oasys1.2.app 36 | Build the application using a fixed set of locked requirements. 37 | ' 38 | } 39 | 40 | DIR=$(dirname "$0") 41 | 42 | # Python version in the bundled framework 43 | PYTHON_VERSION=3.8.10 44 | 45 | # Pip arguments used to populate the python environment in the application 46 | # bundle 47 | PIP_REQ_ARGS=( ) 48 | 49 | while [[ "${1:0:1}" == "-" ]]; do 50 | case "${1}" in 51 | --python-version=*) 52 | PYTHON_VERSION=${1#*=} 53 | shift 1;; 54 | --python-version) 55 | PYTHON_VERSION=${2:?"--python-version requires an argument"} 56 | shift 2;; 57 | --pip-arg=*) 58 | PIP_REQ_ARGS+=( "${1#*=}" ) 59 | shift 1;; 60 | --pip-arg) 61 | PIP_REQ_ARGS+=( "${2:?"--pip-arg requires an argument"}" ) 62 | shift 2;; 63 | --help|-h) 64 | usage; exit 0;; 65 | -*) 66 | echo "Invalid argument ${1}" >&2; usage >&2; exit 1;; 67 | esac 68 | done 69 | 70 | APPDIR=${1:?"Target APPDIR argument is missing"} 71 | 72 | PYVER=${PYTHON_VERSION%.*} # Major.Minor 73 | 74 | if [[ ${#PIP_REQ_ARGS[@]} -eq 0 ]]; then 75 | PIP_REQ_ARGS+=('numpy~=1.23.2' 'fabio==0.14.0' 'PyQt5==5.15.2' 'PyQtWebEngine~=5.15' 'xraylib~=4.1.2' 'oasys1') 76 | fi 77 | 78 | mkdir -p "${APPDIR}"/Contents/MacOS 79 | mkdir -p "${APPDIR}"/Contents/Frameworks 80 | mkdir -p "${APPDIR}"/Contents/Resources 81 | 82 | cp -R ./lib "${APPDIR}"/Contents/Frameworks 83 | 84 | cp -a "${DIR}"/skeleton.app/Contents/{Resources,Info.plist.in} \ 85 | "${APPDIR}"/Contents 86 | 87 | # Layout a 'relocatable' python framework in the app directory 88 | "${DIR}"/python-framework.sh \ 89 | --version "${PYTHON_VERSION}" \ 90 | --macos 10.9 \ 91 | --install-certifi \ 92 | "${APPDIR}"/Contents/Frameworks 93 | 94 | ln -fs ../Frameworks/Python.framework/Versions/${PYVER}/Resources/Python.app/Contents/MacOS/Python \ 95 | "${APPDIR}"/Contents/MacOS/PythonApp 96 | 97 | ln -fs ../Frameworks/Python.framework/Versions/${PYVER}/bin/python${PYVER} \ 98 | "${APPDIR}"/Contents/MacOS/python 99 | 100 | "${APPDIR}"/Contents/MacOS/python -m ensurepip 101 | "${APPDIR}"/Contents/MacOS/python -m pip install pip~=22.2.0 wheel 102 | 103 | 104 | cat <<'EOF' > "${APPDIR}"/Contents/MacOS/ENV 105 | 106 | # Create an environment for running python from the bundle 107 | # Should be run as "source ENV" 108 | 109 | BUNDLE_DIR=`dirname "$0"`/../ 110 | BUNDLE_DIR=`perl -MCwd=realpath -e 'print realpath($ARGV[0])' "$BUNDLE_DIR"`/ 111 | FRAMEWORKS_DIR="$BUNDLE_DIR"Frameworks/ 112 | RESOURCES_DIR="$BUNDLE_DIR"Resources/ 113 | 114 | PYVERSION="3.8" 115 | PYTHONEXECUTABLE="$FRAMEWORKS_DIR"Python.framework/Resources/Python.app/Contents/MacOS/Python 116 | PYTHONHOME="$FRAMEWORKS_DIR"Python.framework/Versions/"$PYVERSION"/ 117 | DYLD_FRAMEWORK_PATH="$FRAMEWORKS_DIR"${DYLD_FRAMEWORK_PATH:+:$DYLD_FRAMEWORK_PATH} 118 | 119 | export PYTHONNOUSERSITE=1 120 | 121 | # Some non framework libraries are put in $FRAMEWORKS_DIR by machlib standalone 122 | base_ver=11.0 123 | ver=$(sw_vers | grep ProductVersion | cut -d':' -f2 | tr -d ' ') 124 | if [ $(echo -e $base_ver"\n"$ver | sort -V | tail -1) == "$base_ver" ] 125 | then 126 | export DYLD_LIBRARY_PATH="$FRAMEWORKS_DIR"${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}lib/os10 127 | else 128 | export DYLD_LIBRARY_PATH="$FRAMEWORKS_DIR"${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}lib/os11 129 | fi 130 | EOF 131 | 132 | cat <<'EOF' > "${APPDIR}"/Contents/MacOS/Oasys1 133 | #!/bin/bash 134 | 135 | DIR=$(dirname "$0") 136 | source "$DIR"/ENV 137 | 138 | # LaunchServices passes the Carbon process identifier to the application with 139 | # -psn parameter - we do not want it 140 | if [[ "${1}" == -psn_* ]]; then 141 | shift 1 142 | fi 143 | 144 | # Disable user site packages 145 | export PYTHONNOUSERSITE=1 146 | 147 | exec "${DIR}"/PythonApp -m oasys.canvas --force-discovery "$@" 148 | EOF 149 | chmod +x "${APPDIR}"/Contents/MacOS/Oasys1 150 | 151 | cat <<'EOF' > "${APPDIR}"/Contents/MacOS/pip 152 | #!/bin/bash 153 | 154 | DIR=$(dirname "$0") 155 | 156 | # Disable user site packages 157 | export PYTHONNOUSERSITE=1 158 | 159 | exec -a "$0" "${DIR}"/python -m pip "$@" 160 | EOF 161 | chmod +x "${APPDIR}"/Contents/MacOS/pip 162 | 163 | PYTHON="${APPDIR}"/Contents/MacOS/python 164 | 165 | "${PYTHON}" -m pip install --no-warn-script-location "${PIP_REQ_ARGS[@]}" 166 | 167 | VERSION=$("${PYTHON}" -m pip show oasys1 | grep -E '^Version:' | 168 | cut -d " " -f 2) 169 | 170 | m4 -D__VERSION__="${VERSION:?}" "${APPDIR}"/Contents/Info.plist.in \ 171 | > "${APPDIR}"/Contents/Info.plist 172 | rm "${APPDIR}"/Contents/Info.plist.in 173 | 174 | # Sanity check 175 | ( 176 | # run from an empty dir to avoid importing/finding any packages on ./ 177 | tempdir=$(mktemp -d) 178 | cleanup() { rm -r "${tempdir}"; } 179 | trap cleanup EXIT 180 | cd "${tempdir}" 181 | "${PYTHON}" -m pip install --no-cache-dir --no-index oasys1 PyQt5==5.15.2 182 | "${PYTHON}" -m oasys.canvas --help > /dev/null 183 | ) 184 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | 3 | from importlib.machinery import SourceFileLoader 4 | import os 5 | import subprocess 6 | import platform 7 | 8 | from setuptools import setup 9 | 10 | NAME = 'OASYS1' 11 | 12 | VERSION = '1.2.150' 13 | 14 | ISRELEASED = True 15 | 16 | DESCRIPTION = 'OrAnge SYnchrotron Suite' 17 | README_FILE = os.path.join(os.path.dirname(__file__), 'README.md') 18 | LONG_DESCRIPTION = open(README_FILE).read() 19 | AUTHOR = 'Luca Rebuffi, Manuel Sanchez del Rio and Bioinformatics Laboratory, FRI UL' 20 | AUTHOR_EMAIL = 'lrebuffi@anl.gov' 21 | URL = 'https://github.com/oasys-kit/OASYS1' 22 | DOWNLOAD_URL = 'https://github.com/oasys-kit/OASYS1' 23 | MAINTAINER = 'Luca Rebuffi, Argonne National Lab, USA' 24 | MAINTAINER_EMAIL = 'lrebuffi@anl.gov' 25 | LICENSE = 'GPLv3' 26 | 27 | KEYWORDS = ( 28 | 'ray tracing', 29 | 'simulation', 30 | ) 31 | 32 | CLASSIFIERS = ( 33 | 'Development Status :: 5 - Production/Stable', 34 | 'Environment :: X11 Applications :: Qt', 35 | 'Environment :: Console', 36 | 'Environment :: Plugins', 37 | 'Programming Language :: Python :: 3', 38 | 'License :: OSI Approved :: ' 39 | 'GNU General Public License v3 or later (GPLv3+)', 40 | 'Operating System :: POSIX', 41 | 'Operating System :: Microsoft :: Windows', 42 | 'Topic :: Scientific/Engineering :: Visualization', 43 | 'Topic :: Software Development :: Libraries :: Python Modules', 44 | 'Intended Audience :: Education', 45 | 'Intended Audience :: Science/Research', 46 | 'Intended Audience :: Developers', 47 | ) 48 | 49 | INSTALL_REQUIRES = ( 50 | 'setuptools', 51 | 'requests', 52 | "importlib_resources", 53 | "importlib_metadata", 54 | 'numpy<1.23,>=1.21', 55 | 'fabio==0.11.0', 56 | 'PyQt5==5.15.2', 57 | 'scipy<=1.9.1,>=1.7.3', 58 | 'matplotlib<=3.5.3,>=3.3.2', 59 | 'oasys-canvas-core>=1.0.9', 60 | 'oasys-widget-core>=1.0.5', 61 | 'silx==0.15.0', 62 | 'hdf5plugin', 63 | 'srxraylib>=1.0.28', 64 | 'syned>=1.0.28', 65 | 'wofry>=1.0.31', 66 | ) 67 | 68 | 69 | try: 70 | system, node, release, version, machine, processor = platform.uname() 71 | if "Debian 3" in version: 72 | l1 = list(INSTALL_REQUIRES) 73 | for i,element in enumerate(l1): 74 | if "PyQt5" in element: 75 | l1[i] = "PyQt5==5.11.3" 76 | INSTALL_REQUIRES = tuple(l1) 77 | except: 78 | pass 79 | 80 | 81 | SETUP_REQUIRES = ( 82 | 'setuptools', 83 | ) 84 | 85 | # Return the git revision as a string 86 | def git_version(): 87 | """Return the git revision as a string. 88 | 89 | Copied from numpy setup.py 90 | """ 91 | def _minimal_ext_cmd(cmd): 92 | # construct minimal environment 93 | env = {} 94 | for k in ['SYSTEMROOT', 'PATH']: 95 | ver = os.environ.get(k) 96 | if ver is not None: 97 | env[k] = ver 98 | # LANGUAGE is used on win32 99 | env['LANGUAGE'] = 'C' 100 | env['LANG'] = 'C' 101 | env['LC_ALL'] = 'C' 102 | out = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=env).communicate()[0] 103 | return out 104 | 105 | try: 106 | out = _minimal_ext_cmd(['git', 'rev-parse', 'HEAD']) 107 | git_revision = out.strip().decode('ascii') 108 | except OSError: 109 | git_revision = "Unknown" 110 | 111 | return git_revision 112 | 113 | 114 | def write_version_py(filename='oasys/version.py'): 115 | # Copied from numpy setup.py 116 | cnt = """ 117 | # THIS FILE IS GENERATED FROM OASYS SETUP.PY 118 | short_version = '%(version)s' 119 | version = '%(version)s' 120 | full_version = '%(full_version)s' 121 | git_revision = '%(git_revision)s' 122 | release = %(isrelease)s 123 | 124 | if not release: 125 | version = full_version 126 | short_version += ".dev" 127 | """ 128 | full_version = VERSION 129 | if os.path.exists('.git'): 130 | git_revision = git_version() 131 | elif os.path.exists('oasys/version.py'): 132 | # must be a source distribution, use existing version file 133 | version = SourceFileLoader('oasys.version', 'oasys/version.py').load_module() 134 | git_revision = version.git_revision 135 | else: 136 | git_revision = "Unknown" 137 | 138 | if not ISRELEASED: 139 | full_version += '.dev0+' + git_revision[:7] 140 | 141 | with open(filename, 'w') as file: 142 | file.write(cnt % {'version': VERSION, 143 | 'full_version': full_version, 144 | 'git_revision': git_revision, 145 | 'isrelease': str(ISRELEASED)}) 146 | 147 | PACKAGES = ( 148 | "oasys", 149 | "oasys.canvas", 150 | "oasys.canvas.styles", 151 | "oasys.menus", 152 | "oasys.widgets", 153 | "oasys.widgets.tools", 154 | "oasys.widgets.loop_management", 155 | ) 156 | 157 | PACKAGE_DATA = { 158 | "oasys.application": ["data/*.txt"], 159 | "oasys.canvas": ["icons/*.png", "icons/*.svg"], 160 | "oasys.canvas.styles": ["*.qss", "orange/*.svg"], 161 | "oasys.widgets.tools": ["icons/*.png", "icons/*.svg", "misc/*.png"], 162 | "oasys.widgets.loop_management": ["icons/*.png", "icons/*.svg"], 163 | "oasys.widgets.scanning": ["icons/*.png", "icons/*.svg"], 164 | } 165 | 166 | ENTRY_POINTS = { 167 | 'oasys.widgets' : ( 168 | "Oasys Tools = oasys.widgets.tools", 169 | "Oasys Basic Loops = oasys.widgets.loop_management", 170 | "Oasys Scanning Loops = oasys.widgets.scanning", 171 | ) 172 | } 173 | 174 | def setup_package(): 175 | write_version_py() 176 | setup( 177 | name=NAME, 178 | version=VERSION, 179 | description=DESCRIPTION, 180 | long_description=LONG_DESCRIPTION, 181 | author=AUTHOR, 182 | author_email=AUTHOR_EMAIL, 183 | maintainer=MAINTAINER, 184 | maintainer_email=MAINTAINER_EMAIL, 185 | url=URL, 186 | download_url=DOWNLOAD_URL, 187 | license=LICENSE, 188 | keywords=KEYWORDS, 189 | classifiers=CLASSIFIERS, 190 | packages=PACKAGES, 191 | package_data=PACKAGE_DATA, 192 | entry_points=ENTRY_POINTS, 193 | # extra setuptools args 194 | zip_safe=False, # the package can run out of an .egg file 195 | include_package_data=True, 196 | install_requires=INSTALL_REQUIRES, 197 | setup_requires=SETUP_REQUIRES, 198 | ) 199 | 200 | if __name__ == '__main__': 201 | setup_package() 202 | -------------------------------------------------------------------------------- /oasys/widgets/abstract/scanning/abstract_scan_file_node_point.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # ######################################################################### 4 | # Copyright (c) 2020, UChicago Argonne, LLC. All rights reserved. # 5 | # # 6 | # Copyright 2020. UChicago Argonne, LLC. This software was produced # 7 | # under U.S. Government contract DE-AC02-06CH11357 for Argonne National # 8 | # Laboratory (ANL), which is operated by UChicago Argonne, LLC for the # 9 | # U.S. Department of Energy. The U.S. Government has rights to use, # 10 | # reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR # 11 | # UChicago Argonne, LLC MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR # 12 | # ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE. If software is # 13 | # modified to produce derivative works, such modified software should # 14 | # be clearly marked, so as not to confuse it with the version available # 15 | # from ANL. # 16 | # # 17 | # Additionally, redistribution and use in source and binary forms, with # 18 | # or without modification, are permitted provided that the following # 19 | # conditions are met: # 20 | # # 21 | # * Redistributions of source code must retain the above copyright # 22 | # notice, this list of conditions and the following disclaimer. # 23 | # # 24 | # * Redistributions in binary form must reproduce the above copyright # 25 | # notice, this list of conditions and the following disclaimer in # 26 | # the documentation and/or other materials provided with the # 27 | # distribution. # 28 | # # 29 | # * Neither the name of UChicago Argonne, LLC, Argonne National # 30 | # Laboratory, ANL, the U.S. Government, nor the names of its # 31 | # contributors may be used to endorse or promote products derived # 32 | # from this software without specific prior written permission. # 33 | # # 34 | # THIS SOFTWARE IS PROVIDED BY UChicago Argonne, LLC AND CONTRIBUTORS # 35 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # 36 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # 37 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UChicago # 38 | # Argonne, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # 39 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # 40 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # 41 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # 42 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # 43 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # 44 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # 45 | # POSSIBILITY OF SUCH DAMAGE. # 46 | # ######################################################################### 47 | 48 | from PyQt5.QtWidgets import QFileDialog 49 | 50 | from orangewidget import gui 51 | from orangewidget.settings import Setting 52 | 53 | from oasys.widgets import gui as oasysgui 54 | 55 | from oasys.widgets.abstract.scanning.abstract_scan_node_point import AbstractScanLoopPoint 56 | 57 | from oasys.util.oasys_util import TriggerIn 58 | 59 | class AbstractScanFileLoopPoint(AbstractScanLoopPoint): 60 | inputs = [("Trigger", TriggerIn, "passTrigger"), 61 | ("Files", list, "setFiles")] 62 | 63 | files_area = None 64 | variable_files = Setting([""]) 65 | 66 | def create_specific_loop_box(self, box): 67 | box_files = oasysgui.widgetBox(box, "", addSpace=False, orientation="vertical", height=270) 68 | 69 | gui.button(box_files, self, "Select Height Error Profile Data Files", callback=self.select_files) 70 | 71 | self.files_area = oasysgui.textArea(height=200, width=360) 72 | 73 | self.refresh_files_text_area() 74 | 75 | box_files.layout().addWidget(self.files_area) 76 | 77 | gui.separator(box) 78 | 79 | def select_files(self): 80 | files, _ = QFileDialog.getOpenFileNames(self, 81 | "Select Height Error Profiles", "", "Data Files (*.dat)", 82 | options=QFileDialog.Options()) 83 | if files: 84 | self.variable_files = files 85 | 86 | self.refresh_files_text_area() 87 | 88 | def setFiles(self, files_data): 89 | if not files_data is None: 90 | if isinstance(files_data, str): 91 | self.variable_files.append(files_data) 92 | elif isinstance(files_data, list): 93 | self.variable_files = files_data 94 | else: 95 | raise ValueError("Error Profile Data File: format not recognized") 96 | 97 | self.refresh_files_text_area() 98 | 99 | def refresh_files_text_area(self): 100 | text = "" 101 | for file in self.variable_files: 102 | text += file + "\n" 103 | self.files_area.setText(text) 104 | 105 | self.number_of_new_objects = len(self.variable_files) 106 | 107 | def has_variable_um(self): return False 108 | 109 | def get_current_value_type(self): return str 110 | 111 | def initialize_start_loop(self): 112 | self.current_variable_value = self.variable_files[0] 113 | self.number_of_new_objects = len(self.variable_files) 114 | 115 | self.start_button.setEnabled(False) 116 | 117 | return True 118 | 119 | def keep_looping(self): 120 | if self.current_new_object < self.number_of_new_objects: 121 | if self.current_variable_value is None: self.current_new_object = 1 122 | else: self.current_new_object += 1 123 | 124 | self.current_variable_value = self.variable_files[self.current_new_object - 1] 125 | 126 | return True 127 | else: 128 | return False 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /oasys/canvas/widgetsscheme.py: -------------------------------------------------------------------------------- 1 | """ 2 | OASYS Widgets Scheme 3 | ==================== 4 | 5 | A Scheme for OASYS Orange Widgets Scheme. 6 | 7 | .. autoclass:: OASYSWidgetsScheme 8 | :bases: 9 | 10 | .. autoclass:: OASYSWidgetsSignalManager 11 | :bases: 12 | 13 | """ 14 | import os 15 | import sys 16 | import logging 17 | 18 | import sip 19 | 20 | from PyQt5.QtCore import QSettings 21 | from PyQt5.QtCore import pyqtSignal as Signal, pyqtProperty as Property 22 | 23 | from orangecanvas.scheme import Scheme, readwrite 24 | 25 | from orangewidget.canvas.workflow import ( 26 | WidgetsScheme, WidgetManager, WidgetsSignalManager 27 | ) 28 | 29 | log = logging.getLogger(__name__) 30 | 31 | 32 | def check_working_directory(working_directory): 33 | if sys.platform == "win32": return working_directory.replace("/", "\\") # weird bug since 12/2023 34 | else: return working_directory.replace("\\", "/") 35 | 36 | class OASYSWidgetsScheme(WidgetsScheme): 37 | #: Signal emitted when the working directory changes. 38 | working_directory_changed = Signal(str) 39 | workspace_units_changed = Signal(int) 40 | 41 | def __init__(self, parent=None, title=None, description=None, working_directory=None, workspace_units=None): 42 | self.__canvas_main_window = parent 43 | 44 | settings = QSettings() 45 | 46 | self.__working_directory = (working_directory or settings.value("output/default-working-directory", os.path.expanduser("~/Oasys"), type=str)) 47 | self.__working_directory = check_working_directory(self.__working_directory) 48 | if not os.path.exists(self.__working_directory): os.makedirs(self.__working_directory, exist_ok=True) 49 | 50 | self.__workspace_units = (workspace_units or settings.value("output/default-units", 1, type=int)) 51 | 52 | super().__init__(parent, title=title, description=description) 53 | 54 | # Replace the signal manager from. 55 | self.signal_manager.setParent(None) 56 | self.signal_manager.deleteLater() 57 | sip.delete(self.signal_manager) 58 | sip.delete(self.widget_manager) 59 | 60 | self.set_loop_flags(Scheme.AllowLoops) 61 | self.signal_manager = OASYSSignalManager(self) 62 | self.widget_manager = OASYSWidgetManager() 63 | self.widget_manager.set_scheme(self) 64 | 65 | def set_working_directory(self, working_directory): 66 | """ 67 | Set the scheme working_directory. 68 | """ 69 | working_directory = check_working_directory(working_directory) 70 | 71 | if self.__working_directory != working_directory: 72 | self.__working_directory = working_directory 73 | self.working_directory_changed.emit(working_directory) 74 | 75 | def working_directory(self): 76 | """ 77 | The working_directory of the scheme. 78 | """ 79 | return self.__working_directory 80 | 81 | def set_workspace_units(self, units): 82 | """ 83 | Set the scheme units. 84 | """ 85 | if self.__workspace_units != units: 86 | self.__workspace_units = units 87 | self.workspace_units_changed.emit(units) 88 | 89 | def workspace_units(self): 90 | """ 91 | The units of the scheme. 92 | """ 93 | return self.__workspace_units 94 | 95 | def canvas_main_window(self): 96 | return self.__canvas_main_window 97 | 98 | working_directory = Property(str, 99 | fget=working_directory, 100 | fset=set_working_directory) 101 | 102 | workspace_units = Property(str, 103 | fget=workspace_units, 104 | fset=set_workspace_units) 105 | 106 | canvas_main_window = Property(object, 107 | fget=canvas_main_window) 108 | 109 | 110 | def save_to(self, stream, pretty=True, pickle_fallback=False): 111 | """ 112 | Reimplemented from Scheme.save_to. 113 | """ 114 | if isinstance(stream, str): 115 | stream = open(stream, "wb") 116 | 117 | self.sync_node_properties() 118 | 119 | tree = readwrite.scheme_to_etree(self, pickle_fallback=pickle_fallback) 120 | root = tree.getroot() 121 | root.set("working_directory", self.working_directory or "") 122 | root.set("workspace_units", str(self.workspace_units) or "") 123 | 124 | if pretty: readwrite.indent(tree.getroot(), 0) 125 | 126 | if sys.version_info < (2, 7): 127 | # in Python 2.6 the write does not have xml_declaration parameter. 128 | tree.write(stream, encoding="utf-8") 129 | else: 130 | tree.write(stream, encoding="utf-8", xml_declaration=True) 131 | 132 | 133 | class OASYSWidgetManager(WidgetManager): 134 | def set_scheme(self, scheme): 135 | super().set_scheme(scheme) 136 | scheme.working_directory_changed.connect(self.__working_directory_changed) 137 | scheme.workspace_units_changed.connect(self.__workspace_units_changed) 138 | 139 | def create_widget_instance(self, node): 140 | """ 141 | Reimplemented from WidgetManager.create_widget_instance 142 | """ 143 | widget = super().create_widget_instance(node) 144 | if hasattr(widget, "setWorkingDirectory"): widget.setWorkingDirectory(self.scheme().working_directory) 145 | if hasattr(widget, "setWorkspaceUnits"): widget.setWorkspaceUnits(self.scheme().workspace_units) 146 | if hasattr(widget, "setCanvasMainWindow"): widget.setCanvasMainWindow(self.scheme().canvas_main_window) 147 | if hasattr(widget, "createdFromNode"): widget.createdFromNode(node) 148 | 149 | return widget 150 | 151 | def __working_directory_changed(self, workdir): 152 | for node in self.scheme().nodes: 153 | w = self.widget_for_node(node) 154 | if hasattr(w, "setWorkingDirectory"): 155 | w.setWorkingDirectory(workdir) 156 | 157 | def __workspace_units_changed(self, units): 158 | for node in self.scheme().nodes: 159 | w = self.widget_for_node(node) 160 | if hasattr(w, "setWorkspaceUnits"): 161 | w.setWorkspaceUnits(units) 162 | 163 | class OASYSSignalManager(WidgetsSignalManager): 164 | def pending_nodes(self): 165 | """ 166 | Reimplemented from SignalManager.pending_nodes. 167 | 168 | Enforce some custom ordering semantics in workflow cycles. 169 | """ 170 | 171 | pending = super().pending_nodes() 172 | 173 | pending_new = [node for node in pending 174 | if not getattr(self.scheme().widget_for_node(node), 175 | "process_last", False)] 176 | 177 | if pending_new: 178 | pending = pending_new 179 | 180 | return pending 181 | -------------------------------------------------------------------------------- /oasys/widgets/widget.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from PyQt5.QtWidgets import QScrollArea 4 | from PyQt5.QtCore import Qt 5 | from PyQt5.Qt import QIcon 6 | 7 | from orangewidget import widget 8 | 9 | def layout_insert(layout, widget, before): 10 | for i in range(layout.count()): 11 | item = layout.itemAt(i) 12 | if item.widget() is before: 13 | break 14 | else: 15 | raise ValueError("{} is not in layout".format(widget)) 16 | layout.insertWidget(i, widget, ) 17 | 18 | class OWWidget(widget.OWWidget): 19 | 20 | IS_DEVELOP = False if not "OASYSDEVELOP" in os.environ.keys() else str(os.environ.get('OASYSDEVELOP')) == "1" 21 | 22 | def __init__(self): 23 | super().__init__() 24 | 25 | self.setWindowFlags(Qt.WindowMinimizeButtonHint | Qt.WindowCloseButtonHint) 26 | 27 | def getScene(self): 28 | return self.canvas_main_window.current_document().scene() 29 | 30 | def getNode(self): 31 | if self._node is None: self._node = self.getScene().node_for_item(self._node_item) 32 | return self._node 33 | 34 | def getNodeItem(self): 35 | if self._node_item is None: self._node_item = self.getScene().item_for_node(self._node) 36 | return self._node_item 37 | 38 | def changeNodeIcon(self, icon): 39 | node_item = self.getNodeItem() 40 | if not node_item is None: 41 | node_item.icon_item.hide() 42 | if isinstance(icon, QIcon): node_item.setIcon(icon) 43 | else: node_item.setIcon(QIcon(icon)) 44 | node_item.update() 45 | 46 | def changeNodeTitle(self, title): 47 | node_item = self.getNodeItem() 48 | if not node_item is None: 49 | node_item.setTitle(title) 50 | node_item.update() 51 | 52 | def insertLayout(self): 53 | """ 54 | Reimplemented from OWWidget.insertLayout. 55 | 56 | Pull the OWWidget created controlArea and mainArea widgets into 57 | QScrollArea's. 58 | 59 | """ 60 | super().insertLayout() 61 | 62 | self.setStyleSheet("background-color: #EBEBEB;") 63 | 64 | cls = type(self) 65 | 66 | if cls.want_basic_layout and cls.want_control_area: 67 | layout = self.leftWidgetPart.layout() 68 | area = QScrollArea() 69 | layout_insert(layout, area, before=self.controlArea) 70 | layout.takeAt(layout.indexOf(self.controlArea)) 71 | area.setWidget(self.controlArea) 72 | area.setWidgetResizable(True) 73 | 74 | if cls.want_basic_layout and cls.want_main_area: 75 | layout = self.topWidgetPart.layout() 76 | area = QScrollArea() 77 | layout_insert(layout, area, before=self.mainArea) 78 | layout.takeAt(layout.indexOf(self.mainArea)) 79 | area.setWidget(self.mainArea) 80 | area.setWidgetResizable(True) 81 | 82 | def setCanvasMainWindow(self, canvas_main_window): 83 | self.canvas_main_window = canvas_main_window 84 | 85 | def setWorkingDirectory(self, directory): 86 | self.working_directory = directory 87 | 88 | self.after_change_working_directory() 89 | 90 | def setWorkspaceUnits(self, units): 91 | self.workspace_units = units 92 | 93 | if self.workspace_units == 0: 94 | self.workspace_units_label = "m" 95 | self.workspace_units_to_m = 1.0 96 | self.workspace_units_to_cm = 100.0 97 | self.workspace_units_to_mm = 1000.0 98 | 99 | elif self.workspace_units == 1: 100 | self.workspace_units_label = "cm" 101 | self.workspace_units_to_m = 0.01 102 | self.workspace_units_to_cm = 1.0 103 | self.workspace_units_to_mm = 10.0 104 | 105 | elif self.workspace_units == 2: 106 | self.workspace_units_label = "mm" 107 | self.workspace_units_to_m = 0.001 108 | self.workspace_units_to_cm = 0.1 109 | self.workspace_units_to_mm = 1.0 110 | 111 | self.after_change_workspace_units() 112 | 113 | def after_change_working_directory(self): 114 | pass 115 | 116 | def after_change_workspace_units(self): 117 | pass 118 | 119 | def __setattr__(self, name, value): 120 | super().__setattr__(name, value) 121 | 122 | for shower in getattr(self, "showers", []): 123 | if name in shower.expression: 124 | shower() 125 | 126 | def show_at(self, expression, what): 127 | class ShowerClass: 128 | def __init__(shower): 129 | shower.what = what 130 | shower.expression = expression 131 | 132 | def __call__(shower): 133 | x = self # to force self into the closure, because we need it in the expression 134 | to_show = eval(expression) 135 | if shower.what.isHidden() == to_show: 136 | if to_show: 137 | shower.what.show() 138 | else: 139 | shower.what.hide() 140 | 141 | shower = ShowerClass() 142 | if not hasattr(self, "showers"): 143 | self.showers = [] 144 | self.showers.append(shower) 145 | 146 | def process_showers(self): 147 | for shower in getattr(self, "showers", []): 148 | shower() 149 | 150 | 151 | # Pull signal definition constants to oasys widget namespace. 152 | Default = widget.Default 153 | NonDefault = widget.NonDefault 154 | Single = widget.Single 155 | Multiple = widget.Multiple 156 | Explicit = widget.Explicit 157 | Dynamic = widget.Dynamic 158 | 159 | InputSignal = widget.InputSignal 160 | OutputSignal = widget.OutputSignal 161 | 162 | from orangewidget import gui 163 | from orangewidget.settings import Setting 164 | 165 | from PyQt5.QtWidgets import QApplication 166 | from PyQt5.QtCore import QRect 167 | 168 | class AutomaticWidget(OWWidget): 169 | 170 | is_automatic_execution = Setting(True) 171 | 172 | CONTROL_AREA_WIDTH = 405 173 | 174 | MAX_WIDTH = 1320 175 | MAX_HEIGHT = 700 176 | 177 | def __init__(self, is_automatic=True): 178 | super().__init__() 179 | 180 | geom = QApplication.desktop().availableGeometry() 181 | self.setGeometry(QRect(round(geom.width()*0.05), 182 | round(geom.height()*0.05), 183 | round(min(geom.width()*0.98, self.MAX_WIDTH)), 184 | round(min(geom.height()*0.95, self.MAX_HEIGHT)))) 185 | 186 | self.setMaximumHeight(self.geometry().height()) 187 | self.setMaximumWidth(self.geometry().width()) 188 | 189 | self.controlArea.setFixedWidth(self.CONTROL_AREA_WIDTH) 190 | 191 | if is_automatic: 192 | self.general_options_box = gui.widgetBox(self.controlArea, "General Options", addSpace=True, orientation="horizontal") 193 | 194 | gui.checkBox(self.general_options_box, self, 'is_automatic_execution', 'Automatic Execution') 195 | else: 196 | self.is_automatic_execution=False 197 | -------------------------------------------------------------------------------- /oasys/widgets/loop_management/ow_node_point.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from orangewidget.widget import OWAction 4 | from oasys.widgets import widget 5 | from oasys.widgets import gui as oasysgui 6 | from oasys.widgets.gui import ConfirmDialog 7 | 8 | from orangewidget import gui 9 | from PyQt5.QtGui import QFont, QPalette, QColor 10 | from PyQt5.QtWidgets import QMessageBox 11 | from orangewidget.settings import Setting 12 | 13 | from oasys.util.oasys_util import TriggerIn, TriggerOut 14 | 15 | class LoopPoint(widget.OWWidget): 16 | 17 | name = "Loop Point" 18 | description = "Tools: LoopPoint" 19 | icon = "icons/cycle.png" 20 | maintainer = "Luca Rebuffi" 21 | maintainer_email = "lrebuffi(@at@)anl.gov" 22 | priority = 2 23 | category = "User Defined" 24 | keywords = ["data", "file", "load", "read"] 25 | 26 | inputs = [("Trigger", TriggerIn, "passTrigger")] 27 | 28 | outputs = [{"name":"Trigger", 29 | "type":TriggerOut, 30 | "doc":"Trigger", 31 | "id":"Trigger"}] 32 | want_main_area = 0 33 | 34 | number_of_new_objects = Setting(1) 35 | current_new_object = 0 36 | run_loop = True 37 | suspend_loop = False 38 | 39 | ################################# 40 | process_last = True 41 | ################################# 42 | 43 | def __init__(self): 44 | self.runaction = OWAction("Start", self) 45 | self.runaction.triggered.connect(self.startLoop) 46 | self.addAction(self.runaction) 47 | 48 | self.runaction = OWAction("Stop", self) 49 | self.runaction.triggered.connect(self.stopLoop) 50 | self.addAction(self.runaction) 51 | 52 | self.runaction = OWAction("Suspend", self) 53 | self.runaction.triggered.connect(self.suspendLoop) 54 | self.addAction(self.runaction) 55 | 56 | self.runaction = OWAction("Restart", self) 57 | self.runaction.triggered.connect(self.restartLoop) 58 | self.addAction(self.runaction) 59 | 60 | self.setFixedWidth(400) 61 | self.setFixedHeight(220) 62 | 63 | button_box = oasysgui.widgetBox(self.controlArea, "", addSpace=True, orientation="horizontal") 64 | 65 | self.start_button = gui.button(button_box, self, "Start", callback=self.startLoop) 66 | self.start_button.setFixedHeight(35) 67 | 68 | stop_button = gui.button(button_box, self, "Stop", callback=self.stopLoop) 69 | stop_button.setFixedHeight(35) 70 | font = QFont(stop_button.font()) 71 | font.setBold(True) 72 | stop_button.setFont(font) 73 | palette = QPalette(stop_button.palette()) # make a copy of the palette 74 | palette.setColor(QPalette.ButtonText, QColor('red')) 75 | stop_button.setPalette(palette) # assign new palette 76 | 77 | self.stop_button = stop_button 78 | 79 | button_box = oasysgui.widgetBox(self.controlArea, "", addSpace=True, orientation="horizontal") 80 | 81 | suspend_button = gui.button(button_box, self, "Suspend", callback=self.suspendLoop) 82 | suspend_button.setFixedHeight(35) 83 | font = QFont(suspend_button.font()) 84 | font.setBold(True) 85 | suspend_button.setFont(font) 86 | palette = QPalette(suspend_button.palette()) # make a copy of the palette 87 | palette.setColor(QPalette.ButtonText, QColor('orange')) 88 | suspend_button.setPalette(palette) # assign new palette 89 | 90 | self.re_start_button = gui.button(button_box, self, "Restart", callback=self.restartLoop) 91 | self.re_start_button.setFixedHeight(35) 92 | self.re_start_button.setEnabled(False) 93 | 94 | left_box_1 = oasysgui.widgetBox(self.controlArea, "Loop Management", addSpace=True, orientation="vertical", width=380, height=100) 95 | 96 | oasysgui.lineEdit(left_box_1, self, "number_of_new_objects", "Number of new " + self.get_object_name() + "s", labelWidth=250, valueType=int, orientation="horizontal") 97 | 98 | self.le_current_new_object = oasysgui.lineEdit(left_box_1, self, "current_new_object", "Current New " + self.get_object_name(), labelWidth=250, valueType=int, orientation="horizontal") 99 | self.le_current_new_object.setReadOnly(True) 100 | font = QFont(self.le_current_new_object.font()) 101 | font.setBold(True) 102 | self.le_current_new_object.setFont(font) 103 | palette = QPalette(self.le_current_new_object.palette()) # make a copy of the palette 104 | palette.setColor(QPalette.Text, QColor('dark blue')) 105 | palette.setColor(QPalette.Base, QColor(243, 240, 160)) 106 | self.le_current_new_object.setPalette(palette) 107 | 108 | gui.rubber(self.controlArea) 109 | 110 | def startLoop(self): 111 | self.current_new_object = 1 112 | self.start_button.setEnabled(False) 113 | self.setStatusMessage("Running " + self.get_object_name() + " " + str(self.current_new_object) + " of " + str(self.number_of_new_objects)) 114 | self.send("Trigger", TriggerOut(new_object=True)) 115 | 116 | def stopLoop(self): 117 | if ConfirmDialog.confirmed(parent=self, message="Confirm Interruption of the Loop?"): 118 | self.run_loop = False 119 | self.setStatusMessage("Interrupted by user") 120 | 121 | def suspendLoop(self): 122 | try: 123 | if ConfirmDialog.confirmed(parent=self, message="Confirm Suspension of the Loop?"): 124 | self.run_loop = False 125 | self.suspend_loop = True 126 | self.stop_button.setEnabled(False) 127 | self.re_start_button.setEnabled(True) 128 | self.setStatusMessage("Suspended by user") 129 | except: 130 | pass 131 | 132 | def restartLoop(self): 133 | try: 134 | self.run_loop = True 135 | self.suspend_loop = False 136 | self.stop_button.setEnabled(True) 137 | self.re_start_button.setEnabled(False) 138 | self.passTrigger(TriggerIn(new_object=True)) 139 | except: 140 | pass 141 | 142 | def passTrigger(self, trigger): 143 | if self.run_loop: 144 | if trigger: 145 | if trigger.interrupt: 146 | self.current_new_object = 0 147 | self.start_button.setEnabled(True) 148 | self.setStatusMessage("") 149 | self.send("Trigger", TriggerOut(new_object=False)) 150 | elif trigger.new_object: 151 | if self.current_new_object == 0: 152 | QMessageBox.critical(self, "Error", "Loop has to be started properly: press the button Start", QMessageBox.Ok) 153 | return 154 | 155 | if self.current_new_object < self.number_of_new_objects: 156 | self.current_new_object += 1 157 | self.setStatusMessage("Running " + self.get_object_name() + " " + str(self.current_new_object) + " of " + str(self.number_of_new_objects)) 158 | self.start_button.setEnabled(False) 159 | self.send("Trigger", TriggerOut(new_object=True)) 160 | else: 161 | self.current_new_object = 0 162 | self.start_button.setEnabled(True) 163 | self.setStatusMessage("") 164 | self.send("Trigger", TriggerOut(new_object=False)) 165 | else: 166 | if not self.suspend_loop: 167 | self.current_new_object = 0 168 | self.start_button.setEnabled(True) 169 | 170 | self.send("Trigger", TriggerOut(new_object=False)) 171 | self.setStatusMessage("") 172 | self.run_loop = True 173 | self.suspend_loop = False 174 | 175 | def get_object_name(self): 176 | return "Object" 177 | 178 | from PyQt5.QtWidgets import QApplication 179 | 180 | if __name__ == "__main__": 181 | a = QApplication(sys.argv) 182 | ow = LoopPoint() 183 | ow.show() 184 | a.exec_() 185 | ow.saveSettings() 186 | -------------------------------------------------------------------------------- /oasys/widgets/abstract/scanning/abstract_scan_variable_node_point.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # ######################################################################### 4 | # Copyright (c) 2020, UChicago Argonne, LLC. All rights reserved. # 5 | # # 6 | # Copyright 2020. UChicago Argonne, LLC. This software was produced # 7 | # under U.S. Government contract DE-AC02-06CH11357 for Argonne National # 8 | # Laboratory (ANL), which is operated by UChicago Argonne, LLC for the # 9 | # U.S. Department of Energy. The U.S. Government has rights to use, # 10 | # reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR # 11 | # UChicago Argonne, LLC MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR # 12 | # ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE. If software is # 13 | # modified to produce derivative works, such modified software should # 14 | # be clearly marked, so as not to confuse it with the version available # 15 | # from ANL. # 16 | # # 17 | # Additionally, redistribution and use in source and binary forms, with # 18 | # or without modification, are permitted provided that the following # 19 | # conditions are met: # 20 | # # 21 | # * Redistributions of source code must retain the above copyright # 22 | # notice, this list of conditions and the following disclaimer. # 23 | # # 24 | # * Redistributions in binary form must reproduce the above copyright # 25 | # notice, this list of conditions and the following disclaimer in # 26 | # the documentation and/or other materials provided with the # 27 | # distribution. # 28 | # # 29 | # * Neither the name of UChicago Argonne, LLC, Argonne National # 30 | # Laboratory, ANL, the U.S. Government, nor the names of its # 31 | # contributors may be used to endorse or promote products derived # 32 | # from this software without specific prior written permission. # 33 | # # 34 | # THIS SOFTWARE IS PROVIDED BY UChicago Argonne, LLC AND CONTRIBUTORS # 35 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # 36 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # 37 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UChicago # 38 | # Argonne, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # 39 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # 40 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # 41 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # 42 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # 43 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # 44 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # 45 | # POSSIBILITY OF SUCH DAMAGE. # 46 | # ######################################################################### 47 | 48 | from oasys.widgets import gui as oasysgui 49 | 50 | from orangewidget import gui 51 | from PyQt5.QtGui import QFont, QPalette, QColor 52 | from orangewidget.settings import Setting 53 | 54 | from oasys.widgets.abstract.scanning.abstract_scan_node_point import AbstractScanLoopPoint 55 | 56 | class AbstractScanVariableLoopPoint(AbstractScanLoopPoint): 57 | 58 | variable_value_from = Setting(0.0) 59 | variable_value_to = Setting(0.0) 60 | variable_value_step = Setting(0.0) 61 | 62 | list_of_values = Setting([""]) 63 | kind_of_loop = Setting(0) 64 | 65 | def create_specific_loop_box(self, box): 66 | gui.separator(box) 67 | 68 | gui.comboBox(box, self, "kind_of_loop", label="Kind of Loop", labelWidth=350, 69 | items=["From Range", "From List"], 70 | callback=self.set_KindOfLoop, sendSelectedValue=False, orientation="horizontal") 71 | 72 | self.box_1 = oasysgui.widgetBox(box, "", addSpace=False, orientation="vertical", width=360, height=160) 73 | self.box_2 = oasysgui.widgetBox(box, "", addSpace=False, orientation="vertical", width=360, height=160) 74 | 75 | oasysgui.lineEdit(self.box_1, self, "variable_value_from", "Value From", labelWidth=250, valueType=float, orientation="horizontal", callback=self.calculate_step) 76 | oasysgui.lineEdit(self.box_1, self, "variable_value_to", "Value to", labelWidth=250, valueType=float, orientation="horizontal", callback=self.calculate_step) 77 | oasysgui.lineEdit(self.box_1, self, "number_of_new_objects", "Number of Steps", labelWidth=250, valueType=int, orientation="horizontal", callback=self.calculate_step) 78 | 79 | self.list_of_values_ta = oasysgui.textArea(height=150, width=360, readOnly=False) 80 | self.list_of_values_ta.textChanged.connect(self.list_of_values_ta_changed) 81 | 82 | text = "" 83 | for value in self.list_of_values: 84 | text += value + "\n" 85 | 86 | self.list_of_values_ta.setText(text[:-1]) 87 | self.box_2.layout().addWidget(self.list_of_values_ta) 88 | 89 | self.le_variable_value_step = oasysgui.lineEdit(self.box_1, self, "variable_value_step", "Step Value", labelWidth=250, valueType=float, orientation="horizontal") 90 | self.le_variable_value_step.setReadOnly(True) 91 | font = QFont(self.le_variable_value_step.font()) 92 | font.setBold(True) 93 | self.le_variable_value_step.setFont(font) 94 | palette = QPalette(self.le_variable_value_step.palette()) # make a copy of the palette 95 | palette.setColor(QPalette.Text, QColor('dark blue')) 96 | palette.setColor(QPalette.Base, QColor(243, 240, 160)) 97 | self.le_variable_value_step.setPalette(palette) 98 | 99 | self.set_KindOfLoop() 100 | self.calculate_step() 101 | 102 | gui.separator(box) 103 | 104 | def list_of_values_ta_changed(self): 105 | self.list_of_values = [] 106 | 107 | values = self.list_of_values_ta.toPlainText().split("\n") 108 | for value in values: 109 | if not value.strip() == "": self.list_of_values.append(value) 110 | 111 | if self.kind_of_loop==1: self.number_of_new_objects = len(self.list_of_values) 112 | 113 | if len(self.list_of_values) == 0: self.list_of_values.append("") 114 | 115 | def set_KindOfLoop(self): 116 | self.box_1.setVisible(self.kind_of_loop == 0) 117 | self.box_2.setVisible(self.kind_of_loop == 1) 118 | 119 | def calculate_step(self): 120 | try: self.variable_value_step = round((self.variable_value_to - self.variable_value_from) / self.number_of_new_objects, 8) 121 | except: self.variable_value_step = 0.0 122 | 123 | def get_current_value_type(self): return float 124 | 125 | def initialize_start_loop(self): 126 | do_loop = True 127 | 128 | if self.kind_of_loop == 0: 129 | self.current_variable_value = round(self.variable_value_from, 8) 130 | self.calculate_step() 131 | elif len(self.list_of_values) > 0: 132 | self.current_variable_value = self.list_of_values[self.current_new_object - 1] 133 | else: 134 | do_loop = False 135 | 136 | return do_loop 137 | 138 | def keep_looping(self): 139 | if (self.current_new_object < self.number_of_new_objects) or (self.current_new_object == self.number_of_new_objects and self.kind_of_loop==0): 140 | if self.current_variable_value is None: 141 | self.current_new_object = 1 142 | 143 | if self.kind_of_loop == 0: 144 | self.current_variable_value = round(self.variable_value_from, 8) 145 | self.calculate_step() 146 | elif len(self.list_of_values) > 0: 147 | self.current_variable_value = self.list_of_values[self.current_new_object - 1] 148 | else: 149 | self.current_new_object += 1 150 | if self.kind_of_loop == 0: 151 | self.current_variable_value = round(self.current_variable_value + self.variable_value_step, 8) 152 | elif len(self.list_of_values) > 0: 153 | self.current_variable_value = self.list_of_values[self.current_new_object - 1] 154 | return True 155 | else: 156 | return False 157 | -------------------------------------------------------------------------------- /oasys/widgets/tools/ow_surface_file_merger.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | 3 | import numpy 4 | from PyQt5.QtCore import QRect, Qt 5 | from PyQt5.QtWidgets import QApplication, QMessageBox, QLabel, QSizePolicy 6 | from PyQt5.QtGui import QTextCursor, QFont, QPalette, QColor, QPixmap 7 | 8 | from matplotlib import cm 9 | from oasys.widgets.gui import FigureCanvas3D 10 | from matplotlib.figure import Figure 11 | 12 | from orangewidget import gui, widget 13 | from orangewidget.settings import Setting 14 | 15 | from oasys.widgets.widget import OWWidget 16 | from oasys.widgets import gui as oasysgui 17 | from oasys.widgets import congruence 18 | 19 | from oasys.util.oasys_objects import OasysPreProcessorData, OasysErrorProfileData, OasysSurfaceData 20 | 21 | import oasys.util.oasys_util as OU 22 | 23 | try: 24 | from mpl_toolkits.mplot3d import Axes3D # necessario per caricare i plot 3D 25 | except: 26 | pass 27 | 28 | class OWSurfaceFileReader(OWWidget): 29 | name = "Surface File Merger" 30 | id = "surface_file_merger" 31 | description = "Surface File Merger" 32 | icon = "icons/surface_merger.png" 33 | author = "Luca Rebuffi" 34 | maintainer_email = "lrebuffi@anl.gov" 35 | priority = 5 36 | category = "" 37 | keywords = ["surface_file_mberger"] 38 | 39 | inputs = [("Surface Data #1", object, "set_input_1"), 40 | ("Surface Data #2", object, "set_input_2"), 41 | ] 42 | 43 | outputs = [{"name": "PreProcessor_Data", 44 | "type": OasysPreProcessorData, 45 | "doc": "PreProcessor Data", 46 | "id": "PreProcessor_Data"}, 47 | {"name": "Surface_Data", 48 | "type": OasysSurfaceData, 49 | "doc": "Surface Data", 50 | "id": "Surface_Data"}] 51 | 52 | 53 | want_main_area = 1 54 | want_control_area = 1 55 | 56 | MAX_WIDTH = 1320 57 | MAX_HEIGHT = 700 58 | 59 | IMAGE_WIDTH = 860 60 | IMAGE_HEIGHT = 645 61 | 62 | CONTROL_AREA_WIDTH = 405 63 | TABS_AREA_HEIGHT = 618 64 | 65 | xx = None 66 | yy = None 67 | zz = None 68 | 69 | xx_1 = None 70 | yy_1 = None 71 | zz_1 = None 72 | 73 | xx_2 = None 74 | yy_2 = None 75 | zz_2 = None 76 | 77 | surface_data = None 78 | preprocessor_data = None 79 | 80 | surface_file_name = Setting('merged_surface.hdf5') 81 | 82 | def __init__(self): 83 | super().__init__() 84 | 85 | geom = QApplication.desktop().availableGeometry() 86 | self.setGeometry(QRect(round(geom.width() * 0.05), 87 | round(geom.height() * 0.05), 88 | round(min(geom.width() * 0.98, self.MAX_WIDTH)), 89 | round(min(geom.height() * 0.95, self.MAX_HEIGHT)))) 90 | 91 | self.setMaximumHeight(self.geometry().height()) 92 | self.setMaximumWidth(self.geometry().width()) 93 | 94 | gui.separator(self.controlArea) 95 | 96 | button_box = oasysgui.widgetBox(self.controlArea, "", addSpace=False, orientation="horizontal") 97 | 98 | button = gui.button(button_box, self, "Read Surface", callback=self.read_surface) 99 | button.setFixedHeight(45) 100 | 101 | button = gui.button(button_box, self, "Render Surface", callback=self.render_surface) 102 | button.setFixedHeight(45) 103 | 104 | input_box_l = oasysgui.widgetBox(self.controlArea, "Input", addSpace=True, orientation="horizontal", height=self.TABS_AREA_HEIGHT) 105 | 106 | self.le_surface_file_name = oasysgui.lineEdit(input_box_l, self, "surface_file_name", "Surface File Name", 107 | labelWidth=120, valueType=str, orientation="horizontal") 108 | 109 | gui.button(input_box_l, self, "...", callback=self.selectSurfaceFile) 110 | 111 | 112 | self.figure = Figure(figsize=(600, 600)) 113 | self.figure.patch.set_facecolor('white') 114 | 115 | self.axis = self.figure.add_subplot(111, projection='3d') 116 | 117 | self.axis.set_zlabel("Z [m]") 118 | 119 | self.figure_canvas = FigureCanvas3D(ax=self.axis, fig=self.figure) 120 | 121 | self.mainArea.layout().addWidget(self.figure_canvas) 122 | 123 | gui.rubber(self.mainArea) 124 | 125 | 126 | def set_input_1(self, data): 127 | if not data is None: 128 | if isinstance(data, OasysPreProcessorData): 129 | self.xx_1 = data.error_profile_data.surface_data.xx 130 | self.yy_1 = data.error_profile_data.surface_data.yy 131 | self.zz_1 = data.error_profile_data.surface_data.zz 132 | elif isinstance(data, OasysSurfaceData): 133 | self.xx_1 = data.xx 134 | self.yy_1 = data.yy 135 | self.zz_1 = data.zz 136 | else: 137 | QMessageBox.critical(self, "Error", 138 | "Data Type #1 not recognized", 139 | QMessageBox.Ok) 140 | 141 | def set_input_2(self, data): 142 | if not data is None: 143 | if isinstance(data, OasysPreProcessorData): 144 | self.xx_2 = data.error_profile_data.surface_data.xx 145 | self.yy_2 = data.error_profile_data.surface_data.yy 146 | self.zz_2 = data.error_profile_data.surface_data.zz 147 | elif isinstance(data, OasysSurfaceData): 148 | self.xx_2 = data.xx 149 | self.yy_2 = data.yy 150 | self.zz_2 = data.zz 151 | else: 152 | QMessageBox.critical(self, "Error", 153 | "Data Type #2 not recognized", 154 | QMessageBox.Ok) 155 | 156 | def compute(self, plot_data=False): 157 | try: 158 | if not self.xx_1 is None and not self.xx_2 is None: 159 | xx_1 = self.xx_1 160 | yy_1 = self.yy_1 161 | zz_1 = self.zz_1 162 | 163 | xx_2 = self.xx_2 164 | yy_2 = self.yy_2 165 | zz_2 = self.zz_2 166 | 167 | if not (len(xx_1) == len(xx_2) and 168 | len(yy_1) == len(yy_1) and 169 | round(xx_1[0], 6) == round(xx_2[0], 6) and 170 | round(xx_1[-1], 6) == round(xx_2[-1], 6) and 171 | round(yy_1[0], 6) == round(yy_2[0], 6) and 172 | round(yy_1[-1], 6) == round(yy_2[-1], 6)): 173 | raise ValueError("The two surfaces cannot be merged: dimensions or binning incompatible") 174 | 175 | xx = xx_2 176 | yy = yy_2 177 | zz = zz_2 + zz_1 178 | 179 | self.axis.clear() 180 | 181 | x_to_plot, y_to_plot = numpy.meshgrid(xx, yy) 182 | 183 | if plot_data: 184 | self.axis.plot_surface(x_to_plot, y_to_plot, zz, 185 | rstride=1, cstride=1, cmap=cm.autumn, linewidth=0.5, antialiased=True) 186 | 187 | self.axis.set_xlabel("X [m]") 188 | self.axis.set_ylabel("Y [m]") 189 | self.axis.set_zlabel("Z [m]") 190 | self.axis.mouse_init() 191 | 192 | self.figure_canvas.draw() 193 | 194 | if not (self.surface_file_name.endswith("hd5") or self.surface_file_name.endswith("hdf5") or self.surface_file_name.endswith("hdf")): 195 | self.surface_file_name += ".hdf5" 196 | 197 | OU.write_surface_file(zz, xx, yy, self.surface_file_name) 198 | 199 | error_profile_x_dim = abs(xx[-1] - xx[0]) 200 | error_profile_y_dim = abs(yy[-1] - yy[0]) 201 | 202 | 203 | self.send("PreProcessor_Data", OasysPreProcessorData(error_profile_data=OasysErrorProfileData(surface_data=OasysSurfaceData(xx=xx, 204 | yy=yy, 205 | zz=zz, 206 | surface_data_file=self.surface_file_name), 207 | error_profile_x_dim=error_profile_x_dim, 208 | error_profile_y_dim=error_profile_y_dim))) 209 | self.send("Surface_Data", OasysSurfaceData(xx=xx, 210 | yy=yy, 211 | zz=zz, 212 | surface_data_file=self.surface_file_name)) 213 | 214 | except Exception as exception: 215 | QMessageBox.critical(self, "Error", 216 | exception.args[0], 217 | QMessageBox.Ok) 218 | 219 | if self.IS_DEVELOP: raise exception 220 | 221 | 222 | def read_surface(self): 223 | self.compute(plot_data=False) 224 | 225 | def render_surface(self): 226 | self.compute(plot_data=True) 227 | 228 | def selectSurfaceFile(self): 229 | self.le_surface_file_name.setText(oasysgui.selectFileFromDialog(self, self.surface_file_name, "Select Input File", file_extension_filter="HDF5 Files (*.hdf5)")) 230 | 231 | 232 | -------------------------------------------------------------------------------- /oasys/canvas/icons/orange-canvas.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /oasys/canvas/styles/orange.qss: -------------------------------------------------------------------------------- 1 | /* Default Orange stylesheet 2 | */ 3 | 4 | /* 5 | * Icon search paths relative to this files directory. 6 | * (main.py script will add this to QDir.searchPaths) 7 | */ 8 | 9 | @canvas_icons: orange; 10 | 11 | 12 | /* Main window background color */ 13 | 14 | CanvasMainWindow { 15 | background-color: #E9EFF2; 16 | } 17 | 18 | QMainWindow::separator { 19 | width: 1px; /* when vertical */ 20 | height: 1px; /* when horizontal */ 21 | } 22 | 23 | 24 | /* The widget buttons in the dock tool box */ 25 | 26 | WidgetsToolGrid QToolButton { 27 | font-family: "Helvetica"; 28 | font-size: 10px; 29 | font-weight: bold; 30 | color: #333; 31 | } 32 | 33 | 34 | /* Dock widget toolbox tab buttons (categories) */ 35 | 36 | WidgetToolBox QToolButton#toolbox-tab-button { 37 | /* nativeStyling property overrides the QStyle and uses a fixed drawing 38 | routine */ 39 | qproperty-nativeStyling_: "false"; 40 | 41 | font-family: "Helvetica"; 42 | font-size: 14px; 43 | font-weight: bold; 44 | color: #333; 45 | border: none; 46 | border-bottom: 1px solid #B5B8B8; 47 | background: qlineargradient( 48 | x1: 0, y1: 0, x2: 0, y2: 1, 49 | stop: 0 #F2F2F2, 50 | stop: 0.5 #F2F2F2, 51 | stop: 0.8 #EBEBEB, 52 | stop: 1.0 #DBDBDB 53 | ); 54 | } 55 | 56 | 57 | WidgetToolBox QToolButton#toolbox-tab-button:hover { 58 | background-color: palette(light); 59 | } 60 | 61 | 62 | WidgetToolBox QToolButton#toolbox-tab-button:checked { 63 | background-color: palette(dark); 64 | } 65 | 66 | 67 | WidgetToolBox QToolButton#toolbox-tab-button:focus { 68 | background-color: palette(highlight); 69 | border: 1px solid #609ED7 70 | } 71 | 72 | 73 | WidgetToolBox ToolGrid { 74 | background-color: #F2F2F2; 75 | padding-bottom: 8px; 76 | } 77 | 78 | 79 | WidgetToolBox ToolGrid QToolButton { 80 | border: none; 81 | /* border-bottom: 2px solid #B5B8B8; 82 | border-right: 2px solid #B5B8B8; */ 83 | background-color: #F2F2F2; 84 | border-radius: 8px; 85 | } 86 | 87 | 88 | WidgetToolBox ToolGrid QToolButton[last-column] { 89 | border-right: none; 90 | } 91 | 92 | WidgetToolBox ToolGrid QToolButton:focus { 93 | background-color: palette(window); 94 | } 95 | 96 | WidgetToolBox ToolGrid QToolButton:hover { 97 | background-color: palette(light); 98 | } 99 | 100 | WidgetToolBox ToolGrid QToolButton:pressed { 101 | background-color: palette(dark); 102 | } 103 | 104 | 105 | /* QuickCategoryToolbar popup menus */ 106 | 107 | CategoryPopupMenu { 108 | background-color: #E9EFF2; 109 | } 110 | 111 | CategoryPopupMenu ToolTree QTreeView::item { 112 | height: 25px; 113 | border-bottom: 1px solid #e9eff2; 114 | } 115 | 116 | CategoryPopupMenu QTreeView::item:selected { 117 | background: qlineargradient( 118 | x1: 0, y1: 0, x2: 0, y2: 1, 119 | stop: 0 #688EF6, 120 | stop: 0.5 #4047f4, 121 | stop: 1.0 #2D68F3 122 | ); 123 | color: white; 124 | } 125 | 126 | 127 | /* Canvas Dock Header */ 128 | 129 | CollapsibleDockWidget::title { 130 | background: qlineargradient( 131 | x1: 0, y1: 0, x2: 0, y2: 1, 132 | stop: 0 #808080, stop: 1.0 #666 133 | ); 134 | } 135 | 136 | /* Dock widget title bar button icons (icon size for both must be set). 137 | * The buttons define the title bar height. 138 | */ 139 | 140 | CollapsibleDockWidget::close-button, CollapsibleDockWidget::float-button { 141 | padding: 1px; 142 | icon-size: 11px; 143 | } 144 | 145 | CanvasToolDock WidgetToolBox { 146 | border: 1px solid #B5B8B8; 147 | } 148 | 149 | 150 | /* Toolbar at the bottom of the dock widget when in in expanded state 151 | */ 152 | 153 | CanvasToolDock QToolBar { 154 | height: 28; 155 | spacing: 1; 156 | border: none; 157 | /* 158 | background: qlineargradient( 159 | x1: 0, y1: 0, x2: 0, y2: 1, 160 | stop: 0 #808080, stop: 1.0 #666 161 | ); 162 | */ 163 | background-color: #898989; 164 | 165 | } 166 | 167 | CanvasToolDock QToolBar QToolButton { 168 | border: none; 169 | background: qlineargradient( 170 | x1: 0, y1: 0, x2: 0, y2: 1, 171 | stop: 0 #808080, stop: 1.0 #666 172 | ); 173 | } 174 | 175 | CanvasToolDock QToolBar QToolButton:menu-indicator { 176 | image: url(canvas_icons:/Dropdown.svg); 177 | subcontrol-position: top right; 178 | height: 8px; 179 | width: 8px; 180 | } 181 | 182 | CanvasToolDock QToolBar QToolButton:checked, 183 | CanvasToolDock QToolBar QToolButton:pressed { 184 | background-color: #FFA840; 185 | } 186 | 187 | 188 | /* Toolbar in the dock when in collapsed state. 189 | */ 190 | 191 | CollapsibleDockWidget QWidget#canvas-quick-dock QToolBar { 192 | spacing: 1; 193 | border: none; 194 | /* 195 | background: qlineargradient( 196 | x1: 0, y1: 0, x2: 0, y2: 1, 197 | stop: 0 #808080, stop: 1.0 #666 198 | ); 199 | */ 200 | background-color: #898989; 201 | } 202 | 203 | 204 | CollapsibleDockWidget QWidget#canvas-quick-dock QToolBar QToolButton { 205 | border: none; 206 | background: qlineargradient( 207 | x1: 0, y1: 0, x2: 1, y2: 0, 208 | stop: 0 #808080, stop: 1.0 #666 209 | ); 210 | } 211 | 212 | CollapsibleDockWidget QWidget#canvas-quick-dock QToolBar QToolButton:menu-indicator { 213 | image: url(canvas_icons:/Dropdown.svg); 214 | subcontrol-position: top right; 215 | height: 8px; 216 | width: 8px; 217 | } 218 | 219 | CollapsibleDockWidget QWidget#canvas-quick-dock QToolBar QToolButton:checked, 220 | CollapsibleDockWidget QWidget#canvas-quick-dock QToolBar QToolButton:pressed { 221 | background-color: #FFA840; 222 | } 223 | 224 | 225 | /* Splitter between the widget toolbox and quick help. 226 | */ 227 | 228 | CanvasToolDock QSplitter::handle { 229 | border: 1px solid #B5B8B8; 230 | 231 | /* border-top: 1px solid #B5B8B8; 232 | * border-bottom: 1px solid #B5B8B8; 233 | * border-left: 1px solid #B6B6B6; 234 | * border-right: 1px solid #B6B6B6; 235 | */ 236 | 237 | background: qlineargradient( 238 | x1: 0, y1: 0, x2: 0, y2: 1, 239 | stop: 0 #D4D4D4, stop: 0.05 #EDEDED, 240 | stop: 0.5 #F2F2F2, 241 | stop: 0.95 #EDEDED, stop: 1.0 #E0E0E0 242 | ); 243 | } 244 | 245 | 246 | /* Scheme Info Dialog 247 | */ 248 | 249 | SchemeInfoDialog { 250 | font-family: "Helvetica"; 251 | background-color: #E9EFF2; 252 | } 253 | 254 | SchemeInfoDialog SchemeInfoEdit QLabel { 255 | font-family: "Helvetica"; 256 | font-weight: bold; 257 | font-size: 16px; 258 | color: black; 259 | } 260 | 261 | SchemeInfoDialog QLabel#heading { 262 | font-size: 21px; 263 | color: #515151; 264 | } 265 | 266 | SchemeInfoDialog StyledWidget#auto-show-container * { 267 | font-family: "Helvetica"; 268 | font-size: 12px; 269 | color: #1A1A1A; 270 | } 271 | 272 | SchemeInfoDialog StyledWidget#auto-show-container { 273 | border-top: 1px solid #C1C2C3; 274 | } 275 | 276 | SchemeInfoDialog SchemeInfoEdit QLineEdit { 277 | padding: 4px; 278 | /* background-color: red; */ 279 | /* font-weight: normal; */ 280 | font-size: 12px; 281 | color: #1A1A1A; 282 | } 283 | 284 | SchemeInfoDialog SchemeInfoEdit QTextEdit { 285 | padding: 4px; 286 | background-color: white; 287 | /* font-weight: normal; */ 288 | font-size: 12px; 289 | color: #1A1A1A; 290 | } 291 | 292 | 293 | /* Preview Dialog (Recent Schemes and Tutorials) 294 | */ 295 | 296 | PreviewDialog { 297 | background-color: #E9EFF2; 298 | } 299 | 300 | PreviewDialog QLabel#heading { 301 | font-family: "Helvetica"; 302 | font-weight: bold; 303 | font-size: 21px; 304 | color: #515151; 305 | } 306 | 307 | PreviewDialog PreviewBrowser * { 308 | font-family: "Helvetica"; 309 | color: #1A1A1A; 310 | } 311 | 312 | PreviewDialog PreviewBrowser TextLabel#path-text { 313 | font-size: 12px; 314 | } 315 | 316 | PreviewDialog PreviewBrowser QLabel#path-label { 317 | font-size: 12px; 318 | } 319 | 320 | PreviewDialog DropShadowFrame { 321 | qproperty-radius_: 10; 322 | qproperty-color_: rgb(0, 0, 0, 100); 323 | } 324 | 325 | /* Welcome Screen Dialog 326 | */ 327 | 328 | WelcomeDialog { 329 | background-color: #E9EFF2; 330 | } 331 | 332 | WelcomeDialog QToolButton { 333 | font-family: "Helvetica"; 334 | font-size: 13px; 335 | font-style: normal; 336 | font-weight: bold; 337 | color: #333; 338 | } 339 | 340 | WelcomeDialog QWidget#bottom-bar { 341 | border-top: 1px solid #C1C2C3; 342 | } 343 | 344 | WelcomeDialog QWidget#bottom-bar QCheckBox { 345 | font-family: "Helvetica"; 346 | font-size: 12px; 347 | color: #333; 348 | } 349 | 350 | /* SchemeEditWidget 351 | */ 352 | 353 | SchemeEditWidget { 354 | font-family: "Helvetica"; 355 | font-size: 12px; 356 | } 357 | 358 | /* Quick Menu 359 | */ 360 | 361 | QuickMenu { 362 | background-color: #E9EFF2; 363 | } 364 | 365 | QuickMenu QFrame#menu-frame { 366 | border: 1px solid #9CACB4; 367 | border-radius: 3px; 368 | background-color: #E9EFF2; 369 | } 370 | 371 | QuickMenu QTreeView::item { 372 | border-bottom: 1px solid #e9eff2; 373 | } 374 | 375 | QuickMenu QTreeView::item:selected { 376 | background: qlineargradient( 377 | x1: 0, y1: 0, x2: 0, y2: 1, 378 | stop: 0 #688EF6, 379 | stop: 0.5 #4047f4, 380 | stop: 1.0 #2D68F3 381 | ); 382 | color: white; 383 | } 384 | 385 | QuickMenu TabBarWidget QToolButton { 386 | height: 25px; 387 | border-bottom: 1px solid palette(dark); 388 | padding-right: 5px; 389 | padding-left: 5px; 390 | qproperty-showMenuIndicator_: true; 391 | } 392 | 393 | QuickMenu TabBarWidget QToolButton#search-tab-button { 394 | background-color: #9CACB4; 395 | } 396 | 397 | QuickMenu TabBarWidget QToolButton:menu-indicator { 398 | image: url(canvas_icons:/arrow-right.svg); 399 | subcontrol-position: center right; 400 | height: 8px; 401 | width: 8px; 402 | } 403 | 404 | /* Quick Menu search line edit 405 | */ 406 | 407 | QuickMenu QLineEdit { 408 | height: 25px; 409 | margin: 0px; 410 | padding: 0px; 411 | border: 1px solid #9CACB4; 412 | border-radius: 3px; 413 | background-color: white; 414 | } 415 | 416 | QuickMenu QLineEdit:focus { 417 | border: 2px solid #9CACB4; 418 | border-radius: 2px; 419 | } 420 | 421 | QuickMenu QLineEdit QToolButton { 422 | qproperty-flat_: false; 423 | height: 25px; 424 | border: 1px solid #9CACB4; 425 | border-top-left-radius: 3px; 426 | border-bottom-left-radius: 3px; 427 | background-color: #9CACB4; 428 | padding: 0px; 429 | margin: 0px; 430 | icon-size: 23px; 431 | } 432 | -------------------------------------------------------------------------------- /scripts/macos/python-framework.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | usage() { 4 | echo "$0 [ --version VERSION ] FRAMEWORKPATH 5 | 6 | Fetch, extract and layout a macOS relocatable Python framework at FRAMEWORKPATH 7 | 8 | Options: 9 | --version VERSION Python version (default ${VERSION}) 10 | --macos MACOSVER Minimum supported macOS version (as of 3.6.5 and 11 | 3.7.0 the python.org provides binaries for 10.6 12 | and 10.9 macOS versions; default ${MACOSVER}) 13 | --install-certifi If present then certifi pypi package will be 14 | installed and its cert store linked in 15 | \${PREFIX}/etc/openssl 16 | -v --verbose Increase verbosity level 17 | 18 | Note: 19 | Python >= 3.6 comes with a bundled openssl library build that is 20 | configured to load certificates from 21 | /Library/Frameworks/Python.frameworks/\${pyver}/etc/openssl 22 | 23 | This script will patch python's stdlib ssl.py to add a 24 | \${PREFIX}/etc/openssl/cert.pem (where \${PREFIX} is the runtime prefix) 25 | certificate store to the default verification chain. However it will only 26 | supply the file if the --install-certifi parameter is passed 27 | 28 | Example 29 | ------- 30 | $ python-framework.sh ./ 31 | $ Python.framework/Versions/3.5/bin/python3.5 --version 32 | $ python-framework.sh --version 2.7.12 ./2.7 33 | $ ./2.7/Python.framework/Versions/2.7/bin/python2.7 --version 34 | " 35 | } 36 | 37 | 38 | VERSION=3.7.5 39 | MACOSVER=10.9 40 | VERBOSE_LEVEL=0 41 | INSTALL_CERTIFI= 42 | 43 | 44 | verbose() { 45 | local level=${1:?} 46 | shift 1 47 | if [[ ${VERBOSE_LEVEL:-0} -ge ${level} ]]; then 48 | echo "$@" 49 | fi 50 | } 51 | 52 | python-framework-fetch-pkg() { 53 | local cachedir=${1:?} 54 | local version=${2:?} 55 | local macosver=${3:-10.6} 56 | local versiondir=${version%%[abrpc]*} # strip alpha, beta, rc component 57 | local filename=python-${version}-macosx${macosver}.pkg 58 | local url="https://www.python.org/ftp/python/${versiondir}/${filename}" 59 | 60 | echo ${url} 61 | 62 | mkdir -p "${cachedir}" 63 | if [[ -f "${cachedir}/${filename}" ]]; then 64 | verbose 1 "python-${version}-macosx{macosver}.pkg is present in cache" 65 | return 0 66 | fi 67 | local tmpfile=$(mktemp "${cachedir}/${filename}"-XXXX) 68 | cleanup-on-exit() { 69 | if [ -f "${tmpfile}" ]; then 70 | rm "${tmpfile}" 71 | fi 72 | } 73 | 74 | ( 75 | trap cleanup-on-exit EXIT 76 | verbose 1 "Fetching ${url}" 77 | curl -sSL --fail -o "${tmpfile}" "${url}" 78 | mv "${tmpfile}" "${cachedir}/${filename}" 79 | ) 80 | } 81 | 82 | 83 | python-framework-extract-pkg() { 84 | local targetdir=${1:?} 85 | local pkgpath=${2:?} 86 | local pkgfilename 87 | pkgfilename=$(basename "${pkgpath}") 88 | mkdir -p "${targetdir}"/Python.framework 89 | verbose 1 "Extracting framework at ${targetdir}/Python.framework" 90 | ( 91 | tmpdir=$(mktemp -d -t python-framework-extract-pkg) 92 | cleanup-on-exit() { 93 | if [ -d "${tmpdir:?}" ] ; then 94 | rm -rf "${tmpdir:?}" 95 | fi 96 | } 97 | trap cleanup-on-exit EXIT 98 | pkgutil --expand "${pkgpath}" "${tmpdir:?}/${pkgfilename}" || exit 1 99 | tar -C "${targetdir}"/Python.framework \ 100 | -xf "${tmpdir}/${pkgfilename}/Python_Framework.pkg/Payload" || exit 1 101 | ) 102 | } 103 | 104 | 105 | python-framework-relocate() { 106 | local fmkdir=${1:?} 107 | if [[ ! ${fmkdir} =~ .*/Python.framework ]]; then 108 | echo "${fmkdir} is not a Python.framework" >&2 109 | return 1 110 | fi 111 | 112 | shopt -s nullglob 113 | local versions=( "${fmkdir}"/Versions/?.? ) 114 | shopt -u nullglob 115 | 116 | if [[ ! ${#versions[*]} == 1 ]]; then 117 | echo "Single version framework expected (found: ${versions[@]})" 118 | return 2 119 | fi 120 | local ver_short=${versions##*/} 121 | local prefix="${fmkdir}"/Versions/${ver_short} 122 | local bindir="${prefix}"/bin 123 | local libdir="${prefix}"/lib 124 | 125 | local existingid=$(otool -X -D "${prefix}"/Python | tail -n 1) 126 | local anchor="${existingid%%/Python.framework*}" 127 | 128 | if [[ ! ${anchor} =~ /.* ]]; then 129 | echo "${anchor} is not an absolute path" 2>&1 130 | return 2 131 | fi 132 | 133 | chmod +w "${fmkdir}"/Versions/${ver_short}/Python 134 | # change main lib's install id 135 | install_name_tool \ 136 | -id @rpath/Python.framework/Versions/${ver_short}/Python \ 137 | "${fmkdir}"/Versions/${ver_short}/Python 138 | 139 | # Add the containing frameworks path to rpath 140 | install_name_tool \ 141 | -add_rpath @loader_path/../../../ \ 142 | "${fmkdir}"/Versions/${ver_short}/Python 143 | 144 | # all expected executable binaries 145 | local binnames=( python${ver_short} python${ver_short}-32 \ 146 | pythonw${ver_short} pythonw${ver_short}-32 \ 147 | python${ver_short}m ) 148 | 149 | for binname in "${binnames[@]}"; 150 | do 151 | if [ -f "${bindir}/${binname}" ]; then 152 | install_name_tool \ 153 | -change "${anchor}"/Python.framework/Versions/${ver_short}/Python \ 154 | "@executable_path/../Python" \ 155 | "${bindir}/${binname}" 156 | fi 157 | done 158 | 159 | install_name_tool \ 160 | -change "${anchor}"/Python.framework/Versions/${ver_short}/Python \ 161 | "@executable_path/../../../../Python" \ 162 | "${prefix}"/Resources/Python.app/Contents/MacOS/Python 163 | 164 | for lib in libncursesw libmenuw libformw libpanelw libssl libcrypto; 165 | do 166 | local libpath="${libdir}"/${lib}.dylib 167 | if [[ -f "${libpath}" ]]; then 168 | local libid=$(otool -X -D "${libpath}") 169 | local libbasename=$(basename "${libid}") 170 | 171 | chmod +w "${libpath}" 172 | install_name_tool \ 173 | -id @rpath/Python.framework/Versions/${ver_short}/lib/${libbasename} \ 174 | "$libpath" 175 | 176 | local librefs=( $(otool -X -L "${libpath}" | cut -d " " -f 1) ) 177 | for libref in "${librefs[@]}" 178 | do 179 | if [[ ${libref} =~ ${anchor}/Python.framework/.* ]]; then 180 | local libbasename=$(basename "${libref}") 181 | install_name_tool \ 182 | -change "${libref}" @loader_path/${libbasename} \ 183 | "${libpath}" 184 | 185 | fi 186 | done 187 | fi 188 | done 189 | 190 | local dylibdir="${libdir}"/python${ver_short}/lib-dynload 191 | # _curses.so, _curses_panel.so, readline.so, ... 192 | local solibs=( "${dylibdir}"/*.so ) 193 | for libpath in "${solibs[@]}" 194 | do 195 | local librefs=( $(otool -X -L "${libpath}" | cut -d " " -f 1) ) 196 | for libref in "${librefs[@]}" 197 | do 198 | local strip_prefix="${anchor}"/Python.framework 199 | local strip_prefixn=$(( ${#strip_prefix} + 1 )) 200 | if [[ ${libref} =~ ${strip_prefix}/.* ]]; then 201 | local relpath=$(echo "${libref}" | cut -c $(( ${strip_prefixn} + 1))- ) 202 | # TODO: should @loader_path be preferred here? 203 | install_name_tool \ 204 | -change "${libref}" \ 205 | @rpath/Python.framework/"${relpath}" \ 206 | "${libpath}" 207 | fi 208 | done 209 | done 210 | 211 | # files/modules which reference /Library/Frameworks/Python.framework/ 212 | # - bin/* 213 | # - lib/pkgconfig/*.pc 214 | # - lib/python3.5/_sysconfigdata.py 215 | # - lib/python3.5/config-3.5m/python-config.py 216 | 217 | sed -i.bck s@prefix=${anchor}'.*'@prefix=\${pcfiledir}/../..@ \ 218 | "${libdir}"/pkgconfig/python-${ver_short}.pc 219 | 220 | # 3.6.* has bundled libssl with a hardcoded absolute openssl_{cafile,capath} 221 | # (need to set SSL_CERT_FILE environment var in all scripts? 222 | # or patch ssl.py module to add certs to default verify list?) 223 | if [[ ${ver_short#*.} -ge 6 ]]; then 224 | patch-ssl "${prefix}" 225 | fi 226 | } 227 | 228 | 229 | # patch python 3.6 to add etc/openssl/cert.pem cert store located relative 230 | # to the runtime prefix. 231 | patch-ssl() { 232 | local prefix=${1:?} 233 | # lib/python relative to prefix 234 | local pylibdir=$( 235 | cd "${prefix}"; 236 | shopt -s failglob; 237 | local path=( lib/python?.? ) 238 | echo "${path:?}" 239 | ) 240 | 241 | patch "${prefix}/${pylibdir}"/ssl.py - <&2 300 | usage >&2; exit 1;; 301 | esac 302 | done 303 | 304 | python-framework-fetch-pkg ~/.cache/pkgs/ ${VERSION} ${MACOSVER} 305 | python-framework-extract-pkg \ 306 | "${1:?"FRAMEWORKPATH argument is missing"}" \ 307 | ~/.cache/pkgs/python-${VERSION}-macosx${MACOSVER}.pkg 308 | 309 | python-framework-relocate "${1:?}"/Python.framework 310 | 311 | # Update the Versions/Current symlink 312 | ( 313 | cd "${1:?}"/Python.framework/Versions 314 | shopt -s failglob 315 | ln -shf ?.? ./Current # assuming single version framework 316 | ) 317 | 318 | if [[ ${INSTALL_CERTIFI} ]]; then 319 | verbose 1 "Installing and linking certifi pypi package" 320 | install-certifi "${1:?}"/Python.framework/Versions/Current 321 | fi 322 | --------------------------------------------------------------------------------