aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside-tools/qml.py
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside-tools/qml.py')
-rw-r--r--sources/pyside-tools/qml.py246
1 files changed, 246 insertions, 0 deletions
diff --git a/sources/pyside-tools/qml.py b/sources/pyside-tools/qml.py
new file mode 100644
index 000000000..5d029f93d
--- /dev/null
+++ b/sources/pyside-tools/qml.py
@@ -0,0 +1,246 @@
+# Copyright (C) 2018 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+"""pyside6-qml tool implementation. This tool mimics the capabilities of qml runtime utility
+for python and enables quick protyping with python modules"""
+
+import argparse
+import importlib.util
+import logging
+import sys
+import os
+from pathlib import Path
+from pprint import pprint
+from typing import List, Set
+
+from PySide6.QtCore import QCoreApplication, Qt, QLibraryInfo, QUrl, SignalInstance
+from PySide6.QtGui import QGuiApplication, QSurfaceFormat
+from PySide6.QtQml import QQmlApplicationEngine, QQmlComponent
+from PySide6.QtQuick import QQuickView, QQuickItem
+from PySide6.QtWidgets import QApplication
+
+
+def import_qml_modules(qml_parent_path: Path, module_paths: List[Path] = []):
+ '''
+ Import all the python modules in the qml_parent_path. This way all the classes
+ containing the @QmlElement/@QmlNamedElement are also imported
+
+ Parameters:
+ qml_parent_path (Path): Parent directory of the qml file
+ module_paths (int): user give import paths obtained through cli
+ '''
+
+ search_dir_paths = []
+ search_file_paths = []
+
+ if not module_paths:
+ search_dir_paths.append(qml_parent_path)
+ else:
+ for module_path in module_paths:
+ if module_path.is_dir():
+ search_dir_paths.append(module_path)
+ elif module_path.exists() and module_path.suffix == ".py":
+ search_file_paths.append(module_path)
+
+ def import_module(import_module_paths: Set[Path]):
+ """Import the modules in 'import_module_paths'"""
+ for module_path in import_module_paths:
+ module_name = module_path.name[:-3]
+ _spec = importlib.util.spec_from_file_location(f"{module_name}", module_path)
+ _module = importlib.util.module_from_spec(_spec)
+ _spec.loader.exec_module(module=_module)
+
+ modules_to_import = set()
+ for search_path in search_dir_paths:
+ possible_modules = list(search_path.glob("**/*.py"))
+ for possible_module in possible_modules:
+ if possible_module.is_file() and possible_module.name != "__init__.py":
+ module_parent = str(possible_module.parent)
+ if module_parent not in sys.path:
+ sys.path.append(module_parent)
+ modules_to_import.add(possible_module)
+
+ for search_path in search_file_paths:
+ sys.path.append(str(search_path.parent))
+ modules_to_import.add(search_path)
+
+ import_module(import_module_paths=modules_to_import)
+
+
+def print_configurations():
+ return "Built-in configurations \n\t default \n\t resizeToItem"
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(
+ description="This tools mimics the capabilities of qml runtime utility by directly"
+ " invoking QQmlEngine/QQuickView. It enables quick prototyping with qml files.",
+ formatter_class=argparse.RawTextHelpFormatter
+ )
+ parser.add_argument(
+ "file",
+ type=lambda p: Path(p).absolute(),
+ help="Path to qml file to display",
+ )
+ parser.add_argument(
+ "--module-paths", "-I",
+ type=lambda p: Path(p).absolute(),
+ nargs="+",
+ help="Specify space separated folder/file paths where the Qml classes are defined. By"
+ " default,the parent directory of the qml_path is searched recursively for all .py"
+ " files and they are imported. Otherwise only the paths give in module paths are"
+ " searched",
+ )
+ parser.add_argument(
+ "--list-conf",
+ action="version",
+ help="List the built-in configurations.",
+ version=print_configurations()
+ )
+ parser.add_argument(
+ "--apptype", "-a",
+ choices=["core", "gui", "widget"],
+ default="gui",
+ help="Select which application class to use. Default is gui",
+ )
+ parser.add_argument(
+ "--config", "-c",
+ choices=["default", "resizeToItem"],
+ default="default",
+ help="Select the built-in configurations.",
+ )
+ parser.add_argument(
+ "--rhi", "-r",
+ choices=["vulkan", "metal", "d3dll", "gl"],
+ help="Set the backend for the Qt graphics abstraction (RHI).",
+ )
+ parser.add_argument(
+ "--core-profile",
+ action="store_true",
+ help="Force use of OpenGL Core Profile.",
+ )
+ parser.add_argument(
+ '-v', '--verbose',
+ help="Print information about what qml is doing, like specific file URLs being loaded.",
+ action="store_const", dest="loglevel", const=logging.INFO,
+ )
+
+ gl_group = parser.add_mutually_exclusive_group(required=False)
+ gl_group.add_argument(
+ "--gles",
+ action="store_true",
+ help="Force use of GLES (AA_UseOpenGLES)",
+ )
+ gl_group.add_argument(
+ "--desktop",
+ action="store_true",
+ help="Force use of desktop OpenGL (AA_UseDesktopOpenGL)",
+ )
+ gl_group.add_argument(
+ "--software",
+ action="store_true",
+ help="Force use of software rendering(AA_UseSoftwareOpenGL)",
+ )
+ gl_group.add_argument(
+ "--disable-context-sharing",
+ action="store_true",
+ help=" Disable the use of a shared GL context for QtQuick Windows",
+ )
+
+ args = parser.parse_args()
+ apptype = args.apptype
+
+ qquick_present = False
+
+ with open(args.file) as myfile:
+ if 'import QtQuick' in myfile.read():
+ qquick_present = True
+
+ # no import QtQuick => QQCoreApplication
+ if not qquick_present:
+ apptype = "core"
+
+ import_qml_modules(args.file.parent, args.module_paths)
+
+ logging.basicConfig(level=args.loglevel)
+ logging.info(f"qml: {QLibraryInfo.build()}")
+ logging.info(f"qml: Using built-in configuration: {args.config}")
+
+ if args.rhi:
+ os.environ['QSG_RHI_BACKEND'] = args.rhi
+
+ logging.info(f"qml: loading {args.file}")
+ qml_file = QUrl.fromLocalFile(str(args.file))
+
+ if apptype == "gui":
+ if args.gles:
+ logging.info("qml: Using attribute AA_UseOpenGLES")
+ QCoreApplication.setAttribute(Qt.AA_UseOpenGLES)
+ elif args.desktop:
+ logging.info("qml: Using attribute AA_UseDesktopOpenGL")
+ QCoreApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
+ elif args.software:
+ logging.info("qml: Using attribute AA_UseSoftwareOpenGL")
+ QCoreApplication.setAttribute(Qt.AA_UseSoftwareOpenGL)
+
+ # context-sharing is enabled by default
+ if not args.disable_context_sharing:
+ logging.info("qml: Using attribute AA_ShareOpenGLContexts")
+ QCoreApplication.setAttribute(Qt.AA_ShareOpenGLContexts)
+
+ if apptype == "core":
+ logging.info("qml: Core application")
+ app = QCoreApplication(sys.argv)
+ elif apptype == "widgets":
+ logging.info("qml: Widget application")
+ app = QApplication(sys.argv)
+ else:
+ logging.info("qml: Gui application")
+ app = QGuiApplication(sys.argv)
+
+ engine = QQmlApplicationEngine()
+
+ # set OpenGLContextProfile
+ if apptype == "gui" and args.core_profile:
+ logging.info("qml: Set profile for QSurfaceFormat as CoreProfile")
+ surfaceFormat = QSurfaceFormat()
+ surfaceFormat.setStencilBufferSize(8)
+ surfaceFormat.setDepthBufferSize(24)
+ surfaceFormat.setVersion(4, 1)
+ surfaceFormat.setProfile(QSurfaceFormat.CoreProfile)
+ QSurfaceFormat.setDefaultFormat(surfaceFormat)
+
+ # in the case of QCoreApplication we print the attributes of the object created via
+ # QQmlComponent and exit
+ if apptype == "core":
+ component = QQmlComponent(engine, qml_file)
+ obj = component.create()
+ filtered_attributes = {k: v for k, v in vars(obj).items() if type(v) is not SignalInstance}
+ logging.info("qml: component object attributes are")
+ pprint(filtered_attributes)
+ del engine
+ sys.exit(0)
+
+ engine.load(qml_file)
+ rootObjects = engine.rootObjects()
+ if not rootObjects:
+ sys.exit(-1)
+
+ qquick_view = False
+ if isinstance(rootObjects[0], QQuickItem) and qquick_present:
+ logging.info("qml: loading with QQuickView")
+ viewer = QQuickView()
+ viewer.setSource(qml_file)
+ if args.config != "resizeToItem":
+ viewer.setResizeMode(QQuickView.SizeRootObjectToView)
+ else:
+ viewer.setResizeMode(QQuickView.SizeViewToRootObject)
+ viewer.show()
+ qquick_view = True
+
+ if not qquick_view:
+ logging.info("qml: loading with QQmlApplicationEngine")
+ if args.config == "resizeToItem":
+ logging.info("qml: Not a QQuickview item. resizeToItem is done by default")
+
+ sys.exit(app.exec())