diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index efc306c32d..b438365f78 100644 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -1,6 +1,7 @@ # Copyright (c) 2015 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. +from UM.i18n import i18nCatalog from UM.Scene.SceneNode import SceneNode from UM.Application import Application from UM.Resources import Resources @@ -9,9 +10,11 @@ from UM.Math.Vector import Vector from UM.Math.Color import Color from UM.Math.AxisAlignedBox import AxisAlignedBox from UM.Math.Polygon import Polygon +from UM.Message import Message from UM.View.RenderBatch import RenderBatch from UM.View.GL.OpenGL import OpenGL +catalog = i18nCatalog("cura") import numpy @@ -162,6 +165,13 @@ class BuildVolume(SceneNode): def getBoundingBox(self): return self._volume_aabb + def _buildVolumeMessage(self): + 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 objects."), lifetime=10).show() + def _onGlobalContainerStackChanged(self): if self._active_container_stack: self._active_container_stack.propertyChanged.disconnect(self._onSettingPropertyChanged) @@ -174,6 +184,7 @@ class BuildVolume(SceneNode): self._width = self._active_container_stack.getProperty("machine_width", "value") if self._active_container_stack.getProperty("print_sequence", "value") == "one_at_a_time": self._height = self._active_container_stack.getProperty("gantry_height", "value") + self._buildVolumeMessage() else: self._height = self._active_container_stack.getProperty("machine_height", "value") self._depth = self._active_container_stack.getProperty("machine_depth", "value") @@ -189,6 +200,7 @@ class BuildVolume(SceneNode): if setting_key == "print_sequence": if Application.getInstance().getGlobalContainerStack().getProperty("print_sequence", "value") == "one_at_a_time": self._height = self._active_container_stack.getProperty("gantry_height", "value") + self._buildVolumeMessage() else: self._height = self._active_container_stack.getProperty("machine_height", "value") self.rebuild() diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index eb9dab0ad7..9184db109a 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -349,6 +349,10 @@ class ContainerManager(QObject): def _updateContainerNameFilters(self): self._container_name_filters = {} for plugin_id, container_type in UM.Settings.ContainerRegistry.getContainerTypes(): + # Ignore default container types since those are not plugins + if container_type in (UM.Settings.InstanceContainer, UM.Settings.ContainerStack, UM.Settings.DefinitionContainer): + continue + serialize_type = "" try: plugin_metadata = UM.PluginRegistry.getInstance().getMetaData(plugin_id) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 6159283353..2448139897 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -206,18 +206,32 @@ class MachineManager(QObject): def _onGlobalContainerChanged(self): if self._global_container_stack: + self._global_container_stack.nameChanged.disconnect(self._onMachineNameChanged) self._global_container_stack.containersChanged.disconnect(self._onInstanceContainersChanged) self._global_container_stack.propertyChanged.disconnect(self._onGlobalPropertyChanged) + material = self._global_container_stack.findContainer({"type": "material"}) + material.nameChanged.disconnect(self._onMaterialNameChanged) + + quality = self._global_container_stack.findContainer({"type": "quality"}) + quality.nameChanged.disconnect(self._onQualityNameChanged) + self._global_container_stack = Application.getInstance().getGlobalContainerStack() self.globalContainerChanged.emit() if self._global_container_stack: Preferences.getInstance().setValue("cura/active_machine", self._global_container_stack.getId()) + self._global_container_stack.nameChanged.connect(self._onMachineNameChanged) self._global_container_stack.containersChanged.connect(self._onInstanceContainersChanged) self._global_container_stack.propertyChanged.connect(self._onGlobalPropertyChanged) self._global_stack_valid = not self._checkStackForErrors(self._global_container_stack) + material = self._global_container_stack.findContainer({"type": "material"}) + material.nameChanged.connect(self._onMaterialNameChanged) + + quality = self._global_container_stack.findContainer({"type": "quality"}) + quality.nameChanged.connect(self._onQualityNameChanged) + def _onActiveExtruderStackChanged(self): self.blurSettings.emit() # Ensure no-one has focus. if self._active_container_stack and self._active_container_stack != self._global_container_stack: @@ -508,9 +522,13 @@ class MachineManager(QObject): old_material = self._active_container_stack.findContainer({"type":"material"}) old_quality = self._active_container_stack.findContainer({"type": "quality"}) if old_material: + old_material.nameChanged.disconnect(self._onMaterialNameChanged) + material_index = self._active_container_stack.getContainerIndex(old_material) self._active_container_stack.replaceContainer(material_index, containers[0]) + containers[0].nameChanged.connect(self._onMaterialNameChanged) + preferred_quality_name = None if old_quality: preferred_quality_name = old_quality.getName() @@ -545,10 +563,14 @@ class MachineManager(QObject): old_quality = self._active_container_stack.findContainer({"type": "quality"}) if old_quality and old_quality != containers[0]: + old_quality.nameChanged.disconnect(self._onQualityNameChanged) + quality_index = self._active_container_stack.getContainerIndex(old_quality) self._active_container_stack.replaceContainer(quality_index, containers[0]) + containers[0].nameChanged.connect(self._onQualityNameChanged) + if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1: # Ask the user if the user profile should be cleared or not (discarding the current settings) # In Simple Mode we assume the user always wants to keep the (limited) current settings @@ -752,3 +774,15 @@ class MachineManager(QObject): return containers[0] return self._empty_quality_container + + def _onMachineNameChanged(self): + print("machine name changed") + self.globalContainerChanged.emit() + + def _onMaterialNameChanged(self): + print("material name changed") + self.activeMaterialChanged.emit() + + def _onQualityNameChanged(self): + print("quality name changed") + self.activeQualityChanged.emit() diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index ec75b7253c..84b78c1d6a 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -20,7 +20,7 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): ## Overridden from InstanceContainer def duplicate(self, new_id, new_name = None): - base_file = self.getMetaDataEntry("base_file", "") + base_file = self.getMetaDataEntry("base_file", None) new_uuid = str(uuid.uuid4()) if base_file: @@ -40,7 +40,8 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): result = super().duplicate(new_id, new_name) result.setMetaDataEntry("GUID", new_uuid) - result.setMetaDataEntry("base_file", base_file) + if result.getMetaDataEntry("base_file", None): + result.setMetaDataEntry("base_file", base_file) return result ## Overridden from InstanceContainer @@ -57,8 +58,13 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): super().setMetaDataEntry(key, value) + if key == "material": + self.setName(value) + for container in UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(GUID = self.getMetaDataEntry("GUID")): container.setMetaData(copy.deepcopy(self._metadata)) + if key == "material": + container.setName(value) ## Overridden from InstanceContainer def setProperty(self, key, property_name, property_value, container = None): diff --git a/resources/definitions/fdmextruder.def.json b/resources/definitions/fdmextruder.def.json index 06a736330c..bb14732493 100644 --- a/resources/definitions/fdmextruder.def.json +++ b/resources/definitions/fdmextruder.def.json @@ -144,6 +144,42 @@ "settable_per_extruder": true, "settable_per_meshgroup": false, "settable_globally": false + }, + "extruder_prime_pos_x": + { + "label": "Extruder Prime X Position", + "description": "The X coordinate of the position where the nozzle primes at the start of printing.", + "type": "float", + "unit": "mm", + "default_value": 0, + "minimum_value_warning": "-1000", + "maximum_value_warning": "1000", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "extruder_prime_pos_y": + { + "label": "Extruder Prime Y Position", + "description": "The Y coordinate of the position where the nozzle primes at the start of printing.", + "type": "float", + "unit": "mm", + "default_value": 0, + "minimum_value_warning": "-1000", + "maximum_value_warning": "1000", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "extruder_prime_pos_z": + { + "label": "Extruder Prime Z Position", + "description": "The Z coordinate of the position where the nozzle primes at the start of printing.", + "type": "float", + "unit": "mm", + "default_value": 0, + "minimum_value_warning": "-1000", + "maximum_value_warning": "1000", + "settable_per_mesh": false, + "settable_per_extruder": true } } } diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index d8c335f0b3..a90df49891 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -774,7 +774,7 @@ "type": "float", "default_value": 2, "minimum_value": "0", - "value": "0 if infill_sparse_density == 0 else (infill_line_width * 100) / infill_sparse_density * (2 if infill_pattern == \"grid\" else (3 if infill_pattern == \"triangles\" else 1))", + "value": "0 if infill_sparse_density == 0 else (infill_line_width * 100) / infill_sparse_density * (2 if infill_pattern == \"grid\" else (3 if infill_pattern == \"triangles\" else (3 if infill_pattern == \"cubic\" else 1)))", "settable_per_mesh": true } } @@ -782,12 +782,13 @@ "infill_pattern": { "label": "Infill Pattern", - "description": "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, triangle and concentric patterns are fully printed every layer.", + "description": "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, cubic, triangle and concentric patterns are fully printed every layer.", "type": "enum", "options": { "grid": "Grid", "lines": "Lines", + "cubic": "Cubic", "triangles": "Triangles", "concentric": "Concentric", "zigzag": "Zig Zag" @@ -2868,7 +2869,7 @@ "type": "extruder", "default_value": "0", "value": "support_extruder_nr", - "enabled": "support_enable", + "enabled": "support_enable and support_roof_enable", "settable_per_mesh": false, "settable_per_extruder": false } diff --git a/resources/qml/Menus/ProfileMenu.qml b/resources/qml/Menus/ProfileMenu.qml index 213f8c2629..68f83305d7 100644 --- a/resources/qml/Menus/ProfileMenu.qml +++ b/resources/qml/Menus/ProfileMenu.qml @@ -13,7 +13,10 @@ import Cura 1.0 as Cura Instantiator { - model: UM.InstanceContainersModel { filter: menu.getFilter({ "read_only": true }); } + model: UM.InstanceContainersModel + { + filter: menu.getFilter({ "read_only": true }); + } MenuItem { @@ -32,13 +35,11 @@ import Cura 1.0 as Cura Instantiator { + id: customProfileInstantiator model: UM.InstanceContainersModel { - id: customProfilesModel; filter: menu.getFilter({ "read_only": false }); - onRowsInserted: customSeparator.visible = rowCount() > 1 - onRowsRemoved: customSeparator.visible = rowCount() > 1 - onModelReset: customSeparator.visible = rowCount() > 1 + onModelReset: customSeparator.visible = rowCount() > 0 } MenuItem @@ -50,8 +51,16 @@ import Cura 1.0 as Cura onTriggered: Cura.MachineManager.setActiveQuality(model.id) } - onObjectAdded: menu.insertItem(index, object); - onObjectRemoved: menu.removeItem(object); + onObjectAdded: + { + customSeparator.visible = model.rowCount() > 0; + menu.insertItem(index, object); + } + onObjectRemoved: + { + customSeparator.visible = model.rowCount() > 0; + menu.removeItem(object); + } } ExclusiveGroup { id: group; } diff --git a/resources/qml/Preferences/MaterialView.qml b/resources/qml/Preferences/MaterialView.qml index 67a149f446..9dbb5c6d15 100644 --- a/resources/qml/Preferences/MaterialView.qml +++ b/resources/qml/Preferences/MaterialView.qml @@ -51,7 +51,7 @@ TabView width: base.secondColumnWidth; text: properties.supplier; readOnly: !base.editingEnabled; - onEditingFinished: Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, "brand", text) + onEditingFinished: base.setMetaDataEntry("brand", properties.supplier, text) } Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Material Type") } @@ -60,7 +60,7 @@ TabView width: base.secondColumnWidth; text: properties.material_type; readOnly: !base.editingEnabled; - onEditingFinished: Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, "material", text) + onEditingFinished: base.setMetaDataEntry("material", properties.material_type, text) } Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Color") } @@ -75,7 +75,6 @@ TabView { id: colorSelector color: properties.color_code - onColorChanged: Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, "color_code", color) width: colorLabel.height * 0.75 height: colorLabel.height * 0.75 @@ -90,15 +89,15 @@ TabView id: colorLabel; text: properties.color_name; readOnly: !base.editingEnabled - onEditingFinished: Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, "color_name", text) + onEditingFinished: base.setMetaDataEntry("color_name", properties.color_name, text) } - ColorDialog { id: colorDialog; color: properties.color_code; onAccepted: colorSelector.color = color } + ColorDialog { id: colorDialog; color: properties.color_code; onAccepted: base.setMetaDataEntry("color_code", properties.color_code, color) } } Item { width: parent.width; height: UM.Theme.getSize("default_margin").height } - Label { width: parent.width; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: "" + catalog.i18nc("@label", "Properties") + "" } + Label { width: parent.width; height: parent.rowHeight; font.bold: true; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Properties") } Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Density") } ReadOnlySpinBox @@ -110,7 +109,7 @@ TabView stepSize: 0.01 readOnly: !base.editingEnabled; - onEditingFinished: Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, "properties/density", value) + onEditingFinished: base.setMetaDataEntry("properties/density", properties.density, value) } Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Diameter") } @@ -123,7 +122,7 @@ TabView stepSize: 0.01 readOnly: !base.editingEnabled; - onEditingFinished: Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, "properties/diameter", value) + onEditingFinished: base.setMetaDataEntry("properties/diameter", properties.diameter, value) } Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament Cost") } @@ -175,7 +174,7 @@ TabView readOnly: !base.editingEnabled; - onEditingFinished: Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, "description", text) + onEditingFinished: base.setMetaDataEntry("description", properties.description, text) } Label { width: parent.width; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Adhesion Information") } @@ -188,7 +187,7 @@ TabView readOnly: !base.editingEnabled; - onEditingFinished: Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, "adhesion_info", text) + onEditingFinished: base.setMetaDataEntry("adhesion_info", properties.adhesion_info, text) } } } @@ -249,4 +248,13 @@ TabView } } } + + // Tiny convenience function to check if a value really changed before trying to set it. + function setMetaDataEntry(entry_name, old_value, new_value) + { + if(old_value != new_value) + { + Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, entry_name, new_value) + } + } } diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml index 35fa7256ea..4e0d64ca5e 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/MaterialsPage.qml @@ -129,7 +129,7 @@ UM.ManagementPage enabled: base.currentItem != null && !base.currentItem.readOnly - checkable: true + checkable: enabled } } @@ -144,10 +144,10 @@ UM.ManagementPage bottom: parent.bottom } - editingEnabled: base.currentItem != null && !base.currentItem.readOnly && editButton.checked; + editingEnabled: editButton.checkable && editButton.checked; properties: materialProperties - containerId: base.currentItem.id + containerId: base.currentItem != null ? base.currentItem.id : "" } QtObject diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index d6dd66e8a8..5a56ac8dc3 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -140,7 +140,7 @@ UM.ManagementPage Row { id: currentSettingsActions - visible: currentItem.id == Cura.MachineManager.activeQualityId + visible: currentItem && currentItem.id == Cura.MachineManager.activeQualityId anchors.left: parent.left anchors.top: profileName.bottom @@ -173,14 +173,14 @@ UM.ManagementPage Label { id: defaultsMessage - visible: !currentItem.metadata.has_settings + visible: currentItem && !currentItem.metadata.has_settings text: catalog.i18nc("@action:label", "This profile has no settings and uses the defaults specified by the printer.") wrapMode: Text.WordWrap width: parent.width } Label { id: noCurrentSettingsMessage - visible: currentItem.id == Cura.MachineManager.activeQualityId && !Cura.MachineManager.hasUserSettings + visible: currentItem && currentItem.id == Cura.MachineManager.activeQualityId && !Cura.MachineManager.hasUserSettings text: catalog.i18nc("@action:label", "Your current settings match the selected profile.") wrapMode: Text.WordWrap width: parent.width @@ -197,7 +197,17 @@ UM.ManagementPage anchors.bottom: parent.bottom ListView { - model: Cura.ContainerSettingsModel{ containers: (currentItem.id == Cura.MachineManager.activeQualityId) ? [base.currentItem.id, Cura.MachineManager.activeUserProfileId] : [base.currentItem.id] } + model: Cura.ContainerSettingsModel{ containers: + { + if (!currentItem) { + return [] + } else if (currentItem.id == Cura.MachineManager.activeQualityId) { + return [base.currentItem.id, Cura.MachineManager.activeUserProfileId] + } else { + return [base.currentItem.id] + } + } + } delegate: Row { property variant setting: model spacing: UM.Theme.getSize("default_margin").width/2 @@ -221,7 +231,7 @@ UM.ManagementPage } } header: Row { - visible: currentItem.id == Cura.MachineManager.activeQualityId + visible: currentItem && currentItem.id == Cura.MachineManager.activeQualityId spacing: UM.Theme.getSize("default_margin").width Label { text: catalog.i18nc("@action:label", "Profile:") @@ -231,7 +241,7 @@ UM.ManagementPage } Label { text: catalog.i18nc("@action:label", "Current:") - visible: currentItem.id == Cura.MachineManager.activeQualityId + visible: currentItem && currentItem.id == Cura.MachineManager.activeQualityId font.bold: true } }