diff --git a/cura/CuraActions.py b/cura/CuraActions.py index 663da3ec09..c313488cac 100644 --- a/cura/CuraActions.py +++ b/cura/CuraActions.py @@ -156,13 +156,8 @@ class CuraActions(QObject): if not nodes_to_change: Logger.log("d", "Nothing to change.") - # If there are no changes to make, we still need to reset the selected extruders. - # This is a workaround for checked menu items being deselected while still being - # selected. - #ExtruderManager.getInstance().resetSelectedObjectExtruders() return - Logger.log("d", "Yes: %s", nodes_to_change) for node in nodes_to_change: operation.addOperation(SetBuildPlateNumberOperation(node, build_plate_nr)) operation.push() diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 5111b9b52a..7a6994e83e 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -79,6 +79,8 @@ from cura.Settings.ContainerManager import ContainerManager from cura.Settings.GlobalStack import GlobalStack from cura.Settings.ExtruderStack import ExtruderStack +from cura.ObjectManager import ObjectManager + from PyQt5.QtCore import QUrl, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS from UM.FlameProfiler import pyqtSlot from PyQt5.QtGui import QColor, QIcon @@ -205,6 +207,7 @@ class CuraApplication(QtApplication): self._machine_action_manager = MachineActionManager.MachineActionManager() self._machine_manager = None # This is initialized on demand. self._material_manager = None + self._object_manager = None self._setting_inheritance_manager = None self._simple_mode_settings_manager = None @@ -292,8 +295,6 @@ class CuraApplication(QtApplication): preferences.addPreference("metadata/setting_version", 0) preferences.setValue("metadata/setting_version", self.SettingVersion) #Don't make it equal to the default so that the setting version always gets written to the file. - preferences.addPreference("view/build_plate_number", 0) - preferences.addPreference("cura/active_mode", "simple") preferences.addPreference("cura/categories_expanded", "") @@ -384,7 +385,7 @@ class CuraApplication(QtApplication): # research self._num_build_plates = 1 # default - self._active_build_plate = 1 + self._active_build_plate = 0 def _onEngineCreated(self): self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider()) @@ -717,6 +718,9 @@ class CuraApplication(QtApplication): qmlRegisterSingletonType(SimpleModeSettingsManager, "Cura", 1, 2, "SimpleModeSettingsManager", self.getSimpleModeSettingsManager) + Logger.log("d", " #### going to register object manager") + qmlRegisterSingletonType(ObjectManager, "Cura", 1, 2, "ObjectManager", self.getObjectManager) + qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager) self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles)) @@ -744,6 +748,11 @@ class CuraApplication(QtApplication): self._material_manager = MaterialManager.createMaterialManager() return self._material_manager + def getObjectManager(self, *args): + if self._object_manager is None: + self._object_manager = ObjectManager.createObjectManager() + return self._object_manager + def getSettingInheritanceManager(self, *args): if self._setting_inheritance_manager is None: self._setting_inheritance_manager = SettingInheritanceManager.createSettingInheritanceManager() @@ -799,6 +808,7 @@ class CuraApplication(QtApplication): qmlRegisterType(QualitySettingsModel, "Cura", 1, 0, "QualitySettingsModel") qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator") qmlRegisterType(UserChangesModel, "Cura", 1, 1, "UserChangesModel") + # qmlRegisterSingletonType(ObjectManager, "Cura", 1, 0, "ObjectManager", ObjectManager.createObjectManager) qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.createContainerManager) @@ -1464,7 +1474,6 @@ class CuraApplication(QtApplication): def setActiveBuildPlate(self, nr): Logger.log("d", "Select build plate: %s" % nr) self._active_build_plate = nr - Preferences.setValue("view/build_plate_number", self._active_build_plate) self.activeBuildPlateChanged.emit() diff --git a/cura/ObjectManager.py b/cura/ObjectManager.py new file mode 100644 index 0000000000..fc6d343252 --- /dev/null +++ b/cura/ObjectManager.py @@ -0,0 +1,68 @@ +from UM.Logger import Logger +from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot +from UM.Application import Application +from UM.Qt.ListModel import ListModel +from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator +from UM.Scene.SceneNode import SceneNode +from UM.Scene.Selection import Selection +from PyQt5.QtCore import Qt +from PyQt5.QtWidgets import QApplication + + +class ObjectManager(ListModel): + def __init__(self): + super().__init__() + self._last_selected_index = 0 + Application.getInstance().getController().getScene().sceneChanged.connect(self._update) + + def _update(self, *args): + nodes = [] + for node in DepthFirstIterator(Application.getInstance().getController().getScene().getRoot()): + if type(node) is not SceneNode or (not node.getMeshData() and not node.callDecoration("getLayerData")): + continue + nodes.append({ + "name": node.getName(), + "isSelected": Selection.isSelected(node), + "buildPlateNumber": node.callDecoration("getBuildPlateNumber"), + "node": node + }) + nodes = sorted(nodes, key=lambda n: n["name"]) + self.setItems(nodes) + + self.itemsChanged.emit() + + ## 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.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.getItem(i) + node = item["node"] + Selection.add(node) + else: + # Single select + item = self.getItem(index) + node = item["node"] + Selection.clear() + Selection.add(node) + build_plate_number = node.callDecoration("getBuildPlateNumber") + if build_plate_number is not None and build_plate_number != -1: + Application.getInstance().setActiveBuildPlate(build_plate_number) + + self._last_selected_index = index + + @staticmethod + def createObjectManager(): + return ObjectManager() diff --git a/cura/Scene/BuildPlateDecorator.py b/cura/Scene/BuildPlateDecorator.py index 8d91f9e90a..2125d731de 100644 --- a/cura/Scene/BuildPlateDecorator.py +++ b/cura/Scene/BuildPlateDecorator.py @@ -9,26 +9,9 @@ class BuildPlateDecorator(SceneNodeDecorator): def setBuildPlateNumber(self, nr): self._build_plate_number = nr - # self.getNode().childrenChanged.connect(self._onChildrenChanged) def getBuildPlateNumber(self): return self._build_plate_number - # def setNode(self, node): - # super().setNode(node) - # self.getNode().childrenChanged.connect(self._onChildrenChanged) - - # def _onChildrenChanged(self, node): - # if not self.getNode().hasChildren(): - # # A group that no longer has children may remove itself from the scene - # self._old_parent = self.getNode().getParent() - # self.getNode().setParent(None) - # Selection.remove(self.getNode()) - # else: - # # A group that has removed itself from the scene because it had no children may add itself back to the scene when a child is added to it - # if not self.getNode().getParent() and self._old_parent: - # self.getNode().setParent(self._old_parent) - # self._old_parent = None - def __deepcopy__(self, memo): return BuildPlateDecorator() diff --git a/plugins/SolidView/SolidView.py b/plugins/SolidView/SolidView.py index 625223a097..d37fbb7c9d 100644 --- a/plugins/SolidView/SolidView.py +++ b/plugins/SolidView/SolidView.py @@ -71,7 +71,7 @@ class SolidView(View): else: self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0))) - activeBuildPlateNumber = Preferences.getInstance().getValue("view/build_plate_number") or 0 + activeBuildPlateNumber = Application.getInstance().activeBuildPlate for node in DepthFirstIterator(scene.getRoot()): if not node.render(renderer): diff --git a/resources/qml/ObjectsList.qml b/resources/qml/ObjectsList.qml index 105bdb957b..758fa59488 100644 --- a/resources/qml/ObjectsList.qml +++ b/resources/qml/ObjectsList.qml @@ -8,7 +8,7 @@ import QtQuick.Layouts 1.1 import QtQuick.Dialogs 1.1 import UM 1.3 as UM -import Cura 1.0 as Cura +import Cura 1.2 as Cura import "Menus" @@ -21,6 +21,8 @@ Rectangle width: UM.Theme.getSize("objects_menu_size").width height: UM.Theme.getSize("objects_menu_size").height + SystemPalette { id: palette } + Button { id: openFileButton; @@ -38,51 +40,188 @@ Rectangle action: Cura.Actions.open; } - ListModel - { - id: objectsListModel; - - ListElement { - name: "Apple" - cost: 2.45 - } - ListElement { - name: "Orange" - cost: 3.25 - } - ListElement { - name: "Banana" - cost: 1.95 - } - } - Component { id: objectDelegate - Rectangle { - height: 30 + Rectangle + { + height: childrenRect.height + color: Cura.ObjectManager.getItem(index).isSelected ? palette.highlight : index % 2 ? palette.base : palette.alternateBase + width: parent.width + Label + { + id: nodeNameLabel + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("default_margin").width + //anchors.right: parent.right + width: parent.width - 2 * UM.Theme.getSize("default_margin").width - 30 + text: Cura.ObjectManager.getItem(index).name; + color: Cura.ObjectManager.getItem(index).isSelected ? palette.highlightedText : palette.text + elide: Text.ElideRight + } - Text { - text: name - color: red + Label + { + id: buildPlateNumberLabel + width: 20 + anchors.left: nodeNameLabel.right + anchors.leftMargin: UM.Theme.getSize("default_margin").width + anchors.right: parent.right + text: Cura.ObjectManager.getItem(index).buildPlateNumber; + color: Cura.ObjectManager.getItem(index).isSelected ? palette.highlightedText : palette.text + elide: Text.ElideRight + } + + MouseArea + { + anchors.fill: parent; + onClicked: + { + Cura.ObjectManager.changeSelection(index); + } + } } - //Text { text: '$' + cost } - } } - ListView + // list all the scene nodes + ScrollView { - model: objectsListModel; + id: objectsList + frameVisible: true + width: parent.width - 2 * UM.Theme.getSize("default_margin").height + anchors { top: openFileButton.bottom; topMargin: UM.Theme.getSize("default_margin").height; left: parent.left; leftMargin: UM.Theme.getSize("default_margin").height; + bottom: buildPlateSelection.top; + bottomMargin: UM.Theme.getSize("default_margin").height; } - width: parent.width - 2 * UM.Theme.getSize("default_margin").height - height: 100 - delegate: objectDelegate + Rectangle + { + parent: viewport + anchors.fill: parent + color: palette.light + } + + ListView + { + id: listview + model: Cura.ObjectManager + //model: objectsListModel + + onModelChanged: + { + //currentIndex = -1; + } + width: parent.width + currentIndex: -1 + onCurrentIndexChanged: + { + //base.selectedPrinter = listview.model[currentIndex]; + // Only allow connecting if the printer has responded to API query since the last refresh + //base.completeProperties = base.selectedPrinter != null && base.selectedPrinter.getProperty("incomplete") != "true"; + } + //Component.onCompleted: manager.startDiscovery() + delegate: objectDelegate + } + } + + ListModel + { + id: buildPlatesModel + + ListElement + { + name: "build plate 0" + buildPlateNumber: 0 + } + ListElement + { + name: "build plate 1" + buildPlateNumber: 1 + } + ListElement + { + name: "build plate 2" + buildPlateNumber: 2 + } + } + + Component { + id: buildPlateDelegate + Rectangle + { + height: childrenRect.height + color: CuraApplication.activeBuildPlate == buildPlateNumber ? palette.highlight : index % 2 ? palette.base : palette.alternateBase + width: parent.width + Label + { + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("default_margin").width + anchors.right: parent.right + text: name //Cura.ObjectManager.getItem(index).name; + color: CuraApplication.activeBuildPlate == buildPlateNumber ? palette.highlightedText : palette.text + elide: Text.ElideRight + } + + MouseArea + { + anchors.fill: parent; + onClicked: + { + CuraApplication.setActiveBuildPlate(buildPlateNumber); + } + } + } + } + + ScrollView + { + id: buildPlateSelection + frameVisible: true + height: 100 + width: parent.width - 2 * UM.Theme.getSize("default_margin").height + + anchors + { + // top: objectsList.bottom; + topMargin: UM.Theme.getSize("default_margin").height; + left: parent.left; + leftMargin: UM.Theme.getSize("default_margin").height; + bottom: parent.bottom; + bottomMargin: UM.Theme.getSize("default_margin").height; + } + + Rectangle + { + parent: viewport + anchors.fill: parent + color: palette.light + } + + ListView + { + id: buildPlateListView + model: buildPlatesModel + + onModelChanged: + { + //currentIndex = -1; + } + width: parent.width + currentIndex: -1 + onCurrentIndexChanged: + { + //base.selectedPrinter = listview.model[currentIndex]; + // Only allow connecting if the printer has responded to API query since the last refresh + //base.completeProperties = base.selectedPrinter != null && base.selectedPrinter.getProperty("incomplete") != "true"; + } + //Component.onCompleted: manager.startDiscovery() + delegate: buildPlateDelegate + } } }