123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- from UM.Logger import Logger
- from PyQt6.QtCore import Qt, pyqtSlot, QObject, QTimer
- from PyQt6.QtWidgets import QApplication
- from UM.Scene.Camera import Camera
- from cura.UI.ObjectsModel import ObjectsModel
- from cura.Machines.Models.MultiBuildPlateModel import MultiBuildPlateModel
- from cura.Scene.CuraSceneNode import CuraSceneNode
- from UM.Application import Application
- from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
- from UM.Scene.SceneNode import SceneNode
- from UM.Scene.Selection import Selection
- from UM.Signal import Signal
- class CuraSceneController(QObject):
- activeBuildPlateChanged = Signal()
- def __init__(self, objects_model: ObjectsModel, multi_build_plate_model: MultiBuildPlateModel) -> None:
- super().__init__()
- self._objects_model = objects_model
- self._multi_build_plate_model = multi_build_plate_model
- self._active_build_plate = -1
- self._last_selected_index = 0
- self._max_build_plate = 1 # default
- self._change_timer = QTimer()
- self._change_timer.setInterval(100)
- self._change_timer.setSingleShot(True)
- self._change_timer.timeout.connect(self.updateMaxBuildPlate)
- Application.getInstance().getController().getScene().sceneChanged.connect(self.updateMaxBuildPlateDelayed)
- def updateMaxBuildPlateDelayed(self, *args):
- if args:
- source = args[0]
- else:
- source = None
- if not isinstance(source, SceneNode) or isinstance(source, Camera):
- return
- self._change_timer.start()
- def updateMaxBuildPlate(self, *args):
- global_stack = Application.getInstance().getGlobalContainerStack()
- if global_stack:
- scene_has_support_meshes = self._sceneHasSupportMeshes() # TODO: see if this can be cached
- if scene_has_support_meshes != global_stack.getProperty("support_meshes_present", "value"):
- # Adjust the setting without having the setting value in an InstanceContainer
- setting_definitions = global_stack.definition.findDefinitions(key="support_meshes_present")
- if setting_definitions:
- # Recreate the setting definition because the default_value is readonly
- definition_dict = setting_definitions[0].serialize_to_dict()
- definition_dict["enabled"] = False # The enabled property has a value that would need to be evaluated
- definition_dict["default_value"] = scene_has_support_meshes
- relations = setting_definitions[0].relations # Relations are wiped when deserializing from a dict
- setting_definitions[0].deserialize(definition_dict)
- # Restore relations and notify them that the setting has changed
- for relation in relations:
- setting_definitions[0].relations.append(relation)
- global_stack.propertyChanged.emit(relation.target.key, "enabled")
- max_build_plate = self._calcMaxBuildPlate()
- changed = False
- if max_build_plate != self._max_build_plate:
- self._max_build_plate = max_build_plate
- changed = True
- if changed:
- self._multi_build_plate_model.setMaxBuildPlate(self._max_build_plate)
- build_plates = [{"name": "Build Plate %d" % (i + 1), "buildPlateNumber": i} for i in range(self._max_build_plate + 1)]
- self._multi_build_plate_model.setItems(build_plates)
- if self._active_build_plate > self._max_build_plate:
- build_plate_number = 0
- if self._last_selected_index >= 0: # go to the buildplate of the item you last selected
- item = self._objects_model.getItem(self._last_selected_index)
- if "node" in item:
- node = item["node"]
- build_plate_number = node.callDecoration("getBuildPlateNumber")
- self.setActiveBuildPlate(build_plate_number)
- # self.buildPlateItemsChanged.emit() # TODO: necessary after setItems?
- def _calcMaxBuildPlate(self):
- max_build_plate = 0
- for node in DepthFirstIterator(Application.getInstance().getController().getScene().getRoot()):
- if node.callDecoration("isSliceable"):
- build_plate_number = node.callDecoration("getBuildPlateNumber")
- if build_plate_number is None:
- build_plate_number = 0
- max_build_plate = max(build_plate_number, max_build_plate)
- return max_build_plate
- def _sceneHasSupportMeshes(self):
- root = Application.getInstance().getController().getScene().getRoot()
- for node in root.getAllChildren():
- if isinstance(node, CuraSceneNode):
- per_mesh_stack = node.callDecoration("getStack")
- if per_mesh_stack and per_mesh_stack.getProperty("support_mesh", "value"):
- return True
- return False
- @pyqtSlot(int)
- def changeSelection(self, index):
- """Either select or deselect an item"""
- modifiers = QApplication.keyboardModifiers()
- ctrl_is_active = modifiers & Qt.KeyboardModifier.ControlModifier
- shift_is_active = modifiers & Qt.KeyboardModifier.ShiftModifier
- if ctrl_is_active:
- item = self._objects_model.getItem(index)
- node = item["node"]
- if Selection.isSelected(node):
- Selection.remove(node)
- else:
- Selection.add(node)
- elif shift_is_active:
- polarity = 1 if index + 1 > self._last_selected_index else -1
- for i in range(self._last_selected_index, index + polarity, polarity):
- item = self._objects_model.getItem(i)
- node = item["node"]
- Selection.add(node)
- else:
- # Single select
- item = self._objects_model.getItem(index)
- node = item["node"]
- build_plate_number = node.callDecoration("getBuildPlateNumber")
- if build_plate_number is not None and build_plate_number != -1:
- self.setActiveBuildPlate(build_plate_number)
- Selection.clear()
- Selection.add(node)
- self._last_selected_index = index
- @pyqtSlot(int)
- def setActiveBuildPlate(self, nr):
- if nr == self._active_build_plate:
- return
- Logger.debug(f"Selected build plate: {nr}")
- self._active_build_plate = nr
- Selection.clear()
- self._multi_build_plate_model.setActiveBuildPlate(nr)
- self._objects_model.setActiveBuildPlate(nr)
- self.activeBuildPlateChanged.emit()
- @staticmethod
- def createCuraSceneController():
- objects_model = Application.getInstance().getObjectsModel()
- multi_build_plate_model = Application.getInstance().getMultiBuildPlateModel()
- return CuraSceneController(objects_model = objects_model, multi_build_plate_model = multi_build_plate_model)
|