diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 6132d8ab36..c32017371f 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1085,9 +1085,9 @@ class CuraApplication(QtApplication): def getTextManager(self, *args) -> "TextManager": return self._text_manager - @pyqtSlot(bool) - def getWorkplaceDropToBuildplate(self, drop_to_build_plate: bool) ->None: - return self._physics.setAppPerModelDropDown(drop_to_build_plate) + @pyqtSlot() + def setWorkplaceDropToBuildplate(self): + return self._physics.setAppAllModelDropDown() def getCuraFormulaFunctions(self, *args) -> "CuraFormulaFunctions": if self._cura_formula_functions is None: diff --git a/cura/PlatformPhysics.py b/cura/PlatformPhysics.py index 6a26190a56..c61f78d86e 100755 --- a/cura/PlatformPhysics.py +++ b/cura/PlatformPhysics.py @@ -38,14 +38,12 @@ class PlatformPhysics: self._minimum_gap = 2 # It is a minimum distance (in mm) between two models, applicable for small models Application.getInstance().getPreferences().addPreference("physics/automatic_push_free", False) - Application.getInstance().getPreferences().addPreference("physics/automatic_drop_down", False) - self._app_per_model_drop = Application.getInstance().getPreferences().getValue("physics/automatic_drop_down") + Application.getInstance().getPreferences().addPreference("physics/automatic_drop_down", True) + self._app_all_model_drop = False - def getAppPerModelDropDown(self): - return self._app_per_model_drop - - def setAppPerModelDropDown(self, drop_to_buildplate): - self._app_per_model_drop = drop_to_buildplate + def setAppAllModelDropDown(self): + self._app_all_model_drop = True + self._onChangeTimerFinished() def _onSceneChanged(self, source): if not source.callDecoration("isSliceable"): @@ -78,7 +76,6 @@ class PlatformPhysics: # We try to shuffle all the nodes to prevent "locked" situations, where iteration B inverts iteration A. # By shuffling the order of the nodes, this might happen a few times, but at some point it will resolve. random.shuffle(nodes) - for node in nodes: if node is root or not isinstance(node, SceneNode) or node.getBoundingBox() is None: continue @@ -88,12 +85,9 @@ class PlatformPhysics: # Move it downwards if bottom is above platform move_vector = Vector() - # if per model drop is different then app_automatic_drop, in case of 3mf loading when user changes this setting for that model - if (self._app_per_model_drop != app_automatic_drop_down): - node.setSetting(SceneNodeSettings.AutoDropDown, self._app_per_model_drop) - if node.getSetting(SceneNodeSettings.AutoDropDown, self._app_per_model_drop) and not (node.getParent() and node.getParent().callDecoration("isGroup") or node.getParent() != root) and node.isEnabled(): #If an object is grouped, don't move it down + if (node.getSetting(SceneNodeSettings.AutoDropDown, app_automatic_drop_down) or self._app_all_model_drop) and not (node.getParent() and node.getParent().callDecoration("isGroup") or node.getParent() != root) and node.isEnabled(): z_offset = node.callDecoration("getZOffset") if node.getDecorator(ZOffsetDecorator.ZOffsetDecorator) else 0 - move_vector = move_vector.set(y = -bbox.bottom + z_offset) + move_vector = move_vector.set(y=-bbox.bottom + z_offset) # If there is no convex hull for the node, start calculating it and continue. if not node.getDecorator(ConvexHullDecorator) and not node.callDecoration("isNonPrintingMesh") and node.callDecoration("getLayerData") is None: @@ -180,7 +174,7 @@ class PlatformPhysics: op.push() # setting this drop to model same as app_automatic_drop_down - self._app_per_model_drop = app_automatic_drop_down + self._app_all_model_drop = False # After moving, we have to evaluate the boundary checks for nodes build_volume.updateNodeBoundaryCheck() diff --git a/cura/Scene/CuraSceneNode.py b/cura/Scene/CuraSceneNode.py index 9b412c7d4f..65b7c1e593 100644 --- a/cura/Scene/CuraSceneNode.py +++ b/cura/Scene/CuraSceneNode.py @@ -11,6 +11,7 @@ from UM.Scene.SceneNode import SceneNode from UM.Scene.SceneNodeDecorator import SceneNodeDecorator # To cast the deepcopy of every decorator back to SceneNodeDecorator. import cura.CuraApplication # To get the build plate. +from UM.Scene.SceneNodeSettings import SceneNodeSettings from cura.Settings.ExtruderStack import ExtruderStack # For typing. from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator # For per-object settings. @@ -41,6 +42,10 @@ class CuraSceneNode(SceneNode): def isOutsideBuildArea(self) -> bool: return self._outside_buildarea or self.callDecoration("getBuildPlateNumber") < 0 + @property + def isDropDownEnabled(self) ->bool: + return self.getSetting(SceneNodeSettings.AutoDropDown, Application.getInstance().getPreferences().getValue("physics/automatic_drop_down")) + def isVisible(self) -> bool: return super().isVisible() and self.callDecoration("getBuildPlateNumber") == cura.CuraApplication.CuraApplication.getInstance().getMultiBuildPlateModel().activeBuildPlate diff --git a/plugins/3MFReader/ThreeMFReader.py b/plugins/3MFReader/ThreeMFReader.py index ac94282136..99852d84ce 100755 --- a/plugins/3MFReader/ThreeMFReader.py +++ b/plugins/3MFReader/ThreeMFReader.py @@ -16,6 +16,7 @@ from UM.Mesh.MeshReader import MeshReader from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType from UM.Scene.GroupDecorator import GroupDecorator from UM.Scene.SceneNode import SceneNode # For typing. +from UM.Scene.SceneNodeSettings import SceneNodeSettings from cura.CuraApplication import CuraApplication from cura.Machines.ContainerTree import ContainerTree from cura.Scene.BuildPlateDecorator import BuildPlateDecorator @@ -180,6 +181,9 @@ class ThreeMFReader(MeshReader): if key == "print_order": um_node.printOrder = int(setting_value) continue + if key =="drop_to_buildplate": + um_node.setSetting(SceneNodeSettings.AutoDropDown, eval(setting_value)) + continue if key in known_setting_keys: setting_container.setProperty(key, "value", setting_value) else: diff --git a/plugins/3MFReader/WorkspaceDialog.py b/plugins/3MFReader/WorkspaceDialog.py index c0ea950915..1fafcf59f5 100644 --- a/plugins/3MFReader/WorkspaceDialog.py +++ b/plugins/3MFReader/WorkspaceDialog.py @@ -353,11 +353,6 @@ class WorkspaceDialog(QObject): Application.getInstance().getBackend().close() - @pyqtSlot(bool) - def setDropToBuildPlateForModel(self, drop_to_buildplate: bool) -> None: - CuraApplication.getInstance().getWorkplaceDropToBuildplate(drop_to_buildplate) - - def setMaterialConflict(self, material_conflict: bool) -> None: if self._has_material_conflict != material_conflict: self._has_material_conflict = material_conflict diff --git a/plugins/3MFReader/WorkspaceDialog.qml b/plugins/3MFReader/WorkspaceDialog.qml index 334317e0dc..8d06b32e14 100644 --- a/plugins/3MFReader/WorkspaceDialog.qml +++ b/plugins/3MFReader/WorkspaceDialog.qml @@ -351,25 +351,6 @@ UM.Dialog } } - Row - { - id: dropToBuildPlate - width: parent.width - height: childrenRect.height - spacing: UM.Theme.getSize("default_margin").width - UM.CheckBox - { - id: checkDropModels - text: catalog.i18nc("@text:window", "Drop models to buildplate") - checked: UM.Preferences.getValue("physics/automatic_drop_down") - onCheckedChanged: manager.setDropToBuildPlateForModel(checked) - } - function reloadValue() - { - checkDropModels.checked = UM.Preferences.getValue("physics/automatic_drop_down") - } - } - Row { id: clearBuildPlateWarning @@ -492,7 +473,6 @@ UM.Dialog materialSection.reloadValues() profileSection.reloadValues() printerSection.reloadValues() - dropToBuildPlate.reloadValue() } } } diff --git a/plugins/3MFWriter/ThreeMFWriter.py b/plugins/3MFWriter/ThreeMFWriter.py index 6fda1742f8..c321505643 100644 --- a/plugins/3MFWriter/ThreeMFWriter.py +++ b/plugins/3MFWriter/ThreeMFWriter.py @@ -155,6 +155,7 @@ class ThreeMFWriter(MeshWriter): if isinstance(um_node, CuraSceneNode): savitar_node.setSetting("cura:print_order", str(um_node.printOrder)) + savitar_node.setSetting("cura:drop_to_buildplate", str(um_node.isDropDownEnabled)) # Store the metadata. for key, value in um_node.metadata.items(): diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index 8fe4a11847..7acf39ecb2 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -39,7 +39,7 @@ Item property alias printObjectAfterNext: printObjectAfterNextAction property alias multiplyObject: multiplyObjectAction - + property alias dropAll: dropAllAction property alias selectAll: selectAllAction property alias deleteAll: deleteAllAction property alias reloadAll: reloadAllAction @@ -490,6 +490,14 @@ Item shortcut: "Shift+Ctrl+R" } + Action + { + id: dropAllAction + text: catalog.i18nc("@action:inmenu menubar:edit","Drop All Models to buildplate") + shortcut: "Ctrl+B" + onTriggered: CuraApplication.setWorkplaceDropToBuildplate() + } + Action { id: resetAllTranslationAction diff --git a/resources/qml/Menus/ContextMenu.qml b/resources/qml/Menus/ContextMenu.qml index 1b32c24254..1ab0a1332e 100644 --- a/resources/qml/Menus/ContextMenu.qml +++ b/resources/qml/Menus/ContextMenu.qml @@ -71,6 +71,7 @@ Cura.Menu Cura.MenuItem { action: Cura.Actions.reloadAll } Cura.MenuItem { action: Cura.Actions.resetAllTranslation } Cura.MenuItem { action: Cura.Actions.resetAll } + Cura.MenuItem { action: Cura.Actions.dropAll } // Group actions Cura.MenuSeparator {} diff --git a/resources/qml/Menus/EditMenu.qml b/resources/qml/Menus/EditMenu.qml index 728b3b212b..fdab70360e 100644 --- a/resources/qml/Menus/EditMenu.qml +++ b/resources/qml/Menus/EditMenu.qml @@ -21,6 +21,7 @@ Cura.Menu Cura.MenuItem { action: Cura.Actions.deleteAll } Cura.MenuItem { action: Cura.Actions.resetAllTranslation } Cura.MenuItem { action: Cura.Actions.resetAll } + Cura.MenuItem { action: Cura.Actions.dropAll } Cura.MenuSeparator { } Cura.MenuItem { action: Cura.Actions.groupObjects } Cura.MenuItem { action: Cura.Actions.mergeObjects } diff --git a/resources/qml/Preferences/GeneralPage.qml b/resources/qml/Preferences/GeneralPage.qml index d87ecac0b3..0f50f169ef 100644 --- a/resources/qml/Preferences/GeneralPage.qml +++ b/resources/qml/Preferences/GeneralPage.qml @@ -513,7 +513,6 @@ UM.PreferencesPage onCheckedChanged: { UM.Preferences.setValue("physics/automatic_drop_down", checked) - CuraApplication.getWorkplaceDropToBuildplate(checked) } } }