def __init__(self, parent=None): super().__init__(parent) self._width = 0 self._height = 0 self._depth = 0 self._shader = None self._grid_mesh = None self._grid_shader = None self._disallowed_areas = [] self._disallowed_area_mesh = None self.setCalculateBoundingBox(False) self._volume_aabb = None self._raft_thickness = 0.0 self._adhesion_type = None self._platform = Platform(self) self._global_container_stack = None Application.getInstance().globalContainerStackChanged.connect( self._onGlobalContainerStackChanged) self._onGlobalContainerStackChanged() self._active_extruder_stack = None ExtruderManager.getInstance().activeExtruderChanged.connect( self._onActiveExtruderStackChanged) self._onActiveExtruderStackChanged()
def __init__(self, parent=None): super().__init__(parent) self._width = 0 self._height = 0 self._depth = 0 self._shader = None self._grid_mesh = None self._grid_shader = None self._disallowed_areas = [] self._disallowed_area_mesh = None self._error_areas = [] self._error_mesh = None self.setCalculateBoundingBox(False) self._volume_aabb = None self._raft_thickness = 0.0 self._adhesion_type = None self._platform = Platform(self) self._global_container_stack = None Application.getInstance().globalContainerStackChanged.connect( self._onStackChanged) self._onStackChanged() self._has_errors = False Application.getInstance().getController().getScene( ).sceneChanged.connect(self._onSceneChanged) # Number of objects loaded at the moment. self._number_of_objects = 0 self._change_timer = QTimer() self._change_timer.setInterval(100) self._change_timer.setSingleShot(True) self._change_timer.timeout.connect(self._onChangeTimerFinished) self._build_volume_message = Message( catalog.i18nc( "@info:status", "The build volume height has been reduced due to the value of the" " \"Print Sequence\" setting to prevent the gantry from colliding" " with printed models.")) # Must be after setting _build_volume_message, apparently that is used in getMachineManager. # activeQualityChanged is always emitted after setActiveVariant, setActiveMaterial and setActiveQuality. # Therefore this works. Application.getInstance().getMachineManager( ).activeQualityChanged.connect(self._onStackChanged) # This should also ways work, and it is semantically more correct, # but it does not update the disallowed areas after material change Application.getInstance().getMachineManager( ).activeStackChanged.connect(self._onStackChanged)
def run(self): if "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION" not in os.environ or os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] != "cpp": Logger.log("w", "Using Python implementation of Protobuf, expect bad performance!") self._i18n_catalog = i18nCatalog("cura"); i18nCatalog.setTagReplacements({ "filename": "font color=\"black\"", "message": "font color=UM.Theme.colors.message_text;", }) self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Setting up scene...")) controller = self.getController() controller.setActiveView("SolidView") controller.setCameraTool("CameraTool") controller.setSelectionTool("SelectionTool") t = controller.getTool("TranslateTool") if t: t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.YAxis,ToolHandle.ZAxis]) Selection.selectionChanged.connect(self.onSelectionChanged) root = controller.getScene().getRoot() self._platform = Platform(root) self._volume = BuildVolume.BuildVolume(root) self.getRenderer().setBackgroundColor(QColor(245, 245, 245)) self._physics = PlatformPhysics.PlatformPhysics(controller, self._volume) camera = Camera("3d", root) camera.setPosition(Vector(-80, 250, 700)) camera.setPerspective(True) camera.lookAt(Vector(0, 0, 0)) controller.getScene().setActiveCamera("3d") self.getController().getTool("CameraTool").setOrigin(Vector(0, 100, 0)) self._camera_animation = CameraAnimation.CameraAnimation() self._camera_animation.setCameraTool(self.getController().getTool("CameraTool")) self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Loading interface...")) self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self.initializeEngine() if self._engine.rootObjects: self.closeSplash() for file in self.getCommandLineOption("file", []): self._openFile(file) self.exec_()
class CuraApplication(QtApplication): def __init__(self): Resources.addResourcePath(os.path.join(QtApplication.getInstallPrefix(), "share", "cura")) if not hasattr(sys, "frozen"): Resources.addResourcePath(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..")) super().__init__(name = "cura", version = "master") self.setWindowIcon(QIcon(Resources.getPath(Resources.ImagesLocation, "cura-icon.png"))) self.setRequiredPlugins([ "CuraEngineBackend", "MeshView", "LayerView", "STLReader", "SelectionTool", "CameraTool", "GCodeWriter", "LocalFileOutputDevice" ]) self._physics = None self._volume = None self._platform = None self._output_devices = {} self._print_information = None self._i18n_catalog = None self._previous_active_tool = None self._platform_activity = False self.activeMachineChanged.connect(self._onActiveMachineChanged) self.getController().getScene().sceneChanged.connect(self.updatePlatformActivity) Preferences.getInstance().addPreference("cura/active_machine", "") Preferences.getInstance().addPreference("cura/active_mode", "simple") Preferences.getInstance().addPreference("cura/recent_files", "") Preferences.getInstance().addPreference("cura/categories_expanded", "") Preferences.getInstance().addPreference("view/center_on_select", True) JobQueue.getInstance().jobFinished.connect(self._onJobFinished) self._recent_files = [] files = Preferences.getInstance().getValue("cura/recent_files").split(";") for f in files: if not os.path.isfile(f): continue self._recent_files.append(QUrl.fromLocalFile(f)) ## Handle loading of all plugin types (and the backend explicitly) # \sa PluginRegistery def _loadPlugins(self): self._plugin_registry.addPluginLocation(os.path.join(QtApplication.getInstallPrefix(), "lib", "cura")) if not hasattr(sys, "frozen"): self._plugin_registry.addPluginLocation(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "plugins")) self._plugin_registry.loadPlugin("ConsoleLogger") self._plugin_registry.loadPlugins() if self.getBackend() == None: raise RuntimeError("Could not load the backend plugin!") def addCommandLineOptions(self, parser): super().addCommandLineOptions(parser) parser.add_argument("file", nargs="*", help="Files to load after starting the application.") def run(self): self._i18n_catalog = i18nCatalog("cura"); i18nCatalog.setTagReplacements({ "filename": "font color=\"black\"", "message": "font color=UM.Theme.colors.message_text;", }) self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Setting up scene...")) controller = self.getController() controller.setActiveView("MeshView") controller.setCameraTool("CameraTool") controller.setSelectionTool("SelectionTool") t = controller.getTool("TranslateTool") if t: t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.YAxis,ToolHandle.ZAxis]) Selection.selectionChanged.connect(self.onSelectionChanged) root = controller.getScene().getRoot() self._platform = Platform(root) self._volume = BuildVolume.BuildVolume(root) self.getRenderer().setLightPosition(Vector(0, 150, 0)) self.getRenderer().setBackgroundColor(QColor(245, 245, 245)) self._physics = PlatformPhysics.PlatformPhysics(controller, self._volume) camera = Camera("3d", root) camera.setPosition(Vector(-150, 150, 300)) camera.setPerspective(True) camera.lookAt(Vector(0, 0, 0)) self._camera_animation = CameraAnimation.CameraAnimation() self._camera_animation.setCameraTool(self.getController().getTool("CameraTool")) controller.getScene().setActiveCamera("3d") self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Loading interface...")) self.setMainQml(Resources.getPath(Resources.QmlFilesLocation, "Cura.qml")) self.initializeEngine() if self.getMachines(): active_machine_pref = Preferences.getInstance().getValue("cura/active_machine") if active_machine_pref: for machine in self.getMachines(): if machine.getName() == active_machine_pref: self.setActiveMachine(machine) if not self.getActiveMachine(): self.setActiveMachine(self.getMachines()[0]) else: self.requestAddPrinter.emit() if self._engine.rootObjects: self.closeSplash() for file in self.getCommandLineOption("file", []): self._openFile(file) self.exec_() # Handle Qt events def event(self, event): if event.type() == QEvent.FileOpen: self._openFile(event.file()) return super().event(event) def getPrintInformation(self): return self._print_information def registerObjects(self, engine): engine.rootContext().setContextProperty("Printer", self) self._print_information = PrintInformation.PrintInformation() engine.rootContext().setContextProperty("PrintInformation", self._print_information) self._cura_actions = CuraActions.CuraActions(self) engine.rootContext().setContextProperty("CuraActions", self._cura_actions) def onSelectionChanged(self): if Selection.hasSelection(): if not self.getController().getActiveTool(): if self._previous_active_tool: self.getController().setActiveTool(self._previous_active_tool) self._previous_active_tool = None else: self.getController().setActiveTool("TranslateTool") if Preferences.getInstance().getValue("view/center_on_select"): self._camera_animation.setStart(self.getController().getTool("CameraTool").getOrigin()) self._camera_animation.setTarget(Selection.getSelectedObject(0).getWorldPosition()) self._camera_animation.start() else: if self.getController().getActiveTool(): self._previous_active_tool = self.getController().getActiveTool().getPluginId() self.getController().setActiveTool(None) else: self._previous_active_tool = None requestAddPrinter = pyqtSignal() activityChanged = pyqtSignal() @pyqtProperty(bool, notify = activityChanged) def getPlatformActivity(self): return self._platform_activity def updatePlatformActivity(self, node = None): count = 0 for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue count += 1 self._platform_activity = True if count > 0 else False self.activityChanged.emit() ## Remove an object from the scene @pyqtSlot("quint64") def deleteObject(self, object_id): object = self.getController().getScene().findObject(object_id) if not object and object_id != 0: #Workaround for tool handles overlapping the selected object object = Selection.getSelectedObject(0) if object: if object.getParent(): group_node = object.getParent() if not group_node.callDecoration("isGroup"): op = RemoveSceneNodeOperation(object) else: while group_node.getParent().callDecoration("isGroup"): group_node = group_node.getParent() op = RemoveSceneNodeOperation(group_node) op.push() ## Create a number of copies of existing object. @pyqtSlot("quint64", int) def multiplyObject(self, object_id, count): node = self.getController().getScene().findObject(object_id) if not node and object_id != 0: #Workaround for tool handles overlapping the selected object node = Selection.getSelectedObject(0) if node: op = GroupedOperation() for i in range(count): new_node = SceneNode() new_node.setMeshData(node.getMeshData()) new_node.translate(Vector((i + 1) * node.getBoundingBox().width, node.getPosition().y, 0)) new_node.setOrientation(node.getOrientation()) new_node.setScale(node.getScale()) new_node.setSelectable(True) op.addOperation(AddSceneNodeOperation(new_node, node.getParent())) op.push() ## Center object on platform. @pyqtSlot("quint64") def centerObject(self, object_id): node = self.getController().getScene().findObject(object_id) if not node and object_id != 0: #Workaround for tool handles overlapping the selected object node = Selection.getSelectedObject(0) if node: op = SetTransformOperation(node, Vector()) op.push() ## Delete all mesh data on the scene. @pyqtSlot() def deleteAll(self): nodes = [] for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) if nodes: op = GroupedOperation() for node in nodes: op.addOperation(RemoveSceneNodeOperation(node)) op.push() ## Reset all translation on nodes with mesh data. @pyqtSlot() def resetAllTranslation(self): nodes = [] for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) if nodes: op = GroupedOperation() for node in nodes: op.addOperation(SetTransformOperation(node, Vector())) op.push() ## Reset all transformations on nodes with mesh data. @pyqtSlot() def resetAll(self): nodes = [] for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) if nodes: op = GroupedOperation() for node in nodes: op.addOperation(SetTransformOperation(node, Vector(), Quaternion(), Vector(1, 1, 1))) op.push() ## Reload all mesh data on the screen from file. @pyqtSlot() def reloadAll(self): nodes = [] for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) if not nodes: return for node in nodes: if not node.getMeshData(): continue file_name = node.getMeshData().getFileName() if file_name: job = ReadMeshJob(file_name) job._node = node job.finished.connect(self._reloadMeshFinished) job.start() ## Get logging data of the backend engine # \returns \type{string} Logging data @pyqtSlot(result=str) def getEngineLog(self): log = "" for entry in self.getBackend().getLog(): log += entry.decode() return log recentFilesChanged = pyqtSignal() @pyqtProperty("QVariantList", notify = recentFilesChanged) def recentFiles(self): return self._recent_files @pyqtSlot("QStringList") def setExpandedCategories(self, categories): categories = list(set(categories)) categories.sort() joined = ";".join(categories) if joined != Preferences.getInstance().getValue("cura/categories_expanded"): Preferences.getInstance().setValue("cura/categories_expanded", joined) self.expandedCategoriesChanged.emit() expandedCategoriesChanged = pyqtSignal() @pyqtProperty("QStringList", notify = expandedCategoriesChanged) def expandedCategories(self): return Preferences.getInstance().getValue("cura/categories_expanded").split(";") @pyqtSlot(str, result = "QVariant") def getSettingValue(self, key): if not self.getActiveMachine(): return None return self.getActiveMachine().getSettingValueByKey(key) ## Change setting by key value pair @pyqtSlot(str, "QVariant") def setSettingValue(self, key, value): if not self.getActiveMachine(): return self.getActiveMachine().setSettingValueByKey(key, value) @pyqtSlot() def mergeSelected(self): self.groupSelected() try: group_node = Selection.getAllSelectedObjects()[0] except Exception as e: return multi_material_decorator = MultiMaterialDecorator.MultiMaterialDecorator() group_node.addDecorator(multi_material_decorator) # Reset the position of each node for node in group_node.getChildren(): new_position = node.getMeshData().getCenterPosition() new_position.setY(0) node.setPosition(new_position) # Use the previously found center of the group bounding box as the new location of the group group_node.setPosition(group_node.getBoundingBox().center) @pyqtSlot() def groupSelected(self): group_node = SceneNode() group_decorator = GroupDecorator() group_node.addDecorator(group_decorator) group_node.setParent(self.getController().getScene().getRoot()) for node in Selection.getAllSelectedObjects(): node.setParent(group_node) for node in group_node.getChildren(): Selection.remove(node) Selection.add(group_node) @pyqtSlot() def ungroupSelected(self): ungrouped_nodes = [] selected_objects = Selection.getAllSelectedObjects()[:] #clone the list for node in selected_objects: if node.callDecoration("isGroup" ): children_to_move = [] for child in node.getChildren(): if type(child) is SceneNode: children_to_move.append(child) for child in children_to_move: child.setParent(node.getParent()) Selection.add(child) child.callDecoration("setConvexHull",None) node.setParent(None) ungrouped_nodes.append(node) for node in ungrouped_nodes: Selection.remove(node) def _onActiveMachineChanged(self): machine = self.getActiveMachine() if machine: Preferences.getInstance().setValue("cura/active_machine", machine.getName()) self._volume.setWidth(machine.getSettingValueByKey("machine_width")) self._volume.setHeight(machine.getSettingValueByKey("machine_height")) self._volume.setDepth(machine.getSettingValueByKey("machine_depth")) disallowed_areas = machine.getSettingValueByKey("machine_disallowed_areas") areas = [] if disallowed_areas: for area in disallowed_areas: areas.append(Polygon(numpy.array(area, numpy.float32))) self._volume.setDisallowedAreas(areas) self._volume.rebuild() offset = machine.getSettingValueByKey("machine_platform_offset") if offset: self._platform.setPosition(Vector(offset[0], offset[1], offset[2])) else: self._platform.setPosition(Vector(0.0, 0.0, 0.0)) def _onFileLoaded(self, job): node = job.getResult() if node != None: node.setSelectable(True) node.setName(os.path.basename(job.getFileName())) op = AddSceneNodeOperation(node, self.getController().getScene().getRoot()) op.push() def _onJobFinished(self, job): if type(job) is not ReadMeshJob or not job.getResult(): return f = QUrl.fromLocalFile(job.getFileName()) if f in self._recent_files: self._recent_files.remove(f) self._recent_files.insert(0, f) if len(self._recent_files) > 10: del self._recent_files[10] pref = "" for path in self._recent_files: pref += path.toLocalFile() + ";" Preferences.getInstance().setValue("cura/recent_files", pref) self.recentFilesChanged.emit() def _reloadMeshFinished(self, job): job._node = job.getResult() def _openFile(self, file): job = ReadMeshJob(os.path.abspath(file)) job.finished.connect(self._onFileLoaded) job.start()
def run(self): self._i18n_catalog = i18nCatalog("cura"); i18nCatalog.setTagReplacements({ "filename": "font color=\"black\"", "message": "font color=UM.Theme.colors.message_text;", }) self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Setting up scene...")) controller = self.getController() controller.setActiveView("MeshView") controller.setCameraTool("CameraTool") controller.setSelectionTool("SelectionTool") t = controller.getTool("TranslateTool") if t: t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.YAxis,ToolHandle.ZAxis]) Selection.selectionChanged.connect(self.onSelectionChanged) root = controller.getScene().getRoot() self._platform = Platform(root) self._volume = BuildVolume.BuildVolume(root) self.getRenderer().setLightPosition(Vector(0, 150, 0)) self.getRenderer().setBackgroundColor(QColor(245, 245, 245)) self._physics = PlatformPhysics.PlatformPhysics(controller, self._volume) camera = Camera("3d", root) camera.setPosition(Vector(-150, 150, 300)) camera.setPerspective(True) camera.lookAt(Vector(0, 0, 0)) self._camera_animation = CameraAnimation.CameraAnimation() self._camera_animation.setCameraTool(self.getController().getTool("CameraTool")) controller.getScene().setActiveCamera("3d") self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Loading interface...")) self.setMainQml(Resources.getPath(Resources.QmlFilesLocation, "Cura.qml")) self.initializeEngine() if self.getMachines(): active_machine_pref = Preferences.getInstance().getValue("cura/active_machine") if active_machine_pref: for machine in self.getMachines(): if machine.getName() == active_machine_pref: self.setActiveMachine(machine) if not self.getActiveMachine(): self.setActiveMachine(self.getMachines()[0]) else: self.requestAddPrinter.emit() if self._engine.rootObjects: self.closeSplash() for file in self.getCommandLineOption("file", []): self._openFile(file) self.exec_()
class CuraApplication(QtApplication): def __init__(self): Resources.addResourcePath(os.path.join(QtApplication.getInstallPrefix(), "share", "cura")) if not hasattr(sys, "frozen"): Resources.addResourcePath(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..")) super().__init__(name = "cura", version = "master") self.setWindowIcon(QIcon(Resources.getPath(Resources.ImagesLocation, "cura-icon.png"))) self.setRequiredPlugins([ "CuraEngineBackend", "MeshView", "LayerView", "STLReader", "SelectionTool", "CameraTool", "GCodeWriter", "LocalFileStorage" ]) self._physics = None self._volume = None self._platform = None self._output_devices = {} self._print_information = None self._i18n_catalog = None self._previous_active_tool = None self._platform_activity = False self.activeMachineChanged.connect(self._onActiveMachineChanged) Preferences.getInstance().addPreference("cura/active_machine", "") Preferences.getInstance().addPreference("cura/active_mode", "simple") Preferences.getInstance().addPreference("cura/recent_files", "") Preferences.getInstance().addPreference("cura/categories_expanded", "") JobQueue.getInstance().jobFinished.connect(self._onJobFinished) self._recent_files = [] files = Preferences.getInstance().getValue("cura/recent_files").split(";") for f in files: if not os.path.isfile(f): continue self._recent_files.append(QUrl.fromLocalFile(f)) ## Handle loading of all plugin types (and the backend explicitly) # \sa PluginRegistery def _loadPlugins(self): self._plugin_registry.addPluginLocation(os.path.join(QtApplication.getInstallPrefix(), "lib", "cura")) if not hasattr(sys, "frozen"): self._plugin_registry.addPluginLocation(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "plugins")) self._plugin_registry.loadPlugins({ "type": "logger"}) self._plugin_registry.loadPlugins({ "type": "storage_device" }) self._plugin_registry.loadPlugins({ "type": "view" }) self._plugin_registry.loadPlugins({ "type": "mesh_reader" }) self._plugin_registry.loadPlugins({ "type": "mesh_writer" }) self._plugin_registry.loadPlugins({ "type": "tool" }) self._plugin_registry.loadPlugins({ "type": "extension" }) self._plugin_registry.loadPlugin("CuraEngineBackend") def addCommandLineOptions(self, parser): super().addCommandLineOptions(parser) parser.add_argument("file", nargs="*", help="Files to load after starting the application.") def run(self): self._i18n_catalog = i18nCatalog("cura"); self.addOutputDevice("local_file", { "id": "local_file", "function": self._writeToLocalFile, "description": self._i18n_catalog.i18nc("Save button tooltip", "Save to Disk"), "shortDescription": self._i18n_catalog.i18nc("Save button tooltip", "Save to Disk"), "icon": "save", "priority": 0 }) self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Setting up scene...")) controller = self.getController() controller.setActiveView("MeshView") controller.setCameraTool("CameraTool") controller.setSelectionTool("SelectionTool") t = controller.getTool("TranslateTool") if t: t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.ZAxis]) Selection.selectionChanged.connect(self.onSelectionChanged) root = controller.getScene().getRoot() self._platform = Platform(root) self._volume = BuildVolume.BuildVolume(root) self.getRenderer().setLightPosition(Vector(0, 150, 0)) self.getRenderer().setBackgroundColor(QColor(245, 245, 245)) self._physics = PlatformPhysics.PlatformPhysics(controller, self._volume) camera = Camera("3d", root) camera.setPosition(Vector(-150, 150, 300)) camera.setPerspective(True) camera.lookAt(Vector(0, 0, 0)) self._camera_animation = CameraAnimation.CameraAnimation() self._camera_animation.setCameraTool(self.getController().getTool("CameraTool")) controller.getScene().setActiveCamera("3d") self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Loading interface...")) self.setMainQml(Resources.getPath(Resources.QmlFilesLocation, "Cura.qml")) self.initializeEngine() self.getStorageDevice("LocalFileStorage").removableDrivesChanged.connect(self._removableDrivesChanged) if self.getMachines(): active_machine_pref = Preferences.getInstance().getValue("cura/active_machine") if active_machine_pref: for machine in self.getMachines(): if machine.getName() == active_machine_pref: self.setActiveMachine(machine) if not self.getActiveMachine(): self.setActiveMachine(self.getMachines()[0]) else: self.requestAddPrinter.emit() self._removableDrivesChanged() if self._engine.rootObjects: self.closeSplash() for file in self.getCommandLineOption("file", []): job = ReadMeshJob(os.path.abspath(file)) job.finished.connect(self._onFileLoaded) job.start() self.exec_() def registerObjects(self, engine): engine.rootContext().setContextProperty("Printer", self) self._print_information = PrintInformation.PrintInformation() engine.rootContext().setContextProperty("PrintInformation", self._print_information) self._cura_actions = CuraActions.CuraActions(self) engine.rootContext().setContextProperty("CuraActions", self._cura_actions) def onSelectionChanged(self): if Selection.hasSelection(): if not self.getController().getActiveTool(): if self._previous_active_tool: self.getController().setActiveTool(self._previous_active_tool) self._previous_active_tool = None else: self.getController().setActiveTool("TranslateTool") self._camera_animation.setStart(self.getController().getTool("CameraTool").getOrigin()) self._camera_animation.setTarget(Selection.getSelectedObject(0).getWorldPosition()) self._camera_animation.start() else: if self.getController().getActiveTool(): self._previous_active_tool = self.getController().getActiveTool().getPluginId() self.getController().setActiveTool(None) else: self._previous_active_tool = None requestAddPrinter = pyqtSignal() activityChanged = pyqtSignal() @pyqtProperty(bool, notify = activityChanged) def getPlatformActivity(self): return self._platform_activity @pyqtSlot(bool) def setPlatformActivity(self, activity): ##Sets the _platform_activity variable on true or false depending on whether there is a mesh on the platform if activity == True: self._platform_activity = activity elif activity == False: nodes = [] for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) i = 0 for node in nodes: if not node.getMeshData(): continue i += 1 if i <= 1: ## i == 0 when the meshes are removed using the deleteAll function; i == 1 when the last remaining mesh is removed using the deleteObject function self._platform_activity = activity self.activityChanged.emit() ## Remove an object from the scene @pyqtSlot("quint64") def deleteObject(self, object_id): object = self.getController().getScene().findObject(object_id) if not object and object_id != 0: #Workaround for tool handles overlapping the selected object object = Selection.getSelectedObject(0) if object: if object.getParent(): group_node = object.getParent() if not group_node.callDecoration("isGroup"): op = RemoveSceneNodeOperation(object) else: while group_node.getParent().callDecoration("isGroup"): group_node = group_node.getParent() op = RemoveSceneNodeOperation(group_node) op.push() self.setPlatformActivity(False) ## Create a number of copies of existing object. @pyqtSlot("quint64", int) def multiplyObject(self, object_id, count): node = self.getController().getScene().findObject(object_id) if not node and object_id != 0: #Workaround for tool handles overlapping the selected object node = Selection.getSelectedObject(0) if node: op = GroupedOperation() for i in range(count): new_node = SceneNode() new_node.setMeshData(node.getMeshData()) new_node.setScale(node.getScale()) new_node.translate(Vector((i + 1) * node.getBoundingBox().width, 0, 0)) new_node.setSelectable(True) op.addOperation(AddSceneNodeOperation(new_node, node.getParent())) op.push() ## Center object on platform. @pyqtSlot("quint64") def centerObject(self, object_id): node = self.getController().getScene().findObject(object_id) if not node and object_id != 0: #Workaround for tool handles overlapping the selected object node = Selection.getSelectedObject(0) if node: op = SetTransformOperation(node, Vector()) op.push() ## Delete all mesh data on the scene. @pyqtSlot() def deleteAll(self): nodes = [] for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) if nodes: op = GroupedOperation() for node in nodes: op.addOperation(RemoveSceneNodeOperation(node)) op.push() self.setPlatformActivity(False) ## Reset all translation on nodes with mesh data. @pyqtSlot() def resetAllTranslation(self): nodes = [] for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) if nodes: op = GroupedOperation() for node in nodes: op.addOperation(SetTransformOperation(node, Vector())) op.push() ## Reset all transformations on nodes with mesh data. @pyqtSlot() def resetAll(self): nodes = [] for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) if nodes: op = GroupedOperation() for node in nodes: op.addOperation(SetTransformOperation(node, Vector(), Quaternion(), Vector(1, 1, 1))) op.push() ## Reload all mesh data on the screen from file. @pyqtSlot() def reloadAll(self): nodes = [] for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) if not nodes: return for node in nodes: if not node.getMeshData(): continue file_name = node.getMeshData().getFileName() if file_name: job = ReadMeshJob(file_name) job._node = node job.finished.connect(self._reloadMeshFinished) job.start() ## Get logging data of the backend engine # \returns \type{string} Logging data @pyqtSlot(result=str) def getEngineLog(self): log = "" for entry in self.getBackend().getLog(): log += entry.decode() return log recentFilesChanged = pyqtSignal() @pyqtProperty("QVariantList", notify = recentFilesChanged) def recentFiles(self): return self._recent_files @pyqtSlot("QStringList") def setExpandedCategories(self, categories): categories = list(set(categories)) categories.sort() joined = ";".join(categories) if joined != Preferences.getInstance().getValue("cura/categories_expanded"): Preferences.getInstance().setValue("cura/categories_expanded", joined) self.expandedCategoriesChanged.emit() expandedCategoriesChanged = pyqtSignal() @pyqtProperty("QStringList", notify = expandedCategoriesChanged) def expandedCategories(self): return Preferences.getInstance().getValue("cura/categories_expanded").split(";") outputDevicesChanged = pyqtSignal() @pyqtProperty("QVariantMap", notify = outputDevicesChanged) def outputDevices(self): return self._output_devices @pyqtProperty("QStringList", notify = outputDevicesChanged) def outputDeviceNames(self): return self._output_devices.keys() @pyqtSlot(str, result = "QVariant") def getSettingValue(self, key): if not self.getActiveMachine(): return None return self.getActiveMachine().getSettingValueByKey(key) ## Change setting by key value pair @pyqtSlot(str, "QVariant") def setSettingValue(self, key, value): if not self.getActiveMachine(): return self.getActiveMachine().setSettingValueByKey(key, value) @pyqtSlot() def mergeSelected(self): self.groupSelected() try: group_node = Selection.getAllSelectedObjects()[0] except Exception as e: return multi_material_decorator = MultiMaterialDecorator.MultiMaterialDecorator() group_node.addDecorator(multi_material_decorator) # Reset the position of each node for node in group_node.getChildren(): new_position = node.getMeshData().getCenterPosition() new_position.setY(0) node.setPosition(new_position) # Use the previously found center of the group bounding box as the new location of the group group_node.setPosition(group_node.getBoundingBox().center) @pyqtSlot() def groupSelected(self): group_node = SceneNode() group_decorator = GroupDecorator() group_node.addDecorator(group_decorator) group_node.setParent(self.getController().getScene().getRoot()) for node in Selection.getAllSelectedObjects(): node.setParent(group_node) for node in group_node.getChildren(): Selection.remove(node) Selection.add(group_node) @pyqtSlot() def ungroupSelected(self): ungrouped_nodes = [] selected_objects = Selection.getAllSelectedObjects()[:] #clone the list for node in selected_objects: if node.callDecoration("isGroup" ): children_to_move = [] for child in node.getChildren(): if type(child) is SceneNode: children_to_move.append(child) for child in children_to_move: child.setParent(node.getParent()) Selection.add(child) child.callDecoration("setConvexHull",None) node.setParent(None) ungrouped_nodes.append(node) for node in ungrouped_nodes: Selection.remove(node) ## Add an output device that can be written to. # # \param id \type{string} The identifier used to identify the device. # \param device \type{StorageDevice} A dictionary of device information. # It should contains the following: # - function: A function to be called when trying to write to the device. Will be passed the device id as first parameter. # - description: A translated string containing a description of what happens when writing to the device. # - icon: The icon to use to represent the device. # - priority: The priority of the device. The device with the highest priority will be used as the default device. def addOutputDevice(self, id, device): self._output_devices[id] = device self.outputDevicesChanged.emit() ## Remove output device # \param id \type{string} The identifier used to identify the device. # \sa PrinterApplication::addOutputDevice() def removeOutputDevice(self, id): if id in self._output_devices: del self._output_devices[id] self.outputDevicesChanged.emit() @pyqtSlot(str) def writeToOutputDevice(self, device): self._output_devices[device]["function"](device) writeToLocalFileRequested = pyqtSignal() def _writeToLocalFile(self, device): self.writeToLocalFileRequested.emit() def _writeToSD(self, device): for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue try: path = self.getStorageDevice("LocalFileStorage").getRemovableDrives()[device] except KeyError: Logger.log("e", "Tried to write to unknown SD card %s", device) return filename = os.path.join(path, node.getName()[0:node.getName().rfind(".")] + ".gcode") message = Message(self._output_devices[device]["description"], 0, False, -1) message.show() job = WriteMeshJob(filename, node.getMeshData()) job._sdcard = device job._message = message job.start() job.finished.connect(self._onWriteToSDFinished) return def _removableDrivesChanged(self): drives = self.getStorageDevice("LocalFileStorage").getRemovableDrives() for drive in drives: if drive not in self._output_devices: self.addOutputDevice(drive, { "id": drive, "function": self._writeToSD, "description": self._i18n_catalog.i18nc("Save button tooltip. {0} is sd card name", "Save to SD Card {0}").format(drive), "shortDescription": self._i18n_catalog.i18nc("Save button tooltip. {0} is sd card name", "Save to SD Card {0}").format(""), "icon": "save_sd", "priority": 1 }) drives_to_remove = [] for device in self._output_devices: if device not in drives: if self._output_devices[device]["function"] == self._writeToSD: drives_to_remove.append(device) for drive in drives_to_remove: self.removeOutputDevice(drive) def _onActiveMachineChanged(self): machine = self.getActiveMachine() if machine: Preferences.getInstance().setValue("cura/active_machine", machine.getName()) self._volume.setWidth(machine.getSettingValueByKey("machine_width")) self._volume.setHeight(machine.getSettingValueByKey("machine_height")) self._volume.setDepth(machine.getSettingValueByKey("machine_depth")) disallowed_areas = machine.getSettingValueByKey("machine_disallowed_areas") areas = [] if disallowed_areas: for area in disallowed_areas: areas.append(Polygon(numpy.array(area, numpy.float32))) self._volume.setDisallowedAreas(areas) self._volume.rebuild() offset = machine.getSettingValueByKey("machine_platform_offset") if offset: self._platform.setPosition(Vector(offset[0], offset[1], offset[2])) else: self._platform.setPosition(Vector(0.0, 0.0, 0.0)) def _onWriteToSDFinished(self, job): message = Message(self._i18n_catalog.i18nc("Saved to SD message, {0} is sdcard, {1} is filename", "Saved to SD Card {0} as {1}").format(job._sdcard, job.getFileName())) message.addAction( "eject", self._i18n_catalog.i18nc("Message action", "Eject"), "eject", self._i18n_catalog.i18nc("Message action tooltip, {0} is sdcard", "Eject SD Card {0}").format(job._sdcard) ) job._message.hide() message._sdcard = job._sdcard message.actionTriggered.connect(self._onMessageActionTriggered) message.show() def _onMessageActionTriggered(self, message, action): if action == "eject": self.getStorageDevice("LocalFileStorage").ejectRemovableDrive(message._sdcard) def _onFileLoaded(self, job): mesh = job.getResult() if mesh != None: node = SceneNode() node.setSelectable(True) node.setMeshData(mesh) node.setName(os.path.basename(job.getFileName())) op = AddSceneNodeOperation(node, self.getController().getScene().getRoot()) op.push() def _onJobFinished(self, job): if type(job) is not ReadMeshJob or not job.getResult(): return f = QUrl.fromLocalFile(job.getFileName()) if f in self._recent_files: self._recent_files.remove(f) self._recent_files.insert(0, f) if len(self._recent_files) > 10: del self._recent_files[10] pref = "" for path in self._recent_files: pref += path.toLocalFile() + ";" Preferences.getInstance().setValue("cura/recent_files", pref) self.recentFilesChanged.emit() def _reloadMeshFinished(self, job): job._node.setMeshData(job.getResult())
def run(self): self._i18n_catalog = i18nCatalog("cura"); self.addOutputDevice("local_file", { "id": "local_file", "function": self._writeToLocalFile, "description": self._i18n_catalog.i18nc("Save button tooltip", "Save to Disk"), "shortDescription": self._i18n_catalog.i18nc("Save button tooltip", "Save to Disk"), "icon": "save", "priority": 0 }) self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Setting up scene...")) controller = self.getController() controller.setActiveView("MeshView") controller.setCameraTool("CameraTool") controller.setSelectionTool("SelectionTool") t = controller.getTool("TranslateTool") if t: t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.ZAxis]) Selection.selectionChanged.connect(self.onSelectionChanged) root = controller.getScene().getRoot() self._platform = Platform(root) self._volume = BuildVolume.BuildVolume(root) self.getRenderer().setLightPosition(Vector(0, 150, 0)) self.getRenderer().setBackgroundColor(QColor(245, 245, 245)) self._physics = PlatformPhysics.PlatformPhysics(controller, self._volume) camera = Camera("3d", root) camera.setPosition(Vector(-150, 150, 300)) camera.setPerspective(True) camera.lookAt(Vector(0, 0, 0)) self._camera_animation = CameraAnimation.CameraAnimation() self._camera_animation.setCameraTool(self.getController().getTool("CameraTool")) controller.getScene().setActiveCamera("3d") self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Loading interface...")) self.setMainQml(Resources.getPath(Resources.QmlFilesLocation, "Cura.qml")) self.initializeEngine() self.getStorageDevice("LocalFileStorage").removableDrivesChanged.connect(self._removableDrivesChanged) if self.getMachines(): active_machine_pref = Preferences.getInstance().getValue("cura/active_machine") if active_machine_pref: for machine in self.getMachines(): if machine.getName() == active_machine_pref: self.setActiveMachine(machine) if not self.getActiveMachine(): self.setActiveMachine(self.getMachines()[0]) else: self.requestAddPrinter.emit() self._removableDrivesChanged() if self._engine.rootObjects: self.closeSplash() for file in self.getCommandLineOption("file", []): job = ReadMeshJob(os.path.abspath(file)) job.finished.connect(self._onFileLoaded) job.start() self.exec_()
class CuraApplication(QtApplication): def __init__(self): Resources.addResourcePath( os.path.join(QtApplication.getInstallPrefix(), "share", "cura")) if not hasattr(sys, "frozen"): Resources.addResourcePath( os.path.join(os.path.abspath(os.path.dirname(__file__)), "..")) super().__init__(name="cura", version="master") self.setWindowIcon( QIcon(Resources.getPath(Resources.ImagesLocation, "cura-icon.png"))) self.setRequiredPlugins([ "CuraEngineBackend", "MeshView", "LayerView", "STLReader", "SelectionTool", "CameraTool", "GCodeWriter", "LocalFileOutputDevice" ]) self._physics = None self._volume = None self._platform = None self._output_devices = {} self._print_information = None self._i18n_catalog = None self._previous_active_tool = None self._platform_activity = False self.activeMachineChanged.connect(self._onActiveMachineChanged) self.getController().getScene().sceneChanged.connect( self.updatePlatformActivity) Preferences.getInstance().addPreference("cura/active_machine", "") Preferences.getInstance().addPreference("cura/active_mode", "simple") Preferences.getInstance().addPreference("cura/recent_files", "") Preferences.getInstance().addPreference("cura/categories_expanded", "") Preferences.getInstance().addPreference("view/center_on_select", True) JobQueue.getInstance().jobFinished.connect(self._onJobFinished) self._recent_files = [] files = Preferences.getInstance().getValue("cura/recent_files").split( ";") for f in files: if not os.path.isfile(f): continue self._recent_files.append(QUrl.fromLocalFile(f)) ## Handle loading of all plugin types (and the backend explicitly) # \sa PluginRegistery def _loadPlugins(self): self._plugin_registry.addPluginLocation( os.path.join(QtApplication.getInstallPrefix(), "lib", "cura")) if not hasattr(sys, "frozen"): self._plugin_registry.addPluginLocation( os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "plugins")) self._plugin_registry.loadPlugin("ConsoleLogger") self._plugin_registry.loadPlugins() if self.getBackend() == None: raise RuntimeError("Could not load the backend plugin!") def addCommandLineOptions(self, parser): super().addCommandLineOptions(parser) parser.add_argument( "file", nargs="*", help="Files to load after starting the application.") def run(self): self._i18n_catalog = i18nCatalog("cura") i18nCatalog.setTagReplacements({ "filename": "font color=\"black\"", "message": "font color=UM.Theme.colors.message_text;", }) self.showSplashMessage( self._i18n_catalog.i18nc("Splash screen message", "Setting up scene...")) controller = self.getController() controller.setActiveView("MeshView") controller.setCameraTool("CameraTool") controller.setSelectionTool("SelectionTool") t = controller.getTool("TranslateTool") if t: t.setEnabledAxis( [ToolHandle.XAxis, ToolHandle.YAxis, ToolHandle.ZAxis]) Selection.selectionChanged.connect(self.onSelectionChanged) root = controller.getScene().getRoot() self._platform = Platform(root) self._volume = BuildVolume.BuildVolume(root) self.getRenderer().setLightPosition(Vector(0, 150, 0)) self.getRenderer().setBackgroundColor(QColor(245, 245, 245)) self._physics = PlatformPhysics.PlatformPhysics( controller, self._volume) camera = Camera("3d", root) camera.setPosition(Vector(-150, 150, 300)) camera.setPerspective(True) camera.lookAt(Vector(0, 0, 0)) self._camera_animation = CameraAnimation.CameraAnimation() self._camera_animation.setCameraTool( self.getController().getTool("CameraTool")) controller.getScene().setActiveCamera("3d") self.showSplashMessage( self._i18n_catalog.i18nc("Splash screen message", "Loading interface...")) self.setMainQml( Resources.getPath(Resources.QmlFilesLocation, "Cura.qml")) self.initializeEngine() if self.getMachines(): active_machine_pref = Preferences.getInstance().getValue( "cura/active_machine") if active_machine_pref: for machine in self.getMachines(): if machine.getName() == active_machine_pref: self.setActiveMachine(machine) if not self.getActiveMachine(): self.setActiveMachine(self.getMachines()[0]) else: self.requestAddPrinter.emit() if self._engine.rootObjects: self.closeSplash() for file in self.getCommandLineOption("file", []): self._openFile(file) self.exec_() # Handle Qt events def event(self, event): if event.type() == QEvent.FileOpen: self._openFile(event.file()) return super().event(event) def registerObjects(self, engine): engine.rootContext().setContextProperty("Printer", self) self._print_information = PrintInformation.PrintInformation() engine.rootContext().setContextProperty("PrintInformation", self._print_information) self._cura_actions = CuraActions.CuraActions(self) engine.rootContext().setContextProperty("CuraActions", self._cura_actions) def onSelectionChanged(self): if Selection.hasSelection(): if not self.getController().getActiveTool(): if self._previous_active_tool: self.getController().setActiveTool( self._previous_active_tool) self._previous_active_tool = None else: self.getController().setActiveTool("TranslateTool") if Preferences.getInstance().getValue("view/center_on_select"): self._camera_animation.setStart( self.getController().getTool("CameraTool").getOrigin()) self._camera_animation.setTarget( Selection.getSelectedObject(0).getWorldPosition()) self._camera_animation.start() else: if self.getController().getActiveTool(): self._previous_active_tool = self.getController( ).getActiveTool().getPluginId() self.getController().setActiveTool(None) else: self._previous_active_tool = None requestAddPrinter = pyqtSignal() activityChanged = pyqtSignal() @pyqtProperty(bool, notify=activityChanged) def getPlatformActivity(self): return self._platform_activity def updatePlatformActivity(self, node=None): count = 0 for node in DepthFirstIterator( self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue count += 1 self._platform_activity = True if count > 0 else False self.activityChanged.emit() ## Remove an object from the scene @pyqtSlot("quint64") def deleteObject(self, object_id): object = self.getController().getScene().findObject(object_id) if not object and object_id != 0: #Workaround for tool handles overlapping the selected object object = Selection.getSelectedObject(0) if object: if object.getParent(): group_node = object.getParent() if not group_node.callDecoration("isGroup"): op = RemoveSceneNodeOperation(object) else: while group_node.getParent().callDecoration("isGroup"): group_node = group_node.getParent() op = RemoveSceneNodeOperation(group_node) op.push() ## Create a number of copies of existing object. @pyqtSlot("quint64", int) def multiplyObject(self, object_id, count): node = self.getController().getScene().findObject(object_id) if not node and object_id != 0: #Workaround for tool handles overlapping the selected object node = Selection.getSelectedObject(0) if node: op = GroupedOperation() for i in range(count): new_node = SceneNode() new_node.setMeshData(node.getMeshData()) new_node.translate( Vector((i + 1) * node.getBoundingBox().width, node.getPosition().y, 0)) new_node.setOrientation(node.getOrientation()) new_node.setScale(node.getScale()) new_node.setSelectable(True) op.addOperation( AddSceneNodeOperation(new_node, node.getParent())) op.push() ## Center object on platform. @pyqtSlot("quint64") def centerObject(self, object_id): node = self.getController().getScene().findObject(object_id) if not node and object_id != 0: #Workaround for tool handles overlapping the selected object node = Selection.getSelectedObject(0) if node: op = SetTransformOperation(node, Vector()) op.push() ## Delete all mesh data on the scene. @pyqtSlot() def deleteAll(self): nodes = [] for node in DepthFirstIterator( self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) if nodes: op = GroupedOperation() for node in nodes: op.addOperation(RemoveSceneNodeOperation(node)) op.push() ## Reset all translation on nodes with mesh data. @pyqtSlot() def resetAllTranslation(self): nodes = [] for node in DepthFirstIterator( self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) if nodes: op = GroupedOperation() for node in nodes: op.addOperation(SetTransformOperation(node, Vector())) op.push() ## Reset all transformations on nodes with mesh data. @pyqtSlot() def resetAll(self): nodes = [] for node in DepthFirstIterator( self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) if nodes: op = GroupedOperation() for node in nodes: op.addOperation( SetTransformOperation(node, Vector(), Quaternion(), Vector(1, 1, 1))) op.push() ## Reload all mesh data on the screen from file. @pyqtSlot() def reloadAll(self): nodes = [] for node in DepthFirstIterator( self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) if not nodes: return for node in nodes: if not node.getMeshData(): continue file_name = node.getMeshData().getFileName() if file_name: job = ReadMeshJob(file_name) job._node = node job.finished.connect(self._reloadMeshFinished) job.start() ## Get logging data of the backend engine # \returns \type{string} Logging data @pyqtSlot(result=str) def getEngineLog(self): log = "" for entry in self.getBackend().getLog(): log += entry.decode() return log recentFilesChanged = pyqtSignal() @pyqtProperty("QVariantList", notify=recentFilesChanged) def recentFiles(self): return self._recent_files @pyqtSlot("QStringList") def setExpandedCategories(self, categories): categories = list(set(categories)) categories.sort() joined = ";".join(categories) if joined != Preferences.getInstance().getValue( "cura/categories_expanded"): Preferences.getInstance().setValue("cura/categories_expanded", joined) self.expandedCategoriesChanged.emit() expandedCategoriesChanged = pyqtSignal() @pyqtProperty("QStringList", notify=expandedCategoriesChanged) def expandedCategories(self): return Preferences.getInstance().getValue( "cura/categories_expanded").split(";") @pyqtSlot(str, result="QVariant") def getSettingValue(self, key): if not self.getActiveMachine(): return None return self.getActiveMachine().getSettingValueByKey(key) ## Change setting by key value pair @pyqtSlot(str, "QVariant") def setSettingValue(self, key, value): if not self.getActiveMachine(): return self.getActiveMachine().setSettingValueByKey(key, value) @pyqtSlot() def mergeSelected(self): self.groupSelected() try: group_node = Selection.getAllSelectedObjects()[0] except Exception as e: return multi_material_decorator = MultiMaterialDecorator.MultiMaterialDecorator( ) group_node.addDecorator(multi_material_decorator) # Reset the position of each node for node in group_node.getChildren(): new_position = node.getMeshData().getCenterPosition() new_position.setY(0) node.setPosition(new_position) # Use the previously found center of the group bounding box as the new location of the group group_node.setPosition(group_node.getBoundingBox().center) @pyqtSlot() def groupSelected(self): group_node = SceneNode() group_decorator = GroupDecorator() group_node.addDecorator(group_decorator) group_node.setParent(self.getController().getScene().getRoot()) for node in Selection.getAllSelectedObjects(): node.setParent(group_node) for node in group_node.getChildren(): Selection.remove(node) Selection.add(group_node) @pyqtSlot() def ungroupSelected(self): ungrouped_nodes = [] selected_objects = Selection.getAllSelectedObjects( )[:] #clone the list for node in selected_objects: if node.callDecoration("isGroup"): children_to_move = [] for child in node.getChildren(): if type(child) is SceneNode: children_to_move.append(child) for child in children_to_move: child.setParent(node.getParent()) Selection.add(child) child.callDecoration("setConvexHull", None) node.setParent(None) ungrouped_nodes.append(node) for node in ungrouped_nodes: Selection.remove(node) def _onActiveMachineChanged(self): machine = self.getActiveMachine() if machine: Preferences.getInstance().setValue("cura/active_machine", machine.getName()) self._volume.setWidth( machine.getSettingValueByKey("machine_width")) self._volume.setHeight( machine.getSettingValueByKey("machine_height")) self._volume.setDepth( machine.getSettingValueByKey("machine_depth")) disallowed_areas = machine.getSettingValueByKey( "machine_disallowed_areas") areas = [] if disallowed_areas: for area in disallowed_areas: areas.append(Polygon(numpy.array(area, numpy.float32))) self._volume.setDisallowedAreas(areas) self._volume.rebuild() offset = machine.getSettingValueByKey("machine_platform_offset") if offset: self._platform.setPosition( Vector(offset[0], offset[1], offset[2])) else: self._platform.setPosition(Vector(0.0, 0.0, 0.0)) def _onFileLoaded(self, job): node = job.getResult() if node != None: node.setSelectable(True) node.setName(os.path.basename(job.getFileName())) op = AddSceneNodeOperation( node, self.getController().getScene().getRoot()) op.push() def _onJobFinished(self, job): if type(job) is not ReadMeshJob or not job.getResult(): return f = QUrl.fromLocalFile(job.getFileName()) if f in self._recent_files: self._recent_files.remove(f) self._recent_files.insert(0, f) if len(self._recent_files) > 10: del self._recent_files[10] pref = "" for path in self._recent_files: pref += path.toLocalFile() + ";" Preferences.getInstance().setValue("cura/recent_files", pref) self.recentFilesChanged.emit() def _reloadMeshFinished(self, job): job._node = job.getResult() def _openFile(self, file): job = ReadMeshJob(os.path.abspath(file)) job.finished.connect(self._onFileLoaded) job.start()
def run(self): self._i18n_catalog = i18nCatalog("cura") i18nCatalog.setTagReplacements({ "filename": "font color=\"black\"", "message": "font color=UM.Theme.colors.message_text;", }) self.showSplashMessage( self._i18n_catalog.i18nc("Splash screen message", "Setting up scene...")) controller = self.getController() controller.setActiveView("MeshView") controller.setCameraTool("CameraTool") controller.setSelectionTool("SelectionTool") t = controller.getTool("TranslateTool") if t: t.setEnabledAxis( [ToolHandle.XAxis, ToolHandle.YAxis, ToolHandle.ZAxis]) Selection.selectionChanged.connect(self.onSelectionChanged) root = controller.getScene().getRoot() self._platform = Platform(root) self._volume = BuildVolume.BuildVolume(root) self.getRenderer().setLightPosition(Vector(0, 150, 0)) self.getRenderer().setBackgroundColor(QColor(245, 245, 245)) self._physics = PlatformPhysics.PlatformPhysics( controller, self._volume) camera = Camera("3d", root) camera.setPosition(Vector(-150, 150, 300)) camera.setPerspective(True) camera.lookAt(Vector(0, 0, 0)) self._camera_animation = CameraAnimation.CameraAnimation() self._camera_animation.setCameraTool( self.getController().getTool("CameraTool")) controller.getScene().setActiveCamera("3d") self.showSplashMessage( self._i18n_catalog.i18nc("Splash screen message", "Loading interface...")) self.setMainQml( Resources.getPath(Resources.QmlFilesLocation, "Cura.qml")) self.initializeEngine() if self.getMachines(): active_machine_pref = Preferences.getInstance().getValue( "cura/active_machine") if active_machine_pref: for machine in self.getMachines(): if machine.getName() == active_machine_pref: self.setActiveMachine(machine) if not self.getActiveMachine(): self.setActiveMachine(self.getMachines()[0]) else: self.requestAddPrinter.emit() if self._engine.rootObjects: self.closeSplash() for file in self.getCommandLineOption("file", []): self._openFile(file) self.exec_()
def run(self): self._i18n_catalog = i18nCatalog("cura") i18nCatalog.setTagReplacements({ "filename": "font color=\"black\"", "message": "font color=UM.Theme.colors.message_text;", }) self.showSplashMessage( self._i18n_catalog.i18nc("@info:progress", "Setting up scene...")) controller = self.getController() controller.setActiveView("SolidView") controller.setCameraTool("CameraTool") controller.setSelectionTool("SelectionTool") t = controller.getTool("TranslateTool") if t: t.setEnabledAxis( [ToolHandle.XAxis, ToolHandle.YAxis, ToolHandle.ZAxis]) Selection.selectionChanged.connect(self.onSelectionChanged) root = controller.getScene().getRoot() self._platform = Platform(root) self._volume = BuildVolume.BuildVolume(root) self.getRenderer().setBackgroundColor(QColor(245, 245, 245)) self._physics = PlatformPhysics.PlatformPhysics( controller, self._volume) camera = Camera("3d", root) camera.setPosition(Vector(-80, 250, 700)) camera.setPerspective(True) camera.lookAt(Vector(0, 0, 0)) controller.getScene().setActiveCamera("3d") self.getController().getTool("CameraTool").setOrigin(Vector(0, 100, 0)) self._camera_animation = CameraAnimation.CameraAnimation() self._camera_animation.setCameraTool( self.getController().getTool("CameraTool")) self.showSplashMessage( self._i18n_catalog.i18nc("@info:progress", "Loading interface...")) qmlRegisterSingletonType(MachineManagerModel.MachineManagerModel, "Cura", 1, 0, "MachineManager", MachineManagerModel.createMachineManagerModel) self.setMainQml( Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self._qml_import_paths.append( Resources.getPath(self.ResourceTypes.QmlFiles)) self.initializeEngine() if self._engine.rootObjects: self.closeSplash() for file in self.getCommandLineOption("file", []): self._openFile(file) for file_name in self._open_file_queue: #Open all the files that were queued up while plug-ins were loading. self._openFile(file_name) self._started = True self.exec_()
class CuraApplication(QtApplication): def __init__(self): Resources.addResourcePath(os.path.join(QtApplication.getInstallPrefix(), "share", "cura")) if not hasattr(sys, "frozen"): Resources.addResourcePath(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..")) super().__init__(name = "cura", version = "master") self.setWindowIcon(QIcon(Resources.getPath(Resources.ImagesLocation, "cura-icon.png"))) self.setRequiredPlugins([ "CuraEngineBackend", "MeshView", "LayerView", "STLReader", "SelectionTool", "CameraTool", "GCodeWriter", "LocalFileStorage" ]) self._physics = None self._volume = None self._platform = None self._output_devices = {} self._print_information = None self._i18n_catalog = None self._previous_active_tool = None self.activeMachineChanged.connect(self._onActiveMachineChanged) Preferences.getInstance().addPreference("cura/active_machine", "") Preferences.getInstance().addPreference("cura/active_mode", "simple") Preferences.getInstance().addPreference("cura/recent_files", "") Preferences.getInstance().addPreference("cura/categories_expanded", "") JobQueue.getInstance().jobFinished.connect(self._onJobFinished) self._recent_files = [] files = Preferences.getInstance().getValue("cura/recent_files").split(";") for f in files: if not os.path.isfile(f): continue self._recent_files.append(QUrl.fromLocalFile(f)) ## Handle loading of all plugin types (and the backend explicitly) # \sa PluginRegistery def _loadPlugins(self): self._plugin_registry.addPluginLocation(os.path.join(QtApplication.getInstallPrefix(), "lib", "cura")) if not hasattr(sys, "frozen"): self._plugin_registry.addPluginLocation(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "plugins")) self._plugin_registry.loadPlugins({ "type": "logger"}) self._plugin_registry.loadPlugins({ "type": "storage_device" }) self._plugin_registry.loadPlugins({ "type": "view" }) self._plugin_registry.loadPlugins({ "type": "mesh_reader" }) self._plugin_registry.loadPlugins({ "type": "mesh_writer" }) self._plugin_registry.loadPlugins({ "type": "tool" }) self._plugin_registry.loadPlugins({ "type": "extension" }) self._plugin_registry.loadPlugin("CuraEngineBackend") def addCommandLineOptions(self, parser): parser.add_argument("file", nargs="*", help="Files to load after starting the application.") def run(self): self._i18n_catalog = i18nCatalog("cura"); self.addOutputDevice("local_file", { "id": "local_file", "function": self._writeToLocalFile, "description": self._i18n_catalog.i18nc("Save button tooltip", "Save to Disk"), "icon": "save", "priority": 0 }) self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Setting up scene...")) controller = self.getController() controller.setActiveView("MeshView") controller.setCameraTool("CameraTool") controller.setSelectionTool("SelectionTool") t = controller.getTool("TranslateTool") if t: t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.ZAxis]) Selection.selectionChanged.connect(self.onSelectionChanged) root = controller.getScene().getRoot() self._platform = Platform(root) self._volume = BuildVolume.BuildVolume(root) self.getRenderer().setLightPosition(Vector(0, 150, 0)) self.getRenderer().setBackgroundColor(QColor(245, 245, 245)) self._physics = PlatformPhysics.PlatformPhysics(controller, self._volume) camera = Camera("3d", root) camera.setPosition(Vector(-150, 150, 300)) camera.setPerspective(True) camera.lookAt(Vector(0, 0, 0)) self._camera_animation = CameraAnimation.CameraAnimation() self._camera_animation.setCameraTool(self.getController().getTool("CameraTool")) controller.getScene().setActiveCamera("3d") self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Loading interface...")) self.setMainQml(Resources.getPath(Resources.QmlFilesLocation, "Cura.qml")) self.initializeEngine() self.getStorageDevice("LocalFileStorage").removableDrivesChanged.connect(self._removableDrivesChanged) if self.getMachines(): active_machine_pref = Preferences.getInstance().getValue("cura/active_machine") if active_machine_pref: for machine in self.getMachines(): if machine.getName() == active_machine_pref: self.setActiveMachine(machine) if not self.getActiveMachine(): self.setActiveMachine(self.getMachines()[0]) else: self.requestAddPrinter.emit() self._removableDrivesChanged() if self._engine.rootObjects: self.closeSplash() for file in self.getCommandLineOption("file", []): job = ReadMeshJob(os.path.abspath(file)) job.finished.connect(self._onFileLoaded) job.start() self.exec_() def registerObjects(self, engine): engine.rootContext().setContextProperty("Printer", self) self._print_information = PrintInformation.PrintInformation() engine.rootContext().setContextProperty("PrintInformation", self._print_information) self._cura_actions = CuraActions.CuraActions(self) engine.rootContext().setContextProperty("CuraActions", self._cura_actions) def onSelectionChanged(self): if Selection.hasSelection(): if not self.getController().getActiveTool(): if self._previous_active_tool: self.getController().setActiveTool(self._previous_active_tool) self._previous_active_tool = None else: self.getController().setActiveTool("TranslateTool") self._camera_animation.setStart(self.getController().getTool("CameraTool").getOrigin()) self._camera_animation.setTarget(Selection.getSelectedObject(0).getWorldPosition()) self._camera_animation.start() else: if self.getController().getActiveTool(): self._previous_active_tool = self.getController().getActiveTool().getPluginId() self.getController().setActiveTool(None) else: self._previous_active_tool = None requestAddPrinter = pyqtSignal() ## Remove an object from the scene @pyqtSlot("quint64") def deleteObject(self, object_id): object = self.getController().getScene().findObject(object_id) if not object and object_id != 0: #Workaround for tool handles overlapping the selected object object = Selection.getSelectedObject(0) if object: op = RemoveSceneNodeOperation(object) op.push() ## Create a number of copies of existing object. @pyqtSlot("quint64", int) def multiplyObject(self, object_id, count): node = self.getController().getScene().findObject(object_id) if not node and object_id != 0: #Workaround for tool handles overlapping the selected object node = Selection.getSelectedObject(0) if node: op = GroupedOperation() for i in range(count): new_node = SceneNode() new_node.setMeshData(node.getMeshData()) new_node.setScale(node.getScale()) new_node.translate(Vector((i + 1) * node.getBoundingBox().width, 0, 0)) new_node.setSelectable(True) op.addOperation(AddSceneNodeOperation(new_node, node.getParent())) op.push() ## Center object on platform. @pyqtSlot("quint64") def centerObject(self, object_id): node = self.getController().getScene().findObject(object_id) if not node and object_id != 0: #Workaround for tool handles overlapping the selected object node = Selection.getSelectedObject(0) if node: op = SetTransformOperation(node, Vector()) op.push() ## Delete all mesh data on the scene. @pyqtSlot() def deleteAll(self): nodes = [] for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) if nodes: op = GroupedOperation() for node in nodes: op.addOperation(RemoveSceneNodeOperation(node)) op.push() ## Reset all translation on nodes with mesh data. @pyqtSlot() def resetAllTranslation(self): nodes = [] for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) if nodes: op = GroupedOperation() for node in nodes: op.addOperation(SetTransformOperation(node, Vector())) op.push() ## Reset all transformations on nodes with mesh data. @pyqtSlot() def resetAll(self): nodes = [] for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) if nodes: op = GroupedOperation() for node in nodes: op.addOperation(SetTransformOperation(node, Vector(), Quaternion(), Vector(1, 1, 1))) op.push() ## Reload all mesh data on the screen from file. @pyqtSlot() def reloadAll(self): nodes = [] for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) if not nodes: return for node in nodes: if not node.getMeshData(): continue file_name = node.getMeshData().getFileName() if file_name: job = ReadMeshJob(file_name) job.finished.connect(lambda j: node.setMeshData(j.getResult())) job.start() ## Get logging data of the backend engine # \returns \type{string} Logging data @pyqtSlot(result=str) def getEngineLog(self): log = "" for entry in self.getBackend().getLog(): log += entry.decode() return log recentFilesChanged = pyqtSignal() @pyqtProperty("QVariantList", notify = recentFilesChanged) def recentFiles(self): return self._recent_files @pyqtSlot("QStringList") def setExpandedCategories(self, categories): categories = list(set(categories)) categories.sort() joined = ";".join(categories) if joined != Preferences.getInstance().getValue("cura/categories_expanded"): Preferences.getInstance().setValue("cura/categories_expanded", joined) self.expandedCategoriesChanged.emit() expandedCategoriesChanged = pyqtSignal() @pyqtProperty("QStringList", notify = expandedCategoriesChanged) def expandedCategories(self): return Preferences.getInstance().getValue("cura/categories_expanded").split(";") outputDevicesChanged = pyqtSignal() @pyqtProperty("QVariantMap", notify = outputDevicesChanged) def outputDevices(self): return self._output_devices @pyqtProperty("QStringList", notify = outputDevicesChanged) def outputDeviceNames(self): return self._output_devices.keys() @pyqtSlot(str, result = "QVariant") def getSettingValue(self, key): if not self.getActiveMachine(): return None return self.getActiveMachine().getSettingValueByKey(key) ## Change setting by key value pair @pyqtSlot(str, "QVariant") def setSettingValue(self, key, value): if not self.getActiveMachine(): return self.getActiveMachine().setSettingValueByKey(key, value) ## Add an output device that can be written to. # # \param id \type{string} The identifier used to identify the device. # \param device \type{StorageDevice} A dictionary of device information. # It should contains the following: # - function: A function to be called when trying to write to the device. Will be passed the device id as first parameter. # - description: A translated string containing a description of what happens when writing to the device. # - icon: The icon to use to represent the device. # - priority: The priority of the device. The device with the highest priority will be used as the default device. def addOutputDevice(self, id, device): self._output_devices[id] = device self.outputDevicesChanged.emit() ## Remove output device # \param id \type{string} The identifier used to identify the device. # \sa PrinterApplication::addOutputDevice() def removeOutputDevice(self, id): if id in self._output_devices: del self._output_devices[id] self.outputDevicesChanged.emit() @pyqtSlot(str) def writeToOutputDevice(self, device): self._output_devices[device]["function"](device) writeToLocalFileRequested = pyqtSignal() def _writeToLocalFile(self, device): self.writeToLocalFileRequested.emit() def _writeToSD(self, device): for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue try: path = self.getStorageDevice("LocalFileStorage").getRemovableDrives()[device] except KeyError: Logger.log("e", "Tried to write to unknown SD card %s", device) return filename = os.path.join(path, node.getName()[0:node.getName().rfind(".")] + ".gcode") job = WriteMeshJob(filename, node.getMeshData()) job._sdcard = device job.start() job.finished.connect(self._onWriteToSDFinished) return def _removableDrivesChanged(self): drives = self.getStorageDevice("LocalFileStorage").getRemovableDrives() for drive in drives: if drive not in self._output_devices: self.addOutputDevice(drive, { "id": drive, "function": self._writeToSD, "description": self._i18n_catalog.i18nc("Save button tooltip. {0} is sd card name", "Save to SD Card {0}").format(drive), "icon": "save_sd", "priority": 1 }) drives_to_remove = [] for device in self._output_devices: if device not in drives: if self._output_devices[device]["function"] == self._writeToSD: drives_to_remove.append(device) for drive in drives_to_remove: self.removeOutputDevice(drive) def _onActiveMachineChanged(self): machine = self.getActiveMachine() if machine: Preferences.getInstance().setValue("cura/active_machine", machine.getName()) self._volume.setWidth(machine.getSettingValueByKey("machine_width")) self._volume.setHeight(machine.getSettingValueByKey("machine_height")) self._volume.setDepth(machine.getSettingValueByKey("machine_depth")) disallowed_areas = machine.getSettingValueByKey("machine_disallowed_areas") areas = [] if disallowed_areas: for area in disallowed_areas: areas.append(Polygon(numpy.array(area, numpy.float32))) self._volume.setDisallowedAreas(areas) self._volume.rebuild() offset = machine.getSettingValueByKey("machine_platform_offset") if offset: self._platform.setPosition(Vector(offset[0], offset[1], offset[2])) else: self._platform.setPosition(Vector(0.0, 0.0, 0.0)) def _onWriteToSDFinished(self, job): message = Message(self._i18n_catalog.i18nc("Saved to SD message, {0} is sdcard, {1} is filename", "Saved to SD Card {0} as {1}").format(job._sdcard, job.getFileName())) message.addAction( "eject", self._i18n_catalog.i18nc("Message action", "Eject"), "eject", self._i18n_catalog.i18nc("Message action tooltip, {0} is sdcard", "Eject SD Card {0}").format(job._sdcard) ) message._sdcard = job._sdcard message.actionTriggered.connect(self._onMessageActionTriggered) message.show() def _onMessageActionTriggered(self, message, action): if action == "eject": self.getStorageDevice("LocalFileStorage").ejectRemovableDrive(message._sdcard) def _onFileLoaded(self, job): mesh = job.getResult() if mesh != None: node = SceneNode() node.setSelectable(True) node.setMeshData(mesh) node.setName(os.path.basename(job.getFileName())) op = AddSceneNodeOperation(node, self.getController().getScene().getRoot()) op.push() def _onJobFinished(self, job): if type(job) is not ReadMeshJob: return f = QUrl.fromLocalFile(job.getFileName()) if f in self._recent_files: self._recent_files.remove(f) self._recent_files.insert(0, f) if len(self._recent_files) > 10: del self._recent_files[10] pref = "" for path in self._recent_files: pref += path.toLocalFile() + ";" Preferences.getInstance().setValue("cura/recent_files", pref) self.recentFilesChanged.emit()
def run(self): self._i18n_catalog = i18nCatalog("cura"); self.addOutputDevice("local_file", { "id": "local_file", "function": self._writeToLocalFile, "description": self._i18n_catalog.i18nc("Save button tooltip", "Save to Disk"), "icon": "save", "priority": 0 }) self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Setting up scene...")) controller = self.getController() controller.setActiveView("MeshView") controller.setCameraTool("CameraTool") controller.setSelectionTool("SelectionTool") t = controller.getTool("TranslateTool") if t: t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.ZAxis]) Selection.selectionChanged.connect(self.onSelectionChanged) root = controller.getScene().getRoot() self._platform = Platform(root) self._volume = BuildVolume.BuildVolume(root) self.getRenderer().setLightPosition(Vector(0, 150, 0)) self.getRenderer().setBackgroundColor(QColor(245, 245, 245)) self._physics = PlatformPhysics.PlatformPhysics(controller, self._volume) camera = Camera("3d", root) camera.setPosition(Vector(-150, 150, 300)) camera.setPerspective(True) camera.lookAt(Vector(0, 0, 0)) self._camera_animation = CameraAnimation.CameraAnimation() self._camera_animation.setCameraTool(self.getController().getTool("CameraTool")) controller.getScene().setActiveCamera("3d") self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Loading interface...")) self.setMainQml(Resources.getPath(Resources.QmlFilesLocation, "Cura.qml")) self.initializeEngine() self.getStorageDevice("LocalFileStorage").removableDrivesChanged.connect(self._removableDrivesChanged) if self.getMachines(): active_machine_pref = Preferences.getInstance().getValue("cura/active_machine") if active_machine_pref: for machine in self.getMachines(): if machine.getName() == active_machine_pref: self.setActiveMachine(machine) if not self.getActiveMachine(): self.setActiveMachine(self.getMachines()[0]) else: self.requestAddPrinter.emit() self._removableDrivesChanged() if self._engine.rootObjects: self.closeSplash() for file in self.getCommandLineOption("file", []): job = ReadMeshJob(os.path.abspath(file)) job.finished.connect(self._onFileLoaded) job.start() self.exec_()
class CuraApplication(QtApplication): def __init__(self): Resources.addResourcePath(os.path.join(QtApplication.getInstallPrefix(), "share", "cura")) if not hasattr(sys, "frozen"): Resources.addResourcePath(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..")) super().__init__(name = "cura", version = "master") self.setRequiredPlugins([ "CuraEngineBackend", "MeshView", "LayerView", "STLReader", "SelectionTool", "CameraTool", "GCodeWriter", "LocalFileStorage" ]) self._physics = None self._volume = None self._platform = None self._output_devices = {} self._print_information = None self._i18n_catalog = None self.activeMachineChanged.connect(self._onActiveMachineChanged) Preferences.getInstance().addPreference("cura/active_machine", "") Preferences.getInstance().addPreference("cura/active_mode", "simple") ## Handle loading of all plugin types (and the backend explicitly) # \sa PluginRegistery def _loadPlugins(self): self._plugin_registry.addPluginLocation(os.path.join(QtApplication.getInstallPrefix(), "lib", "cura")) if not hasattr(sys, "frozen"): self._plugin_registry.addPluginLocation(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "plugins")) self._plugin_registry.loadPlugins({ "type": "logger"}) self._plugin_registry.loadPlugins({ "type": "storage_device" }) self._plugin_registry.loadPlugins({ "type": "view" }) self._plugin_registry.loadPlugins({ "type": "mesh_reader" }) self._plugin_registry.loadPlugins({ "type": "mesh_writer" }) self._plugin_registry.loadPlugins({ "type": "tool" }) self._plugin_registry.loadPlugins({ "type": "extension" }) self._plugin_registry.loadPlugin("CuraEngineBackend") def addCommandLineOptions(self, parser): parser.add_argument("file", nargs="*", help="Files to load after starting the application.") def run(self): self._i18n_catalog = i18nCatalog("cura"); self.addOutputDevice("local_file", { "id": "local_file", "function": self._writeToLocalFile, "description": self._i18n_catalog.i18nc("Save button tooltip", "Save to Disk"), "icon": "save", "priority": 0 }) self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Setting up scene...")) controller = self.getController() controller.setActiveView("MeshView") controller.setCameraTool("CameraTool") controller.setSelectionTool("SelectionTool") t = controller.getTool("TranslateTool") if t: t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.ZAxis]) Selection.selectionChanged.connect(self.onSelectionChanged) root = controller.getScene().getRoot() self._platform = Platform(root) self._volume = BuildVolume.BuildVolume(root) self.getRenderer().setLightPosition(Vector(0, 150, 0)) self.getRenderer().setBackgroundColor(QColor(245, 245, 245)) self._physics = PlatformPhysics.PlatformPhysics(controller, self._volume) camera = Camera("3d", root) camera.setPosition(Vector(-150, 150, 300)) camera.setPerspective(True) camera.lookAt(Vector(0, 0, 0)) self._camera_animation = CameraAnimation.CameraAnimation() self._camera_animation.setCameraTool(self.getController().getTool("CameraTool")) controller.getScene().setActiveCamera("3d") self.showSplashMessage(self._i18n_catalog.i18nc("Splash screen message", "Loading interface...")) self.setMainQml(Resources.getPath(Resources.QmlFilesLocation, "Cura.qml")) self.initializeEngine() self.getStorageDevice("LocalFileStorage").removableDrivesChanged.connect(self._removableDrivesChanged) if self.getMachines(): active_machine_pref = Preferences.getInstance().getValue("cura/active_machine") if active_machine_pref: for machine in self.getMachines(): if machine.getName() == active_machine_pref: self.setActiveMachine(machine) if not self.getActiveMachine(): self.setActiveMachine(self.getMachines()[0]) else: self.requestAddPrinter.emit() self._removableDrivesChanged() if self._engine.rootObjects: self.closeSplash() for file in self.getCommandLineOption("file", []): job = ReadMeshJob(os.path.abspath(file)) job.finished.connect(self._onFileLoaded) job.start() self.exec_() def registerObjects(self, engine): engine.rootContext().setContextProperty("Printer", self) self._print_information = PrintInformation.PrintInformation() engine.rootContext().setContextProperty("PrintInformation", self._print_information) def onSelectionChanged(self): if Selection.hasSelection(): if not self.getController().getActiveTool(): self.getController().setActiveTool("TranslateTool") self._camera_animation.setStart(self.getController().getTool("CameraTool").getOrigin()) self._camera_animation.setTarget(Selection.getSelectedObject(0).getWorldPosition()) self._camera_animation.start() else: if self.getController().getActiveTool(): self.getController().setActiveTool(None) requestAddPrinter = pyqtSignal() ## Remove an object from the scene @pyqtSlot("quint64") def deleteObject(self, object_id): object = self.getController().getScene().findObject(object_id) if object: op = RemoveSceneNodeOperation(object) op.push() ## Create a number of copies of existing object. @pyqtSlot("quint64", int) def multiplyObject(self, object_id, count): node = self.getController().getScene().findObject(object_id) if node: op = GroupedOperation() for i in range(count): new_node = SceneNode() new_node.setMeshData(node.getMeshData()) new_node.setScale(node.getScale()) new_node.translate(Vector((i + 1) * node.getBoundingBox().width, 0, 0)) new_node.setSelectable(True) op.addOperation(AddSceneNodeOperation(new_node, node.getParent())) op.push() ## Center object on platform. @pyqtSlot("quint64") def centerObject(self, object_id): node = self.getController().getScene().findObject(object_id) if node: op = SetTransformOperation(node, Vector()) op.push() ## Delete all mesh data on the scene. @pyqtSlot() def deleteAll(self): nodes = [] for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) if nodes: op = GroupedOperation() for node in nodes: op.addOperation(RemoveSceneNodeOperation(node)) op.push() ## Reset all translation on nodes with mesh data. @pyqtSlot() def resetAllTranslation(self): nodes = [] for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) if nodes: op = GroupedOperation() for node in nodes: op.addOperation(SetTransformOperation(node, Vector())) op.push() ## Reset all transformations on nodes with mesh data. @pyqtSlot() def resetAll(self): nodes = [] for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) if nodes: op = GroupedOperation() for node in nodes: op.addOperation(SetTransformOperation(node, Vector(), Quaternion(), Vector(1, 1, 1))) op.push() ## Reload all mesh data on the screen from file. @pyqtSlot() def reloadAll(self): nodes = [] for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue nodes.append(node) if not nodes: return for node in nodes: if not node.getMeshData(): continue file_name = node.getMeshData().getFileName() if file_name: job = ReadMeshJob(file_name) job.finished.connect(lambda j: node.setMeshData(j.getResult())) job.start() ## Get logging data of the backend engine # \returns \type{string} Logging data @pyqtSlot(result=str) def getEngineLog(self): log = "" for entry in self.getBackend().getLog(): log += entry.decode() return log outputDevicesChanged = pyqtSignal() @pyqtProperty("QVariantMap", notify = outputDevicesChanged) def outputDevices(self): return self._output_devices @pyqtProperty("QStringList", notify = outputDevicesChanged) def outputDeviceNames(self): return self._output_devices.keys() @pyqtSlot(str, result = "QVariant") def getSettingValue(self, key): if not self.getActiveMachine(): return None return self.getActiveMachine().getSettingValueByKey(key) ## Change setting by key value pair @pyqtSlot(str, "QVariant") def setSettingValue(self, key, value): if not self.getActiveMachine(): return self.getActiveMachine().setSettingValueByKey(key, value) ## Add an output device that can be written to. # # \param id \type{string} The identifier used to identify the device. # \param device \type{StorageDevice} A dictionary of device information. # It should contains the following: # - function: A function to be called when trying to write to the device. Will be passed the device id as first parameter. # - description: A translated string containing a description of what happens when writing to the device. # - icon: The icon to use to represent the device. # - priority: The priority of the device. The device with the highest priority will be used as the default device. def addOutputDevice(self, id, device): self._output_devices[id] = device self.outputDevicesChanged.emit() ## Remove output device # \param id \type{string} The identifier used to identify the device. # \sa PrinterApplication::addOutputDevice() def removeOutputDevice(self, id): if id in self._output_devices: del self._output_devices[id] self.outputDevicesChanged.emit() @pyqtSlot(str) def writeToOutputDevice(self, device): self._output_devices[device]["function"](device) writeToLocalFileRequested = pyqtSignal() def _writeToLocalFile(self, device): self.writeToLocalFileRequested.emit() def _writeToSD(self, device): for node in DepthFirstIterator(self.getController().getScene().getRoot()): if type(node) is not SceneNode or not node.getMeshData(): continue try: path = self.getStorageDevice("LocalFileStorage").getRemovableDrives()[device] except KeyError: Logger.log("e", "Tried to write to unknown SD card %s", device) return filename = os.path.join(path, node.getName()[0:node.getName().rfind(".")] + ".gcode") job = WriteMeshJob(filename, node.getMeshData()) job._sdcard = device job.start() job.finished.connect(self._onWriteToSDFinished) return def _removableDrivesChanged(self): drives = self.getStorageDevice("LocalFileStorage").getRemovableDrives() for drive in drives: if drive not in self._output_devices: self.addOutputDevice(drive, { "id": drive, "function": self._writeToSD, "description": self._i18n_catalog.i18nc("Save button tooltip. {0} is sd card name", "Save to SD Card {0}".format(drive)), "icon": "save_sd", "priority": 1 }) drives_to_remove = [] for device in self._output_devices: if device not in drives: if self._output_devices[device]["function"] == self._writeToSD: drives_to_remove.append(device) for drive in drives_to_remove: self.removeOutputDevice(drive) def _onActiveMachineChanged(self): machine = self.getActiveMachine() if machine: Preferences.getInstance().setValue("cura/active_machine", machine.getName()) self._volume.setWidth(machine.getSettingValueByKey("machine_width")) self._volume.setHeight(machine.getSettingValueByKey("machine_height")) self._volume.setDepth(machine.getSettingValueByKey("machine_depth")) disallowed_areas = machine.getSettingValueByKey("machine_disallowed_areas") areas = [] if disallowed_areas: for area in disallowed_areas: polygon = [] polygon.append(Vector(area[0][0], 0.2, area[0][1])) polygon.append(Vector(area[1][0], 0.2, area[1][1])) polygon.append(Vector(area[2][0], 0.2, area[2][1])) polygon.append(Vector(area[3][0], 0.2, area[3][1])) areas.append(polygon) self._volume.setDisallowedAreas(areas) self._volume.rebuild() if self.getController().getTool("ScaleTool"): self.getController().getTool("ScaleTool").setMaximumBounds(self._volume.getBoundingBox()) offset = machine.getSettingValueByKey("machine_platform_offset") if offset: self._platform.setPosition(Vector(offset[0], offset[1], offset[2])) else: self._platform.setPosition(Vector(0.0, 0.0, 0.0)) def _onWriteToSDFinished(self, job): message = Message(self._i18n_catalog.i18nc("Saved to SD message, {0} is sdcard, {1} is filename", "Saved to SD Card {0} as {1}").format(job._sdcard, job.getFileName())) message.addAction( "eject", self._i18n_catalog.i18nc("Message action", "Eject"), "eject", self._i18n_catalog.i18nc("Message action tooltip, {0} is sdcard", "Eject SD Card {0}".format(job._sdcard)) ) message._sdcard = job._sdcard message.actionTriggered.connect(self._onMessageActionTriggered) message.show() def _onMessageActionTriggered(self, message, action): if action == "eject": self.getStorageDevice("LocalFileStorage").ejectRemovableDrive(message._sdcard) def _onFileLoaded(self, job): mesh = job.getResult() if mesh != None: node = SceneNode() node.setSelectable(True) node.setMeshData(mesh) node.setName(os.path.basename(job.getFileName())) op = AddSceneNodeOperation(node, self.getController().getScene().getRoot()) op.push()