diff --git a/conandata.yml b/conandata.yml index ba9b85c479..b098ce19cf 100644 --- a/conandata.yml +++ b/conandata.yml @@ -125,6 +125,7 @@ pyinstaller: - "PyQt6.sip" - "stl" - "keyrings.alt" + - "pynavlib" collect_all_WINDOWS_ONLY: - "PyQt6.Qt" - "PyQt6.Qt6" diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 723cbcd2e5..b292191091 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -36,6 +36,7 @@ from UM.Operations.SetTransformOperation import SetTransformOperation from UM.OutputDevice.ProjectOutputDevice import ProjectOutputDevice from UM.Platform import Platform from UM.PluginError import PluginNotFoundError +from UM.PluginObject import PluginObject from UM.Preferences import Preferences from UM.Qt.Bindings.FileProviderModel import FileProviderModel from UM.Qt.QtApplication import QtApplication # The class we're inheriting from. @@ -130,8 +131,6 @@ from .Machines.Models.IntentSelectionModel import IntentSelectionModel from .PrintOrderManager import PrintOrderManager from .SingleInstance import SingleInstance -from .NavlibClient import NavlibClient - if TYPE_CHECKING: from UM.Settings.EmptyInstanceContainer import EmptyInstanceContainer @@ -220,6 +219,7 @@ class CuraApplication(QtApplication): self._machine_error_checker = None self._backend_plugins: List[BackendPlugin] = [] + self._view_manipulators: List[PluginObject] = [] self._machine_settings_manager = MachineSettingsManager(self, parent = self) self._material_management_model = None @@ -845,6 +845,7 @@ class CuraApplication(QtApplication): self._plugin_registry.addType("profile_reader", self._addProfileReader) self._plugin_registry.addType("profile_writer", self._addProfileWriter) self._plugin_registry.addType("backend_plugin", self._addBackendPlugin) + self._plugin_registry.addType("view_manipulator", self._addViewManipulator) if Platform.isLinux(): lib_suffixes = {"", "64", "32", "x32"} # A few common ones on different distributions. @@ -1039,10 +1040,6 @@ class CuraApplication(QtApplication): controller.setCameraTool("CameraTool") controller.setSelectionTool("SelectionTool") - self._navlib_client = NavlibClient(controller.getScene(), self.getRenderer()) - self._navlib_client.put_profile_hint("UltiMaker Cura") - self._navlib_client.enable_navigation(True) - # Hide the splash screen self.closeSplash() @@ -1951,6 +1948,9 @@ class CuraApplication(QtApplication): def getBackendPlugins(self) -> List["BackendPlugin"]: return self._backend_plugins + def _addViewManipulator(self, view_manipulator: "PluginObject"): + self._view_manipulators.append(view_manipulator) + @pyqtSlot("QSize") def setMinimumWindowSize(self, size): main_window = self.getMainWindow() diff --git a/cura/NavlibClient.py b/plugins/3DConnexion/NavlibClient.py similarity index 94% rename from cura/NavlibClient.py rename to plugins/3DConnexion/NavlibClient.py index db7711e773..68bbcf5772 100644 --- a/cura/NavlibClient.py +++ b/plugins/3DConnexion/NavlibClient.py @@ -3,25 +3,18 @@ from UM.Math.Vector import Vector from UM.Math.AxisAlignedBox import AxisAlignedBox from cura.PickingPass import PickingPass from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator -from cura.Scene.OverlayNode import OverlayNode, SceneNode +from UM.Scene.SceneNode import SceneNode from UM.Resources import Resources +from UM.PluginObject import PluginObject from UM.Logger import Logger +from .OverlayNode import OverlayNode +import pynavlib.pynavlib_interface as pynav -try: - import pynavlib.pynavlib_interface as pynav - parent_class = pynav.NavlibNavigationModel -except BaseException as exception: - Logger.warning(f"Unable to load 3DConnexion library: {exception}") - pynav = None - parent_class = object - -class NavlibClient(parent_class): +class NavlibClient(pynav.NavlibNavigationModel, PluginObject): def __init__(self, scene, renderer) -> None: - if not pynav: - return - - super().__init__(False, pynav.NavlibOptions.RowMajorOrder) + pynav.NavlibNavigationModel.__init__(self, False, pynav.NavlibOptions.RowMajorOrder) + PluginObject.__init__(self) self._scene = scene self._renderer = renderer self._pointer_pick = None @@ -29,14 +22,8 @@ class NavlibClient(parent_class): self._hit_selection_only = False self._picking_pass = None self._pivot_node = OverlayNode(node=SceneNode(), image_path=Resources.getPath(Resources.Images, "cor.png"), size=2.5) - - def put_profile_hint(self, hint) -> None: - if pynav: - super().put_profile_hint(hint) - - def enable_navigation(self, enabled) -> None: - if pynav: - super().enable_navigation(enabled) + self.put_profile_hint("UltiMaker Cura") + self.enable_navigation(True) def pick(self, x, y, check_selection = False, radius = 0.): diff --git a/cura/Scene/OverlayNode.py b/plugins/3DConnexion/OverlayNode.py similarity index 100% rename from cura/Scene/OverlayNode.py rename to plugins/3DConnexion/OverlayNode.py diff --git a/plugins/3DConnexion/__init__.py b/plugins/3DConnexion/__init__.py new file mode 100644 index 0000000000..368580797e --- /dev/null +++ b/plugins/3DConnexion/__init__.py @@ -0,0 +1,22 @@ +# Copyright (c) 2025 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from UM.Logger import Logger + +from typing import TYPE_CHECKING, Dict, Any + +if TYPE_CHECKING: + from UM.Application import Application + + +def getMetaData() -> Dict[str, Any]: + return {} + + +def register(app: "Application") -> Dict[str, Any]: + try: + from .NavlibClient import NavlibClient + return { "view_manipulator": NavlibClient(app.getController().getScene(), app.getRenderer()) } + except BaseException as exception: + Logger.warning(f"Unable to load 3DConnexion library: {exception}") + return { } diff --git a/plugins/3DConnexion/plugin.json b/plugins/3DConnexion/plugin.json new file mode 100644 index 0000000000..eadb70fc44 --- /dev/null +++ b/plugins/3DConnexion/plugin.json @@ -0,0 +1,8 @@ +{ + "name": "3DConnexion mouses", + "author": "3DConnexion", + "version": "1.0.0", + "description": "Allows working with 3D mouses inside Cura.", + "api": 8, + "i18n-catalog": "cura" +} diff --git a/resources/bundled_packages/cura.json b/resources/bundled_packages/cura.json index c89db0e151..1b32ee3484 100644 --- a/resources/bundled_packages/cura.json +++ b/resources/bundled_packages/cura.json @@ -1,4 +1,21 @@ { + "3DConnexion": { + "package_info": { + "package_id": "3DConnexion", + "package_type": "plugin", + "display_name": "3DConnexion mouses", + "description": "Allows working with 3D mouses inside Cura.\nOnly available on Windows and MacOS.", + "package_version": "1.0.0", + "sdk_version": "8.6.0", + "website": "https://3dconnexion.com", + "author": { + "author_id": "UltimakerPackages", + "display_name": "3DConnexion", + "email": "plugins@ultimaker.com", + "website": "https://3dconnexion.com" + } + } + }, "3MFReader": { "package_info": { "package_id": "3MFReader",