diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 629f7ba6d8..56fa8d7b3b 100644 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -721,7 +721,12 @@ class BuildVolume(SceneNode): # # \return A sequence of setting values, one for each extruder. def _getSettingFromAllExtruders(self, setting_key, property = "value"): - return ExtruderManager.getInstance().getAllExtruderSettings(setting_key, property) + all_values = ExtruderManager.getInstance().getAllExtruderSettings(setting_key, property) + all_types = ExtruderManager.getInstance().getAllExtruderSettings(setting_key, "type") + for i in range(len(all_values)): + if not all_values[i] and (all_types[i] == "int" or all_types[i] == "float"): + all_values[i] = 0 + return all_values ## Private convenience function to get a setting from the support infill # extruder. @@ -745,16 +750,21 @@ class BuildVolume(SceneNode): multi_extrusion = self._global_container_stack.getProperty("machine_extruder_count", "value") > 1 if not multi_extrusion: - return self._global_container_stack.getProperty(setting_key, property) + stack = self._global_container_stack + else: + extruder_index = self._global_container_stack.getProperty(extruder_setting_key, "value") - extruder_index = self._global_container_stack.getProperty(extruder_setting_key, "value") + if extruder_index == "-1": # If extruder index is -1 use global instead + stack = self._global_container_stack + else: + extruder_stack_id = ExtruderManager.getInstance().extruderIds[str(extruder_index)] + stack = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = extruder_stack_id)[0] - if extruder_index == "-1": # If extruder index is -1 use global instead - return self._global_container_stack.getProperty(setting_key, property) - - extruder_stack_id = ExtruderManager.getInstance().extruderIds[str(extruder_index)] - stack = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = extruder_stack_id)[0] - return stack.getProperty(setting_key, property) + value = stack.getProperty(setting_key, property) + setting_type = stack.getProperty(setting_key, "type") + if not value and (setting_type == "int" or setting_type == "float"): + return 0 + return value ## Convenience function to calculate the disallowed radius around the edge. # diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index a0db1bbf83..e98386a908 100644 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -395,7 +395,12 @@ class ExtruderManager(QObject): # \return \type{List[ContainerStack]} a list of def getActiveExtruderStacks(self): global_stack = UM.Application.getInstance().getGlobalContainerStack() - return list(self._extruder_trains[global_stack.getId()].values()) if global_stack else [] + + result = [] + if global_stack: + for extruder in sorted(self._extruder_trains[global_stack.getId()]): + result.append(self._extruder_trains[global_stack.getId()][extruder]) + return result def __globalContainerStackChanged(self): self._addCurrentMachineExtruders() diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 11a8087f37..6bc407928b 100644 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -412,6 +412,17 @@ class MachineManager(QObject): return False + @pyqtProperty(int, notify = activeStackValueChanged) + def numUserSettings(self): + if not self._global_container_stack: + return 0 + num_user_settings = 0 + num_user_settings += len(self._global_container_stack.getTop().findInstances()) + stacks = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId())) + for stack in stacks: + num_user_settings += len(stack.getTop().findInstances()) + return num_user_settings + ## Delete a user setting from the global stack and all extruder stacks. # \param key \type{str} the name of the key to delete @pyqtSlot(str) @@ -487,6 +498,17 @@ class MachineManager(QObject): return "" + @pyqtProperty("QVariantList", notify=activeVariantChanged) + def activeVariantNames(self): + result = [] + if ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks() is not None: + for stack in ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks(): + variant_container = stack.findContainer({"type": "variant"}) + if variant_container and variant_container != self._empty_variant_container: + result.append(variant_container.getName()) + + return result + @pyqtProperty("QVariantList", notify = activeMaterialChanged) def activeMaterialNames(self): result = [] @@ -971,6 +993,15 @@ class MachineManager(QObject): return "" + @pyqtProperty(str, notify=globalContainerChanged) + def activeDefinitionName(self): + if self._global_container_stack: + definition = self._global_container_stack.getBottom() + if definition: + return definition.getName() + + return "" + ## Get the Definition ID to use to select quality profiles for the currently active machine # \returns DefinitionID (string) if found, empty string otherwise # \sa getQualityDefinitionId diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index b4de6c0736..10cc7b5c88 100644 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -55,9 +55,11 @@ class ThreeMFWorkspaceReader(WorkspaceReader): Logger.log("w", "Could not find reader that was able to read the scene data for 3MF workspace") return WorkspaceReader.PreReadResult.failed - machine_name = "" machine_type = "" + variant_type_name = i18n_catalog.i18nc("@label", "Nozzle") + + num_extruders = 0 # Check if there are any conflicts, so we can ask the user. archive = zipfile.ZipFile(file_name, "r") cura_file_names = [name for name in archive.namelist() if name.startswith("Cura/")] @@ -87,13 +89,22 @@ class ThreeMFWorkspaceReader(WorkspaceReader): if not definitions: definition_container = DefinitionContainer(container_id) definition_container.deserialize(archive.open(definition_container_file).read().decode("utf-8")) - if definition_container.getMetaDataEntry("type") != "extruder": - machine_type = definition_container.getName() + else: - if definitions[0].getMetaDataEntry("type") != "extruder": - machine_type = definitions[0].getName() + definition_container = definitions[0] + + if definition_container.getMetaDataEntry("type") != "extruder": + machine_type = definition_container.getName() + variant_type_name = definition_container.getMetaDataEntry("variants_name", variant_type_name) + else: + num_extruders += 1 Job.yieldThread() + if num_extruders == 0: + num_extruders = 1 # No extruder stacks found, which means there is one extruder + + extruders = num_extruders * [""] + material_labels = [] material_conflict = False xml_material_profile = self._getXmlProfileClass() @@ -138,6 +149,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): quality_type = instance_container.getName() elif container_type == "user": num_user_settings += len(instance_container._instances) + Job.yieldThread() num_visible_settings = 0 try: @@ -168,6 +180,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader): self._dialog.setMachineName(machine_name) self._dialog.setMaterialLabels(material_labels) self._dialog.setMachineType(machine_type) + self._dialog.setExtruders(extruders) + self._dialog.setVariantType(variant_type_name) self._dialog.setHasObjectsOnPlate(Application.getInstance().getPlatformActivity) self._dialog.show() diff --git a/plugins/3MFReader/WorkspaceDialog.py b/plugins/3MFReader/WorkspaceDialog.py index ec2509252b..c26f0707f6 100644 --- a/plugins/3MFReader/WorkspaceDialog.py +++ b/plugins/3MFReader/WorkspaceDialog.py @@ -43,7 +43,9 @@ class WorkspaceDialog(QObject): self._quality_type = "" self._machine_name = "" self._machine_type = "" + self._variant_type = "" self._material_labels = [] + self._extruders = [] self._objects_on_plate = False machineConflictChanged = pyqtSignal() @@ -59,6 +61,16 @@ class WorkspaceDialog(QObject): objectsOnPlateChanged = pyqtSignal() numUserSettingsChanged = pyqtSignal() machineTypeChanged = pyqtSignal() + variantTypeChanged = pyqtSignal() + extrudersChanged = pyqtSignal() + + @pyqtProperty(str, notify=variantTypeChanged) + def variantType(self): + return self._variant_type + + def setVariantType(self, variant_type): + self._variant_type = variant_type + self.variantTypeChanged.emit() @pyqtProperty(str, notify=machineTypeChanged) def machineType(self): @@ -92,6 +104,14 @@ class WorkspaceDialog(QObject): self._material_labels = material_labels self.materialLabelsChanged.emit() + @pyqtProperty("QVariantList", notify=extrudersChanged) + def extruders(self): + return self._extruders + + def setExtruders(self, extruders): + self._extruders = extruders + self.extrudersChanged.emit() + @pyqtProperty(str, notify = machineNameChanged) def machineName(self): return self._machine_name diff --git a/plugins/3MFReader/WorkspaceDialog.qml b/plugins/3MFReader/WorkspaceDialog.qml index 3d30d17d25..cb8e667872 100644 --- a/plugins/3MFReader/WorkspaceDialog.qml +++ b/plugins/3MFReader/WorkspaceDialog.qml @@ -16,9 +16,9 @@ UM.Dialog minimumWidth: 550 maximumWidth: 550 - height: 350 - minimumHeight: 350 - maximumHeight: 350 + height: 400 + minimumHeight: 400 + maximumHeight: 400 property int comboboxHeight: 15 property int spacerHeight: 10 onClosing: manager.notifyClosed() @@ -33,7 +33,15 @@ UM.Dialog } Item { - anchors.fill: parent + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + + anchors.topMargin: 20 + anchors.bottomMargin: 20 + anchors.leftMargin:20 + anchors.rightMargin: 20 UM.I18nCatalog { @@ -133,6 +141,7 @@ UM.Dialog } } } + Item // Spacer { height: spacerHeight @@ -321,30 +330,47 @@ UM.Dialog height: spacerHeight width: height } - Label + Row { - text: catalog.i18nc("@action:warning", "Loading a project will clear all models on the buildplate") - visible: manager.hasObjectsOnPlate - color: "red" width: parent.width - wrapMode: Text.Wrap + height: childrenRect.height + visible: manager.hasObjectsOnPlate + UM.RecolorImage + { + width: warningLabel.height + height: width + + source: UM.Theme.getIcon("notice") + color: "black" + + } + Label + { + id: warningLabel + text: catalog.i18nc("@action:warning", "Loading a project will clear all models on the buildplate") + wrapMode: Text.Wrap + } } } - } - rightButtons: [ - Button - { - id: ok_button - text: catalog.i18nc("@action:button","OK"); - onClicked: { manager.closeBackend(); manager.onOkButtonClicked() } - enabled: true - }, Button { id: cancel_button text: catalog.i18nc("@action:button","Cancel"); onClicked: { manager.onCancelButtonClicked() } enabled: true + anchors.bottom: parent.bottom + anchors.right: ok_button.left + anchors.bottomMargin: - 0.5 * height + anchors.rightMargin:2 } - ] + Button + { + id: ok_button + text: catalog.i18nc("@action:button","Open"); + onClicked: { manager.closeBackend(); manager.onOkButtonClicked() } + anchors.bottomMargin: - 0.5 * height + anchors.bottom: parent.bottom + anchors.right: parent.right + } + } } \ No newline at end of file diff --git a/resources/qml/Settings/SettingTextField.qml b/resources/qml/Settings/SettingTextField.qml index d89f540aa3..427b482cea 100644 --- a/resources/qml/Settings/SettingTextField.qml +++ b/resources/qml/Settings/SettingTextField.qml @@ -100,7 +100,7 @@ SettingItem maximumLength: 10; - validator: RegExpValidator { regExp: (definition.type == "int") ? /^-?[0-9]{0,10}/ : /^-?[0-9.,]{0,10}/ } // definition.type property from parent loader used to disallow fractional number entry + validator: RegExpValidator { regExp: (definition.type == "int") ? /^-?[0-9]{0,10}$/ : /^-?[0-9]?[.,]?[0-9]{0,10}$/ } // definition.type property from parent loader used to disallow fractional number entry Binding { @@ -113,7 +113,8 @@ SettingItem // 2: quality // 3: material -> user changed material in materialspage // 4: variant - // 5: machine + // 5: machine_changes + // 6: machine if ((base.resolve != "None" && base.resolve) && (stackLevel != 0) && (stackLevel != 1)) { // We have a resolve function. Indicates that the setting is not settable per extruder and that // we have to choose between the resolved value (default) and the global value diff --git a/resources/qml/WorkspaceSummaryDialog.qml b/resources/qml/WorkspaceSummaryDialog.qml index c8da87dc76..c87830fe5c 100644 --- a/resources/qml/WorkspaceSummaryDialog.qml +++ b/resources/qml/WorkspaceSummaryDialog.qml @@ -46,7 +46,16 @@ UM.Dialog Item { - anchors.fill: parent + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + + anchors.topMargin: 20 + anchors.bottomMargin: 20 + anchors.leftMargin:20 + anchors.rightMargin: 20 + UM.SettingDefinitionsModel { id: definitionsModel @@ -91,7 +100,21 @@ UM.Dialog text: catalog.i18nc("@action:label", "Printer settings") font.bold: true } - + Row + { + width: parent.width + height: childrenRect.height + Label + { + text: catalog.i18nc("@action:label", "Type") + width: parent.width / 3 + } + Label + { + text: Cura.MachineManager.activeDefinitionName + width: parent.width / 3 + } + } Row { width: parent.width @@ -106,8 +129,42 @@ UM.Dialog text: Cura.MachineManager.activeMachineName width: parent.width / 3 } - } + + Repeater + { + model: Cura.MachineManager.activeMaterialNames + delegate: Column + { + Item // Spacer + { + height: spacerHeight + width: height + } + Label + { + text: catalog.i18nc("@action:label", "Extruder %1").arg(index+1) + } + height: childrenRect.height + width: parent.width + Row + { + width: parent.width + height: childrenRect.height + Label + { + text: catalog.i18nc("@action:label", "%1 & material").arg(Cura.MachineManager.activeDefinitionVariantsName) + width: parent.width / 3 + } + Label + { + text: Cura.MachineManager.activeVariantNames[index] + ", " + modelData + width: parent.width / 3 + } + } + } + } + Item // Spacer { height: spacerHeight @@ -119,7 +176,21 @@ UM.Dialog text: catalog.i18nc("@action:label", "Profile settings") font.bold: true } - + Row + { + width: parent.width + Label + { + text: catalog.i18nc("@action:label", "Not in profile") + width: parent.width / 3 + } + Label + { + text: catalog.i18nc("@action:label", "%1 override(s)").arg(Cura.MachineManager.numUserSettings) + width: parent.width / 3 + } + visible: Cura.MachineManager.numUserSettings + } Row { width: parent.width @@ -136,7 +207,7 @@ UM.Dialog } } - Item // Spacer + /*Item // Spacer { height: spacerHeight width: height @@ -166,8 +237,7 @@ UM.Dialog width: parent.width / 3 } } - } - + }*/ Item // Spacer { @@ -202,22 +272,34 @@ UM.Dialog checked: dontShowAgain } } - } - rightButtons: [ - Button - { - id: cancel_button - text: catalog.i18nc("@action:button","Cancel"); - enabled: true - onClicked: close() - }, + + Button { id: ok_button text: catalog.i18nc("@action:button","Save"); enabled: true onClicked: { - close(); yes() } + close() + yes() + } + anchors.bottomMargin: - 0.5 * height + anchors.bottom: parent.bottom + anchors.right: parent.right } - ] + + Button + { + id: cancel_button + text: catalog.i18nc("@action:button","Cancel"); + enabled: true + onClicked: close() + + anchors.bottom: parent.bottom + anchors.right: ok_button.left + anchors.bottomMargin: - 0.5 * height + anchors.rightMargin:2 + + } + } } \ No newline at end of file