from UM.Logger import Logger from PyQt5.QtCore import Qt, pyqtSlot, QObject from PyQt5.QtWidgets import QApplication from cura.ObjectsModel import ObjectsModel from cura.Machines.Models.MultiBuildPlateModel import MultiBuildPlateModel 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): 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 Application.getInstance().getController().getScene().sceneChanged.connect(self.updateMaxBuildPlate) # it may be a bit inefficient when changing a lot simultaneously def updateMaxBuildPlate(self, *args): if args: source = args[0] else: source = None if not isinstance(source, SceneNode): return 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 ## Either select or deselect an item @pyqtSlot(int) def changeSelection(self, index): modifiers = QApplication.keyboardModifiers() ctrl_is_active = modifiers & Qt.ControlModifier shift_is_active = modifiers & Qt.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.log("d", "Select build plate: %s" % 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)