From 4bb67fbd82e65c24b55efcab550a0e943c68fb86 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 25 Oct 2017 17:04:23 +0200 Subject: [PATCH 001/446] Add setting visibility profile menu button --- resources/qml/Settings/SettingView.qml | 58 +++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 56fd789564..6fa07124f1 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -102,6 +102,60 @@ Item } } + ToolButton + { + id: settingVisibilityProfileMenu + + width: height + height: UM.Theme.getSize("setting_control").height + anchors + { + top: globalProfileRow.bottom + topMargin: UM.Theme.getSize("sidebar_margin").height + right: parent.right + rightMargin: UM.Theme.getSize("sidebar_margin").width + } + style: ButtonStyle + { + background: Rectangle { + color: + { + if(!control.enabled) + { + return UM.Theme.getColor("setting_control_disabled"); + } + return UM.Theme.getColor("setting_control"); + } + + border.width: UM.Theme.getSize("default_lining").width + border.color: + { + if (!control.enabled) + { + return UM.Theme.getColor("setting_control_disabled_border"); + } + else if (control.hovered) + { + return UM.Theme.getColor("setting_control_border_highlight"); + } + return UM.Theme.getColor("setting_control_border"); + } + UM.RecolorImage { + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + width: UM.Theme.getSize("standard_arrow").width + height: UM.Theme.getSize("standard_arrow").height + sourceSize.width: width + sourceSize.height: width + color: control.enabled ? UM.Theme.getColor("setting_category_text") : UM.Theme.getColor("setting_category_disabled_text") + source: UM.Theme.getIcon("menu") + } + } + label: Label{} + } + menu: Menu {} + } + Rectangle { id: filterContainer @@ -128,8 +182,8 @@ Item topMargin: UM.Theme.getSize("sidebar_margin").height left: parent.left leftMargin: UM.Theme.getSize("sidebar_margin").width - right: parent.right - rightMargin: UM.Theme.getSize("sidebar_margin").width + right: settingVisibilityProfileMenu.left + rightMargin: UM.Theme.getSize("default_margin").width } height: visible ? UM.Theme.getSize("setting_control").height : 0 Behavior on height { NumberAnimation { duration: 100 } } From 078fd074e5597120e1855b2f487bdb8722834d14 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 26 Oct 2017 00:00:07 +0200 Subject: [PATCH 002/446] Add initial menu stub --- .../Menus/SettingVisibilityProfilesMenu.qml | 55 +++++++++++++++++ resources/qml/Settings/SettingView.qml | 61 ++++++++++++++----- 2 files changed, 100 insertions(+), 16 deletions(-) create mode 100644 resources/qml/Menus/SettingVisibilityProfilesMenu.qml diff --git a/resources/qml/Menus/SettingVisibilityProfilesMenu.qml b/resources/qml/Menus/SettingVisibilityProfilesMenu.qml new file mode 100644 index 0000000000..e826053a50 --- /dev/null +++ b/resources/qml/Menus/SettingVisibilityProfilesMenu.qml @@ -0,0 +1,55 @@ +// Copyright (c) 2017 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.2 +import QtQuick.Controls 1.1 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +Menu +{ + id: menu + title: "Visible Settings" + + property bool showingSearchResults + property bool showingAllSettings + + signal showAllSettings() + signal showSettingVisibilityProfile() + + MenuItem + { + text: catalog.i18nc("@action:inmenu", "Normal Set") + checkable: true + checked: !showingSearchResults && !showingAllSettings + exclusiveGroup: group + onTriggered: showAllSettings() + } + MenuSeparator {} + MenuItem + { + text: catalog.i18nc("@action:inmenu", "Search Results") + checkable: true + visible: showingSearchResults + checked: showingSearchResults + exclusiveGroup: group + } + MenuItem + { + text: catalog.i18nc("@action:inmenu", "All Settings") + checkable: true + checked: showingAllSettings + exclusiveGroup: group + onTriggered: showAllSettings() + } + MenuSeparator {} + MenuItem + { + text: catalog.i18nc("@action:inmenu", "Manage Visibility Profiles...") + iconName: "configure" + onTriggered: Cura.Actions.configureSettingVisibility.trigger() + } + + ExclusiveGroup { id: group } +} diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 6fa07124f1..0f7cc3f855 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -15,10 +15,11 @@ Item { id: base; - property Action configureSettings; - property bool findingSettings; - signal showTooltip(Item item, point location, string text); - signal hideTooltip(); + property Action configureSettings + property bool findingSettings + property bool showingAllSettings + signal showTooltip(Item item, point location, string text) + signal hideTooltip() Item { @@ -153,7 +154,26 @@ Item } label: Label{} } - menu: Menu {} + menu: SettingVisibilityProfilesMenu + { + showingSearchResults: findingSettings + showingAllSettings: showingAllSettings + + onShowAllSettings: + { + base.showingAllSettings = true; + base.findingSettings = false; + filter.text = ""; + filter.updateDefinitionModel(); + } + onShowSettingVisibilityProfile: + { + base.showingAllSettings = false; + base.findingSettings = false; + filter.text = ""; + filter.updateDefinitionModel(); + } + } } Rectangle @@ -217,17 +237,9 @@ Item { if(findingSettings) { - expandedCategories = definitionsModel.expanded.slice(); - definitionsModel.expanded = ["*"]; - definitionsModel.showAncestors = true; - definitionsModel.showAll = true; - } - else - { - definitionsModel.expanded = expandedCategories; - definitionsModel.showAncestors = false; - definitionsModel.showAll = false; + showingAllSettings = false; } + updateDefinitionModel(); lastFindingSettings = findingSettings; } } @@ -236,6 +248,23 @@ Item { filter.text = ""; } + + function updateDefinitionModel() + { + if(findingSettings || base.showingAllSettings) + { + expandedCategories = definitionsModel.expanded.slice(); + definitionsModel.expanded = ["*"]; + definitionsModel.showAncestors = true; + definitionsModel.showAll = true; + } + else + { + definitionsModel.expanded = expandedCategories; + definitionsModel.showAncestors = false; + definitionsModel.showAll = false; + } + } } MouseArea @@ -258,7 +287,7 @@ Item anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width + anchors.rightMargin: UM.Theme.getSize("default_margin").width color: UM.Theme.getColor("setting_control_button") hoverColor: UM.Theme.getColor("setting_control_button_hover") From c9ad5eaedb1fd1ac54d5aeac797ab6f5da6bf5f7 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 26 Oct 2017 00:00:39 +0200 Subject: [PATCH 003/446] Add menu icon --- resources/themes/cura-light/icons/menu.svg | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 resources/themes/cura-light/icons/menu.svg diff --git a/resources/themes/cura-light/icons/menu.svg b/resources/themes/cura-light/icons/menu.svg new file mode 100644 index 0000000000..85fbfb072c --- /dev/null +++ b/resources/themes/cura-light/icons/menu.svg @@ -0,0 +1,3 @@ + + + From 5638ebe8cf15e6c7e228bc304a50cd6b978d21b9 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 26 Oct 2017 11:05:59 +0200 Subject: [PATCH 004/446] Tweak appearance of the menu button --- resources/qml/Settings/SettingView.qml | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 0f7cc3f855..7c44f01c3c 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -118,29 +118,7 @@ Item } style: ButtonStyle { - background: Rectangle { - color: - { - if(!control.enabled) - { - return UM.Theme.getColor("setting_control_disabled"); - } - return UM.Theme.getColor("setting_control"); - } - - border.width: UM.Theme.getSize("default_lining").width - border.color: - { - if (!control.enabled) - { - return UM.Theme.getColor("setting_control_disabled_border"); - } - else if (control.hovered) - { - return UM.Theme.getColor("setting_control_border_highlight"); - } - return UM.Theme.getColor("setting_control_border"); - } + background: Item { UM.RecolorImage { anchors.verticalCenter: parent.verticalCenter anchors.horizontalCenter: parent.horizontalCenter @@ -203,7 +181,7 @@ Item left: parent.left leftMargin: UM.Theme.getSize("sidebar_margin").width right: settingVisibilityProfileMenu.left - rightMargin: UM.Theme.getSize("default_margin").width + rightMargin: Math.floor(UM.Theme.getSize("default_margin").width / 2) } height: visible ? UM.Theme.getSize("setting_control").height : 0 Behavior on height { NumberAnimation { duration: 100 } } From 32b0e536211ec61b77d17bfe5e062e409fbdda99 Mon Sep 17 00:00:00 2001 From: Ruben D Date: Sun, 10 Dec 2017 23:46:49 +0100 Subject: [PATCH 005/446] Add more machine information These are some additional settings that a slicer might need to know. Specifically, it needs to know these for proper X3G output. --- resources/definitions/fdmprinter.def.json | 77 +++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index ed8bf59b97..766bc22d3d 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -606,6 +606,73 @@ "settable_per_extruder": false, "settable_per_meshgroup": false }, + "machine_steps_per_mm_x": + { + "label": "Steps per Millimeter (X)", + "description": "How many steps of the stepper motor will result in one millimeter of movement in the X direction.", + "type": "int", + "default_value": 50, + "minimum_value": "0.0000001", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "machine_steps_per_mm_y": + { + "label": "Steps per Millimeter (Y)", + "description": "How many steps of the stepper motor will result in one millimeter of movement in the Y direction.", + "type": "int", + "default_value": 50, + "minimum_value": "0.0000001", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "machine_steps_per_mm_z": + { + "label": "Steps per Millimeter (Z)", + "description": "How many steps of the stepper motor will result in one millimeter of movement in the Z direction.", + "type": "int", + "default_value": 50, + "minimum_value": "0.0000001", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "machine_steps_per_mm_e": + { + "label": "Steps per Millimeter (E)", + "description": "How many steps of the stepper motors will result in one millimeter of extrusion.", + "type": "int", + "default_value": 1600, + "minimum_value": "0.0000001", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "machine_endstop_positive_direction_x": + { + "label": "X Endstop in Positive Direction", + "description": "Whether the endstop of the X axis is in the positive direction (high X coordinate) or negative (low X coordinate).", + "type": "bool", + "default_value": false, + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "machine_endstop_positive_direction_y": + { + "label": "Y Endstop in Positive Direction", + "description": "Whether the endstop of the Y axis is in the positive direction (high Y coordinate) or negative (low Y coordinate).", + "type": "bool", + "default_value": false, + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "machine_endstop_positive_direction_z": + { + "label": "Z Endstop in Positive Direction", + "description": "Whether the endstop of the Z axis is in the positive direction (high Z coordinate) or negative (low Z coordinate).", + "type": "bool", + "default_value": true, + "settable_per_mesh": false, + "settable_per_extruder": true + }, "machine_minimum_feedrate": { "label": "Minimum Feedrate", @@ -616,6 +683,16 @@ "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false + }, + "machine_feeder_wheel_diameter": + { + "label": "Feeder Wheel Diameter", + "description": "The diameter of the wheel that drives the material in the feeder.", + "unit": "mm", + "type": "float", + "default_value": 10.0, + "settable_per_mesh": false, + "settable_per_extruder": true } } }, From 9917d567a333166019dc08c778331a93c571770e Mon Sep 17 00:00:00 2001 From: Ruben D Date: Sun, 10 Dec 2017 23:48:11 +0100 Subject: [PATCH 006/446] Correction to M180 settings for X3G These settings are needed for X3G output to have the correct dimensions and feedrate. The steps_per_mm settings are important. --- resources/definitions/m180.def.json | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/resources/definitions/m180.def.json b/resources/definitions/m180.def.json index 1e8ac1767b..1fab24f702 100644 --- a/resources/definitions/m180.def.json +++ b/resources/definitions/m180.def.json @@ -25,8 +25,7 @@ "default_value": true }, "machine_nozzle_size": { - "default_value": 0.4, - "minimum_value": "0.001" + "default_value": 0.4 }, "machine_head_with_fans_polygon": { "default_value": [ @@ -36,6 +35,21 @@ [ 18, 35 ] ] }, + "machine_max_feedrate_z": { + "default_value": 400 + }, + "steps_per_mm_x": { + "default_value": 93 + }, + "steps_per_mm_y": { + "default_value": 93 + }, + "steps_per_mm_z": { + "default_value": 1600 + }, + "steps_per_mm_e": { + "default_value": 92 + }, "gantry_height": { "default_value": 55 }, From 503c612509346d5a215953255d9230c1e2dc9288 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 4 Jan 2018 11:21:44 +0100 Subject: [PATCH 007/446] Add (non-functional) items for changed settings (user-changes) and current profile settings --- .../Menus/SettingVisibilityProfilesMenu.qml | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/resources/qml/Menus/SettingVisibilityProfilesMenu.qml b/resources/qml/Menus/SettingVisibilityProfilesMenu.qml index e826053a50..513930a3ce 100644 --- a/resources/qml/Menus/SettingVisibilityProfilesMenu.qml +++ b/resources/qml/Menus/SettingVisibilityProfilesMenu.qml @@ -18,6 +18,15 @@ Menu signal showAllSettings() signal showSettingVisibilityProfile() + MenuItem + { + text: catalog.i18nc("@action:inmenu", "Search Results") + checkable: true + visible: showingSearchResults + checked: showingSearchResults + exclusiveGroup: group + } + MenuSeparator { visible: showingSearchResults } MenuItem { text: catalog.i18nc("@action:inmenu", "Normal Set") @@ -29,13 +38,22 @@ Menu MenuSeparator {} MenuItem { - text: catalog.i18nc("@action:inmenu", "Search Results") + text: catalog.i18nc("@action:inmenu", "Changed settings") checkable: true - visible: showingSearchResults - checked: showingSearchResults + checked: showingAllSettings exclusiveGroup: group + onTriggered: showAllSettings() } MenuItem + { + text: catalog.i18nc("@action:inmenu", "Settings in profile") + checkable: true + checked: showingAllSettings + exclusiveGroup: group + onTriggered: showAllSettings() + } + MenuSeparator {} + MenuItem { text: catalog.i18nc("@action:inmenu", "All Settings") checkable: true From 9730c25ec6fc1056277136fb99a502e52f7ea961 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 4 Jan 2018 14:29:40 +0100 Subject: [PATCH 008/446] Fix showing the normal set --- resources/qml/Menus/SettingVisibilityProfilesMenu.qml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/resources/qml/Menus/SettingVisibilityProfilesMenu.qml b/resources/qml/Menus/SettingVisibilityProfilesMenu.qml index 513930a3ce..019d56be16 100644 --- a/resources/qml/Menus/SettingVisibilityProfilesMenu.qml +++ b/resources/qml/Menus/SettingVisibilityProfilesMenu.qml @@ -33,12 +33,13 @@ Menu checkable: true checked: !showingSearchResults && !showingAllSettings exclusiveGroup: group - onTriggered: showAllSettings() + onTriggered: showSettingVisibilityProfile() } MenuSeparator {} MenuItem { text: catalog.i18nc("@action:inmenu", "Changed settings") + enabled: false checkable: true checked: showingAllSettings exclusiveGroup: group @@ -47,6 +48,7 @@ Menu MenuItem { text: catalog.i18nc("@action:inmenu", "Settings in profile") + enabled: false checkable: true checked: showingAllSettings exclusiveGroup: group From c4aae784ee3c5befd5ab76b3c947e8096c1ae59e Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 10 Jan 2018 20:53:58 +0100 Subject: [PATCH 009/446] Improve tooltip text quality --- resources/qml/PrinterOutput/ExtruderBox.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/qml/PrinterOutput/ExtruderBox.qml b/resources/qml/PrinterOutput/ExtruderBox.qml index a7141262a9..4e15ba75c5 100644 --- a/resources/qml/PrinterOutput/ExtruderBox.qml +++ b/resources/qml/PrinterOutput/ExtruderBox.qml @@ -52,7 +52,7 @@ Item { base.showTooltip( base, - {x: 0, y: extruderTargetTemperature.mapToItem(base, 0, -parent.height / 4).y}, + {x: 0, y: extruderTargetTemperature.mapToItem(base, 0, Math.floor(-parent.height / 4)).y}, catalog.i18nc("@tooltip", "The target temperature of the hotend. The hotend will heat up or cool down towards this temperature. If this is 0, the hotend heating is turned off.") ); } @@ -85,7 +85,7 @@ Item { base.showTooltip( base, - {x: 0, y: parent.mapToItem(base, 0, -parent.height / 4).y}, + {x: 0, y: parent.mapToItem(base, 0, Math.floor(-parent.height / 4)).y}, catalog.i18nc("@tooltip", "The current temperature of this extruder.") ); } From fb9d841c90e4b0d685bcba570da1d0b2495a77ce Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 10 Jan 2018 21:41:59 +0100 Subject: [PATCH 010/446] Add per-extruder preheat controls These are lifted from the bed preheat controls and are not functional at the moment --- cura/PrinterOutput/PrinterOutputController.py | 1 + cura/PrinterOutput/PrinterOutputModel.py | 7 + .../ClusterUM3PrinterOutputController.py | 1 + resources/qml/PrinterOutput/ExtruderBox.qml | 258 +++++++++++++++++- 4 files changed, 264 insertions(+), 3 deletions(-) diff --git a/cura/PrinterOutput/PrinterOutputController.py b/cura/PrinterOutput/PrinterOutputController.py index 86ca10e2d3..6bfe562f1a 100644 --- a/cura/PrinterOutput/PrinterOutputController.py +++ b/cura/PrinterOutput/PrinterOutputController.py @@ -15,6 +15,7 @@ class PrinterOutputController: self.can_pause = True self.can_abort = True self.can_pre_heat_bed = True + self.can_pre_heat_extruders = True self.can_control_manually = True self._output_device = output_device diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index 8234989519..cbed44fa65 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -218,6 +218,13 @@ class PrinterOutputModel(QObject): return self._controller.can_pre_heat_bed return False + # Does the printer support pre-heating the bed at all + @pyqtProperty(bool, constant=True) + def canPreHeatExtruders(self): + if self._controller: + return self._controller.can_pre_heat_extruders + return False + # Does the printer support pause at all @pyqtProperty(bool, constant=True) def canPause(self): diff --git a/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py b/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py index 4615cd62dc..8909a15d2c 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py @@ -13,6 +13,7 @@ class ClusterUM3PrinterOutputController(PrinterOutputController): def __init__(self, output_device): super().__init__(output_device) self.can_pre_heat_bed = False + self.can_pre_heat_extruders = False self.can_control_manually = False def setJobState(self, job: "PrintJobOutputModel", state: str): diff --git a/resources/qml/PrinterOutput/ExtruderBox.qml b/resources/qml/PrinterOutput/ExtruderBox.qml index 4e15ba75c5..609bd65c1d 100644 --- a/resources/qml/PrinterOutput/ExtruderBox.qml +++ b/resources/qml/PrinterOutput/ExtruderBox.qml @@ -39,7 +39,7 @@ Item color: UM.Theme.getColor("text_inactive") anchors.right: parent.right anchors.rightMargin: UM.Theme.getSize("default_margin").width - anchors.bottom: extruderTemperature.bottom + anchors.bottom: extruderCurrentTemperature.bottom MouseArea //For tooltip. { @@ -65,7 +65,7 @@ Item } Label //Temperature indication. { - id: extruderTemperature + id: extruderCurrentTemperature text: Math.round(extruderModel.hotendTemperature) + "°C" //text: (connectedPrinter != null && connectedPrinter.hotendIds[index] != null && connectedPrinter.hotendTemperatures[index] != null) ? Math.round(connectedPrinter.hotendTemperatures[index]) + "°C" : "" color: UM.Theme.getColor("text") @@ -76,7 +76,7 @@ Item MouseArea //For tooltip. { - id: extruderTemperatureTooltipArea + id: extruderCurrentTemperatureTooltipArea hoverEnabled: true anchors.fill: parent onHoveredChanged: @@ -97,6 +97,258 @@ Item } } + Rectangle //Input field for pre-heat temperature. + { + id: preheatTemperatureControl + color: !enabled ? UM.Theme.getColor("setting_control_disabled") : showError ? UM.Theme.getColor("setting_validation_error_background") : UM.Theme.getColor("setting_validation_ok") + property var showError: + { + if(extruderTemperature.properties.maximum_value != "None" && extruderTemperature.properties.maximum_value < Math.floor(preheatTemperatureInput.text)) + { + return true; + } else + { + return false; + } + } + enabled: + { + if (extruderModel == null) + { + return false; //Can't preheat if not connected. + } + if (!connectedPrinter.acceptsCommands) + { + return false; //Not allowed to do anything. + } + if (connectedPrinter.jobState == "printing" || connectedPrinter.jobState == "pre_print" || connectedPrinter.jobState == "resuming" || connectedPrinter.jobState == "pausing" || connectedPrinter.jobState == "paused" || connectedPrinter.jobState == "error" || connectedPrinter.jobState == "offline") + { + return false; //Printer is in a state where it can't react to pre-heating. + } + return true; + } + border.width: UM.Theme.getSize("default_lining").width + border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : preheatTemperatureInputMouseArea.containsMouse ? UM.Theme.getColor("setting_control_border_highlight") : UM.Theme.getColor("setting_control_border") + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("default_margin").width + anchors.bottom: parent.bottom + anchors.bottomMargin: UM.Theme.getSize("default_margin").height + width: Math.floor(UM.Theme.getSize("setting_control").width * 0.75) + height: UM.Theme.getSize("setting_control").height + visible: extruderModel != null ? extruderModel.canPreHeatExtruders: true + Rectangle //Highlight of input field. + { + anchors.fill: parent + anchors.margins: UM.Theme.getSize("default_lining").width + color: UM.Theme.getColor("setting_control_highlight") + opacity: preheatTemperatureControl.hovered ? 1.0 : 0 + } + MouseArea //Change cursor on hovering. + { + id: preheatTemperatureInputMouseArea + hoverEnabled: true + anchors.fill: parent + cursorShape: Qt.IBeamCursor + + onHoveredChanged: + { + if (containsMouse) + { + base.showTooltip( + base, + {x: 0, y: preheatTemperatureInputMouseArea.mapToItem(base, 0, 0).y}, + catalog.i18nc("@tooltip of temperature input", "The temperature to pre-heat the extruder to.") + ); + } + else + { + base.hideTooltip(); + } + } + } + TextInput + { + id: preheatTemperatureInput + font: UM.Theme.getFont("default") + color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : UM.Theme.getColor("setting_control_text") + selectByMouse: true + maximumLength: 5 + enabled: parent.enabled + validator: RegExpValidator { regExp: /^-?[0-9]{0,9}[.,]?[0-9]{0,10}$/ } //Floating point regex. + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("setting_unit_margin").width + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + renderType: Text.NativeRendering + + Component.onCompleted: + { + if (!extruderTemperature.properties.value) + { + text = ""; + } + else + { + text = extruderTemperature.properties.value; + } + } + } + } + + Button //The pre-heat button. + { + id: preheatButton + height: UM.Theme.getSize("setting_control").height + visible: extruderModel != null ? extruderModel.canPreHeatExtruders: true + enabled: + { + if (!preheatTemperatureControl.enabled) + { + return false; //Not connected, not authenticated or printer is busy. + } + if (extruderModel.isPreheating) + { + return true; + } + if (extruderTemperature.properties.minimum_value != "None" && Math.floor(preheatTemperatureInput.text) < Math.floor(extruderTemperature.properties.minimum_value)) + { + return false; //Target temperature too low. + } + if (extruderTemperature.properties.maximum_value != "None" && Math.floor(preheatTemperatureInput.text) > Math.floor(extruderTemperature.properties.maximum_value)) + { + return false; //Target temperature too high. + } + if (Math.floor(preheatTemperatureInput.text) == 0) + { + return false; //Setting the temperature to 0 is not allowed (since that cancels the pre-heating). + } + return true; //Preconditions are met. + } + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: UM.Theme.getSize("default_margin").width + style: ButtonStyle { + background: Rectangle + { + border.width: UM.Theme.getSize("default_lining").width + implicitWidth: actualLabel.contentWidth + (UM.Theme.getSize("default_margin").width * 2) + border.color: + { + if(!control.enabled) + { + return UM.Theme.getColor("action_button_disabled_border"); + } + else if(control.pressed) + { + return UM.Theme.getColor("action_button_active_border"); + } + else if(control.hovered) + { + return UM.Theme.getColor("action_button_hovered_border"); + } + else + { + return UM.Theme.getColor("action_button_border"); + } + } + color: + { + if(!control.enabled) + { + return UM.Theme.getColor("action_button_disabled"); + } + else if(control.pressed) + { + return UM.Theme.getColor("action_button_active"); + } + else if(control.hovered) + { + return UM.Theme.getColor("action_button_hovered"); + } + else + { + return UM.Theme.getColor("action_button"); + } + } + Behavior on color + { + ColorAnimation + { + duration: 50 + } + } + + Label + { + id: actualLabel + anchors.centerIn: parent + color: + { + if(!control.enabled) + { + return UM.Theme.getColor("action_button_disabled_text"); + } + else if(control.pressed) + { + return UM.Theme.getColor("action_button_active_text"); + } + else if(control.hovered) + { + return UM.Theme.getColor("action_button_hovered_text"); + } + else + { + return UM.Theme.getColor("action_button_text"); + } + } + font: UM.Theme.getFont("action_button") + text: + { + if(extruderModel == null) + { + return "" + } + if(extruderModel.isPreheating ) + { + return catalog.i18nc("@button Cancel pre-heating", "Cancel") + } else + { + return catalog.i18nc("@button", "Pre-heat") + } + } + } + } + } + + onClicked: + { + if (!extruderModel.isPreheating) + { + extruderModel.preheatExtruder(preheatTemperatureInput.text, 900); + } + else + { + extruderModel.cancelPreheatExtruder(); + } + } + + onHoveredChanged: + { + if (hovered) + { + base.showTooltip( + base, + {x: 0, y: preheatButton.mapToItem(base, 0, 0).y}, + catalog.i18nc("@tooltip of pre-heat", "Heat the extruder in advance before printing. You can continue adjusting your print while it is heating, and you won't have to wait for the extruder to heat up when you're ready to print.") + ); + } + else + { + base.hideTooltip(); + } + } + } + Rectangle //Material colour indication. { id: materialColor From 52412cb1cdf328acd8c9e14c150063df5c98060b Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 10 Jan 2018 21:59:17 +0100 Subject: [PATCH 011/446] Remove commented-out code --- resources/qml/PrinterOutput/ExtruderBox.qml | 2 -- 1 file changed, 2 deletions(-) diff --git a/resources/qml/PrinterOutput/ExtruderBox.qml b/resources/qml/PrinterOutput/ExtruderBox.qml index 609bd65c1d..80f2b94f6c 100644 --- a/resources/qml/PrinterOutput/ExtruderBox.qml +++ b/resources/qml/PrinterOutput/ExtruderBox.qml @@ -34,7 +34,6 @@ Item { id: extruderTargetTemperature text: Math.round(extruderModel.targetHotendTemperature) + "°C" - //text: (connectedPrinter != null && connectedPrinter.hotendIds[index] != null && connectedPrinter.targetHotendTemperatures[index] != null) ? Math.round(connectedPrinter.targetHotendTemperatures[index]) + "°C" : "" font: UM.Theme.getFont("small") color: UM.Theme.getColor("text_inactive") anchors.right: parent.right @@ -67,7 +66,6 @@ Item { id: extruderCurrentTemperature text: Math.round(extruderModel.hotendTemperature) + "°C" - //text: (connectedPrinter != null && connectedPrinter.hotendIds[index] != null && connectedPrinter.hotendTemperatures[index] != null) ? Math.round(connectedPrinter.hotendTemperatures[index]) + "°C" : "" color: UM.Theme.getColor("text") font: UM.Theme.getFont("large") anchors.right: extruderTargetTemperature.left From d3f94a1137cea7352bdb2ec3ef60b09a7ff80f2f Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 10 Jan 2018 22:36:52 +0100 Subject: [PATCH 012/446] Get preheat temperatures from the proper stacks --- resources/qml/PrinterOutput/ExtruderBox.qml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/resources/qml/PrinterOutput/ExtruderBox.qml b/resources/qml/PrinterOutput/ExtruderBox.qml index 80f2b94f6c..f1d4a61604 100644 --- a/resources/qml/PrinterOutput/ExtruderBox.qml +++ b/resources/qml/PrinterOutput/ExtruderBox.qml @@ -15,6 +15,18 @@ Item //width: index == machineExtruderCount.properties.value - 1 && index % 2 == 0 ? extrudersGrid.width : Math.floor(extrudersGrid.width / 2 - UM.Theme.getSize("sidebar_lining_thin").width / 2) implicitWidth: parent.width implicitHeight: UM.Theme.getSize("sidebar_extruder_box").height + + UM.SettingPropertyProvider + { + id: extruderTemperature + containerStackId: Cura.ExtruderManager.extruderIds[position] + key: "material_print_temperature" + watchedProperties: ["value", "minimum_value", "maximum_value", "resolve"] + storeIndex: 0 + + property var resolve: Cura.MachineManager.activeStackId != Cura.MachineManager.activeMachineId ? properties.resolve : "None" + } + Rectangle { id: background From 70cd6aad534ac43d6def756ee250dc60086de13f Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 11 Jan 2018 15:17:30 +0100 Subject: [PATCH 013/446] Remove commented-out code --- resources/qml/PrinterOutput/ExtruderBox.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/qml/PrinterOutput/ExtruderBox.qml b/resources/qml/PrinterOutput/ExtruderBox.qml index f1d4a61604..171fbf2013 100644 --- a/resources/qml/PrinterOutput/ExtruderBox.qml +++ b/resources/qml/PrinterOutput/ExtruderBox.qml @@ -12,7 +12,6 @@ Item property alias color: background.color property var extruderModel property var position: index - //width: index == machineExtruderCount.properties.value - 1 && index % 2 == 0 ? extrudersGrid.width : Math.floor(extrudersGrid.width / 2 - UM.Theme.getSize("sidebar_lining_thin").width / 2) implicitWidth: parent.width implicitHeight: UM.Theme.getSize("sidebar_extruder_box").height From bc5b5ac283765078b25c157e6ec64738169afdf9 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 11 Jan 2018 15:27:38 +0100 Subject: [PATCH 014/446] Implement preheating hotends for USB printing --- cura/PrinterOutput/ExtruderOuputModel.py | 33 ++++++++++++- cura/PrinterOutput/PrinterOutputController.py | 2 +- cura/PrinterOutput/PrinterOutputModel.py | 6 +-- .../ClusterUM3PrinterOutputController.py | 2 +- .../USBPrinting/USBPrinterOutputController.py | 49 +++++++++++++++++-- resources/qml/PrinterOutput/ExtruderBox.qml | 14 +++--- 6 files changed, 89 insertions(+), 17 deletions(-) diff --git a/cura/PrinterOutput/ExtruderOuputModel.py b/cura/PrinterOutput/ExtruderOuputModel.py index b0be6cbbe4..befde28f99 100644 --- a/cura/PrinterOutput/ExtruderOuputModel.py +++ b/cura/PrinterOutput/ExtruderOuputModel.py @@ -17,14 +17,23 @@ class ExtruderOutputModel(QObject): targetHotendTemperatureChanged = pyqtSignal() hotendTemperatureChanged = pyqtSignal() activeMaterialChanged = pyqtSignal() + isPreheatingChanged = pyqtSignal() - def __init__(self, printer: "PrinterOutputModel", parent=None): + def __init__(self, printer: "PrinterOutputModel", position: int, parent=None): super().__init__(parent) self._printer = printer + self._position = position self._target_hotend_temperature = 0 self._hotend_temperature = 0 self._hotend_id = "" self._active_material = None # type: Optional[MaterialOutputModel] + self._is_preheating = False + + def getPrinter(self): + return self._printer + + def getPosition(self): + return self._position @pyqtProperty(QObject, notify = activeMaterialChanged) def activeMaterial(self) -> "MaterialOutputModel": @@ -68,3 +77,25 @@ class ExtruderOutputModel(QObject): if self._hotend_id != id: self._hotend_id = id self.hotendIDChanged.emit() + + def updateIsPreheating(self, pre_heating): + if self._is_preheating != pre_heating: + self._is_preheating = pre_heating + self.isPreheatingChanged.emit() + + @pyqtProperty(bool, notify=isPreheatingChanged) + def isPreheating(self): + return self._is_preheating + + ## Pre-heats the extruder before printer. + # + # \param temperature The temperature to heat the extruder to, in degrees + # Celsius. + # \param duration How long the bed should stay warm, in seconds. + @pyqtSlot(float, float) + def preheatHotend(self, temperature, duration): + self._printer._controller.preheatHotend(self, temperature, duration) + + @pyqtSlot() + def cancelPreheatHotend(self): + self._printer._controller.cancelPreheatHotend(self) \ No newline at end of file diff --git a/cura/PrinterOutput/PrinterOutputController.py b/cura/PrinterOutput/PrinterOutputController.py index 6bfe562f1a..512ac4aa02 100644 --- a/cura/PrinterOutput/PrinterOutputController.py +++ b/cura/PrinterOutput/PrinterOutputController.py @@ -15,7 +15,7 @@ class PrinterOutputController: self.can_pause = True self.can_abort = True self.can_pre_heat_bed = True - self.can_pre_heat_extruders = True + self.can_pre_heat_hotends = True self.can_control_manually = True self._output_device = output_device diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index cbed44fa65..f510829101 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -32,7 +32,7 @@ class PrinterOutputModel(QObject): self._name = "" self._key = "" # Unique identifier self._controller = output_controller - self._extruders = [ExtruderOutputModel(printer=self) for i in range(number_of_extruders)] + self._extruders = [ExtruderOutputModel(printer=self, position=i) for i in range(number_of_extruders)] self._head_position = Vector(0, 0, 0) self._active_print_job = None # type: Optional[PrintJobOutputModel] self._firmware_version = firmware_version @@ -220,9 +220,9 @@ class PrinterOutputModel(QObject): # Does the printer support pre-heating the bed at all @pyqtProperty(bool, constant=True) - def canPreHeatExtruders(self): + def canPreHeatHotends(self): if self._controller: - return self._controller.can_pre_heat_extruders + return self._controller.can_pre_heat_hotends return False # Does the printer support pause at all diff --git a/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py b/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py index 8909a15d2c..076c4584af 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py @@ -13,7 +13,7 @@ class ClusterUM3PrinterOutputController(PrinterOutputController): def __init__(self, output_device): super().__init__(output_device) self.can_pre_heat_bed = False - self.can_pre_heat_extruders = False + self.can_pre_heat_hotends = False self.can_control_manually = False def setJobState(self, job: "PrintJobOutputModel", state: str): diff --git a/plugins/USBPrinting/USBPrinterOutputController.py b/plugins/USBPrinting/USBPrinterOutputController.py index ba45e7b0ca..5640db4a63 100644 --- a/plugins/USBPrinting/USBPrinterOutputController.py +++ b/plugins/USBPrinting/USBPrinterOutputController.py @@ -19,6 +19,11 @@ class USBPrinterOuptutController(PrinterOutputController): self._preheat_bed_timer.timeout.connect(self._onPreheatBedTimerFinished) self._preheat_printer = None + self._preheat_extruders_timer = QTimer() + self._preheat_extruders_timer.setSingleShot(True) + self._preheat_extruders_timer.timeout.connect(self._onPreheatHotendsTimerFinished) + self._preheat_extruders = set() + def moveHead(self, printer: "PrinterOutputModel", x, y, z, speed): self._output_device.sendCommand("G91") self._output_device.sendCommand("G0 X%s Y%s Z%s F%s" % (x, y, z, speed)) @@ -42,6 +47,9 @@ class USBPrinterOuptutController(PrinterOutputController): self._output_device.cancelPrint() pass + def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int): + self._output_device.sendCommand("M140 S%s" % temperature) + def preheatBed(self, printer: "PrinterOutputModel", temperature, duration): try: temperature = round(temperature) # The API doesn't allow floating point. @@ -60,9 +68,42 @@ class USBPrinterOuptutController(PrinterOutputController): self._preheat_bed_timer.stop() printer.updateIsPreheating(False) - def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int): - self._output_device.sendCommand("M140 S%s" % temperature) - def _onPreheatBedTimerFinished(self): self.setTargetBedTemperature(self._preheat_printer, 0) - self._preheat_printer.updateIsPreheating(False) \ No newline at end of file + self._preheat_printer.updateIsPreheating(False) + + def setTargetHotendTemperature(self, printer: "PrinterOutputModel", position: int, temperature: int): + self._output_device.sendCommand("M104 S%s T%s" % (temperature, position)) + + def _onPreheatHotendsTimerFinished(self): + for extruder in self._preheat_extruders: + self.setTargetHotendTemperature(extruder.getPrinter(), extruder.getPosition(), 0) + self._preheat_extruders = set() + self._preheat_printer.updateIsPreheating(False) + + def cancelPreheatHotend(self, extruder: "ExtruderOutputModel"): + self.preheatHotend(extruder, temperature=0, duration=0) + self._preheat_extruders_timer.stop() + try: + self._preheat_extruders.remove(extruder) + except KeyError: + pass + extruder.updateIsPreheating(False) + + def preheatHotend(self, extruder: "ExtruderOutputModel", temperature, duration): + position = extruder.getPosition() + number_of_extruders = len(extruder.getPrinter().extruders) + if position >= number_of_extruders: + return # Got invalid extruder nr, can't pre-heat. + + try: + temperature = round(temperature) # The API doesn't allow floating point. + duration = round(duration) + except ValueError: + return # Got invalid values, can't pre-heat. + + self.setTargetHotendTemperature(extruder.getPrinter(), position, temperature=temperature) + self._preheat_extruders_timer.setInterval(duration * 1000) + self._preheat_extruders_timer.start() + self._preheat_extruders.add(extruder) + extruder.updateIsPreheating(True) \ No newline at end of file diff --git a/resources/qml/PrinterOutput/ExtruderBox.qml b/resources/qml/PrinterOutput/ExtruderBox.qml index 171fbf2013..dee9377425 100644 --- a/resources/qml/PrinterOutput/ExtruderBox.qml +++ b/resources/qml/PrinterOutput/ExtruderBox.qml @@ -95,7 +95,7 @@ Item base.showTooltip( base, {x: 0, y: parent.mapToItem(base, 0, Math.floor(-parent.height / 4)).y}, - catalog.i18nc("@tooltip", "The current temperature of this extruder.") + catalog.i18nc("@tooltip", "The current temperature of this hotend.") ); } else @@ -144,7 +144,7 @@ Item anchors.bottomMargin: UM.Theme.getSize("default_margin").height width: Math.floor(UM.Theme.getSize("setting_control").width * 0.75) height: UM.Theme.getSize("setting_control").height - visible: extruderModel != null ? extruderModel.canPreHeatExtruders: true + visible: extruderModel != null ? extruderModel.canPreHeatHotends: true Rectangle //Highlight of input field. { anchors.fill: parent @@ -166,7 +166,7 @@ Item base.showTooltip( base, {x: 0, y: preheatTemperatureInputMouseArea.mapToItem(base, 0, 0).y}, - catalog.i18nc("@tooltip of temperature input", "The temperature to pre-heat the extruder to.") + catalog.i18nc("@tooltip of temperature input", "The temperature to pre-heat the hotend to.") ); } else @@ -208,7 +208,7 @@ Item { id: preheatButton height: UM.Theme.getSize("setting_control").height - visible: extruderModel != null ? extruderModel.canPreHeatExtruders: true + visible: extruderModel != null ? extruderModel.canPreHeatHotends: true enabled: { if (!preheatTemperatureControl.enabled) @@ -333,11 +333,11 @@ Item { if (!extruderModel.isPreheating) { - extruderModel.preheatExtruder(preheatTemperatureInput.text, 900); + extruderModel.preheatHotend(preheatTemperatureInput.text, 900); } else { - extruderModel.cancelPreheatExtruder(); + extruderModel.cancelPreheatHotend(); } } @@ -348,7 +348,7 @@ Item base.showTooltip( base, {x: 0, y: preheatButton.mapToItem(base, 0, 0).y}, - catalog.i18nc("@tooltip of pre-heat", "Heat the extruder in advance before printing. You can continue adjusting your print while it is heating, and you won't have to wait for the extruder to heat up when you're ready to print.") + catalog.i18nc("@tooltip of pre-heat", "Heat the hotend in advance before printing. You can continue adjusting your print while it is heating, and you won't have to wait for the hotend to heat up when you're ready to print.") ); } else From 7994c95bbe4cf9f6928b3e4baf811e3705eb63cf Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 17 Jan 2018 18:03:01 +0100 Subject: [PATCH 015/446] Add unit to preheat temperature boxes --- resources/qml/PrinterOutput/ExtruderBox.qml | 23 +++++++++++++----- resources/qml/PrinterOutput/HeatedBedBox.qml | 25 ++++++++++++++------ resources/themes/cura-light/theme.json | 2 ++ 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/resources/qml/PrinterOutput/ExtruderBox.qml b/resources/qml/PrinterOutput/ExtruderBox.qml index dee9377425..4aacef1a94 100644 --- a/resources/qml/PrinterOutput/ExtruderBox.qml +++ b/resources/qml/PrinterOutput/ExtruderBox.qml @@ -138,13 +138,13 @@ Item } border.width: UM.Theme.getSize("default_lining").width border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : preheatTemperatureInputMouseArea.containsMouse ? UM.Theme.getColor("setting_control_border_highlight") : UM.Theme.getColor("setting_control_border") - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("default_margin").width + anchors.right: preheatButton.left + anchors.rightMargin: UM.Theme.getSize("default_margin").width anchors.bottom: parent.bottom anchors.bottomMargin: UM.Theme.getSize("default_margin").height - width: Math.floor(UM.Theme.getSize("setting_control").width * 0.75) - height: UM.Theme.getSize("setting_control").height - visible: extruderModel != null ? extruderModel.canPreHeatHotends: true + width: UM.Theme.getSize("monitor_preheat_temperature_control").width + height: UM.Theme.getSize("monitor_preheat_temperature_control").height + visible: extruderModel != null ? extruderModel.canPreHeatHotends && !extruderModel.isPreheating : true Rectangle //Highlight of input field. { anchors.fill: parent @@ -175,6 +175,17 @@ Item } } } + Label + { + id: unit + anchors.right: parent.right + anchors.rightMargin: UM.Theme.getSize("setting_unit_margin").width + anchors.verticalCenter: parent.verticalCenter + + text: "°C"; + color: UM.Theme.getColor("setting_unit") + font: UM.Theme.getFont("default") + } TextInput { id: preheatTemperatureInput @@ -186,7 +197,7 @@ Item validator: RegExpValidator { regExp: /^-?[0-9]{0,9}[.,]?[0-9]{0,10}$/ } //Floating point regex. anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("setting_unit_margin").width - anchors.right: parent.right + anchors.right: unit.left anchors.verticalCenter: parent.verticalCenter renderType: Text.NativeRendering diff --git a/resources/qml/PrinterOutput/HeatedBedBox.qml b/resources/qml/PrinterOutput/HeatedBedBox.qml index bc89da2251..8d1e37b23d 100644 --- a/resources/qml/PrinterOutput/HeatedBedBox.qml +++ b/resources/qml/PrinterOutput/HeatedBedBox.qml @@ -122,13 +122,13 @@ Item } border.width: UM.Theme.getSize("default_lining").width border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : preheatTemperatureInputMouseArea.containsMouse ? UM.Theme.getColor("setting_control_border_highlight") : UM.Theme.getColor("setting_control_border") - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("default_margin").width + anchors.right: preheatButton.left + anchors.rightMargin: UM.Theme.getSize("default_margin").width anchors.bottom: parent.bottom anchors.bottomMargin: UM.Theme.getSize("default_margin").height - width: UM.Theme.getSize("setting_control").width - height: UM.Theme.getSize("setting_control").height - visible: printerModel != null ? printerModel.canPreHeatBed: true + width: UM.Theme.getSize("monitor_preheat_temperature_control").width + height: UM.Theme.getSize("monitor_preheat_temperature_control").height + visible: printerModel != null ? printerModel.canPreHeatBed && !printerModel.isPreheating : true Rectangle //Highlight of input field. { anchors.fill: parent @@ -159,18 +159,29 @@ Item } } } + Label + { + id: unit + anchors.right: parent.right + anchors.rightMargin: UM.Theme.getSize("setting_unit_margin").width + anchors.verticalCenter: parent.verticalCenter + + text: "°C"; + color: UM.Theme.getColor("setting_unit") + font: UM.Theme.getFont("default") + } TextInput { id: preheatTemperatureInput font: UM.Theme.getFont("default") color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : UM.Theme.getColor("setting_control_text") selectByMouse: true - maximumLength: 10 + maximumLength: 5 enabled: parent.enabled validator: RegExpValidator { regExp: /^-?[0-9]{0,9}[.,]?[0-9]{0,10}$/ } //Floating point regex. anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("setting_unit_margin").width - anchors.right: parent.right + anchors.right: unit.left anchors.verticalCenter: parent.verticalCenter renderType: Text.NativeRendering diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json index 51c96a5f82..aebd527749 100644 --- a/resources/themes/cura-light/theme.json +++ b/resources/themes/cura-light/theme.json @@ -379,6 +379,8 @@ "save_button_save_to_button": [0.3, 2.7], "save_button_specs_icons": [1.4, 1.4], + "monitor_preheat_temperature_control": [4.5, 2.0], + "modal_window_minimum": [60.0, 45], "license_window_minimum": [45, 45], "wizard_progress": [10.0, 0.0], From b68a30662aead1418c931d7c58ec2d2ab24f25f5 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 17 Jan 2018 21:21:13 +0100 Subject: [PATCH 016/446] Add stubs to PrinterOutputController --- cura/PrinterOutput/PrinterOutputController.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cura/PrinterOutput/PrinterOutputController.py b/cura/PrinterOutput/PrinterOutputController.py index 512ac4aa02..6710216a02 100644 --- a/cura/PrinterOutput/PrinterOutputController.py +++ b/cura/PrinterOutput/PrinterOutputController.py @@ -34,6 +34,12 @@ class PrinterOutputController: def preheatBed(self, printer: "PrinterOutputModel", temperature, duration): Logger.log("w", "Preheat bed not implemented in controller") + def cancelPreheatHotend(self, extruder: "ExtruderOutputModel"): + Logger.log("w", "Cancel preheat hotend not implemented in controller") + + def preheatHotend(self, extruder: "ExtruderOutputModel", temperature, duration): + Logger.log("w", "Preheat hotend not implemented in controller") + def setHeadPosition(self, printer: "PrinterOutputModel", x, y, z, speed): Logger.log("w", "Set head position not implemented in controller") From 0f0b1c6795374b7434ccf994bf554e8c88840b6e Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 18 Jan 2018 00:05:16 +0100 Subject: [PATCH 017/446] Fix getting ability to preheat from extruder --- cura/PrinterOutput/ExtruderOuputModel.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cura/PrinterOutput/ExtruderOuputModel.py b/cura/PrinterOutput/ExtruderOuputModel.py index befde28f99..d2fbabea8f 100644 --- a/cura/PrinterOutput/ExtruderOuputModel.py +++ b/cura/PrinterOutput/ExtruderOuputModel.py @@ -35,6 +35,13 @@ class ExtruderOutputModel(QObject): def getPosition(self): return self._position + # Does the printer support pre-heating the bed at all + @pyqtProperty(bool, constant=True) + def canPreHeatHotends(self): + if self._printer: + return self._printer.canPreHeatHotends + return False + @pyqtProperty(QObject, notify = activeMaterialChanged) def activeMaterial(self) -> "MaterialOutputModel": return self._active_material From 3fed44bb5e84d74fe55d53af07f180cecfc707ce Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 18 Jan 2018 00:42:41 +0100 Subject: [PATCH 018/446] Fix typo in class name --- plugins/USBPrinting/USBPrinterOutputController.py | 2 +- plugins/USBPrinting/USBPrinterOutputDevice.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/USBPrinting/USBPrinterOutputController.py b/plugins/USBPrinting/USBPrinterOutputController.py index 5640db4a63..ec47878f9c 100644 --- a/plugins/USBPrinting/USBPrinterOutputController.py +++ b/plugins/USBPrinting/USBPrinterOutputController.py @@ -10,7 +10,7 @@ if MYPY: from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel -class USBPrinterOuptutController(PrinterOutputController): +class USBPrinterOutputController(PrinterOutputController): def __init__(self, output_device): super().__init__(output_device) diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index d372b54c38..b53f502d81 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -12,7 +12,7 @@ from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel from .AutoDetectBaudJob import AutoDetectBaudJob -from .USBPrinterOutputController import USBPrinterOuptutController +from .USBPrinterOutputController import USBPrinterOutputController from .avr_isp import stk500v2, intelHex from PyQt5.QtCore import pyqtSlot, pyqtSignal, pyqtProperty @@ -237,7 +237,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): container_stack = Application.getInstance().getGlobalContainerStack() num_extruders = container_stack.getProperty("machine_extruder_count", "value") # Ensure that a printer is created. - self._printers = [PrinterOutputModel(output_controller=USBPrinterOuptutController(self), number_of_extruders=num_extruders)] + self._printers = [PrinterOutputModel(output_controller=USBPrinterOutputController(self), number_of_extruders=num_extruders)] self._printers[0].updateName(container_stack.getName()) self.setConnectionState(ConnectionState.connected) self._update_thread.start() @@ -364,7 +364,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): elapsed_time = int(time() - self._print_start_time) print_job = self._printers[0].activePrintJob if print_job is None: - print_job = PrintJobOutputModel(output_controller = USBPrinterOuptutController(self), name= Application.getInstance().getPrintInformation().jobName) + print_job = PrintJobOutputModel(output_controller = USBPrinterOutputController(self), name= Application.getInstance().getPrintInformation().jobName) print_job.updateState("printing") self._printers[0].updateActivePrintJob(print_job) From 13206e1fdcc80ae05a2c30902ebd668373101710 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 18 Jan 2018 00:46:20 +0100 Subject: [PATCH 019/446] Stop preheating when a print is started or the temperature is set to 0 on the printer --- .../USBPrinting/USBPrinterOutputController.py | 91 ++++++++++++++----- 1 file changed, 68 insertions(+), 23 deletions(-) diff --git a/plugins/USBPrinting/USBPrinterOutputController.py b/plugins/USBPrinting/USBPrinterOutputController.py index ec47878f9c..b59e60c244 100644 --- a/plugins/USBPrinting/USBPrinterOutputController.py +++ b/plugins/USBPrinting/USBPrinterOutputController.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from cura.PrinterOutput.PrinterOutputController import PrinterOutputController @@ -19,10 +19,39 @@ class USBPrinterOutputController(PrinterOutputController): self._preheat_bed_timer.timeout.connect(self._onPreheatBedTimerFinished) self._preheat_printer = None - self._preheat_extruders_timer = QTimer() - self._preheat_extruders_timer.setSingleShot(True) - self._preheat_extruders_timer.timeout.connect(self._onPreheatHotendsTimerFinished) - self._preheat_extruders = set() + self._preheat_hotends_timer = QTimer() + self._preheat_hotends_timer.setSingleShot(True) + self._preheat_hotends_timer.timeout.connect(self._onPreheatHotendsTimerFinished) + self._preheat_hotends = set() + + self._output_device.printersChanged.connect(self._onPrintersChanged) + self._active_printer = None + + def _onPrintersChanged(self): + if self._active_printer: + self._active_printer.stateChanged.disconnect(self._onPrinterStateChanged) + self._active_printer.targetBedTemperatureChanged.disconnect(self._onTargetBedTemperatureChanged) + for extruder in self._active_printer.extruders: + extruder.targetHotendTemperatureChanged.disconnect(self._onTargetHotendTemperatureChanged) + + self._active_printer = self._output_device.activePrinter + if self._active_printer: + self._active_printer.stateChanged.connect(self._onPrinterStateChanged) + self._active_printer.targetBedTemperatureChanged.connect(self._onTargetBedTemperatureChanged) + for extruder in self._active_printer.extruders: + extruder.targetHotendTemperatureChanged.connect(self._onTargetHotendTemperatureChanged) + + def _onPrinterStateChanged(self): + if self._active_printer.state != "idle": + if self._preheat_bed_timer.isActive(): + self._preheat_bed_timer.stop() + self._preheat_printer.updateIsPreheating(False) + if self._preheat_hotends_timer.isActive(): + self._preheat_hotends_timer.stop() + for extruder in self._preheat_hotends: + extruder.updateIsPreheating(False) + self._preheat_hotends = set() + def moveHead(self, printer: "PrinterOutputModel", x, y, z, speed): self._output_device.sendCommand("G91") @@ -47,9 +76,15 @@ class USBPrinterOutputController(PrinterOutputController): self._output_device.cancelPrint() pass + def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int): self._output_device.sendCommand("M140 S%s" % temperature) + def _onTargetBedTemperatureChanged(self): + if self._preheat_bed_timer.isActive() and self._preheat_printer.targetBedTemperature == 0: + self._preheat_bed_timer.stop() + self._preheat_printer.updateIsPreheating(False) + def preheatBed(self, printer: "PrinterOutputModel", temperature, duration): try: temperature = round(temperature) # The API doesn't allow floating point. @@ -64,7 +99,7 @@ class USBPrinterOutputController(PrinterOutputController): printer.updateIsPreheating(True) def cancelPreheatBed(self, printer: "PrinterOutputModel"): - self.preheatBed(printer, temperature=0, duration=0) + self.setTargetBedTemperature(printer, temperature=0) self._preheat_bed_timer.stop() printer.updateIsPreheating(False) @@ -72,23 +107,20 @@ class USBPrinterOutputController(PrinterOutputController): self.setTargetBedTemperature(self._preheat_printer, 0) self._preheat_printer.updateIsPreheating(False) + def setTargetHotendTemperature(self, printer: "PrinterOutputModel", position: int, temperature: int): self._output_device.sendCommand("M104 S%s T%s" % (temperature, position)) - def _onPreheatHotendsTimerFinished(self): - for extruder in self._preheat_extruders: - self.setTargetHotendTemperature(extruder.getPrinter(), extruder.getPosition(), 0) - self._preheat_extruders = set() - self._preheat_printer.updateIsPreheating(False) + def _onTargetHotendTemperatureChanged(self): + if not self._preheat_hotends_timer.isActive(): + return - def cancelPreheatHotend(self, extruder: "ExtruderOutputModel"): - self.preheatHotend(extruder, temperature=0, duration=0) - self._preheat_extruders_timer.stop() - try: - self._preheat_extruders.remove(extruder) - except KeyError: - pass - extruder.updateIsPreheating(False) + for extruder in self._active_printer.extruders: + if extruder in self._preheat_hotends and extruder.targetHotendTemperature == 0: + extruder.updateIsPreheating(False) + self._preheat_hotends.remove(extruder) + if not self._preheat_hotends: + self._preheat_hotends_timer.stop() def preheatHotend(self, extruder: "ExtruderOutputModel", temperature, duration): position = extruder.getPosition() @@ -103,7 +135,20 @@ class USBPrinterOutputController(PrinterOutputController): return # Got invalid values, can't pre-heat. self.setTargetHotendTemperature(extruder.getPrinter(), position, temperature=temperature) - self._preheat_extruders_timer.setInterval(duration * 1000) - self._preheat_extruders_timer.start() - self._preheat_extruders.add(extruder) - extruder.updateIsPreheating(True) \ No newline at end of file + self._preheat_hotends_timer.setInterval(duration * 1000) + self._preheat_hotends_timer.start() + self._preheat_hotends.add(extruder) + extruder.updateIsPreheating(True) + + def cancelPreheatHotend(self, extruder: "ExtruderOutputModel"): + self.setTargetHotendTemperature(extruder.getPrinter(), extruder.getPosition(), temperature=0) + if extruder in self._preheat_hotends: + extruder.updateIsPreheating(False) + self._preheat_hotends.remove(extruder) + if not self._preheat_hotends and self._preheat_hotends_timer.isActive(): + self._preheat_hotends_timer.stop() + + def _onPreheatHotendsTimerFinished(self): + for extruder in self._preheat_hotends: + self.setTargetHotendTemperature(extruder.getPrinter(), extruder.getPosition(), 0) + self._preheat_hotends = set() From f135b1675ccc427bf4825ced2da5a77f6b307874 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 18 Jan 2018 10:20:37 +0100 Subject: [PATCH 020/446] Fix disabling preheat button when printer is not idle --- resources/qml/PrinterOutput/ExtruderBox.qml | 9 ++++++--- resources/qml/PrinterOutput/HeatedBedBox.qml | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/resources/qml/PrinterOutput/ExtruderBox.qml b/resources/qml/PrinterOutput/ExtruderBox.qml index 4aacef1a94..56c86f1034 100644 --- a/resources/qml/PrinterOutput/ExtruderBox.qml +++ b/resources/qml/PrinterOutput/ExtruderBox.qml @@ -130,9 +130,12 @@ Item { return false; //Not allowed to do anything. } - if (connectedPrinter.jobState == "printing" || connectedPrinter.jobState == "pre_print" || connectedPrinter.jobState == "resuming" || connectedPrinter.jobState == "pausing" || connectedPrinter.jobState == "paused" || connectedPrinter.jobState == "error" || connectedPrinter.jobState == "offline") + if (connectedPrinter.activePrinter && connectedPrinter.activePrinter.activePrintJob) { - return false; //Printer is in a state where it can't react to pre-heating. + if((["printing", "pre_print", "resuming", "pausing", "paused", "error", "offline"]).indexOf(connectedPrinter.activePrinter.activePrintJob.state) != -1) + { + return false; //Printer is in a state where it can't react to pre-heating. + } } return true; } @@ -144,7 +147,7 @@ Item anchors.bottomMargin: UM.Theme.getSize("default_margin").height width: UM.Theme.getSize("monitor_preheat_temperature_control").width height: UM.Theme.getSize("monitor_preheat_temperature_control").height - visible: extruderModel != null ? extruderModel.canPreHeatHotends && !extruderModel.isPreheating : true + visible: extruderModel != null ? enabled && extruderModel.canPreHeatHotends && !extruderModel.isPreheating : true Rectangle //Highlight of input field. { anchors.fill: parent diff --git a/resources/qml/PrinterOutput/HeatedBedBox.qml b/resources/qml/PrinterOutput/HeatedBedBox.qml index 8d1e37b23d..385977141c 100644 --- a/resources/qml/PrinterOutput/HeatedBedBox.qml +++ b/resources/qml/PrinterOutput/HeatedBedBox.qml @@ -114,9 +114,12 @@ Item { return false; //Not allowed to do anything. } - if (connectedPrinter.jobState == "printing" || connectedPrinter.jobState == "pre_print" || connectedPrinter.jobState == "resuming" || connectedPrinter.jobState == "pausing" || connectedPrinter.jobState == "paused" || connectedPrinter.jobState == "error" || connectedPrinter.jobState == "offline") + if (connectedPrinter.activePrinter && connectedPrinter.activePrinter.activePrintJob) { - return false; //Printer is in a state where it can't react to pre-heating. + if((["printing", "pre_print", "resuming", "pausing", "paused", "error", "offline"]).indexOf(connectedPrinter.activePrinter.activePrintJob.state) != -1) + { + return false; //Printer is in a state where it can't react to pre-heating. + } } return true; } @@ -128,7 +131,7 @@ Item anchors.bottomMargin: UM.Theme.getSize("default_margin").height width: UM.Theme.getSize("monitor_preheat_temperature_control").width height: UM.Theme.getSize("monitor_preheat_temperature_control").height - visible: printerModel != null ? printerModel.canPreHeatBed && !printerModel.isPreheating : true + visible: printerModel != null ? enabled && printerModel.canPreHeatBed && !printerModel.isPreheating : true Rectangle //Highlight of input field. { anchors.fill: parent From fb2a5ea28a52c99830cb49503d26d609e51cbbd5 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 18 Jan 2018 11:55:30 +0100 Subject: [PATCH 021/446] Refactor USBPrinterOutputController to reusable cura.PrinterOutput.GenericOutputController --- .../PrinterOutput/GenericOutputController.py | 2 +- plugins/USBPrinting/USBPrinterOutputDevice.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) rename plugins/USBPrinting/USBPrinterOutputController.py => cura/PrinterOutput/GenericOutputController.py (99%) diff --git a/plugins/USBPrinting/USBPrinterOutputController.py b/cura/PrinterOutput/GenericOutputController.py similarity index 99% rename from plugins/USBPrinting/USBPrinterOutputController.py rename to cura/PrinterOutput/GenericOutputController.py index b59e60c244..106c1e3a44 100644 --- a/plugins/USBPrinting/USBPrinterOutputController.py +++ b/cura/PrinterOutput/GenericOutputController.py @@ -10,7 +10,7 @@ if MYPY: from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel -class USBPrinterOutputController(PrinterOutputController): +class GenericOutputController(PrinterOutputController): def __init__(self, output_device): super().__init__(output_device) diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index b53f502d81..52cb0d47f5 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -10,9 +10,9 @@ from UM.PluginRegistry import PluginRegistry from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel +from cura.PrinterOutput.GenericOutputController import GenericOutputController from .AutoDetectBaudJob import AutoDetectBaudJob -from .USBPrinterOutputController import USBPrinterOutputController from .avr_isp import stk500v2, intelHex from PyQt5.QtCore import pyqtSlot, pyqtSignal, pyqtProperty @@ -237,7 +237,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): container_stack = Application.getInstance().getGlobalContainerStack() num_extruders = container_stack.getProperty("machine_extruder_count", "value") # Ensure that a printer is created. - self._printers = [PrinterOutputModel(output_controller=USBPrinterOutputController(self), number_of_extruders=num_extruders)] + self._printers = [PrinterOutputModel(output_controller=GenericOutputController(self), number_of_extruders=num_extruders)] self._printers[0].updateName(container_stack.getName()) self.setConnectionState(ConnectionState.connected) self._update_thread.start() @@ -364,7 +364,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): elapsed_time = int(time() - self._print_start_time) print_job = self._printers[0].activePrintJob if print_job is None: - print_job = PrintJobOutputModel(output_controller = USBPrinterOutputController(self), name= Application.getInstance().getPrintInformation().jobName) + print_job = PrintJobOutputModel(output_controller = GenericOutputController(self), name= Application.getInstance().getPrintInformation().jobName) print_job.updateState("printing") self._printers[0].updateActivePrintJob(print_job) From bcfcc8cc7c26f8cdc85ef3d69d9ea08cdd72838f Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 19 Jan 2018 14:59:25 +0100 Subject: [PATCH 022/446] Enable setting per mesh group settings when printing One at a Time --- .../PerObjectSettingsPanel.qml | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index eb492d8de2..0976dd5df6 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -163,7 +163,16 @@ Item { id: addedSettingsModel; containerId: Cura.MachineManager.activeDefinitionId expanded: [ "*" ] - exclude: { + filter: + { + if (printSequencePropertyProvider.properties.value == "one_at_a_time") + { + return {"settable_per_meshgroup": true}; + } + return {"settable_per_mesh": true}; + } + exclude: + { var excluded_settings = [ "support_mesh", "anti_overhang_mesh", "cutting_mesh", "infill_mesh" ]; if(meshTypeSelection.model.get(meshTypeSelection.currentIndex).type == "support_mesh") @@ -451,7 +460,11 @@ Item { containerId: Cura.MachineManager.activeDefinitionId filter: { - "settable_per_mesh": true + if (printSequencePropertyProvider.properties.value == "one_at_a_time") + { + return {"settable_per_meshgroup": true}; + } + return {"settable_per_mesh": true}; } visibilityHandler: UM.SettingPreferenceVisibilityHandler {} expanded: [ "*" ] @@ -507,6 +520,16 @@ Item { storeIndex: 0 } + UM.SettingPropertyProvider + { + id: printSequencePropertyProvider + + containerStackId: Cura.MachineManager.activeMachineId + key: "print_sequence" + watchedProperties: [ "value" ] + storeIndex: 0 + } + SystemPalette { id: palette; } Component From 860169cfe59c6acb49f243bd5ff5bf04703b7203 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Wed, 24 Jan 2018 14:31:00 +0000 Subject: [PATCH 023/446] Add bridge settings to experimental category. --- resources/definitions/fdmprinter.def.json | 79 +++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index aef5533ead..44d5cbe457 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6189,6 +6189,85 @@ "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false + }, + "bridge_settings_enabled": + { + "label": "Enable Bridge Settings", + "description": "Detect bridges and modify print speed, flow and fan settings while bridges are printed.", + "type": "bool", + "default_value": true, + "settable_per_mesh": true, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, + "bridge_skin_line_width": + { + "label": "Bridge Skin Line Width", + "description": "Width of a single skin line used when bridging.", + "unit": "mm", + "minimum_value": "0.001", + "minimum_value_warning": "0.1 + 0.4 * machine_nozzle_size", + "maximum_value_warning": "2 * machine_nozzle_size", + "default_value": 0.4, + "type": "float", + "value": "line_width", + "enabled": "bridge_settings_enabled", + "limit_to_extruder": "top_bottom_extruder_nr", + "settable_per_mesh": true + }, + "bridge_skin_speed": + { + "label": "Bridge Skin Speed", + "description": "The speed at which bridge skin regions are printed.", + "unit": "mm/s", + "type": "float", + "minimum_value": "0.1", + "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)", + "maximum_value_warning": "300", + "default_value": 20, + "value": "speed_topbottom / 2", + "enabled": "bridge_settings_enabled", + "settable_per_mesh": true + }, + "bridge_wall_speed": + { + "label": "Bridge Wall Speed", + "description": "The speed at which the bridge walls are printed.", + "unit": "mm/s", + "type": "float", + "minimum_value": "0.1", + "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)", + "maximum_value_warning": "300", + "default_value": 20, + "value": "speed_wall_0 / 2", + "enabled": "bridge_settings_enabled", + "settable_per_mesh": true + }, + "bridge_material_flow": + { + "label": "Bridge Flow", + "description": "Flow compensation: the amount of material extruded when bridging is multiplied by this value.", + "unit": "%", + "default_value": 100, + "type": "float", + "minimum_value": "5", + "minimum_value_warning": "50", + "maximum_value_warning": "150", + "enabled": "bridge_settings_enabled", + "settable_per_mesh": true + }, + "bridge_fan_speed": + { + "label": "Bridge Fan Speed", + "description": "Fan speed to use when printing bridge walls and skin.", + "unit": "%", + "minimum_value": "0", + "maximum_value": "100", + "default_value": 100, + "type": "float", + "enabled": "bridge_settings_enabled", + "settable_per_mesh": false, + "settable_per_extruder": true } } }, From 2ae7b488507e987146d72a1b1317c824004817cb Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Thu, 25 Jan 2018 18:23:25 +0000 Subject: [PATCH 024/446] Added bridge_skin_support_threshold setting. --- resources/definitions/fdmprinter.def.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 44d5cbe457..608577c7f0 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6200,6 +6200,18 @@ "settable_per_extruder": false, "settable_per_meshgroup": false }, + "bridge_skin_support_threshold": + { + "label": "Bridge Skin Support Threshold", + "description": "If a skin region is supported for less than this percentage of its area, print it using the bridge settings. Otherwise it is printed using the normal skin settings.", + "unit": "%", + "default_value": 50, + "type": "float", + "minimum_value": "0", + "maximum_value": "100", + "enabled": "bridge_settings_enabled", + "settable_per_mesh": true + }, "bridge_skin_line_width": { "label": "Bridge Skin Line Width", From 80b589344f22e035cbe9826fcd9ac182b696207d Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Thu, 25 Jan 2018 22:40:30 +0100 Subject: [PATCH 025/446] Add custom command methods to output device and controller --- cura/PrinterOutput/PrinterOutputController.py | 9 ++++++--- cura/PrinterOutput/PrinterOutputModel.py | 4 ++++ plugins/USBPrinting/USBPrinterOutputController.py | 5 ++++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/cura/PrinterOutput/PrinterOutputController.py b/cura/PrinterOutput/PrinterOutputController.py index 86ca10e2d3..02ab84cca8 100644 --- a/cura/PrinterOutput/PrinterOutputController.py +++ b/cura/PrinterOutput/PrinterOutputController.py @@ -39,8 +39,11 @@ class PrinterOutputController: def moveHead(self, printer: "PrinterOutputModel", x, y, z, speed): Logger.log("w", "Move head not implemented in controller") - def homeBed(self, printer): + def homeBed(self, printer: "PrinterOutputModel"): Logger.log("w", "Home bed not implemented in controller") - def homeHead(self, printer): - Logger.log("w", "Home head not implemented in controller") \ No newline at end of file + def homeHead(self, printer: "PrinterOutputModel"): + Logger.log("w", "Home head not implemented in controller") + + def sendCustomCommand(self, printer: "PrinterOutputModel", command: str): + Logger.log("w", "Custom command not implemented in controller") diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index 8234989519..02c1f9e489 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -90,6 +90,10 @@ class PrinterOutputModel(QObject): def homeBed(self): self._controller.homeBed(self) + @pyqtSlot(str) + def sendCustomCommand(self, command): + self._controller.sendCustomCommand(self, command) + @pyqtProperty("QVariantList", constant = True) def extruders(self): return self._extruders diff --git a/plugins/USBPrinting/USBPrinterOutputController.py b/plugins/USBPrinting/USBPrinterOutputController.py index f189ed5876..66941acd9e 100644 --- a/plugins/USBPrinting/USBPrinterOutputController.py +++ b/plugins/USBPrinting/USBPrinterOutputController.py @@ -31,6 +31,9 @@ class USBPrinterOutputController(PrinterOutputController): def homeBed(self, printer): self._output_device.sendCommand("G28 Z") + def sendCustomCommand(self, printer, command): + self._output_device.sendCommand(str(command)) + def setJobState(self, job: "PrintJobOutputModel", state: str): if state == "pause": self._output_device.pausePrint() @@ -65,4 +68,4 @@ class USBPrinterOutputController(PrinterOutputController): def _onPreheatBedTimerFinished(self): self.setTargetBedTemperature(self._preheat_printer, 0) - self._preheat_printer.updateIsPreheating(False) \ No newline at end of file + self._preheat_printer.updateIsPreheating(False) From 01b8bd60bdf7ef8230dd891a94738bcc0638e290 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Thu, 25 Jan 2018 22:47:02 +0100 Subject: [PATCH 026/446] Add type hinting --- cura/PrinterOutput/PrinterOutputModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index 02c1f9e489..95e0daf34f 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -91,7 +91,7 @@ class PrinterOutputModel(QObject): self._controller.homeBed(self) @pyqtSlot(str) - def sendCustomCommand(self, command): + def sendCustomCommand(self, command: str): self._controller.sendCustomCommand(self, command) @pyqtProperty("QVariantList", constant = True) From d7254ff8d0cbf7a3fce51fe4d5fcba15e282f413 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Thu, 25 Jan 2018 22:56:46 +0100 Subject: [PATCH 027/446] Start UI elements for custom command input --- .../PrinterOutput/ManualPrinterControl.qml | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/resources/qml/PrinterOutput/ManualPrinterControl.qml b/resources/qml/PrinterOutput/ManualPrinterControl.qml index 43fa769fb5..d3ae280d61 100644 --- a/resources/qml/PrinterOutput/ManualPrinterControl.qml +++ b/resources/qml/PrinterOutput/ManualPrinterControl.qml @@ -429,6 +429,29 @@ Item } } + Row + { + id: customCommandInputRow + + width: base.width - 2 * UM.Theme.getSize("default_margin").width + height: childrenRect.height + UM.Theme.getSize("default_margin").width + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("default_margin").width + + spacing: UM.Theme.getSize("default_margin").width + + Label + { + text: catalog.i18nc("@label", "Custom command input") + color: UM.Theme.getColor("setting_control_text") + font: UM.Theme.getFont("default") + + width: Math.floor(parent.width * 0.4) - UM.Theme.getSize("default_margin").width + height: UM.Theme.getSize("setting_control").height + verticalAlignment: Text.AlignVCenter + } + } + ListModel { id: distancesModel From 866e99bcbb76b3ac371b005a7b8636e6592c15c8 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Thu, 25 Jan 2018 23:02:46 +0100 Subject: [PATCH 028/446] More QML for sending custom commands, not styled or tested yet --- .../PrinterOutput/ManualPrinterControl.qml | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/resources/qml/PrinterOutput/ManualPrinterControl.qml b/resources/qml/PrinterOutput/ManualPrinterControl.qml index d3ae280d61..0720cd1976 100644 --- a/resources/qml/PrinterOutput/ManualPrinterControl.qml +++ b/resources/qml/PrinterOutput/ManualPrinterControl.qml @@ -450,6 +450,43 @@ Item height: UM.Theme.getSize("setting_control").height verticalAlignment: Text.AlignVCenter } + + Row + { + TextInput + { + id: customCommandInput + + font: UM.Theme.getFont("default") + color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : UM.Theme.getColor("setting_control_text") + selectByMouse: true + + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("setting_unit_margin").width + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + renderType: Text.NativeRendering + } + } + + Row + { + Button + { + id: sendCustomCommandButton + + height: UM.Theme.getSize("setting_control").height + + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: UM.Theme.getSize("default_margin").width + + onClicked: { + printerModel.sendCustomCommand(customCommandInput.text) + } + } + } } ListModel From bd46515382834d8491c28022899801a3939e70c2 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Fri, 26 Jan 2018 22:10:44 +0100 Subject: [PATCH 029/446] Make custom commands functional, fix UI layout, typos --- cura/PrinterOutput/PrinterOutputController.py | 4 +- resources/qml/PrinterOutput/HeatedBedBox.qml | 6 +- .../PrinterOutput/ManualPrinterControl.qml | 151 ++++++++++++------ 3 files changed, 109 insertions(+), 52 deletions(-) diff --git a/cura/PrinterOutput/PrinterOutputController.py b/cura/PrinterOutput/PrinterOutputController.py index 02ab84cca8..204bdd5b62 100644 --- a/cura/PrinterOutput/PrinterOutputController.py +++ b/cura/PrinterOutput/PrinterOutputController.py @@ -6,7 +6,7 @@ from UM.Logger import Logger MYPY = False if MYPY: from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel - from cura.PrinterOutput.ExtruderOuputModel import ExtruderOuputModel + from cura.PrinterOutput.ExtruderOuputModel import ExtruderOutputModel from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel @@ -18,7 +18,7 @@ class PrinterOutputController: self.can_control_manually = True self._output_device = output_device - def setTargetHotendTemperature(self, printer: "PrinterOutputModel", extruder: "ExtruderOuputModel", temperature: int): + def setTargetHotendTemperature(self, printer: "PrinterOutputModel", extruder: "ExtruderOutputModel", temperature: int): Logger.log("w", "Set target hotend temperature not implemented in controller") def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int): diff --git a/resources/qml/PrinterOutput/HeatedBedBox.qml b/resources/qml/PrinterOutput/HeatedBedBox.qml index bc89da2251..552f33f620 100644 --- a/resources/qml/PrinterOutput/HeatedBedBox.qml +++ b/resources/qml/PrinterOutput/HeatedBedBox.qml @@ -1,3 +1,6 @@ +// Copyright (c) 2017 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.1 @@ -11,6 +14,7 @@ Item implicitWidth: parent.width height: visible ? UM.Theme.getSize("sidebar_extruder_box").height : 0 property var printerModel + Rectangle { color: UM.Theme.getColor("sidebar") @@ -195,7 +199,7 @@ Item } } - Button //The pre-heat button. + Button // The pre-heat button. { id: preheatButton height: UM.Theme.getSize("setting_control").height diff --git a/resources/qml/PrinterOutput/ManualPrinterControl.qml b/resources/qml/PrinterOutput/ManualPrinterControl.qml index 0720cd1976..632a3de72f 100644 --- a/resources/qml/PrinterOutput/ManualPrinterControl.qml +++ b/resources/qml/PrinterOutput/ManualPrinterControl.qml @@ -9,7 +9,6 @@ import QtQuick.Layouts 1.1 import UM 1.2 as UM import Cura 1.0 as Cura - Item { property var printerModel @@ -101,29 +100,29 @@ Item Column { - enabled: - { - if (printerModel == null) - { - return false; //Can't control the printer if not connected - } - - if (!connectedDevice.acceptsCommands) - { - return false; //Not allowed to do anything. - } - - if(activePrintJob == null) - { - return true - } - - if (activePrintJob.state == "printing" || activePrintJob.state == "resuming" || activePrintJob.state == "pausing" || activePrintJob.state == "error" || activePrintJob.state == "offline") - { - return false; //Printer is in a state where it can't react to manual control - } - return true; - } +// enabled: +// { +// if (printerModel == null) +// { +// return false; //Can't control the printer if not connected +// } +// +// if (!connectedDevice.acceptsCommands) +// { +// return false; //Not allowed to do anything. +// } +// +// if(activePrintJob == null) +// { +// return true +// } +// +// if (activePrintJob.state == "printing" || activePrintJob.state == "resuming" || activePrintJob.state == "pausing" || activePrintJob.state == "error" || activePrintJob.state == "offline") +// { +// return false; //Printer is in a state where it can't react to manual control +// } +// return true; +// } MonitorSection @@ -442,7 +441,7 @@ Item Label { - text: catalog.i18nc("@label", "Custom command input") + text: catalog.i18nc("@label", "Send G-code") color: UM.Theme.getColor("setting_control_text") font: UM.Theme.getFont("default") @@ -453,37 +452,91 @@ Item Row { - TextInput + // Input field for custom G-code commands. + Rectangle { - id: customCommandInput + id: customCommandControl - font: UM.Theme.getFont("default") - color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : UM.Theme.getColor("setting_control_text") - selectByMouse: true + // state + visible: printerModel != null ? printerModel.canPreHeatBed: true + enabled: { + if (printerModel == null) { + return false // Can't preheat if not connected + } + if (!connectedPrinter.acceptsCommands) { + return false // Not allowed to do anything + } + if (connectedPrinter.jobState == "printing" || connectedPrinter.jobState == "pre_print" || connectedPrinter.jobState == "resuming" || connectedPrinter.jobState == "pausing" || connectedPrinter.jobState == "paused" || connectedPrinter.jobState == "error" || connectedPrinter.jobState == "offline") { + return false // Printer is in a state where it can't react to pre-heating + } + return true + } - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("setting_unit_margin").width - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - - renderType: Text.NativeRendering - } - } - - Row - { - Button - { - id: sendCustomCommandButton + // style + color: !enabled ? UM.Theme.getColor("setting_control_disabled") : UM.Theme.getColor("setting_validation_ok") + border.width: UM.Theme.getSize("default_lining").width + border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : customCommandControlMouseArea.containsMouse ? UM.Theme.getColor("setting_control_border_highlight") : UM.Theme.getColor("setting_control_border") + // size + width: UM.Theme.getSize("setting_control").width height: UM.Theme.getSize("setting_control").height - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.margins: UM.Theme.getSize("default_margin").width + // highlight + Rectangle + { + anchors.fill: parent + anchors.margins: UM.Theme.getSize("default_lining").width + color: UM.Theme.getColor("setting_control_highlight") + opacity: customCommandControl.hovered ? 1.0 : 0 + } - onClicked: { - printerModel.sendCustomCommand(customCommandInput.text) + // cursor hover popup + MouseArea + { + id: customCommandControlMouseArea + hoverEnabled: true + anchors.fill: parent + cursorShape: Qt.IBeamCursor + + onHoveredChanged: + { + if (containsMouse) { + base.showTooltip( + base, + { x: 0, y: customCommandControlMouseArea.mapToItem(base, 0, 0).y }, + catalog.i18nc("@tooltip of G-code command input", "Send a custom G-code command to the connected printer. Press 'enter' to send the command.") + ) + } else { + base.hideTooltip() + } + } + } + + TextInput + { + id: customCommandControlInput + + // style + font: UM.Theme.getFont("default") + color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : UM.Theme.getColor("setting_control_text") + selectByMouse: true + clip: true + enabled: parent.enabled + renderType: Text.NativeRendering + + // anchors + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("setting_unit_margin").width + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + // send the command when pressing enter + // we also clear the text field + Keys.onReturnPressed: + { + printerModel.sendCustomCommand(customCommandControlInput.text) + customCommandControlInput.text = "" + } } } } From 2703474861f50269228fd34f0ef2d4dc5cbb645c Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Sat, 27 Jan 2018 21:49:19 +0100 Subject: [PATCH 030/446] Only select all text when tabbing through fields, not when clicking a field --- resources/qml/Settings/SettingTextField.qml | 33 +++++++++++++++------ 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/resources/qml/Settings/SettingTextField.qml b/resources/qml/Settings/SettingTextField.qml index 9056bbe45a..2226e1f09d 100644 --- a/resources/qml/Settings/SettingTextField.qml +++ b/resources/qml/Settings/SettingTextField.qml @@ -13,11 +13,17 @@ SettingItem property string textBeforeEdit property bool textHasChanged + property bool focusGainedByClick: false onFocusReceived: { textHasChanged = false; textBeforeEdit = focusItem.text; - focusItem.selectAll(); + + if(!focusGainedByClick) + { + // select all text when tabbing through fields (but not when selecting a field with the mouse) + focusItem.selectAll(); + } } contents: Rectangle @@ -92,14 +98,6 @@ SettingItem font: UM.Theme.getFont("default") } - MouseArea - { - id: mouseArea - anchors.fill: parent; - //hoverEnabled: true; - cursorShape: Qt.IBeamCursor - } - TextInput { id: input @@ -141,6 +139,7 @@ SettingItem { base.focusReceived(); } + base.focusGainedByClick = false; } color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : UM.Theme.getColor("setting_control_text") @@ -177,6 +176,22 @@ SettingItem } when: !input.activeFocus } + + MouseArea + { + id: mouseArea + anchors.fill: parent; + + cursorShape: Qt.IBeamCursor + + onPressed: { + if(!input.activeFocus) { + base.focusGainedByClick = true; + input.forceActiveFocus(); + } + mouse.accepted = false; + } + } } } } From 8d69e845633f87455c1b79ffb2afa03acf7bb951 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Mon, 29 Jan 2018 08:58:47 +0000 Subject: [PATCH 031/446] Refactor bridge settings. Added bridge_wall_max_air_gap, bridge_wall_material_flow and bridge_skin_material_flow. Removed bridge_skin_line_width and bridge_material_flow. --- resources/definitions/fdmprinter.def.json | 36 +++++++++++++++-------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 608577c7f0..d18f22c7b8 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6212,19 +6212,16 @@ "enabled": "bridge_settings_enabled", "settable_per_mesh": true }, - "bridge_skin_line_width": + "bridge_wall_max_air_gap": { - "label": "Bridge Skin Line Width", - "description": "Width of a single skin line used when bridging.", - "unit": "mm", - "minimum_value": "0.001", - "minimum_value_warning": "0.1 + 0.4 * machine_nozzle_size", - "maximum_value_warning": "2 * machine_nozzle_size", - "default_value": 0.4, + "label": "Bridge Wall Max Air Gap", + "description": "The maximum allowed width of the region of air below a wall line before the wall is printed using bridge settings. Expressed as a percentage of the wall line width. When the air gap is wider than this, the wall line is printed using the bridge settings. Otherwise, the wall line is printed using the normal settings. The lower the value, the more likely it is that overhung wall lines will be printed using bridge settings.", + "unit": "%", + "default_value": 50, "type": "float", - "value": "line_width", + "minimum_value": "0", + "maximum_value": "100", "enabled": "bridge_settings_enabled", - "limit_to_extruder": "top_bottom_extruder_nr", "settable_per_mesh": true }, "bridge_skin_speed": @@ -6255,10 +6252,23 @@ "enabled": "bridge_settings_enabled", "settable_per_mesh": true }, - "bridge_material_flow": + "bridge_skin_material_flow": { - "label": "Bridge Flow", - "description": "Flow compensation: the amount of material extruded when bridging is multiplied by this value.", + "label": "Bridge Skin Flow", + "description": "Flow compensation: the amount of material extruded when bridging skin is multiplied by this value.", + "unit": "%", + "default_value": 100, + "type": "float", + "minimum_value": "5", + "minimum_value_warning": "50", + "maximum_value_warning": "150", + "enabled": "bridge_settings_enabled", + "settable_per_mesh": true + }, + "bridge_wall_material_flow": + { + "label": "Bridge Wall Flow", + "description": "Flow compensation: the amount of material extruded when bridging walls is multiplied by this value.", "unit": "%", "default_value": 100, "type": "float", From 35600fddd78b5f82e411208c3ac53fa13b0419fb Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Mon, 29 Jan 2018 15:53:52 +0000 Subject: [PATCH 032/446] By default, bridging is disabled when support is enabled but the user can override that. --- resources/definitions/fdmprinter.def.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index d18f22c7b8..0e0857d2f9 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6195,7 +6195,8 @@ "label": "Enable Bridge Settings", "description": "Detect bridges and modify print speed, flow and fan settings while bridges are printed.", "type": "bool", - "default_value": true, + "default_value": false, + "value": "not support_enable and not support_tree_enable", "settable_per_mesh": true, "settable_per_extruder": false, "settable_per_meshgroup": false From 15a0ec1ef17022a4cfdea51e219638d5c99b6292 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Tue, 30 Jan 2018 09:24:23 +0000 Subject: [PATCH 033/446] Make the default value of bridge_wall_max_air_gap 100% so that partial overhangs do not use bridging. Full overhangs (no support at all) will still use the wall bridge settings. --- resources/definitions/fdmprinter.def.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 0e0857d2f9..1467cca252 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6218,7 +6218,7 @@ "label": "Bridge Wall Max Air Gap", "description": "The maximum allowed width of the region of air below a wall line before the wall is printed using bridge settings. Expressed as a percentage of the wall line width. When the air gap is wider than this, the wall line is printed using the bridge settings. Otherwise, the wall line is printed using the normal settings. The lower the value, the more likely it is that overhung wall lines will be printed using bridge settings.", "unit": "%", - "default_value": 50, + "default_value": 100, "type": "float", "minimum_value": "0", "maximum_value": "100", From 872efd16b238e17d546db25b6f6fc308b5bc3762 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 8 Feb 2018 17:13:59 +0100 Subject: [PATCH 034/446] Fix selecting presets from menu Switching back to Custom is not yet implemented, and the menu selection does not yet change if the preset is changed in the preferences --- .../Menus/SettingVisibilityProfilesMenu.qml | 52 ++++++++++++++++--- resources/qml/Settings/SettingView.qml | 9 +++- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/resources/qml/Menus/SettingVisibilityProfilesMenu.qml b/resources/qml/Menus/SettingVisibilityProfilesMenu.qml index 019d56be16..b71520a2ca 100644 --- a/resources/qml/Menus/SettingVisibilityProfilesMenu.qml +++ b/resources/qml/Menus/SettingVisibilityProfilesMenu.qml @@ -16,7 +16,7 @@ Menu property bool showingAllSettings signal showAllSettings() - signal showSettingVisibilityProfile() + signal showSettingVisibilityProfile(string profileName) MenuItem { @@ -27,19 +27,56 @@ Menu exclusiveGroup: group } MenuSeparator { visible: showingSearchResults } + MenuItem { - text: catalog.i18nc("@action:inmenu", "Normal Set") + text: catalog.i18nc("@action:inmenu", "Custom selection") checkable: true checked: !showingSearchResults && !showingAllSettings exclusiveGroup: group - onTriggered: showSettingVisibilityProfile() + onTriggered: showSettingVisibilityProfile("Custom") } - MenuSeparator {} + MenuSeparator { } + + Instantiator + { + model: ListModel + { + id: presetNamesList + Component.onCompleted: + { + // returned value is Dictionary (Ex: {1:"Basic"}, The number 1 is the weight and sort by weight) + var itemsDict = UM.Preferences.getValue("general/visible_settings_preset") + var sorted = []; + for(var key in itemsDict) { + sorted[sorted.length] = key; + } + sorted.sort(); + for(var i = 0; i < sorted.length; i++) { + presetNamesList.append({text: itemsDict[sorted[i]], value: i}); + } + } + } + + MenuItem + { + text: model.text + checkable: true + checked: false + exclusiveGroup: group + onTriggered: showSettingVisibilityProfile(model.text) + } + + onObjectAdded: menu.insertItem(index, object) + onObjectRemoved: menu.removeItem(object) + } + + MenuSeparator { visible: false } MenuItem { text: catalog.i18nc("@action:inmenu", "Changed settings") - enabled: false + visible: false + enabled: true checkable: true checked: showingAllSettings exclusiveGroup: group @@ -48,7 +85,8 @@ Menu MenuItem { text: catalog.i18nc("@action:inmenu", "Settings in profile") - enabled: false + visible: false + enabled: true checkable: true checked: showingAllSettings exclusiveGroup: group @@ -66,7 +104,7 @@ Menu MenuSeparator {} MenuItem { - text: catalog.i18nc("@action:inmenu", "Manage Visibility Profiles...") + text: catalog.i18nc("@action:inmenu", "Manage Setting Visibility...") iconName: "configure" onTriggered: Cura.Actions.configureSettingVisibility.trigger() } diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 78b29d4d5c..f3a4e92d96 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -151,6 +151,10 @@ Item } onShowSettingVisibilityProfile: { + var newVisibleSettings = CuraApplication.getVisibilitySettingPreset(profileName) + UM.Preferences.setValue("general/visible_settings", newVisibleSettings) + UM.Preferences.setValue("general/preset_setting_visibility_choice", profileName) + base.showingAllSettings = false; base.findingSettings = false; filter.text = ""; @@ -243,7 +247,10 @@ Item } else { - definitionsModel.expanded = expandedCategories; + if(expandedCategories) + { + definitionsModel.expanded = expandedCategories; + } definitionsModel.showAncestors = false; definitionsModel.showAll = false; } From 080979caeb50155b2536e1d43e07527408f19351 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 8 Feb 2018 22:57:05 +0100 Subject: [PATCH 035/446] Move setting visibility presets into a model Handling of "Custom" is still under consideration --- cura/CuraApplication.py | 105 ++---------------- .../SettingVisibilityProfilesModel.py | 90 +++++++++++++++ .../Menus/SettingVisibilityProfilesMenu.qml | 32 ++---- .../qml/Preferences/SettingVisibilityPage.qml | 73 +++--------- resources/qml/Settings/SettingView.qml | 4 - 5 files changed, 127 insertions(+), 177 deletions(-) create mode 100644 cura/Settings/SettingVisibilityProfilesModel.py diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 4ff39b84a4..7afea3de13 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -57,6 +57,7 @@ from cura.Settings.QualityAndUserProfilesModel import QualityAndUserProfilesMode from cura.Settings.SettingInheritanceManager import SettingInheritanceManager from cura.Settings.UserProfilesModel import UserProfilesModel from cura.Settings.SimpleModeSettingsManager import SimpleModeSettingsManager +from cura.Settings.SettingVisibilityProfilesModel import SettingVisibilityProfilesModel from . import PlatformPhysics @@ -78,6 +79,7 @@ from cura.Settings.ContainerSettingsModel import ContainerSettingsModel from cura.Settings.MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler from cura.Settings.QualitySettingsModel import QualitySettingsModel from cura.Settings.ContainerManager import ContainerManager +from cura.Settings.SettingVisibilityProfilesModel import SettingVisibilityProfilesModel from cura.ObjectsModel import ObjectsModel from cura.BuildPlateModel import BuildPlateModel @@ -356,19 +358,14 @@ class CuraApplication(QtApplication): preferences.setDefault("local_file/last_used_type", "text/x-gcode") - setting_visibily_preset_names = self.getVisibilitySettingPresetTypes() - preferences.setDefault("general/visible_settings_preset", setting_visibily_preset_names) + default_visibility_profile = SettingVisibilityProfilesModel.getInstance().getItem(0) + + preferences.setDefault("general/visible_settings", ";".join(default_visibility_profile["settings"])) + preferences.setDefault("general/preset_setting_visibility_choice", default_visibility_profile["id"]) preset_setting_visibility_choice = Preferences.getInstance().getValue("general/preset_setting_visibility_choice") - - default_preset_visibility_group_name = "Basic" - if preset_setting_visibility_choice == "" or preset_setting_visibility_choice is None: - if preset_setting_visibility_choice not in setting_visibily_preset_names: - preset_setting_visibility_choice = default_preset_visibility_group_name - - visible_settings = self.getVisibilitySettingPreset(settings_preset_name = preset_setting_visibility_choice) - preferences.setDefault("general/visible_settings", visible_settings) - preferences.setDefault("general/preset_setting_visibility_choice", preset_setting_visibility_choice) + if not SettingVisibilityProfilesModel.getInstance().find("id", preset_setting_visibility_choice): + Preferences.getInstance().setValue("general/preset_setting_visibility_choice", default_visibility_profile["id"]) self.applicationShuttingDown.connect(self.saveSettings) self.engineCreatedSignal.connect(self._onEngineCreated) @@ -382,91 +379,6 @@ class CuraApplication(QtApplication): CuraApplication.Created = True - @pyqtSlot(str, result = str) - def getVisibilitySettingPreset(self, settings_preset_name) -> str: - result = self._loadPresetSettingVisibilityGroup(settings_preset_name) - formatted_preset_settings = self._serializePresetSettingVisibilityData(result) - - return formatted_preset_settings - - ## Serialise the given preset setting visibitlity group dictionary into a string which is concatenated by ";" - # - def _serializePresetSettingVisibilityData(self, settings_data: dict) -> str: - result_string = "" - - for key in settings_data: - result_string += key + ";" - for value in settings_data[key]: - result_string += value + ";" - - return result_string - - ## Load the preset setting visibility group with the given name - # - def _loadPresetSettingVisibilityGroup(self, visibility_preset_name) -> Dict[str, str]: - preset_dir = Resources.getPath(Resources.PresetSettingVisibilityGroups) - - result = {} - right_preset_found = False - - for item in os.listdir(preset_dir): - file_path = os.path.join(preset_dir, item) - if not os.path.isfile(file_path): - continue - - parser = ConfigParser(allow_no_value = True) # accept options without any value, - - try: - parser.read([file_path]) - - if not parser.has_option("general", "name"): - continue - - if parser["general"]["name"] == visibility_preset_name: - right_preset_found = True - for section in parser.sections(): - if section == 'general': - continue - else: - section_settings = [] - for option in parser[section].keys(): - section_settings.append(option) - - result[section] = section_settings - - if right_preset_found: - break - - except Exception as e: - Logger.log("e", "Failed to load setting visibility preset %s: %s", file_path, str(e)) - - return result - - ## Check visibility setting preset folder and returns available types - # - def getVisibilitySettingPresetTypes(self): - preset_dir = Resources.getPath(Resources.PresetSettingVisibilityGroups) - result = {} - - for item in os.listdir(preset_dir): - file_path = os.path.join(preset_dir, item) - if not os.path.isfile(file_path): - continue - - parser = ConfigParser(allow_no_value=True) # accept options without any value, - - try: - parser.read([file_path]) - - if not parser.has_option("general", "name") and not parser.has_option("general", "weight"): - continue - - result[parser["general"]["weight"]] = parser["general"]["name"] - - except Exception as e: - Logger.log("e", "Failed to load setting preset %s: %s", file_path, str(e)) - - return result def _onEngineCreated(self): self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider()) @@ -904,6 +816,7 @@ class CuraApplication(QtApplication): qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator") qmlRegisterType(UserChangesModel, "Cura", 1, 1, "UserChangesModel") qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.createContainerManager) + qmlRegisterSingletonType(SettingVisibilityProfilesModel, "Cura", 1, 0, "SettingVisibilityProfilesModel", SettingVisibilityProfilesModel.createSettingVisibilityProfilesModel) # As of Qt5.7, it is necessary to get rid of any ".." in the path for the singleton to work. actions_url = QUrl.fromLocalFile(os.path.abspath(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml"))) diff --git a/cura/Settings/SettingVisibilityProfilesModel.py b/cura/Settings/SettingVisibilityProfilesModel.py new file mode 100644 index 0000000000..2bc5f2f382 --- /dev/null +++ b/cura/Settings/SettingVisibilityProfilesModel.py @@ -0,0 +1,90 @@ +# Copyright (c) 2016 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +import os +import urllib +from configparser import ConfigParser + +from PyQt5.QtCore import pyqtProperty, Qt, pyqtSignal, pyqtSlot, QUrl + +from UM.Logger import Logger +from UM.Qt.ListModel import ListModel + +from UM.Resources import Resources +from UM.MimeTypeDatabase import MimeTypeDatabase, MimeTypeNotFoundError + +class SettingVisibilityProfilesModel(ListModel): + IdRole = Qt.UserRole + 1 + NameRole = Qt.UserRole + 2 + SettingsRole = Qt.UserRole + 4 + + def __init__(self, parent = None): + super().__init__(parent) + self.addRoleName(self.IdRole, "id") + self.addRoleName(self.NameRole, "name") + self.addRoleName(self.SettingsRole, "settings") + + self._container_ids = [] + self._containers = [] + + self._populate() + + def _populate(self): + items = [] + for item in Resources.getAllResourcesOfType(Resources.PresetSettingVisibilityGroups): + try: + mime_type = MimeTypeDatabase.getMimeTypeForFile(item) + except MimeTypeNotFoundError: + Logger.log("e", "Could not determine mime type of file %s", item) + continue + + id = urllib.parse.unquote_plus(mime_type.stripExtension(os.path.basename(item))) + + if not os.path.isfile(item): + continue + + parser = ConfigParser(allow_no_value=True) # accept options without any value, + + try: + parser.read([item]) + + if not parser.has_option("general", "name") and not parser.has_option("general", "weight"): + continue + + settings = [] + for section in parser.sections(): + if section == 'general': + continue + + settings.append(section) + for option in parser[section].keys(): + settings.append(option) + + items.append({ + "id": id, + "name": parser["general"]["name"], + "weight": parser["general"]["weight"], + "settings": settings + }) + + except Exception as e: + Logger.log("e", "Failed to load setting preset %s: %s", file_path, str(e)) + + + items.sort(key = lambda k: (k["weight"], k["id"])) + self.setItems(items) + + # Factory function, used by QML + @staticmethod + def createSettingVisibilityProfilesModel(engine, js_engine): + return SettingVisibilityProfilesModel.getInstance() + + ## Get the singleton instance for this class. + @classmethod + def getInstance(cls) -> "SettingVisibilityProfilesModel": + # Note: Explicit use of class name to prevent issues with inheritance. + if not SettingVisibilityProfilesModel.__instance: + SettingVisibilityProfilesModel.__instance = cls() + return SettingVisibilityProfilesModel.__instance + + __instance = None # type: "SettingVisibilityProfilesModel" \ No newline at end of file diff --git a/resources/qml/Menus/SettingVisibilityProfilesMenu.qml b/resources/qml/Menus/SettingVisibilityProfilesMenu.qml index b71520a2ca..764f07ed41 100644 --- a/resources/qml/Menus/SettingVisibilityProfilesMenu.qml +++ b/resources/qml/Menus/SettingVisibilityProfilesMenu.qml @@ -10,13 +10,13 @@ import Cura 1.0 as Cura Menu { id: menu - title: "Visible Settings" + title: catalog.i18nc("@action:inmenu", "Visible Settings") property bool showingSearchResults property bool showingAllSettings signal showAllSettings() - signal showSettingVisibilityProfile(string profileName) + signal showSettingVisibilityProfile() MenuItem { @@ -40,31 +40,21 @@ Menu Instantiator { - model: ListModel - { - id: presetNamesList - Component.onCompleted: - { - // returned value is Dictionary (Ex: {1:"Basic"}, The number 1 is the weight and sort by weight) - var itemsDict = UM.Preferences.getValue("general/visible_settings_preset") - var sorted = []; - for(var key in itemsDict) { - sorted[sorted.length] = key; - } - sorted.sort(); - for(var i = 0; i < sorted.length; i++) { - presetNamesList.append({text: itemsDict[sorted[i]], value: i}); - } - } - } + model: Cura.SettingVisibilityProfilesModel MenuItem { - text: model.text + text: model.name checkable: true checked: false exclusiveGroup: group - onTriggered: showSettingVisibilityProfile(model.text) + onTriggered: + { + UM.Preferences.setValue("general/visible_settings", model.settings.join(";")); + UM.Preferences.setValue("general/preset_setting_visibility_choice", model.id); + + showSettingVisibilityProfile(); + } } onObjectAdded: menu.insertItem(index, object) diff --git a/resources/qml/Preferences/SettingVisibilityPage.qml b/resources/qml/Preferences/SettingVisibilityPage.qml index 0e3069d194..3d94fca6c4 100644 --- a/resources/qml/Preferences/SettingVisibilityPage.qml +++ b/resources/qml/Preferences/SettingVisibilityPage.qml @@ -26,8 +26,8 @@ UM.PreferencesPage UM.Preferences.resetPreference("general/visible_settings") // After calling this function update Setting visibility preset combobox. - // Reset should set "Basic" setting preset - visibilityPreset.setBasicPreset() + // Reset should set default setting preset ("Basic") + visibilityPreset.setDefaultPreset() } resetEnabled: true; @@ -84,7 +84,7 @@ UM.PreferencesPage if (visibilityPreset.currentIndex != visibilityPreset.model.count - 1) { visibilityPreset.currentIndex = visibilityPreset.model.count - 1 - UM.Preferences.setValue("general/preset_setting_visibility_choice", visibilityPreset.model.get(visibilityPreset.currentIndex).text) + UM.Preferences.setValue("general/preset_setting_visibility_choice", visibilityPreset.model.getItem(visibilityPreset.currentIndex).id) } } } @@ -110,83 +110,44 @@ UM.PreferencesPage ComboBox { - property int customOptionValue: 100 - - function setBasicPreset() + function setDefaultPreset() { - var index = 0 - for(var i = 0; i < presetNamesList.count; ++i) - { - if(model.get(i).text == "Basic") - { - index = i; - break; - } - } - - visibilityPreset.currentIndex = index + visibilityPreset.currentIndex = 0 } id: visibilityPreset - width: 150 + width: 150 * screenScaleFactor anchors { top: parent.top right: parent.right } - model: ListModel - { - id: presetNamesList - Component.onCompleted: - { - // returned value is Dictionary (Ex: {1:"Basic"}, The number 1 is the weight and sort by weight) - var itemsDict = UM.Preferences.getValue("general/visible_settings_preset") - var sorted = []; - for(var key in itemsDict) { - sorted[sorted.length] = key; - } - - sorted.sort(); - for(var i = 0; i < sorted.length; i++) { - presetNamesList.append({text: itemsDict[sorted[i]], value: i}); - } - - // By agreement lets "Custom" option will have value 100 - presetNamesList.append({text: "Custom", value: visibilityPreset.customOptionValue}); - } - } + model: Cura.SettingVisibilityProfilesModel + textRole: "name" currentIndex: { // Load previously selected preset. - var text = UM.Preferences.getValue("general/preset_setting_visibility_choice"); - - - - var index = 0; - for(var i = 0; i < presetNamesList.count; ++i) + var index = model.find("id", UM.Preferences.getValue("general/preset_setting_visibility_choice")); + if(index == -1) { - if(model.get(i).text == text) - { - index = i; - break; - } + index = 0; } + return index; } onActivated: { // TODO What to do if user is selected "Custom from Combobox" ? - if (model.get(index).text == "Custom"){ - UM.Preferences.setValue("general/preset_setting_visibility_choice", model.get(index).text) + if (model.getItem(index).id == "custom"){ + UM.Preferences.setValue("general/preset_setting_visibility_choice", model.get(index).id) return } - var newVisibleSettings = CuraApplication.getVisibilitySettingPreset(model.get(index).text) - UM.Preferences.setValue("general/visible_settings", newVisibleSettings) - UM.Preferences.setValue("general/preset_setting_visibility_choice", model.get(index).text) + UM.Preferences.setValue("general/visible_settings", model.getItem(index).settings.join(";")) + UM.Preferences.setValue("general/preset_setting_visibility_choice", model.getItem(index).id) } } @@ -268,7 +229,7 @@ UM.PreferencesPage if (visibilityPreset.currentIndex != visibilityPreset.model.count - 1) { visibilityPreset.currentIndex = visibilityPreset.model.count - 1 - UM.Preferences.setValue("general/preset_setting_visibility_choice", visibilityPreset.model.get(visibilityPreset.currentIndex).text) + UM.Preferences.setValue("general/preset_setting_visibility_choice", visibilityPreset.model.getItem(visibilityPreset.currentIndex).id) } } } diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index f3a4e92d96..6eb37981be 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -151,10 +151,6 @@ Item } onShowSettingVisibilityProfile: { - var newVisibleSettings = CuraApplication.getVisibilitySettingPreset(profileName) - UM.Preferences.setValue("general/visible_settings", newVisibleSettings) - UM.Preferences.setValue("general/preset_setting_visibility_choice", profileName) - base.showingAllSettings = false; base.findingSettings = false; filter.text = ""; From f79e787f2c959c12d0253ce4a5de4a24f519d323 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 8 Feb 2018 23:19:12 +0100 Subject: [PATCH 036/446] Refactor SettingVisibilityProfiles to SettingVisibilityPresets This is closer to the current Cura intend --- cura/CuraApplication.py | 10 +++++----- ...del.py => SettingVisibilityPresetsModel.py} | 18 +++++++++--------- ...nu.qml => SettingVisibilityPresetsMenu.qml} | 2 +- .../qml/Preferences/SettingVisibilityPage.qml | 2 +- resources/qml/Settings/SettingView.qml | 6 +++--- 5 files changed, 19 insertions(+), 19 deletions(-) rename cura/Settings/{SettingVisibilityProfilesModel.py => SettingVisibilityPresetsModel.py} (83%) rename resources/qml/Menus/{SettingVisibilityProfilesMenu.qml => SettingVisibilityPresetsMenu.qml} (98%) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 7afea3de13..19a5b50e65 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -57,7 +57,7 @@ from cura.Settings.QualityAndUserProfilesModel import QualityAndUserProfilesMode from cura.Settings.SettingInheritanceManager import SettingInheritanceManager from cura.Settings.UserProfilesModel import UserProfilesModel from cura.Settings.SimpleModeSettingsManager import SimpleModeSettingsManager -from cura.Settings.SettingVisibilityProfilesModel import SettingVisibilityProfilesModel +from cura.Settings.SettingVisibilityPresetsModel import SettingVisibilityPresetsModel from . import PlatformPhysics @@ -79,7 +79,7 @@ from cura.Settings.ContainerSettingsModel import ContainerSettingsModel from cura.Settings.MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler from cura.Settings.QualitySettingsModel import QualitySettingsModel from cura.Settings.ContainerManager import ContainerManager -from cura.Settings.SettingVisibilityProfilesModel import SettingVisibilityProfilesModel +from cura.Settings.SettingVisibilityPresetsModel import SettingVisibilityPresetsModel from cura.ObjectsModel import ObjectsModel from cura.BuildPlateModel import BuildPlateModel @@ -358,13 +358,13 @@ class CuraApplication(QtApplication): preferences.setDefault("local_file/last_used_type", "text/x-gcode") - default_visibility_profile = SettingVisibilityProfilesModel.getInstance().getItem(0) + default_visibility_profile = SettingVisibilityPresetsModel.getInstance().getItem(0) preferences.setDefault("general/visible_settings", ";".join(default_visibility_profile["settings"])) preferences.setDefault("general/preset_setting_visibility_choice", default_visibility_profile["id"]) preset_setting_visibility_choice = Preferences.getInstance().getValue("general/preset_setting_visibility_choice") - if not SettingVisibilityProfilesModel.getInstance().find("id", preset_setting_visibility_choice): + if not SettingVisibilityPresetsModel.getInstance().find("id", preset_setting_visibility_choice): Preferences.getInstance().setValue("general/preset_setting_visibility_choice", default_visibility_profile["id"]) self.applicationShuttingDown.connect(self.saveSettings) @@ -816,7 +816,7 @@ class CuraApplication(QtApplication): qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator") qmlRegisterType(UserChangesModel, "Cura", 1, 1, "UserChangesModel") qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.createContainerManager) - qmlRegisterSingletonType(SettingVisibilityProfilesModel, "Cura", 1, 0, "SettingVisibilityProfilesModel", SettingVisibilityProfilesModel.createSettingVisibilityProfilesModel) + qmlRegisterSingletonType(SettingVisibilityPresetsModel, "Cura", 1, 0, "SettingVisibilityPresetsModel", SettingVisibilityPresetsModel.createSettingVisibilityPresetsModel) # As of Qt5.7, it is necessary to get rid of any ".." in the path for the singleton to work. actions_url = QUrl.fromLocalFile(os.path.abspath(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml"))) diff --git a/cura/Settings/SettingVisibilityProfilesModel.py b/cura/Settings/SettingVisibilityPresetsModel.py similarity index 83% rename from cura/Settings/SettingVisibilityProfilesModel.py rename to cura/Settings/SettingVisibilityPresetsModel.py index 2bc5f2f382..a5b4541ee4 100644 --- a/cura/Settings/SettingVisibilityProfilesModel.py +++ b/cura/Settings/SettingVisibilityPresetsModel.py @@ -13,7 +13,7 @@ from UM.Qt.ListModel import ListModel from UM.Resources import Resources from UM.MimeTypeDatabase import MimeTypeDatabase, MimeTypeNotFoundError -class SettingVisibilityProfilesModel(ListModel): +class SettingVisibilityPresetsModel(ListModel): IdRole = Qt.UserRole + 1 NameRole = Qt.UserRole + 2 SettingsRole = Qt.UserRole + 4 @@ -31,7 +31,7 @@ class SettingVisibilityProfilesModel(ListModel): def _populate(self): items = [] - for item in Resources.getAllResourcesOfType(Resources.PresetSettingVisibilityGroups): + for item in Resources.getAllResourcesOfType(Resources.PresetSettingVisibilityPresets): try: mime_type = MimeTypeDatabase.getMimeTypeForFile(item) except MimeTypeNotFoundError: @@ -76,15 +76,15 @@ class SettingVisibilityProfilesModel(ListModel): # Factory function, used by QML @staticmethod - def createSettingVisibilityProfilesModel(engine, js_engine): - return SettingVisibilityProfilesModel.getInstance() + def createSettingVisibilityPresetsModel(engine, js_engine): + return SettingVisibilityPresetsModel.getInstance() ## Get the singleton instance for this class. @classmethod - def getInstance(cls) -> "SettingVisibilityProfilesModel": + def getInstance(cls) -> "SettingVisibilityPresetsModel": # Note: Explicit use of class name to prevent issues with inheritance. - if not SettingVisibilityProfilesModel.__instance: - SettingVisibilityProfilesModel.__instance = cls() - return SettingVisibilityProfilesModel.__instance + if not SettingVisibilityPresetsModel.__instance: + SettingVisibilityPresetsModel.__instance = cls() + return SettingVisibilityPresetsModel.__instance - __instance = None # type: "SettingVisibilityProfilesModel" \ No newline at end of file + __instance = None # type: "SettingVisibilityPresetsModel" \ No newline at end of file diff --git a/resources/qml/Menus/SettingVisibilityProfilesMenu.qml b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml similarity index 98% rename from resources/qml/Menus/SettingVisibilityProfilesMenu.qml rename to resources/qml/Menus/SettingVisibilityPresetsMenu.qml index 764f07ed41..6fcadeac2c 100644 --- a/resources/qml/Menus/SettingVisibilityProfilesMenu.qml +++ b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml @@ -40,7 +40,7 @@ Menu Instantiator { - model: Cura.SettingVisibilityProfilesModel + model: Cura.SettingVisibilityPresetsModel MenuItem { diff --git a/resources/qml/Preferences/SettingVisibilityPage.qml b/resources/qml/Preferences/SettingVisibilityPage.qml index 3d94fca6c4..64c997e5f7 100644 --- a/resources/qml/Preferences/SettingVisibilityPage.qml +++ b/resources/qml/Preferences/SettingVisibilityPage.qml @@ -123,7 +123,7 @@ UM.PreferencesPage right: parent.right } - model: Cura.SettingVisibilityProfilesModel + model: Cura.SettingVisibilityPresetsModel textRole: "name" currentIndex: diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 6eb37981be..e2e99fbc3d 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -110,7 +110,7 @@ Item ToolButton { - id: settingVisibilityProfileMenu + id: settingVisibilityMenu width: height height: UM.Theme.getSize("setting_control").height @@ -137,7 +137,7 @@ Item } label: Label{} } - menu: SettingVisibilityProfilesMenu + menu: SettingVisibilityPresetsMenu { showingSearchResults: findingSettings showingAllSettings: showingAllSettings @@ -185,7 +185,7 @@ Item topMargin: UM.Theme.getSize("sidebar_margin").height left: parent.left leftMargin: UM.Theme.getSize("sidebar_margin").width - right: settingVisibilityProfileMenu.left + right: settingVisibilityMenu.left rightMargin: Math.floor(UM.Theme.getSize("default_margin").width / 2) } height: visible ? UM.Theme.getSize("setting_control").height : 0 From 4c1002bf47f9ae901a3ecae59c34391b4cb8158b Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 9 Feb 2018 09:19:15 +0100 Subject: [PATCH 037/446] Move setting visibility resource type from Uranium to Cura --- cura/CuraApplication.py | 4 +++- cura/Settings/SettingVisibilityPresetsModel.py | 5 ++++- .../advanced.cfg | 0 .../basic.cfg | 0 .../expert.cfg | 0 5 files changed, 7 insertions(+), 2 deletions(-) rename resources/{preset_setting_visibility_groups => setting_visibility}/advanced.cfg (100%) rename resources/{preset_setting_visibility_groups => setting_visibility}/basic.cfg (100%) rename resources/{preset_setting_visibility_groups => setting_visibility}/expert.cfg (100%) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 19a5b50e65..05ed178bf9 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -130,6 +130,7 @@ class CuraApplication(QtApplication): MachineStack = Resources.UserType + 7 ExtruderStack = Resources.UserType + 8 DefinitionChangesContainer = Resources.UserType + 9 + SettingVisibilityPreset = Resources.UserType + 10 Q_ENUMS(ResourceTypes) @@ -183,6 +184,7 @@ class CuraApplication(QtApplication): Resources.addStorageType(self.ResourceTypes.ExtruderStack, "extruders") Resources.addStorageType(self.ResourceTypes.MachineStack, "machine_instances") Resources.addStorageType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes") + Resources.addStorageType(self.ResourceTypes.SettingVisibilityPreset, "setting_visibility") ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.QualityInstanceContainer, "quality") ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.QualityInstanceContainer, "quality_changes") @@ -360,8 +362,8 @@ class CuraApplication(QtApplication): default_visibility_profile = SettingVisibilityPresetsModel.getInstance().getItem(0) + preferences.addPreference("general/preset_setting_visibility_choice", default_visibility_profile["id"]) preferences.setDefault("general/visible_settings", ";".join(default_visibility_profile["settings"])) - preferences.setDefault("general/preset_setting_visibility_choice", default_visibility_profile["id"]) preset_setting_visibility_choice = Preferences.getInstance().getValue("general/preset_setting_visibility_choice") if not SettingVisibilityPresetsModel.getInstance().find("id", preset_setting_visibility_choice): diff --git a/cura/Settings/SettingVisibilityPresetsModel.py b/cura/Settings/SettingVisibilityPresetsModel.py index a5b4541ee4..6052fd2509 100644 --- a/cura/Settings/SettingVisibilityPresetsModel.py +++ b/cura/Settings/SettingVisibilityPresetsModel.py @@ -13,6 +13,9 @@ from UM.Qt.ListModel import ListModel from UM.Resources import Resources from UM.MimeTypeDatabase import MimeTypeDatabase, MimeTypeNotFoundError +import cura.CuraApplication + + class SettingVisibilityPresetsModel(ListModel): IdRole = Qt.UserRole + 1 NameRole = Qt.UserRole + 2 @@ -31,7 +34,7 @@ class SettingVisibilityPresetsModel(ListModel): def _populate(self): items = [] - for item in Resources.getAllResourcesOfType(Resources.PresetSettingVisibilityPresets): + for item in Resources.getAllResourcesOfType(cura.CuraApplication.CuraApplication.ResourceTypes.SettingVisibilityPreset): try: mime_type = MimeTypeDatabase.getMimeTypeForFile(item) except MimeTypeNotFoundError: diff --git a/resources/preset_setting_visibility_groups/advanced.cfg b/resources/setting_visibility/advanced.cfg similarity index 100% rename from resources/preset_setting_visibility_groups/advanced.cfg rename to resources/setting_visibility/advanced.cfg diff --git a/resources/preset_setting_visibility_groups/basic.cfg b/resources/setting_visibility/basic.cfg similarity index 100% rename from resources/preset_setting_visibility_groups/basic.cfg rename to resources/setting_visibility/basic.cfg diff --git a/resources/preset_setting_visibility_groups/expert.cfg b/resources/setting_visibility/expert.cfg similarity index 100% rename from resources/preset_setting_visibility_groups/expert.cfg rename to resources/setting_visibility/expert.cfg From 74fe281e1db3b3fbf1dc3bf4a3cd041d03acc079 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 9 Feb 2018 17:04:08 +0100 Subject: [PATCH 038/446] Sync currently selected preset between visibility-page and -menu --- cura/CuraApplication.py | 5 --- .../Settings/SettingVisibilityPresetsModel.py | 32 ++++++++++++-- plugins/3MFReader/ThreeMFWorkspaceReader.py | 2 +- resources/qml/Cura.qml | 5 ++- .../Menus/SettingVisibilityPresetsMenu.qml | 40 ++++++----------- .../qml/Preferences/SettingVisibilityPage.qml | 43 +++++++++---------- resources/qml/Settings/SettingView.qml | 16 ++++++- 7 files changed, 82 insertions(+), 61 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 05ed178bf9..87c24d788b 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -362,13 +362,8 @@ class CuraApplication(QtApplication): default_visibility_profile = SettingVisibilityPresetsModel.getInstance().getItem(0) - preferences.addPreference("general/preset_setting_visibility_choice", default_visibility_profile["id"]) preferences.setDefault("general/visible_settings", ";".join(default_visibility_profile["settings"])) - preset_setting_visibility_choice = Preferences.getInstance().getValue("general/preset_setting_visibility_choice") - if not SettingVisibilityPresetsModel.getInstance().find("id", preset_setting_visibility_choice): - Preferences.getInstance().setValue("general/preset_setting_visibility_choice", default_visibility_profile["id"]) - self.applicationShuttingDown.connect(self.saveSettings) self.engineCreatedSignal.connect(self._onEngineCreated) diff --git a/cura/Settings/SettingVisibilityPresetsModel.py b/cura/Settings/SettingVisibilityPresetsModel.py index 6052fd2509..307cbc3602 100644 --- a/cura/Settings/SettingVisibilityPresetsModel.py +++ b/cura/Settings/SettingVisibilityPresetsModel.py @@ -9,7 +9,7 @@ from PyQt5.QtCore import pyqtProperty, Qt, pyqtSignal, pyqtSlot, QUrl from UM.Logger import Logger from UM.Qt.ListModel import ListModel - +from UM.Preferences import Preferences from UM.Resources import Resources from UM.MimeTypeDatabase import MimeTypeDatabase, MimeTypeNotFoundError @@ -27,11 +27,18 @@ class SettingVisibilityPresetsModel(ListModel): self.addRoleName(self.NameRole, "name") self.addRoleName(self.SettingsRole, "settings") - self._container_ids = [] - self._containers = [] - self._populate() + preferences = Preferences.getInstance() + preferences.addPreference("cura/active_setting_visibility_preset", "custom") + + self._active_preset = Preferences.getInstance().getValue("cura/active_setting_visibility_preset") + if self.find("id", self._active_preset) < 0: + self._active_preset = "custom" + + self.activePresetChanged.emit() + + def _populate(self): items = [] for item in Resources.getAllResourcesOfType(cura.CuraApplication.CuraApplication.ResourceTypes.SettingVisibilityPreset): @@ -77,6 +84,23 @@ class SettingVisibilityPresetsModel(ListModel): items.sort(key = lambda k: (k["weight"], k["id"])) self.setItems(items) + @pyqtSlot(str) + def setActivePreset(self, preset_id): + if preset_id != "custom" and self.find("id", preset_id) == -1: + Logger.log("w", "Tried to set active preset to unknown id %s", preset_id) + return + + Preferences.getInstance().setValue("cura/active_setting_visibility_preset", preset_id); + + self._active_preset = preset_id + self.activePresetChanged.emit() + + activePresetChanged = pyqtSignal() + + @pyqtProperty(str, notify = activePresetChanged) + def activePreset(self): + return self._active_preset + # Factory function, used by QML @staticmethod def createSettingVisibilityPresetsModel(engine, js_engine): diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index a2e02fa9d4..bef387d667 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -453,7 +453,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): Logger.log("w", "Workspace did not contain visible settings. Leaving visibility unchanged") else: global_preferences.setValue("general/visible_settings", visible_settings) - global_preferences.setValue("general/preset_setting_visibility_choice", "Custom") + global_preferences.setValue("cura/active_setting_visibility_preset", "custom") categories_expanded = temp_preferences.getValue("cura/categories_expanded") if categories_expanded is None: diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 6f649a7273..6d48ee34c3 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -625,7 +625,10 @@ UM.MainWindow { preferences.visible = true; preferences.setPage(1); - preferences.getCurrentItem().scrollToSection(source.key); + if(source && source.key) + { + preferences.getCurrentItem().scrollToSection(source.key); + } } } diff --git a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml index 6fcadeac2c..72ca93a27e 100644 --- a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml +++ b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml @@ -32,9 +32,13 @@ Menu { text: catalog.i18nc("@action:inmenu", "Custom selection") checkable: true - checked: !showingSearchResults && !showingAllSettings + checked: !showingSearchResults && !showingAllSettings && Cura.SettingVisibilityPresetsModel.activePreset == "custom" exclusiveGroup: group - onTriggered: showSettingVisibilityProfile("Custom") + onTriggered: + { + Cura.SettingVisibilityPresetsModel.setActivePreset("custom"); + showSettingVisibilityProfile(); + } } MenuSeparator { } @@ -46,12 +50,13 @@ Menu { text: model.name checkable: true - checked: false + checked: model.id == Cura.SettingVisibilityPresetsModel.activePreset exclusiveGroup: group onTriggered: { + Cura.SettingVisibilityPresetsModel.setActivePreset(model.id); + UM.Preferences.setValue("general/visible_settings", model.settings.join(";")); - UM.Preferences.setValue("general/preset_setting_visibility_choice", model.id); showSettingVisibilityProfile(); } @@ -61,27 +66,6 @@ Menu onObjectRemoved: menu.removeItem(object) } - MenuSeparator { visible: false } - MenuItem - { - text: catalog.i18nc("@action:inmenu", "Changed settings") - visible: false - enabled: true - checkable: true - checked: showingAllSettings - exclusiveGroup: group - onTriggered: showAllSettings() - } - MenuItem - { - text: catalog.i18nc("@action:inmenu", "Settings in profile") - visible: false - enabled: true - checkable: true - checked: showingAllSettings - exclusiveGroup: group - onTriggered: showAllSettings() - } MenuSeparator {} MenuItem { @@ -89,7 +73,11 @@ Menu checkable: true checked: showingAllSettings exclusiveGroup: group - onTriggered: showAllSettings() + onTriggered: + { + Cura.SettingVisibilityPresetsModel.setActivePreset("custom"); + showAllSettings(); + } } MenuSeparator {} MenuItem diff --git a/resources/qml/Preferences/SettingVisibilityPage.qml b/resources/qml/Preferences/SettingVisibilityPage.qml index 64c997e5f7..fa1b1a1be1 100644 --- a/resources/qml/Preferences/SettingVisibilityPage.qml +++ b/resources/qml/Preferences/SettingVisibilityPage.qml @@ -37,6 +37,8 @@ UM.PreferencesPage id: base; anchors.fill: parent; + property bool inhibitSwitchToCustom: false + CheckBox { id: toggleVisibleSettings @@ -84,7 +86,7 @@ UM.PreferencesPage if (visibilityPreset.currentIndex != visibilityPreset.model.count - 1) { visibilityPreset.currentIndex = visibilityPreset.model.count - 1 - UM.Preferences.setValue("general/preset_setting_visibility_choice", visibilityPreset.model.getItem(visibilityPreset.currentIndex).id) + UM.Preferences.setValue("cura/active_setting_visibility_preset", visibilityPreset.model.getItem(visibilityPreset.currentIndex).id) } } } @@ -129,7 +131,7 @@ UM.PreferencesPage currentIndex: { // Load previously selected preset. - var index = model.find("id", UM.Preferences.getValue("general/preset_setting_visibility_choice")); + var index = model.find("id", model.activePreset); if(index == -1) { index = 0; @@ -140,14 +142,12 @@ UM.PreferencesPage onActivated: { - // TODO What to do if user is selected "Custom from Combobox" ? - if (model.getItem(index).id == "custom"){ - UM.Preferences.setValue("general/preset_setting_visibility_choice", model.get(index).id) - return - } + base.inhibitSwitchToCustom = true; + model.setActivePreset(model.getItem(index).id); - UM.Preferences.setValue("general/visible_settings", model.getItem(index).settings.join(";")) - UM.Preferences.setValue("general/preset_setting_visibility_choice", model.getItem(index).id) + UM.Preferences.setValue("general/visible_settings", model.getItem(index).settings.join(";")); + UM.Preferences.setValue("cura/active_setting_visibility_preset", model.getItem(index).id); + base.inhibitSwitchToCustom = false; } } @@ -177,7 +177,16 @@ UM.PreferencesPage exclude: ["machine_settings", "command_line_settings"] showAncestors: true expanded: ["*"] - visibilityHandler: UM.SettingPreferenceVisibilityHandler { } + visibilityHandler: UM.SettingPreferenceVisibilityHandler + { + onVisibilityChanged: + { + if(Cura.SettingVisibilityPresetsModel.activePreset != "" && !base.inhibitSwitchToCustom) + { + Cura.SettingVisibilityPresetsModel.setActivePreset("custom"); + } + } + } } delegate: Loader @@ -220,19 +229,7 @@ UM.PreferencesPage { id: settingVisibilityItem; - UM.SettingVisibilityItem { - - // after changing any visibility of settings, set the preset to the "Custom" option - visibilityChangeCallback : function() - { - // If already "Custom" then don't do nothing - if (visibilityPreset.currentIndex != visibilityPreset.model.count - 1) - { - visibilityPreset.currentIndex = visibilityPreset.model.count - 1 - UM.Preferences.setValue("general/preset_setting_visibility_choice", visibilityPreset.model.getItem(visibilityPreset.currentIndex).id) - } - } - } + UM.SettingVisibilityItem { } } } } \ No newline at end of file diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index e2e99fbc3d..98753d0b4c 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -18,6 +18,7 @@ Item property Action configureSettings property bool findingSettings property bool showingAllSettings + property bool inhibitSwitchToCustom: false signal showTooltip(Item item, point location, string text) signal hideTooltip() @@ -559,7 +560,15 @@ Item //: Settings context menu action visible: !findingSettings; text: catalog.i18nc("@action:menu", "Hide this setting"); - onTriggered: definitionsModel.hide(contextMenu.key); + onTriggered: + { + definitionsModel.hide(contextMenu.key); + // visible settings have changed, so we're no longer showing a preset + if (Cura.SettingVisibilityPresetsModel.activePreset != "") + { + Cura.SettingVisibilityPresetsModel.setActivePreset("custom"); + } + } } MenuItem { @@ -586,6 +595,11 @@ Item { definitionsModel.show(contextMenu.key); } + // visible settings have changed, so we're no longer showing a preset + if (Cura.SettingVisibilityPresetsModel.activePreset != "") + { + Cura.SettingVisibilityPresetsModel.setActivePreset("custom"); + } } } MenuItem From 61bbfcda3ab59b555618fa07e07f37c516cef284 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 9 Feb 2018 19:28:00 +0100 Subject: [PATCH 039/446] Add back "custom" option to the setting visibility page --- .../qml/Preferences/SettingVisibilityPage.qml | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/resources/qml/Preferences/SettingVisibilityPage.qml b/resources/qml/Preferences/SettingVisibilityPage.qml index fa1b1a1be1..bc271971b4 100644 --- a/resources/qml/Preferences/SettingVisibilityPage.qml +++ b/resources/qml/Preferences/SettingVisibilityPage.qml @@ -125,28 +125,45 @@ UM.PreferencesPage right: parent.right } - model: Cura.SettingVisibilityPresetsModel - textRole: "name" + model: ListModel + { + id: visibilityPresetsModel + Component.onCompleted: + { + visibilityPresetsModel.append({text: catalog.i18nc("@action:inmenu", "Custom selection"), id: "custom"}); + + var presets = Cura.SettingVisibilityPresetsModel; + for(var i = 0; i < presets.rowCount(); i++) + { + visibilityPresetsModel.append({text: presets.getItem(i)["name"], id: presets.getItem(i)["id"]}); + } + } + } currentIndex: { // Load previously selected preset. - var index = model.find("id", model.activePreset); + var index = Cura.SettingVisibilityPresetsModel.find("id", Cura.SettingVisibilityPresetsModel.activePreset); if(index == -1) { - index = 0; + return 0; } - return index; + return index + 1; // "Custom selection" entry is added in front, so index is off by 1 } onActivated: { base.inhibitSwitchToCustom = true; - model.setActivePreset(model.getItem(index).id); + var preset_id = visibilityPresetsModel.get(index).id; + Cura.SettingVisibilityPresetsModel.setActivePreset(preset_id); - UM.Preferences.setValue("general/visible_settings", model.getItem(index).settings.join(";")); - UM.Preferences.setValue("cura/active_setting_visibility_preset", model.getItem(index).id); + UM.Preferences.setValue("cura/active_setting_visibility_preset", preset_id); + if (preset_id != "custom") + { + UM.Preferences.setValue("general/visible_settings", Cura.SettingVisibilityPresetsModel.getItem(index - 1).settings.join(";")); + // "Custom selection" entry is added in front, so index is off by 1 + } base.inhibitSwitchToCustom = false; } } From 3f9d92ade090fed2356e3ace748165e6b644d7e7 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 9 Feb 2018 20:22:46 +0100 Subject: [PATCH 040/446] Remove "Search Results" item It makes no sense to have it; instead none of the other menuitems are selected when search results are shown. --- resources/qml/Menus/SettingVisibilityPresetsMenu.qml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml index 72ca93a27e..d9ffd630e1 100644 --- a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml +++ b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml @@ -18,16 +18,6 @@ Menu signal showAllSettings() signal showSettingVisibilityProfile() - MenuItem - { - text: catalog.i18nc("@action:inmenu", "Search Results") - checkable: true - visible: showingSearchResults - checked: showingSearchResults - exclusiveGroup: group - } - MenuSeparator { visible: showingSearchResults } - MenuItem { text: catalog.i18nc("@action:inmenu", "Custom selection") From 4a499ddfec72aa9d4e0fe4a27d4d6756be47a419 Mon Sep 17 00:00:00 2001 From: Andreea Scorojitu Date: Wed, 14 Feb 2018 10:50:14 +0100 Subject: [PATCH 041/446] CURA-4958 Update_3.2.1_changelog Added the bug fixes done for the 3.2.1 --- plugins/ChangeLogPlugin/ChangeLog.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/ChangeLogPlugin/ChangeLog.txt b/plugins/ChangeLogPlugin/ChangeLog.txt index 6b394f1e2e..8a031c9eae 100755 --- a/plugins/ChangeLogPlugin/ChangeLog.txt +++ b/plugins/ChangeLogPlugin/ChangeLog.txt @@ -1,3 +1,9 @@ +[3.2.1] +*Bug fixes +- Fixed issues where Cura crashes on startup and loading profiles +- Updated translations +- Fixed an issue where the text would not render properly + [3.2.0] *Tree support Experimental tree-like support structure that uses ‘branches’ to support prints. Branches ‘grow’ and multiply towards the model, with fewer contact points than alternative support methods. This results in better surface finishes for organic-shaped prints. From 2f8f42aa64f21b8f4f5a5b9d10a50639147ac51b Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Thu, 15 Feb 2018 10:45:24 +0000 Subject: [PATCH 042/446] Reduce default bridge flows to 50%. --- resources/definitions/fdmprinter.def.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 1467cca252..a3a4583b0b 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6258,7 +6258,7 @@ "label": "Bridge Skin Flow", "description": "Flow compensation: the amount of material extruded when bridging skin is multiplied by this value.", "unit": "%", - "default_value": 100, + "default_value": 50, "type": "float", "minimum_value": "5", "minimum_value_warning": "50", @@ -6271,7 +6271,7 @@ "label": "Bridge Wall Flow", "description": "Flow compensation: the amount of material extruded when bridging walls is multiplied by this value.", "unit": "%", - "default_value": 100, + "default_value": 50, "type": "float", "minimum_value": "5", "minimum_value_warning": "50", From ca115d2f4805b139fc8986cfdeaba9615ec3af0b Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Thu, 15 Feb 2018 10:45:40 +0000 Subject: [PATCH 043/446] Added bridge_wall_coast setting. --- resources/definitions/fdmprinter.def.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index a3a4583b0b..57770df26c 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6225,6 +6225,18 @@ "enabled": "bridge_settings_enabled", "settable_per_mesh": true }, + "bridge_wall_coast": + { + "label": "Bridge Wall Coasting", + "description": "This controls the distance the extruder should coast immediately before a bridge wall begins. Coasting before the bridge starts can reduce the pressure in the nozzle and may produce a flatter bridge.", + "unit": "%", + "default_value": 100, + "type": "float", + "minimum_value": "0", + "maximum_value": "500", + "enabled": "bridge_settings_enabled", + "settable_per_mesh": false + }, "bridge_skin_speed": { "label": "Bridge Skin Speed", From 0cf6e3a1cd7f91bda8f1804caf0d52c63a54de29 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 15 Feb 2018 11:38:51 +0100 Subject: [PATCH 044/446] Set rendertype for units in SettingTextField --- resources/qml/Settings/SettingTextField.qml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/resources/qml/Settings/SettingTextField.qml b/resources/qml/Settings/SettingTextField.qml index 6684ce86cf..f5a15f6f38 100644 --- a/resources/qml/Settings/SettingTextField.qml +++ b/resources/qml/Settings/SettingTextField.qml @@ -83,11 +83,12 @@ SettingItem Label { - anchors.right: parent.right; + anchors.right: parent.right anchors.rightMargin: Math.round(UM.Theme.getSize("setting_unit_margin").width) - anchors.verticalCenter: parent.verticalCenter; + anchors.verticalCenter: parent.verticalCenter - text: definition.unit; + text: definition.unit + renderType: Text.NativeRendering color: UM.Theme.getColor("setting_unit") font: UM.Theme.getFont("default") } From ec8dea927f8d20976953a2388374969e7b493e4d Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 15 Feb 2018 11:34:46 +0100 Subject: [PATCH 045/446] Fix categories too --- resources/qml/Settings/SettingCategory.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/qml/Settings/SettingCategory.qml b/resources/qml/Settings/SettingCategory.qml index 5f22910b00..2266249678 100644 --- a/resources/qml/Settings/SettingCategory.qml +++ b/resources/qml/Settings/SettingCategory.qml @@ -78,6 +78,7 @@ Button verticalCenter: parent.verticalCenter; } text: definition.label + renderType: Text.NativeRendering font: UM.Theme.getFont("setting_category") color: { From 7e4f60cc128f4c6b51c83369af7427c6cacc3a96 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 15 Feb 2018 11:12:19 +0100 Subject: [PATCH 046/446] Set renderType to Text.NativeRendering for qtquick controls 2 Labels Apparently, the qtquickcontrols 2 Label no longer defaults to using renderType: Text.NativeRendering This causes text to render with QtRendering which looks subtly different on Windows and succinctly broken on some OSX installations. --- resources/qml/Settings/SettingComboBox.qml | 2 ++ resources/qml/Settings/SettingExtruder.qml | 2 ++ resources/qml/Settings/SettingItem.qml | 4 +--- resources/qml/Settings/SettingOptionalExtruder.qml | 2 ++ resources/qml/Sidebar.qml | 5 ++++- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/resources/qml/Settings/SettingComboBox.qml b/resources/qml/Settings/SettingComboBox.qml index 4debf147ae..ad41fc3385 100644 --- a/resources/qml/Settings/SettingComboBox.qml +++ b/resources/qml/Settings/SettingComboBox.qml @@ -80,6 +80,7 @@ SettingItem anchors.right: downArrow.left text: control.currentText + renderType: Text.NativeRendering font: UM.Theme.getFont("default") color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : UM.Theme.getColor("setting_control_text") elide: Text.ElideRight @@ -116,6 +117,7 @@ SettingItem contentItem: Label { text: modelData.value + renderType: Text.NativeRendering color: control.contentItem.color font: UM.Theme.getFont("default") elide: Text.ElideRight diff --git a/resources/qml/Settings/SettingExtruder.qml b/resources/qml/Settings/SettingExtruder.qml index 462512f476..d63f73717a 100644 --- a/resources/qml/Settings/SettingExtruder.qml +++ b/resources/qml/Settings/SettingExtruder.qml @@ -117,6 +117,7 @@ SettingItem rightPadding: swatch.width + UM.Theme.getSize("setting_unit_margin").width text: control.currentText + renderType: Text.NativeRendering font: UM.Theme.getFont("default") color: enabled ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text") @@ -171,6 +172,7 @@ SettingItem contentItem: Label { text: model.name + renderType: Text.NativeRendering color: UM.Theme.getColor("setting_control_text") font: UM.Theme.getFont("default") elide: Text.ElideRight diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index 41fc21b026..8150c1b382 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -112,11 +112,9 @@ Item { anchors.right: settingControls.left; anchors.verticalCenter: parent.verticalCenter - height: UM.Theme.getSize("section").height; - verticalAlignment: Text.AlignVCenter; - text: definition.label elide: Text.ElideMiddle; + renderType: Text.NativeRendering color: UM.Theme.getColor("setting_control_text"); opacity: (definition.visible) ? 1 : 0.5 diff --git a/resources/qml/Settings/SettingOptionalExtruder.qml b/resources/qml/Settings/SettingOptionalExtruder.qml index 2a5220ad5e..bf4cd733d9 100644 --- a/resources/qml/Settings/SettingOptionalExtruder.qml +++ b/resources/qml/Settings/SettingOptionalExtruder.qml @@ -136,6 +136,7 @@ SettingItem rightPadding: swatch.width + UM.Theme.getSize("setting_unit_margin").width text: control.currentText + renderType: Text.NativeRendering font: UM.Theme.getFont("default") color: enabled ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text") @@ -190,6 +191,7 @@ SettingItem contentItem: Label { text: model.name + renderType: Text.NativeRendering color: UM.Theme.getColor("setting_control_text") font: UM.Theme.getFont("default") elide: Text.ElideRight diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml index 2da16f3ccb..7b2d6b2247 100644 --- a/resources/qml/Sidebar.qml +++ b/resources/qml/Sidebar.qml @@ -207,12 +207,13 @@ Rectangle color: (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active") : control.hovered ? UM.Theme.getColor("action_button_hovered") : UM.Theme.getColor("action_button") } - contentItem: Text + contentItem: Label { text: model.text font: UM.Theme.getFont("default") horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter + renderType: Text.NativeRendering elide: Text.ElideRight color: { @@ -352,6 +353,7 @@ Rectangle font: UM.Theme.getFont("large") color: UM.Theme.getColor("text_subtext") text: (!base.printDuration || !base.printDuration.valid) ? catalog.i18nc("@label Hours and minutes", "00h 00min") : base.printDuration.getDisplayString(UM.DurationFormat.Short) + renderType: Text.NativeRendering MouseArea { @@ -479,6 +481,7 @@ Rectangle anchors.left: parent.left anchors.bottom: parent.bottom font: UM.Theme.getFont("very_small") + renderType: Text.NativeRendering color: UM.Theme.getColor("text_subtext") elide: Text.ElideMiddle width: parent.width From 0fe2806667824669c4ea71976f6624160488b9ca Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 15 Feb 2018 12:53:14 +0100 Subject: [PATCH 047/446] Add native rendering to Print Setup Label CURA-4941 --- resources/qml/Sidebar.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml index 7b2d6b2247..faf226d556 100644 --- a/resources/qml/Sidebar.qml +++ b/resources/qml/Sidebar.qml @@ -126,6 +126,7 @@ Rectangle { id: settingsModeLabel text: !hideSettings ? catalog.i18nc("@label:listbox", "Print Setup") : catalog.i18nc("@label:listbox", "Print Setup disabled\nG-code files cannot be modified") + renderType: Text.NativeRendering anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width anchors.top: hideSettings ? machineSelection.bottom : headerSeparator.bottom From ca3dd511a8193e30321b5d0219ea44384e869f0b Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 15 Feb 2018 16:39:37 +0100 Subject: [PATCH 048/446] Add a button to open the configuration folder. --- cura/CrashHandler.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/cura/CrashHandler.py b/cura/CrashHandler.py index 4d8cb6f54d..f0771dade1 100644 --- a/cura/CrashHandler.py +++ b/cura/CrashHandler.py @@ -15,9 +15,11 @@ import urllib.error import shutil import sys -from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR +from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR, Qt, QUrl from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QLabel, QTextEdit, QGroupBox, QCheckBox, QPushButton +from PyQt5.QtGui import QDesktopServices +from UM.Resources import Resources from UM.Application import Application from UM.Logger import Logger from UM.View.GL.OpenGL import OpenGL @@ -91,6 +93,7 @@ class CrashHandler: label = QLabel() label.setText(catalog.i18nc("@label crash message", """

A fatal error has occurred.

Unfortunately, Cura encountered an unrecoverable error during start up. It was possibly caused by some incorrect configuration files. We suggest to backup and reset your configuration.

+

Backups can be found in the configuration folder.

Please send us this Crash Report to fix the problem.

""")) label.setWordWrap(True) @@ -104,8 +107,13 @@ class CrashHandler: show_details_button.setMaximumWidth(200) show_details_button.clicked.connect(self._showDetailedReport) + show_configuration_folder_button = QPushButton(catalog.i18nc("@action:button", "Show configuration folder"), dialog) + show_configuration_folder_button.setMaximumWidth(200) + show_configuration_folder_button.clicked.connect(self._showConfigurationFolder) + layout.addWidget(self._send_report_checkbox) layout.addWidget(show_details_button) + layout.addWidget(show_configuration_folder_button) # "backup and start clean" and "close" buttons buttons = QDialogButtonBox() @@ -181,6 +189,10 @@ class CrashHandler: self.early_crash_dialog.close() + def _showConfigurationFolder(self): + path = Resources.getConfigStoragePath(); + QDesktopServices.openUrl(QUrl.fromLocalFile( path )) + def _showDetailedReport(self): self.dialog.exec_() From bd1f2922effd7f852bea90dadc3298054733ae97 Mon Sep 17 00:00:00 2001 From: Christophe Baribaud Date: Sat, 17 Feb 2018 13:30:08 +0100 Subject: [PATCH 049/446] Post stretch algorithm fixes Extract line width from current extruder nozzle size Change default values of stretch parameters from 0.08 to 0.1 --- .../PostProcessingPlugin/scripts/Stretch.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/PostProcessingPlugin/scripts/Stretch.py b/plugins/PostProcessingPlugin/scripts/Stretch.py index bcb923d3ff..c7a36ab7d6 100644 --- a/plugins/PostProcessingPlugin/scripts/Stretch.py +++ b/plugins/PostProcessingPlugin/scripts/Stretch.py @@ -12,6 +12,7 @@ import numpy as np from UM.Logger import Logger from UM.Application import Application import re +from cura.Settings.ExtruderManager import ExtruderManager def _getValue(line, key, default=None): """ @@ -90,9 +91,9 @@ class Stretcher(): """ Computes the new X and Y coordinates of all g-code steps """ - Logger.log("d", "Post stretch with line width = " + str(self.line_width) - + "mm wide circle stretch = " + str(self.wc_stretch)+ "mm" - + "and push wall stretch = " + str(self.pw_stretch) + "mm") + Logger.log("d", "Post stretch with line width " + str(self.line_width) + + "mm wide circle stretch " + str(self.wc_stretch)+ "mm" + + " and push wall stretch " + str(self.pw_stretch) + "mm") retdata = [] layer_steps = [] current = GCodeStep(0) @@ -282,7 +283,7 @@ class Stretcher(): dmin_tri is the minimum distance between two consecutive points of an acceptable triangle """ - dmin_tri = self.line_width / 2.0 + dmin_tri = 0.5 iextra_base = np.floor_divide(len(orig_seq), 3) # Nb of extra points ibeg = 0 # Index of first point of the triangle iend = 0 # Index of the third point of the triangle @@ -325,9 +326,10 @@ class Stretcher(): relpos = 0.5 # To avoid division by zero or precision loss projection = (pos_before[ibeg] + relpos * (pos_after[iend] - pos_before[ibeg])) dist_from_proj = np.sqrt(((projection - step) ** 2).sum(0)) - if dist_from_proj > 0.001: # Move central point only if points are not aligned + if dist_from_proj > 0.0003: # Move central point only if points are not aligned modif_seq[i] = (step - (self.wc_stretch / dist_from_proj) * (projection - step)) + return def wideTurn(self, orig_seq, modif_seq): @@ -411,8 +413,6 @@ class Stretcher(): modif_seq[ibeg] = modif_seq[ibeg] + xperp * self.pw_stretch elif not materialleft and materialright: modif_seq[ibeg] = modif_seq[ibeg] - xperp * self.pw_stretch - if materialleft and materialright: - modif_seq[ibeg] = orig_seq[ibeg] # Surrounded by walls, don't move # Setup part of the stretch plugin class Stretch(Script): @@ -437,7 +437,7 @@ class Stretch(Script): "description": "Distance by which the points are moved by the correction effect in corners. The higher this value, the higher the effect", "unit": "mm", "type": "float", - "default_value": 0.08, + "default_value": 0.1, "minimum_value": 0, "minimum_value_warning": 0, "maximum_value_warning": 0.2 @@ -448,7 +448,7 @@ class Stretch(Script): "description": "Distance by which the points are moved by the correction effect when two lines are nearby. The higher this value, the higher the effect", "unit": "mm", "type": "float", - "default_value": 0.08, + "default_value": 0.1, "minimum_value": 0, "minimum_value_warning": 0, "maximum_value_warning": 0.2 @@ -463,7 +463,7 @@ class Stretch(Script): the returned string is the list of modified g-code instructions """ stretcher = Stretcher( - Application.getInstance().getGlobalContainerStack().getProperty("line_width", "value") + ExtruderManager.getInstance().getActiveExtruderStack().getProperty("machine_nozzle_size", "value") , self.getSettingValueByKey("wc_stretch"), self.getSettingValueByKey("pw_stretch")) return stretcher.execute(data) From 112bb260acb8655e929cf377b18f505d62608eb1 Mon Sep 17 00:00:00 2001 From: Simon Lundell Date: Sun, 18 Feb 2018 11:44:04 +0100 Subject: [PATCH 050/446] Do not send new G-CODEs when the RX buffer is filling up. This is in an attempt to fix #1777 where smoothieware based printers would halt in the middle of the print. --- plugins/USBPrinting/USBPrinterOutputDevice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index b53f502d81..c177ad64d6 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -304,7 +304,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): self._sendCommand(self._command_queue.get()) elif self._paused: pass # Nothing to do! - else: + elif self._serial.in_waiting < 256: # Do not send new G-CODE when the RX buffer is filling up self._sendNextGcodeLine() elif b"resend" in line.lower() or b"rs" in line: # A resend can be requested either by Resend, resend or rs. From c3bf0b834d6e1a78849ef85604615524f1b2368e Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 20 Feb 2018 09:20:01 +0100 Subject: [PATCH 051/446] Fix location of post processing scripts on Linux On Windows and OSX, resources and preferences are stored in the same folder. On Linux, preferences are in ~/.config, resources are in ~/.local/shared. Postprocessing scripts belong in the latter, along with all the other resources (definitions, plugins, themes). Fixes #3356 --- plugins/PostProcessingPlugin/PostProcessingPlugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/PostProcessingPlugin/PostProcessingPlugin.py b/plugins/PostProcessingPlugin/PostProcessingPlugin.py index f491afbec0..92e31d9135 100644 --- a/plugins/PostProcessingPlugin/PostProcessingPlugin.py +++ b/plugins/PostProcessingPlugin/PostProcessingPlugin.py @@ -173,7 +173,7 @@ class PostProcessingPlugin(QObject, Extension): Logger.log("d", "Creating post processing plugin view.") ## Load all scripts in the scripts folders - for root in [PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), Resources.getStoragePath(Resources.Preferences)]: + for root in [PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), Resources.getStoragePath(Resources.Resources)]: path = os.path.join(root, "scripts") if not os.path.isdir(path): try: From d62dbe51876da7c8715b54ec1b30774914a782fa Mon Sep 17 00:00:00 2001 From: Simon Lundell Date: Fri, 23 Feb 2018 16:12:01 +0100 Subject: [PATCH 052/446] Stop sending empty commands as this confuses the communication with e.g. Smoothieware. See PR #3346 and bug #1777 --- plugins/USBPrinting/USBPrinterOutputDevice.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index c177ad64d6..a25bfcb5a2 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -266,7 +266,6 @@ class USBPrinterOutputDevice(PrinterOutputDevice): command = (command + "\n").encode() if not command.endswith(b"\n"): command += b"\n" - self._serial.write(b"\n") self._serial.write(command) def _update(self): From 946a09eb62e1bbf3fe623e47da2de61de3686d37 Mon Sep 17 00:00:00 2001 From: Simon Lundell Date: Fri, 23 Feb 2018 16:14:57 +0100 Subject: [PATCH 053/446] Parse heatbed temperatures even if no extruder temperature is sent. Attempts to fix bug #3332 --- plugins/USBPrinting/USBPrinterOutputDevice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index a25bfcb5a2..e34736c241 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -280,7 +280,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): self.sendCommand("M105") self._last_temperature_request = time() - if b"ok T:" in line or line.startswith(b"T:"): # Temperature message + if b"ok T:" in line or line.startswith(b"T:") or b"ok B:" in line or line.startswith(b"B:"): # Temperature message. 'T:' for extruder and 'B:' for bed extruder_temperature_matches = re.findall(b"T(\d*): ?([\d\.]+) ?\/?([\d\.]+)?", line) # Update all temperature values for match, extruder in zip(extruder_temperature_matches, self._printers[0].extruders): From b1be25e8d8142d59cddb5d5ec505808810598c66 Mon Sep 17 00:00:00 2001 From: Simon Lundell Date: Fri, 23 Feb 2018 18:13:42 +0100 Subject: [PATCH 054/446] Start the device thread GCODE streaming after the main thread has sent those first few lines of codes. This fixes an issue where a race between the main thread and device thread, caused both to try to send the first lines of codes and the line numbering were then messed up. This caused the printer to send a resend request for a line whose number Cura did not recognize, and the printing would wait forever to start. --- plugins/USBPrinting/USBPrinterOutputDevice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index e34736c241..942e8d5306 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -198,7 +198,6 @@ class USBPrinterOutputDevice(PrinterOutputDevice): # Reset line number. If this is not done, first line is sometimes ignored self._gcode.insert(0, "M110") self._gcode_position = 0 - self._is_printing = True self._print_start_time = time() self._print_estimated_time = int(Application.getInstance().getPrintInformation().currentPrintTime.getDisplayString(DurationFormat.Format.Seconds)) @@ -206,6 +205,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): for i in range(0, 4): # Push first 4 entries before accepting other inputs self._sendNextGcodeLine() + self._is_printing = True self.writeFinished.emit(self) def _autoDetectFinished(self, job: AutoDetectBaudJob): From b3f0292ce60c2920a9117de8fb102dc40f19aa51 Mon Sep 17 00:00:00 2001 From: Simon Lundell Date: Fri, 23 Feb 2018 18:19:11 +0100 Subject: [PATCH 055/446] Cancel the print when the printer sends message (b'!!') about a fatal error. --- plugins/USBPrinting/USBPrinterOutputDevice.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index 942e8d5306..8cb477d10d 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -298,6 +298,9 @@ class USBPrinterOutputDevice(PrinterOutputDevice): self._printers[0].updateTargetBedTemperature(float(match[1])) if self._is_printing: + if line.startswith(b'!!'): + Logger.log('e', "Printer signals fatal error. Cancelling print. {}".format(line)) + self.cancelPrint() if b"ok" in line: if not self._command_queue.empty(): self._sendCommand(self._command_queue.get()) From 5214ef3bde8e632908d2b346e2a96c6f8a3df766 Mon Sep 17 00:00:00 2001 From: Simon Lundell Date: Fri, 23 Feb 2018 18:20:47 +0100 Subject: [PATCH 056/446] Add a retry when probing for printers on discovered ports. This is to accomodate for printers that needs a few seconds to initialize before they open the port. --- plugins/USBPrinting/AutoDetectBaudJob.py | 61 +++++++++++++----------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/plugins/USBPrinting/AutoDetectBaudJob.py b/plugins/USBPrinting/AutoDetectBaudJob.py index 72f4f20262..50bb831ba8 100644 --- a/plugins/USBPrinting/AutoDetectBaudJob.py +++ b/plugins/USBPrinting/AutoDetectBaudJob.py @@ -22,6 +22,7 @@ class AutoDetectBaudJob(Job): def run(self): Logger.log("d", "Auto detect baud rate started.") timeout = 3 + tries = 2 programmer = Stk500v2() serial = None @@ -31,36 +32,38 @@ class AutoDetectBaudJob(Job): except: programmer.close() - for baud_rate in self._all_baud_rates: - Logger.log("d", "Checking {serial} if baud rate {baud_rate} works".format(serial= self._serial_port, baud_rate = baud_rate)) + for retry in range(tries): + for baud_rate in self._all_baud_rates: + Logger.log("d", "Checking {serial} if baud rate {baud_rate} works".format(serial= self._serial_port, baud_rate = baud_rate)) - if serial is None: - try: - serial = Serial(str(self._serial_port), baud_rate, timeout = timeout, writeTimeout = timeout) - except SerialException as e: - Logger.logException("w", "Unable to create serial") - continue - else: - # We already have a serial connection, just change the baud rate. - try: - serial.baudrate = baud_rate - except: - continue - sleep(1.5) # Ensure that we are not talking to the boot loader. 1.5 seconds seems to be the magic number - successful_responses = 0 - - serial.write(b"\n") # Ensure we clear out previous responses - serial.write(b"M105\n") - - timeout_time = time() + timeout - - while timeout_time > time(): - line = serial.readline() - if b"ok T:" in line: - successful_responses += 1 - if successful_responses >= 3: - self.setResult(baud_rate) - return + if serial is None: + try: + serial = Serial(str(self._serial_port), baud_rate, timeout = timeout, writeTimeout = timeout) + except SerialException as e: + Logger.logException("w", "Unable to create serial") + continue + else: + # We already have a serial connection, just change the baud rate. + try: + serial.baudrate = baud_rate + except: + continue + sleep(1.5) # Ensure that we are not talking to the boot loader. 1.5 seconds seems to be the magic number + successful_responses = 0 + serial.write(b"\n") # Ensure we clear out previous responses serial.write(b"M105\n") + + timeout_time = time() + timeout + + while timeout_time > time(): + line = serial.readline() + if b"ok T:" in line: + successful_responses += 1 + if successful_responses >= 3: + self.setResult(baud_rate) + return + + serial.write(b"M105\n") + sleep(15) # Give the printer some time to init and try again. self.setResult(None) # Unable to detect the correct baudrate. From a024be78dc4a74d6ef9ae0776533b42e33d1d443 Mon Sep 17 00:00:00 2001 From: Simon Lundell Date: Fri, 23 Feb 2018 18:54:31 +0100 Subject: [PATCH 057/446] Reverting this commit as this was not the correct way to fix it. Revert "Do not send new G-CODEs when the RX buffer is filling up. This is in an attempt to fix #1777 where smoothieware based printers would halt in the middle of the print." This reverts commit 112bb260acb8655e929cf377b18f505d62608eb1. --- plugins/USBPrinting/USBPrinterOutputDevice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index 8cb477d10d..4f5fdc340a 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -306,7 +306,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): self._sendCommand(self._command_queue.get()) elif self._paused: pass # Nothing to do! - elif self._serial.in_waiting < 256: # Do not send new G-CODE when the RX buffer is filling up + else: self._sendNextGcodeLine() elif b"resend" in line.lower() or b"rs" in line: # A resend can be requested either by Resend, resend or rs. From 0d8302d864fc36dd466c9f0c481f574da59aae41 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 27 Feb 2018 11:23:04 +0100 Subject: [PATCH 058/446] CURA-4870 Start showing the list of printers separating between local and networked priters. --- resources/qml/Menus/LocalPrinterMenu.qml | 26 +++++++++++++++++ resources/qml/Menus/NetworkPrinterMenu.qml | 26 +++++++++++++++++ resources/qml/Menus/PrinterMenu.qml | 34 +++++++++++----------- resources/qml/Topbar.qml | 2 +- 4 files changed, 70 insertions(+), 18 deletions(-) create mode 100644 resources/qml/Menus/LocalPrinterMenu.qml create mode 100644 resources/qml/Menus/NetworkPrinterMenu.qml diff --git a/resources/qml/Menus/LocalPrinterMenu.qml b/resources/qml/Menus/LocalPrinterMenu.qml new file mode 100644 index 0000000000..ef9a7b13b0 --- /dev/null +++ b/resources/qml/Menus/LocalPrinterMenu.qml @@ -0,0 +1,26 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.2 +import QtQuick.Controls 1.4 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +Instantiator +{ + model: UM.ContainerStacksModel + { + filter: {"type": "machine", "um_network_key": null} + } + MenuItem + { + text: model.name; + checkable: true; + checked: Cura.MachineManager.activeMachineId == model.id + exclusiveGroup: group; + onTriggered: Cura.MachineManager.setActiveMachine(model.id); + } + onObjectAdded: menu.insertItem(index, object) + onObjectRemoved: menu.removeItem(object) +} diff --git a/resources/qml/Menus/NetworkPrinterMenu.qml b/resources/qml/Menus/NetworkPrinterMenu.qml new file mode 100644 index 0000000000..3dadad3913 --- /dev/null +++ b/resources/qml/Menus/NetworkPrinterMenu.qml @@ -0,0 +1,26 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.2 +import QtQuick.Controls 1.4 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +Instantiator +{ + model: UM.ContainerStacksModel + { + filter: {"type": "machine", "um_network_key": "*"} + } + MenuItem + { + text: model.name; + checkable: true; + checked: Cura.MachineManager.activeMachineId == model.id + exclusiveGroup: group; + onTriggered: Cura.MachineManager.setActiveMachine(model.id); + } + onObjectAdded: menu.insertItem(index, object) + onObjectRemoved: menu.removeItem(object) +} diff --git a/resources/qml/Menus/PrinterMenu.qml b/resources/qml/Menus/PrinterMenu.qml index 073723a60d..0d60606fb9 100644 --- a/resources/qml/Menus/PrinterMenu.qml +++ b/resources/qml/Menus/PrinterMenu.qml @@ -1,8 +1,8 @@ -// Copyright (c) 2016 Ultimaker B.V. +// Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.2 -import QtQuick.Controls 1.1 +import QtQuick.Controls 1.4 import UM 1.2 as UM import Cura 1.0 as Cura @@ -11,24 +11,24 @@ Menu { id: menu; - Instantiator + MenuItem { - model: UM.ContainerStacksModel - { - filter: {"type": "machine"} - } - MenuItem - { - text: model.name; - checkable: true; - checked: Cura.MachineManager.activeMachineId == model.id - exclusiveGroup: group; - onTriggered: Cura.MachineManager.setActiveMachine(model.id); - } - onObjectAdded: menu.insertItem(index, object) - onObjectRemoved: menu.removeItem(object) + text: "Network printers" + checkable: false } + NetworkPrinterMenu { } + + MenuSeparator { } + + MenuItem + { + text: "Local printers" + checkable: false + } + + LocalPrinterMenu { } + ExclusiveGroup { id: group; } MenuSeparator { } diff --git a/resources/qml/Topbar.qml b/resources/qml/Topbar.qml index 950b9ec12d..69d27d483a 100644 --- a/resources/qml/Topbar.qml +++ b/resources/qml/Topbar.qml @@ -150,7 +150,7 @@ Rectangle visible: base.width - allItemsWidth - 1 * this.width > 0 } - // #5 Left view + // #5 Right view Button { iconSource: UM.Theme.getIcon("view_right") From 6fca1f1589677a9bb90bb6dfeab00d82b8e386d2 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 27 Feb 2018 13:14:18 +0100 Subject: [PATCH 059/446] CURA-4870 Add i18n labels --- resources/qml/Menus/PrinterMenu.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/qml/Menus/PrinterMenu.qml b/resources/qml/Menus/PrinterMenu.qml index 0d60606fb9..283063b522 100644 --- a/resources/qml/Menus/PrinterMenu.qml +++ b/resources/qml/Menus/PrinterMenu.qml @@ -13,8 +13,8 @@ Menu MenuItem { - text: "Network printers" - checkable: false + text: catalog.i18nc("@label:category menu label", "Network printers") + enabled: false } NetworkPrinterMenu { } @@ -23,8 +23,8 @@ Menu MenuItem { - text: "Local printers" - checkable: false + text: catalog.i18nc("@label:category menu label", "Local printers") + enabled: false } LocalPrinterMenu { } From dae2d9d761c2233f58d4300973253e6d45c300fe Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Tue, 27 Feb 2018 13:20:18 +0100 Subject: [PATCH 060/446] Add Dockerfile --- Dockerfile | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..4aa7b4557c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +FROM ultimaker/cura-build-environment:3.2 + +# Environment vars for easy configuration +ENV CURA_BRANCH=master +ENV URANIUM_BRANCH=$CURA_BRANCH +ENV CURA_BENV_GIT_DIR=/srv/cura + +# Setup the repositories +RUN mkdir $CURA_BENV_GIT_DIR +WORKDIR $CURA_BENV_GIT_DIR +RUN git clone https://github.com/Ultimaker/Uranium +WORKDIR $CURA_BENV_GIT_DIR/Uranium +RUN git fetch origin +RUN git checkout $URANIUM_BRANCH +RUN git clone https://github.com/Ultimaker/cura +WORKDIR $CURA_BENV_GIT_DIR/Cura +RUN git fetch origin +RUN git checkout origin $CURA_BRANCH + +# Ensure Uranium is in the python path +RUN export PYTHOHPATH="${PYTHONPATH}:$CURA_BENV_GIT_DIR/Uranium" + +# Run Cura +CMD ["python3", "cura_app.py"] From 4dd01afffbc96363f18fc16773a5a37d42d1324f Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Tue, 27 Feb 2018 13:31:07 +0100 Subject: [PATCH 061/446] Cleanup Dockerfile --- Dockerfile | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4aa7b4557c..e71ae35b46 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,20 +5,23 @@ ENV CURA_BRANCH=master ENV URANIUM_BRANCH=$CURA_BRANCH ENV CURA_BENV_GIT_DIR=/srv/cura -# Setup the repositories RUN mkdir $CURA_BENV_GIT_DIR + +# Setup Uranium WORKDIR $CURA_BENV_GIT_DIR RUN git clone https://github.com/Ultimaker/Uranium WORKDIR $CURA_BENV_GIT_DIR/Uranium RUN git fetch origin RUN git checkout $URANIUM_BRANCH +RUN export PYTHOHPATH="${PYTHONPATH}:$CURA_BENV_GIT_DIR/Uranium" + +# Setup Cura +WORKDIR $CURA_BENV_GIT_DIR RUN git clone https://github.com/Ultimaker/cura WORKDIR $CURA_BENV_GIT_DIR/Cura RUN git fetch origin RUN git checkout origin $CURA_BRANCH -# Ensure Uranium is in the python path -RUN export PYTHOHPATH="${PYTHONPATH}:$CURA_BENV_GIT_DIR/Uranium" - # Run Cura +WORKDIR $CURA_BENV_GIT_DIR/Cura CMD ["python3", "cura_app.py"] From 8144ca978b2b67d413c5acd36766da2e6d9f6cf5 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Tue, 27 Feb 2018 15:55:24 +0100 Subject: [PATCH 062/446] Add CuraEngine to Dockerfile --- Dockerfile | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index e71ae35b46..3f21496e92 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,10 @@ FROM ultimaker/cura-build-environment:3.2 # Environment vars for easy configuration +ENV CURA_BENV_BUILD_TYPE=Release ENV CURA_BRANCH=master ENV URANIUM_BRANCH=$CURA_BRANCH +ENV CURA_ENGINE_BRANCH=$CURA_BRANCH ENV CURA_BENV_GIT_DIR=/srv/cura RUN mkdir $CURA_BENV_GIT_DIR @@ -17,11 +19,28 @@ RUN export PYTHOHPATH="${PYTHONPATH}:$CURA_BENV_GIT_DIR/Uranium" # Setup Cura WORKDIR $CURA_BENV_GIT_DIR -RUN git clone https://github.com/Ultimaker/cura +RUN git clone https://github.com/Ultimaker/Cura WORKDIR $CURA_BENV_GIT_DIR/Cura RUN git fetch origin RUN git checkout origin $CURA_BRANCH +# Setup CuraEngine +WORKDIR $CURA_BENV_GIT_DIR +RUN git clone https://github.com/Ultimaker/CuraEngine +WORKDIR $CURA_BENV_GIT_DIR/CuraEngine +RUN git fetch origin +RUN git checkout $URANIUM_BRANCH +RUN mkdir build +WORKDIR $CURA_BENV_GIT_DIR/CuraEngine/build +RUN cmake3 .. \ + -DCMAKE_BUILD_TYPE=$CURA_BENV_BUILD_TYPE \ + -DCMAKE_C_COMPILER=gcc \ + -DCMAKE_CXX_COMPILER=g++ +RUN make + +# Make sure Cura can find CuraEngine +RUN ln -s /usr/local/bin/CuraEngine $CURA_BENV_GIT_DIR/Cura + # Run Cura WORKDIR $CURA_BENV_GIT_DIR/Cura CMD ["python3", "cura_app.py"] From e1a6ab098a5ebf79a0a21fdb16ad55f740335682 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Tue, 27 Feb 2018 16:21:07 +0100 Subject: [PATCH 063/446] Rename source paths env variable --- Dockerfile | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Dockerfile b/Dockerfile index 3f21496e92..b2ecb5e843 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,33 +5,33 @@ ENV CURA_BENV_BUILD_TYPE=Release ENV CURA_BRANCH=master ENV URANIUM_BRANCH=$CURA_BRANCH ENV CURA_ENGINE_BRANCH=$CURA_BRANCH -ENV CURA_BENV_GIT_DIR=/srv/cura +ENV CURA_APP_DIR=/srv/cura -RUN mkdir $CURA_BENV_GIT_DIR +RUN mkdir $CURA_APP_DIR # Setup Uranium -WORKDIR $CURA_BENV_GIT_DIR +WORKDIR $CURA_APP_DIR RUN git clone https://github.com/Ultimaker/Uranium -WORKDIR $CURA_BENV_GIT_DIR/Uranium +WORKDIR $CURA_APP_DIR/Uranium RUN git fetch origin RUN git checkout $URANIUM_BRANCH -RUN export PYTHOHPATH="${PYTHONPATH}:$CURA_BENV_GIT_DIR/Uranium" +RUN export PYTHOHPATH="${PYTHONPATH}:$CURA_APP_DIR/Uranium" # Setup Cura -WORKDIR $CURA_BENV_GIT_DIR +WORKDIR $CURA_APP_DIR RUN git clone https://github.com/Ultimaker/Cura -WORKDIR $CURA_BENV_GIT_DIR/Cura +WORKDIR $CURA_APP_DIR/Cura RUN git fetch origin RUN git checkout origin $CURA_BRANCH # Setup CuraEngine -WORKDIR $CURA_BENV_GIT_DIR +WORKDIR $CURA_APP_DIR RUN git clone https://github.com/Ultimaker/CuraEngine -WORKDIR $CURA_BENV_GIT_DIR/CuraEngine +WORKDIR $CURA_APP_DIR/CuraEngine RUN git fetch origin RUN git checkout $URANIUM_BRANCH RUN mkdir build -WORKDIR $CURA_BENV_GIT_DIR/CuraEngine/build +WORKDIR $CURA_APP_DIR/CuraEngine/build RUN cmake3 .. \ -DCMAKE_BUILD_TYPE=$CURA_BENV_BUILD_TYPE \ -DCMAKE_C_COMPILER=gcc \ @@ -39,8 +39,8 @@ RUN cmake3 .. \ RUN make # Make sure Cura can find CuraEngine -RUN ln -s /usr/local/bin/CuraEngine $CURA_BENV_GIT_DIR/Cura +RUN ln -s /usr/local/bin/CuraEngine $CURA_APP_DIR/Cura # Run Cura -WORKDIR $CURA_BENV_GIT_DIR/Cura +WORKDIR $CURA_APP_DIR/Cura CMD ["python3", "cura_app.py"] From d3f7771e16e00b15efd08214eab146950bfdb6b6 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Tue, 27 Feb 2018 16:24:17 +0100 Subject: [PATCH 064/446] Simplify cura engine cmake --- Dockerfile | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index b2ecb5e843..3f2a3a239e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,10 +32,7 @@ RUN git fetch origin RUN git checkout $URANIUM_BRANCH RUN mkdir build WORKDIR $CURA_APP_DIR/CuraEngine/build -RUN cmake3 .. \ - -DCMAKE_BUILD_TYPE=$CURA_BENV_BUILD_TYPE \ - -DCMAKE_C_COMPILER=gcc \ - -DCMAKE_CXX_COMPILER=g++ +RUN cmake3 .. RUN make # Make sure Cura can find CuraEngine From cee0887d1b146ab88fa22ac61f08bd5cacd66d68 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Tue, 27 Feb 2018 16:24:50 +0100 Subject: [PATCH 065/446] Fix typo in python path --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 3f2a3a239e..1a0cbe0fff 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,7 @@ RUN git clone https://github.com/Ultimaker/Uranium WORKDIR $CURA_APP_DIR/Uranium RUN git fetch origin RUN git checkout $URANIUM_BRANCH -RUN export PYTHOHPATH="${PYTHONPATH}:$CURA_APP_DIR/Uranium" +RUN export PYTHONPATH="${PYTHONPATH}:$CURA_APP_DIR/Uranium" # Setup Cura WORKDIR $CURA_APP_DIR From ac635ba748239d0f91d85879f659eb0229082db9 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 27 Feb 2018 17:10:19 +0100 Subject: [PATCH 066/446] CURA-4870 Add mock-up for the printer type dropdown selector. Add mock-up for the configuration selection. --- resources/qml/Menus/ConfigurationItem.qml | 45 ++++++++ .../qml/Menus/ConfigurationSelection.qml | 109 ++++++++++++++++++ resources/qml/Sidebar.qml | 12 +- resources/qml/SidebarHeader.qml | 56 +++++++++ 4 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 resources/qml/Menus/ConfigurationItem.qml create mode 100644 resources/qml/Menus/ConfigurationSelection.qml diff --git a/resources/qml/Menus/ConfigurationItem.qml b/resources/qml/Menus/ConfigurationItem.qml new file mode 100644 index 0000000000..aed37facf9 --- /dev/null +++ b/resources/qml/Menus/ConfigurationItem.qml @@ -0,0 +1,45 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.0 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +ItemDelegate +{ + contentItem: Label + { + text: model.name + renderType: Text.NativeRendering + color: UM.Theme.getColor("setting_control_text") + font: UM.Theme.getFont("default") + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + rightPadding: swatch.width + UM.Theme.getSize("setting_unit_margin").width + + background: Rectangle + { + id: swatch + height: Math.round(UM.Theme.getSize("setting_control").height / 2) + width: height + + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Math.round(UM.Theme.getSize("default_margin").width / 4) + + border.width: UM.Theme.getSize("default_lining").width + border.color: enabled ? UM.Theme.getColor("setting_control_border") : UM.Theme.getColor("setting_control_disabled_border") + radius: Math.round(width / 2) + + color: control.model.getItem(index).color + } + } + + background: Rectangle + { + color: parent.highlighted ? UM.Theme.getColor("setting_control_highlight") : "transparent" + border.color: parent.highlighted ? UM.Theme.getColor("setting_control_border_highlight") : "transparent" + } +} \ No newline at end of file diff --git a/resources/qml/Menus/ConfigurationSelection.qml b/resources/qml/Menus/ConfigurationSelection.qml new file mode 100644 index 0000000000..d0784f4432 --- /dev/null +++ b/resources/qml/Menus/ConfigurationSelection.qml @@ -0,0 +1,109 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.0 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +ComboBox +{ + id: control + + property var panelWidth: control.width + + model: Cura.ExtrudersModel { } + + textRole: "name" + + indicator: UM.RecolorImage + { + id: downArrow + x: control.width - width - control.rightPadding + y: control.topPadding + Math.round((control.availableHeight - height) / 2) + + source: UM.Theme.getIcon("arrow_bottom") + width: UM.Theme.getSize("standard_arrow").width + height: UM.Theme.getSize("standard_arrow").height + sourceSize.width: width + 5 * screenScaleFactor + sourceSize.height: width + 5 * screenScaleFactor + + color: UM.Theme.getColor("setting_control_text"); + } + + background: Rectangle + { + color: + { + if (!enabled) + { + return UM.Theme.getColor("setting_control_disabled"); + } + if (control.hovered || control.activeFocus) + { + return UM.Theme.getColor("setting_control_highlight"); + } + return UM.Theme.getColor("setting_control"); + } + border.width: UM.Theme.getSize("default_lining").width + border.color: + { + if (!enabled) + { + return UM.Theme.getColor("setting_control_disabled_border") + } + if (control.hovered || control.activeFocus) + { + return UM.Theme.getColor("setting_control_border_highlight") + } + return UM.Theme.getColor("setting_control_border") + } + } + + contentItem: Label + { + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("setting_unit_margin").width + anchors.right: downArrow.left + rightPadding: swatch.width + UM.Theme.getSize("setting_unit_margin").width + + text: "HOLA" + renderType: Text.NativeRendering + font: UM.Theme.getFont("default") + color: enabled ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text") + + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + } + + popup: Popup { + y: control.height - UM.Theme.getSize("default_lining").height + x: control.width - width + width: panelWidth + implicitHeight: contentItem.implicitHeight + padding: UM.Theme.getSize("default_lining").width + + contentItem: GridView { + clip: true + implicitHeight: contentHeight + model: control.popup.visible ? control.delegateModel : null + currentIndex: control.highlightedIndex + + ScrollIndicator.vertical: ScrollIndicator { } + } + + background: Rectangle { + color: UM.Theme.getColor("setting_control") + border.color: UM.Theme.getColor("setting_control_border") + } + } + + delegate: ConfigurationItem + { + width: panelWidth - 2 * UM.Theme.getSize("default_lining").width + height: control.height + highlighted: control.highlightedIndex == index + } +} \ No newline at end of file diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml index 57a8e8beaa..e5e497276b 100644 --- a/resources/qml/Sidebar.qml +++ b/resources/qml/Sidebar.qml @@ -87,10 +87,20 @@ Rectangle MachineSelection { id: machineSelection - width: base.width + width: base.width - configSelection.width + height: UM.Theme.getSize("sidebar_header").height + anchors.top: base.top + anchors.left: parent.left + } + + ConfigurationSelection { + id: configSelection + visible: printerConnected && !sidebar.monitoringPrint && !sidebar.hideSettings + width: visible ? Math.round(base.width * 0.25) : 0 height: UM.Theme.getSize("sidebar_header").height anchors.top: base.top anchors.right: parent.right + panelWidth: base.width } SidebarHeader { diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index d43b8d3752..52a03b46bb 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -16,6 +16,7 @@ Column property int currentExtruderIndex: Cura.ExtruderManager.activeExtruderIndex; property bool currentExtruderVisible: extrudersList.visible; + property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0 spacing: Math.round(UM.Theme.getSize("sidebar_margin").width * 0.9) @@ -34,6 +35,55 @@ Column width: height } + // Printer Type Row + Item + { + id: printerTypeSelectionRow + height: UM.Theme.getSize("sidebar_setup").height + visible: printerConnected && !sidebar.monitoringPrint && !sidebar.hideSettings + + anchors + { + left: parent.left + leftMargin: UM.Theme.getSize("sidebar_margin").width + right: parent.right + rightMargin: UM.Theme.getSize("sidebar_margin").width + } + + Label + { + id: configurationLabel + text: catalog.i18nc("@label", "Printer type"); + width: Math.round(parent.width * 0.4 - UM.Theme.getSize("default_margin").width) + height: parent.height + verticalAlignment: Text.AlignVCenter + font: UM.Theme.getFont("default"); + color: UM.Theme.getColor("text"); + } + + ToolButton + { + id: configurationSelection + + text: catalog.i18nc("@label", "Printer type"); + height: UM.Theme.getSize("setting_control").height + width: Math.round(parent.width * 0.7) + UM.Theme.getSize("sidebar_margin").width + anchors.right: parent.right + style: UM.Theme.styles.sidebar_header_button + activeFocusOnPress: true; + menu: Menu { + MenuItem + { + text: "Printer type 1" + } + MenuItem + { + text: "Printer type 2" + } + } + } + } + // Extruder Row Item { @@ -244,6 +294,8 @@ Column id: materialLabel text: catalog.i18nc("@label", "Material"); width: Math.round(parent.width * 0.45 - UM.Theme.getSize("default_margin").width) + height: parent.height + verticalAlignment: Text.AlignVCenter font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); } @@ -294,6 +346,8 @@ Column id: variantLabel text: Cura.MachineManager.activeDefinitionVariantsName; width: Math.round(parent.width * 0.45 - UM.Theme.getSize("default_margin").width) + height: parent.height + verticalAlignment: Text.AlignVCenter font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); } @@ -347,6 +401,8 @@ Column id: bulidplateLabel text: catalog.i18nc("@label", "Build plate"); width: Math.floor(parent.width * 0.45 - UM.Theme.getSize("default_margin").width) + height: parent.height + verticalAlignment: Text.AlignVCenter font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); } From 1c2999551b036755e66d889c620e3a5a3d2ead86 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Wed, 28 Feb 2018 10:30:51 +0100 Subject: [PATCH 067/446] install materials, install cura engine, run headless --- Dockerfile | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1a0cbe0fff..30aacfdb56 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,14 @@ -FROM ultimaker/cura-build-environment:3.2 +FROM ultimaker/cura-build-environment:1 # Environment vars for easy configuration ENV CURA_BENV_BUILD_TYPE=Release -ENV CURA_BRANCH=master +ENV CURA_BRANCH=3.2 ENV URANIUM_BRANCH=$CURA_BRANCH ENV CURA_ENGINE_BRANCH=$CURA_BRANCH +ENV MATERIALS_BRANCH=$CURA_BRANCH ENV CURA_APP_DIR=/srv/cura +# Ensure our sources dir exists RUN mkdir $CURA_APP_DIR # Setup Uranium @@ -15,7 +17,7 @@ RUN git clone https://github.com/Ultimaker/Uranium WORKDIR $CURA_APP_DIR/Uranium RUN git fetch origin RUN git checkout $URANIUM_BRANCH -RUN export PYTHONPATH="${PYTHONPATH}:$CURA_APP_DIR/Uranium" +RUN export PYTHONPATH=${PYTHONPATH}:$CURA_APP_DIR/Uranium # Setup Cura WORKDIR $CURA_APP_DIR @@ -24,6 +26,13 @@ WORKDIR $CURA_APP_DIR/Cura RUN git fetch origin RUN git checkout origin $CURA_BRANCH +# Setup materials +WORKDIR $CURA_APP_DIR/Cura/resources +RUN git clone https://github.com/Ultimaker/fdm_materials materials +WORKDIR $CURA_APP_DIR/Cura/resources/materials +RUN git fetch origin +RUN git checkout origin $MATERIALS_BRANCH + # Setup CuraEngine WORKDIR $CURA_APP_DIR RUN git clone https://github.com/Ultimaker/CuraEngine @@ -34,10 +43,13 @@ RUN mkdir build WORKDIR $CURA_APP_DIR/CuraEngine/build RUN cmake3 .. RUN make +RUN make install + +# TODO: setup libCharon # Make sure Cura can find CuraEngine RUN ln -s /usr/local/bin/CuraEngine $CURA_APP_DIR/Cura # Run Cura WORKDIR $CURA_APP_DIR/Cura -CMD ["python3", "cura_app.py"] +CMD ["python3", "cura_app.py", "--headless"] From 86c13e86c742610e225724a94251dd142421f8c2 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 28 Feb 2018 11:01:32 +0100 Subject: [PATCH 068/446] CURA-4400 first version that disables extruder and updates available quality profiles --- cura/Machines/Models/QualityProfilesModel.py | 1 + cura/Machines/QualityManager.py | 4 ++-- cura/Settings/ExtruderStack.py | 13 ++++++++++++- cura/Settings/MachineManager.py | 8 ++++++++ resources/qml/Cura.qml | 15 ++++++++++++++- resources/qml/ExtruderButton.qml | 2 +- resources/qml/SidebarHeader.qml | 20 ++++++++++++++------ resources/qml/SidebarSimple.qml | 6 ++---- 8 files changed, 54 insertions(+), 15 deletions(-) diff --git a/cura/Machines/Models/QualityProfilesModel.py b/cura/Machines/Models/QualityProfilesModel.py index 3bfccd409d..519213e8e2 100644 --- a/cura/Machines/Models/QualityProfilesModel.py +++ b/cura/Machines/Models/QualityProfilesModel.py @@ -35,6 +35,7 @@ class QualityProfilesModel(ListModel): # connect signals Application.getInstance().globalContainerStackChanged.connect(self._update) Application.getInstance().getMachineManager().activeQualityGroupChanged.connect(self._update) + Application.getInstance().getMachineManager().extruderChanged.connect(self._update) self._quality_manager = Application.getInstance()._quality_manager self._quality_manager.qualitiesUpdated.connect(self._update) diff --git a/cura/Machines/QualityManager.py b/cura/Machines/QualityManager.py index eb8a3611c1..08f565ac66 100644 --- a/cura/Machines/QualityManager.py +++ b/cura/Machines/QualityManager.py @@ -237,9 +237,9 @@ class QualityManager(QObject): # Updates the given quality groups' availabilities according to which extruders are being used/ enabled. def _updateQualityGroupsAvailability(self, machine: "GlobalStack", quality_group_list): used_extruders = set() - # TODO: This will change after the Machine refactoring for i in range(machine.getProperty("machine_extruder_count", "value")): - used_extruders.add(str(i)) + if machine.extruders[str(i)].isEnabled: + used_extruders.add(str(i)) # Update the "is_available" flag for each quality group. for quality_group in quality_group_list: diff --git a/cura/Settings/ExtruderStack.py b/cura/Settings/ExtruderStack.py index 2995aae795..2a4207c3f3 100644 --- a/cura/Settings/ExtruderStack.py +++ b/cura/Settings/ExtruderStack.py @@ -3,7 +3,7 @@ from typing import Any, TYPE_CHECKING, Optional -from PyQt5.QtCore import pyqtProperty +from PyQt5.QtCore import pyqtProperty, pyqtSignal from UM.Decorators import override from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase @@ -28,9 +28,12 @@ class ExtruderStack(CuraContainerStack): super().__init__(container_id, *args, **kwargs) self.addMetaDataEntry("type", "extruder_train") # For backward compatibility + self._enabled = True self.propertiesChanged.connect(self._onPropertiesChanged) + enabledChanged = pyqtSignal() + ## Overridden from ContainerStack # # This will set the next stack and ensure that we register this stack as an extruder. @@ -47,6 +50,14 @@ class ExtruderStack(CuraContainerStack): def getNextStack(self) -> Optional["GlobalStack"]: return super().getNextStack() + def setEnabled(self, enabled): + self._enabled = enabled + self.enabledChanged.emit() + + @pyqtProperty(bool, notify = enabledChanged) + def isEnabled(self): + return self._enabled + @classmethod def getLoadingPriority(cls) -> int: return 3 diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 5abd5d4649..b3a2a7ed9e 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -135,6 +135,7 @@ class MachineManager(QObject): activeVariantChanged = pyqtSignal() activeQualityChanged = pyqtSignal() activeStackChanged = pyqtSignal() # Emitted whenever the active stack is changed (ie: when changing between extruders, changing a profile, but not when changing a value) + extruderChanged = pyqtSignal() globalValueChanged = pyqtSignal() # Emitted whenever a value inside global container is changed. activeStackValueChanged = pyqtSignal() # Emitted whenever a value inside the active stack is changed. @@ -764,6 +765,13 @@ class MachineManager(QObject): extruder = self._global_container_stack.extruders.get(str(position)) return extruder + @pyqtSlot(int, bool) + def setExtruderEnabled(self, position: int, enabled) -> None: + extruder = self.getExtruder(position) + extruder.setEnabled(enabled) + + self.extruderChanged.emit() + def _onMachineNameChanged(self): self.globalContainerChanged.emit() diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index aeb75a79c5..5764ff0628 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -200,8 +200,21 @@ UM.MainWindow MenuItem { text: catalog.i18nc("@action:inmenu", "Set as Active Extruder") - onTriggered: Cura.ExtruderManager.setActiveExtruderIndex(model.index) + onTriggered: Cura.MachineManager.setExtruderIndex(model.index) } + + MenuItem { + text: catalog.i18nc("@action:inmenu", "Enable Extruder") + onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, true) + visible: !Cura.MachineManager.getExtruder(model.index).isEnabled + } + + MenuItem { + text: catalog.i18nc("@action:inmenu", "Disable Extruder") + onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false) + visible: Cura.MachineManager.getExtruder(model.index).isEnabled + } + } onObjectAdded: settingsMenu.insertItem(index, object) onObjectRemoved: settingsMenu.removeItem(object) diff --git a/resources/qml/ExtruderButton.qml b/resources/qml/ExtruderButton.qml index e4350e0a2c..2c1b80047e 100644 --- a/resources/qml/ExtruderButton.qml +++ b/resources/qml/ExtruderButton.qml @@ -19,7 +19,7 @@ Button iconSource: UM.Theme.getIcon("extruder_button") checked: Cura.ExtruderManager.selectedObjectExtruders.indexOf(extruder.id) != -1 - enabled: UM.Selection.hasSelection + enabled: UM.Selection.hasSelection && extruder.stack.isEnabled property color customColor: base.hovered ? UM.Theme.getColor("button_hover") : UM.Theme.getColor("button"); diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 5d9cbe2ad1..a9aefe4848 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -114,6 +114,18 @@ Column Behavior on color { ColorAnimation { duration: 50; } } } + function buttonColor(index) { + var extruder = Cura.MachineManager.getExtruder(index); + if (extruder.isEnabled) { + return ( + control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_text") : + control.hovered ? UM.Theme.getColor("action_button_hovered_text") : + UM.Theme.getColor("action_button_text"); + } else { + return UM.Theme.getColor("action_button_disabled"); + } + } + Item { id: extruderButtonFace @@ -131,9 +143,7 @@ Column anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left - color: (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_text") : - control.hovered ? UM.Theme.getColor("action_button_hovered_text") : - UM.Theme.getColor("action_button_text") + color: buttonColor(index) font: UM.Theme.getFont("large_nonbold") text: catalog.i18nc("@label", "Extruder") @@ -176,9 +186,7 @@ Column id: extruderNumberText anchors.centerIn: parent text: index + 1; - color: (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_text") : - control.hovered ? UM.Theme.getColor("action_button_hovered_text") : - UM.Theme.getColor("action_button_text") + color: buttonColor(index) font: UM.Theme.getFont("default_bold") } diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index 877e3a1557..4181e9df73 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -67,10 +67,8 @@ Item Connections { - target: Cura.MachineManager - onActiveQualityChanged: qualityModel.update() - onActiveMaterialChanged: qualityModel.update() - onActiveVariantChanged: qualityModel.update() + target: Cura.QualityProfilesModel + onItemsChanged: qualityModel.update() } Connections { From f28bed9b4f79732d9def090e1267aff5193bc333 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 28 Feb 2018 12:56:39 +0100 Subject: [PATCH 069/446] CURA-4400 not sending objects that are printed with a disabled extruder --- cura/Settings/ExtrudersModel.py | 3 +++ plugins/CuraEngineBackend/StartSliceJob.py | 24 +++++++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/cura/Settings/ExtrudersModel.py b/cura/Settings/ExtrudersModel.py index 5139b9885d..c3db797e19 100644 --- a/cura/Settings/ExtrudersModel.py +++ b/cura/Settings/ExtrudersModel.py @@ -43,6 +43,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): # The variant of the extruder. VariantRole = Qt.UserRole + 7 + StackRole = Qt.UserRole + 8 ## List of colours to display if there is no material or the material has no known # colour. @@ -62,6 +63,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): self.addRoleName(self.DefinitionRole, "definition") self.addRoleName(self.MaterialRole, "material") self.addRoleName(self.VariantRole, "variant") + self.addRoleName(self.StackRole, "stack") self._update_extruder_timer = QTimer() self._update_extruder_timer.setInterval(100) @@ -188,6 +190,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): "definition": extruder.getBottom().getId(), "material": extruder.material.getName() if extruder.material else "", "variant": extruder.variant.getName() if extruder.variant else "", # e.g. print core + "stack": extruder, } items.append(item) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 8b7205f8b2..11d98c0e43 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -110,6 +110,7 @@ class StartSliceJob(Job): return stack = Application.getInstance().getGlobalContainerStack() + extruder_stack_id_to_position = {} # a lookup table because we need the position, not the id. if not stack: self.setResult(StartJobResult.Error) return @@ -129,7 +130,8 @@ class StartSliceJob(Job): self.setResult(StartJobResult.MaterialIncompatible) return - for extruder_stack in ExtruderManager.getInstance().getMachineExtruders(stack.getId()): + for position, extruder_stack in stack.extruders.items(): + extruder_stack_id_to_position[extruder_stack.getId()] = position material = extruder_stack.findContainer({"type": "material"}) if material: if material.getMetaDataEntry("compatible") == False: @@ -193,11 +195,19 @@ class StartSliceJob(Job): if per_object_stack: is_non_printing_mesh = any(per_object_stack.getProperty(key, "value") for key in NON_PRINTING_MESH_SETTINGS) - if node.callDecoration("getBuildPlateNumber") == self._build_plate_number: - if not getattr(node, "_outside_buildarea", False) or is_non_printing_mesh: - temp_list.append(node) - if not is_non_printing_mesh: - has_printing_mesh = True + # Find a reason not to add the node + if node.callDecoration("getBuildPlateNumber") != self._build_plate_number: + continue + if getattr(node, "_outside_buildarea", False) and is_non_printing_mesh: + continue + node_extruder_id = node.callDecoration("getActiveExtruder") + node_position = extruder_stack_id_to_position.get(node_extruder_id, "0") + if not stack.extruders[str(node_position)].isEnabled: + continue + + temp_list.append(node) + if not is_non_printing_mesh: + has_printing_mesh = True Job.yieldThread() @@ -382,7 +392,7 @@ class StartSliceJob(Job): def _buildGlobalInheritsStackMessage(self, stack): for key in stack.getAllKeys(): extruder = int(round(float(stack.getProperty(key, "limit_to_extruder")))) - if extruder >= 0: #Set to a specific extruder. + if extruder >= 0 and stack.extruders[str(extruder)].isEnabled: #Set to a specific extruder. setting_extruder = self._slice_message.addRepeatedMessage("limit_to_extruder") setting_extruder.name = key setting_extruder.extruder = extruder From 3aa37296358192ca34f767e1de175dc4d4f2df34 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 28 Feb 2018 13:36:39 +0100 Subject: [PATCH 070/446] CURA-4870 Add printer type selector that show the unique name list of all the types of printers in a group. --- ...erOuputModel.py => ExtruderOutputModel.py} | 0 cura/PrinterOutput/PrinterOutputController.py | 4 +-- cura/PrinterOutput/PrinterOutputModel.py | 2 +- resources/qml/Menus/ConfigurationItem.qml | 2 +- .../qml/Menus/ConfigurationSelection.qml | 24 +++++++++++-- resources/qml/Menus/PrinterTypeMenu.qml | 36 +++++++++++++++++++ resources/qml/SidebarHeader.qml | 11 +----- 7 files changed, 62 insertions(+), 17 deletions(-) rename cura/PrinterOutput/{ExtruderOuputModel.py => ExtruderOutputModel.py} (100%) create mode 100644 resources/qml/Menus/PrinterTypeMenu.qml diff --git a/cura/PrinterOutput/ExtruderOuputModel.py b/cura/PrinterOutput/ExtruderOutputModel.py similarity index 100% rename from cura/PrinterOutput/ExtruderOuputModel.py rename to cura/PrinterOutput/ExtruderOutputModel.py diff --git a/cura/PrinterOutput/PrinterOutputController.py b/cura/PrinterOutput/PrinterOutputController.py index 86ca10e2d3..1d658e79be 100644 --- a/cura/PrinterOutput/PrinterOutputController.py +++ b/cura/PrinterOutput/PrinterOutputController.py @@ -6,7 +6,7 @@ from UM.Logger import Logger MYPY = False if MYPY: from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel - from cura.PrinterOutput.ExtruderOuputModel import ExtruderOuputModel + from cura.PrinterOutput.ExtruderOutputModel import ExtruderOutputModel from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel @@ -18,7 +18,7 @@ class PrinterOutputController: self.can_control_manually = True self._output_device = output_device - def setTargetHotendTemperature(self, printer: "PrinterOutputModel", extruder: "ExtruderOuputModel", temperature: int): + def setTargetHotendTemperature(self, printer: "PrinterOutputModel", extruder: "ExtruderOutputModel", temperature: int): Logger.log("w", "Set target hotend temperature not implemented in controller") def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int): diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index 8234989519..01a8203c32 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -5,7 +5,7 @@ from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, QVariant, pyqtSlot from UM.Logger import Logger from typing import Optional, List from UM.Math.Vector import Vector -from cura.PrinterOutput.ExtruderOuputModel import ExtruderOutputModel +from cura.PrinterOutput.ExtruderOutputModel import ExtruderOutputModel MYPY = False if MYPY: diff --git a/resources/qml/Menus/ConfigurationItem.qml b/resources/qml/Menus/ConfigurationItem.qml index aed37facf9..8ed2ebafc2 100644 --- a/resources/qml/Menus/ConfigurationItem.qml +++ b/resources/qml/Menus/ConfigurationItem.qml @@ -33,7 +33,7 @@ ItemDelegate border.color: enabled ? UM.Theme.getColor("setting_control_border") : UM.Theme.getColor("setting_control_disabled_border") radius: Math.round(width / 2) - color: control.model.getItem(index).color + color: model.color } } diff --git a/resources/qml/Menus/ConfigurationSelection.qml b/resources/qml/Menus/ConfigurationSelection.qml index d0784f4432..e40e8025a4 100644 --- a/resources/qml/Menus/ConfigurationSelection.qml +++ b/resources/qml/Menus/ConfigurationSelection.qml @@ -13,7 +13,25 @@ ComboBox property var panelWidth: control.width - model: Cura.ExtrudersModel { } + model: ListModel { + + ListElement { + name: "Configuration 1" + color: "yellow" + } + ListElement { + name: "Configuration 2" + color: "black" + } + ListElement { + name: "Configuration 3" + color: "green" + } + ListElement { + name: "Configuration 4" + color: "red" + } + } textRole: "name" @@ -85,7 +103,7 @@ ComboBox implicitHeight: contentItem.implicitHeight padding: UM.Theme.getSize("default_lining").width - contentItem: GridView { + contentItem: ListView { clip: true implicitHeight: contentHeight model: control.popup.visible ? control.delegateModel : null @@ -103,7 +121,7 @@ ComboBox delegate: ConfigurationItem { width: panelWidth - 2 * UM.Theme.getSize("default_lining").width - height: control.height + height: control.height - 2 * UM.Theme.getSize("default_lining").height highlighted: control.highlightedIndex == index } } \ No newline at end of file diff --git a/resources/qml/Menus/PrinterTypeMenu.qml b/resources/qml/Menus/PrinterTypeMenu.qml new file mode 100644 index 0000000000..b4fdb0a1d4 --- /dev/null +++ b/resources/qml/Menus/PrinterTypeMenu.qml @@ -0,0 +1,36 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.2 +import QtQuick.Controls 1.1 + +import UM 1.3 as UM +import Cura 1.0 as Cura + +Menu +{ + id: menu + title: "Printer type" + property var outputDevice: Cura.MachineManager.printerOutputDevices[0] + + Instantiator + { + id: printerTypeInstantiator + model: outputDevice != null ? outputDevice.connectedPrintersTypeCount : null + + MenuItem { + text: modelData.machine_type + checkable: true + checked: false + exclusiveGroup: group +// onTriggered: +// { +// TODO +// } + } + onObjectAdded: menu.insertItem(index, object) + onObjectRemoved: menu.removeItem(object) + } + + ExclusiveGroup { id: group } +} diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 52a03b46bb..637db76c4f 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -71,16 +71,7 @@ Column anchors.right: parent.right style: UM.Theme.styles.sidebar_header_button activeFocusOnPress: true; - menu: Menu { - MenuItem - { - text: "Printer type 1" - } - MenuItem - { - text: "Printer type 2" - } - } + menu: PrinterTypeMenu { } } } From 11bad271d3c809b903184798c972041a4563d44e Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 28 Feb 2018 15:50:37 +0100 Subject: [PATCH 071/446] CURA-4400 set extruder numbers of settings to an enabled extruder; added SettingOverrideDecorator by default in CuraSceneNode --- cura/Scene/CuraSceneNode.py | 9 ++- cura/Settings/MachineManager.py | 66 +++++++++++++++---- .../ProcessSlicedLayersJob.py | 3 +- plugins/CuraEngineBackend/StartSliceJob.py | 11 ++-- 4 files changed, 67 insertions(+), 22 deletions(-) diff --git a/cura/Scene/CuraSceneNode.py b/cura/Scene/CuraSceneNode.py index df346baaad..88f89522f6 100644 --- a/cura/Scene/CuraSceneNode.py +++ b/cura/Scene/CuraSceneNode.py @@ -1,9 +1,12 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from copy import deepcopy from typing import List from UM.Application import Application from UM.Scene.SceneNode import SceneNode -from copy import deepcopy -from cura.Settings.ExtrudersModel import ExtrudersModel + +from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator ## Scene nodes that are models are only seen when selecting the corresponding build plate @@ -11,6 +14,8 @@ from cura.Settings.ExtrudersModel import ExtrudersModel class CuraSceneNode(SceneNode): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + if "no_setting_override" not in kwargs: + self.addDecorator(SettingOverrideDecorator()) # now we always have a getActiveExtruderPosition, unless explicitly disabled self._outside_buildarea = False def setOutsideBuildArea(self, new_value): diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index b3a2a7ed9e..817317bf0a 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -52,6 +52,8 @@ class MachineManager(QObject): self._current_quality_group = None self._current_quality_changes_group = None + self._default_extruder_position = "0" # to be updated when extruders are switched on and off + self.machine_extruder_material_update_dict = collections.defaultdict(list) self._error_check_timer = QTimer() @@ -696,6 +698,39 @@ class MachineManager(QObject): if containers: return containers[0].definition.getId() + ## Update extruder number to a valid value when the number of extruders are changed, or when an extruder is changed + def correctExtruderSettings(self): + definition_changes_container = self._global_container_stack.definitionChanges + extruder_count = definition_changes_container.getProperty("machine_extruder_count", "value") + + # reset all extruder number settings whose value is no longer valid + for setting_instance in self._global_container_stack.userChanges.findInstances(): + setting_key = setting_instance.definition.key + if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"): + continue + + old_value = self._global_container_stack.userChanges.getProperty(setting_key, "value") + if int(old_value) >= extruder_count: + self._global_container_stack.userChanges.removeInstance(setting_key) + Logger.log("d", "Reset [%s] because its old value [%s] is no longer valid", setting_key, old_value) + if not self._global_container_stack.extruders[str(old_value)].isEnabled: + self._global_container_stack.userChanges.removeInstance(setting_key) + Logger.log("d", "Reset [%s] because its old value [%s] is no longer valid (2)", setting_key, old_value) + + for setting_key in self._global_container_stack.definition.getAllKeys(): + if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"): + continue + if setting_key == "support_infill_extruder_nr": + print("asdf") + current_value = self._global_container_stack.getProperty(setting_key, "value") + if current_value is None: + continue + if current_value == "-1": + continue + if not self._global_container_stack.extruders[str(current_value)].isEnabled: + self._global_container_stack.userChanges.setProperty(setting_key, "value", str(self._default_extruder_position)) + Logger.log("d", "Change [%s] to [%s] because its value [%s] is not valid", setting_key, self._default_extruder_position, current_value) + ## Set the amount of extruders on the active machine (global stack) # \param extruder_count int the number of extruders to set def setActiveMachineExtruderCount(self, extruder_count): @@ -709,16 +744,10 @@ class MachineManager(QObject): if extruder_count == previous_extruder_count: return - # reset all extruder number settings whose value is no longer valid - for setting_instance in self._global_container_stack.userChanges.findInstances(): - setting_key = setting_instance.definition.key - if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"): - continue + definition_changes_container.setProperty("machine_extruder_count", "value", extruder_count) - old_value = int(self._global_container_stack.userChanges.getProperty(setting_key, "value")) - if old_value >= extruder_count: - self._global_container_stack.userChanges.removeInstance(setting_key) - Logger.log("d", "Reset [%s] because its old value [%s] is no longer valid ", setting_key, old_value) + self.updateDefaultExtruder() + self.correctExtruderSettings() # Check to see if any objects are set to print with an extruder that will no longer exist root_node = Application.getInstance().getController().getScene().getRoot() @@ -729,8 +758,6 @@ class MachineManager(QObject): if extruder_nr is not None and int(extruder_nr) > extruder_count - 1: node.callDecoration("setActiveExtruder", extruder_manager.getExtruderStack(extruder_count - 1).getId()) - definition_changes_container.setProperty("machine_extruder_count", "value", extruder_count) - # Make sure one of the extruder stacks is active extruder_manager.setActiveExtruderIndex(0) @@ -765,11 +792,26 @@ class MachineManager(QObject): extruder = self._global_container_stack.extruders.get(str(position)) return extruder + def updateDefaultExtruder(self): + extruder_items = sorted(self._global_container_stack.extruders.items()) + new_default_position = "0" + for position, extruder in extruder_items: + if extruder.isEnabled: + new_default_position = position + break + self._default_extruder_position = new_default_position + + @pyqtProperty(str, notify = extruderChanged) + def defaultExtruderPosition(self): + return self._default_extruder_position + @pyqtSlot(int, bool) def setExtruderEnabled(self, position: int, enabled) -> None: extruder = self.getExtruder(position) extruder.setEnabled(enabled) - + if enabled == False: + self.updateDefaultExtruder() + self.correctExtruderSettings() self.extruderChanged.emit() def _onMachineNameChanged(self): diff --git a/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py b/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py index c1fc597d80..cbc097bb33 100644 --- a/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py +++ b/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py @@ -81,7 +81,8 @@ class ProcessSlicedLayersJob(Job): Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged) - new_node = CuraSceneNode() + # The no_setting_override is here because adding the SettingOverrideDecorator will trigger a reslice + new_node = CuraSceneNode(no_setting_override = True) new_node.addDecorator(BuildPlateDecorator(self._build_plate_number)) # Force garbage collection. diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 11d98c0e43..cdf33eac26 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -110,7 +110,6 @@ class StartSliceJob(Job): return stack = Application.getInstance().getGlobalContainerStack() - extruder_stack_id_to_position = {} # a lookup table because we need the position, not the id. if not stack: self.setResult(StartJobResult.Error) return @@ -131,7 +130,6 @@ class StartSliceJob(Job): return for position, extruder_stack in stack.extruders.items(): - extruder_stack_id_to_position[extruder_stack.getId()] = position material = extruder_stack.findContainer({"type": "material"}) if material: if material.getMetaDataEntry("compatible") == False: @@ -200,8 +198,7 @@ class StartSliceJob(Job): continue if getattr(node, "_outside_buildarea", False) and is_non_printing_mesh: continue - node_extruder_id = node.callDecoration("getActiveExtruder") - node_position = extruder_stack_id_to_position.get(node_extruder_id, "0") + node_position = node.callDecoration("getActiveExtruderPosition") if not stack.extruders[str(node_position)].isEnabled: continue @@ -391,11 +388,11 @@ class StartSliceJob(Job): # limit_to_extruder property. def _buildGlobalInheritsStackMessage(self, stack): for key in stack.getAllKeys(): - extruder = int(round(float(stack.getProperty(key, "limit_to_extruder")))) - if extruder >= 0 and stack.extruders[str(extruder)].isEnabled: #Set to a specific extruder. + extruder_position = int(round(float(stack.getProperty(key, "limit_to_extruder")))) + if extruder_position >= 0: # Set to a specific extruder. setting_extruder = self._slice_message.addRepeatedMessage("limit_to_extruder") setting_extruder.name = key - setting_extruder.extruder = extruder + setting_extruder.extruder = extruder_position Job.yieldThread() ## Check if a node has per object settings and ensure that they are set correctly in the message From 6952e3f5c16985375d24ede3246fde985ea3ced2 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 28 Feb 2018 19:41:23 +0100 Subject: [PATCH 072/446] CURA-4870 Create a customized popup for the sync dropdown and fill it out with the information about the printers in the group --- resources/qml/Menus/ConfigurationItem.qml | 95 +++++++--- resources/qml/Menus/ConfigurationListView.qml | 57 ++++++ .../qml/Menus/ConfigurationSelection.qml | 163 ++++++++---------- 3 files changed, 194 insertions(+), 121 deletions(-) create mode 100644 resources/qml/Menus/ConfigurationListView.qml diff --git a/resources/qml/Menus/ConfigurationItem.qml b/resources/qml/Menus/ConfigurationItem.qml index 8ed2ebafc2..29e3d1263b 100644 --- a/resources/qml/Menus/ConfigurationItem.qml +++ b/resources/qml/Menus/ConfigurationItem.qml @@ -7,39 +7,82 @@ import QtQuick.Controls 2.0 import UM 1.2 as UM import Cura 1.0 as Cura -ItemDelegate +Rectangle { - contentItem: Label + id: configurationItem + + property var printer: null + signal configurationSelected() + + anchors.leftMargin: 25 + border.width: UM.Theme.getSize("default_lining").width + border.color: "black" + + Rectangle { - text: model.name - renderType: Text.NativeRendering - color: UM.Theme.getColor("setting_control_text") - font: UM.Theme.getFont("default") - elide: Text.ElideRight - verticalAlignment: Text.AlignVCenter - rightPadding: swatch.width + UM.Theme.getSize("setting_unit_margin").width + id: printerInformation - background: Rectangle + Label { - id: swatch - height: Math.round(UM.Theme.getSize("setting_control").height / 2) - width: height - - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Math.round(UM.Theme.getSize("default_margin").width / 4) - - border.width: UM.Theme.getSize("default_lining").width - border.color: enabled ? UM.Theme.getColor("setting_control_border") : UM.Theme.getColor("setting_control_disabled_border") - radius: Math.round(width / 2) - - color: model.color + text: printer.name } } - background: Rectangle + Rectangle { - color: parent.highlighted ? UM.Theme.getColor("setting_control_highlight") : "transparent" - border.color: parent.highlighted ? UM.Theme.getColor("setting_control_border_highlight") : "transparent" + id: extruderInformation + + Row + { + id: extrudersRow + + Repeater + { + model: printer.extruders + delegate: Item + { + id: extruderInfo + + width: Math.round(parent.width / 2) + height: childrenRect.height + Label + { + id: materialLabel + text: modelData.activeMaterial != null ? modelData.activeMaterial.name : "" + elide: Text.ElideRight + width: parent.width + font: UM.Theme.getFont("very_small") + } + Label + { + id: printCoreLabel + text: modelData.hotendID + anchors.top: materialLabel.bottom + elide: Text.ElideRight + width: parent.width + font: UM.Theme.getFont("very_small") + opacity: 0.5 + } + } + } + } + } + +// Rectangle +// { +// id: buildplateInformation +// +// Label +// { +// text: printer.name + "-" + printer.type +// } +// } + + MouseArea + { + id: mouse + anchors.fill: parent + onClicked: configurationSelected() + hoverEnabled: true } } \ No newline at end of file diff --git a/resources/qml/Menus/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationListView.qml new file mode 100644 index 0000000000..979e6b07b2 --- /dev/null +++ b/resources/qml/Menus/ConfigurationListView.qml @@ -0,0 +1,57 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.0 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +Column +{ + id: base + property var outputDevice: Cura.MachineManager.printerOutputDevices[0] + + Rectangle + { + id: header + color: "red" + height: 25 + width: parent.width + } + + Repeater { + height: childrenRect.height + model: outputDevice != null ? outputDevice.connectedPrintersTypeCount : null + delegate: Rectangle + { + height: childrenRect.height + Label + { + id: printerTypeHeader + text: modelData.machine_type + } + + GridView + { + id: grid + anchors.top: printerTypeHeader.bottom + anchors.topMargin: UM.Theme.getSize("sidebar_margin").height + width: base.width + cellWidth: Math.round(base.width / 2) + cellHeight: 100 * screenScaleFactor + model: outputDevice.printers + delegate: ConfigurationItem + { + height: grid.cellHeight + width: grid.cellWidth + printer: modelData + onConfigurationSelected: + { + outputDevice.setActivePrinter(printer) + } + } + } + } + } +} \ No newline at end of file diff --git a/resources/qml/Menus/ConfigurationSelection.qml b/resources/qml/Menus/ConfigurationSelection.qml index e40e8025a4..03f005cebe 100644 --- a/resources/qml/Menus/ConfigurationSelection.qml +++ b/resources/qml/Menus/ConfigurationSelection.qml @@ -2,114 +2,94 @@ // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.7 -import QtQuick.Controls 2.0 +import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 as QQC2 +import QtQuick.Layouts 1.1 +import QtQuick.Controls.Styles 1.4 import UM 1.2 as UM import Cura 1.0 as Cura -ComboBox +Item { - id: control - + id: configurationSelector property var panelWidth: control.width - - model: ListModel { - - ListElement { - name: "Configuration 1" - color: "yellow" - } - ListElement { - name: "Configuration 2" - color: "black" - } - ListElement { - name: "Configuration 3" - color: "green" - } - ListElement { - name: "Configuration 4" - color: "red" - } - } - - textRole: "name" - - indicator: UM.RecolorImage + property var panelVisible: false + Button { - id: downArrow - x: control.width - width - control.rightPadding - y: control.topPadding + Math.round((control.availableHeight - height) / 2) + text: "SYNC" + width: parent.width + height: parent.height - source: UM.Theme.getIcon("arrow_bottom") - width: UM.Theme.getSize("standard_arrow").width - height: UM.Theme.getSize("standard_arrow").height - sourceSize.width: width + 5 * screenScaleFactor - sourceSize.height: width + 5 * screenScaleFactor - - color: UM.Theme.getColor("setting_control_text"); - } - - background: Rectangle - { - color: + style: ButtonStyle { - if (!enabled) + background: Rectangle { - return UM.Theme.getColor("setting_control_disabled"); + color: + { + if(control.pressed) + { + return UM.Theme.getColor("sidebar_header_active"); + } + else if(control.hovered) + { + return UM.Theme.getColor("sidebar_header_hover"); + } + else + { + return UM.Theme.getColor("sidebar_header_bar"); + } + } + Behavior on color { ColorAnimation { duration: 50; } } + + UM.RecolorImage + { + id: downArrow + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: UM.Theme.getSize("default_margin").width + width: UM.Theme.getSize("standard_arrow").width + height: UM.Theme.getSize("standard_arrow").height + sourceSize.width: width + sourceSize.height: width + color: UM.Theme.getColor("text_emphasis") + source: UM.Theme.getIcon("arrow_bottom") + } + Label + { + id: sidebarComboBoxLabel + color: UM.Theme.getColor("sidebar_header_text_active") + text: control.text + elide: Text.ElideRight + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("default_margin").width * 2 + anchors.right: downArrow.left + anchors.rightMargin: control.rightMargin + anchors.verticalCenter: parent.verticalCenter; + font: UM.Theme.getFont("large") + } } - if (control.hovered || control.activeFocus) - { - return UM.Theme.getColor("setting_control_highlight"); - } - return UM.Theme.getColor("setting_control"); + label: Label {} } - border.width: UM.Theme.getSize("default_lining").width - border.color: + + onClicked: { - if (!enabled) - { - return UM.Theme.getColor("setting_control_disabled_border") - } - if (control.hovered || control.activeFocus) - { - return UM.Theme.getColor("setting_control_border_highlight") - } - return UM.Theme.getColor("setting_control_border") + panelVisible = !panelVisible } } - contentItem: Label + QQC2.Popup { - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("setting_unit_margin").width - anchors.right: downArrow.left - rightPadding: swatch.width + UM.Theme.getSize("setting_unit_margin").width - - text: "HOLA" - renderType: Text.NativeRendering - font: UM.Theme.getFont("default") - color: enabled ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text") - - elide: Text.ElideRight - verticalAlignment: Text.AlignVCenter - } - - popup: Popup { - y: control.height - UM.Theme.getSize("default_lining").height - x: control.width - width + id: popup + y: configurationSelector.height - UM.Theme.getSize("default_lining").height + x: configurationSelector.width - width width: panelWidth - implicitHeight: contentItem.implicitHeight + height: 300 //contentItem.height + visible: panelVisible padding: UM.Theme.getSize("default_lining").width - contentItem: ListView { - clip: true - implicitHeight: contentHeight - model: control.popup.visible ? control.delegateModel : null - currentIndex: control.highlightedIndex - - ScrollIndicator.vertical: ScrollIndicator { } + contentItem: ConfigurationListView { + width: panelWidth - 2 * UM.Theme.getSize("default_lining").width } background: Rectangle { @@ -117,11 +97,4 @@ ComboBox border.color: UM.Theme.getColor("setting_control_border") } } - - delegate: ConfigurationItem - { - width: panelWidth - 2 * UM.Theme.getSize("default_lining").width - height: control.height - 2 * UM.Theme.getSize("default_lining").height - highlighted: control.highlightedIndex == index - } } \ No newline at end of file From 8b1bca6743581d9d31300bd36ff6e0b87d586e8a Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Thu, 1 Mar 2018 10:58:18 +0100 Subject: [PATCH 073/446] Add run in docker script --- Dockerfile | 26 ++++++++++++-------------- run_in_docker.sh | 3 +++ 2 files changed, 15 insertions(+), 14 deletions(-) create mode 100644 run_in_docker.sh diff --git a/Dockerfile b/Dockerfile index 30aacfdb56..464aebff53 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,32 +13,23 @@ RUN mkdir $CURA_APP_DIR # Setup Uranium WORKDIR $CURA_APP_DIR -RUN git clone https://github.com/Ultimaker/Uranium +RUN git clone -b $URANIUM_BRANCH --depth 1 https://github.com/Ultimaker/Uranium WORKDIR $CURA_APP_DIR/Uranium -RUN git fetch origin -RUN git checkout $URANIUM_BRANCH -RUN export PYTHONPATH=${PYTHONPATH}:$CURA_APP_DIR/Uranium # Setup Cura WORKDIR $CURA_APP_DIR -RUN git clone https://github.com/Ultimaker/Cura +RUN git clone -b $CURA_BRANCH --depth 1 https://github.com/Ultimaker/Cura WORKDIR $CURA_APP_DIR/Cura -RUN git fetch origin -RUN git checkout origin $CURA_BRANCH # Setup materials WORKDIR $CURA_APP_DIR/Cura/resources -RUN git clone https://github.com/Ultimaker/fdm_materials materials +RUN git clone -b $MATERIALS_BRANCH --depth 1 https://github.com/Ultimaker/fdm_materials materials WORKDIR $CURA_APP_DIR/Cura/resources/materials -RUN git fetch origin -RUN git checkout origin $MATERIALS_BRANCH # Setup CuraEngine WORKDIR $CURA_APP_DIR -RUN git clone https://github.com/Ultimaker/CuraEngine +RUN git clone -b $CURA_ENGINE_BRANCH --depth 1 https://github.com/Ultimaker/CuraEngine WORKDIR $CURA_APP_DIR/CuraEngine -RUN git fetch origin -RUN git checkout $URANIUM_BRANCH RUN mkdir build WORKDIR $CURA_APP_DIR/CuraEngine/build RUN cmake3 .. @@ -50,6 +41,13 @@ RUN make install # Make sure Cura can find CuraEngine RUN ln -s /usr/local/bin/CuraEngine $CURA_APP_DIR/Cura +# Tmp cleanup +RUN rm -Rf /var/cache + # Run Cura WORKDIR $CURA_APP_DIR/Cura -CMD ["python3", "cura_app.py", "--headless"] +ENV PYTHONPATH=${PYTHONPATH}:$CURA_APP_DIR/Uranium +ENV DISPLAY=:1.0 +ADD run_in_docker.sh . +RUN chmod +x ./run_in_docker.sh +CMD "./run_in_docker.sh" diff --git a/run_in_docker.sh b/run_in_docker.sh new file mode 100644 index 0000000000..1e939a2739 --- /dev/null +++ b/run_in_docker.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +Xvfb :1 -screen 0 1280x800x16 & +python3 cura_app.py --headless \ No newline at end of file From e8481f55055d0128d4875c315f2c554299994193 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Thu, 1 Mar 2018 11:00:49 +0100 Subject: [PATCH 074/446] Cleanup --- Dockerfile | 13 ++++--------- run_in_docker.sh | 1 + 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index 464aebff53..d4338c1a4f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,10 +2,10 @@ FROM ultimaker/cura-build-environment:1 # Environment vars for easy configuration ENV CURA_BENV_BUILD_TYPE=Release -ENV CURA_BRANCH=3.2 -ENV URANIUM_BRANCH=$CURA_BRANCH -ENV CURA_ENGINE_BRANCH=$CURA_BRANCH -ENV MATERIALS_BRANCH=$CURA_BRANCH +ENV CURA_BRANCH=docker +ENV URANIUM_BRANCH=3.2 +ENV CURA_ENGINE_BRANCH=3.2 +ENV MATERIALS_BRANCH=3.2 ENV CURA_APP_DIR=/srv/cura # Ensure our sources dir exists @@ -41,13 +41,8 @@ RUN make install # Make sure Cura can find CuraEngine RUN ln -s /usr/local/bin/CuraEngine $CURA_APP_DIR/Cura -# Tmp cleanup -RUN rm -Rf /var/cache - # Run Cura WORKDIR $CURA_APP_DIR/Cura ENV PYTHONPATH=${PYTHONPATH}:$CURA_APP_DIR/Uranium -ENV DISPLAY=:1.0 -ADD run_in_docker.sh . RUN chmod +x ./run_in_docker.sh CMD "./run_in_docker.sh" diff --git a/run_in_docker.sh b/run_in_docker.sh index 1e939a2739..eb364fd887 100644 --- a/run_in_docker.sh +++ b/run_in_docker.sh @@ -1,3 +1,4 @@ #!/usr/bin/env bash Xvfb :1 -screen 0 1280x800x16 & +export DISPLAY=:1.0 python3 cura_app.py --headless \ No newline at end of file From 700254ffc910d1e3c52cba6eec93bc7cbf4bb9cf Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Thu, 1 Mar 2018 11:40:08 +0100 Subject: [PATCH 075/446] use master for testing --- Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index d4338c1a4f..65c6851b31 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,9 +3,9 @@ FROM ultimaker/cura-build-environment:1 # Environment vars for easy configuration ENV CURA_BENV_BUILD_TYPE=Release ENV CURA_BRANCH=docker -ENV URANIUM_BRANCH=3.2 -ENV CURA_ENGINE_BRANCH=3.2 -ENV MATERIALS_BRANCH=3.2 +ENV URANIUM_BRANCH=master +ENV CURA_ENGINE_BRANCH=master +ENV MATERIALS_BRANCH=master ENV CURA_APP_DIR=/srv/cura # Ensure our sources dir exists From 2b0211a45f510c81e8a9b2d47ff8c39f4c313cec Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Thu, 1 Mar 2018 11:45:40 +0100 Subject: [PATCH 076/446] Move build steps for better caching strategy --- Dockerfile | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/Dockerfile b/Dockerfile index 65c6851b31..3e6adc0f4c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,32 +1,13 @@ FROM ultimaker/cura-build-environment:1 # Environment vars for easy configuration -ENV CURA_BENV_BUILD_TYPE=Release -ENV CURA_BRANCH=docker -ENV URANIUM_BRANCH=master -ENV CURA_ENGINE_BRANCH=master -ENV MATERIALS_BRANCH=master ENV CURA_APP_DIR=/srv/cura # Ensure our sources dir exists RUN mkdir $CURA_APP_DIR -# Setup Uranium -WORKDIR $CURA_APP_DIR -RUN git clone -b $URANIUM_BRANCH --depth 1 https://github.com/Ultimaker/Uranium -WORKDIR $CURA_APP_DIR/Uranium - -# Setup Cura -WORKDIR $CURA_APP_DIR -RUN git clone -b $CURA_BRANCH --depth 1 https://github.com/Ultimaker/Cura -WORKDIR $CURA_APP_DIR/Cura - -# Setup materials -WORKDIR $CURA_APP_DIR/Cura/resources -RUN git clone -b $MATERIALS_BRANCH --depth 1 https://github.com/Ultimaker/fdm_materials materials -WORKDIR $CURA_APP_DIR/Cura/resources/materials - # Setup CuraEngine +ENV CURA_ENGINE_BRANCH=master WORKDIR $CURA_APP_DIR RUN git clone -b $CURA_ENGINE_BRANCH --depth 1 https://github.com/Ultimaker/CuraEngine WORKDIR $CURA_APP_DIR/CuraEngine @@ -38,6 +19,24 @@ RUN make install # TODO: setup libCharon +# Setup Uranium +ENV URANIUM_BRANCH=master +WORKDIR $CURA_APP_DIR +RUN git clone -b $URANIUM_BRANCH --depth 1 https://github.com/Ultimaker/Uranium +WORKDIR $CURA_APP_DIR/Uranium + +# Setup materials +ENV MATERIALS_BRANCH=master +WORKDIR $CURA_APP_DIR/Cura/resources +RUN git clone -b $MATERIALS_BRANCH --depth 1 https://github.com/Ultimaker/fdm_materials materials +WORKDIR $CURA_APP_DIR/Cura/resources/materials + +# Setup Cura +ENV CURA_BRANCH=docker +WORKDIR $CURA_APP_DIR +RUN git clone -b $CURA_BRANCH --depth 1 https://github.com/Ultimaker/Cura +WORKDIR $CURA_APP_DIR/Cura + # Make sure Cura can find CuraEngine RUN ln -s /usr/local/bin/CuraEngine $CURA_APP_DIR/Cura From a8bf44003f0fd8d362efd41b44cf873cda40b921 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Thu, 1 Mar 2018 11:52:09 +0100 Subject: [PATCH 077/446] Some fixes in Dockerfile --- Dockerfile | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index 3e6adc0f4c..b2b6243071 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,19 +23,16 @@ RUN make install ENV URANIUM_BRANCH=master WORKDIR $CURA_APP_DIR RUN git clone -b $URANIUM_BRANCH --depth 1 https://github.com/Ultimaker/Uranium -WORKDIR $CURA_APP_DIR/Uranium - -# Setup materials -ENV MATERIALS_BRANCH=master -WORKDIR $CURA_APP_DIR/Cura/resources -RUN git clone -b $MATERIALS_BRANCH --depth 1 https://github.com/Ultimaker/fdm_materials materials -WORKDIR $CURA_APP_DIR/Cura/resources/materials # Setup Cura ENV CURA_BRANCH=docker WORKDIR $CURA_APP_DIR RUN git clone -b $CURA_BRANCH --depth 1 https://github.com/Ultimaker/Cura -WORKDIR $CURA_APP_DIR/Cura + +# Setup materials +ENV MATERIALS_BRANCH=master +WORKDIR $CURA_APP_DIR/Cura/resources +RUN git clone -b $MATERIALS_BRANCH --depth 1 https://github.com/Ultimaker/fdm_materials materials # Make sure Cura can find CuraEngine RUN ln -s /usr/local/bin/CuraEngine $CURA_APP_DIR/Cura From 657a52a5e749dccf2b5c0dc21e8f909cfe495a1e Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 1 Mar 2018 11:54:31 +0100 Subject: [PATCH 078/446] CURA-4400 add checking for enabled extruder in setting _outside_buildarea, cleaned up a bit and factored some functions out BuildVolume --- cura/BuildVolume.py | 61 +++++++++++------------ cura/Scene/CuraSceneNode.py | 24 +++++++++ cura/Settings/MachineManager.py | 2 - cura/Settings/SettingOverrideDecorator.py | 7 ++- plugins/SolidView/SolidView.py | 6 +-- 5 files changed, 58 insertions(+), 42 deletions(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 6401ad77af..5d1e38f5c8 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -111,6 +111,9 @@ class BuildVolume(SceneNode): # but it does not update the disallowed areas after material change Application.getInstance().getMachineManager().activeStackChanged.connect(self._onStackChanged) + # Enable and disable extruder + Application.getInstance().getMachineManager().extruderChanged.connect(self.updateNodeBoundaryCheck) + # list of settings which were updated self._changed_settings_since_last_rebuild = [] @@ -217,30 +220,26 @@ class BuildVolume(SceneNode): group_nodes.append(node) # Keep list of affected group_nodes if node.callDecoration("isSliceable") or node.callDecoration("isGroup"): - node._outside_buildarea = False - bbox = node.getBoundingBox() - - # Mark the node as outside the build volume if the bounding box test fails. - if build_volume_bounding_box.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection: - node._outside_buildarea = True + if node.collidesWithBbox(build_volume_bounding_box): + node.setOutsideBuildArea(True) continue - convex_hull = node.callDecoration("getConvexHull") - if convex_hull: - if not convex_hull.isValid(): - return - # Check for collisions between disallowed areas and the object - for area in self.getDisallowedAreas(): - overlap = convex_hull.intersectsPolygon(area) - if overlap is None: - continue - node._outside_buildarea = True - continue + if node.collidesWithArea(self.getDisallowedAreas()): + node.setOutsideBuildArea(True) + continue + + # Mark the node as outside build volume if the set extruder is disabled + extruder_position = node.callDecoration("getActiveExtruderPosition") + if not self._global_container_stack.extruders[extruder_position].isEnabled: + node.setOutsideBuildArea(True) + continue + + node.setOutsideBuildArea(False) # Group nodes should override the _outside_buildarea property of their children. for group_node in group_nodes: for child_node in group_node.getAllChildren(): - child_node._outside_buildarea = group_node._outside_buildarea + child_node.setOutsideBuildArea(group_node.isOutsideBuildArea) ## Update the outsideBuildArea of a single node, given bounds or current build volume def checkBoundsAndUpdate(self, node: CuraSceneNode, bounds: Optional[AxisAlignedBox] = None): @@ -260,24 +259,20 @@ class BuildVolume(SceneNode): build_volume_bounding_box = bounds if node.callDecoration("isSliceable") or node.callDecoration("isGroup"): - bbox = node.getBoundingBox() - - # Mark the node as outside the build volume if the bounding box test fails. - if build_volume_bounding_box.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection: + if node.collidesWithBbox(build_volume_bounding_box): + node.setOutsideBuildArea(True) + return + + if node.collidesWithArea(self.getDisallowedAreas()): + node.setOutsideBuildArea(True) + return + + # Mark the node as outside build volume if the set extruder is disabled + extruder_position = node.callDecoration("getActiveExtruderPosition") + if not self._global_container_stack.extruders[extruder_position].isEnabled: node.setOutsideBuildArea(True) return - convex_hull = self.callDecoration("getConvexHull") - if convex_hull: - if not convex_hull.isValid(): - return - # Check for collisions between disallowed areas and the object - for area in self.getDisallowedAreas(): - overlap = convex_hull.intersectsPolygon(area) - if overlap is None: - continue - node.setOutsideBuildArea(True) - return node.setOutsideBuildArea(False) ## Recalculates the build volume & disallowed areas. diff --git a/cura/Scene/CuraSceneNode.py b/cura/Scene/CuraSceneNode.py index 88f89522f6..cfc41eb689 100644 --- a/cura/Scene/CuraSceneNode.py +++ b/cura/Scene/CuraSceneNode.py @@ -4,6 +4,7 @@ from copy import deepcopy from typing import List from UM.Application import Application +from UM.Math.AxisAlignedBox import AxisAlignedBox from UM.Scene.SceneNode import SceneNode from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator @@ -77,6 +78,29 @@ class CuraSceneNode(SceneNode): 1.0 ] + def collidesWithBbox(self, check_bbox): + bbox = self.getBoundingBox() + + # Mark the node as outside the build volume if the bounding box test fails. + if check_bbox.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection: + return True + + return False + + def collidesWithArea(self, areas): + convex_hull = self.callDecoration("getConvexHull") + if convex_hull: + if not convex_hull.isValid(): + return False + + # Check for collisions between disallowed areas and the object + for area in areas: + overlap = convex_hull.intersectsPolygon(area) + if overlap is None: + continue + return True + return False + ## Taken from SceneNode, but replaced SceneNode with CuraSceneNode def __deepcopy__(self, memo): copy = CuraSceneNode() diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 817317bf0a..cb0ce4ffc5 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -720,8 +720,6 @@ class MachineManager(QObject): for setting_key in self._global_container_stack.definition.getAllKeys(): if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"): continue - if setting_key == "support_infill_extruder_nr": - print("asdf") current_value = self._global_container_stack.getProperty(setting_key, "value") if current_value is None: continue diff --git a/cura/Settings/SettingOverrideDecorator.py b/cura/Settings/SettingOverrideDecorator.py index b853c06c8e..686c546836 100644 --- a/cura/Settings/SettingOverrideDecorator.py +++ b/cura/Settings/SettingOverrideDecorator.py @@ -61,7 +61,7 @@ class SettingOverrideDecorator(SceneNodeDecorator): # use value from the stack because there can be a delay in signal triggering and "_is_non_printing_mesh" # has not been updated yet. - deep_copy._is_non_printing_mesh = any(bool(self._stack.getProperty(setting, "value")) for setting in self._non_printing_mesh_settings) + deep_copy._is_non_printing_mesh = self.evaluateIsNonPrintingMesh() return deep_copy @@ -89,10 +89,13 @@ class SettingOverrideDecorator(SceneNodeDecorator): def isNonPrintingMesh(self): return self._is_non_printing_mesh + def evaluateIsNonPrintingMesh(self): + return any(bool(self._stack.getProperty(setting, "value")) for setting in self._non_printing_mesh_settings) + def _onSettingChanged(self, instance, property_name): # Reminder: 'property' is a built-in function # Trigger slice/need slicing if the value has changed. if property_name == "value": - self._is_non_printing_mesh = any(bool(self._stack.getProperty(setting, "value")) for setting in self._non_printing_mesh_settings) + self._is_non_printing_mesh = self.evaluateIsNonPrintingMesh() Application.getInstance().getBackend().needsSlicing() Application.getInstance().getBackend().tickle() diff --git a/plugins/SolidView/SolidView.py b/plugins/SolidView/SolidView.py index 50ff2864b7..2abfe80f95 100644 --- a/plugins/SolidView/SolidView.py +++ b/plugins/SolidView/SolidView.py @@ -84,11 +84,7 @@ class SolidView(View): per_mesh_stack = node.callDecoration("getStack") - # Get color to render this mesh in from ExtrudersModel - extruder_index = 0 - extruder_id = node.callDecoration("getActiveExtruder") - if extruder_id: - extruder_index = max(0, self._extruders_model.find("id", extruder_id)) + extruder_index = int(node.callDecoration("getActiveExtruderPosition")) # Use the support extruder instead of the active extruder if this is a support_mesh if per_mesh_stack: From c94d88cd9d26c6d856205412ecca6d5b6be49025 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 1 Mar 2018 12:53:50 +0100 Subject: [PATCH 079/446] CURA-4400 added context menu on right click extruder in SidebarHeader --- resources/qml/SidebarHeader.qml | 35 ++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index a9aefe4848..cf76b5eb53 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -91,10 +91,39 @@ Column exclusiveGroup: extruderMenuGroup checked: base.currentExtruderIndex == index - onClicked: + MouseArea { - forceActiveFocus() // Changing focus applies the currently-being-typed values so it can change the displayed setting values. - Cura.ExtruderManager.setActiveExtruderIndex(index); + anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton + onClicked: { + switch (mouse.button) { + case Qt.LeftButton: + forceActiveFocus(); // Changing focus applies the currently-being-typed values so it can change the displayed setting values. + Cura.ExtruderManager.setActiveExtruderIndex(index); + break; + case Qt.RightButton: + extruderMenu.popup(); + break; + } + + } + } + + Menu + { + id: extruderMenu + + MenuItem { + text: catalog.i18nc("@action:inmenu", "Enable Extruder") + onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, true) + visible: !Cura.MachineManager.getExtruder(model.index).isEnabled + } + + MenuItem { + text: catalog.i18nc("@action:inmenu", "Disable Extruder") + onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false) + visible: Cura.MachineManager.getExtruder(model.index).isEnabled + } } style: ButtonStyle From 71e631150de66fc16efbacae45d52f6a25f0944b Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 1 Mar 2018 13:06:12 +0100 Subject: [PATCH 080/446] CURA-4400 update extruder disabled color --- resources/qml/SidebarHeader.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index cf76b5eb53..473f4c5cc8 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -151,7 +151,7 @@ Column control.hovered ? UM.Theme.getColor("action_button_hovered_text") : UM.Theme.getColor("action_button_text"); } else { - return UM.Theme.getColor("action_button_disabled"); + return UM.Theme.getColor("action_button_disabled_text"); } } From ba7b18a88b326b718ba8c6de395a73a9d22259b5 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 1 Mar 2018 15:02:35 +0100 Subject: [PATCH 081/446] CURA-4400 corrected getProperty in correctExtruderSettings --- cura/Settings/ContainerManager.py | 4 +++- cura/Settings/MachineManager.py | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index 96fff61b0b..20ce9638c1 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -346,10 +346,12 @@ class ContainerManager(QObject): # Go through global and extruder stacks and clear their topmost container (the user settings). for stack in ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks(): - container = stack.getTop() + container = stack.userChanges container.clear() send_emits_containers.append(container) + Application.getInstance().getMachineManager().correctExtruderSettings() + for container in send_emits_containers: container.sendPostponedEmits() diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index a46fedd853..52058789c3 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -699,9 +699,9 @@ class MachineManager(QObject): return containers[0].definition.getId() ## Update extruder number to a valid value when the number of extruders are changed, or when an extruder is changed + # \return if any properties has been added def correctExtruderSettings(self): - definition_changes_container = self._global_container_stack.definitionChanges - extruder_count = definition_changes_container.getProperty("machine_extruder_count", "value") + extruder_count = self._global_container_stack.getProperty("machine_extruder_count", "value") # reset all extruder number settings whose value is no longer valid for setting_instance in self._global_container_stack.userChanges.findInstances(): @@ -717,6 +717,7 @@ class MachineManager(QObject): self._global_container_stack.userChanges.removeInstance(setting_key) Logger.log("d", "Reset [%s] because its old value [%s] is no longer valid (2)", setting_key, old_value) + added_properties = False for setting_key in self._global_container_stack.definition.getAllKeys(): if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"): continue @@ -727,8 +728,11 @@ class MachineManager(QObject): continue if not self._global_container_stack.extruders[str(current_value)].isEnabled: self._global_container_stack.userChanges.setProperty(setting_key, "value", str(self._default_extruder_position)) + added_properties = True Logger.log("d", "Change [%s] to [%s] because its value [%s] is not valid", setting_key, self._default_extruder_position, current_value) + return added_properties + ## Set the amount of extruders on the active machine (global stack) # \param extruder_count int the number of extruders to set def setActiveMachineExtruderCount(self, extruder_count): From 2538c689f191430339500ba532bb81bbff121565 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 1 Mar 2018 16:22:40 +0100 Subject: [PATCH 082/446] CURA-4400 make extruder combobox disabled items grey --- cura/Settings/ExtrudersModel.py | 4 ++++ cura/Settings/MachineManager.py | 4 +++- resources/qml/Settings/SettingExtruder.qml | 22 ++++++++++++++++++---- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/cura/Settings/ExtrudersModel.py b/cura/Settings/ExtrudersModel.py index c3db797e19..ae8cff3c9a 100644 --- a/cura/Settings/ExtrudersModel.py +++ b/cura/Settings/ExtrudersModel.py @@ -24,6 +24,8 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): ## Human-readable name of the extruder. NameRole = Qt.UserRole + 2 + ## Is the extruder enabled? + EnabledRole = Qt.UserRole + 9 ## Colour of the material loaded in the extruder. ColorRole = Qt.UserRole + 3 @@ -58,6 +60,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): self.addRoleName(self.IdRole, "id") self.addRoleName(self.NameRole, "name") + self.addRoleName(self.EnabledRole, "enabled") self.addRoleName(self.ColorRole, "color") self.addRoleName(self.IndexRole, "index") self.addRoleName(self.DefinitionRole, "definition") @@ -185,6 +188,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): item = { "id": extruder.getId(), "name": extruder.getName(), + "enabled": extruder.isEnabled, "color": color, "index": position, "definition": extruder.getBottom().getId(), diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 52058789c3..5faebd4dac 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -811,10 +811,12 @@ class MachineManager(QObject): def setExtruderEnabled(self, position: int, enabled) -> None: extruder = self.getExtruder(position) extruder.setEnabled(enabled) + self.updateDefaultExtruder() if enabled == False: - self.updateDefaultExtruder() self.correctExtruderSettings() self.extruderChanged.emit() + # HACK to update items in SettingExtruder + ExtruderManager.getInstance().extrudersChanged.emit(self._global_container_stack.getId()) def _onMachineNameChanged(self): self.globalContainerChanged.emit() diff --git a/resources/qml/Settings/SettingExtruder.qml b/resources/qml/Settings/SettingExtruder.qml index 17a0dd5eee..3db5d327f4 100644 --- a/resources/qml/Settings/SettingExtruder.qml +++ b/resources/qml/Settings/SettingExtruder.qml @@ -17,14 +17,22 @@ SettingItem id: control anchors.fill: parent - model: Cura.ExtrudersModel { onModelChanged: control.color = getItem(control.currentIndex).color } + model: Cura.ExtrudersModel { + onModelChanged: { + control.color = getItem(control.currentIndex).color; + } + } textRole: "name" onActivated: { - forceActiveFocus(); - propertyProvider.setPropertyValue("value", model.getItem(index).index); + if (model.getItem(index).enabled) { + forceActiveFocus(); + propertyProvider.setPropertyValue("value", model.getItem(index).index); + } else { + currentIndex = propertyProvider.properties.value; // keep the old value + } } onActiveFocusChanged: @@ -173,7 +181,13 @@ SettingItem { text: model.name renderType: Text.NativeRendering - color: UM.Theme.getColor("setting_control_text") + color: { + if (model.enabled) { + UM.Theme.getColor("setting_control_text") + } else { + UM.Theme.getColor("action_button_disabled_text"); + } + } font: UM.Theme.getFont("default") elide: Text.ElideRight verticalAlignment: Text.AlignVCenter From 53ec846436ce2528d3b3e4418b0d4a93ba813bd5 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 1 Mar 2018 17:21:35 +0100 Subject: [PATCH 083/446] CURA-4400 introduced value -1 for extruder number setting (not optional_extruder); this one takes the defaultExtruderPosition in MachineManager --- cura/Settings/ExtruderManager.py | 22 ++++++++++++++----- cura/Settings/MachineManager.py | 17 -------------- .../CuraEngineBackend/CuraEngineBackend.py | 8 +++++++ plugins/CuraEngineBackend/StartSliceJob.py | 8 ++++++- resources/definitions/fdmprinter.def.json | 14 ++++++------ resources/qml/Settings/SettingExtruder.qml | 18 +++++++++++++++ 6 files changed, 56 insertions(+), 31 deletions(-) diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index fe1bb6a990..ee38055a98 100755 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -241,6 +241,13 @@ class ExtruderManager(QObject): result.append(extruder_stack.getProperty(setting_key, prop)) return result + def extruderValueWithDefault(self, value): + machine_manager = self._application.getMachineManager() + if value == "-1": + return machine_manager.defaultExtruderPosition + else: + return value + ## Gets the extruder stacks that are actually being used at the moment. # # An extruder stack is being used if it is the extruder to print any mesh @@ -252,7 +259,7 @@ class ExtruderManager(QObject): # # \return A list of extruder stacks. def getUsedExtruderStacks(self) -> List["ContainerStack"]: - global_stack = Application.getInstance().getGlobalContainerStack() + global_stack = self._application.getGlobalContainerStack() container_registry = ContainerRegistry.getInstance() used_extruder_stack_ids = set() @@ -302,16 +309,19 @@ class ExtruderManager(QObject): # Check support extruders if support_enabled: - used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_infill_extruder_nr", "value"))]) - used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_extruder_nr_layer_0", "value"))]) + used_extruder_stack_ids.add(self.extruderIds[self.extruderValueWithDefault(str(global_stack.getProperty("support_infill_extruder_nr", "value")))]) + used_extruder_stack_ids.add(self.extruderIds[self.extruderValueWithDefault(str(global_stack.getProperty("support_extruder_nr_layer_0", "value")))]) if support_bottom_enabled: - used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_bottom_extruder_nr", "value"))]) + used_extruder_stack_ids.add(self.extruderIds[self.extruderValueWithDefault(str(global_stack.getProperty("support_bottom_extruder_nr", "value")))]) if support_roof_enabled: - used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_roof_extruder_nr", "value"))]) + used_extruder_stack_ids.add(self.extruderIds[self.extruderValueWithDefault(str(global_stack.getProperty("support_roof_extruder_nr", "value")))]) # The platform adhesion extruder. Not used if using none. if global_stack.getProperty("adhesion_type", "value") != "none": - used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("adhesion_extruder_nr", "value"))]) + extruder_nr = str(global_stack.getProperty("adhesion_extruder_nr", "value")) + if extruder_nr == "-1": + extruder_nr = Application.getInstance().getMachineManager().defaultExtruderPosition + used_extruder_stack_ids.add(self.extruderIds[extruder_nr]) try: return [container_registry.findContainerStacks(id = stack_id)[0] for stack_id in used_extruder_stack_ids] diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 5faebd4dac..b46078176f 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -699,7 +699,6 @@ class MachineManager(QObject): return containers[0].definition.getId() ## Update extruder number to a valid value when the number of extruders are changed, or when an extruder is changed - # \return if any properties has been added def correctExtruderSettings(self): extruder_count = self._global_container_stack.getProperty("machine_extruder_count", "value") @@ -717,22 +716,6 @@ class MachineManager(QObject): self._global_container_stack.userChanges.removeInstance(setting_key) Logger.log("d", "Reset [%s] because its old value [%s] is no longer valid (2)", setting_key, old_value) - added_properties = False - for setting_key in self._global_container_stack.definition.getAllKeys(): - if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"): - continue - current_value = self._global_container_stack.getProperty(setting_key, "value") - if current_value is None: - continue - if current_value == "-1": - continue - if not self._global_container_stack.extruders[str(current_value)].isEnabled: - self._global_container_stack.userChanges.setProperty(setting_key, "value", str(self._default_extruder_position)) - added_properties = True - Logger.log("d", "Change [%s] to [%s] because its value [%s] is not valid", setting_key, self._default_extruder_position, current_value) - - return added_properties - ## Set the amount of extruders on the active machine (global stack) # \param extruder_count int the number of extruders to set def setActiveMachineExtruderCount(self, extruder_count): diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index 3982a0ad06..86c181213e 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -91,6 +91,8 @@ class CuraEngineBackend(QObject, Backend): self._onGlobalStackChanged() Application.getInstance().stacksValidationFinished.connect(self._onStackErrorCheckFinished) + # extruder enable / disable. Actually wanted to use machine manager here, but the initialization order causes it to crash + ExtruderManager.getInstance().extrudersChanged.connect(self._extruderChanged) # A flag indicating if an error check was scheduled # If so, we will stop the auto-slice timer and start upon the error check @@ -773,3 +775,9 @@ class CuraEngineBackend(QObject, Backend): def tickle(self): if self._use_timer: self._change_timer.start() + + def _extruderChanged(self): + for build_plate_number in range(Application.getInstance().getMultiBuildPlateModel().maxBuildPlate + 1): + if build_plate_number not in self._build_plates_to_be_sliced: + self._build_plates_to_be_sliced.append(build_plate_number) + self._invokeSlice() diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index cdf33eac26..c426044ae2 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -280,9 +280,15 @@ class StartSliceJob(Job): # \return A dictionary of replacement tokens to the values they should be # replaced with. def _buildReplacementTokens(self, stack) -> dict: + default_extruder_position = Application.getInstance().getMachineManager().defaultExtruderPosition result = {} for key in stack.getAllKeys(): - result[key] = stack.getProperty(key, "value") + setting_type = stack.getProperty(key, "type") + value = stack.getProperty(key, "value") + if setting_type == "extruder" and value == "-1": + # replace with the default value + value = default_extruder_position + result[key] = value Job.yieldThread() result["print_bed_temperature"] = result["material_bed_temperature"] # Renamed settings. diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 8c67462667..b926dc0abc 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -3458,7 +3458,7 @@ "label": "Support Extruder", "description": "The extruder train to use for printing the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": "0", + "default_value": "-1", "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", "settable_per_mesh": false, "settable_per_extruder": false, @@ -3468,7 +3468,7 @@ "label": "Support Infill Extruder", "description": "The extruder train to use for printing the infill of the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": "0", + "default_value": "-1", "value": "support_extruder_nr", "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", "settable_per_mesh": false, @@ -3479,7 +3479,7 @@ "label": "First Layer Support Extruder", "description": "The extruder train to use for printing the first layer of support infill. This is used in multi-extrusion.", "type": "extruder", - "default_value": "0", + "default_value": "-1", "value": "support_extruder_nr", "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", "settable_per_mesh": false, @@ -3490,7 +3490,7 @@ "label": "Support Interface Extruder", "description": "The extruder train to use for printing the roofs and floors of the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": "0", + "default_value": "-1", "value": "support_extruder_nr", "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", "settable_per_mesh": false, @@ -3502,7 +3502,7 @@ "label": "Support Roof Extruder", "description": "The extruder train to use for printing the roofs of the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": "0", + "default_value": "-1", "value": "support_interface_extruder_nr", "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", "settable_per_mesh": false, @@ -3513,7 +3513,7 @@ "label": "Support Floor Extruder", "description": "The extruder train to use for printing the floors of the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": "0", + "default_value": "-1", "value": "support_interface_extruder_nr", "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", "settable_per_mesh": false, @@ -4184,7 +4184,7 @@ "label": "Build Plate Adhesion Extruder", "description": "The extruder train to use for printing the skirt/brim/raft. This is used in multi-extrusion.", "type": "extruder", - "default_value": "0", + "default_value": "-1", "enabled": "machine_extruder_count > 1 and resolveOrValue('adhesion_type') != 'none'", "settable_per_mesh": false, "settable_per_extruder": false diff --git a/resources/qml/Settings/SettingExtruder.qml b/resources/qml/Settings/SettingExtruder.qml index 3db5d327f4..2a2e213142 100644 --- a/resources/qml/Settings/SettingExtruder.qml +++ b/resources/qml/Settings/SettingExtruder.qml @@ -72,6 +72,24 @@ SettingItem value: control.currentText != "" ? control.model.getItem(control.currentIndex).color : "" } + Binding + { + target: control + property: "currentIndex" + value: + { + if(propertyProvider.properties.value == -1) + { + // TODO: accidently the extruder position is also the index. fix it + return Cura.MachineManager.defaultExtruderPosition; + } + return propertyProvider.properties.value + } + // Sometimes when the value is already changed, the model is still being built. + // The when clause ensures that the current index is not updated when this happens. + when: control.model.items.length > 0 + } + indicator: UM.RecolorImage { id: downArrow From 135208bfeef1de9834e0c00f52c5c168fece6930 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Fri, 2 Mar 2018 13:26:04 +0100 Subject: [PATCH 084/446] CURA-4870 Modify the dropdown look and feel --- resources/qml/Menus/ConfigurationItem.qml | 88 ------------------- resources/qml/Menus/ConfigurationListView.qml | 57 ------------ .../ConfigurationMenu/ConfigurationItem.qml | 72 +++++++++++++++ .../ConfigurationListView.qml | 66 ++++++++++++++ .../ConfigurationSelection.qml | 5 +- .../PrintCoreConfiguration.qml | 35 ++++++++ resources/qml/Sidebar.qml | 1 + 7 files changed, 176 insertions(+), 148 deletions(-) delete mode 100644 resources/qml/Menus/ConfigurationItem.qml delete mode 100644 resources/qml/Menus/ConfigurationListView.qml create mode 100644 resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml create mode 100644 resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml rename resources/qml/Menus/{ => ConfigurationMenu}/ConfigurationSelection.qml (95%) create mode 100644 resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml diff --git a/resources/qml/Menus/ConfigurationItem.qml b/resources/qml/Menus/ConfigurationItem.qml deleted file mode 100644 index 29e3d1263b..0000000000 --- a/resources/qml/Menus/ConfigurationItem.qml +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2018 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.7 -import QtQuick.Controls 2.0 - -import UM 1.2 as UM -import Cura 1.0 as Cura - -Rectangle -{ - id: configurationItem - - property var printer: null - signal configurationSelected() - - anchors.leftMargin: 25 - border.width: UM.Theme.getSize("default_lining").width - border.color: "black" - - Rectangle - { - id: printerInformation - - Label - { - text: printer.name - } - } - - Rectangle - { - id: extruderInformation - - Row - { - id: extrudersRow - - Repeater - { - model: printer.extruders - delegate: Item - { - id: extruderInfo - - width: Math.round(parent.width / 2) - height: childrenRect.height - Label - { - id: materialLabel - text: modelData.activeMaterial != null ? modelData.activeMaterial.name : "" - elide: Text.ElideRight - width: parent.width - font: UM.Theme.getFont("very_small") - } - Label - { - id: printCoreLabel - text: modelData.hotendID - anchors.top: materialLabel.bottom - elide: Text.ElideRight - width: parent.width - font: UM.Theme.getFont("very_small") - opacity: 0.5 - } - } - } - } - } - -// Rectangle -// { -// id: buildplateInformation -// -// Label -// { -// text: printer.name + "-" + printer.type -// } -// } - - MouseArea - { - id: mouse - anchors.fill: parent - onClicked: configurationSelected() - hoverEnabled: true - } -} \ No newline at end of file diff --git a/resources/qml/Menus/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationListView.qml deleted file mode 100644 index 979e6b07b2..0000000000 --- a/resources/qml/Menus/ConfigurationListView.qml +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2018 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.7 -import QtQuick.Controls 2.0 - -import UM 1.2 as UM -import Cura 1.0 as Cura - -Column -{ - id: base - property var outputDevice: Cura.MachineManager.printerOutputDevices[0] - - Rectangle - { - id: header - color: "red" - height: 25 - width: parent.width - } - - Repeater { - height: childrenRect.height - model: outputDevice != null ? outputDevice.connectedPrintersTypeCount : null - delegate: Rectangle - { - height: childrenRect.height - Label - { - id: printerTypeHeader - text: modelData.machine_type - } - - GridView - { - id: grid - anchors.top: printerTypeHeader.bottom - anchors.topMargin: UM.Theme.getSize("sidebar_margin").height - width: base.width - cellWidth: Math.round(base.width / 2) - cellHeight: 100 * screenScaleFactor - model: outputDevice.printers - delegate: ConfigurationItem - { - height: grid.cellHeight - width: grid.cellWidth - printer: modelData - onConfigurationSelected: - { - outputDevice.setActivePrinter(printer) - } - } - } - } - } -} \ No newline at end of file diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml new file mode 100644 index 0000000000..45adfb88f2 --- /dev/null +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml @@ -0,0 +1,72 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.0 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +Rectangle +{ + id: configurationItem + + property var printer: null + signal configurationSelected() + + height: childrenRect.height + border.width: UM.Theme.getSize("default_lining").width + border.color: "black" + + Column + { + id: contentColumn + padding: UM.Theme.getSize("default_margin").width + spacing: UM.Theme.getSize("default_margin").height + + Label + { + text: printer.name + } + + Row + { + id: extruderRow + + width: parent.width + height: childrenRect.height + + spacing: UM.Theme.getSize("default_margin").width + + Repeater + { + height: childrenRect.height + model: printer.extruders + delegate: PrintCoreConfiguration + { + printCoreConfiguration: modelData + } + } + } + +// Rectangle +// { +// id: buildplateInformation +// +// Label +// { +// text: printer.name + "-" + printer.type +// } +// } + } + + MouseArea + { + id: mouse + anchors.fill: parent + onClicked: configurationSelected() + hoverEnabled: true + onEntered: parent.border.color = UM.Theme.getColor("primary_hover") + onExited: parent.border.color = "black" + } +} \ No newline at end of file diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml new file mode 100644 index 0000000000..1575f47ecc --- /dev/null +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -0,0 +1,66 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.0 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +Column +{ + id: base + property var outputDevice: Cura.MachineManager.printerOutputDevices[0] + height: childrenRect.height + 2 * padding + padding: UM.Theme.getSize("default_margin").width + spacing: UM.Theme.getSize("default_margin").height + + Label { + text: catalog.i18nc("@label:header configurations", "Available configurations") + font: UM.Theme.getFont("large") + width: parent.width - 2 * parent.padding + } + + Item + { + id: container + width: parent.width - 2 * parent.padding + height: childrenRect.height + + Repeater { + height: childrenRect.height + model: outputDevice != null ? outputDevice.connectedPrintersTypeCount : null + delegate: Rectangle + { + height: childrenRect.height + Label + { + id: printerTypeHeader + text: modelData.machine_type + font: UM.Theme.getFont("default_bold") + } + + ListView + { + id: grid + anchors.top: printerTypeHeader.bottom + anchors.topMargin: UM.Theme.getSize("default_margin").height + width: container.width + height: childrenRect.height + model: outputDevice.printers + delegate: ConfigurationItem + { + height: parent.height + width: parent.width + printer: modelData + onConfigurationSelected: + { + print("SELECCIONANDO IMPRESORA", printer.name) + outputDevice.setActivePrinter(printer) + } + } + } + } + } + } +} \ No newline at end of file diff --git a/resources/qml/Menus/ConfigurationSelection.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml similarity index 95% rename from resources/qml/Menus/ConfigurationSelection.qml rename to resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml index 03f005cebe..4b2c3800f0 100644 --- a/resources/qml/Menus/ConfigurationSelection.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml @@ -17,7 +17,7 @@ Item property var panelVisible: false Button { - text: "SYNC" + text: "Matched" width: parent.width height: parent.height @@ -84,12 +84,11 @@ Item y: configurationSelector.height - UM.Theme.getSize("default_lining").height x: configurationSelector.width - width width: panelWidth - height: 300 //contentItem.height visible: panelVisible padding: UM.Theme.getSize("default_lining").width contentItem: ConfigurationListView { - width: panelWidth - 2 * UM.Theme.getSize("default_lining").width + width: panelWidth - 2 * popup.padding } background: Rectangle { diff --git a/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml b/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml new file mode 100644 index 0000000000..c9875ae668 --- /dev/null +++ b/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml @@ -0,0 +1,35 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.0 + +import UM 1.2 as UM + + +Item +{ + id: extruderInfo + property var printCoreConfiguration + + height: childrenRect.height + + Label + { + id: materialLabel + text: printCoreConfiguration.activeMaterial != null ? printCoreConfiguration.activeMaterial.name : "" + elide: Text.ElideRight + width: parent.width + font: UM.Theme.getFont("very_small") + } + Label + { + id: printCoreLabel + text: printCoreConfiguration.hotendID + anchors.top: materialLabel.bottom + elide: Text.ElideRight + width: parent.width + font: UM.Theme.getFont("very_small") + opacity: 0.5 + } +} diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml index e5e497276b..ef7b49098a 100644 --- a/resources/qml/Sidebar.qml +++ b/resources/qml/Sidebar.qml @@ -8,6 +8,7 @@ import QtQuick.Layouts 1.3 import UM 1.2 as UM import Cura 1.0 as Cura import "Menus" +import "Menus/ConfigurationMenu" Rectangle { From 62169bed2a1781e8c0b187687d87521b2e7aa06b Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Fri, 2 Mar 2018 16:35:21 +0000 Subject: [PATCH 085/446] Rename bridge_wall_max_air_gap to bridge_wall_max_overhang. --- resources/definitions/fdmprinter.def.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 57770df26c..c803f9c084 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6213,9 +6213,9 @@ "enabled": "bridge_settings_enabled", "settable_per_mesh": true }, - "bridge_wall_max_air_gap": + "bridge_wall_max_overhang": { - "label": "Bridge Wall Max Air Gap", + "label": "Bridge Wall Max Overhang", "description": "The maximum allowed width of the region of air below a wall line before the wall is printed using bridge settings. Expressed as a percentage of the wall line width. When the air gap is wider than this, the wall line is printed using the bridge settings. Otherwise, the wall line is printed using the normal settings. The lower the value, the more likely it is that overhung wall lines will be printed using bridge settings.", "unit": "%", "default_value": 100, From 5db636bf9beadaf499a1ae9c953fbb54ffc70ace Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Fri, 2 Mar 2018 16:36:26 +0000 Subject: [PATCH 086/446] Add bridge_wall_min_length setting. It's currently per extruder to make it easy to access within the engine but this should be changed when the settings are refactored. --- resources/definitions/fdmprinter.def.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index c803f9c084..151cb3f45b 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6201,6 +6201,18 @@ "settable_per_extruder": false, "settable_per_meshgroup": false }, + "bridge_wall_min_length": + { + "label": "Minimum Bridge Wall Length", + "description": "Unsupported walls shorter than this will be printed using the normal wall settings. Longer unsupported walls will be printed using the bridge wall settings.", + "unit": "mm", + "type": "float", + "minimum_value": "0", + "default_value": 5, + "enabled": "bridge_settings_enabled", + "settable_per_mesh": false, + "settable_per_extruder": true + }, "bridge_skin_support_threshold": { "label": "Bridge Skin Support Threshold", From 323eac345a086540b2e1faea744abc60b4fa79c2 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Sat, 3 Mar 2018 12:04:58 +0000 Subject: [PATCH 087/446] Added bridge_modify_skins_above. --- resources/definitions/fdmprinter.def.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 151cb3f45b..b7ffcdf240 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6303,6 +6303,15 @@ "enabled": "bridge_settings_enabled", "settable_per_mesh": true }, + "bridge_modify_skins_above": + { + "label": "Modify Skins Above Bridge", + "description": "If enabled, the skin regions present on the 2nd and 3rd layers above the air gap are printed using Bridge Skin Speed. Otherwise, those skins are printed using the normal skin speed.", + "type": "bool", + "default_value": true, + "enabled": "bridge_settings_enabled", + "settable_per_mesh": true + }, "bridge_fan_speed": { "label": "Bridge Fan Speed", From dead2122dd0db7c34dfb507462f3839c2bcb9a08 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Sat, 3 Mar 2018 20:29:06 +0100 Subject: [PATCH 088/446] CURA-4870 Add list of unique configurations to the output device. The printer output model calculates the configuration every time a change is received from the output device --- cura/PrinterOutput/ConfigurationModel.py | 42 +++++++++++++++++++++++ cura/PrinterOutput/ExtruderOutputModel.py | 21 +++++++++++- cura/PrinterOutput/PrinterOutputModel.py | 20 ++++++++++- cura/PrinterOutputDevice.py | 21 ++++++++++++ 4 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 cura/PrinterOutput/ConfigurationModel.py diff --git a/cura/PrinterOutput/ConfigurationModel.py b/cura/PrinterOutput/ConfigurationModel.py new file mode 100644 index 0000000000..bb219a0e2f --- /dev/null +++ b/cura/PrinterOutput/ConfigurationModel.py @@ -0,0 +1,42 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from PyQt5.QtCore import pyqtProperty, QObject + + +class ConfigurationModel(QObject): + + def __init__(self): + self._printer_type = None + self._extruder_configurations = [] + self._buildplate_configuration = None + + def setPrinterType(self, printer_type): + self._printer_type = printer_type + + @pyqtProperty(str, fset = setPrinterType, constant = True) + def printerType(self): + return self._printer_type + + def setExtruderConfigurations(self, extruder_configurations): + self._extruder_configurations = extruder_configurations + + @pyqtProperty("QVariantList", fset = setExtruderConfigurations, constant = True) + def extruderConfigurations(self): + return self._extruder_configurations + + def setBuildplateConfiguration(self, buildplate_configuration): + self._buildplate_configuration = buildplate_configuration + + @pyqtProperty(str, fset = setBuildplateConfiguration, constant = True) + def buildplateConfiguration(self): + return self._buildplate_configuration + + def __eq__(self, other): + return hash(self) == hash(other) + + def __hash__(self): + extruder_hash = hash(0) + for configuration in self.extruderConfigurations: + extruder_hash ^= hash(frozenset(configuration.items())) + return hash(self.printerType) ^ extruder_hash ^ hash(self.buildplateConfiguration) \ No newline at end of file diff --git a/cura/PrinterOutput/ExtruderOutputModel.py b/cura/PrinterOutput/ExtruderOutputModel.py index b0be6cbbe4..33f3bf71f5 100644 --- a/cura/PrinterOutput/ExtruderOutputModel.py +++ b/cura/PrinterOutput/ExtruderOutputModel.py @@ -17,14 +17,20 @@ class ExtruderOutputModel(QObject): targetHotendTemperatureChanged = pyqtSignal() hotendTemperatureChanged = pyqtSignal() activeMaterialChanged = pyqtSignal() + extruderConfigurationChanged = pyqtSignal() - def __init__(self, printer: "PrinterOutputModel", parent=None): + def __init__(self, printer: "PrinterOutputModel", position, parent=None): super().__init__(parent) self._printer = printer + self._position = position self._target_hotend_temperature = 0 self._hotend_temperature = 0 self._hotend_id = "" self._active_material = None # type: Optional[MaterialOutputModel] + self._extruder_configuration = {} + # Update the configuration every time the hotend or the active material change + self.hotendIDChanged.connect(self._updateExtruderConfiguration) + self.activeMaterialChanged.connect(self._updateExtruderConfiguration) @pyqtProperty(QObject, notify = activeMaterialChanged) def activeMaterial(self) -> "MaterialOutputModel": @@ -68,3 +74,16 @@ class ExtruderOutputModel(QObject): if self._hotend_id != id: self._hotend_id = id self.hotendIDChanged.emit() + + @pyqtProperty("QVariantMap", notify = extruderConfigurationChanged) + def extruderConfiguration(self): + return self._extruder_configuration + + def _updateExtruderConfiguration(self): + self._extruder_configuration = { + "position": self._position, + "material": self._active_material.type if self.activeMaterial is not None else None, + "hotend_id": self._hotend_id + } + print("Recalculating extruder configuration:", self._extruder_configuration) + self.extruderConfigurationChanged.emit() diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index 01a8203c32..0cdec88194 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -5,6 +5,7 @@ from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, QVariant, pyqtSlot from UM.Logger import Logger from typing import Optional, List from UM.Math.Vector import Vector +from cura.PrinterOutput.ConfigurationModel import ConfigurationModel from cura.PrinterOutput.ExtruderOutputModel import ExtruderOutputModel MYPY = False @@ -24,6 +25,7 @@ class PrinterOutputModel(QObject): keyChanged = pyqtSignal() typeChanged = pyqtSignal() cameraChanged = pyqtSignal() + configurationChanged = pyqtSignal() def __init__(self, output_controller: "PrinterOutputController", number_of_extruders: int = 1, parent=None, firmware_version = ""): super().__init__(parent) @@ -32,13 +34,17 @@ class PrinterOutputModel(QObject): self._name = "" self._key = "" # Unique identifier self._controller = output_controller - self._extruders = [ExtruderOutputModel(printer=self) for i in range(number_of_extruders)] + self._extruders = [ExtruderOutputModel(printer = self, position = i) for i in range(number_of_extruders)] + self._printer_configuration = ConfigurationModel() # Indicates the current configuration setup in this printer self._head_position = Vector(0, 0, 0) self._active_print_job = None # type: Optional[PrintJobOutputModel] self._firmware_version = firmware_version self._printer_state = "unknown" self._is_preheating = False self._type = "" + # Update the configuration every time the one of the extruders changes its configuration + for extruder in self._extruders: + extruder.extruderConfigurationChanged.connect(self._updatePrinterConfiguration) self._camera = None @@ -238,3 +244,15 @@ class PrinterOutputModel(QObject): if self._controller: return self._controller.can_control_manually return False + + # Returns the configuration (material, variant and buildplate) of the current printer + @pyqtProperty(QObject, notify = configurationChanged) + def printerConfiguration(self): + return self._printer_configuration + + def _updatePrinterConfiguration(self): + self._printer_configuration.printerType = self._type + self._printer_configuration.extruderConfigurations = [extruder.extruderConfiguration for extruder in self._extruders] + self._printer_configuration.buildplateConfiguration = None # TODO Add the buildplate information + print("Recalculating printer configuration", self.name, ":", self._printer_configuration) + self.configurationChanged.emit() diff --git a/cura/PrinterOutputDevice.py b/cura/PrinterOutputDevice.py index 9e603b83ae..ac8f317689 100644 --- a/cura/PrinterOutputDevice.py +++ b/cura/PrinterOutputDevice.py @@ -17,6 +17,7 @@ from typing import List, Optional MYPY = False if MYPY: from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel + from cura.PrinterOutput.ConfigurationModel import ConfigurationModel i18n_catalog = i18nCatalog("cura") @@ -44,10 +45,14 @@ class PrinterOutputDevice(QObject, OutputDevice): # Signal to indicate that the info text about the connection has changed. connectionTextChanged = pyqtSignal() + # Signal to indicate that the configuration of one of the printers has changed. + configurationChanged = pyqtSignal() + def __init__(self, device_id, parent = None): super().__init__(device_id = device_id, parent = parent) self._printers = [] # type: List[PrinterOutputModel] + self._unique_configurations = [] # type: List[ConfigurationModel] self._monitor_view_qml_path = "" self._monitor_component = None @@ -69,6 +74,7 @@ class PrinterOutputDevice(QObject, OutputDevice): self._address = "" self._connection_text = "" + self.printersChanged.connect(self._onPrintersChanged) @pyqtProperty(str, notify = connectionTextChanged) def address(self): @@ -175,6 +181,21 @@ class PrinterOutputDevice(QObject, OutputDevice): self.acceptsCommandsChanged.emit() + # Returns the unique configurations of the current printers + @pyqtProperty("QVariantList", notify = configurationChanged) + def uniqueConfiguration(self): + return self._unique_configurations + + def _updateUniqueConfigurations(self): + print("Calculating the unique configurations") + self._unique_configurations = list(set([printer.printerConfiguration for printer in self._printers])) + print(self._unique_configurations) + self.configurationChanged.emit() + + def _onPrintersChanged(self): + for printer in self._printers: + printer.configurationChanged.connect(self._updateUniqueConfigurations) + ## The current processing state of the backend. class ConnectionState(IntEnum): From 754e85815a0b881077f2e37cde83568c19d4f099 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Sun, 4 Mar 2018 09:00:41 +0000 Subject: [PATCH 089/446] Additional second bridge skin settings. --- resources/definitions/fdmprinter.def.json | 60 ++++++++++++++++++----- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index b7ffcdf240..5550924c4f 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6303,15 +6303,6 @@ "enabled": "bridge_settings_enabled", "settable_per_mesh": true }, - "bridge_modify_skins_above": - { - "label": "Modify Skins Above Bridge", - "description": "If enabled, the skin regions present on the 2nd and 3rd layers above the air gap are printed using Bridge Skin Speed. Otherwise, those skins are printed using the normal skin speed.", - "type": "bool", - "default_value": true, - "enabled": "bridge_settings_enabled", - "settable_per_mesh": true - }, "bridge_fan_speed": { "label": "Bridge Fan Speed", @@ -6322,8 +6313,55 @@ "default_value": 100, "type": "float", "enabled": "bridge_settings_enabled", - "settable_per_mesh": false, - "settable_per_extruder": true + "settable_per_mesh": true + }, + "bridge_process_second_skin": + { + "label": "Bridges Have Second Skin", + "description": "If enabled, the skin regions on the second layer above the air gap are printed using bridge second skin settings. Otherwise, those skin regions are printed using the normal skin settings.", + "type": "bool", + "default_value": true, + "enabled": "bridge_settings_enabled", + "settable_per_mesh": true + }, + "bridge_skin_speed_2": + { + "label": "Bridge Second Skin Speed", + "description": "Print speed to use when printing the second bridge skin layer.", + "unit": "mm/s", + "type": "float", + "minimum_value": "0.1", + "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)", + "maximum_value_warning": "300", + "default_value": 20, + "value": "bridge_skin_speed", + "enabled": "bridge_settings_enabled and bridge_process_second_skin", + "settable_per_mesh": true + }, + "bridge_skin_material_flow_2": + { + "label": "Bridge Second Skin Flow", + "description": "Flow compensation: the amount of material extruded when printing the second bridge skin layer is multiplied by this value.", + "unit": "%", + "default_value": 100, + "type": "float", + "minimum_value": "5", + "minimum_value_warning": "50", + "maximum_value_warning": "150", + "enabled": "bridge_settings_enabled and bridge_process_second_skin", + "settable_per_mesh": true + }, + "bridge_fan_speed_2": + { + "label": "Bridge Second Skin Fan Speed", + "description": "Fan speed to use when printing the second bridge skin layer.", + "unit": "%", + "minimum_value": "0", + "maximum_value": "100", + "default_value": 0, + "type": "float", + "enabled": "bridge_settings_enabled and bridge_process_second_skin", + "settable_per_mesh": true } } }, From 6e35fc5035b5333157adcd78797de3e0578c8b67 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Sun, 4 Mar 2018 12:53:16 +0100 Subject: [PATCH 090/446] CURA-4870 Modify printer menu visibility of the items. Show local or network submenu only when there is local or network printers respectively --- resources/qml/Menus/PrinterMenu.qml | 35 ++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/resources/qml/Menus/PrinterMenu.qml b/resources/qml/Menus/PrinterMenu.qml index 283063b522..741d927c13 100644 --- a/resources/qml/Menus/PrinterMenu.qml +++ b/resources/qml/Menus/PrinterMenu.qml @@ -3,35 +3,58 @@ import QtQuick 2.2 import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 import UM 1.2 as UM import Cura 1.0 as Cura Menu { - id: menu; + id: menu +// TODO Enable custom style to the menu +// style: MenuStyle +// { +// frame: Rectangle +// { +// color: "white" +// } +// } MenuItem { - text: catalog.i18nc("@label:category menu label", "Network printers") + text: catalog.i18nc("@label:category menu label", "Network enabled printers") enabled: false + visible: networkPrinterMenu.count > 0 } - NetworkPrinterMenu { } + NetworkPrinterMenu + { + id: networkPrinterMenu + } - MenuSeparator { } + MenuSeparator + { + visible: networkPrinterMenu.count > 0 + } MenuItem { text: catalog.i18nc("@label:category menu label", "Local printers") enabled: false + visible: localPrinterMenu.count > 0 } - LocalPrinterMenu { } + LocalPrinterMenu + { + id: localPrinterMenu + } ExclusiveGroup { id: group; } - MenuSeparator { } + MenuSeparator + { + visible: localPrinterMenu.count > 0 + } MenuItem { action: Cura.Actions.addMachine; } MenuItem { action: Cura.Actions.configureMachines; } From 49fcf35d9b6e64cb45145c810a14edc47214a422 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Sun, 4 Mar 2018 17:26:37 +0100 Subject: [PATCH 091/446] CURA-4870 Prepare the UI to show the list of configurations --- cura/PrinterOutput/ConfigurationModel.py | 8 ++- cura/PrinterOutput/ExtruderOutputModel.py | 7 +- cura/PrinterOutput/PrinterOutputModel.py | 7 +- cura/PrinterOutputDevice.py | 23 +++--- .../ConfigurationMenu/ConfigurationItem.qml | 8 +-- .../ConfigurationListView.qml | 19 ++--- .../ConfigurationSelection.qml | 68 +----------------- .../PrintCoreConfiguration.qml | 2 +- .../Menus/ConfigurationMenu/SyncButton.qml | 71 +++++++++++++++++++ 9 files changed, 113 insertions(+), 100 deletions(-) create mode 100644 resources/qml/Menus/ConfigurationMenu/SyncButton.qml diff --git a/cura/PrinterOutput/ConfigurationModel.py b/cura/PrinterOutput/ConfigurationModel.py index bb219a0e2f..a7219c6a55 100644 --- a/cura/PrinterOutput/ConfigurationModel.py +++ b/cura/PrinterOutput/ConfigurationModel.py @@ -1,11 +1,13 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from PyQt5.QtCore import pyqtProperty, QObject +from PyQt5.QtCore import pyqtProperty, QObject, pyqtSignal class ConfigurationModel(QObject): + configurationChanged = pyqtSignal() + def __init__(self): self._printer_type = None self._extruder_configurations = [] @@ -21,14 +23,14 @@ class ConfigurationModel(QObject): def setExtruderConfigurations(self, extruder_configurations): self._extruder_configurations = extruder_configurations - @pyqtProperty("QVariantList", fset = setExtruderConfigurations, constant = True) + @pyqtProperty("QVariantList", fset = setExtruderConfigurations, notify = configurationChanged) def extruderConfigurations(self): return self._extruder_configurations def setBuildplateConfiguration(self, buildplate_configuration): self._buildplate_configuration = buildplate_configuration - @pyqtProperty(str, fset = setBuildplateConfiguration, constant = True) + @pyqtProperty(str, fset = setBuildplateConfiguration, notify = configurationChanged) def buildplateConfiguration(self): return self._buildplate_configuration diff --git a/cura/PrinterOutput/ExtruderOutputModel.py b/cura/PrinterOutput/ExtruderOutputModel.py index 33f3bf71f5..3e415fb47a 100644 --- a/cura/PrinterOutput/ExtruderOutputModel.py +++ b/cura/PrinterOutput/ExtruderOutputModel.py @@ -1,8 +1,7 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, QVariant, pyqtSlot -from UM.Logger import Logger +from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, pyqtSlot from typing import Optional @@ -83,7 +82,7 @@ class ExtruderOutputModel(QObject): self._extruder_configuration = { "position": self._position, "material": self._active_material.type if self.activeMaterial is not None else None, - "hotend_id": self._hotend_id + "hotendID": self._hotend_id } print("Recalculating extruder configuration:", self._extruder_configuration) self.extruderConfigurationChanged.emit() diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index 0cdec88194..9d0c9a81b5 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -1,9 +1,8 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, QVariant, pyqtSlot -from UM.Logger import Logger -from typing import Optional, List +from typing import Optional from UM.Math.Vector import Vector from cura.PrinterOutput.ConfigurationModel import ConfigurationModel from cura.PrinterOutput.ExtruderOutputModel import ExtruderOutputModel @@ -42,7 +41,7 @@ class PrinterOutputModel(QObject): self._printer_state = "unknown" self._is_preheating = False self._type = "" - # Update the configuration every time the one of the extruders changes its configuration + # Update the printer configuration every time any of the extruders changes its configuration for extruder in self._extruders: extruder.extruderConfigurationChanged.connect(self._updatePrinterConfiguration) diff --git a/cura/PrinterOutputDevice.py b/cura/PrinterOutputDevice.py index ac8f317689..4600559fe8 100644 --- a/cura/PrinterOutputDevice.py +++ b/cura/PrinterOutputDevice.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from UM.i18n import i18nCatalog @@ -6,13 +6,12 @@ from UM.OutputDevice.OutputDevice import OutputDevice from PyQt5.QtCore import pyqtProperty, QObject, QTimer, pyqtSignal from PyQt5.QtWidgets import QMessageBox - from UM.Logger import Logger from UM.Signal import signalemitter from UM.Application import Application from enum import IntEnum # For the connection state tracking. -from typing import List, Optional +from typing import List, Set, Optional MYPY = False if MYPY: @@ -46,13 +45,13 @@ class PrinterOutputDevice(QObject, OutputDevice): connectionTextChanged = pyqtSignal() # Signal to indicate that the configuration of one of the printers has changed. - configurationChanged = pyqtSignal() + uniqueConfigurationsChanged = pyqtSignal() def __init__(self, device_id, parent = None): super().__init__(device_id = device_id, parent = parent) self._printers = [] # type: List[PrinterOutputModel] - self._unique_configurations = [] # type: List[ConfigurationModel] + self._unique_configurations = {} # type: Set[ConfigurationModel] self._monitor_view_qml_path = "" self._monitor_component = None @@ -182,20 +181,22 @@ class PrinterOutputDevice(QObject, OutputDevice): self.acceptsCommandsChanged.emit() # Returns the unique configurations of the current printers - @pyqtProperty("QVariantList", notify = configurationChanged) - def uniqueConfiguration(self): + @pyqtProperty("QVariantMap", notify = uniqueConfigurationsChanged) + def uniqueConfigurations(self): return self._unique_configurations def _updateUniqueConfigurations(self): - print("Calculating the unique configurations") - self._unique_configurations = list(set([printer.printerConfiguration for printer in self._printers])) - print(self._unique_configurations) - self.configurationChanged.emit() + self._unique_configurations = set([printer.printerConfiguration for printer in self._printers]) + self.uniqueConfigurationsChanged.emit() def _onPrintersChanged(self): for printer in self._printers: printer.configurationChanged.connect(self._updateUniqueConfigurations) + # If at this point the list of unique configurations is empty, we force the calculation + if not self._unique_configurations: + self._updateUniqueConfigurations() + ## The current processing state of the backend. class ConnectionState(IntEnum): diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml index 45adfb88f2..7d9c87edf4 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml @@ -11,7 +11,7 @@ Rectangle { id: configurationItem - property var printer: null + property var configuration: null signal configurationSelected() height: childrenRect.height @@ -26,7 +26,7 @@ Rectangle Label { - text: printer.name + text: configuration.printerType } Row @@ -41,7 +41,7 @@ Rectangle Repeater { height: childrenRect.height - model: printer.extruders + model: configuration.extruderConfigurations delegate: PrintCoreConfiguration { printCoreConfiguration: modelData @@ -55,7 +55,7 @@ Rectangle // // Label // { -// text: printer.name + "-" + printer.type +// text: configuration.buildplateConfiguration // } // } } diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml index 1575f47ecc..fa82f43871 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -2,7 +2,8 @@ // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.7 -import QtQuick.Controls 2.0 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 import UM 1.2 as UM import Cura 1.0 as Cura @@ -21,12 +22,13 @@ Column width: parent.width - 2 * parent.padding } - Item - { + ScrollView { id: container width: parent.width - 2 * parent.padding height: childrenRect.height + style: UM.Theme.styles.scrollview + Repeater { height: childrenRect.height model: outputDevice != null ? outputDevice.connectedPrintersTypeCount : null @@ -42,23 +44,24 @@ Column ListView { - id: grid + id: configurationList anchors.top: printerTypeHeader.bottom anchors.topMargin: UM.Theme.getSize("default_margin").height width: container.width height: childrenRect.height - model: outputDevice.printers + model: outputDevice.uniqueConfigurations delegate: ConfigurationItem { height: parent.height width: parent.width - printer: modelData + configuration: modelData onConfigurationSelected: { - print("SELECCIONANDO IMPRESORA", printer.name) - outputDevice.setActivePrinter(printer) + print("SELECCIONANDO CONFIGURACION", JSON.stringify(configuration)) } + Component.onCompleted: {print("$$$$$$$$$$$$$$$$$$ Configuracion", JSON.stringify(configuration))} } + Component.onCompleted: {print("$$$$$$$$$$$$$$$$$$ Elementos del modelo", JSON.stringify(outputDevice.uniqueConfigurations))} } } } diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml index 4b2c3800f0..4097df229b 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml @@ -2,9 +2,7 @@ // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.7 -import QtQuick.Controls 1.4 -import QtQuick.Controls 2.3 as QQC2 -import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.3 import QtQuick.Controls.Styles 1.4 import UM 1.2 as UM @@ -15,70 +13,10 @@ Item id: configurationSelector property var panelWidth: control.width property var panelVisible: false - Button - { - text: "Matched" - width: parent.width - height: parent.height - style: ButtonStyle - { - background: Rectangle - { - color: - { - if(control.pressed) - { - return UM.Theme.getColor("sidebar_header_active"); - } - else if(control.hovered) - { - return UM.Theme.getColor("sidebar_header_hover"); - } - else - { - return UM.Theme.getColor("sidebar_header_bar"); - } - } - Behavior on color { ColorAnimation { duration: 50; } } + SyncButton { } - UM.RecolorImage - { - id: downArrow - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("default_margin").width - width: UM.Theme.getSize("standard_arrow").width - height: UM.Theme.getSize("standard_arrow").height - sourceSize.width: width - sourceSize.height: width - color: UM.Theme.getColor("text_emphasis") - source: UM.Theme.getIcon("arrow_bottom") - } - Label - { - id: sidebarComboBoxLabel - color: UM.Theme.getColor("sidebar_header_text_active") - text: control.text - elide: Text.ElideRight - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("default_margin").width * 2 - anchors.right: downArrow.left - anchors.rightMargin: control.rightMargin - anchors.verticalCenter: parent.verticalCenter; - font: UM.Theme.getFont("large") - } - } - label: Label {} - } - - onClicked: - { - panelVisible = !panelVisible - } - } - - QQC2.Popup + Popup { id: popup y: configurationSelector.height - UM.Theme.getSize("default_lining").height diff --git a/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml b/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml index c9875ae668..670d618849 100644 --- a/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml +++ b/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml @@ -17,7 +17,7 @@ Item Label { id: materialLabel - text: printCoreConfiguration.activeMaterial != null ? printCoreConfiguration.activeMaterial.name : "" + text: printCoreConfiguration.material elide: Text.ElideRight width: parent.width font: UM.Theme.getFont("very_small") diff --git a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml new file mode 100644 index 0000000000..79c75bb55d --- /dev/null +++ b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml @@ -0,0 +1,71 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import UM 1.2 as UM + +Button +{ + text: "Matched" + width: parent.width + height: parent.height + + style: ButtonStyle + { + background: Rectangle + { + color: + { + if(control.pressed) + { + return UM.Theme.getColor("sidebar_header_active"); + } + else if(control.hovered) + { + return UM.Theme.getColor("sidebar_header_hover"); + } + else + { + return UM.Theme.getColor("sidebar_header_bar"); + } + } + Behavior on color { ColorAnimation { duration: 50; } } + + UM.RecolorImage + { + id: downArrow + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: UM.Theme.getSize("default_margin").width + width: UM.Theme.getSize("standard_arrow").width + height: UM.Theme.getSize("standard_arrow").height + sourceSize.width: width + sourceSize.height: width + color: UM.Theme.getColor("text_emphasis") + source: UM.Theme.getIcon("arrow_bottom") + } + Label + { + id: sidebarComboBoxLabel + color: UM.Theme.getColor("sidebar_header_text_active") + text: control.text + elide: Text.ElideRight + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("default_margin").width * 2 + anchors.right: downArrow.left + anchors.rightMargin: control.rightMargin + anchors.verticalCenter: parent.verticalCenter; + font: UM.Theme.getFont("large") + } + } + label: Label {} + } + + onClicked: + { + panelVisible = !panelVisible + } +} \ No newline at end of file From 22b1c2127f3afe56fb36b0b1f9a133ec55a81882 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Sun, 4 Mar 2018 18:13:27 +0100 Subject: [PATCH 092/446] CURA-4870 Add information of the current configuration selected in the active printer --- cura/PrinterOutputDevice.py | 5 ++--- cura/Settings/MachineManager.py | 29 ++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/cura/PrinterOutputDevice.py b/cura/PrinterOutputDevice.py index 4600559fe8..97fa6c01d9 100644 --- a/cura/PrinterOutputDevice.py +++ b/cura/PrinterOutputDevice.py @@ -193,9 +193,8 @@ class PrinterOutputDevice(QObject, OutputDevice): for printer in self._printers: printer.configurationChanged.connect(self._updateUniqueConfigurations) - # If at this point the list of unique configurations is empty, we force the calculation - if not self._unique_configurations: - self._updateUniqueConfigurations() + # At this point there may be non-updated configurations + self._updateUniqueConfigurations() ## The current processing state of the backend. diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index cc5c4aa539..d487a0605d 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -27,9 +27,9 @@ from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.SettingFunction import SettingFunction from UM.Signal import postponeSignals, CompressTechnique - from cura.QualityManager import QualityManager from cura.PrinterOutputDevice import PrinterOutputDevice +from cura.PrinterOutput.ConfigurationModel import ConfigurationModel from cura.Settings.ExtruderManager import ExtruderManager from .CuraStackBuilder import CuraStackBuilder @@ -115,6 +115,12 @@ class MachineManager(QObject): # There might already be some output devices by the time the signal is connected self._onOutputDevicesChanged() + self._current_printer_configuration = ConfigurationModel() # Indicates the current configuration setup in this printer + self.activeMaterialChanged.connect(self._onCurrentConfigurationChanged) + self.activeVariantChanged.connect(self._onCurrentConfigurationChanged) + # Force to compute the current configuration + self._onCurrentConfigurationChanged() + if active_machine_id != "" and ContainerRegistry.getInstance().findContainerStacksMetadata(id = active_machine_id): # An active machine was saved, so restore it. self.setActiveMachine(active_machine_id) @@ -146,6 +152,7 @@ class MachineManager(QObject): blurSettings = pyqtSignal() # Emitted to force fields in the advanced sidebar to un-focus, so they update properly outputDevicesChanged = pyqtSignal() + currentConfigurationChanged = pyqtSignal() # Emitted every time the current configurations of the machine changes def _onOutputDevicesChanged(self) -> None: for printer_output_device in self._printer_output_devices: @@ -161,6 +168,26 @@ class MachineManager(QObject): self.outputDevicesChanged.emit() + @pyqtProperty(QObject, notify = currentConfigurationChanged) + def currentConfiguration(self): + return self._current_printer_configuration + + def _onCurrentConfigurationChanged(self) -> None: + if not self._global_container_stack: + return + + self._printer_configuration.printerType = self._global_container_stack.definition.getName() + extruder_configurations = [] + for extruder in self._global_container_stack.extruders: + extruder_configurations.append({ + "position": len(extruder_configurations), + "material": extruder.material.getName() if extruder.material != self._empty_material_container else None, + "hotendID": extruder.variant.getName() if extruder.variant != self._empty_variant_container else None + }) + self._printer_configuration.extruderConfigurations = extruder_configurations + self._printer_configuration.buildplateConfiguration = self._global_container_stack.variant.getName() if self._global_container_stack.variant is not None else None + self.currentConfigurationChanged.emit() + @property def newVariant(self): return self._new_variant_container From 1ee5b441878e92225675aa31fb4f49d2a25fe095 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Sun, 4 Mar 2018 18:20:42 +0100 Subject: [PATCH 093/446] CURA-4870 Fix references to the extruder stacks --- cura/Settings/MachineManager.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index d487a0605d..f148942336 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -176,16 +176,17 @@ class MachineManager(QObject): if not self._global_container_stack: return - self._printer_configuration.printerType = self._global_container_stack.definition.getName() + self._current_printer_configuration.printerType = self._global_container_stack.definition.getName() extruder_configurations = [] - for extruder in self._global_container_stack.extruders: + for extruder in self._global_container_stack.extruders.values(): extruder_configurations.append({ "position": len(extruder_configurations), "material": extruder.material.getName() if extruder.material != self._empty_material_container else None, "hotendID": extruder.variant.getName() if extruder.variant != self._empty_variant_container else None }) - self._printer_configuration.extruderConfigurations = extruder_configurations - self._printer_configuration.buildplateConfiguration = self._global_container_stack.variant.getName() if self._global_container_stack.variant is not None else None + self._current_printer_configuration.extruderConfigurations = extruder_configurations + self._current_printer_configuration.buildplateConfiguration = self._global_container_stack.variant.getName() if self._global_container_stack.variant is not None else None + print(self._current_printer_configuration.extruderConfigurations) self.currentConfigurationChanged.emit() @property From 4a498fd622bf38c9e93560d1d4da79fec55b6bfb Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Sun, 4 Mar 2018 21:56:44 +0000 Subject: [PATCH 094/446] Tweak various bridge setting values & descriptions. --- resources/definitions/fdmprinter.def.json | 33 ++++++++++++----------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 5550924c4f..396c45a59e 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6255,11 +6255,11 @@ "description": "The speed at which bridge skin regions are printed.", "unit": "mm/s", "type": "float", - "minimum_value": "0.1", + "minimum_value": "cool_min_speed", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)", "maximum_value_warning": "300", - "default_value": 20, - "value": "speed_topbottom / 2", + "default_value": 15, + "value": "max(cool_min_speed, speed_topbottom / 2)", "enabled": "bridge_settings_enabled", "settable_per_mesh": true }, @@ -6269,18 +6269,18 @@ "description": "The speed at which the bridge walls are printed.", "unit": "mm/s", "type": "float", - "minimum_value": "0.1", + "minimum_value": "cool_min_speed", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)", "maximum_value_warning": "300", - "default_value": 20, - "value": "speed_wall_0 / 2", + "default_value": 15, + "value": "max(cool_min_speed, speed_wall_0 / 2)", "enabled": "bridge_settings_enabled", "settable_per_mesh": true }, "bridge_skin_material_flow": { "label": "Bridge Skin Flow", - "description": "Flow compensation: the amount of material extruded when bridging skin is multiplied by this value.", + "description": "When printing bridge skin regions, the amount of material extruded is multiplied by this value.", "unit": "%", "default_value": 50, "type": "float", @@ -6293,7 +6293,7 @@ "bridge_wall_material_flow": { "label": "Bridge Wall Flow", - "description": "Flow compensation: the amount of material extruded when bridging walls is multiplied by this value.", + "description": "When printing bridge walls, the amount of material extruded is multiplied by this value.", "unit": "%", "default_value": 50, "type": "float", @@ -6306,7 +6306,7 @@ "bridge_fan_speed": { "label": "Bridge Fan Speed", - "description": "Fan speed to use when printing bridge walls and skin.", + "description": "Percentage fan speed to use when printing bridge walls and skin.", "unit": "%", "minimum_value": "0", "maximum_value": "100", @@ -6317,8 +6317,8 @@ }, "bridge_process_second_skin": { - "label": "Bridges Have Second Skin", - "description": "If enabled, the skin regions on the second layer above the air gap are printed using bridge second skin settings. Otherwise, those skin regions are printed using the normal skin settings.", + "label": "Enable Second Bridge Layer", + "description": "If enabled, the skin regions on the second layer above the air are printed using bridge second skin settings. Otherwise, those skin regions are printed using the normal skin settings.", "type": "bool", "default_value": true, "enabled": "bridge_settings_enabled", @@ -6330,10 +6330,10 @@ "description": "Print speed to use when printing the second bridge skin layer.", "unit": "mm/s", "type": "float", - "minimum_value": "0.1", + "minimum_value": "cool_min_speed", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)", "maximum_value_warning": "300", - "default_value": 20, + "default_value": 15, "value": "bridge_skin_speed", "enabled": "bridge_settings_enabled and bridge_process_second_skin", "settable_per_mesh": true @@ -6341,11 +6341,12 @@ "bridge_skin_material_flow_2": { "label": "Bridge Second Skin Flow", - "description": "Flow compensation: the amount of material extruded when printing the second bridge skin layer is multiplied by this value.", + "description": "When printing the second bridge skin layer, the amount of material extruded is multiplied by this value.", "unit": "%", - "default_value": 100, + "default_value": 125, "type": "float", "minimum_value": "5", + "maximum_value": "500", "minimum_value_warning": "50", "maximum_value_warning": "150", "enabled": "bridge_settings_enabled and bridge_process_second_skin", @@ -6354,7 +6355,7 @@ "bridge_fan_speed_2": { "label": "Bridge Second Skin Fan Speed", - "description": "Fan speed to use when printing the second bridge skin layer.", + "description": "Percentage fan speed to use when printing the second bridge skin layer.", "unit": "%", "minimum_value": "0", "maximum_value": "100", From b8ad0959a744785360a29b0b4824b1952a906521 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 5 Mar 2018 09:41:22 +0100 Subject: [PATCH 095/446] CURA-4870 Add call to the QObject constructor --- cura/PrinterOutput/ConfigurationModel.py | 1 + cura/PrinterOutputDevice.py | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cura/PrinterOutput/ConfigurationModel.py b/cura/PrinterOutput/ConfigurationModel.py index a7219c6a55..5102dff239 100644 --- a/cura/PrinterOutput/ConfigurationModel.py +++ b/cura/PrinterOutput/ConfigurationModel.py @@ -9,6 +9,7 @@ class ConfigurationModel(QObject): configurationChanged = pyqtSignal() def __init__(self): + super().__init__() self._printer_type = None self._extruder_configurations = [] self._buildplate_configuration = None diff --git a/cura/PrinterOutputDevice.py b/cura/PrinterOutputDevice.py index 97fa6c01d9..875cc17fe8 100644 --- a/cura/PrinterOutputDevice.py +++ b/cura/PrinterOutputDevice.py @@ -3,7 +3,7 @@ from UM.i18n import i18nCatalog from UM.OutputDevice.OutputDevice import OutputDevice -from PyQt5.QtCore import pyqtProperty, QObject, QTimer, pyqtSignal +from PyQt5.QtCore import pyqtProperty, QObject, QTimer, pyqtSignal, QVariant from PyQt5.QtWidgets import QMessageBox from UM.Logger import Logger @@ -11,7 +11,7 @@ from UM.Signal import signalemitter from UM.Application import Application from enum import IntEnum # For the connection state tracking. -from typing import List, Set, Optional +from typing import List, Optional MYPY = False if MYPY: @@ -51,7 +51,7 @@ class PrinterOutputDevice(QObject, OutputDevice): super().__init__(device_id = device_id, parent = parent) self._printers = [] # type: List[PrinterOutputModel] - self._unique_configurations = {} # type: Set[ConfigurationModel] + self._unique_configurations = [] # type: List[ConfigurationModel] self._monitor_view_qml_path = "" self._monitor_component = None @@ -180,13 +180,13 @@ class PrinterOutputDevice(QObject, OutputDevice): self.acceptsCommandsChanged.emit() - # Returns the unique configurations of the current printers - @pyqtProperty("QVariantMap", notify = uniqueConfigurationsChanged) + # Returns the unique configurations of the printers within this output device + @pyqtProperty("QVariantList", notify = uniqueConfigurationsChanged) def uniqueConfigurations(self): return self._unique_configurations def _updateUniqueConfigurations(self): - self._unique_configurations = set([printer.printerConfiguration for printer in self._printers]) + self._unique_configurations = list(set([printer.printerConfiguration for printer in self._printers])) self.uniqueConfigurationsChanged.emit() def _onPrintersChanged(self): From 871f0a130edd32d2dff694e2e19f770230ed2d64 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 5 Mar 2018 11:44:26 +0100 Subject: [PATCH 096/446] CURA-4870 Frontend formatting to show the configurations --- .../ConfigurationMenu/ConfigurationItem.qml | 63 ++++++++++++++----- .../ConfigurationListView.qml | 7 +-- .../PrintCoreConfiguration.qml | 57 +++++++++++++++-- .../Menus/ConfigurationMenu/SyncButton.qml | 2 +- 4 files changed, 101 insertions(+), 28 deletions(-) diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml index 7d9c87edf4..3d511e3250 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml @@ -16,48 +16,77 @@ Rectangle height: childrenRect.height border.width: UM.Theme.getSize("default_lining").width - border.color: "black" + border.color: UM.Theme.getColor("sidebar_lining_thin") Column { id: contentColumn + width: parent.width padding: UM.Theme.getSize("default_margin").width - spacing: UM.Theme.getSize("default_margin").height - - Label - { - text: configuration.printerType - } + spacing: Math.round(UM.Theme.getSize("default_margin").height / 2) Row { id: extruderRow - width: parent.width + width: parent.width - 2 * parent.padding height: childrenRect.height spacing: UM.Theme.getSize("default_margin").width Repeater { + id: repeater height: childrenRect.height model: configuration.extruderConfigurations delegate: PrintCoreConfiguration { + width: Math.round(parent.width / 2) printCoreConfiguration: modelData } + Component.onCompleted: {print("ELEMENTOS:", repeater.model.count)} } } -// Rectangle -// { -// id: buildplateInformation -// -// Label -// { -// text: configuration.buildplateConfiguration -// } -// } + //Buildplate row separator + Rectangle { + id: separator + + visible: buildplateInformation.visible + width: parent.width - 2 * parent.padding + height: visible ? Math.round(UM.Theme.getSize("sidebar_lining_thin").height / 2) : 0 + color: UM.Theme.getColor("sidebar_lining_thin") + } + + Item + { + id: buildplateInformation + width: parent.width - 2 * parent.padding + height: childrenRect.height + visible: configuration.buildplateConfiguration != "" + + UM.RecolorImage { + id: buildplateIcon + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + width: UM.Theme.getSize("standard_arrow").width + height: UM.Theme.getSize("standard_arrow").height + sourceSize.width: width + sourceSize.height: height + source: UM.Theme.getIcon("extruder_button") + + color: "black" + } + + Label + { + id: buildplateLabel + anchors.left: buildplateIcon.right + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: Math.round(UM.Theme.getSize("default_margin").height / 2) + text: configuration.buildplateConfiguration + } + } } MouseArea diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml index fa82f43871..f962dbaa9f 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -14,7 +14,7 @@ Column property var outputDevice: Cura.MachineManager.printerOutputDevices[0] height: childrenRect.height + 2 * padding padding: UM.Theme.getSize("default_margin").width - spacing: UM.Theme.getSize("default_margin").height + spacing: Math.round(UM.Theme.getSize("default_margin").height / 2) Label { text: catalog.i18nc("@label:header configurations", "Available configurations") @@ -25,7 +25,7 @@ Column ScrollView { id: container width: parent.width - 2 * parent.padding - height: childrenRect.height + height: 500 //childrenRect.height style: UM.Theme.styles.scrollview @@ -52,16 +52,13 @@ Column model: outputDevice.uniqueConfigurations delegate: ConfigurationItem { - height: parent.height width: parent.width configuration: modelData onConfigurationSelected: { print("SELECCIONANDO CONFIGURACION", JSON.stringify(configuration)) } - Component.onCompleted: {print("$$$$$$$$$$$$$$$$$$ Configuracion", JSON.stringify(configuration))} } - Component.onCompleted: {print("$$$$$$$$$$$$$$$$$$ Elementos del modelo", JSON.stringify(outputDevice.uniqueConfigurations))} } } } diff --git a/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml b/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml index 670d618849..8155842349 100644 --- a/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml +++ b/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml @@ -7,29 +7,76 @@ import QtQuick.Controls 2.0 import UM 1.2 as UM -Item +Column { id: extruderInfo property var printCoreConfiguration + spacing: Math.round(UM.Theme.getSize("default_margin").height / 2) height: childrenRect.height + Item + { + id: extruder + width: parent.width + height: childrenRect.height + + Label + { + id: extruderLabel + text: catalog.i18nc("@label:extruder label", "Extruder") + elide: Text.ElideRight + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + font: UM.Theme.getFont("small") + } + + // Rounded item to show the extruder number + Item + { + id: extruderIconItem + anchors.verticalCenter: parent.verticalCenter + anchors.left: extruderLabel.right + anchors.leftMargin: Math.round(UM.Theme.getSize("default_margin").width / 2) + + width: UM.Theme.getSize("section_icon").width + height: UM.Theme.getSize("section_icon").height + + UM.RecolorImage { + id: mainCircle + anchors.fill: parent + + sourceSize.width: parent.width + sourceSize.height: parent.height + source: UM.Theme.getIcon("extruder_button") + + color: extruderNumberText.color + } + + Label + { + id: extruderNumberText + anchors.centerIn: parent + text: printCoreConfiguration.position + 1 + font: UM.Theme.getFont("small") + } + } + } + Label { id: materialLabel text: printCoreConfiguration.material elide: Text.ElideRight width: parent.width - font: UM.Theme.getFont("very_small") + font: UM.Theme.getFont("small") } Label { - id: printCoreLabel + id: printCoreTypeLabel text: printCoreConfiguration.hotendID - anchors.top: materialLabel.bottom elide: Text.ElideRight width: parent.width font: UM.Theme.getFont("very_small") - opacity: 0.5 } } diff --git a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml index 79c75bb55d..f9e93b2d22 100644 --- a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml +++ b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml @@ -43,7 +43,7 @@ Button width: UM.Theme.getSize("standard_arrow").width height: UM.Theme.getSize("standard_arrow").height sourceSize.width: width - sourceSize.height: width + sourceSize.height: height color: UM.Theme.getColor("text_emphasis") source: UM.Theme.getIcon("arrow_bottom") } From f779a20a6ea8e762f7c92de7281492eb13c2d993 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 5 Mar 2018 12:13:46 +0100 Subject: [PATCH 097/446] CURA-4870 Cleanup UI and add buildplate icon --- .../ConfigurationMenu/ConfigurationItem.qml | 7 +++---- .../PrintCoreConfiguration.qml | 9 +++++---- .../themes/cura-light/icons/buildplate.svg | 17 +++++++++++++++++ 3 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 resources/themes/cura-light/icons/buildplate.svg diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml index 3d511e3250..4359e4eac7 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml @@ -44,7 +44,6 @@ Rectangle width: Math.round(parent.width / 2) printCoreConfiguration: modelData } - Component.onCompleted: {print("ELEMENTOS:", repeater.model.count)} } } @@ -69,11 +68,11 @@ Rectangle id: buildplateIcon anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter - width: UM.Theme.getSize("standard_arrow").width - height: UM.Theme.getSize("standard_arrow").height + width: UM.Theme.getSize("topbar_button_icon").width + height: UM.Theme.getSize("topbar_button_icon").height sourceSize.width: width sourceSize.height: height - source: UM.Theme.getIcon("extruder_button") + source: UM.Theme.getIcon("buildplate") color: "black" } diff --git a/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml b/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml index 8155842349..7b64ab61ac 100644 --- a/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml +++ b/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml @@ -28,7 +28,7 @@ Column elide: Text.ElideRight anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left - font: UM.Theme.getFont("small") + font: UM.Theme.getFont("default") } // Rounded item to show the extruder number @@ -58,7 +58,7 @@ Column id: extruderNumberText anchors.centerIn: parent text: printCoreConfiguration.position + 1 - font: UM.Theme.getFont("small") + font: UM.Theme.getFont("default") } } } @@ -69,14 +69,15 @@ Column text: printCoreConfiguration.material elide: Text.ElideRight width: parent.width - font: UM.Theme.getFont("small") + font: UM.Theme.getFont("default_bold") } + Label { id: printCoreTypeLabel text: printCoreConfiguration.hotendID elide: Text.ElideRight width: parent.width - font: UM.Theme.getFont("very_small") + font: UM.Theme.getFont("default") } } diff --git a/resources/themes/cura-light/icons/buildplate.svg b/resources/themes/cura-light/icons/buildplate.svg new file mode 100644 index 0000000000..9e61296958 --- /dev/null +++ b/resources/themes/cura-light/icons/buildplate.svg @@ -0,0 +1,17 @@ + + + + icn_buildplate + Created with Sketch. + + + + + + + + + + + + \ No newline at end of file From b0801d40e3f7d5b026ac5bbda3c4b336b0fb8a9b Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 5 Mar 2018 12:47:32 +0100 Subject: [PATCH 098/446] CURA-4400 added metadata entry for enabled instead of internal variable --- cura/Settings/ExtruderStack.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cura/Settings/ExtruderStack.py b/cura/Settings/ExtruderStack.py index 2a4207c3f3..fcdcdd9228 100644 --- a/cura/Settings/ExtruderStack.py +++ b/cura/Settings/ExtruderStack.py @@ -10,7 +10,7 @@ from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase from UM.Settings.ContainerStack import ContainerStack from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.Interfaces import ContainerInterface, PropertyEvaluationContext -from UM.Settings.SettingInstance import SettingInstance +from UM.Util import parseBool from . import Exceptions from .CuraContainerStack import CuraContainerStack @@ -28,7 +28,6 @@ class ExtruderStack(CuraContainerStack): super().__init__(container_id, *args, **kwargs) self.addMetaDataEntry("type", "extruder_train") # For backward compatibility - self._enabled = True self.propertiesChanged.connect(self._onPropertiesChanged) @@ -51,12 +50,14 @@ class ExtruderStack(CuraContainerStack): return super().getNextStack() def setEnabled(self, enabled): - self._enabled = enabled + if "enabled" not in self._metadata: + self.addMetaDataEntry("enabled", "True") + self.setMetaDataEntry("enabled", str(enabled)) self.enabledChanged.emit() @pyqtProperty(bool, notify = enabledChanged) def isEnabled(self): - return self._enabled + return parseBool(self.getMetaDataEntry("enabled", "True")) @classmethod def getLoadingPriority(cls) -> int: From 37d02da1f147cedd4f832b277925755cf63ace90 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 5 Mar 2018 14:01:39 +0100 Subject: [PATCH 099/446] CURA-4400 restore correct default extruder, added extruders_enabled_count and use that in fdmprinters (result: i.e. one at a time can be enabled by disabling an extruder) --- cura/Settings/ExtruderManager.py | 2 + cura/Settings/MachineManager.py | 26 +++++++++--- resources/definitions/fdmprinter.def.json | 52 ++++++++++++++--------- 3 files changed, 54 insertions(+), 26 deletions(-) diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index ee38055a98..fcbe67e465 100755 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -484,6 +484,8 @@ class ExtruderManager(QObject): result = [] for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()): + if not extruder.isEnabled: + continue # only include values from extruders that are "active" for the current machine instance if int(extruder.getMetaDataEntry("position")) >= global_stack.getProperty("machine_extruder_count", "value"): continue diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index b46078176f..56479f40a2 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -195,7 +195,6 @@ class MachineManager(QObject): # Update the local global container stack reference self._global_container_stack = Application.getInstance().getGlobalContainerStack() - self.globalContainerChanged.emit() # after switching the global stack we reconnect all the signals and set the variant and material references @@ -309,6 +308,8 @@ class MachineManager(QObject): Application.getInstance().setGlobalContainerStack(global_stack) ExtruderManager.getInstance()._globalContainerStackChanged() self._initMachineState(containers[0]) + self.updateDefaultExtruder() + self.updateNumberExtrudersEnabled() self.globalContainerChanged.emit() self._onGlobalContainerChanged() @@ -732,6 +733,7 @@ class MachineManager(QObject): definition_changes_container.setProperty("machine_extruder_count", "value", extruder_count) self.updateDefaultExtruder() + self.updateNumberExtrudersEnabled() self.correctExtruderSettings() # Check to see if any objects are set to print with an extruder that will no longer exist @@ -748,14 +750,14 @@ class MachineManager(QObject): # Move settable_per_extruder values out of the global container # After CURA-4482 this should not be the case anymore, but we still want to support older project files. - global_user_container = self._global_container_stack.getTop() + global_user_container = self._global_container_stack.userChanges # Make sure extruder_stacks exists extruder_stacks = [] if previous_extruder_count == 1: extruder_stacks = ExtruderManager.getInstance().getActiveExtruderStacks() - global_user_container = self._global_container_stack.getTop() + global_user_container = self._global_container_stack.userChanges for setting_instance in global_user_container.findInstances(): setting_key = setting_instance.definition.key @@ -764,7 +766,7 @@ class MachineManager(QObject): if settable_per_extruder: limit_to_extruder = int(self._global_container_stack.getProperty(setting_key, "limit_to_extruder")) extruder_stack = extruder_stacks[max(0, limit_to_extruder)] - extruder_stack.getTop().setProperty(setting_key, "value", global_user_container.getProperty(setting_key, "value")) + extruder_stack.userChanges.setProperty(setting_key, "value", global_user_container.getProperty(setting_key, "value")) global_user_container.removeInstance(setting_key) # Signal that the global stack has changed @@ -779,12 +781,23 @@ class MachineManager(QObject): def updateDefaultExtruder(self): extruder_items = sorted(self._global_container_stack.extruders.items()) + old_position = self._default_extruder_position new_default_position = "0" for position, extruder in extruder_items: if extruder.isEnabled: new_default_position = position break - self._default_extruder_position = new_default_position + if new_default_position != old_position: + self._default_extruder_position = new_default_position + self.extruderChanged.emit() + + def updateNumberExtrudersEnabled(self): + definition_changes_container = self._global_container_stack.definitionChanges + extruder_count = 0 + for position, extruder in self._global_container_stack.extruders.items(): + if extruder.isEnabled: + extruder_count += 1 + definition_changes_container.setProperty("extruders_enabled_count", "value", extruder_count) @pyqtProperty(str, notify = extruderChanged) def defaultExtruderPosition(self): @@ -795,10 +808,11 @@ class MachineManager(QObject): extruder = self.getExtruder(position) extruder.setEnabled(enabled) self.updateDefaultExtruder() + self.updateNumberExtrudersEnabled() if enabled == False: self.correctExtruderSettings() self.extruderChanged.emit() - # HACK to update items in SettingExtruder + # update items in SettingExtruder ExtruderManager.getInstance().extrudersChanged.emit(self._global_container_stack.getId()) def _onMachineNameChanged(self): diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index b926dc0abc..34dc6538b3 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -211,6 +211,18 @@ "settable_per_extruder": false, "settable_per_meshgroup": false }, + "extruders_enabled_count": + { + "label": "Number of Extruders that are enabled", + "description": "Number of extruder trains that are enabled; automatically set in software", + "default_value": "machine_extruder_count", + "minimum_value": "1", + "maximum_value": "16", + "type": "int", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false + }, "machine_nozzle_tip_outer_diameter": { "label": "Outer nozzle diameter", @@ -887,7 +899,7 @@ "settable_per_extruder": false, "settable_per_meshgroup": true, "settable_globally": true, - "enabled": "machine_extruder_count > 1", + "enabled": "extruders_enabled_count > 1", "children": { "wall_0_extruder_nr": { @@ -900,7 +912,7 @@ "settable_per_extruder": false, "settable_per_meshgroup": true, "settable_globally": true, - "enabled": "machine_extruder_count > 1" + "enabled": "extruders_enabled_count > 1" }, "wall_x_extruder_nr": { @@ -913,7 +925,7 @@ "settable_per_extruder": false, "settable_per_meshgroup": true, "settable_globally": true, - "enabled": "machine_extruder_count > 1" + "enabled": "extruders_enabled_count > 1" } } }, @@ -970,7 +982,7 @@ "settable_per_extruder": false, "settable_per_meshgroup": true, "settable_globally": true, - "enabled": "machine_extruder_count > 1 and max(extruderValues('roofing_layer_count')) > 0 and max(extruderValues('top_layers')) > 0" + "enabled": "extruders_enabled_count > 1 and max(extruderValues('roofing_layer_count')) > 0 and max(extruderValues('top_layers')) > 0" }, "roofing_layer_count": { @@ -995,7 +1007,7 @@ "settable_per_extruder": false, "settable_per_meshgroup": true, "settable_globally": true, - "enabled": "machine_extruder_count > 1" + "enabled": "extruders_enabled_count > 1" }, "top_bottom_thickness": { @@ -1465,7 +1477,7 @@ "settable_per_extruder": false, "settable_per_meshgroup": true, "settable_globally": true, - "enabled": "machine_extruder_count > 1" + "enabled": "extruders_enabled_count > 1" }, "infill_sparse_density": { @@ -1916,7 +1928,7 @@ "minimum_value": "0", "maximum_value_warning": "10.0", "maximum_value": "machine_nozzle_heat_up_speed", - "enabled": "material_flow_dependent_temperature or (machine_extruder_count > 1 and material_final_print_temperature != material_print_temperature)", + "enabled": "material_flow_dependent_temperature or (extruders_enabled_count > 1 and material_final_print_temperature != material_print_temperature)", "settable_per_mesh": false, "settable_per_extruder": true }, @@ -2179,7 +2191,7 @@ "minimum_value": "-273.15", "minimum_value_warning": "0", "maximum_value_warning": "260", - "enabled": "machine_extruder_count > 1 and machine_nozzle_temp_enabled", + "enabled": "extruders_enabled_count > 1 and machine_nozzle_temp_enabled", "settable_per_mesh": false, "settable_per_extruder": true }, @@ -3281,7 +3293,7 @@ "description": "After the machine switched from one extruder to the other, the build plate is lowered to create clearance between the nozzle and the print. This prevents the nozzle from leaving oozed material on the outside of a print.", "type": "bool", "default_value": true, - "enabled": "retraction_hop_enabled and machine_extruder_count > 1", + "enabled": "retraction_hop_enabled and extruders_enabled_count > 1", "settable_per_mesh": false, "settable_per_extruder": true } @@ -3459,7 +3471,7 @@ "description": "The extruder train to use for printing the support. This is used in multi-extrusion.", "type": "extruder", "default_value": "-1", - "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", + "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, "settable_per_extruder": false, "children": { @@ -3470,7 +3482,7 @@ "type": "extruder", "default_value": "-1", "value": "support_extruder_nr", - "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", + "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, "settable_per_extruder": false }, @@ -3481,7 +3493,7 @@ "type": "extruder", "default_value": "-1", "value": "support_extruder_nr", - "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", + "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, "settable_per_extruder": false }, @@ -3492,7 +3504,7 @@ "type": "extruder", "default_value": "-1", "value": "support_extruder_nr", - "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", + "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, "settable_per_extruder": false, "children": @@ -3504,7 +3516,7 @@ "type": "extruder", "default_value": "-1", "value": "support_interface_extruder_nr", - "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", + "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, "settable_per_extruder": false }, @@ -3515,7 +3527,7 @@ "type": "extruder", "default_value": "-1", "value": "support_interface_extruder_nr", - "enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1", + "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, "settable_per_extruder": false } @@ -4185,7 +4197,7 @@ "description": "The extruder train to use for printing the skirt/brim/raft. This is used in multi-extrusion.", "type": "extruder", "default_value": "-1", - "enabled": "machine_extruder_count > 1 and resolveOrValue('adhesion_type') != 'none'", + "enabled": "extruders_enabled_count > 1 and resolveOrValue('adhesion_type') != 'none'", "settable_per_mesh": false, "settable_per_extruder": false }, @@ -4756,7 +4768,7 @@ "label": "Enable Prime Tower", "description": "Print a tower next to the print which serves to prime the material after each nozzle switch.", "type": "bool", - "enabled": "machine_extruder_count > 1", + "enabled": "extruders_enabled_count > 1", "default_value": false, "resolve": "any(extruderValues('prime_tower_enable'))", "settable_per_mesh": false, @@ -4904,7 +4916,7 @@ "description": "Enable exterior ooze shield. This will create a shell around the model which is likely to wipe a second nozzle if it's at the same height as the first nozzle.", "type": "bool", "resolve": "any(extruderValues('ooze_shield_enabled'))", - "enabled": "machine_extruder_count > 1", + "enabled": "extruders_enabled_count > 1", "default_value": false, "settable_per_mesh": false, "settable_per_extruder": false @@ -4997,7 +5009,7 @@ "description": "Remove areas where multiple meshes are overlapping with each other. This may be used if merged dual material objects overlap with each other.", "type": "bool", "default_value": true, - "value": "machine_extruder_count > 1", + "value": "extruders_enabled_count > 1", "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": true @@ -5044,7 +5056,7 @@ "one_at_a_time": "One at a Time" }, "default_value": "all_at_once", - "enabled": "machine_extruder_count == 1", + "enabled": "extruders_enabled_count == 1", "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false From cd01b096b52357c6384e555a141505cebb3c65cf Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Mon, 5 Mar 2018 14:33:13 +0100 Subject: [PATCH 100/446] Emit backend errors so we can process them differently than through a qml notification --- .dockerignore | 4 ++++ Dockerfile | 13 +++++++------ plugins/CuraEngineBackend/CuraEngineBackend.py | 9 +++++++++ 3 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..d25d71bcc9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +.git +.github +resources/materials +CuraEngine \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index b2b6243071..68255c56b9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,21 +24,22 @@ ENV URANIUM_BRANCH=master WORKDIR $CURA_APP_DIR RUN git clone -b $URANIUM_BRANCH --depth 1 https://github.com/Ultimaker/Uranium -# Setup Cura -ENV CURA_BRANCH=docker -WORKDIR $CURA_APP_DIR -RUN git clone -b $CURA_BRANCH --depth 1 https://github.com/Ultimaker/Cura - # Setup materials ENV MATERIALS_BRANCH=master -WORKDIR $CURA_APP_DIR/Cura/resources +WORKDIR $CURA_APP_DIR RUN git clone -b $MATERIALS_BRANCH --depth 1 https://github.com/Ultimaker/fdm_materials materials +# Setup Cura +WORKDIR $CURA_APP_DIR/Cura +ADD . . +RUN mv $CURA_APP_DIR/materials resources/materials + # Make sure Cura can find CuraEngine RUN ln -s /usr/local/bin/CuraEngine $CURA_APP_DIR/Cura # Run Cura WORKDIR $CURA_APP_DIR/Cura ENV PYTHONPATH=${PYTHONPATH}:$CURA_APP_DIR/Uranium +RUN chmod +x ./CuraEngine RUN chmod +x ./run_in_docker.sh CMD "./run_in_docker.sh" diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index 3982a0ad06..ffeddf21cc 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -33,6 +33,9 @@ from UM.i18n import i18nCatalog catalog = i18nCatalog("cura") class CuraEngineBackend(QObject, Backend): + + backendError = Signal() + ## Starts the back-end plug-in. # # This registers all the signal listeners and prepares for communication @@ -289,6 +292,7 @@ class CuraEngineBackend(QObject, Backend): if job.isCancelled() or job.getError() or job.getResult() == StartSliceJob.StartJobResult.Error: self.backendStateChange.emit(BackendState.Error) + self.backendError.emit(job) return if job.getResult() == StartSliceJob.StartJobResult.MaterialIncompatible: @@ -297,6 +301,7 @@ class CuraEngineBackend(QObject, Backend): "Unable to slice with the current material as it is incompatible with the selected machine or configuration."), title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() self.backendStateChange.emit(BackendState.Error) + self.backendError.emit(job) else: self.backendStateChange.emit(BackendState.NotStarted) return @@ -325,6 +330,7 @@ class CuraEngineBackend(QObject, Backend): title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() self.backendStateChange.emit(BackendState.Error) + self.backendError.emit(job) else: self.backendStateChange.emit(BackendState.NotStarted) return @@ -347,6 +353,7 @@ class CuraEngineBackend(QObject, Backend): title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() self.backendStateChange.emit(BackendState.Error) + self.backendError.emit(job) return if job.getResult() == StartSliceJob.StartJobResult.BuildPlateError: @@ -355,6 +362,7 @@ class CuraEngineBackend(QObject, Backend): title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() self.backendStateChange.emit(BackendState.Error) + self.backendError.emit(job) else: self.backendStateChange.emit(BackendState.NotStarted) @@ -364,6 +372,7 @@ class CuraEngineBackend(QObject, Backend): title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() self.backendStateChange.emit(BackendState.Error) + self.backendError.emit(job) else: self.backendStateChange.emit(BackendState.NotStarted) self._invokeSlice() From a992487589ec0992c5b20bb594afe9c11e97031c Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 5 Mar 2018 14:39:49 +0100 Subject: [PATCH 101/446] CURA-4870 Check wether the current configuration matches one of the unique configurations available on the printer output device. Improve some elements in the UI --- cura/Settings/MachineManager.py | 9 ++++++--- .../ConfigurationMenu/ConfigurationItem.qml | 17 ++++++++++++++--- .../PrintCoreConfiguration.qml | 9 +++++++-- .../qml/Menus/ConfigurationMenu/SyncButton.qml | 6 +++--- resources/themes/cura-light/theme.json | 17 ++++++++++++++++- 5 files changed, 46 insertions(+), 12 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index f148942336..0c0187ee98 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -180,15 +180,18 @@ class MachineManager(QObject): extruder_configurations = [] for extruder in self._global_container_stack.extruders.values(): extruder_configurations.append({ - "position": len(extruder_configurations), + "position": int(extruder.getMetaDataEntry("position")), "material": extruder.material.getName() if extruder.material != self._empty_material_container else None, "hotendID": extruder.variant.getName() if extruder.variant != self._empty_variant_container else None }) self._current_printer_configuration.extruderConfigurations = extruder_configurations - self._current_printer_configuration.buildplateConfiguration = self._global_container_stack.variant.getName() if self._global_container_stack.variant is not None else None - print(self._current_printer_configuration.extruderConfigurations) + self._current_printer_configuration.buildplateConfiguration = self._global_container_stack.variant.getName() if self._global_container_stack.variant != self._empty_variant_container else None self.currentConfigurationChanged.emit() + @pyqtSlot(QObject, result = bool) + def matchesConfiguration(self, configuration: ConfigurationModel) -> bool: + return self._current_printer_configuration == configuration + @property def newVariant(self): return self._new_variant_container diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml index 4359e4eac7..3bb14c3c26 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml @@ -12,11 +12,14 @@ Rectangle id: configurationItem property var configuration: null + property var selected: false signal configurationSelected() height: childrenRect.height border.width: UM.Theme.getSize("default_lining").width border.color: UM.Theme.getColor("sidebar_lining_thin") + color: selected ? UM.Theme.getColor("configuration_item_active") : UM.Theme.getColor("configuration_item") + property var textColor: selected ? UM.Theme.getColor("configuration_item_text_active") : UM.Theme.getColor("configuration_item_text") Column { @@ -43,6 +46,7 @@ Rectangle { width: Math.round(parent.width / 2) printCoreConfiguration: modelData + mainColor: textColor } } } @@ -54,7 +58,7 @@ Rectangle visible: buildplateInformation.visible width: parent.width - 2 * parent.padding height: visible ? Math.round(UM.Theme.getSize("sidebar_lining_thin").height / 2) : 0 - color: UM.Theme.getColor("sidebar_lining_thin") + color: textColor } Item @@ -73,8 +77,7 @@ Rectangle sourceSize.width: width sourceSize.height: height source: UM.Theme.getIcon("buildplate") - - color: "black" + color: textColor } Label @@ -84,6 +87,7 @@ Rectangle anchors.verticalCenter: parent.verticalCenter anchors.leftMargin: Math.round(UM.Theme.getSize("default_margin").height / 2) text: configuration.buildplateConfiguration + color: textColor } } } @@ -97,4 +101,11 @@ Rectangle onEntered: parent.border.color = UM.Theme.getColor("primary_hover") onExited: parent.border.color = "black" } + + Connections { + target: Cura.MachineManager + onCurrentConfigurationChanged: { + configurationItem.selected = Cura.MachineManager.matchesConfiguration(configuration) + } + } } \ No newline at end of file diff --git a/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml b/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml index 7b64ab61ac..74ecc114c7 100644 --- a/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml +++ b/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml @@ -11,6 +11,7 @@ Column { id: extruderInfo property var printCoreConfiguration + property var mainColor: "black" spacing: Math.round(UM.Theme.getSize("default_margin").height / 2) height: childrenRect.height @@ -29,6 +30,7 @@ Column anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left font: UM.Theme.getFont("default") + color: mainColor } // Rounded item to show the extruder number @@ -46,11 +48,11 @@ Column id: mainCircle anchors.fill: parent + anchors.centerIn: parent sourceSize.width: parent.width sourceSize.height: parent.height source: UM.Theme.getIcon("extruder_button") - - color: extruderNumberText.color + color: mainColor } Label @@ -59,6 +61,7 @@ Column anchors.centerIn: parent text: printCoreConfiguration.position + 1 font: UM.Theme.getFont("default") + color: mainColor } } } @@ -70,6 +73,7 @@ Column elide: Text.ElideRight width: parent.width font: UM.Theme.getFont("default_bold") + color: mainColor } Label @@ -79,5 +83,6 @@ Column elide: Text.ElideRight width: parent.width font: UM.Theme.getFont("default") + color: mainColor } } diff --git a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml index f9e93b2d22..a82d7cc515 100644 --- a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml +++ b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml @@ -9,7 +9,7 @@ import UM 1.2 as UM Button { - text: "Matched" + text: "No match" width: parent.width height: parent.height @@ -54,11 +54,11 @@ Button text: control.text elide: Text.ElideRight anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("default_margin").width * 2 + anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.right: downArrow.left anchors.rightMargin: control.rightMargin anchors.verticalCenter: parent.verticalCenter; - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("medium_bold") } } label: Label {} diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json index 8c8e6d1c47..46ea0fc49e 100644 --- a/resources/themes/cura-light/theme.json +++ b/resources/themes/cura-light/theme.json @@ -14,6 +14,16 @@ "weight": 50, "family": "Noto Sans" }, + "medium": { + "size": 1.16, + "weight": 50, + "family": "Noto Sans" + }, + "medium_bold": { + "size": 1.16, + "weight": 63, + "family": "Noto Sans" + }, "default": { "size": 1.0, "weight": 50, @@ -289,7 +299,12 @@ "layerview_move_combing": [0, 0, 255, 255], "layerview_move_retraction": [128, 128, 255, 255], "layerview_support_interface": [64, 192, 255, 255], - "layerview_nozzle": [181, 166, 66, 50] + "layerview_nozzle": [181, 166, 66, 50], + + "configuration_item": [255, 255, 255, 0], + "configuration_item_active": [31, 36, 39, 255], + "configuration_item_text": [0, 0, 0, 255], + "configuration_item_text_active": [255, 255, 255, 255] }, "sizes": { From 01f4e7c0e33d7d54fc9225ca54ef26b3420b2f17 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 5 Mar 2018 16:31:49 +0100 Subject: [PATCH 102/446] CURA-4400 on load mesh, set the extruder to the default extruder --- cura/CuraApplication.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index a4e86626dc..db0848bdf4 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1601,6 +1601,8 @@ class CuraApplication(QtApplication): fixed_nodes.append(node_) arranger = Arrange.create(fixed_nodes = fixed_nodes) min_offset = 8 + default_extruder_position = self.getMachineManager().defaultExtruderPosition + default_extruder_id = self._global_container_stack.extruders[default_extruder_position].getId() for original_node in nodes: @@ -1666,6 +1668,8 @@ class CuraApplication(QtApplication): op = AddSceneNodeOperation(node, scene.getRoot()) op.push() + + node.callDecoration("setActiveExtruder", default_extruder_id) scene.sceneChanged.emit(node) self.fileCompleted.emit(filename) From 7fd0a9b98b5faf1ab468ae8eba74bbf3e682fa1e Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 5 Mar 2018 17:01:53 +0100 Subject: [PATCH 103/446] CURA-4400 fixed multiply --- cura/Scene/CuraSceneNode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Scene/CuraSceneNode.py b/cura/Scene/CuraSceneNode.py index cfc41eb689..588fb75667 100644 --- a/cura/Scene/CuraSceneNode.py +++ b/cura/Scene/CuraSceneNode.py @@ -103,7 +103,7 @@ class CuraSceneNode(SceneNode): ## Taken from SceneNode, but replaced SceneNode with CuraSceneNode def __deepcopy__(self, memo): - copy = CuraSceneNode() + copy = CuraSceneNode(no_setting_override = True) # Setting override will be added later copy.setTransformation(self.getLocalTransformation()) copy.setMeshData(self._mesh_data) copy.setVisible(deepcopy(self._visible, memo)) From 51686943e6a3867a265fa7451b2420e23c26c18b Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 5 Mar 2018 17:15:09 +0100 Subject: [PATCH 104/446] CURA-4870 Create an extruder configuration model to store the extruder configuration. Connect the signals coming from the printer to correctly update the UI --- cura/PrinterOutput/ConfigurationModel.py | 11 +++-- .../ExtruderConfigurationModel.py | 42 +++++++++++++++++++ cura/PrinterOutput/ExtruderOutputModel.py | 13 +++--- cura/Settings/MachineManager.py | 17 ++++---- .../ConfigurationMenu/ConfigurationItem.qml | 7 ++++ .../ConfigurationListView.qml | 9 ++++ 6 files changed, 82 insertions(+), 17 deletions(-) create mode 100644 cura/PrinterOutput/ExtruderConfigurationModel.py diff --git a/cura/PrinterOutput/ConfigurationModel.py b/cura/PrinterOutput/ConfigurationModel.py index 5102dff239..633986a65c 100644 --- a/cura/PrinterOutput/ConfigurationModel.py +++ b/cura/PrinterOutput/ConfigurationModel.py @@ -2,6 +2,11 @@ # Cura is released under the terms of the LGPLv3 or higher. from PyQt5.QtCore import pyqtProperty, QObject, pyqtSignal +from typing import List + +MYPY = False +if MYPY: + from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationModel class ConfigurationModel(QObject): @@ -11,13 +16,13 @@ class ConfigurationModel(QObject): def __init__(self): super().__init__() self._printer_type = None - self._extruder_configurations = [] + self._extruder_configurations = [] # type: List[ExtruderConfigurationModel] self._buildplate_configuration = None def setPrinterType(self, printer_type): self._printer_type = printer_type - @pyqtProperty(str, fset = setPrinterType, constant = True) + @pyqtProperty(str, fset = setPrinterType, notify = configurationChanged) def printerType(self): return self._printer_type @@ -41,5 +46,5 @@ class ConfigurationModel(QObject): def __hash__(self): extruder_hash = hash(0) for configuration in self.extruderConfigurations: - extruder_hash ^= hash(frozenset(configuration.items())) + extruder_hash ^= configuration.__hash__() return hash(self.printerType) ^ extruder_hash ^ hash(self.buildplateConfiguration) \ No newline at end of file diff --git a/cura/PrinterOutput/ExtruderConfigurationModel.py b/cura/PrinterOutput/ExtruderConfigurationModel.py new file mode 100644 index 0000000000..4871dca3cc --- /dev/null +++ b/cura/PrinterOutput/ExtruderConfigurationModel.py @@ -0,0 +1,42 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from PyQt5.QtCore import pyqtProperty, QObject, pyqtSignal + + +class ExtruderConfigurationModel(QObject): + + extruderConfigurationChanged = pyqtSignal() + + def __init__(self): + super().__init__() + self._position = -1 + self._material = None + self._hotend_id = None + + def setPosition(self, position): + self._position = position + + @pyqtProperty(int, fset = setPosition, notify = extruderConfigurationChanged) + def position(self): + return self._position + + def setMaterial(self, material): + self._material = material + + @pyqtProperty(str, fset = setMaterial, notify = extruderConfigurationChanged) + def material(self): + return self._material + + def setHotendID(self, hotend_id): + self._hotend_id = hotend_id + + @pyqtProperty(str, fset = setHotendID, notify = extruderConfigurationChanged) + def hotendID(self): + return self._hotend_id + + def __eq__(self, other): + return hash(self) == hash(other) + + def __hash__(self): + return hash(self.position) ^ hash(self.material) ^ hash(self.hotendID) \ No newline at end of file diff --git a/cura/PrinterOutput/ExtruderOutputModel.py b/cura/PrinterOutput/ExtruderOutputModel.py index 3e415fb47a..d74b3a90d5 100644 --- a/cura/PrinterOutput/ExtruderOutputModel.py +++ b/cura/PrinterOutput/ExtruderOutputModel.py @@ -2,6 +2,7 @@ # Cura is released under the terms of the LGPLv3 or higher. from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, pyqtSlot +from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationModel from typing import Optional @@ -26,7 +27,7 @@ class ExtruderOutputModel(QObject): self._hotend_temperature = 0 self._hotend_id = "" self._active_material = None # type: Optional[MaterialOutputModel] - self._extruder_configuration = {} + self._extruder_configuration = ExtruderConfigurationModel() # Update the configuration every time the hotend or the active material change self.hotendIDChanged.connect(self._updateExtruderConfiguration) self.activeMaterialChanged.connect(self._updateExtruderConfiguration) @@ -74,15 +75,13 @@ class ExtruderOutputModel(QObject): self._hotend_id = id self.hotendIDChanged.emit() - @pyqtProperty("QVariantMap", notify = extruderConfigurationChanged) + @pyqtProperty(QObject, notify = extruderConfigurationChanged) def extruderConfiguration(self): return self._extruder_configuration def _updateExtruderConfiguration(self): - self._extruder_configuration = { - "position": self._position, - "material": self._active_material.type if self.activeMaterial is not None else None, - "hotendID": self._hotend_id - } + self._extruder_configuration.position = self._position + self._extruder_configuration.material = self._active_material.type if self.activeMaterial is not None else None + self._extruder_configuration.hotendID = self._hotend_id print("Recalculating extruder configuration:", self._extruder_configuration) self.extruderConfigurationChanged.emit() diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 0c0187ee98..7d5e00f0b5 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -30,6 +30,7 @@ from UM.Signal import postponeSignals, CompressTechnique from cura.QualityManager import QualityManager from cura.PrinterOutputDevice import PrinterOutputDevice from cura.PrinterOutput.ConfigurationModel import ConfigurationModel +from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationModel from cura.Settings.ExtruderManager import ExtruderManager from .CuraStackBuilder import CuraStackBuilder @@ -177,19 +178,21 @@ class MachineManager(QObject): return self._current_printer_configuration.printerType = self._global_container_stack.definition.getName() - extruder_configurations = [] + self._current_printer_configuration.extruderConfigurations = [] for extruder in self._global_container_stack.extruders.values(): - extruder_configurations.append({ - "position": int(extruder.getMetaDataEntry("position")), - "material": extruder.material.getName() if extruder.material != self._empty_material_container else None, - "hotendID": extruder.variant.getName() if extruder.variant != self._empty_variant_container else None - }) - self._current_printer_configuration.extruderConfigurations = extruder_configurations + extruder_configuration = ExtruderConfigurationModel() + extruder_configuration.position = int(extruder.getMetaDataEntry("position")) + extruder_configuration.material = extruder.material.getName() if extruder.material != self._empty_material_container else None + extruder_configuration.hotendID = extruder.variant.getName() if extruder.variant != self._empty_variant_container else None + self._current_printer_configuration.extruderConfigurations.append(extruder_configuration) + self._current_printer_configuration.buildplateConfiguration = self._global_container_stack.variant.getName() if self._global_container_stack.variant != self._empty_variant_container else None self.currentConfigurationChanged.emit() @pyqtSlot(QObject, result = bool) def matchesConfiguration(self, configuration: ConfigurationModel) -> bool: + # print("@@@@@@@@@@@@@@@@@@", configuration.extruderConfigurations) + # print("##################", self._current_printer_configuration.extruderConfigurations, configuration == self._current_printer_configuration) return self._current_printer_configuration == configuration @property diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml index 3bb14c3c26..b28c5b4812 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml @@ -108,4 +108,11 @@ Rectangle configurationItem.selected = Cura.MachineManager.matchesConfiguration(configuration) } } + + Connections { + target: configuration + onConfigurationChanged: { + configurationItem.selected = Cura.MachineManager.matchesConfiguration(configuration) + } + } } \ No newline at end of file diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml index f962dbaa9f..bc257c8a61 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -42,6 +42,15 @@ Column font: UM.Theme.getFont("default_bold") } + Connections { + target: outputDevice + onUniqueConfigurationsChanged: { + // FIXME For now the model should be removed and then created again, otherwise changes in the printer don't automatically update the UI + configurationList.model = null + configurationList.model = outputDevice.uniqueConfigurations + } + } + ListView { id: configurationList From 5a8f2040d3695a83000aa67ad1a6f038fcc95c02 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Mon, 5 Mar 2018 17:53:40 +0100 Subject: [PATCH 105/446] Add method to machine manager to get a machine stack by definition id --- cura/Settings/MachineManager.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index e357d778ca..d478321ffc 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -306,6 +306,14 @@ class MachineManager(QObject): self.__emitChangedSignals() + @staticmethod + def getMachine(definition_id: str) -> Optional["GlobalStack"]: + machines = ContainerRegistry.getInstance().findContainerStacks(type = "machine") + for machine in machines: + if machine.definition.getId() == definition_id: + return machine + return None + @pyqtSlot(str, str) def addMachine(self, name: str, definition_id: str) -> None: new_stack = CuraStackBuilder.createMachine(name, definition_id) From d9eb4406bfa3560e0f2042d506705968ccab1d55 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 5 Mar 2018 23:25:33 +0100 Subject: [PATCH 106/446] Speed up showing all settings --- resources/qml/Settings/SettingView.qml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 16b0691a56..73a76a028f 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -235,12 +235,13 @@ Item function updateDefinitionModel() { - if(findingSettings || base.showingAllSettings) + if(findingSettings || showingAllSettings) { expandedCategories = definitionsModel.expanded.slice(); - definitionsModel.expanded = ["*"]; + definitionsModel.expanded = [""]; // keep categories closed while to prevent render while making settings visible one by one definitionsModel.showAncestors = true; definitionsModel.showAll = true; + definitionsModel.expanded = ["*"]; } else { From 7a56c4f63180b1293d8f580b9f9775d7a6d60dfa Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 5 Mar 2018 23:50:42 +0100 Subject: [PATCH 107/446] Fix activating "All settings" menuitem --- resources/qml/Menus/SettingVisibilityPresetsMenu.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml index d9ffd630e1..17204d6b6c 100644 --- a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml +++ b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml @@ -65,7 +65,6 @@ Menu exclusiveGroup: group onTriggered: { - Cura.SettingVisibilityPresetsModel.setActivePreset("custom"); showAllSettings(); } } From 6c1aee2c471f7d01d5d055083462467c64e6c007 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 5 Mar 2018 23:55:23 +0100 Subject: [PATCH 108/446] Update copyright --- cura/Settings/SettingVisibilityPresetsModel.py | 2 +- resources/qml/Menus/SettingVisibilityPresetsMenu.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/Settings/SettingVisibilityPresetsModel.py b/cura/Settings/SettingVisibilityPresetsModel.py index 307cbc3602..9ec8875a39 100644 --- a/cura/Settings/SettingVisibilityPresetsModel.py +++ b/cura/Settings/SettingVisibilityPresetsModel.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import os diff --git a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml index 17204d6b6c..de9eac08cf 100644 --- a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml +++ b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Ultimaker B.V. +// Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.2 From d83eb383d93f313202dcec3cf104bcc02a66528b Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 6 Mar 2018 08:44:43 +0100 Subject: [PATCH 109/446] CURA-4870 Fix an error in the hash function that detects a matching when the extruders are inverted. Add pretty output to the configuration model. --- cura/PrinterOutput/ConfigurationModel.py | 14 +++++++++++--- cura/PrinterOutput/ExtruderConfigurationModel.py | 7 ++++++- cura/Settings/MachineManager.py | 5 +++-- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/cura/PrinterOutput/ConfigurationModel.py b/cura/PrinterOutput/ConfigurationModel.py index 633986a65c..8138543d7b 100644 --- a/cura/PrinterOutput/ConfigurationModel.py +++ b/cura/PrinterOutput/ConfigurationModel.py @@ -40,11 +40,19 @@ class ConfigurationModel(QObject): def buildplateConfiguration(self): return self._buildplate_configuration + def __str__(self): + info = "Printer type: " + self.printerType + "\n" + info += "Extruders: [\n" + for configuration in self.extruderConfigurations: + info += " " + str(configuration) + "\n" + info += "]" + return info + def __eq__(self, other): return hash(self) == hash(other) def __hash__(self): - extruder_hash = hash(0) + extruder_hash = hash(self.extruderConfigurations[0]) # Use the hash of the first extruder as a seed for configuration in self.extruderConfigurations: - extruder_hash ^= configuration.__hash__() - return hash(self.printerType) ^ extruder_hash ^ hash(self.buildplateConfiguration) \ No newline at end of file + extruder_hash ^= hash(configuration) + return hash(self._printer_type) ^ extruder_hash ^ hash(self._buildplate_configuration) \ No newline at end of file diff --git a/cura/PrinterOutput/ExtruderConfigurationModel.py b/cura/PrinterOutput/ExtruderConfigurationModel.py index 4871dca3cc..7aa8785ae9 100644 --- a/cura/PrinterOutput/ExtruderConfigurationModel.py +++ b/cura/PrinterOutput/ExtruderConfigurationModel.py @@ -35,8 +35,13 @@ class ExtruderConfigurationModel(QObject): def hotendID(self): return self._hotend_id + def __str__(self): + if self._material is None or self._hotend_id is None: + return "No information" + return "Position: " + str(self._position) + " - Material: " + self._material + " - HotendID: " + self._hotend_id + def __eq__(self, other): return hash(self) == hash(other) def __hash__(self): - return hash(self.position) ^ hash(self.material) ^ hash(self.hotendID) \ No newline at end of file + return hash(self._position) ^ hash(self._material) ^ hash(self._hotend_id) \ No newline at end of file diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 7d5e00f0b5..39962690bb 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -191,8 +191,9 @@ class MachineManager(QObject): @pyqtSlot(QObject, result = bool) def matchesConfiguration(self, configuration: ConfigurationModel) -> bool: - # print("@@@@@@@@@@@@@@@@@@", configuration.extruderConfigurations) - # print("##################", self._current_printer_configuration.extruderConfigurations, configuration == self._current_printer_configuration) + # print(configuration) + # print(self._current_printer_configuration) + # print("%%%%%%%%", configuration == self._current_printer_configuration) return self._current_printer_configuration == configuration @property From d02d845d1bc8645c9d26f003728690ff95f6b80b Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 6 Mar 2018 09:24:42 +0100 Subject: [PATCH 110/446] CURA-4870 Update the selected configuration in the UI when the configuration in the printer changes. Modify again the hash function. --- cura/PrinterOutput/ConfigurationModel.py | 8 +++++++- cura/PrinterOutputDevice.py | 1 + .../qml/Menus/ConfigurationMenu/ConfigurationItem.qml | 11 ++++------- .../Menus/ConfigurationMenu/ConfigurationListView.qml | 3 ++- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/cura/PrinterOutput/ConfigurationModel.py b/cura/PrinterOutput/ConfigurationModel.py index 8138543d7b..230a734797 100644 --- a/cura/PrinterOutput/ConfigurationModel.py +++ b/cura/PrinterOutput/ConfigurationModel.py @@ -52,7 +52,13 @@ class ConfigurationModel(QObject): return hash(self) == hash(other) def __hash__(self): - extruder_hash = hash(self.extruderConfigurations[0]) # Use the hash of the first extruder as a seed + extruder_hash = hash(0) + first_extruder = None for configuration in self.extruderConfigurations: extruder_hash ^= hash(configuration) + if configuration.position == 0: + first_extruder = configuration + if first_extruder: + extruder_hash &= hash(first_extruder) + return hash(self._printer_type) ^ extruder_hash ^ hash(self._buildplate_configuration) \ No newline at end of file diff --git a/cura/PrinterOutputDevice.py b/cura/PrinterOutputDevice.py index 875cc17fe8..d2916016e0 100644 --- a/cura/PrinterOutputDevice.py +++ b/cura/PrinterOutputDevice.py @@ -187,6 +187,7 @@ class PrinterOutputDevice(QObject, OutputDevice): def _updateUniqueConfigurations(self): self._unique_configurations = list(set([printer.printerConfiguration for printer in self._printers])) + self._unique_configurations.sort(key = lambda k: k.printerType) self.uniqueConfigurationsChanged.emit() def _onPrintersChanged(self): diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml index b28c5b4812..ae97a82207 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml @@ -13,7 +13,7 @@ Rectangle property var configuration: null property var selected: false - signal configurationSelected() + signal activateConfiguration() height: childrenRect.height border.width: UM.Theme.getSize("default_lining").width @@ -96,7 +96,7 @@ Rectangle { id: mouse anchors.fill: parent - onClicked: configurationSelected() + onClicked: activateConfiguration() hoverEnabled: true onEntered: parent.border.color = UM.Theme.getColor("primary_hover") onExited: parent.border.color = "black" @@ -109,10 +109,7 @@ Rectangle } } - Connections { - target: configuration - onConfigurationChanged: { - configurationItem.selected = Cura.MachineManager.matchesConfiguration(configuration) - } + Component.onCompleted: { + configurationItem.selected = Cura.MachineManager.matchesConfiguration(configuration) } } \ No newline at end of file diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml index bc257c8a61..2effa5177f 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -46,6 +46,7 @@ Column target: outputDevice onUniqueConfigurationsChanged: { // FIXME For now the model should be removed and then created again, otherwise changes in the printer don't automatically update the UI + print("Update unique configurations") configurationList.model = null configurationList.model = outputDevice.uniqueConfigurations } @@ -63,7 +64,7 @@ Column { width: parent.width configuration: modelData - onConfigurationSelected: + onActivateConfiguration: { print("SELECCIONANDO CONFIGURACION", JSON.stringify(configuration)) } From 3e8f29d380764766383cd87c006f01c0b27c1523 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 6 Mar 2018 09:37:21 +0100 Subject: [PATCH 111/446] Allow floating point values for moving print head The X, Y, Z coordinates and speed don't necessarily have to be full millimetres or millimetres per minute. Fixes #3271. --- cura/PrinterOutput/PrinterOutputModel.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index 8234989519..1c23d0e18e 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -103,32 +103,32 @@ class PrinterOutputModel(QObject): self._head_position = Vector(x, y, z) self.headPositionChanged.emit() - @pyqtProperty("long", "long", "long") - @pyqtProperty("long", "long", "long", "long") + @pyqtProperty(float, float, float) + @pyqtProperty(float, float, float, float) def setHeadPosition(self, x, y, z, speed = 3000): self.updateHeadPosition(x, y, z) self._controller.setHeadPosition(self, x, y, z, speed) - @pyqtProperty("long") - @pyqtProperty("long", "long") + @pyqtProperty(float) + @pyqtProperty(float, float) def setHeadX(self, x, speed = 3000): self.updateHeadPosition(x, self._head_position.y, self._head_position.z) self._controller.setHeadPosition(self, x, self._head_position.y, self._head_position.z, speed) - @pyqtProperty("long") - @pyqtProperty("long", "long") + @pyqtProperty(float) + @pyqtProperty(float, float) def setHeadY(self, y, speed = 3000): self.updateHeadPosition(self._head_position.x, y, self._head_position.z) self._controller.setHeadPosition(self, self._head_position.x, y, self._head_position.z, speed) - @pyqtProperty("long") - @pyqtProperty("long", "long") + @pyqtProperty(float) + @pyqtProperty(float, float) def setHeadZ(self, z, speed = 3000): self.updateHeadPosition(self._head_position.x, self._head_position.y, z) self._controller.setHeadPosition(self, self._head_position.x, self._head_position.y, z, speed) - @pyqtSlot("long", "long", "long") - @pyqtSlot("long", "long", "long", "long") + @pyqtSlot(float, float, float) + @pyqtSlot(float, float, float, float) def moveHead(self, x = 0, y = 0, z = 0, speed = 3000): self._controller.moveHead(self, x, y, z, speed) From 00a173b1bf62a1c5c23033be90c08c4c4969bb89 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 6 Mar 2018 09:45:32 +0100 Subject: [PATCH 112/446] CURA-4400 when enabling / disabling extruder, remove user changes that are no longer enabled --- cura/Settings/MachineManager.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 52887c1899..13a431824b 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -701,16 +701,22 @@ class MachineManager(QObject): # reset all extruder number settings whose value is no longer valid for setting_instance in self._global_container_stack.userChanges.findInstances(): setting_key = setting_instance.definition.key + enabled = self._global_container_stack.getProperty(setting_key, "enabled") + if not enabled: + self._global_container_stack.userChanges.removeInstance(setting_key) + Logger.log("d", "Reset setting [%s] because the setting is no longer enabled", setting_key) + continue + if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"): continue old_value = self._global_container_stack.userChanges.getProperty(setting_key, "value") if int(old_value) >= extruder_count: self._global_container_stack.userChanges.removeInstance(setting_key) - Logger.log("d", "Reset [%s] because its old value [%s] is no longer valid", setting_key, old_value) + Logger.log("d", "Reset setting [%s] because its old value [%s] is no longer valid", setting_key, old_value) if not self._global_container_stack.extruders[str(old_value)].isEnabled: self._global_container_stack.userChanges.removeInstance(setting_key) - Logger.log("d", "Reset [%s] because its old value [%s] is no longer valid (2)", setting_key, old_value) + Logger.log("d", "Reset setting [%s] because its old value [%s] is no longer valid (2)", setting_key, old_value) ## Set the amount of extruders on the active machine (global stack) # \param extruder_count int the number of extruders to set @@ -804,8 +810,7 @@ class MachineManager(QObject): extruder.setEnabled(enabled) self.updateDefaultExtruder() self.updateNumberExtrudersEnabled() - if enabled == False: - self.correctExtruderSettings() + self.correctExtruderSettings() self.extruderChanged.emit() # update items in SettingExtruder ExtruderManager.getInstance().extrudersChanged.emit(self._global_container_stack.getId()) From 731a1092c521a363c6f0fbc3b53ea21848af5ccf Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 6 Mar 2018 10:18:54 +0100 Subject: [PATCH 113/446] CURA-4870 Add callback function to apply remote configuration --- cura/Settings/MachineManager.py | 5 +++++ .../qml/Menus/ConfigurationMenu/ConfigurationListView.qml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 39962690bb..c2b2e2b0dd 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -196,6 +196,11 @@ class MachineManager(QObject): # print("%%%%%%%%", configuration == self._current_printer_configuration) return self._current_printer_configuration == configuration + @pyqtSlot(QObject) + def applyRemoteConfiguration(self, configuration: ConfigurationModel): + print("Applying remote configuration", configuration) + + @property def newVariant(self): return self._new_variant_container diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml index 2effa5177f..0645567c86 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -66,7 +66,7 @@ Column configuration: modelData onActivateConfiguration: { - print("SELECCIONANDO CONFIGURACION", JSON.stringify(configuration)) + Cura.MachineManager.applyRemoteConfiguration(configuration) } } } From d11d850f7cedf962a6209894f929578bca9ca6a7 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 6 Mar 2018 10:42:24 +0100 Subject: [PATCH 114/446] CURA-4870 Add spacing to the list of configurations --- resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml index 0645567c86..00de9d0003 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -57,6 +57,7 @@ Column id: configurationList anchors.top: printerTypeHeader.bottom anchors.topMargin: UM.Theme.getSize("default_margin").height + spacing: Math.round(UM.Theme.getSize("default_margin").height / 2) width: container.width height: childrenRect.height model: outputDevice.uniqueConfigurations From 8d5a643c9b0830e381c05b7e97c3483d48b369e3 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Tue, 6 Mar 2018 10:51:39 +0100 Subject: [PATCH 115/446] Removed `print()` statement --- plugins/PerObjectSettingsTool/PerObjectSettingsTool.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py index b671db48fb..11e26a033a 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py @@ -181,7 +181,6 @@ class PerObjectSettingsTool(Tool): def _checkStackForErrors(self, stack): - print("checking for errors") if stack is None: return False From 27b3a71a98c7c01db88b2b8e38bdbe0770a8c112 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 6 Mar 2018 11:26:14 +0100 Subject: [PATCH 116/446] Sort branded materials for dropdown menu CURA-4606 --- cura/Machines/Models/BrandMaterialsModel.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cura/Machines/Models/BrandMaterialsModel.py b/cura/Machines/Models/BrandMaterialsModel.py index 6628d924f1..2ef1425986 100644 --- a/cura/Machines/Models/BrandMaterialsModel.py +++ b/cura/Machines/Models/BrandMaterialsModel.py @@ -120,12 +120,19 @@ class BrandMaterialsModel(ListModel): material_type_item = {"name": material_type, "colors": BaseMaterialsModel(self)} material_type_item["colors"].clear() + + # Sort materials by name + material_list = sorted(material_list, key = lambda x: x["name"]) material_type_item["colors"].setItems(material_list) material_type_item_list.append(material_type_item) + # Sort material type by name + material_type_item_list = sorted(material_type_item_list, key = lambda x: x["name"]) brand_item["materials"].setItems(material_type_item_list) brand_item_list.append(brand_item) + # Sort brand by name + brand_item_list = sorted(brand_item_list, key = lambda x: x["name"]) self.setItems(brand_item_list) From 1ed5a00198e3e3b28de84c60e149427ef2d69004 Mon Sep 17 00:00:00 2001 From: Mark Burton Date: Tue, 6 Mar 2018 10:47:28 +0000 Subject: [PATCH 117/446] Added skin densities and layer 3 settings + tweaked various defaults. --- resources/definitions/fdmprinter.def.json | 149 +++++++++++++++++----- 1 file changed, 114 insertions(+), 35 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 396c45a59e..a3e50c2b1c 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6249,20 +6249,6 @@ "enabled": "bridge_settings_enabled", "settable_per_mesh": false }, - "bridge_skin_speed": - { - "label": "Bridge Skin Speed", - "description": "The speed at which bridge skin regions are printed.", - "unit": "mm/s", - "type": "float", - "minimum_value": "cool_min_speed", - "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)", - "maximum_value_warning": "300", - "default_value": 15, - "value": "max(cool_min_speed, speed_topbottom / 2)", - "enabled": "bridge_settings_enabled", - "settable_per_mesh": true - }, "bridge_wall_speed": { "label": "Bridge Wall Speed", @@ -6277,19 +6263,6 @@ "enabled": "bridge_settings_enabled", "settable_per_mesh": true }, - "bridge_skin_material_flow": - { - "label": "Bridge Skin Flow", - "description": "When printing bridge skin regions, the amount of material extruded is multiplied by this value.", - "unit": "%", - "default_value": 50, - "type": "float", - "minimum_value": "5", - "minimum_value_warning": "50", - "maximum_value_warning": "150", - "enabled": "bridge_settings_enabled", - "settable_per_mesh": true - }, "bridge_wall_material_flow": { "label": "Bridge Wall Flow", @@ -6303,6 +6276,46 @@ "enabled": "bridge_settings_enabled", "settable_per_mesh": true }, + "bridge_skin_speed": + { + "label": "Bridge Skin Speed", + "description": "The speed at which bridge skin regions are printed.", + "unit": "mm/s", + "type": "float", + "minimum_value": "cool_min_speed", + "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)", + "maximum_value_warning": "300", + "default_value": 15, + "value": "max(cool_min_speed, speed_topbottom / 2)", + "enabled": "bridge_settings_enabled", + "settable_per_mesh": true + }, + "bridge_skin_material_flow": + { + "label": "Bridge Skin Flow", + "description": "When printing bridge skin regions, the amount of material extruded is multiplied by this value.", + "unit": "%", + "default_value": 60, + "type": "float", + "minimum_value": "5", + "minimum_value_warning": "50", + "maximum_value_warning": "150", + "enabled": "bridge_settings_enabled", + "settable_per_mesh": true + }, + "bridge_skin_density": + { + "label": "Bridge Skin Density", + "description": "The density of the bridge skin layer. Values less than 100 will increase the gaps between the skin lines.", + "unit": "%", + "default_value": 100, + "type": "float", + "minimum_value": "5", + "maximum_value": "100", + "minimum_value_warning": "20", + "enabled": "bridge_settings_enabled", + "settable_per_mesh": true + }, "bridge_fan_speed": { "label": "Bridge Fan Speed", @@ -6315,10 +6328,10 @@ "enabled": "bridge_settings_enabled", "settable_per_mesh": true }, - "bridge_process_second_skin": + "bridge_enable_more_layers": { - "label": "Enable Second Bridge Layer", - "description": "If enabled, the skin regions on the second layer above the air are printed using bridge second skin settings. Otherwise, those skin regions are printed using the normal skin settings.", + "label": "Bridge Has Multiple Layers", + "description": "If enabled, the second and third layers above the air are printed using the following settings. Otherwise, those layers are printed using the normal settings.", "type": "bool", "default_value": true, "enabled": "bridge_settings_enabled", @@ -6333,9 +6346,9 @@ "minimum_value": "cool_min_speed", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)", "maximum_value_warning": "300", - "default_value": 15, + "default_value": 25, "value": "bridge_skin_speed", - "enabled": "bridge_settings_enabled and bridge_process_second_skin", + "enabled": "bridge_settings_enabled and bridge_enable_more_layers", "settable_per_mesh": true }, "bridge_skin_material_flow_2": @@ -6343,13 +6356,26 @@ "label": "Bridge Second Skin Flow", "description": "When printing the second bridge skin layer, the amount of material extruded is multiplied by this value.", "unit": "%", - "default_value": 125, + "default_value": 100, "type": "float", "minimum_value": "5", "maximum_value": "500", "minimum_value_warning": "50", "maximum_value_warning": "150", - "enabled": "bridge_settings_enabled and bridge_process_second_skin", + "enabled": "bridge_settings_enabled and bridge_enable_more_layers", + "settable_per_mesh": true + }, + "bridge_skin_density_2": + { + "label": "Bridge Second Skin Density", + "description": "The density of the second bridge skin layer. Values less than 100 will increase the gaps between the skin lines.", + "unit": "%", + "default_value": 75, + "type": "float", + "minimum_value": "5", + "maximum_value": "100", + "minimum_value_warning": "20", + "enabled": "bridge_settings_enabled and bridge_enable_more_layers", "settable_per_mesh": true }, "bridge_fan_speed_2": @@ -6361,7 +6387,60 @@ "maximum_value": "100", "default_value": 0, "type": "float", - "enabled": "bridge_settings_enabled and bridge_process_second_skin", + "enabled": "bridge_settings_enabled and bridge_enable_more_layers", + "settable_per_mesh": true + }, + "bridge_skin_speed_3": + { + "label": "Bridge Third Skin Speed", + "description": "Print speed to use when printing the third bridge skin layer.", + "unit": "mm/s", + "type": "float", + "minimum_value": "cool_min_speed", + "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)", + "maximum_value_warning": "300", + "default_value": 15, + "value": "bridge_skin_speed", + "enabled": "bridge_settings_enabled and bridge_enable_more_layers", + "settable_per_mesh": true + }, + "bridge_skin_material_flow_3": + { + "label": "Bridge Third Skin Flow", + "description": "When printing the third bridge skin layer, the amount of material extruded is multiplied by this value.", + "unit": "%", + "default_value": 110, + "type": "float", + "minimum_value": "5", + "maximum_value": "500", + "minimum_value_warning": "50", + "maximum_value_warning": "150", + "enabled": "bridge_settings_enabled and bridge_enable_more_layers", + "settable_per_mesh": true + }, + "bridge_skin_density_3": + { + "label": "Bridge Third Skin Density", + "description": "The density of the third bridge skin layer. Values less than 100 will increase the gaps between the skin lines.", + "unit": "%", + "default_value": 80, + "type": "float", + "minimum_value": "5", + "maximum_value": "100", + "minimum_value_warning": "20", + "enabled": "bridge_settings_enabled and bridge_enable_more_layers", + "settable_per_mesh": true + }, + "bridge_fan_speed_3": + { + "label": "Bridge Third Skin Fan Speed", + "description": "Percentage fan speed to use when printing the third bridge skin layer.", + "unit": "%", + "minimum_value": "0", + "maximum_value": "100", + "default_value": 0, + "type": "float", + "enabled": "bridge_settings_enabled and bridge_enable_more_layers", "settable_per_mesh": true } } From 8ebd77822469aaf54b1d5b333a7c6ee0ca77ca96 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 6 Mar 2018 11:44:42 +0100 Subject: [PATCH 118/446] CURA-4400 force update all settings if something changed with the extruder --- cura/Settings/MachineManager.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 13a431824b..7e75067ce6 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -772,6 +772,7 @@ class MachineManager(QObject): # Signal that the global stack has changed Application.getInstance().globalContainerStackChanged.emit() + self.forceUpdateAllSettings() @pyqtSlot(int, result = QObject) def getExtruder(self, position: int): @@ -804,6 +805,12 @@ class MachineManager(QObject): def defaultExtruderPosition(self): return self._default_extruder_position + ## This will fire the propertiesChanged for all settings so they will be updated in the front-end + def forceUpdateAllSettings(self): + property_names = ["value", "resolve"] + for setting_key in self._global_container_stack.getAllKeys(): + self._global_container_stack.propertiesChanged.emit(setting_key, property_names) + @pyqtSlot(int, bool) def setExtruderEnabled(self, position: int, enabled) -> None: extruder = self.getExtruder(position) @@ -814,6 +821,8 @@ class MachineManager(QObject): self.extruderChanged.emit() # update items in SettingExtruder ExtruderManager.getInstance().extrudersChanged.emit(self._global_container_stack.getId()) + # Make sure the front end reflects changes + self.forceUpdateAllSettings() def _onMachineNameChanged(self): self.globalContainerChanged.emit() From ff0d694e72b41dd860d1ddfdff5b004c68ba67da Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 6 Mar 2018 11:55:20 +0100 Subject: [PATCH 119/446] Select the activated material when material management page shows up CURA-4606 --- resources/qml/Preferences/MaterialsPage.qml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml index 4a6d07df81..553cfe0423 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/MaterialsPage.qml @@ -52,6 +52,24 @@ Item return base.currentItem.root_material_id == root_material_id; } + Component.onCompleted: + { + // Select the activated material when this page shows up + const extruder_position = Cura.ExtruderManager.activeExtruderIndex; + const active_root_material_id = Cura.MachineManager.currentRootMaterialId[extruder_position]; + var itemIndex = -1; + for (var i = 0; i < materialsModel.rowCount(); ++i) + { + var item = materialsModel.getItem(i); + if (item.root_material_id == active_root_material_id) + { + itemIndex = i; + break; + } + } + materialListView.currentIndex = itemIndex; + } + Row // Button Row { id: buttonRow From 1f883f331216c4a39ee2611775d98c39a4562ca8 Mon Sep 17 00:00:00 2001 From: Aleksei S Date: Tue, 6 Mar 2018 12:39:54 +0100 Subject: [PATCH 120/446] Remove reply hanlder to prevent crash after canceling a printing job CURA-4960 --- plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py index c0d538bb78..73acc02cae 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py @@ -194,6 +194,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): # the "reply" should be disconnected if self._latest_reply_handler: self._latest_reply_handler.disconnect() + self._latest_reply_handler = None @pyqtSlot() From f8c129f4c79b563f9355ffd868e08235dc50486b Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Tue, 6 Mar 2018 12:46:48 +0100 Subject: [PATCH 121/446] Update ISSUE_TEMPLATE.md Allow for uploading curaproject files in github directly --- .github/ISSUE_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 97c849144d..af5b6b6d3c 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -6,7 +6,7 @@ Before filing, PLEASE check if the issue already exists (either open or closed) Also, please note the application version in the title of the issue. For example: "[3.2.1] Cannot connect to 3rd-party printer". Please do not write thigns like "Request:" or "[BUG]" in the title; this is what labels are for. It is also helpful to attach a project (.3mf or .curaproject) file and Cura log file so we can debug issues quicker. -Information about how to find the log file can be found at https://github.com/Ultimaker/Cura/wiki/Cura-Preferences-and-Settings-Locations. To upload a project, we recommend http://wetransfer.com, but other file hosts like Google Drive or Dropbox work well too. +Information about how to find the log file can be found at https://github.com/Ultimaker/Cura/wiki/Cura-Preferences-and-Settings-Locations. To upload a project, try changing the extension to e.g. .curaproject.3mf.zip so that github accepts uploading the file. Otherwise we recommend http://wetransfer.com, but other file hosts like Google Drive or Dropbox work well too. Thank you for using Cura! --> From 5950d147ac475abc8edab89da3c5bd8daf90fd39 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Tue, 6 Mar 2018 13:20:15 +0100 Subject: [PATCH 122/446] Update ISSUE_TEMPLATE.md More focus on printer and attaching project file --- .github/ISSUE_TEMPLATE.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index af5b6b6d3c..c69cf91433 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -26,6 +26,9 @@ Thank you for using Cura! **Display Driver** +**Printer** + + **Steps to Reproduce** From 31b737468944c6645edfd9779a7562f4a2242259 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 6 Mar 2018 13:39:35 +0100 Subject: [PATCH 123/446] Fix material settings saving upon dialog close CURA-4606 Force to trigger a lose focus on all editing fields so their onEditingFinished callback will get triggered. --- resources/qml/Preferences/MaterialView.qml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/resources/qml/Preferences/MaterialView.qml b/resources/qml/Preferences/MaterialView.qml index c987880305..d2f653e650 100644 --- a/resources/qml/Preferences/MaterialView.qml +++ b/resources/qml/Preferences/MaterialView.qml @@ -47,6 +47,19 @@ TabView return Math.round(diameter); } + // This trick makes sure to make all fields lose focus so their onEditingFinished will be triggered + // and modified values will be saved. This can happen when a user changes a value and then closes the + // dialog directly. + // + // Please note that somehow this callback is ONLY triggered when visible is false. + onVisibleChanged: + { + if (!visible) + { + base.focus = false; + } + } + Tab { title: catalog.i18nc("@title", "Information") From cb7677347d73a5d22f38f90c910faae731ffca13 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 6 Mar 2018 15:26:54 +0100 Subject: [PATCH 124/446] Fix material model update upon variant change CURA-5052 --- cura/Machines/Models/BaseMaterialsModel.py | 26 +++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/cura/Machines/Models/BaseMaterialsModel.py b/cura/Machines/Models/BaseMaterialsModel.py index de0c68d60a..5c09a4f060 100644 --- a/cura/Machines/Models/BaseMaterialsModel.py +++ b/cura/Machines/Models/BaseMaterialsModel.py @@ -3,6 +3,7 @@ from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty +from UM.Application import Application from UM.Qt.ListModel import ListModel @@ -25,6 +26,8 @@ class BaseMaterialsModel(ListModel): def __init__(self, parent = None): super().__init__(parent) + self._application = Application.getInstance() + self._machine_manager = self._application.getMachineManager() self.addRoleName(self.RootMaterialIdRole, "root_material_id") self.addRoleName(self.IdRole, "id") @@ -35,12 +38,33 @@ class BaseMaterialsModel(ListModel): self.addRoleName(self.ContainerNodeRole, "container_node") self._extruder_position = 0 + self._extruder_stack = None + + self._machine_manager.globalContainerChanged.connect(self._updateExtruderStack) + + def _updateExtruderStack(self): + global_stack = self._machine_manager.activeMachine + if global_stack is None: + return + + if self._extruder_stack is not None: + self._extruder_stack.pyqtContainersChanged.disconnect(self._update) + self._extruder_stack = global_stack.extruders.get(str(self._extruder_position)) + if self._extruder_stack is not None: + self._extruder_stack.pyqtContainersChanged.connect(self._update) def setExtruderPosition(self, position: int): if self._extruder_position != position: self._extruder_position = position + self._updateExtruderStack() self.extruderPositionChanged.emit() @pyqtProperty(int, fset = setExtruderPosition, notify = extruderPositionChanged) def extruderPosition(self) -> int: - return self._extruder_positoin + return self._extruder_position + + # + # This is an abstract method that needs to be implemented by + # + def _update(self): + pass From fb798ab7e569436ac4da5494a2b6a780efcb710f Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 6 Mar 2018 15:30:37 +0100 Subject: [PATCH 125/446] Small refactor in MachineManager and add more loggings CURA-4606 - Added more info loggings - Changed some variant names - Use some shortcut variables instead of getInstance()s --- cura/Settings/MachineManager.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index e357d778ca..8cc25b0ccc 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -917,30 +917,38 @@ class MachineManager(QObject): ## Update current quality type and machine after setting material def _updateQualityWithMaterial(self): - current_quality = None + Logger.log("i", "Updating quality/quality_changes due to material change") + current_quality_type = None if self._current_quality_group: - current_quality = self._current_quality_group.quality_type - quality_manager = Application.getInstance()._quality_manager - candidate_quality_groups = quality_manager.getQualityGroups(self._global_container_stack) + current_quality_type = self._current_quality_group.quality_type + candidate_quality_groups = self._quality_manager.getQualityGroups(self._global_container_stack) available_quality_types = {qt for qt, g in candidate_quality_groups.items() if g.is_available} + Logger.log("d", "Current quality type = [%s]", current_quality_type) if not self.activeMaterialsCompatible(): + Logger.log("i", "Active materials are not compatible, setting all qualities to empty (Not Supported).") self._setEmptyQuality() return if not available_quality_types: + Logger.log("i", "No available quality types found, setting all qualities to empty (Not Supported).") self._setEmptyQuality() return - if current_quality in available_quality_types: - self._setQualityGroup(candidate_quality_groups[current_quality], empty_quality_changes = False) + if current_quality_type in available_quality_types: + Logger.log("i", "Current available quality type [%s] is available, applying changes.", current_quality_type) + self._setQualityGroup(candidate_quality_groups[current_quality_type], empty_quality_changes = False) return + # The current quality type is not available so we use the preferred quality type if it's available, + # otherwise use one of the available quality types. quality_type = sorted(list(available_quality_types))[0] preferred_quality_type = self._global_container_stack.getMetaDataEntry("preferred_quality_type") if preferred_quality_type in available_quality_types: quality_type = preferred_quality_type + Logger.log("i", "The current quality type [%s] is not available, switching to [%s] instead", + current_quality_type, quality_type) self._setQualityGroup(candidate_quality_groups[quality_type], empty_quality_changes = True) def _updateMaterialWithVariant(self, position: Optional[str]): @@ -955,9 +963,8 @@ class MachineManager(QObject): current_material_base_name = extruder.material.getMetaDataEntry("base_file") current_variant_name = extruder.variant.getMetaDataEntry("name") - material_manager = Application.getInstance()._material_manager material_diameter = self._global_container_stack.getProperty("material_diameter", "value") - candidate_materials = material_manager.getAvailableMaterials( + candidate_materials = self._material_manager.getAvailableMaterials( self._global_container_stack.definition.getId(), current_variant_name, material_diameter) @@ -1004,7 +1011,7 @@ class MachineManager(QObject): # See if we need to show the Discard or Keep changes screen if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1: - Application.getInstance().discardOrKeepProfileChanges() + self._application.discardOrKeepProfileChanges() @pyqtProperty(QObject, fset = setQualityGroup, notify = activeQualityGroupChanged) def activeQualityGroup(self): @@ -1018,7 +1025,7 @@ class MachineManager(QObject): # See if we need to show the Discard or Keep changes screen if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1: - Application.getInstance().discardOrKeepProfileChanges() + self._application.discardOrKeepProfileChanges() @pyqtProperty(QObject, fset = setQualityChangesGroup, notify = activeQualityChangesGroupChanged) def activeQualityChangesGroup(self): From 6bb42da0566b2d687053152288e2d9234cbf79f1 Mon Sep 17 00:00:00 2001 From: Aleksei S Date: Tue, 6 Mar 2018 15:40:26 +0100 Subject: [PATCH 126/446] Removed related commits to Settins per Object validation and added short validation in StartScliceJob CURA-4972 --- cura/ObjectsModel.py | 10 --- cura/Settings/SettingOverrideDecorator.py | 23 +----- plugins/CuraEngineBackend/StartSliceJob.py | 6 +- .../PerObjectSettingsTool/PerObjectItem.qml | 15 +--- .../PerObjectSettingsPanel.qml | 5 +- .../PerObjectSettingsTool.py | 70 ------------------- 6 files changed, 6 insertions(+), 123 deletions(-) diff --git a/cura/ObjectsModel.py b/cura/ObjectsModel.py index d7077d3d85..f02e8b4db5 100644 --- a/cura/ObjectsModel.py +++ b/cura/ObjectsModel.py @@ -19,8 +19,6 @@ class ObjectsModel(ListModel): self._build_plate_number = -1 - self._stacks_have_errors = None # type:Optional[bool] - def setActiveBuildPlate(self, nr): self._build_plate_number = nr self._update() @@ -69,11 +67,3 @@ class ObjectsModel(ListModel): @staticmethod def createObjectsModel(): return ObjectsModel() - - ## Check if none of the model's stacks contain error states - # The setting applied for the settings per model - def stacksHaveErrors(self) -> bool: - return bool(self._stacks_have_errors) - - def setStacksHaveErrors(self, value): - self._stacks_have_errors = value \ No newline at end of file diff --git a/cura/Settings/SettingOverrideDecorator.py b/cura/Settings/SettingOverrideDecorator.py index 6e98f014dc..24d94e4955 100644 --- a/cura/Settings/SettingOverrideDecorator.py +++ b/cura/Settings/SettingOverrideDecorator.py @@ -9,8 +9,7 @@ from UM.Signal import Signal, signalemitter from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Logger import Logger -from UM.Settings.Validator import ValidatorState -from PyQt5.QtCore import QTimer + from UM.Application import Application from cura.Settings.PerObjectContainerStack import PerObjectContainerStack @@ -40,10 +39,6 @@ class SettingOverrideDecorator(SceneNodeDecorator): self._extruder_stack = ExtruderManager.getInstance().getExtruderStack(0).getId() self._is_non_printing_mesh = False - self._error_check_timer = QTimer() - self._error_check_timer.setInterval(250) - self._error_check_timer.setSingleShot(True) - self._error_check_timer.timeout.connect(self._checkStackForErrors) self._stack.propertyChanged.connect(self._onSettingChanged) @@ -99,21 +94,9 @@ class SettingOverrideDecorator(SceneNodeDecorator): # Trigger slice/need slicing if the value has changed. if property_name == "value": self._is_non_printing_mesh = any(bool(self._stack.getProperty(setting, "value")) for setting in self._non_printing_mesh_settings) - if not self._is_non_printing_mesh: - # self._error_check_timer.start() - self._checkStackForErrors() - Application.getInstance().getBackend().needsSlicing() - Application.getInstance().getBackend().tickle() - def _checkStackForErrors(self): - hasErrors = False; - for key in self._stack.getAllKeys(): - validation_state = self._stack.getProperty(key, "validationState") - if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError): - Logger.log("w", "Setting Per Object %s is not valid.", key) - hasErrors = True - break - Application.getInstance().getObjectsModel().setStacksHaveErrors(hasErrors) + Application.getInstance().getBackend().needsSlicing() + Application.getInstance().getBackend().tickle() ## Makes sure that the stack upon which the container stack is placed is # kept up to date. diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 8b7205f8b2..afbc816cc5 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -136,14 +136,10 @@ class StartSliceJob(Job): self.setResult(StartJobResult.MaterialIncompatible) return - # Validate settings per selectable model - if Application.getInstance().getObjectsModel().stacksHaveErrors(): - self.setResult(StartJobResult.ObjectSettingError) - return # Don't slice if there is a per object setting with an error value. for node in DepthFirstIterator(self._scene.getRoot()): - if node.isSelectable(): + if type(node) is not CuraSceneNode or not node.isSelectable(): continue if self._checkStackForErrors(node.callDecoration("getStack")): diff --git a/plugins/PerObjectSettingsTool/PerObjectItem.qml b/plugins/PerObjectSettingsTool/PerObjectItem.qml index 1317c00b19..559ad2bf81 100644 --- a/plugins/PerObjectSettingsTool/PerObjectItem.qml +++ b/plugins/PerObjectSettingsTool/PerObjectItem.qml @@ -25,20 +25,7 @@ UM.TooltipArea onClicked: { - // Important first set visible and then subscribe - // otherwise the setting is not yet in list - // For unsubscribe is important first remove the subscription and then - // set as invisible - if(checked) - { - addedSettingsModel.setVisible(model.key, checked); - UM.ActiveTool.triggerActionWithData("subscribeForSettingValidation", model.key) - } - else - { - UM.ActiveTool.triggerActionWithData("unsubscribeForSettingValidation", model.key) - addedSettingsModel.setVisible(model.key, checked); - } + addedSettingsModel.setVisible(model.key, checked); UM.ActiveTool.forceUpdate(); } } diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index e72e1224df..03a2ce1bf4 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -240,10 +240,7 @@ Item { width: Math.round(UM.Theme.getSize("setting").height / 2) height: UM.Theme.getSize("setting").height - onClicked: { - addedSettingsModel.setVisible(model.key, false) - UM.ActiveTool.triggerActionWithData("unsubscribeForSettingValidation", model.key) - } + onClicked: addedSettingsModel.setVisible(model.key, false) style: ButtonStyle { diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py index 11e26a033a..d2db5ff420 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py @@ -10,10 +10,7 @@ from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator from cura.Settings.ExtruderManager import ExtruderManager from UM.Settings.SettingInstance import SettingInstance from UM.Event import Event -from UM.Settings.Validator import ValidatorState -from UM.Logger import Logger -from PyQt5.QtCore import QTimer ## This tool allows the user to add & change settings per node in the scene. # The settings per object are kept in a ContainerStack, which is linked to a node by decorator. @@ -37,12 +34,6 @@ class PerObjectSettingsTool(Tool): self._onGlobalContainerChanged() Selection.selectionChanged.connect(self._updateEnabled) - self._scene = Application.getInstance().getController().getScene() - - self._error_check_timer = QTimer() - self._error_check_timer.setInterval(250) - self._error_check_timer.setSingleShot(True) - self._error_check_timer.timeout.connect(self._updateStacksHaveErrors) def event(self, event): super().event(event) @@ -151,64 +142,3 @@ class PerObjectSettingsTool(Tool): else: self._single_model_selected = True Application.getInstance().getController().toolEnabledChanged.emit(self._plugin_id, self._advanced_mode and self._single_model_selected) - - - def _onPropertyChanged(self, key: str, property_name: str) -> None: - if property_name == "validationState": - # self._error_check_timer.start() - return - - def _updateStacksHaveErrors(self) -> None: - return - # self._checkStacksHaveErrors() - - - def _checkStacksHaveErrors(self): - - for node in DepthFirstIterator(self._scene.getRoot()): - - # valdiate only objects which can be selected because the settings per object - # can be applied only for them - if not node.isSelectable(): - continue - - hasErrors = self._checkStackForErrors(node.callDecoration("getStack")) - Application.getInstance().getObjectsModel().setStacksHaveErrors(hasErrors) - - #If any of models has an error then no reason check next objects on the build plate - if hasErrors: - break - - - def _checkStackForErrors(self, stack): - if stack is None: - return False - - for key in stack.getAllKeys(): - validation_state = stack.getProperty(key, "validationState") - if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError): - Logger.log("w", "Setting Per Object %s is not valid.", key) - return True - return False - - def subscribeForSettingValidation(self, setting_name): - selected_object = Selection.getSelectedObject(0) - stack = selected_object.callDecoration("getStack") # Don't try to get the active extruder since it may be None anyway. - if not stack: - return "" - - settings = stack.getTop() - setting_instance = settings.getInstance(setting_name) - if setting_instance: - setting_instance.propertyChanged.connect(self._onPropertyChanged) - - def unsubscribeForSettingValidation(self, setting_name): - selected_object = Selection.getSelectedObject(0) - stack = selected_object.callDecoration("getStack") # Don't try to get the active extruder since it may be None anyway. - if not stack: - return "" - - settings = stack.getTop() - setting_instance = settings.getInstance(setting_name) - if setting_instance: - setting_instance.propertyChanged.disconnect(self._onPropertyChanged) From eb84e6aa3ef13cfa40fcb81a1b8bbd62994e049b Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 6 Mar 2018 15:47:01 +0100 Subject: [PATCH 127/446] Disable not supported custom profiles CURA-5051 --- resources/qml/Menus/ProfileMenu.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/qml/Menus/ProfileMenu.qml b/resources/qml/Menus/ProfileMenu.qml index 72cda13ca9..5b9a5a3b73 100644 --- a/resources/qml/Menus/ProfileMenu.qml +++ b/resources/qml/Menus/ProfileMenu.qml @@ -52,6 +52,7 @@ Menu { text: model.name checkable: model.available + enabled: model.available checked: Cura.MachineManager.activeQualityOrQualityChangesName == model.name exclusiveGroup: group onTriggered: Cura.MachineManager.setQualityChangesGroup(model.quality_changes_group) From b179edf60e31a57e42c84cf88ce82f84187cd60f Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 6 Mar 2018 15:41:14 +0100 Subject: [PATCH 128/446] Document which layer is which pass Contributes to issue CURA-5040. --- plugins/XRayView/xray_composite.shader | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/XRayView/xray_composite.shader b/plugins/XRayView/xray_composite.shader index 82dca52cf9..0a8f6364d7 100644 --- a/plugins/XRayView/xray_composite.shader +++ b/plugins/XRayView/xray_composite.shader @@ -13,9 +13,9 @@ vertex = } fragment = - uniform sampler2D u_layer0; - uniform sampler2D u_layer1; - uniform sampler2D u_layer2; + uniform sampler2D u_layer0; //Default pass. + uniform sampler2D u_layer1; //Selection pass. + uniform sampler2D u_layer2; //X-ray pass. uniform vec2 u_offset[9]; @@ -83,9 +83,9 @@ vertex41core = fragment41core = #version 410 - uniform sampler2D u_layer0; - uniform sampler2D u_layer1; - uniform sampler2D u_layer2; + uniform sampler2D u_layer0; //Default pass. + uniform sampler2D u_layer1; //Selection pass. + uniform sampler2D u_layer2; //X-ray pass. uniform vec2 u_offset[9]; From 3b0a9bf16c88d0f8ae9179d5cdbd855f7b64204d Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 6 Mar 2018 15:50:35 +0100 Subject: [PATCH 129/446] Fix checking whether to render objects in X-ray pass Otherwise nothing gets drawn there. Contributes to issue CURA-5040. --- plugins/XRayView/XRayPass.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/XRayView/XRayPass.py b/plugins/XRayView/XRayPass.py index 38c88a256e..a75d393b35 100644 --- a/plugins/XRayView/XRayPass.py +++ b/plugins/XRayView/XRayPass.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import os.path @@ -10,7 +10,7 @@ from UM.View.RenderPass import RenderPass from UM.View.RenderBatch import RenderBatch from UM.View.GL.OpenGL import OpenGL -from UM.Scene.SceneNode import SceneNode +from cura.Scene.CuraSceneNode import CuraSceneNode from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator class XRayPass(RenderPass): @@ -27,7 +27,7 @@ class XRayPass(RenderPass): batch = RenderBatch(self._shader, type = RenderBatch.RenderType.NoType, backface_cull = False, blend_mode = RenderBatch.BlendMode.Additive) for node in DepthFirstIterator(self._scene.getRoot()): - if type(node) is SceneNode and node.getMeshData() and node.isVisible(): + if isinstance(node, CuraSceneNode) and node.getMeshData() and node.isVisible(): batch.addItem(node.getWorldTransformation(), node.getMeshData()) self.bind() From f625fa8a90e97a7486ef15f6f264c5f74a56b3b6 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 6 Mar 2018 16:08:50 +0100 Subject: [PATCH 130/446] CURA-4870 Add function to set the configuration from the printer back to Cura. Change the hash function to compare by GUID instead of type. Show the material name instead of type in the list. --- cura/Machines/MaterialGroup.py | 3 +- cura/Machines/MaterialManager.py | 30 +++++++++++++++++++ .../ExtruderConfigurationModel.py | 10 ++++--- cura/PrinterOutput/ExtruderOutputModel.py | 3 +- cura/PrinterOutput/PrinterOutputModel.py | 1 - cura/Settings/MachineManager.py | 30 ++++++++++++++++--- .../ConfigurationListView.qml | 1 - .../PrintCoreConfiguration.qml | 2 +- 8 files changed, 66 insertions(+), 14 deletions(-) diff --git a/cura/Machines/MaterialGroup.py b/cura/Machines/MaterialGroup.py index 009778943a..75ab51182c 100644 --- a/cura/Machines/MaterialGroup.py +++ b/cura/Machines/MaterialGroup.py @@ -15,10 +15,11 @@ # so "generic_abs_ultimaker3", "generic_abs_ultimaker3_AA_0.4", etc. # class MaterialGroup: - __slots__ = ("name", "root_material_node", "derived_material_node_list") + __slots__ = ("name", "is_read_only", "root_material_node", "derived_material_node_list") def __init__(self, name: str): self.name = name + self.is_read_only = False self.root_material_node = None self.derived_material_node_list = [] diff --git a/cura/Machines/MaterialManager.py b/cura/Machines/MaterialManager.py index 98e4f67f82..4bad33b890 100644 --- a/cura/Machines/MaterialManager.py +++ b/cura/Machines/MaterialManager.py @@ -87,6 +87,7 @@ class MaterialManager(QObject): root_material_id = material_metadata.get("base_file") if root_material_id not in self._material_group_map: self._material_group_map[root_material_id] = MaterialGroup(root_material_id) + self._material_group_map[root_material_id].is_read_only = self._container_registry.isReadOnly(root_material_id) group = self._material_group_map[root_material_id] # We only add root materials here @@ -325,6 +326,35 @@ class MaterialManager(QObject): return material_node + # + # Gets MaterialNode for the given extruder and machine with the given material type. + # Returns None if: + # 1. the given machine doesn't have materials; + # 2. cannot find any material InstanceContainers with the given settings. + # + def getMaterialNodeByType(self, global_stack: "GlobalStack", extruder_variant_name: str, material_guid: str) -> Optional["MaterialNode"]: + node = None + machine_definition = global_stack.definition + if parseBool(machine_definition.getMetaDataEntry("has_materials", False)): + material_diameter = machine_definition.getProperty("material_diameter", "value") + if isinstance(material_diameter, SettingFunction): + material_diameter = material_diameter(global_stack) + + # Look at the guid to material dictionary + root_material_id = None + for material_group in self._guid_material_groups_map[material_guid]: + if material_group.is_read_only: + root_material_id = material_group.root_material_node.metadata["id"] + break + + if not root_material_id: + Logger.log("i", "Cannot find materials with guid [%s] ", material_guid) + return None + + node = self.getMaterialNode(machine_definition.getId(), extruder_variant_name, + material_diameter, root_material_id) + return node + # # Used by QualityManager. Built-in quality profiles may be based on generic material IDs such as "generic_pla". # For materials such as ultimaker_pla_orange, no quality profiles may be found, so we should fall back to use diff --git a/cura/PrinterOutput/ExtruderConfigurationModel.py b/cura/PrinterOutput/ExtruderConfigurationModel.py index 7aa8785ae9..072adfc24e 100644 --- a/cura/PrinterOutput/ExtruderConfigurationModel.py +++ b/cura/PrinterOutput/ExtruderConfigurationModel.py @@ -24,7 +24,7 @@ class ExtruderConfigurationModel(QObject): def setMaterial(self, material): self._material = material - @pyqtProperty(str, fset = setMaterial, notify = extruderConfigurationChanged) + @pyqtProperty(QObject, fset = setMaterial, notify = extruderConfigurationChanged) def material(self): return self._material @@ -36,12 +36,14 @@ class ExtruderConfigurationModel(QObject): return self._hotend_id def __str__(self): - if self._material is None or self._hotend_id is None: + if self._material is None or self._hotend_id is None or self.material.type is None: return "No information" - return "Position: " + str(self._position) + " - Material: " + self._material + " - HotendID: " + self._hotend_id + return "Position: " + str(self._position) + " - Material: " + self._material.type + " - HotendID: " + self._hotend_id def __eq__(self, other): return hash(self) == hash(other) + # Calculating a hash function using the position of the extruder, the material GUID and the hotend id to check if is + # unique within a set def __hash__(self): - return hash(self._position) ^ hash(self._material) ^ hash(self._hotend_id) \ No newline at end of file + return hash(self._position) ^ (hash(self._material.guid) if self.material is not None else hash(0)) ^ hash(self._hotend_id) \ No newline at end of file diff --git a/cura/PrinterOutput/ExtruderOutputModel.py b/cura/PrinterOutput/ExtruderOutputModel.py index d74b3a90d5..a639d428f9 100644 --- a/cura/PrinterOutput/ExtruderOutputModel.py +++ b/cura/PrinterOutput/ExtruderOutputModel.py @@ -81,7 +81,6 @@ class ExtruderOutputModel(QObject): def _updateExtruderConfiguration(self): self._extruder_configuration.position = self._position - self._extruder_configuration.material = self._active_material.type if self.activeMaterial is not None else None + self._extruder_configuration.material = self._active_material self._extruder_configuration.hotendID = self._hotend_id - print("Recalculating extruder configuration:", self._extruder_configuration) self.extruderConfigurationChanged.emit() diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index 19365b9cc6..f59cc1bece 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -253,5 +253,4 @@ class PrinterOutputModel(QObject): self._printer_configuration.printerType = self._type self._printer_configuration.extruderConfigurations = [extruder.extruderConfiguration for extruder in self._extruders] self._printer_configuration.buildplateConfiguration = None # TODO Add the buildplate information - print("Recalculating printer configuration", self.name, ":", self._printer_configuration) self.configurationChanged.emit() diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 0cde440fd8..6e0679e11c 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -20,7 +20,6 @@ from UM.Logger import Logger from UM.Message import Message from UM.Settings.ContainerRegistry import ContainerRegistry -from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.SettingFunction import SettingFunction from UM.Signal import postponeSignals, CompressTechnique @@ -28,6 +27,7 @@ from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch from cura.PrinterOutputDevice import PrinterOutputDevice from cura.PrinterOutput.ConfigurationModel import ConfigurationModel from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationModel +from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel from cura.Settings.ExtruderManager import ExtruderManager from .CuraStackBuilder import CuraStackBuilder @@ -124,7 +124,8 @@ class MachineManager(QObject): if containers: containers[0].nameChanged.connect(self._onMaterialNameChanged) - self._material_manager = self._application._material_manager + self._material_manager = self._application.getMaterialManager() + self._variant_manager = self._application.getVariantManager() self._quality_manager = self._application.getQualityManager() # When the materials lookup table gets updated, it can mean that a material has its name changed, which should @@ -176,12 +177,21 @@ class MachineManager(QObject): if not self._global_container_stack: return + # Create the configuration model with the current data in Cura self._current_printer_configuration.printerType = self._global_container_stack.definition.getName() self._current_printer_configuration.extruderConfigurations = [] for extruder in self._global_container_stack.extruders.values(): extruder_configuration = ExtruderConfigurationModel() + # For compare just the GUID is needed at this moment + mat_type = extruder.material.getMetaDataEntry("material") if extruder.material != self._empty_material_container else None + mat_guid = extruder.material.getMetaDataEntry("GUID") if extruder.material != self._empty_material_container else None + mat_color = extruder.material.getMetaDataEntry("color_name") if extruder.material != self._empty_material_container else None + mat_brand = extruder.material.getMetaDataEntry("brand") if extruder.material != self._empty_material_container else None + mat_name = extruder.material.getMetaDataEntry("name") if extruder.material != self._empty_material_container else None + material_model = MaterialOutputModel(mat_guid, mat_type, mat_color, mat_brand, mat_name) + extruder_configuration.position = int(extruder.getMetaDataEntry("position")) - extruder_configuration.material = extruder.material.getName() if extruder.material != self._empty_material_container else None + extruder_configuration.material = material_model extruder_configuration.hotendID = extruder.variant.getName() if extruder.variant != self._empty_variant_container else None self._current_printer_configuration.extruderConfigurations.append(extruder_configuration) @@ -197,7 +207,8 @@ class MachineManager(QObject): @pyqtSlot(QObject) def applyRemoteConfiguration(self, configuration: ConfigurationModel): - print("Applying remote configuration", configuration) + for extruder_configuration in configuration.extruderConfigurations: + self.setConfiguration(extruder_configuration.position, extruder_configuration.hotendID, extruder_configuration.material.guid) @pyqtProperty("QVariantList", notify = outputDevicesChanged) def printerOutputDevices(self): @@ -355,6 +366,7 @@ class MachineManager(QObject): Logger.log("w", "Failed creating a new machine!") def _checkStacksHaveErrors(self) -> bool: + return False time_start = time.time() if self._global_container_stack is None: #No active machine. return False @@ -1018,6 +1030,16 @@ class MachineManager(QObject): self._updateMaterialWithVariant(None) # Update all materials self._updateQualityWithMaterial() + def setConfiguration(self, position, variant_name, material_guid): + position = str(position) + variant_container_node = self._variant_manager.getVariantNode(self._global_container_stack.definition.getId(), variant_name) + material_container_node = self._material_manager.getMaterialNodeByType(self._global_container_stack, variant_name, material_guid) + with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): + self._setVariantNode(position, variant_container_node) + self._setMaterial(position, material_container_node) + self._updateMaterialWithVariant(position) + self._updateQualityWithMaterial() + @pyqtSlot(str, "QVariant") def setMaterial(self, position, container_node): position = str(position) diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml index 00de9d0003..f476383169 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -46,7 +46,6 @@ Column target: outputDevice onUniqueConfigurationsChanged: { // FIXME For now the model should be removed and then created again, otherwise changes in the printer don't automatically update the UI - print("Update unique configurations") configurationList.model = null configurationList.model = outputDevice.uniqueConfigurations } diff --git a/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml b/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml index 74ecc114c7..d34252adc4 100644 --- a/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml +++ b/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml @@ -69,7 +69,7 @@ Column Label { id: materialLabel - text: printCoreConfiguration.material + text: printCoreConfiguration.material.name elide: Text.ElideRight width: parent.width font: UM.Theme.getFont("default_bold") From 63e679e4a087c7f682c9e0ccd11c5a6e2c617ccd Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 6 Mar 2018 16:28:00 +0100 Subject: [PATCH 131/446] CURA-4400 updated UM3 machine_head_with_fans_polygon --- resources/definitions/ultimaker3.def.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/definitions/ultimaker3.def.json b/resources/definitions/ultimaker3.def.json index dcf6b167c0..211e749c90 100644 --- a/resources/definitions/ultimaker3.def.json +++ b/resources/definitions/ultimaker3.def.json @@ -43,10 +43,10 @@ { "default_value": [ - [ -29, 6.1 ], - [ -29, -33.9 ], - [ 71, 6.1 ], - [ 71, -33.9 ] + [-41.9, -45.8], + [-41.9, 33.9], + [59.9, 33.9], + [59.9, -45.8] ] }, "machine_gcode_flavor": { "default_value": "Griffin" }, From 92e80fa26a12c2174e4f1a64d5eff894f9707a4e Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 6 Mar 2018 16:28:40 +0100 Subject: [PATCH 132/446] CURA-4400 Bugfix do not handle layer scene nodes in solidview --- plugins/SolidView/SolidView.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/SolidView/SolidView.py b/plugins/SolidView/SolidView.py index 2abfe80f95..de9f922267 100644 --- a/plugins/SolidView/SolidView.py +++ b/plugins/SolidView/SolidView.py @@ -78,7 +78,7 @@ class SolidView(View): for node in DepthFirstIterator(scene.getRoot()): if not node.render(renderer): - if node.getMeshData() and node.isVisible(): + if node.getMeshData() and node.isVisible() and not node.callDecoration("getLayerData"): uniforms = {} shade_factor = 1.0 From 987794c5158930e76a771dc4b2f4d5315d9f91e3 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 6 Mar 2018 16:59:51 +0100 Subject: [PATCH 133/446] CURA-4870 Update the Sync Button accordingly to changes both in the output device or in the current configuration, in order to check wether a configuration matches or not. --- .../Menus/ConfigurationMenu/SyncButton.qml | 33 ++++++++++++++++++- resources/qml/SidebarHeader.qml | 3 +- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml index a82d7cc515..3834f2ebd2 100644 --- a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml +++ b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml @@ -6,13 +6,30 @@ import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import UM 1.2 as UM +import Cura 1.0 as Cura Button { - text: "No match" + id: base + property var outputDevice: Cura.MachineManager.printerOutputDevices[0] != null ? Cura.MachineManager.printerOutputDevices[0] : null + text: catalog.i18nc("@label:sync indicator", "No match") width: parent.width height: parent.height + function updateOnSync() + { + for (var index in outputDevice.uniqueConfigurations) + { + var configuration = outputDevice.uniqueConfigurations[index] + if (Cura.MachineManager.matchesConfiguration(configuration)) + { + base.text = catalog.i18nc("@label:sync indicator", "Matched") + return + } + } + base.text = catalog.i18nc("@label:sync indicator", "No match") + } + style: ButtonStyle { background: Rectangle @@ -68,4 +85,18 @@ Button { panelVisible = !panelVisible } + + Connections { + target: outputDevice + onUniqueConfigurationsChanged: { + updateOnSync() + } + } + + Connections { + target: Cura.MachineManager + onCurrentConfigurationChanged: { + updateOnSync() + } + } } \ No newline at end of file diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 449600bf61..7acc58c52a 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -63,8 +63,7 @@ Column ToolButton { - id: configurationSelection - + id: printerTypeSelection text: catalog.i18nc("@label", "Printer type"); height: UM.Theme.getSize("setting_control").height width: Math.round(parent.width * 0.7) + UM.Theme.getSize("sidebar_margin").width From 095d9fbdf6b0e8d65ef79581d720becd2f6cfdcb Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 6 Mar 2018 16:28:40 +0100 Subject: [PATCH 134/446] CURA-4400 Bugfix do not handle layer scene nodes in solidview --- plugins/SolidView/SolidView.py | 2 +- resources/definitions/ultimaker3.def.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/SolidView/SolidView.py b/plugins/SolidView/SolidView.py index 2abfe80f95..de9f922267 100644 --- a/plugins/SolidView/SolidView.py +++ b/plugins/SolidView/SolidView.py @@ -78,7 +78,7 @@ class SolidView(View): for node in DepthFirstIterator(scene.getRoot()): if not node.render(renderer): - if node.getMeshData() and node.isVisible(): + if node.getMeshData() and node.isVisible() and not node.callDecoration("getLayerData"): uniforms = {} shade_factor = 1.0 diff --git a/resources/definitions/ultimaker3.def.json b/resources/definitions/ultimaker3.def.json index 211e749c90..4e2b5ad4c2 100644 --- a/resources/definitions/ultimaker3.def.json +++ b/resources/definitions/ultimaker3.def.json @@ -43,10 +43,10 @@ { "default_value": [ - [-41.9, -45.8], - [-41.9, 33.9], - [59.9, 33.9], - [59.9, -45.8] + [ -41.9, -45.8 ], + [ -41.9, 33.9 ], + [ 59.9, 33.9 ], + [ 59.9, -45.8 ] ] }, "machine_gcode_flavor": { "default_value": "Griffin" }, From 5b2ff705e79ea365a476e195b8a2b2ac0a7eeb07 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Tue, 6 Mar 2018 17:03:44 +0100 Subject: [PATCH 135/446] CURA-4870 Add menu icons --- resources/qml/Menus/LocalPrinterMenu.qml | 10 ++++------ resources/qml/Menus/NetworkPrinterMenu.qml | 11 +++++------ .../themes/cura-light/icons/printer_group.svg | 12 ++++++++++++ .../themes/cura-light/icons/printer_single.svg | 14 ++++++++++++++ 4 files changed, 35 insertions(+), 12 deletions(-) create mode 100644 resources/themes/cura-light/icons/printer_group.svg create mode 100644 resources/themes/cura-light/icons/printer_single.svg diff --git a/resources/qml/Menus/LocalPrinterMenu.qml b/resources/qml/Menus/LocalPrinterMenu.qml index ef9a7b13b0..1c3064499b 100644 --- a/resources/qml/Menus/LocalPrinterMenu.qml +++ b/resources/qml/Menus/LocalPrinterMenu.qml @@ -7,14 +7,12 @@ import QtQuick.Controls 1.4 import UM 1.2 as UM import Cura 1.0 as Cura -Instantiator -{ - model: UM.ContainerStacksModel - { +Instantiator { + model: UM.ContainerStacksModel { filter: {"type": "machine", "um_network_key": null} } - MenuItem - { + MenuItem { + iconSource: UM.Theme.getIcon("printer_single") text: model.name; checkable: true; checked: Cura.MachineManager.activeMachineId == model.id diff --git a/resources/qml/Menus/NetworkPrinterMenu.qml b/resources/qml/Menus/NetworkPrinterMenu.qml index 3dadad3913..fda99d065c 100644 --- a/resources/qml/Menus/NetworkPrinterMenu.qml +++ b/resources/qml/Menus/NetworkPrinterMenu.qml @@ -7,14 +7,13 @@ import QtQuick.Controls 1.4 import UM 1.2 as UM import Cura 1.0 as Cura -Instantiator -{ - model: UM.ContainerStacksModel - { +Instantiator { + model: UM.ContainerStacksModel { filter: {"type": "machine", "um_network_key": "*"} } - MenuItem - { + MenuItem { + // TODO: Use printer_group icon when it's a cluster. + iconSource: UM.Theme.getIcon("printer_single") text: model.name; checkable: true; checked: Cura.MachineManager.activeMachineId == model.id diff --git a/resources/themes/cura-light/icons/printer_group.svg b/resources/themes/cura-light/icons/printer_group.svg new file mode 100644 index 0000000000..614bea90b8 --- /dev/null +++ b/resources/themes/cura-light/icons/printer_group.svg @@ -0,0 +1,12 @@ + + + + icn_groupPrinters + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/resources/themes/cura-light/icons/printer_single.svg b/resources/themes/cura-light/icons/printer_single.svg new file mode 100644 index 0000000000..f7dc83987d --- /dev/null +++ b/resources/themes/cura-light/icons/printer_single.svg @@ -0,0 +1,14 @@ + + + + icn_singlePrinter + Created with Sketch. + + + + + + + + + \ No newline at end of file From 75d9297c7d664347fb579ae0d01f44bcbaf04832 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 6 Mar 2018 17:05:21 +0100 Subject: [PATCH 136/446] Optimize 3MF writer and XML material serialization CURA-5049 --- plugins/3MFWriter/ThreeMFWorkspaceWriter.py | 35 +++++++++++-------- .../XmlMaterialProfile/XmlMaterialProfile.py | 23 ++++++++---- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/plugins/3MFWriter/ThreeMFWorkspaceWriter.py b/plugins/3MFWriter/ThreeMFWorkspaceWriter.py index 507274d355..3f5e69317e 100644 --- a/plugins/3MFWriter/ThreeMFWorkspaceWriter.py +++ b/plugins/3MFWriter/ThreeMFWorkspaceWriter.py @@ -1,14 +1,15 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from UM.Workspace.WorkspaceWriter import WorkspaceWriter +import configparser +from io import StringIO +import zipfile + from UM.Application import Application +from UM.Logger import Logger from UM.Preferences import Preferences from UM.Settings.ContainerRegistry import ContainerRegistry -from cura.Settings.ExtruderManager import ExtruderManager -import zipfile -from io import StringIO -import configparser +from UM.Workspace.WorkspaceWriter import WorkspaceWriter class ThreeMFWorkspaceWriter(WorkspaceWriter): @@ -16,7 +17,10 @@ class ThreeMFWorkspaceWriter(WorkspaceWriter): super().__init__() def write(self, stream, nodes, mode=WorkspaceWriter.OutputMode.BinaryMode): - mesh_writer = Application.getInstance().getMeshFileHandler().getWriter("3MFWriter") + application = Application.getInstance() + machine_manager = application.getMachineManager() + + mesh_writer = application.getMeshFileHandler().getWriter("3MFWriter") if not mesh_writer: # We need to have the 3mf mesh writer, otherwise we can't save the entire workspace return False @@ -29,17 +33,17 @@ class ThreeMFWorkspaceWriter(WorkspaceWriter): if archive is None: # This happens if there was no mesh data to write. archive = zipfile.ZipFile(stream, "w", compression = zipfile.ZIP_DEFLATED) - global_container_stack = Application.getInstance().getGlobalContainerStack() + global_stack = machine_manager.activeMachine # Add global container stack data to the archive. - self._writeContainerToArchive(global_container_stack, archive) + self._writeContainerToArchive(global_stack, archive) # Also write all containers in the stack to the file - for container in global_container_stack.getContainers(): + for container in global_stack.getContainers(): self._writeContainerToArchive(container, archive) # Check if the machine has extruders and save all that data as well. - for extruder_stack in ExtruderManager.getInstance().getMachineExtruders(global_container_stack.getId()): + for extruder_stack in global_stack.extruders.values(): self._writeContainerToArchive(extruder_stack, archive) for container in extruder_stack.getContainers(): self._writeContainerToArchive(container, archive) @@ -59,9 +63,9 @@ class ThreeMFWorkspaceWriter(WorkspaceWriter): version_file = zipfile.ZipInfo("Cura/version.ini") version_config_parser = configparser.ConfigParser(interpolation = None) version_config_parser.add_section("versions") - version_config_parser.set("versions", "cura_version", Application.getInstance().getVersion()) - version_config_parser.set("versions", "build_type", Application.getInstance().getBuildType()) - version_config_parser.set("versions", "is_debug_mode", str(Application.getInstance().getIsDebugMode())) + version_config_parser.set("versions", "cura_version", application.getVersion()) + version_config_parser.set("versions", "build_type", application.getBuildType()) + version_config_parser.set("versions", "is_debug_mode", str(application.getIsDebugMode())) version_file_string = StringIO() version_config_parser.write(version_file_string) @@ -85,7 +89,8 @@ class ThreeMFWorkspaceWriter(WorkspaceWriter): # Some containers have a base file, which should then be the file to use. if "base_file" in container.getMetaData(): base_file = container.getMetaDataEntry("base_file") - container = ContainerRegistry.getInstance().findContainers(id = base_file)[0] + if base_file != container.getId(): + container = ContainerRegistry.getInstance().findContainers(id = base_file)[0] file_name = "Cura/%s.%s" % (container.getId(), file_suffix) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index edc782cc9e..a7ba423153 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -200,18 +200,25 @@ class XmlMaterialProfile(InstanceContainer): ## Begin Settings Block builder.start("settings") - if self.getDefinition().getId() == "fdmprinter": + if self.getMetaDataEntry("definition") == "fdmprinter": for instance in self.findInstances(): self._addSettingElement(builder, instance) machine_container_map = {} machine_nozzle_map = {} - variant_manager = CuraApplication.getInstance()._variant_manager + variant_manager = CuraApplication.getInstance().getVariantManager() + material_manager = CuraApplication.getInstance().getMaterialManager() + + root_material_id = self.getMetaDataEntry("base_file") # if basefile is self.getId, this is a basefile. + material_group = material_manager.getMaterialGroup(root_material_id) + + all_containers = [] + for node in [material_group.root_material_node] + material_group.derived_material_node_list: + all_containers.append(node.getContainer()) - all_containers = registry.findInstanceContainers(GUID = self.getMetaDataEntry("GUID"), base_file = self.getId()) for container in all_containers: - definition_id = container.getDefinition().getId() + definition_id = container.getMetaDataEntry("definition") if definition_id == "fdmprinter": continue @@ -233,7 +240,8 @@ class XmlMaterialProfile(InstanceContainer): product_id_map = self.getProductIdMap() for definition_id, container in machine_container_map.items(): - definition = container.getDefinition() + definition_id = container.getMetaDataEntry("definition") + definition_metadata = ContainerRegistry.getInstance().findDefinitionContainersMetadata(id = definition_id)[0] product = definition_id for product_name, product_id_list in product_id_map.items(): @@ -243,13 +251,14 @@ class XmlMaterialProfile(InstanceContainer): builder.start("machine") builder.start("machine_identifier", { - "manufacturer": container.getMetaDataEntry("machine_manufacturer", definition.getMetaDataEntry("manufacturer", "Unknown")), + "manufacturer": container.getMetaDataEntry("machine_manufacturer", + definition_metadata.get("manufacturer", "Unknown")), "product": product }) builder.end("machine_identifier") for instance in container.findInstances(): - if self.getDefinition().getId() == "fdmprinter" and self.getInstance(instance.definition.key) and self.getProperty(instance.definition.key, "value") == instance.value: + if self.getMetaDataEntry("definition") == "fdmprinter" and self.getInstance(instance.definition.key) and self.getProperty(instance.definition.key, "value") == instance.value: # If the settings match that of the base profile, just skip since we inherit the base profile. continue From bab46d7048f4f3d2c40359ad3086675c37d19cd0 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 6 Mar 2018 17:19:31 +0100 Subject: [PATCH 137/446] CURA-4400 only reevaluate non printing mesh if the setting actually matters --- cura/Settings/SettingOverrideDecorator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Settings/SettingOverrideDecorator.py b/cura/Settings/SettingOverrideDecorator.py index c9c9d7e411..357bc87024 100644 --- a/cura/Settings/SettingOverrideDecorator.py +++ b/cura/Settings/SettingOverrideDecorator.py @@ -95,7 +95,7 @@ class SettingOverrideDecorator(SceneNodeDecorator): def _onSettingChanged(self, instance, property_name): # Reminder: 'property' is a built-in function # Trigger slice/need slicing if the value has changed. - if property_name == "value": + if property_name == "value" and instance in self._non_printing_mesh_settings: self._is_non_printing_mesh = self.evaluateIsNonPrintingMesh() Application.getInstance().getBackend().needsSlicing() From 813f4e83e048679617fd529d7615b9337d79dfca Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 7 Mar 2018 09:56:38 +0100 Subject: [PATCH 138/446] CURA-4870 Adjust colors for the selected configuration Remove the printer icon since it doesn't look as expected --- .../ConfigurationMenu/ConfigurationItem.qml | 22 ++++++++++++++----- resources/qml/Menus/LocalPrinterMenu.qml | 1 - resources/qml/Menus/NetworkPrinterMenu.qml | 4 ++-- resources/themes/cura-light/theme.json | 7 ++++-- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml index ae97a82207..e4c4683869 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml @@ -17,10 +17,15 @@ Rectangle height: childrenRect.height border.width: UM.Theme.getSize("default_lining").width - border.color: UM.Theme.getColor("sidebar_lining_thin") + border.color: updateBorderColor() color: selected ? UM.Theme.getColor("configuration_item_active") : UM.Theme.getColor("configuration_item") property var textColor: selected ? UM.Theme.getColor("configuration_item_text_active") : UM.Theme.getColor("configuration_item_text") + function updateBorderColor() + { + border.color = selected ? UM.Theme.getColor("configuration_item_border_active") : UM.Theme.getColor("configuration_item_border") + } + Column { id: contentColumn @@ -52,7 +57,8 @@ Rectangle } //Buildplate row separator - Rectangle { + Rectangle + { id: separator visible: buildplateInformation.visible @@ -98,18 +104,22 @@ Rectangle anchors.fill: parent onClicked: activateConfiguration() hoverEnabled: true - onEntered: parent.border.color = UM.Theme.getColor("primary_hover") - onExited: parent.border.color = "black" + onEntered: parent.border.color = UM.Theme.getColor("configuration_item_border_hover") + onExited: updateBorderColor() } - Connections { + Connections + { target: Cura.MachineManager onCurrentConfigurationChanged: { configurationItem.selected = Cura.MachineManager.matchesConfiguration(configuration) + updateBorderColor() } } - Component.onCompleted: { + Component.onCompleted: + { configurationItem.selected = Cura.MachineManager.matchesConfiguration(configuration) + updateBorderColor() } } \ No newline at end of file diff --git a/resources/qml/Menus/LocalPrinterMenu.qml b/resources/qml/Menus/LocalPrinterMenu.qml index 1c3064499b..0bdd4f33b9 100644 --- a/resources/qml/Menus/LocalPrinterMenu.qml +++ b/resources/qml/Menus/LocalPrinterMenu.qml @@ -12,7 +12,6 @@ Instantiator { filter: {"type": "machine", "um_network_key": null} } MenuItem { - iconSource: UM.Theme.getIcon("printer_single") text: model.name; checkable: true; checked: Cura.MachineManager.activeMachineId == model.id diff --git a/resources/qml/Menus/NetworkPrinterMenu.qml b/resources/qml/Menus/NetworkPrinterMenu.qml index fda99d065c..64539c9892 100644 --- a/resources/qml/Menus/NetworkPrinterMenu.qml +++ b/resources/qml/Menus/NetworkPrinterMenu.qml @@ -12,8 +12,8 @@ Instantiator { filter: {"type": "machine", "um_network_key": "*"} } MenuItem { - // TODO: Use printer_group icon when it's a cluster. - iconSource: UM.Theme.getIcon("printer_single") + // TODO: Use printer_group icon when it's a cluster. Not use it for now since it doesn't look as expected +// iconSource: UM.Theme.getIcon("printer_single") text: model.name; checkable: true; checked: Cura.MachineManager.activeMachineId == model.id diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json index 46ea0fc49e..d97970e566 100644 --- a/resources/themes/cura-light/theme.json +++ b/resources/themes/cura-light/theme.json @@ -302,9 +302,12 @@ "layerview_nozzle": [181, 166, 66, 50], "configuration_item": [255, 255, 255, 0], - "configuration_item_active": [31, 36, 39, 255], + "configuration_item_active": [12, 169, 227, 32], "configuration_item_text": [0, 0, 0, 255], - "configuration_item_text_active": [255, 255, 255, 255] + "configuration_item_text_active": [0, 0, 0, 255], + "configuration_item_border": [127, 127, 127, 255], + "configuration_item_border_active": [12, 169, 227, 32], + "configuration_item_border_hover": [12, 169, 227, 255] }, "sizes": { From 6cae5c2e35956dccd2e0e64ff222e561c9edac1b Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 7 Mar 2018 10:39:20 +0100 Subject: [PATCH 139/446] Remove unnecessary signal connection in MaterialsModel CURA-5052 --- cura/Machines/Models/BaseMaterialsModel.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cura/Machines/Models/BaseMaterialsModel.py b/cura/Machines/Models/BaseMaterialsModel.py index 5c09a4f060..0a1337feeb 100644 --- a/cura/Machines/Models/BaseMaterialsModel.py +++ b/cura/Machines/Models/BaseMaterialsModel.py @@ -40,8 +40,6 @@ class BaseMaterialsModel(ListModel): self._extruder_position = 0 self._extruder_stack = None - self._machine_manager.globalContainerChanged.connect(self._updateExtruderStack) - def _updateExtruderStack(self): global_stack = self._machine_manager.activeMachine if global_stack is None: From ecfb62b69ec6e7726150cb7c61e27a0f0e5d6122 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 7 Mar 2018 11:00:42 +0100 Subject: [PATCH 140/446] Rename ColorChange to FilamentChange I think this is more clear to the users what this should actually do. --- .../{ColorChange.py => FilamentChange.py} | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) rename plugins/PostProcessingPlugin/scripts/{ColorChange.py => FilamentChange.py} (79%) diff --git a/plugins/PostProcessingPlugin/scripts/ColorChange.py b/plugins/PostProcessingPlugin/scripts/FilamentChange.py similarity index 79% rename from plugins/PostProcessingPlugin/scripts/ColorChange.py rename to plugins/PostProcessingPlugin/scripts/FilamentChange.py index 8db45f4033..2bb7891634 100644 --- a/plugins/PostProcessingPlugin/scripts/ColorChange.py +++ b/plugins/PostProcessingPlugin/scripts/FilamentChange.py @@ -2,17 +2,15 @@ # under the terms of the AGPLv3 or higher from ..Script import Script -#from UM.Logger import Logger -# from cura.Settings.ExtruderManager import ExtruderManager -class ColorChange(Script): +class FilamentChange(Script): def __init__(self): super().__init__() def getSettingDataString(self): return """{ - "name":"Color Change", - "key": "ColorChange", + "name":"Filament Change", + "key": "FilamentChange", "metadata": {}, "version": 2, "settings": @@ -60,17 +58,17 @@ class ColorChange(Script): if later_retract is not None and later_retract > 0.: color_change = color_change + (" L%.2f" % later_retract) - color_change = color_change + " ; Generated by ColorChange plugin" + color_change = color_change + " ; Generated by FilamentChange plugin" - layer_targets = layer_nums.split(',') + layer_targets = layer_nums.split(",") if len(layer_targets) > 0: for layer_num in layer_targets: - layer_num = int( layer_num.strip() ) + layer_num = int(layer_num.strip()) if layer_num < len(data): - layer = data[ layer_num - 1 ] + layer = data[layer_num - 1] lines = layer.split("\n") - lines.insert(2, color_change ) - final_line = "\n".join( lines ) - data[ layer_num - 1 ] = final_line + lines.insert(2, color_change) + final_line = "\n".join(lines) + data[layer_num - 1] = final_line return data From bb3d706c9265f098a2c1523f8c8311c342128ba9 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 7 Mar 2018 11:24:02 +0100 Subject: [PATCH 141/446] CURA-4870 Adapt the size of the sync dropdown to the height of the contents or a maximum size defined manually. Create sections in the list view depending on the machine types that are in the group. --- .../ConfigurationListView.qml | 91 ++++++++++--------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml index f476383169..6aa8297e21 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -16,61 +16,68 @@ Column padding: UM.Theme.getSize("default_margin").width spacing: Math.round(UM.Theme.getSize("default_margin").height / 2) - Label { + Label + { text: catalog.i18nc("@label:header configurations", "Available configurations") font: UM.Theme.getFont("large") width: parent.width - 2 * parent.padding } - ScrollView { + Component + { + id: sectionHeading + Rectangle + { + height: childrenRect.height + UM.Theme.getSize("default_margin").height + Label + { + text: section + font: UM.Theme.getFont("default_bold") + } + } + } + + ScrollView + { id: container - width: parent.width - 2 * parent.padding - height: 500 //childrenRect.height + width: parent.width - parent.padding + height: Math.min(configurationList.contentHeight, 300 * screenScaleFactor) style: UM.Theme.styles.scrollview + __wheelAreaScrollSpeed: 75 // Scroll three lines in one scroll event - Repeater { - height: childrenRect.height - model: outputDevice != null ? outputDevice.connectedPrintersTypeCount : null - delegate: Rectangle + ListView + { + id: configurationList + spacing: Math.round(UM.Theme.getSize("default_margin").height / 2) + width: container.width + contentHeight: childrenRect.height + + section.property: "modelData.printerType" + section.criteria: ViewSection.FullString + section.delegate: sectionHeading + + model: outputDevice.uniqueConfigurations + delegate: ConfigurationItem { - height: childrenRect.height - Label + width: parent.width - UM.Theme.getSize("default_margin").width + configuration: modelData + onActivateConfiguration: { - id: printerTypeHeader - text: modelData.machine_type - font: UM.Theme.getFont("default_bold") - } - - Connections { - target: outputDevice - onUniqueConfigurationsChanged: { - // FIXME For now the model should be removed and then created again, otherwise changes in the printer don't automatically update the UI - configurationList.model = null - configurationList.model = outputDevice.uniqueConfigurations - } - } - - ListView - { - id: configurationList - anchors.top: printerTypeHeader.bottom - anchors.topMargin: UM.Theme.getSize("default_margin").height - spacing: Math.round(UM.Theme.getSize("default_margin").height / 2) - width: container.width - height: childrenRect.height - model: outputDevice.uniqueConfigurations - delegate: ConfigurationItem - { - width: parent.width - configuration: modelData - onActivateConfiguration: - { - Cura.MachineManager.applyRemoteConfiguration(configuration) - } - } + Cura.MachineManager.applyRemoteConfiguration(configuration) } } } } + + Connections + { + target: outputDevice + onUniqueConfigurationsChanged: + { + // FIXME For now the model should be removed and then created again, otherwise changes in the printer don't automatically update the UI + configurationList.model = null + configurationList.model = outputDevice.uniqueConfigurations + } + } } \ No newline at end of file From 6abbe7381aabeed2b80b17682d60a4abc853561d Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 7 Mar 2018 11:26:50 +0100 Subject: [PATCH 142/446] CURA-4870 Adjust a little bit the maximum size so three printers of two different types can fit --- resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml index 6aa8297e21..037fadcb22 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -41,7 +41,7 @@ Column { id: container width: parent.width - parent.padding - height: Math.min(configurationList.contentHeight, 300 * screenScaleFactor) + height: Math.min(configurationList.contentHeight, 350 * screenScaleFactor) style: UM.Theme.styles.scrollview __wheelAreaScrollSpeed: 75 // Scroll three lines in one scroll event From 4568fab5315c48d7b79349183422144fbfc5262a Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 7 Mar 2018 11:27:23 +0100 Subject: [PATCH 143/446] CURA-4400 fix quality profiles model to not use disabled extruder and update Not Supported or select a valid quality when enabling/disabling extruder --- cura/Settings/MachineManager.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index fa5bb44757..2264038472 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -818,7 +818,11 @@ class MachineManager(QObject): self.updateDefaultExtruder() self.updateNumberExtrudersEnabled() self.correctExtruderSettings() + # ensure that the quality profile is compatible with current combination, or choose a compatible one if available + self._updateQualityWithMaterial() self.extruderChanged.emit() + # update material compatibility color + self.activeQualityGroupChanged.emit() # update items in SettingExtruder ExtruderManager.getInstance().extrudersChanged.emit(self._global_container_stack.getId()) # Make sure the front end reflects changes @@ -976,7 +980,7 @@ class MachineManager(QObject): # check material - variant compatibility if Util.parseBool(self._global_container_stack.getMetaDataEntry("has_materials", False)): for position, extruder in self._global_container_stack.extruders.items(): - if not extruder.material.getMetaDataEntry("compatible"): + if extruder.isEnabled and not extruder.material.getMetaDataEntry("compatible"): return False return True From 507de9c22c0e957a2e7dcaa9e8c91939f6b94c92 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 7 Mar 2018 11:30:36 +0100 Subject: [PATCH 144/446] Catch timeout exceptions when printing via USB If the firmware froze or something... --- plugins/USBPrinting/USBPrinterOutputDevice.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index 6e2b5153db..11cc7bf472 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from UM.Logger import Logger @@ -17,7 +17,7 @@ from .avr_isp import stk500v2, intelHex from PyQt5.QtCore import pyqtSlot, pyqtSignal, pyqtProperty -from serial import Serial, SerialException +from serial import Serial, SerialException, SerialTimeoutException from threading import Thread from time import time, sleep from queue import Queue @@ -266,8 +266,11 @@ class USBPrinterOutputDevice(PrinterOutputDevice): command = (command + "\n").encode() if not command.endswith(b"\n"): command += b"\n" - self._serial.write(b"\n") - self._serial.write(command) + try: + self._serial.write(b"\n") + self._serial.write(command) + except SerialTimeoutException: + Logger.log("w", "Timeout when sending command to printer via USB.") def _update(self): while self._connection_state == ConnectionState.connected and self._serial is not None: From 23653d73577039c25bfc5586deacd2986a2bd3fc Mon Sep 17 00:00:00 2001 From: Aleksei S Date: Wed, 7 Mar 2018 11:34:10 +0100 Subject: [PATCH 145/446] Fix: Pressing 'cancel' button during compressing the print job should show "Prepare" page CURA-4960 --- plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py index 73acc02cae..7a4c590acc 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py @@ -93,13 +93,15 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): self._gcode = gcode_list + is_job_sent = True if len(self._printers) > 1: self._spawnPrinterSelectionDialog() else: - self.sendPrintJob() + is_job_sent = self.sendPrintJob() # Notify the UI that a switch to the print monitor should happen - Application.getInstance().getController().setActiveStage("MonitorStage") + if is_job_sent: + Application.getInstance().getController().setActiveStage("MonitorStage") def _spawnPrinterSelectionDialog(self): if self._printer_selection_dialog is None: @@ -121,7 +123,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): i18n_catalog.i18nc("@info:status", "Sending new jobs (temporarily) blocked, still sending the previous print job.")) self._error_message.show() - return + return False self._sending_gcode = True @@ -134,7 +136,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): compressed_gcode = self._compressGCode() if compressed_gcode is None: # Abort was called. - return + return False parts = [] @@ -152,6 +154,8 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): self._latest_reply_handler = self.postFormWithParts("print_jobs/", parts, onFinished=self._onPostPrintJobFinished, onProgress=self._onUploadPrintJobProgress) + return True + @pyqtProperty(QObject, notify=activePrinterChanged) def activePrinter(self) -> Optional["PrinterOutputModel"]: return self._active_printer From ff1c378c08663b82cc4a980da7ddd8557cc7ed43 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 7 Mar 2018 11:38:35 +0100 Subject: [PATCH 146/446] CURA-4400 fix start slicing when disabled extruder is incompatible --- cura/Settings/MachineManager.py | 2 ++ plugins/CuraEngineBackend/StartSliceJob.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 2264038472..651714c005 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -637,6 +637,8 @@ class MachineManager(QObject): buildplate_compatible = True # It is compatible by default extruder_stacks = self._global_container_stack.extruders.values() for stack in extruder_stacks: + if not stack.isEnabled: + continue material_container = stack.material if material_container == self._empty_material_container: continue diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index aee6a46e5b..ed7731f6ec 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -131,6 +131,8 @@ class StartSliceJob(Job): for position, extruder_stack in stack.extruders.items(): material = extruder_stack.findContainer({"type": "material"}) + if not extruder_stack.isEnabled: + continue if material: if material.getMetaDataEntry("compatible") == False: self.setResult(StartJobResult.MaterialIncompatible) From c0d55ac2a8c7ab36debb0f1dee912cacb6748b11 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 7 Mar 2018 11:15:26 +0100 Subject: [PATCH 147/446] Postpone signals in project loading to avoid incomplete data update CURA-5056 --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index cbe882f253..6b56ec89f5 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -6,6 +6,7 @@ from UM.Application import Application from UM.Logger import Logger from UM.i18n import i18nCatalog +from UM.Signal import postponeSignals, CompressTechnique from UM.Settings.ContainerStack import ContainerStack from UM.Settings.DefinitionContainer import DefinitionContainer from UM.Settings.InstanceContainer import InstanceContainer @@ -434,6 +435,24 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # \param file_name @call_on_qt_thread def read(self, file_name): + container_registry = ContainerRegistry.getInstance() + signals = [container_registry.containerAdded, + container_registry.containerRemoved, + container_registry.containerMetaDataChanged] + # + # We now have different managers updating their lookup tables upon container changes. It is critical to make + # sure that the managers have a complete set of data when they update. + # + # In project loading, lots of the container-related signals are loosely emitted, which can create timing gaps + # for incomplete data update or other kinds of issues to happen. + # + # To avoid this, we postpone all signals so they don't get emitted immediately. But, please also be aware that, + # because of this, do not expect to have the latest data in the lookup tables in project loading. + # + with postponeSignals(*signals, compress = CompressTechnique.CompressSingle): + return self._read(file_name) + + def _read(self, file_name): archive = zipfile.ZipFile(file_name, "r") cura_file_names = [name for name in archive.namelist() if name.startswith("Cura/")] From 27cce564677afb836259de72779ad71d499ad5cc Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 7 Mar 2018 11:42:57 +0100 Subject: [PATCH 148/446] Add error message for possible bugs in MaterialManager CURA-5056 --- cura/Machines/MaterialManager.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cura/Machines/MaterialManager.py b/cura/Machines/MaterialManager.py index 98e4f67f82..56577b5655 100644 --- a/cura/Machines/MaterialManager.py +++ b/cura/Machines/MaterialManager.py @@ -102,6 +102,13 @@ class MaterialManager(QObject): # GUID -> material group list self._guid_material_groups_map = defaultdict(list) for root_material_id, material_group in self._material_group_map.items(): + # This can happen when we are updating with incomplete data. + if material_group.root_material_node is None: + Logger.log("e", "Missing root material node for [%s]. Probably caused by update using incomplete data." + " Check all related signals for further debugging.", + material_group.name) + # Do nothing here, we wait for a next signal to trigger an update. + return guid = material_group.root_material_node.metadata["GUID"] self._guid_material_groups_map[guid].append(material_group) From 0beee79c3a844d8cd6c1890e276b063052fb9381 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 7 Mar 2018 13:17:55 +0100 Subject: [PATCH 149/446] CURA-4870 Revert skipping stack checks --- cura/Settings/MachineManager.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 053b9d033a..0924b1d33b 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -366,7 +366,6 @@ class MachineManager(QObject): Logger.log("w", "Failed creating a new machine!") def _checkStacksHaveErrors(self) -> bool: - return False time_start = time.time() if self._global_container_stack is None: #No active machine. return False From 97740123fa39db5229dd72f7c18d9c9ae8787b9e Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 7 Mar 2018 13:57:13 +0100 Subject: [PATCH 150/446] CURA-4870 Add information about the buildplate in the printer output model so it can be used to show the buildplate name in the configuration list. --- cura/PrinterOutput/ConfigurationModel.py | 8 ++-- .../ExtruderConfigurationModel.py | 2 +- cura/PrinterOutput/PrinterOutputModel.py | 13 ++++++- cura/Settings/MachineManager.py | 39 ++++++++++++------- .../ClusterUM3OutputDevice.py | 2 + 5 files changed, 44 insertions(+), 20 deletions(-) diff --git a/cura/PrinterOutput/ConfigurationModel.py b/cura/PrinterOutput/ConfigurationModel.py index 230a734797..30c95f2765 100644 --- a/cura/PrinterOutput/ConfigurationModel.py +++ b/cura/PrinterOutput/ConfigurationModel.py @@ -41,11 +41,13 @@ class ConfigurationModel(QObject): return self._buildplate_configuration def __str__(self): - info = "Printer type: " + self.printerType + "\n" + info = "Printer type: " + self._printer_type + "\n" info += "Extruders: [\n" - for configuration in self.extruderConfigurations: + for configuration in self._extruder_configurations: info += " " + str(configuration) + "\n" info += "]" + if self._buildplate_configuration is not None: + info += "\nBuildplate: " + self._buildplate_configuration return info def __eq__(self, other): @@ -54,7 +56,7 @@ class ConfigurationModel(QObject): def __hash__(self): extruder_hash = hash(0) first_extruder = None - for configuration in self.extruderConfigurations: + for configuration in self._extruder_configurations: extruder_hash ^= hash(configuration) if configuration.position == 0: first_extruder = configuration diff --git a/cura/PrinterOutput/ExtruderConfigurationModel.py b/cura/PrinterOutput/ExtruderConfigurationModel.py index 072adfc24e..34eddb3038 100644 --- a/cura/PrinterOutput/ExtruderConfigurationModel.py +++ b/cura/PrinterOutput/ExtruderConfigurationModel.py @@ -46,4 +46,4 @@ class ExtruderConfigurationModel(QObject): # Calculating a hash function using the position of the extruder, the material GUID and the hotend id to check if is # unique within a set def __hash__(self): - return hash(self._position) ^ (hash(self._material.guid) if self.material is not None else hash(0)) ^ hash(self._hotend_id) \ No newline at end of file + return hash(self._position) ^ (hash(self._material.guid) if self._material is not None else hash(0)) ^ hash(self._hotend_id) \ No newline at end of file diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index f59cc1bece..8d674c1c5f 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -23,6 +23,7 @@ class PrinterOutputModel(QObject): headPositionChanged = pyqtSignal() keyChanged = pyqtSignal() typeChanged = pyqtSignal() + buildplateChanged = pyqtSignal() cameraChanged = pyqtSignal() configurationChanged = pyqtSignal() @@ -41,6 +42,7 @@ class PrinterOutputModel(QObject): self._printer_state = "unknown" self._is_preheating = False self._type = "" + self._buildplate_name = None # Update the printer configuration every time any of the extruders changes its configuration for extruder in self._extruders: extruder.extruderConfigurationChanged.connect(self._updatePrinterConfiguration) @@ -78,6 +80,15 @@ class PrinterOutputModel(QObject): self._type = type self.typeChanged.emit() + @pyqtProperty(str, notify = buildplateChanged) + def buildplate(self): + return self._buildplate_name + + def updateBuildplate(self, buildplate_name): + if self._buildplate_name != buildplate_name: + self._buildplate_name = buildplate_name + self.buildplateChanged.emit() + @pyqtProperty(str, notify=keyChanged) def key(self): return self._key @@ -252,5 +263,5 @@ class PrinterOutputModel(QObject): def _updatePrinterConfiguration(self): self._printer_configuration.printerType = self._type self._printer_configuration.extruderConfigurations = [extruder.extruderConfiguration for extruder in self._extruders] - self._printer_configuration.buildplateConfiguration = None # TODO Add the buildplate information + self._printer_configuration.buildplateConfiguration = self._buildplate_name self.configurationChanged.emit() diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 0924b1d33b..12146e927e 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -24,6 +24,7 @@ from UM.Settings.SettingFunction import SettingFunction from UM.Signal import postponeSignals, CompressTechnique from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch +from cura.Machines.VariantManager import VariantType from cura.PrinterOutputDevice import PrinterOutputDevice from cura.PrinterOutput.ConfigurationModel import ConfigurationModel from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationModel @@ -205,11 +206,6 @@ class MachineManager(QObject): # print("%%%%%%%%", configuration == self._current_printer_configuration) return self._current_printer_configuration == configuration - @pyqtSlot(QObject) - def applyRemoteConfiguration(self, configuration: ConfigurationModel): - for extruder_configuration in configuration.extruderConfigurations: - self.setConfiguration(extruder_configuration.position, extruder_configuration.hotendID, extruder_configuration.material.guid) - @pyqtProperty("QVariantList", notify = outputDevicesChanged) def printerOutputDevices(self): return self._printer_output_devices @@ -1028,6 +1024,29 @@ class MachineManager(QObject): self._setMaterial(position, new_material) continue + @pyqtSlot(QObject) + def applyRemoteConfiguration(self, configuration: ConfigurationModel): + self.blurSettings.emit() + with postponeSignals(*self._getContainerChangedSignals(), + compress=CompressTechnique.CompressPerParameterValue): + for extruder_configuration in configuration.extruderConfigurations: + position = str(extruder_configuration.position) + variant_container_node = self._variant_manager.getVariantNode( + self._global_container_stack.definition.getId(), extruder_configuration.hotendID) + material_container_node = self._material_manager.getMaterialNodeByType( + self._global_container_stack, extruder_configuration.hotendID, + extruder_configuration.material.guid) + self._setVariantNode(position, variant_container_node) + self._setMaterial(position, material_container_node) + self._updateMaterialWithVariant(position) + + if configuration.buildplateConfiguration is not None: + global_variant_container_node = self._variant_manager.getVariantNode( + self._global_container_stack.definition.getId(), configuration.buildplateConfiguration, + variant_type=VariantType.BUILD_PLATE) + self._setGlobalVariant(global_variant_container_node) + self._updateQualityWithMaterial() + @pyqtSlot("QVariant") def setGlobalVariant(self, container_node): self.blurSettings.emit() @@ -1036,16 +1055,6 @@ class MachineManager(QObject): self._updateMaterialWithVariant(None) # Update all materials self._updateQualityWithMaterial() - def setConfiguration(self, position, variant_name, material_guid): - position = str(position) - variant_container_node = self._variant_manager.getVariantNode(self._global_container_stack.definition.getId(), variant_name) - material_container_node = self._material_manager.getMaterialNodeByType(self._global_container_stack, variant_name, material_guid) - with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): - self._setVariantNode(position, variant_container_node) - self._setMaterial(position, material_container_node) - self._updateMaterialWithVariant(position) - self._updateQualityWithMaterial() - @pyqtSlot(str, "QVariant") def setMaterial(self, position, container_node): position = str(position) diff --git a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py index 7a4c590acc..a79936bdcf 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py @@ -380,6 +380,8 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): printer.updateName(data["friendly_name"]) printer.updateKey(data["uuid"]) printer.updateType(data["machine_variant"]) + if "build_plate" in data: + printer.updateBuildplate(data["build_plate"]["name"]) if not data["enabled"]: printer.updateState("disabled") else: From 29792bbdd82ff62a4cc782e515a76058d4ce954f Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 7 Mar 2018 11:42:57 +0100 Subject: [PATCH 151/446] Reschedule update upon incomplete data in MaterialManager CURA-5056 --- cura/Machines/MaterialManager.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cura/Machines/MaterialManager.py b/cura/Machines/MaterialManager.py index 56577b5655..92bdbd0e86 100644 --- a/cura/Machines/MaterialManager.py +++ b/cura/Machines/MaterialManager.py @@ -107,7 +107,7 @@ class MaterialManager(QObject): Logger.log("e", "Missing root material node for [%s]. Probably caused by update using incomplete data." " Check all related signals for further debugging.", material_group.name) - # Do nothing here, we wait for a next signal to trigger an update. + self._update_timer.start() return guid = material_group.root_material_node.metadata["GUID"] self._guid_material_groups_map[guid].append(material_group) @@ -217,6 +217,7 @@ class MaterialManager(QObject): self.materialsUpdated.emit() def _updateMaps(self): + Logger.log("i", "Updating material lookup data ...") self.initialize() def _onContainerMetadataChanged(self, container): From 77e3be68b3de78924088aaf236fbc78eaaa3031d Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 7 Mar 2018 13:23:25 +0100 Subject: [PATCH 152/446] Add removeMaterialByRootId() in MaterialManager CURA-5056 --- cura/Machines/MaterialManager.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/cura/Machines/MaterialManager.py b/cura/Machines/MaterialManager.py index 92bdbd0e86..89b3a76f9a 100644 --- a/cura/Machines/MaterialManager.py +++ b/cura/Machines/MaterialManager.py @@ -371,6 +371,16 @@ class MaterialManager(QObject): material_diameter, root_material_id) return node + def removeMaterialByRootId(self, root_material_id: str): + material_group = self.getMaterialGroup(root_material_id) + if not material_group: + Logger.log("i", "Unable to remove the material with id %s, because it doesn't exist.", root_material_id) + return + + nodes_to_remove = [material_group.root_material_node] + material_group.derived_material_node_list + for node in nodes_to_remove: + self._container_registry.removeContainer(node.metadata["id"]) + # # Methods for GUI # @@ -394,14 +404,7 @@ class MaterialManager(QObject): @pyqtSlot("QVariant") def removeMaterial(self, material_node: "MaterialNode"): root_material_id = material_node.metadata["base_file"] - material_group = self.getMaterialGroup(root_material_id) - if not material_group: - Logger.log("d", "Unable to remove the material with id %s, because it doesn't exist.", root_material_id) - return - - nodes_to_remove = [material_group.root_material_node] + material_group.derived_material_node_list - for node in nodes_to_remove: - self._container_registry.removeContainer(node.metadata["id"]) + self.removeMaterialByRootId(root_material_id) # # Creates a duplicate of a material, which has the same GUID and base_file metadata. From 618bcebd8251beb7b74298442b4504a9bfbec77a Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 7 Mar 2018 13:24:22 +0100 Subject: [PATCH 153/446] Fix create new for conflicting materials in project loading CURA-5056 --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 74 +++++++++++++++++---- 1 file changed, 60 insertions(+), 14 deletions(-) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 6b56ec89f5..01ca136bcf 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -97,6 +97,14 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # In Cura 2.5 and 2.6, the empty profiles used to have those long names self._old_empty_profile_id_dict = {"empty_%s" % k: "empty" for k in ["material", "variant"]} + self._old_new_materials = {} + self._materials_to_select = {} + + def _clearState(self): + self._id_mapping = {} + self._old_new_materials = {} + self._materials_to_select = {} + ## Get a unique name based on the old_id. This is different from directly calling the registry in that it caches results. # This has nothing to do with speed, but with getting consistent new naming for instances & objects. def getNewId(self, old_id): @@ -449,10 +457,15 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # To avoid this, we postpone all signals so they don't get emitted immediately. But, please also be aware that, # because of this, do not expect to have the latest data in the lookup tables in project loading. # - with postponeSignals(*signals, compress = CompressTechnique.CompressSingle): + with postponeSignals(*signals, compress = CompressTechnique.NoCompression): return self._read(file_name) def _read(self, file_name): + application = CuraApplication.getInstance() + material_manager = application.getMaterialManager() + + self._clearState() + archive = zipfile.ZipFile(file_name, "r") cura_file_names = [name for name in archive.namelist() if name.startswith("Cura/")] @@ -545,31 +558,41 @@ class ThreeMFWorkspaceReader(WorkspaceReader): if self._material_container_suffix is None: self._material_container_suffix = ContainerRegistry.getMimeTypeForContainer(xml_material_profile).suffixes[0] if xml_material_profile: + to_deserialize_material = False material_container_files = [name for name in cura_file_names if name.endswith(self._material_container_suffix)] for material_container_file in material_container_files: container_id = self._stripFileToId(material_container_file) + need_new_name = False materials = self._container_registry.findInstanceContainers(id = container_id) if not materials: - material_container = xml_material_profile(container_id) - material_container.deserialize(archive.open(material_container_file).read().decode("utf-8"), - file_name = material_container_file) - containers_to_add.append(material_container) + # No material found, deserialize this material later and add it + to_deserialize_material = True else: material_container = materials[0] + old_material_root_id = material_container.getMetaDataEntry("base_file") if not self._container_registry.isReadOnly(container_id): # Only create new materials if they are not read only. + to_deserialize_material = True + if self._resolve_strategies["material"] == "override": - material_container.deserialize(archive.open(material_container_file).read().decode("utf-8"), - file_name = material_container_file) + # Remove the old materials and then deserialize the one from the project + root_material_id = material_container.getMetaDataEntry("base_file") + material_manager.removeMaterialByRootId(root_material_id) elif self._resolve_strategies["material"] == "new": # Note that we *must* deserialize it with a new ID, as multiple containers will be # auto created & added. - material_container = xml_material_profile(self.getNewId(container_id)) - material_container.deserialize(archive.open(material_container_file).read().decode("utf-8"), - file_name = material_container_file) - containers_to_add.append(material_container) + container_id = self.getNewId(container_id) + self._old_new_materials[old_material_root_id] = container_id + need_new_name = True - material_containers.append(material_container) + if to_deserialize_material: + material_container = xml_material_profile(container_id) + material_container.deserialize(archive.open(material_container_file).read().decode("utf-8"), + file_name = container_id + "." + self._material_container_suffix) + if need_new_name: + new_name = ContainerRegistry.getInstance().uniqueName(material_container.getName()) + material_container.setName(new_name) + containers_to_add.append(material_container) Job.yieldThread() Logger.log("d", "Workspace loading is checking instance containers...") @@ -1081,11 +1104,18 @@ class ThreeMFWorkspaceReader(WorkspaceReader): old_to_new_material_dict[old_id] = each_material break + global_stack.quality = empty_quality_container + # replace old material in global and extruder stacks with new self._replaceStackMaterialWithNew(global_stack, old_to_new_material_dict) if extruder_stacks: - for each_extruder_stack in extruder_stacks: - self._replaceStackMaterialWithNew(each_extruder_stack, old_to_new_material_dict) + for extruder_stack in extruder_stacks: + if extruder_stack.material.getId() in ("empty", "empty_material"): + continue + old_root_material_id = extruder_stack.material.getMetaDataEntry("base_file") + if old_root_material_id in self._old_new_materials: + new_root_material_id = self._old_new_materials[old_root_material_id] + self._materials_to_select[extruder_stack.getMetaDataEntry("position")] = new_root_material_id if extruder_stacks: for stack in extruder_stacks: @@ -1123,6 +1153,22 @@ class ThreeMFWorkspaceReader(WorkspaceReader): def _updateActiveMachine(self, global_stack): # Actually change the active machine. machine_manager = Application.getInstance().getMachineManager() + material_manager = Application.getInstance().getMaterialManager() + + # Switch materials if new materials are created due to conflicts + # We do it here because MaterialManager hasn't been updated in _read() yet. + for position, root_material_id in self._materials_to_select.items(): + extruder_stack = global_stack.extruders[position] + material_diameter = extruder_stack.materialDiameter + material_node = material_manager.getMaterialNode(global_stack.getMetaDataEntry("definition"), + extruder_stack.variant.getName(), + material_diameter, root_material_id) + if material_node is None: + Application.getInstance().callLater(self._updateActiveMachine, global_stack) + return + extruder_stack.material = material_node.getContainer() + Logger.log("d", "Changed extruder [%s] to material [%s]", position, root_material_id) + machine_manager.setActiveMachine(global_stack.getId()) # Notify everything/one that is to notify about changes. From 16cebe35ef381bd31b6bc33f317dd8f7edd1b71b Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 7 Mar 2018 16:41:03 +0100 Subject: [PATCH 154/446] CURA-4400 added docs to new functions --- cura/Scene/CuraSceneNode.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cura/Scene/CuraSceneNode.py b/cura/Scene/CuraSceneNode.py index 588fb75667..b29108d636 100644 --- a/cura/Scene/CuraSceneNode.py +++ b/cura/Scene/CuraSceneNode.py @@ -78,6 +78,7 @@ class CuraSceneNode(SceneNode): 1.0 ] + ## Return if the provided bbox collides with the bbox of this scene node def collidesWithBbox(self, check_bbox): bbox = self.getBoundingBox() @@ -87,6 +88,7 @@ class CuraSceneNode(SceneNode): return False + ## Return if any area collides with the convex hull of this scene node def collidesWithArea(self, areas): convex_hull = self.callDecoration("getConvexHull") if convex_hull: From a02486e85a71a4aa04cc4820dc649d62fef5041c Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Wed, 7 Mar 2018 17:15:56 +0100 Subject: [PATCH 155/446] Added status icon --- resources/qml/MachineSelection.qml | 40 ++++++++++++----------- resources/qml/Menus/PrinterStatusIcon.qml | 27 +++++++++++++++ resources/themes/cura-light/theme.json | 2 ++ 3 files changed, 50 insertions(+), 19 deletions(-) create mode 100644 resources/qml/Menus/PrinterStatusIcon.qml diff --git a/resources/qml/MachineSelection.qml b/resources/qml/MachineSelection.qml index e40731f3ca..b266b0c839 100644 --- a/resources/qml/MachineSelection.qml +++ b/resources/qml/MachineSelection.qml @@ -10,35 +10,28 @@ import UM 1.2 as UM import Cura 1.0 as Cura import "Menus" -ToolButton -{ +ToolButton { + property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0 text: Cura.MachineManager.activeMachineName tooltip: Cura.MachineManager.activeMachineName - style: ButtonStyle - { - background: Rectangle - { - color: - { - if(control.pressed) - { + style: ButtonStyle { + background: Rectangle { + color: { + if (control.pressed) { return UM.Theme.getColor("sidebar_header_active"); } - else if(control.hovered) - { + else if (control.hovered) { return UM.Theme.getColor("sidebar_header_hover"); } - else - { + else { return UM.Theme.getColor("sidebar_header_bar"); } } Behavior on color { ColorAnimation { duration: 50; } } - UM.RecolorImage - { + UM.RecolorImage { id: downArrow anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right @@ -50,14 +43,23 @@ ToolButton color: UM.Theme.getColor("text_emphasis") source: UM.Theme.getIcon("arrow_bottom") } - Label - { + + PrinterStatusIcon { + visible: printerConnected + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + leftMargin: UM.Theme.getSize("default_margin").width + } + } + + Label { id: sidebarComboBoxLabel color: UM.Theme.getColor("sidebar_header_text_active") text: control.text; elide: Text.ElideRight; anchors.left: parent.left; - anchors.leftMargin: UM.Theme.getSize("default_margin").width * 2 + anchors.leftMargin: printerConnected ? UM.Theme.getSize("default_margin").width * 3 : UM.Theme.getSize("default_margin").width * 2 anchors.right: downArrow.left; anchors.rightMargin: control.rightMargin; anchors.verticalCenter: parent.verticalCenter; diff --git a/resources/qml/Menus/PrinterStatusIcon.qml b/resources/qml/Menus/PrinterStatusIcon.qml new file mode 100644 index 0000000000..a8c465dba8 --- /dev/null +++ b/resources/qml/Menus/PrinterStatusIcon.qml @@ -0,0 +1,27 @@ +// Copyright (c) 2017 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 +import QtQuick.Layouts 1.1 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +Item { + property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0 + width: childrenRect.width + height: childrenRect.height + Image { + id: statusIcon + width: UM.Theme.getSize("status_icon").width + height: UM.Theme.getSize("status_icon").height + sourceSize.width: width + sourceSize.height: width + source: printerConnected ? UM.Theme.getIcon("tab_status_connected") : UM.Theme.getIcon("tab_status_busy") + } +} + + + diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json index d97970e566..7c5d7bddec 100644 --- a/resources/themes/cura-light/theme.json +++ b/resources/themes/cura-light/theme.json @@ -360,6 +360,8 @@ "small_button": [2, 2], "small_button_icon": [1.5, 1.5], + "status_icon": [1.0, 1.0], + "topbar_logo_right_margin": [3, 0], "topbar_button": [8, 4], "topbar_button_icon": [1.2, 1.2], From e7294e1299c03aa54dcaa12ac9eeea22448dfb5e Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 7 Mar 2018 18:52:48 +0100 Subject: [PATCH 156/446] CURA-4870 Correctly look for the buildplate variants using the machine_buildplate_type that is also sent in the gcode and is the information that Cura gets from connect. Create a new dict in the VariantManager that maps the machine_buildplate_type with the right container --- cura/Machines/VariantManager.py | 26 ++++++++++++++++++- cura/Settings/MachineManager.py | 16 ++++-------- .../ClusterUM3OutputDevice.py | 2 +- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/cura/Machines/VariantManager.py b/cura/Machines/VariantManager.py index 6cb0a3d7b2..44ed9614f7 100644 --- a/cura/Machines/VariantManager.py +++ b/cura/Machines/VariantManager.py @@ -25,7 +25,7 @@ ALL_VARIANT_TYPES = (VariantType.BUILD_PLATE, VariantType.NOZZLE) # -# VariantManager is THE place to look for a specific variant. It maintains a variant lookup table with the following +# VariantManager is THE place to look for a specific variant. It maintains two variant lookup tables with the following # structure: # # [machine_definition_id] -> [variant_type] -> [variant_name] -> ContainerNode(metadata / container) @@ -35,6 +35,9 @@ ALL_VARIANT_TYPES = (VariantType.BUILD_PLATE, VariantType.NOZZLE) # -> "BB 0.8" # -> ... # +# [machine_definition_id] -> [machine_buildplate_type] -> ContainerNode(metadata / container) +# Example: "ultimaker3" -> "glass" (this is different from the variant name) -> ContainerNode +# # Note that the "container" field is not loaded in the beginning because it would defeat the purpose of lazy-loading. # A container is loaded when getVariant() is called to load a variant InstanceContainer. # @@ -44,6 +47,7 @@ class VariantManager: self._container_registry = container_registry # type: ContainerRegistry self._machine_to_variant_dict_map = dict() # -> + self._machine_to_buildplate_dict_map = dict() self._exclude_variant_id_list = ["empty_variant"] @@ -53,6 +57,7 @@ class VariantManager: # def initialize(self): self._machine_to_variant_dict_map = OrderedDict() + self._machine_to_buildplate_dict_map = OrderedDict() # Cache all variants from the container registry to a variant map for better searching and organization. variant_metadata_list = self._container_registry.findContainersMetadata(type = "variant") @@ -78,6 +83,22 @@ class VariantManager: variant_dict[variant_name] = ContainerNode(metadata = variant_metadata) + # If the variant is a buildplate then fill also the buildplate map + if variant_type == VariantType.BUILD_PLATE: + if variant_definition not in self._machine_to_buildplate_dict_map: + self._machine_to_buildplate_dict_map[variant_definition] = OrderedDict() + + variant_container = self._container_registry.findContainers(type = "variant", id = variant_metadata["id"]) + if not variant_container: + # ERROR: not variant container. This should never happen + raise RuntimeError("Not variant found [%s], type [%s] for machine [%s]" % + (variant_name, variant_type, variant_definition)) + buildplate_type = variant_container[0].getProperty("machine_buildplate_type", "value") + if buildplate_type not in self._machine_to_buildplate_dict_map[variant_definition]: + self._machine_to_variant_dict_map[variant_definition][buildplate_type] = dict() + + self._machine_to_buildplate_dict_map[variant_definition][buildplate_type] = variant_dict[variant_name] + # # Gets the variant InstanceContainer with the given information. # Almost the same as getVariantMetadata() except that this returns an InstanceContainer if present. @@ -109,3 +130,6 @@ class VariantManager: if preferred_variant_name: node = self.getVariantNode(machine_definition_id, preferred_variant_name, variant_type) return node + + def getBuildplateVariantNode(self, machine_definition_id: str, buildplate_type: str) -> Optional["ContainerNode"]: + return self._machine_to_buildplate_dict_map[machine_definition_id].get(buildplate_type) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 12146e927e..de7a08a65a 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -196,7 +196,7 @@ class MachineManager(QObject): extruder_configuration.hotendID = extruder.variant.getName() if extruder.variant != self._empty_variant_container else None self._current_printer_configuration.extruderConfigurations.append(extruder_configuration) - self._current_printer_configuration.buildplateConfiguration = self._global_container_stack.variant.getName() if self._global_container_stack.variant != self._empty_variant_container else None + self._current_printer_configuration.buildplateConfiguration = self._global_container_stack.getProperty("machine_buildplate_type", "value") if self._global_container_stack.variant != self._empty_variant_container else None self.currentConfigurationChanged.emit() @pyqtSlot(QObject, result = bool) @@ -1027,23 +1027,17 @@ class MachineManager(QObject): @pyqtSlot(QObject) def applyRemoteConfiguration(self, configuration: ConfigurationModel): self.blurSettings.emit() - with postponeSignals(*self._getContainerChangedSignals(), - compress=CompressTechnique.CompressPerParameterValue): + with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): for extruder_configuration in configuration.extruderConfigurations: position = str(extruder_configuration.position) - variant_container_node = self._variant_manager.getVariantNode( - self._global_container_stack.definition.getId(), extruder_configuration.hotendID) - material_container_node = self._material_manager.getMaterialNodeByType( - self._global_container_stack, extruder_configuration.hotendID, - extruder_configuration.material.guid) + variant_container_node = self._variant_manager.getVariantNode(self._global_container_stack.definition.getId(), extruder_configuration.hotendID) + material_container_node = self._material_manager.getMaterialNodeByType(self._global_container_stack, extruder_configuration.hotendID,extruder_configuration.material.guid) self._setVariantNode(position, variant_container_node) self._setMaterial(position, material_container_node) self._updateMaterialWithVariant(position) if configuration.buildplateConfiguration is not None: - global_variant_container_node = self._variant_manager.getVariantNode( - self._global_container_stack.definition.getId(), configuration.buildplateConfiguration, - variant_type=VariantType.BUILD_PLATE) + global_variant_container_node = self._variant_manager.getBuildplateVariantNode(self._global_container_stack.definition.getId(), configuration.buildplateConfiguration) self._setGlobalVariant(global_variant_container_node) self._updateQualityWithMaterial() diff --git a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py index a79936bdcf..8eeb8d91e7 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py @@ -381,7 +381,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): printer.updateKey(data["uuid"]) printer.updateType(data["machine_variant"]) if "build_plate" in data: - printer.updateBuildplate(data["build_plate"]["name"]) + printer.updateBuildplate(data["build_plate"]["type"]) if not data["enabled"]: printer.updateState("disabled") else: From 2818ff7f31d16d2affe89a118aef5bb83b70bb33 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 7 Mar 2018 19:40:44 +0100 Subject: [PATCH 157/446] CURA-4870 Fix binding loop in some components with the height property by changing the vertical alignments --- resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml | 3 +-- .../qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml | 3 +-- resources/qml/Menus/ConfigurationMenu/SyncButton.qml | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml index e4c4683869..be8c8bcb45 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml @@ -77,7 +77,6 @@ Rectangle UM.RecolorImage { id: buildplateIcon anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter width: UM.Theme.getSize("topbar_button_icon").width height: UM.Theme.getSize("topbar_button_icon").height sourceSize.width: width @@ -90,7 +89,7 @@ Rectangle { id: buildplateLabel anchors.left: buildplateIcon.right - anchors.verticalCenter: parent.verticalCenter + anchors.verticalCenter: buildplateIcon.verticalCenter anchors.leftMargin: Math.round(UM.Theme.getSize("default_margin").height / 2) text: configuration.buildplateConfiguration color: textColor diff --git a/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml b/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml index d34252adc4..ca1b666e69 100644 --- a/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml +++ b/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml @@ -27,7 +27,6 @@ Column id: extruderLabel text: catalog.i18nc("@label:extruder label", "Extruder") elide: Text.ElideRight - anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left font: UM.Theme.getFont("default") color: mainColor @@ -37,7 +36,7 @@ Column Item { id: extruderIconItem - anchors.verticalCenter: parent.verticalCenter + anchors.verticalCenter: extruderLabel.verticalCenter anchors.left: extruderLabel.right anchors.leftMargin: Math.round(UM.Theme.getSize("default_margin").width / 2) diff --git a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml index 3834f2ebd2..43cf4529cb 100644 --- a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml +++ b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml @@ -11,7 +11,7 @@ import Cura 1.0 as Cura Button { id: base - property var outputDevice: Cura.MachineManager.printerOutputDevices[0] != null ? Cura.MachineManager.printerOutputDevices[0] : null + property var outputDevice: Cura.MachineManager.printerOutputDevices[0] text: catalog.i18nc("@label:sync indicator", "No match") width: parent.width height: parent.height From be8fc9f3f1c5eb2e7dcda6cae3a10c0762783ba4 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 7 Mar 2018 19:59:06 +0100 Subject: [PATCH 158/446] CURA-4870 Manage the case when there is an empty material or variant in the printer and Cura needs to apply this configuration --- cura/Settings/MachineManager.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index de7a08a65a..767021e2df 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1032,13 +1032,22 @@ class MachineManager(QObject): position = str(extruder_configuration.position) variant_container_node = self._variant_manager.getVariantNode(self._global_container_stack.definition.getId(), extruder_configuration.hotendID) material_container_node = self._material_manager.getMaterialNodeByType(self._global_container_stack, extruder_configuration.hotendID,extruder_configuration.material.guid) - self._setVariantNode(position, variant_container_node) - self._setMaterial(position, material_container_node) + if variant_container_node: + self._setVariantNode(position, variant_container_node) + else: + self._global_container_stack.extruders[position].variant = self._empty_variant_container + + if material_container_node: + self._setMaterial(position, material_container_node) + else: + self._global_container_stack.extruders[position].material = self._empty_material_container self._updateMaterialWithVariant(position) if configuration.buildplateConfiguration is not None: global_variant_container_node = self._variant_manager.getBuildplateVariantNode(self._global_container_stack.definition.getId(), configuration.buildplateConfiguration) self._setGlobalVariant(global_variant_container_node) + else: + self._global_container_stack.variant = self._empty_variant_container self._updateQualityWithMaterial() @pyqtSlot("QVariant") From 3629c3959e54fe10d7dedb37fe67421d81bf25ef Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 7 Mar 2018 22:33:15 +0100 Subject: [PATCH 159/446] CURA-4870 Match the printer type in the dropdown with one of the available printer types in the group --- cura/Settings/MachineManager.py | 17 ++++ .../ConfigurationListView.qml | 2 +- .../Menus/ConfigurationMenu/SyncButton.qml | 13 +-- resources/qml/Menus/PrinterTypeMenu.qml | 8 +- resources/qml/SidebarHeader.qml | 81 ++++++++++--------- 5 files changed, 72 insertions(+), 49 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 767021e2df..be30c83dda 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -451,6 +451,12 @@ class MachineManager(QObject): def stacksHaveErrors(self) -> bool: return bool(self._stacks_have_errors) + @pyqtProperty(str, notify = globalContainerChanged) + def activeMachineDefinitionName(self) -> str: + if self._global_container_stack: + return self._global_container_stack.definition.getName() + return "" + @pyqtProperty(str, notify = globalContainerChanged) def activeMachineName(self) -> str: if self._global_container_stack: @@ -1024,6 +1030,17 @@ class MachineManager(QObject): self._setMaterial(position, new_material) continue + def switchPrinterType(self, machine_type): + container_registry = ContainerRegistry.getInstance() + machine_definition = container_registry.findDefinitionContainers(name = machine_type)[0] + self._global_container_stack.definition = machine_definition + self.globalContainerChanged.emit() + # machine_stack = CuraStackBuilder.createMachine("ultimaker_s5" + "_instance", "ultimaker_s5") + # # if not machine_stack: + # # raise Exception("No machine found for ID {}".format(machine_id)) + # Logger.log("d", "Setting active machine to %s", machine_stack.getId()) + # self.setActiveMachine(machine_stack.getId()) + @pyqtSlot(QObject) def applyRemoteConfiguration(self, configuration: ConfigurationModel): self.blurSettings.emit() diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml index 037fadcb22..be11240831 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -57,7 +57,7 @@ Column section.criteria: ViewSection.FullString section.delegate: sectionHeading - model: outputDevice.uniqueConfigurations + model: (ouputDevice != null) ? outputDevice.uniqueConfigurations : [] delegate: ConfigurationItem { width: parent.width - UM.Theme.getSize("default_margin").width diff --git a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml index 43cf4529cb..58b738323e 100644 --- a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml +++ b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml @@ -18,13 +18,16 @@ Button function updateOnSync() { - for (var index in outputDevice.uniqueConfigurations) + if (outputDevice != undefined) { - var configuration = outputDevice.uniqueConfigurations[index] - if (Cura.MachineManager.matchesConfiguration(configuration)) + for (var index in outputDevice.uniqueConfigurations) { - base.text = catalog.i18nc("@label:sync indicator", "Matched") - return + var configuration = outputDevice.uniqueConfigurations[index] + if (Cura.MachineManager.matchesConfiguration(configuration)) + { + base.text = catalog.i18nc("@label:sync indicator", "Matched") + return + } } } base.text = catalog.i18nc("@label:sync indicator", "No match") diff --git a/resources/qml/Menus/PrinterTypeMenu.qml b/resources/qml/Menus/PrinterTypeMenu.qml index b4fdb0a1d4..e84f53a4ba 100644 --- a/resources/qml/Menus/PrinterTypeMenu.qml +++ b/resources/qml/Menus/PrinterTypeMenu.qml @@ -1,8 +1,8 @@ // Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. -import QtQuick 2.2 -import QtQuick.Controls 1.1 +import QtQuick 2.7 +import QtQuick.Controls 1.4 import UM 1.3 as UM import Cura 1.0 as Cura @@ -16,12 +16,12 @@ Menu Instantiator { id: printerTypeInstantiator - model: outputDevice != null ? outputDevice.connectedPrintersTypeCount : null + model: outputDevice != null ? outputDevice.connectedPrintersTypeCount : [] MenuItem { text: modelData.machine_type checkable: true - checked: false + checked: Cura.MachineManager.activeMachineDefinitionName == modelData.machine_type exclusiveGroup: group // onTriggered: // { diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 7acc58c52a..8e12cd017b 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -17,6 +17,7 @@ Column property int currentExtruderIndex: Cura.ExtruderManager.activeExtruderIndex; property bool currentExtruderVisible: extrudersList.visible; property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0 + property bool hasManyPrinterTypes: printerConnected ? Cura.MachineManager.printerOutputDevices[0].connectedPrintersTypeCount.length > 1 : false spacing: Math.round(UM.Theme.getSize("sidebar_margin").width * 0.9) @@ -35,45 +36,6 @@ Column width: height } - // Printer Type Row - Item - { - id: printerTypeSelectionRow - height: UM.Theme.getSize("sidebar_setup").height - visible: printerConnected && !sidebar.monitoringPrint && !sidebar.hideSettings - - anchors - { - left: parent.left - leftMargin: UM.Theme.getSize("sidebar_margin").width - right: parent.right - rightMargin: UM.Theme.getSize("sidebar_margin").width - } - - Label - { - id: configurationLabel - text: catalog.i18nc("@label", "Printer type"); - width: Math.round(parent.width * 0.4 - UM.Theme.getSize("default_margin").width) - height: parent.height - verticalAlignment: Text.AlignVCenter - font: UM.Theme.getFont("default"); - color: UM.Theme.getColor("text"); - } - - ToolButton - { - id: printerTypeSelection - text: catalog.i18nc("@label", "Printer type"); - height: UM.Theme.getSize("setting_control").height - width: Math.round(parent.width * 0.7) + UM.Theme.getSize("sidebar_margin").width - anchors.right: parent.right - style: UM.Theme.styles.sidebar_header_button - activeFocusOnPress: true; - menu: PrinterTypeMenu { } - } - } - // Extruder Row Item { @@ -264,6 +226,47 @@ Column visible: !extruderSelectionRow.visible } + // Printer Type Row + Item + { + id: printerTypeSelectionRow + height: UM.Theme.getSize("sidebar_setup").height + visible: printerConnected && hasManyPrinterTypes && !sidebar.monitoringPrint && !sidebar.hideSettings + + anchors + { + left: parent.left + leftMargin: UM.Theme.getSize("sidebar_margin").width + right: parent.right + rightMargin: UM.Theme.getSize("sidebar_margin").width + } + + Label + { + id: configurationLabel + text: catalog.i18nc("@label", "Printer type"); + width: Math.round(parent.width * 0.4 - UM.Theme.getSize("default_margin").width) + height: parent.height + verticalAlignment: Text.AlignVCenter + font: UM.Theme.getFont("default"); + color: UM.Theme.getColor("text"); + } + + ToolButton + { + id: printerTypeSelection + text: Cura.MachineManager.activeMachineDefinitionName + tooltip: Cura.MachineManager.activeMachineDefinitionName + height: UM.Theme.getSize("setting_control").height + width: Math.round(parent.width * 0.7) + UM.Theme.getSize("sidebar_margin").width + anchors.right: parent.right + style: UM.Theme.styles.sidebar_header_button + activeFocusOnPress: true; + + menu: PrinterTypeMenu { } + } + } + // Material Row Item { From ae5f1c34080aa1983697b33c119d3be146ea28c8 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 7 Mar 2018 22:49:27 +0100 Subject: [PATCH 160/446] CURA-4870 Add line separator between machine selector and sync button --- resources/qml/Sidebar.qml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml index 7a65a278eb..a93048cb26 100644 --- a/resources/qml/Sidebar.qml +++ b/resources/qml/Sidebar.qml @@ -88,12 +88,22 @@ Rectangle MachineSelection { id: machineSelection - width: base.width - configSelection.width + width: base.width - configSelection.width - separator.width height: UM.Theme.getSize("sidebar_header").height anchors.top: base.top anchors.left: parent.left } + Rectangle + { + id: separator + visible: configSelection.visible + width: visible ? Math.round(UM.Theme.getSize("sidebar_lining_thin").height / 2) : 0 + height: UM.Theme.getSize("sidebar_header").height + color: UM.Theme.getColor("sidebar_lining_thin") + anchors.left: machineSelection.right + } + ConfigurationSelection { id: configSelection visible: printerConnected && !sidebar.monitoringPrint && !sidebar.hideSettings From 86103b4a0f5db416985a1056c451e48e781a7f9a Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 7 Mar 2018 22:54:03 +0100 Subject: [PATCH 161/446] CURA-4870 Change text size of the selected printer --- resources/qml/MachineSelection.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/MachineSelection.qml b/resources/qml/MachineSelection.qml index b266b0c839..b9d8840f2f 100644 --- a/resources/qml/MachineSelection.qml +++ b/resources/qml/MachineSelection.qml @@ -63,7 +63,7 @@ ToolButton { anchors.right: downArrow.left; anchors.rightMargin: control.rightMargin; anchors.verticalCenter: parent.verticalCenter; - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("medium_bold") } } label: Label {} From 2a10c9a2d72dd4672032847e9856b222a63f7a55 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 8 Mar 2018 09:10:43 +0100 Subject: [PATCH 162/446] Move assertion in _performMerge() CURA-5070 --- cura/Settings/ContainerManager.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index f910f0c0e2..345c25ded9 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -389,8 +389,6 @@ class ContainerManager(QObject): return ContainerManager.getInstance() def _performMerge(self, merge_into, merge, clear_settings = True): - assert isinstance(merge, type(merge_into)) - if merge == merge_into: return From 4c7ec3920d4acb178e037f7c9ba2defe210be34b Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Thu, 8 Mar 2018 09:25:14 +0100 Subject: [PATCH 163/446] CURA-4870 Reduce text size of the Machine selector menu --- resources/qml/Menus/ConfigurationMenu/SyncButton.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml index 58b738323e..4a92db6e6b 100644 --- a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml +++ b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml @@ -78,7 +78,7 @@ Button anchors.right: downArrow.left anchors.rightMargin: control.rightMargin anchors.verticalCenter: parent.verticalCenter; - font: UM.Theme.getFont("medium_bold") + font: UM.Theme.getFont("medium") } } label: Label {} From 961b868424d39acec787b66da978d9818230fca0 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 8 Mar 2018 09:47:22 +0100 Subject: [PATCH 164/446] CURA-4400 fix updating quality slider --- resources/qml/SidebarSimple.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index 699365238a..b9b254e280 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -67,7 +67,7 @@ Item Connections { - target: Cura.QualityProfilesModel + target: Cura.QualityProfilesDropDownMenuModel onItemsChanged: qualityModel.update() } From ffccdd99c03d74f060a49a608009f7e706876fa8 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Thu, 8 Mar 2018 10:55:29 +0100 Subject: [PATCH 165/446] Added status icon --- cura/Settings/MachineManager.py | 6 ++++++ resources/qml/MachineSelection.qml | 8 +++++--- resources/qml/Menus/PrinterStatusIcon.qml | 11 ++++++----- resources/themes/cura-light/theme.json | 11 +++++++++-- 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index be30c83dda..7b9a4191ed 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -469,6 +469,12 @@ class MachineManager(QObject): return self._global_container_stack.getId() return "" + @pyqtProperty(str, notify = globalContainerChanged) + def activeMachineNetworkKey(self) -> str: + if self._global_container_stack: + return self._global_container_stack.getMetaDataEntry("um_network_key") + return "" + @pyqtProperty(QObject, notify = globalContainerChanged) def activeMachine(self) -> Optional["GlobalStack"]: return self._global_container_stack diff --git a/resources/qml/MachineSelection.qml b/resources/qml/MachineSelection.qml index b9d8840f2f..5ca6cda406 100644 --- a/resources/qml/MachineSelection.qml +++ b/resources/qml/MachineSelection.qml @@ -11,7 +11,8 @@ import Cura 1.0 as Cura import "Menus" ToolButton { - property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0 + property var isNetworkPrinter: Cura.MachineManager.activeMachineNetworkKey ? true : false + property var printerStatus: Cura.MachineManager.printerOutputDevices.length != 0 ? "connected" : "unknown" text: Cura.MachineManager.activeMachineName tooltip: Cura.MachineManager.activeMachineName @@ -45,7 +46,8 @@ ToolButton { } PrinterStatusIcon { - visible: printerConnected + visible: isNetworkPrinter + status: printerStatus anchors { verticalCenter: parent.verticalCenter left: parent.left @@ -59,7 +61,7 @@ ToolButton { text: control.text; elide: Text.ElideRight; anchors.left: parent.left; - anchors.leftMargin: printerConnected ? UM.Theme.getSize("default_margin").width * 3 : UM.Theme.getSize("default_margin").width * 2 + anchors.leftMargin: isNetworkPrinter ? UM.Theme.getSize("default_margin").width * 3 : UM.Theme.getSize("default_margin").width * 2 anchors.right: downArrow.left; anchors.rightMargin: control.rightMargin; anchors.verticalCenter: parent.verticalCenter; diff --git a/resources/qml/Menus/PrinterStatusIcon.qml b/resources/qml/Menus/PrinterStatusIcon.qml index a8c465dba8..d7106bf33d 100644 --- a/resources/qml/Menus/PrinterStatusIcon.qml +++ b/resources/qml/Menus/PrinterStatusIcon.qml @@ -10,16 +10,17 @@ import UM 1.2 as UM import Cura 1.0 as Cura Item { - property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0 + property var status: "unknown" width: childrenRect.width height: childrenRect.height - Image { + UM.RecolorImage { id: statusIcon - width: UM.Theme.getSize("status_icon").width - height: UM.Theme.getSize("status_icon").height + width: UM.Theme.getSize("printer_status_icon").width + height: UM.Theme.getSize("printer_status_icon").height sourceSize.width: width sourceSize.height: width - source: printerConnected ? UM.Theme.getIcon("tab_status_connected") : UM.Theme.getIcon("tab_status_busy") + color: UM.Theme.getColor("tab_status_" + parent.status ) + source: UM.Theme.getIcon("tab_status_" + parent.status ) } } diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json index 7c5d7bddec..1e3f9ce79a 100644 --- a/resources/themes/cura-light/theme.json +++ b/resources/themes/cura-light/theme.json @@ -307,7 +307,14 @@ "configuration_item_text_active": [0, 0, 0, 255], "configuration_item_border": [127, 127, 127, 255], "configuration_item_border_active": [12, 169, 227, 32], - "configuration_item_border_hover": [12, 169, 227, 255] + "configuration_item_border_hover": [12, 169, 227, 255], + + "tab_status_busy": [255, 255, 255, 255], + "tab_status_connected": [12, 169, 227, 255], + "tab_status_finished": [255, 255, 255, 255], + "tab_status_paused": [255, 255, 255, 255], + "tab_status_stopped": [255, 255, 255, 255], + "tab_status_unknown": [200, 200, 200, 255] }, "sizes": { @@ -360,7 +367,7 @@ "small_button": [2, 2], "small_button_icon": [1.5, 1.5], - "status_icon": [1.0, 1.0], + "printer_status_icon": [1.0, 1.0], "topbar_logo_right_margin": [3, 0], "topbar_button": [8, 4], From 1a57e9323b3acf7f69e7b3b732c93b6a669062dd Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Thu, 8 Mar 2018 12:54:59 +0100 Subject: [PATCH 166/446] Improved status icon size --- resources/qml/MachineSelection.qml | 7 ++++--- resources/themes/cura-light/theme.json | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/resources/qml/MachineSelection.qml b/resources/qml/MachineSelection.qml index 5ca6cda406..cce2bbea7b 100644 --- a/resources/qml/MachineSelection.qml +++ b/resources/qml/MachineSelection.qml @@ -46,12 +46,13 @@ ToolButton { } PrinterStatusIcon { + id: printerStatusIcon visible: isNetworkPrinter status: printerStatus anchors { verticalCenter: parent.verticalCenter left: parent.left - leftMargin: UM.Theme.getSize("default_margin").width + leftMargin: UM.Theme.getSize("sidebar_margin").width } } @@ -60,8 +61,8 @@ ToolButton { color: UM.Theme.getColor("sidebar_header_text_active") text: control.text; elide: Text.ElideRight; - anchors.left: parent.left; - anchors.leftMargin: isNetworkPrinter ? UM.Theme.getSize("default_margin").width * 3 : UM.Theme.getSize("default_margin").width * 2 + anchors.left: isNetworkPrinter ? printerStatusIcon.right : parent.left; + anchors.leftMargin: isNetworkPrinter ? UM.Theme.getSize("sidebar_lining").width : UM.Theme.getSize("sidebar_margin").width anchors.right: downArrow.left; anchors.rightMargin: control.rightMargin; anchors.verticalCenter: parent.verticalCenter; diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json index 1e3f9ce79a..4cdff3c296 100644 --- a/resources/themes/cura-light/theme.json +++ b/resources/themes/cura-light/theme.json @@ -367,7 +367,7 @@ "small_button": [2, 2], "small_button_icon": [1.5, 1.5], - "printer_status_icon": [1.0, 1.0], + "printer_status_icon": [1.2, 1.2], "topbar_logo_right_margin": [3, 0], "topbar_button": [8, 4], From a9976e93c13bcdf7c6061f852a4f97bcf103c1b2 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 8 Mar 2018 13:57:11 +0100 Subject: [PATCH 167/446] CURA-4400 fix per object setting change reslicing without reevaluate is non printing mesh all the time --- cura/Settings/SettingOverrideDecorator.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cura/Settings/SettingOverrideDecorator.py b/cura/Settings/SettingOverrideDecorator.py index 357bc87024..9054d9d04f 100644 --- a/cura/Settings/SettingOverrideDecorator.py +++ b/cura/Settings/SettingOverrideDecorator.py @@ -94,8 +94,13 @@ class SettingOverrideDecorator(SceneNodeDecorator): return any(bool(self._stack.getProperty(setting, "value")) for setting in self._non_printing_mesh_settings) def _onSettingChanged(self, instance, property_name): # Reminder: 'property' is a built-in function - # Trigger slice/need slicing if the value has changed. - if property_name == "value" and instance in self._non_printing_mesh_settings: + object_has_instance_setting = False + for container in self._stack.getContainers(): + if container.hasProperty(instance, "value"): + object_has_instance_setting = True + break + if property_name == "value" and object_has_instance_setting: + # Trigger slice/need slicing if the value has changed. self._is_non_printing_mesh = self.evaluateIsNonPrintingMesh() Application.getInstance().getBackend().needsSlicing() From 1bde7a6228cef6b9ba7ac87d531ec239ca8dd01a Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Thu, 8 Mar 2018 14:01:19 +0100 Subject: [PATCH 168/446] CURA-4870 Set the correct version of the QtQuick.Controls to be compliant with v5.8 --- .../qml/Menus/ConfigurationMenu/ConfigurationSelection.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml index 4097df229b..10d8f60e90 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml @@ -2,7 +2,7 @@ // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.7 -import QtQuick.Controls 2.3 +import QtQuick.Controls 2.0 import QtQuick.Controls.Styles 1.4 import UM 1.2 as UM From ae094c8201c639c62a89168eaaf417d6fed90d31 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Thu, 8 Mar 2018 14:02:22 +0100 Subject: [PATCH 169/446] CURA-4870 Disable the connect button in the discovery list when the printer is not a host of printers. --- plugins/UM3NetworkPrinting/DiscoverUM3Action.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml b/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml index c0cb5a78b7..a5d13b2cdf 100644 --- a/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml +++ b/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml @@ -303,7 +303,7 @@ Cura.MachineAction Button { text: catalog.i18nc("@action:button", "Connect") - enabled: (base.selectedDevice && base.completeProperties) ? true : false + enabled: (base.selectedDevice && base.completeProperties && base.selectedDevice.clusterSize > 0) ? true : false onClicked: connectToPrinter() } } From 375770818b762a9d75b159e260b5c879fa15e7c6 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 8 Mar 2018 14:23:14 +0100 Subject: [PATCH 170/446] Add typing for _getPrinterOutputDevices Then my IDE will give hints on where a printer of the wrong type is being added. Contributes to issue CURA-5061. --- plugins/UltimakerMachineActions/BedLevelMachineAction.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/UltimakerMachineActions/BedLevelMachineAction.py b/plugins/UltimakerMachineActions/BedLevelMachineAction.py index 04b6cf1acc..738fd81c63 100644 --- a/plugins/UltimakerMachineActions/BedLevelMachineAction.py +++ b/plugins/UltimakerMachineActions/BedLevelMachineAction.py @@ -1,3 +1,8 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from typing import List + from cura.MachineAction import MachineAction from cura.PrinterOutputDevice import PrinterOutputDevice @@ -32,7 +37,7 @@ class BedLevelMachineAction(MachineAction): printer_output_devices[0].moveHead(0, 0, 3) printer_output_devices[0].homeHead() - def _getPrinterOutputDevices(self): + def _getPrinterOutputDevices(self) -> List[PrinterOutputDevice]: return [printer_output_device for printer_output_device in Application.getInstance().getOutputDeviceManager().getOutputDevices() if isinstance(printer_output_device, PrinterOutputDevice)] @pyqtSlot() From f576b1f1170deb28d3a755d461201161817e2e88 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 8 Mar 2018 14:07:01 +0100 Subject: [PATCH 171/446] CURA-4400 fix crash when switching from disabled 1st extruder to single extruder machine --- cura/Settings/MachineManager.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index e3338e9ca7..d6c4671691 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -299,6 +299,7 @@ class MachineManager(QObject): containers = container_registry.findContainerStacks(id = stack_id) if containers: global_stack = containers[0] + self._default_extruder_position = "0" # start off with position 0, later on update the default extruder ExtruderManager.getInstance().setActiveExtruderIndex(0) # Switch to first extruder self._global_container_stack = global_stack Application.getInstance().setGlobalContainerStack(global_stack) From 138f77179dd6e1190dd8defc87858bbee5a57a6a Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 8 Mar 2018 14:31:55 +0100 Subject: [PATCH 172/446] CURA-4400 fix errors when switch or adding to new machine --- cura/Settings/MachineManager.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index d6c4671691..5afecb8ef5 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -192,6 +192,9 @@ class MachineManager(QObject): # Update the local global container stack reference self._global_container_stack = Application.getInstance().getGlobalContainerStack() + if self._global_container_stack: + self.updateDefaultExtruder() + self.updateNumberExtrudersEnabled() self.globalContainerChanged.emit() # after switching the global stack we reconnect all the signals and set the variant and material references @@ -299,14 +302,11 @@ class MachineManager(QObject): containers = container_registry.findContainerStacks(id = stack_id) if containers: global_stack = containers[0] - self._default_extruder_position = "0" # start off with position 0, later on update the default extruder ExtruderManager.getInstance().setActiveExtruderIndex(0) # Switch to first extruder self._global_container_stack = global_stack Application.getInstance().setGlobalContainerStack(global_stack) ExtruderManager.getInstance()._globalContainerStackChanged() self._initMachineState(containers[0]) - self.updateDefaultExtruder() - self.updateNumberExtrudersEnabled() self._onGlobalContainerChanged() self.__emitChangedSignals() From 5135a972a2e7d95d57f8d955c0230f849f62df6f Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 8 Mar 2018 14:32:10 +0100 Subject: [PATCH 173/446] CURA-4400 code style --- resources/qml/Cura.qml | 12 ++++++++---- resources/qml/Settings/SettingExtruder.qml | 9 ++++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 185e3563a5..c81281f0d7 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -194,22 +194,26 @@ UM.MainWindow NozzleMenu { title: Cura.MachineManager.activeDefinitionVariantsName; visible: Cura.MachineManager.hasVariants; extruderIndex: index } MaterialMenu { title: catalog.i18nc("@title:menu", "&Material"); visible: Cura.MachineManager.hasMaterials; extruderIndex: index } - MenuSeparator { + MenuSeparator + { visible: Cura.MachineManager.hasVariants || Cura.MachineManager.hasMaterials } - MenuItem { + MenuItem + { text: catalog.i18nc("@action:inmenu", "Set as Active Extruder") onTriggered: Cura.MachineManager.setExtruderIndex(model.index) } - MenuItem { + MenuItem + { text: catalog.i18nc("@action:inmenu", "Enable Extruder") onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, true) visible: !Cura.MachineManager.getExtruder(model.index).isEnabled } - MenuItem { + MenuItem + { text: catalog.i18nc("@action:inmenu", "Disable Extruder") onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false) visible: Cura.MachineManager.getExtruder(model.index).isEnabled diff --git a/resources/qml/Settings/SettingExtruder.qml b/resources/qml/Settings/SettingExtruder.qml index 2a2e213142..35ad198edf 100644 --- a/resources/qml/Settings/SettingExtruder.qml +++ b/resources/qml/Settings/SettingExtruder.qml @@ -17,7 +17,8 @@ SettingItem id: control anchors.fill: parent - model: Cura.ExtrudersModel { + model: Cura.ExtrudersModel + { onModelChanged: { control.color = getItem(control.currentIndex).color; } @@ -27,10 +28,12 @@ SettingItem onActivated: { - if (model.getItem(index).enabled) { + if (model.getItem(index).enabled) + { forceActiveFocus(); propertyProvider.setPropertyValue("value", model.getItem(index).index); - } else { + } else + { currentIndex = propertyProvider.properties.value; // keep the old value } } From 676f9b84747337eaf80262c5d2e632c60d91d272 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 8 Mar 2018 15:18:32 +0100 Subject: [PATCH 174/446] Switch if-statement around for fail checking This reduces indent and makes the control flow a bit easier to read in my opinion. Contributes to issue CURA-5061. --- .../BedLevelMachineAction.py | 59 +++++++++++-------- 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/plugins/UltimakerMachineActions/BedLevelMachineAction.py b/plugins/UltimakerMachineActions/BedLevelMachineAction.py index 738fd81c63..b6ecdeec34 100644 --- a/plugins/UltimakerMachineActions/BedLevelMachineAction.py +++ b/plugins/UltimakerMachineActions/BedLevelMachineAction.py @@ -10,6 +10,7 @@ from UM.FlameProfiler import pyqtSlot from UM.Application import Application from UM.i18n import i18nCatalog +from UM.Logger import Logger catalog = i18nCatalog("cura") @@ -32,10 +33,13 @@ class BedLevelMachineAction(MachineAction): def startBedLeveling(self): self._bed_level_position = 0 printer_output_devices = self._getPrinterOutputDevices() - if printer_output_devices: - printer_output_devices[0].homeBed() - printer_output_devices[0].moveHead(0, 0, 3) - printer_output_devices[0].homeHead() + if not printer_output_devices: + Logger.log("e", "Can't start bed levelling. The printer connection seems to have been lost.") + return + + printer_output_devices[0].homeBed() + printer_output_devices[0].moveHead(0, 0, 3) + printer_output_devices[0].homeHead() def _getPrinterOutputDevices(self) -> List[PrinterOutputDevice]: return [printer_output_device for printer_output_device in Application.getInstance().getOutputDeviceManager().getOutputDevices() if isinstance(printer_output_device, PrinterOutputDevice)] @@ -43,26 +47,29 @@ class BedLevelMachineAction(MachineAction): @pyqtSlot() def moveToNextLevelPosition(self): output_devices = self._getPrinterOutputDevices() - if output_devices: # We found at least one output device - output_device = output_devices[0] + if not output_devices: #No output devices. Can't move. + Logger.log("e", "Can't move to the next position. The printer connection seems to have been lost.") + return - if self._bed_level_position == 0: - output_device.moveHead(0, 0, 3) - output_device.homeHead() - output_device.moveHead(0, 0, 3) - output_device.moveHead(Application.getInstance().getGlobalContainerStack().getProperty("machine_width", "value") - 10, 0, 0) - output_device.moveHead(0, 0, -3) - self._bed_level_position += 1 - elif self._bed_level_position == 1: - output_device.moveHead(0, 0, 3) - output_device.moveHead(-Application.getInstance().getGlobalContainerStack().getProperty("machine_width", "value" ) / 2, Application.getInstance().getGlobalContainerStack().getProperty("machine_depth", "value") - 10, 0) - output_device.moveHead(0, 0, -3) - self._bed_level_position += 1 - elif self._bed_level_position == 2: - output_device.moveHead(0, 0, 3) - output_device.moveHead(-Application.getInstance().getGlobalContainerStack().getProperty("machine_width", "value") / 2 + 10, -(Application.getInstance().getGlobalContainerStack().getProperty("machine_depth", "value") + 10), 0) - output_device.moveHead(0, 0, -3) - self._bed_level_position += 1 - elif self._bed_level_position >= 3: - output_device.sendCommand("M18") # Turn off all motors so the user can move the axes - self.setFinished() \ No newline at end of file + output_device = output_devices[0] + + if self._bed_level_position == 0: + output_device.moveHead(0, 0, 3) + output_device.homeHead() + output_device.moveHead(0, 0, 3) + output_device.moveHead(Application.getInstance().getGlobalContainerStack().getProperty("machine_width", "value") - 10, 0, 0) + output_device.moveHead(0, 0, -3) + self._bed_level_position += 1 + elif self._bed_level_position == 1: + output_device.moveHead(0, 0, 3) + output_device.moveHead(-Application.getInstance().getGlobalContainerStack().getProperty("machine_width", "value" ) / 2, Application.getInstance().getGlobalContainerStack().getProperty("machine_depth", "value") - 10, 0) + output_device.moveHead(0, 0, -3) + self._bed_level_position += 1 + elif self._bed_level_position == 2: + output_device.moveHead(0, 0, 3) + output_device.moveHead(-Application.getInstance().getGlobalContainerStack().getProperty("machine_width", "value") / 2 + 10, -(Application.getInstance().getGlobalContainerStack().getProperty("machine_depth", "value") + 10), 0) + output_device.moveHead(0, 0, -3) + self._bed_level_position += 1 + elif self._bed_level_position >= 3: + output_device.sendCommand("M18") # Turn off all motors so the user can move the axes + self.setFinished() \ No newline at end of file From b4cf25cb7f9b7653fc7b6bfe531d7348a111419d Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 8 Mar 2018 15:29:48 +0100 Subject: [PATCH 175/446] Call moveHead and moveBed on the printer model Instead of on the output device. This function was moved, which caused Cura to crash when the bed levelling procedure was called. Contributes to issue CURA-5061. --- .../BedLevelMachineAction.py | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/plugins/UltimakerMachineActions/BedLevelMachineAction.py b/plugins/UltimakerMachineActions/BedLevelMachineAction.py index b6ecdeec34..6a8a337d8c 100644 --- a/plugins/UltimakerMachineActions/BedLevelMachineAction.py +++ b/plugins/UltimakerMachineActions/BedLevelMachineAction.py @@ -32,14 +32,16 @@ class BedLevelMachineAction(MachineAction): @pyqtSlot() def startBedLeveling(self): self._bed_level_position = 0 + printer_output_devices = self._getPrinterOutputDevices() if not printer_output_devices: Logger.log("e", "Can't start bed levelling. The printer connection seems to have been lost.") return + printer = printer_output_devices[0].activePrinter - printer_output_devices[0].homeBed() - printer_output_devices[0].moveHead(0, 0, 3) - printer_output_devices[0].homeHead() + printer.homeBed() + printer.moveHead(0, 0, 3) + printer.homeHead() def _getPrinterOutputDevices(self) -> List[PrinterOutputDevice]: return [printer_output_device for printer_output_device in Application.getInstance().getOutputDeviceManager().getOutputDevices() if isinstance(printer_output_device, PrinterOutputDevice)] @@ -50,26 +52,25 @@ class BedLevelMachineAction(MachineAction): if not output_devices: #No output devices. Can't move. Logger.log("e", "Can't move to the next position. The printer connection seems to have been lost.") return - - output_device = output_devices[0] + printer = output_devices[0].activePrinter if self._bed_level_position == 0: - output_device.moveHead(0, 0, 3) - output_device.homeHead() - output_device.moveHead(0, 0, 3) - output_device.moveHead(Application.getInstance().getGlobalContainerStack().getProperty("machine_width", "value") - 10, 0, 0) - output_device.moveHead(0, 0, -3) + printer.moveHead(0, 0, 3) + printer.homeHead() + printer.moveHead(0, 0, 3) + printer.moveHead(Application.getInstance().getGlobalContainerStack().getProperty("machine_width", "value") - 10, 0, 0) + printer.moveHead(0, 0, -3) self._bed_level_position += 1 elif self._bed_level_position == 1: - output_device.moveHead(0, 0, 3) - output_device.moveHead(-Application.getInstance().getGlobalContainerStack().getProperty("machine_width", "value" ) / 2, Application.getInstance().getGlobalContainerStack().getProperty("machine_depth", "value") - 10, 0) - output_device.moveHead(0, 0, -3) + printer.moveHead(0, 0, 3) + printer.moveHead(-Application.getInstance().getGlobalContainerStack().getProperty("machine_width", "value" ) / 2, Application.getInstance().getGlobalContainerStack().getProperty("machine_depth", "value") - 10, 0) + printer.moveHead(0, 0, -3) self._bed_level_position += 1 elif self._bed_level_position == 2: - output_device.moveHead(0, 0, 3) - output_device.moveHead(-Application.getInstance().getGlobalContainerStack().getProperty("machine_width", "value") / 2 + 10, -(Application.getInstance().getGlobalContainerStack().getProperty("machine_depth", "value") + 10), 0) - output_device.moveHead(0, 0, -3) + printer.moveHead(0, 0, 3) + printer.moveHead(-Application.getInstance().getGlobalContainerStack().getProperty("machine_width", "value") / 2 + 10, -(Application.getInstance().getGlobalContainerStack().getProperty("machine_depth", "value") + 10), 0) + printer.moveHead(0, 0, -3) self._bed_level_position += 1 elif self._bed_level_position >= 3: - output_device.sendCommand("M18") # Turn off all motors so the user can move the axes + output_devices[0].sendCommand("M18") # Turn off all motors so the user can move the axes self.setFinished() \ No newline at end of file From 591d3f29ec860a940e5c1ba73a23ea26b4ca95b1 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Thu, 8 Mar 2018 15:36:12 +0100 Subject: [PATCH 176/446] CURA-4870 Don't crash when there is not buildplate variant for the current machine --- cura/Machines/VariantManager.py | 4 +++- cura/Settings/MachineManager.py | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/cura/Machines/VariantManager.py b/cura/Machines/VariantManager.py index 44ed9614f7..196c2e7b1d 100644 --- a/cura/Machines/VariantManager.py +++ b/cura/Machines/VariantManager.py @@ -132,4 +132,6 @@ class VariantManager: return node def getBuildplateVariantNode(self, machine_definition_id: str, buildplate_type: str) -> Optional["ContainerNode"]: - return self._machine_to_buildplate_dict_map[machine_definition_id].get(buildplate_type) + if machine_definition_id in self._machine_to_buildplate_dict_map: + return self._machine_to_buildplate_dict_map[machine_definition_id].get(buildplate_type) + return None diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 7b9a4191ed..aa86311259 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1068,7 +1068,10 @@ class MachineManager(QObject): if configuration.buildplateConfiguration is not None: global_variant_container_node = self._variant_manager.getBuildplateVariantNode(self._global_container_stack.definition.getId(), configuration.buildplateConfiguration) - self._setGlobalVariant(global_variant_container_node) + if global_variant_container_node: + self._setGlobalVariant(global_variant_container_node) + else: + self._global_container_stack.variant = self._empty_variant_container else: self._global_container_stack.variant = self._empty_variant_container self._updateQualityWithMaterial() From 0d61b6652c6ff2bebb2648685aef0b64f32ec361 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 8 Mar 2018 15:38:32 +0100 Subject: [PATCH 177/446] CURA-4400 merge two if statements in 1 --- cura/Settings/MachineManager.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 5afecb8ef5..d84b5eb3d9 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -722,12 +722,9 @@ class MachineManager(QObject): continue old_value = self._global_container_stack.userChanges.getProperty(setting_key, "value") - if int(old_value) >= extruder_count: + if int(old_value) >= extruder_count or not self._global_container_stack.extruders[str(old_value)].isEnabled: self._global_container_stack.userChanges.removeInstance(setting_key) Logger.log("d", "Reset setting [%s] because its old value [%s] is no longer valid", setting_key, old_value) - if not self._global_container_stack.extruders[str(old_value)].isEnabled: - self._global_container_stack.userChanges.removeInstance(setting_key) - Logger.log("d", "Reset setting [%s] because its old value [%s] is no longer valid (2)", setting_key, old_value) ## Set the amount of extruders on the active machine (global stack) # \param extruder_count int the number of extruders to set From 53764a8274bc862c9396777b9e69ee3cd08984bd Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 8 Mar 2018 15:39:23 +0100 Subject: [PATCH 178/446] CURA-4400 use extrudersEnabledCount for recommended mode's extruder number visibility --- resources/qml/SidebarSimple.qml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index b9b254e280..eabc1d202a 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -19,7 +19,7 @@ Item property Action configureSettings; property variant minimumPrintTime: PrintInformation.minimumPrintTime; property variant maximumPrintTime: PrintInformation.maximumPrintTime; - property bool settingsEnabled: Cura.ExtruderManager.activeExtruderStackId || machineExtruderCount.properties.value == 1 + property bool settingsEnabled: Cura.ExtruderManager.activeExtruderStackId || extrudersEnabledCount.properties.value == 1 Component.onCompleted: PrintInformation.enabled = true Component.onDestruction: PrintInformation.enabled = false @@ -804,7 +804,7 @@ Item ComboBox { id: supportExtruderCombobox - visible: enableSupportCheckBox.visible && (supportEnabled.properties.value == "True") && (machineExtruderCount.properties.value > 1) + visible: enableSupportCheckBox.visible && (supportEnabled.properties.value == "True") && (extrudersEnabledCount.properties.value > 1) model: extruderModel property string color_override: "" // for manually setting values @@ -819,11 +819,11 @@ Item textRole: "text" // this solves that the combobox isn't populated in the first time Cura is started anchors.top: enableSupportCheckBox.bottom - anchors.topMargin: ((supportEnabled.properties.value === "True") && (machineExtruderCount.properties.value > 1)) ? UM.Theme.getSize("sidebar_margin").height : 0 + anchors.topMargin: ((supportEnabled.properties.value === "True") && (extrudersEnabledCount.properties.value > 1)) ? UM.Theme.getSize("sidebar_margin").height : 0 anchors.left: infillCellRight.left width: Math.round(UM.Theme.getSize("sidebar").width * .55) - height: ((supportEnabled.properties.value == "True") && (machineExtruderCount.properties.value > 1)) ? UM.Theme.getSize("setting_control").height : 0 + height: ((supportEnabled.properties.value == "True") && (extrudersEnabledCount.properties.value > 1)) ? UM.Theme.getSize("setting_control").height : 0 Behavior on height { NumberAnimation { duration: 100 } } @@ -1020,9 +1020,9 @@ Item UM.SettingPropertyProvider { - id: machineExtruderCount + id: extrudersEnabledCount containerStackId: Cura.MachineManager.activeMachineId - key: "machine_extruder_count" + key: "extruders_enabled_count" watchedProperties: [ "value" ] storeIndex: 0 } From a2773ca8974471d768e59d1584984ea662f8c749 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Thu, 8 Mar 2018 16:30:05 +0100 Subject: [PATCH 179/446] Animated popup --- .../ConfigurationListView.qml | 2 ++ .../ConfigurationSelection.qml | 36 ++++++++++++++++--- resources/qml/Menus/PrinterStatusIcon.qml | 3 -- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml index be11240831..1bb81656a3 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -12,12 +12,14 @@ Column { id: base property var outputDevice: Cura.MachineManager.printerOutputDevices[0] + property var computedHeight: container.height + configurationListHeading.height + 3 * padding height: childrenRect.height + 2 * padding padding: UM.Theme.getSize("default_margin").width spacing: Math.round(UM.Theme.getSize("default_margin").height / 2) Label { + id: configurationListHeading text: catalog.i18nc("@label:header configurations", "Available configurations") font: UM.Theme.getFont("large") width: parent.width - 2 * parent.padding diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml index 10d8f60e90..3b053afb15 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml @@ -14,24 +14,50 @@ Item property var panelWidth: control.width property var panelVisible: false - SyncButton { } + SyncButton { + onClicked: configurationSelector.state == "open" ? configurationSelector.state = "closed" : configurationSelector.state = "open" + } - Popup - { + Popup { id: popup + clip: true y: configurationSelector.height - UM.Theme.getSize("default_lining").height x: configurationSelector.width - width width: panelWidth visible: panelVisible padding: UM.Theme.getSize("default_lining").width - contentItem: ConfigurationListView { + id: configList width: panelWidth - 2 * popup.padding } - background: Rectangle { color: UM.Theme.getColor("setting_control") border.color: UM.Theme.getColor("setting_control_border") } } + + states: [ + // This adds a second state to the container where the rectangle is farther to the right + State { + name: "open" + PropertyChanges { + target: popup + height: configList.computedHeight + } + }, + State { + name: "closed" + PropertyChanges { + target: popup + height: 0 + } + } + ] + transitions: [ + // This adds a transition that defaults to applying to all state changes + Transition { + // This applies a default NumberAnimation to any changes a state change makes to x or y properties + NumberAnimation { properties: "height"; duration: 200; easing.type: Easing.InOutQuad; } + } + ] } \ No newline at end of file diff --git a/resources/qml/Menus/PrinterStatusIcon.qml b/resources/qml/Menus/PrinterStatusIcon.qml index d7106bf33d..23459386d9 100644 --- a/resources/qml/Menus/PrinterStatusIcon.qml +++ b/resources/qml/Menus/PrinterStatusIcon.qml @@ -2,9 +2,6 @@ // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.2 -import QtQuick.Controls 1.1 -import QtQuick.Controls.Styles 1.1 -import QtQuick.Layouts 1.1 import UM 1.2 as UM import Cura 1.0 as Cura From fa5aa0a53f2b884c72bca30c7ce0917905bc5e09 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Thu, 8 Mar 2018 16:55:40 +0100 Subject: [PATCH 180/446] CURA-4870 React to outputdeviceschanged signal, to update the list of the configurations. --- cura/PrinterOutputDevice.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cura/PrinterOutputDevice.py b/cura/PrinterOutputDevice.py index d2916016e0..453cb4d78a 100644 --- a/cura/PrinterOutputDevice.py +++ b/cura/PrinterOutputDevice.py @@ -74,6 +74,7 @@ class PrinterOutputDevice(QObject, OutputDevice): self._address = "" self._connection_text = "" self.printersChanged.connect(self._onPrintersChanged) + Application.getInstance().getOutputDeviceManager().outputDevicesChanged.connect(self._updateUniqueConfigurations) @pyqtProperty(str, notify = connectionTextChanged) def address(self): From d1beae46034c8d181fdc5bc7d16abe39de2c4822 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 8 Mar 2018 15:42:27 +0100 Subject: [PATCH 181/446] Better logging for checkIsValidProjectFile() CURA-4966 --- cura/CuraApplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 2ca321e4cc..438e8ffed7 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1689,7 +1689,7 @@ class CuraApplication(QtApplication): result = workspace_reader.preRead(file_path, show_dialog=False) return result == WorkspaceReader.PreReadResult.accepted except Exception as e: - Logger.log("e", "Could not check file %s: %s", file_url, e) + Logger.logException("e", "Could not check file %s: %s", file_url) return False def _onContextMenuRequested(self, x: float, y: float) -> None: From 6aefb2215ddabc00b3708acc8909315cda1c9d9d Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 8 Mar 2018 16:50:57 +0100 Subject: [PATCH 182/446] Fix _setQualityChangesGroup() CURA-4966 --- cura/Settings/MachineManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index f7483ae38b..f8692da0e3 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -881,7 +881,7 @@ class MachineManager(QObject): quality_node = quality_group.nodes_for_extruders.get(position) quality_changes_container = self._empty_quality_changes_container - quality_container = self._empty_quality_changes_container + quality_container = self._empty_quality_container if quality_changes_node: quality_changes_container = quality_changes_node.getContainer() if quality_node: From b8d3cbfe169fe83c38b958b8ebd110292811bd91 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 8 Mar 2018 15:43:10 +0100 Subject: [PATCH 183/446] Refactor project loading CURA-4966 --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 1193 ++++++++----------- plugins/3MFReader/WorkspaceDialog.py | 12 - 2 files changed, 482 insertions(+), 723 deletions(-) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 01ca136bcf..4698d498d2 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -1,6 +1,13 @@ # Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from configparser import ConfigParser +import zipfile +import os +import threading + +import xml.etree.ElementTree as ET + from UM.Workspace.WorkspaceReader import WorkspaceReader from UM.Application import Application @@ -14,24 +21,14 @@ from UM.Settings.ContainerRegistry import ContainerRegistry from UM.MimeTypeDatabase import MimeTypeDatabase from UM.Job import Job from UM.Preferences import Preferences -from UM.Util import parseBool -from .WorkspaceDialog import WorkspaceDialog - -import xml.etree.ElementTree as ET from cura.Settings.CuraStackBuilder import CuraStackBuilder -from cura.Settings.ExtruderManager import ExtruderManager from cura.Settings.ExtruderStack import ExtruderStack from cura.Settings.GlobalStack import GlobalStack from cura.Settings.CuraContainerStack import _ContainerIndexes from cura.CuraApplication import CuraApplication -from configparser import ConfigParser -import zipfile -import io -import configparser -import os -import threading +from .WorkspaceDialog import WorkspaceDialog i18n_catalog = i18nCatalog("cura") @@ -67,6 +64,48 @@ def call_on_qt_thread(func): return _call_on_qt_thread_wrapper +class ContainerInfo: + def __init__(self, file_name: str, serialized: str, parser: ConfigParser): + self.file_name = file_name + self.serialized = serialized + self.parser = parser + self.container = None + self.definition_id = None + + +class QualityChangesInfo: + def __init__(self): + self.name = None + self.global_info = None + self.extruder_info_dict = {} + + +class MachineInfo: + def __init__(self): + self.container_id = None + self.name = None + self.definition_id = None + self.quality_type = None + self.custom_quality_name = None + self.quality_changes_info = None + self.variant_info = None + + self.definition_changes_info = None + self.user_changes_info = None + + self.extruder_info_dict = {} + + +class ExtruderInfo: + def __init__(self): + self.position = None + self.variant_info = None + self.root_material_id = None + + self.definition_changes_info = None + self.user_changes_info = None + + ## Base implementation for reading 3MF workspace files. class ThreeMFWorkspaceReader(WorkspaceReader): def __init__(self): @@ -97,13 +136,17 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # In Cura 2.5 and 2.6, the empty profiles used to have those long names self._old_empty_profile_id_dict = {"empty_%s" % k: "empty" for k in ["material", "variant"]} + self._is_same_machine_type = False self._old_new_materials = {} self._materials_to_select = {} + self._machine_info = None def _clearState(self): + self._is_same_machine_type = False self._id_mapping = {} self._old_new_materials = {} self._materials_to_select = {} + self._machine_info = None ## Get a unique name based on the old_id. This is different from directly calling the registry in that it caches results. # This has nothing to do with speed, but with getting consistent new naming for instances & objects. @@ -156,6 +199,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # \param file_name # \param show_dialog In case we use preRead() to check if a file is a valid project file, we don't want to show a dialog. def preRead(self, file_name, show_dialog=True, *args, **kwargs): + self._clearState() + self._3mf_mesh_reader = Application.getInstance().getMeshFileHandler().getReaderForFile(file_name) if self._3mf_mesh_reader and self._3mf_mesh_reader.preRead(file_name) == WorkspaceReader.PreReadResult.accepted: pass @@ -163,6 +208,7 @@ 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 + self._machine_info = MachineInfo() machine_type = "" variant_type_name = i18n_catalog.i18nc("@label", "Nozzle") @@ -182,23 +228,23 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # # Read definition containers # + machine_definition_id = None machine_definition_container_count = 0 extruder_definition_container_count = 0 definition_container_files = [name for name in cura_file_names if name.endswith(self._definition_container_suffix)] - for each_definition_container_file in definition_container_files: - container_id = self._stripFileToId(each_definition_container_file) + for definition_container_file in definition_container_files: + container_id = self._stripFileToId(definition_container_file) definitions = self._container_registry.findDefinitionContainersMetadata(id = container_id) + serialized = archive.open(definition_container_file).read().decode("utf-8") if not definitions: - definition_container = DefinitionContainer(container_id) - definition_container.deserialize(archive.open(each_definition_container_file).read().decode("utf-8"), file_name = each_definition_container_file) - definition_container = definition_container.getMetaData() - + definition_container = DefinitionContainer.deserializeMetadata(serialized, container_id)[0] else: definition_container = definitions[0] definition_container_type = definition_container.get("type") if definition_container_type == "machine": + machine_definition_id = container_id machine_type = definition_container["name"] variant_type_name = definition_container.get("variants_name", variant_type_name) @@ -207,22 +253,33 @@ class ThreeMFWorkspaceReader(WorkspaceReader): extruder_definition_container_count += 1 else: Logger.log("w", "Unknown definition container type %s for %s", - definition_container_type, each_definition_container_file) + definition_container_type, definition_container_file) Job.yieldThread() if machine_definition_container_count != 1: - return WorkspaceReader.PreReadResult.failed #Not a workspace file but ordinary 3MF. + return WorkspaceReader.PreReadResult.failed # Not a workspace file but ordinary 3MF. material_labels = [] material_conflict = False xml_material_profile = self._getXmlProfileClass() + reverse_material_id_dict = {} if self._material_container_suffix is None: self._material_container_suffix = ContainerRegistry.getMimeTypeForContainer(xml_material_profile).preferredSuffix if xml_material_profile: material_container_files = [name for name in cura_file_names if name.endswith(self._material_container_suffix)] for material_container_file in material_container_files: container_id = self._stripFileToId(material_container_file) - material_labels.append(self._getMaterialLabelFromSerialized(archive.open(material_container_file).read().decode("utf-8"))) + + from hashlib import sha1 + hex_container_id = sha1(container_id.encode('utf-8')).hexdigest() + + serialized = archive.open(material_container_file).read().decode("utf-8") + metadata_list = xml_material_profile.deserializeMetadata(serialized, hex_container_id) + reverse_map = {metadata["id"].replace(hex_container_id, container_id): container_id.replace(hex_container_id, container_id) + for metadata in metadata_list} + reverse_material_id_dict.update(reverse_map) + + material_labels.append(self._getMaterialLabelFromSerialized(serialized)) if self._container_registry.findContainersMetadata(id = container_id): #This material already exists. containers_found_dict["material"] = True if not self._container_registry.isReadOnly(container_id): # Only non readonly materials can be in conflict @@ -232,24 +289,38 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # Check if any quality_changes instance container is in conflict. instance_container_files = [name for name in cura_file_names if name.endswith(self._instance_container_suffix)] quality_name = "" - quality_type = "" num_settings_overriden_by_quality_changes = 0 # How many settings are changed by the quality changes - num_settings_overriden_by_definition_changes = 0 # How many settings are changed by the definition changes num_user_settings = 0 quality_changes_conflict = False - definition_changes_conflict = False - for each_instance_container_file in instance_container_files: - container_id = self._stripFileToId(each_instance_container_file) + self._machine_info.quality_changes_info = QualityChangesInfo() + + quality_changes_info_list = [] + instance_container_info_dict = {} # id -> parser + for instance_container_file_name in instance_container_files: + container_id = self._stripFileToId(instance_container_file_name) + + serialized = archive.open(instance_container_file_name).read().decode("utf-8") + serialized = InstanceContainer._updateSerialized(serialized, instance_container_file_name) + parser = ConfigParser(interpolation = None) + parser.read_string(serialized) + container_info = ContainerInfo(instance_container_file_name, serialized, parser) + instance_container_info_dict[container_id] = container_info + instance_container = InstanceContainer(container_id) # Deserialize InstanceContainer by converting read data from bytes to string - instance_container.deserialize(archive.open(each_instance_container_file).read().decode("utf-8"), - file_name = each_instance_container_file) + instance_container.deserialize(serialized, file_name = instance_container_file_name) instance_container_list.append(instance_container) container_type = instance_container.getMetaDataEntry("type") if container_type == "quality_changes": + quality_changes_info_list.append(container_info) + + if not parser.has_option("metadata", "extruder"): + self._machine_info.quality_changes_info.name = parser["general"]["name"] + self._machine_info.quality_changes_info.global_info = container_info + quality_name = instance_container.getName() num_settings_overriden_by_quality_changes += len(instance_container._instances) # Check if quality changes already exists. @@ -259,17 +330,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # Check if there really is a conflict by comparing the values if quality_changes[0] != instance_container: quality_changes_conflict = True - elif container_type == "definition_changes": - definition_name = instance_container.getName() - num_settings_overriden_by_definition_changes += len(instance_container._instances) - # Check if definition changes already exists. - definition_changes = self._container_registry.findInstanceContainers(id = container_id) - # Check if there is any difference the loaded settings from the project file and the settings in Cura. - if definition_changes: - containers_found_dict["definition_changes"] = True - # Check if there really is a conflict by comparing the values - if definition_changes[0] != instance_container: - definition_changes_conflict = True elif container_type == "quality": if not quality_name: quality_name = instance_container.getName() @@ -282,6 +342,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader): Job.yieldThread() + if self._machine_info.quality_changes_info.global_info is None: + self._machine_info.quality_changes_info = None + # Load ContainerStack files and ExtruderStack files global_stack_file, extruder_stack_files = self._determineGlobalAndExtruderStackFiles( file_name, cura_file_names) @@ -290,10 +353,11 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # - the global stack exists but some/all of the extruder stacks DON'T exist # - the global stack DOESN'T exist but some/all of the extruder stacks exist # To simplify this, only check if the global stack exists or not - container_id = self._stripFileToId(global_stack_file) + global_stack_id = self._stripFileToId(global_stack_file) serialized = archive.open(global_stack_file).read().decode("utf-8") machine_name = self._getMachineNameFromSerializedStack(serialized) - stacks = self._container_registry.findContainerStacks(id = container_id) + stacks = self._container_registry.findContainerStacks(name = machine_name, type = "machine") + self._is_same_machine_type = True if stacks: global_stack = stacks[0] containers_found_dict["machine"] = True @@ -305,30 +369,79 @@ class ThreeMFWorkspaceReader(WorkspaceReader): if global_stack.getContainer(index).getId() != container_id: machine_conflict = True break + self._is_same_machine_type = global_stack.definition.getId() == machine_definition_id + + # Get quality type + parser = ConfigParser(interpolation = None) + parser.read_string(serialized) + quality_container_id = parser["containers"][str(_ContainerIndexes.Quality)] + quality_type = instance_container_info_dict[quality_container_id].parser["metadata"]["quality_type"] + + # Get machine info + serialized = archive.open(global_stack_file).read().decode("utf-8") + serialized = GlobalStack._updateSerialized(serialized, global_stack_file) + parser = ConfigParser(interpolation = None) + parser.read_string(serialized) + definition_changes_id = parser["containers"][str(_ContainerIndexes.DefinitionChanges)] + if definition_changes_id not in ("empty", "empty_definition_changes"): + self._machine_info.definition_changes_info = instance_container_info_dict[definition_changes_id] + user_changes_id = parser["containers"][str(_ContainerIndexes.UserChanges)] + if user_changes_id not in ("empty", "empty_user_changes"): + self._machine_info.user_changes_info = instance_container_info_dict[user_changes_id] + + # Also check variant and material in case it doesn't have extruder stacks + if not extruder_stack_files: + position = "0" + + extruder_info = ExtruderInfo() + extruder_info.position = position + variant_id = parser["containers"][str(_ContainerIndexes.Variant)] + material_id = parser["containers"][str(_ContainerIndexes.Material)] + if variant_id not in ("empty", "empty_variant"): + extruder_info.variant_info = instance_container_info_dict[variant_id] + if material_id not in ("empty", "empty_material"): + root_material_id = reverse_material_id_dict[material_id] + extruder_info.root_material_id = root_material_id + self._machine_info.extruder_info_dict[position] = extruder_info + else: + variant_id = parser["containers"][str(_ContainerIndexes.Variant)] + if variant_id not in ("empty", "empty_variant"): + self._machine_info.variant_info = instance_container_info_dict[variant_id] + Job.yieldThread() # if the global stack is found, we check if there are conflicts in the extruder stacks - if containers_found_dict["machine"] and not machine_conflict: - for extruder_stack_file in extruder_stack_files: - serialized = archive.open(extruder_stack_file).read().decode("utf-8") - parser = configparser.ConfigParser(interpolation = None) - parser.read_string(serialized) + for extruder_stack_file in extruder_stack_files: + serialized = archive.open(extruder_stack_file).read().decode("utf-8") + serialized = ExtruderStack._updateSerialized(serialized, extruder_stack_file) + parser = ConfigParser(interpolation = None) + parser.read_string(serialized) - # The check should be done for the extruder stack that's associated with the existing global stack, - # and those extruder stacks may have different IDs. - # So we check according to the positions + # The check should be done for the extruder stack that's associated with the existing global stack, + # and those extruder stacks may have different IDs. + # So we check according to the positions + position = parser["metadata"]["position"] + variant_id = parser["containers"][str(_ContainerIndexes.Variant)] + material_id = parser["containers"][str(_ContainerIndexes.Material)] - position = str(parser["metadata"]["position"]) + extruder_info = ExtruderInfo() + extruder_info.position = position + if variant_id not in ("empty", "empty_variant"): + extruder_info.variant_info = instance_container_info_dict[variant_id] + if material_id not in ("empty", "empty_material"): + root_material_id = reverse_material_id_dict[material_id] + extruder_info.root_material_id = root_material_id + definition_changes_id = parser["containers"][str(_ContainerIndexes.DefinitionChanges)] + if definition_changes_id not in ("empty", "empty_definition_changes"): + extruder_info.definition_changes_info = instance_container_info_dict[definition_changes_id] + user_changes_id = parser["containers"][str(_ContainerIndexes.UserChanges)] + if user_changes_id not in ("empty", "empty_user_changes"): + extruder_info.user_changes_info = instance_container_info_dict[user_changes_id] + self._machine_info.extruder_info_dict[position] = extruder_info + + if not machine_conflict and containers_found_dict["machine"]: if position not in global_stack.extruders: - # The extruder position defined in the project doesn't exist in this global stack. - # We can say that it is a machine conflict, but it is very hard to override the machine in this - # case because we need to override the existing extruders and add the non-existing extruders. - # - # HACK: - # To make this simple, we simply say that there is no machine conflict and create a new machine - # by default. - machine_conflict = False - break + continue existing_extruder_stack = global_stack.extruders[position] # check if there are any changes at all in any of the container stacks. @@ -340,6 +453,15 @@ class ThreeMFWorkspaceReader(WorkspaceReader): machine_conflict = True break + if self._machine_info.quality_changes_info is not None: + for quality_changes_info in quality_changes_info_list: + if not quality_changes_info.parser.has_option("metadata", "extruder"): + continue + extruder_definition_id = quality_changes_info.parser["metadata"]["extruder"] + extruder_definition_metadata = self._container_registry.findDefinitionContainersMetadata(id = extruder_definition_id)[0] + position = extruder_definition_metadata["position"] + self._machine_info.quality_changes_info.extruder_info_dict[position] = quality_changes_info + num_visible_settings = 0 try: temp_preferences = Preferences() @@ -369,10 +491,18 @@ class ThreeMFWorkspaceReader(WorkspaceReader): extruders = num_extruders * [""] + self._machine_info.container_id = global_stack_id + self._machine_info.name = machine_name + self._machine_info.definition_id = machine_definition_id + self._machine_info.quality_type = quality_type + self._machine_info.custom_quality_name = quality_name + + if machine_conflict and not self._is_same_machine_type: + machine_conflict = False + # Show the dialog, informing the user what is about to happen. self._dialog.setMachineConflict(machine_conflict) self._dialog.setQualityChangesConflict(quality_changes_conflict) - self._dialog.setDefinitionChangesConflict(definition_changes_conflict) self._dialog.setMaterialConflict(material_conflict) self._dialog.setHasVisibleSettingsField(has_visible_settings_string) self._dialog.setNumVisibleSettings(num_visible_settings) @@ -415,7 +545,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): ## Overrides an ExtruderStack in the given GlobalStack and returns the new ExtruderStack. def _overrideExtruderStack(self, global_stack, extruder_file_content, extruder_stack_file): # Get extruder position first - extruder_config = configparser.ConfigParser(interpolation = None) + extruder_config = ConfigParser(interpolation = None) extruder_config.read_string(extruder_file_content) if not extruder_config.has_option("metadata", "position"): msg = "Could not find 'metadata/position' in extruder stack file" @@ -464,8 +594,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader): application = CuraApplication.getInstance() material_manager = application.getMaterialManager() - self._clearState() - archive = zipfile.ZipFile(file_name, "r") cura_file_names = [name for name in archive.namelist() if name.startswith("Cura/")] @@ -492,52 +620,24 @@ class ThreeMFWorkspaceReader(WorkspaceReader): else: global_preferences.setValue("cura/categories_expanded", categories_expanded) - Application.getInstance().expandedCategoriesChanged.emit() # Notify the GUI of the change + application.expandedCategoriesChanged.emit() # Notify the GUI of the change - self._id_mapping = {} + # If a machine with the same name is of a different type, always create a new one. + if not self._is_same_machine_type or self._resolve_strategies["machine"] != "override": + # We need to create a new machine + machine_name = self._container_registry.uniqueName(self._machine_info.name) - # We don't add containers right away, but wait right until right before the stack serialization. - # We do this so that if something goes wrong, it's easier to clean up. - containers_to_add = [] + global_stack = CuraStackBuilder.createMachine(machine_name, self._machine_info.definition_id) + extruder_stack_dict = global_stack.extruders - global_stack_file, extruder_stack_files = self._determineGlobalAndExtruderStackFiles(file_name, cura_file_names) + self._container_registry.addContainer(global_stack) + else: + # Find the machine + global_stack = self._container_registry.findContainerStacks(name = self._machine_info.name, type = "machine")[0] + extruder_stacks = self._container_registry.findContainerStacks(machine = global_stack.getId(), + type = "extruder_train") + extruder_stack_dict = {stack.getMetaDataEntry("position"): stack for stack in extruder_stacks} - global_stack = None - extruder_stacks = [] - extruder_stacks_added = [] - container_stacks_added = [] - machine_extruder_count = None - - containers_added = [] - - global_stack_id_original = self._stripFileToId(global_stack_file) - global_stack_id_new = global_stack_id_original - global_stack_name_original = self._getMachineNameFromSerializedStack(archive.open(global_stack_file).read().decode("utf-8")) - global_stack_name_new = global_stack_name_original - global_stack_need_rename = False - - extruder_stack_id_map = {} # new and old ExtruderStack IDs map - if self._resolve_strategies["machine"] == "new": - # We need a new id if the id already exists - if self._container_registry.findContainerStacksMetadata(id = global_stack_id_original): - global_stack_id_new = self.getNewId(global_stack_id_original) - global_stack_need_rename = True - - if self._container_registry.findContainerStacksMetadata(name = global_stack_id_original): - global_stack_name_new = self._container_registry.uniqueName(global_stack_name_original) - - for each_extruder_stack_file in extruder_stack_files: - old_container_id = self._stripFileToId(each_extruder_stack_file) - new_container_id = old_container_id - if self._container_registry.findContainerStacksMetadata(id = old_container_id): - # get a new name for this extruder - new_container_id = self.getNewId(old_container_id) - - extruder_stack_id_map[old_container_id] = new_container_id - - # TODO: For the moment we use pretty naive existence checking. If the ID is the same, we assume in quite a few - # TODO: cases that the container loaded is the same (most notable in materials & definitions). - # TODO: It might be possible that we need to add smarter checking in the future. Logger.log("d", "Workspace loading is checking definitions...") # Get all the definition files & check if they exist. If not, add them. definition_container_files = [name for name in cura_file_names if name.endswith(self._definition_container_suffix)] @@ -552,15 +652,14 @@ class ThreeMFWorkspaceReader(WorkspaceReader): Job.yieldThread() Logger.log("d", "Workspace loading is checking materials...") - material_containers = [] # Get all the material files and check if they exist. If not, add them. xml_material_profile = self._getXmlProfileClass() if self._material_container_suffix is None: self._material_container_suffix = ContainerRegistry.getMimeTypeForContainer(xml_material_profile).suffixes[0] if xml_material_profile: - to_deserialize_material = False material_container_files = [name for name in cura_file_names if name.endswith(self._material_container_suffix)] for material_container_file in material_container_files: + to_deserialize_material = False container_id = self._stripFileToId(material_container_file) need_new_name = False materials = self._container_registry.findInstanceContainers(id = container_id) @@ -571,7 +670,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): else: material_container = materials[0] old_material_root_id = material_container.getMetaDataEntry("base_file") - if not self._container_registry.isReadOnly(container_id): # Only create new materials if they are not read only. + if not self._container_registry.isReadOnly(old_material_root_id): # Only create new materials if they are not read only. to_deserialize_material = True if self._resolve_strategies["material"] == "override": @@ -592,544 +691,16 @@ class ThreeMFWorkspaceReader(WorkspaceReader): if need_new_name: new_name = ContainerRegistry.getInstance().uniqueName(material_container.getName()) material_container.setName(new_name) - containers_to_add.append(material_container) + self._container_registry.addContainer(material_container) Job.yieldThread() - Logger.log("d", "Workspace loading is checking instance containers...") - # Get quality_changes and user profiles saved in the workspace - instance_container_files = [name for name in cura_file_names if name.endswith(self._instance_container_suffix)] - user_instance_containers = [] - quality_and_definition_changes_instance_containers = [] - quality_changes_instance_containers = [] - for instance_container_file in instance_container_files: - container_id = self._stripFileToId(instance_container_file) - serialized = archive.open(instance_container_file).read().decode("utf-8") + # Handle quality changes if any + self._processQualityChanges(global_stack) - # HACK! we ignore "quality" and "variant" instance containers! - parser = configparser.ConfigParser(interpolation = None) - parser.read_string(serialized) - if not parser.has_option("metadata", "type"): - Logger.log("w", "Cannot find metadata/type in %s, ignoring it", instance_container_file) - continue - if parser.get("metadata", "type") in self._ignored_instance_container_types: - continue - - instance_container = InstanceContainer(container_id) - - # Deserialize InstanceContainer by converting read data from bytes to string - instance_container.deserialize(serialized, file_name = instance_container_file) - container_type = instance_container.getMetaDataEntry("type") - Job.yieldThread() - - # - # IMPORTANT: - # If an instance container (or maybe other type of container) exists, and user chooses "Create New", - # we need to rename this container and all references to it, and changing those references are VERY - # HARD. - # - if container_type in self._ignored_instance_container_types: - # Ignore certain instance container types - Logger.log("w", "Ignoring instance container [%s] with type [%s]", container_id, container_type) - continue - elif container_type == "user": - # Check if quality changes already exists. - user_containers = self._container_registry.findInstanceContainers(id = container_id) - if not user_containers: - containers_to_add.append(instance_container) - else: - if self._resolve_strategies["machine"] == "override" or self._resolve_strategies["machine"] is None: - instance_container = user_containers[0] - instance_container.deserialize(archive.open(instance_container_file).read().decode("utf-8"), - file_name = instance_container_file) - instance_container.setDirty(True) - elif self._resolve_strategies["machine"] == "new": - # The machine is going to get a spiffy new name, so ensure that the id's of user settings match. - old_extruder_id = instance_container.getMetaDataEntry("extruder", None) - if old_extruder_id: - new_extruder_id = extruder_stack_id_map[old_extruder_id] - new_id = new_extruder_id + "_current_settings" - instance_container.setMetaDataEntry("id", new_id) - instance_container.setName(new_id) - instance_container.setMetaDataEntry("extruder", new_extruder_id) - containers_to_add.append(instance_container) - - machine_id = instance_container.getMetaDataEntry("machine", None) - if machine_id: - new_machine_id = self.getNewId(machine_id) - new_id = new_machine_id + "_current_settings" - instance_container.setMetaDataEntry("id", new_id) - instance_container.setName(new_id) - instance_container.setMetaDataEntry("machine", new_machine_id) - containers_to_add.append(instance_container) - user_instance_containers.append(instance_container) - elif container_type in ("quality_changes", "definition_changes"): - # Check if quality changes already exists. - changes_containers = self._container_registry.findInstanceContainers(id = container_id) - if not changes_containers: - # no existing containers with the same ID, so we can safely add the new one - containers_to_add.append(instance_container) - else: - # we have found existing container with the same ID, so we need to resolve according to the - # selected strategy. - if self._resolve_strategies[container_type] == "override": - instance_container = changes_containers[0] - instance_container.deserialize(archive.open(instance_container_file).read().decode("utf-8"), - file_name = instance_container_file) - instance_container.setDirty(True) - - elif self._resolve_strategies[container_type] == "new": - # TODO: how should we handle the case "new" for quality_changes and definition_changes? - - instance_container.setName(self._container_registry.uniqueName(instance_container.getName())) - new_changes_container_id = self.getNewId(instance_container.getId()) - instance_container.setMetaDataEntry("id", new_changes_container_id) - - # TODO: we don't know the following is correct or not, need to verify - # AND REFACTOR!!! - if self._resolve_strategies["machine"] == "new": - # The machine is going to get a spiffy new name, so ensure that the id's of user settings match. - old_extruder_id = instance_container.getMetaDataEntry("extruder", None) - # Note that in case of a quality_changes extruder means the definition id of the extruder stack - # For the user settings, it means the actual extruder stack id it's assigned to. - if old_extruder_id and old_extruder_id in extruder_stack_id_map: - new_extruder_id = extruder_stack_id_map[old_extruder_id] - instance_container.setMetaDataEntry("extruder", new_extruder_id) - - machine_id = instance_container.getMetaDataEntry("machine", None) - if machine_id: - new_machine_id = self.getNewId(machine_id) - instance_container.setMetaDataEntry("machine", new_machine_id) - - containers_to_add.append(instance_container) - - elif self._resolve_strategies[container_type] is None: - # The ID already exists, but nothing in the values changed, so do nothing. - pass - quality_and_definition_changes_instance_containers.append(instance_container) - if container_type == "quality_changes": - quality_changes_instance_containers.append(instance_container) - - if container_type == "definition_changes": - definition_changes_extruder_count = instance_container.getProperty("machine_extruder_count", "value") - if definition_changes_extruder_count is not None: - machine_extruder_count = definition_changes_extruder_count - - else: - existing_container = self._container_registry.findInstanceContainersMetadata(id = container_id) - if not existing_container: - containers_to_add.append(instance_container) - if global_stack_need_rename: - if instance_container.getMetaDataEntry("machine"): - instance_container.setMetaDataEntry("machine", global_stack_id_new) - - # Add all the containers right before we try to add / serialize the stack - for container in containers_to_add: - self._container_registry.addContainer(container) - container.setDirty(True) - containers_added.append(container) - - # Get the stack(s) saved in the workspace. - Logger.log("d", "Workspace loading is checking stacks containers...") - - # load global stack file - try: - stack = None - - if self._resolve_strategies["machine"] == "override": - container_stacks = self._container_registry.findContainerStacks(id = global_stack_id_original) - stack = container_stacks[0] - - # HACK - # There is a machine, check if it has authentication data. If so, keep that data. - network_authentication_id = stack.getMetaDataEntry("network_authentication_id") - network_authentication_key = stack.getMetaDataEntry("network_authentication_key") - stack.deserialize(archive.open(global_stack_file).read().decode("utf-8"), file_name = global_stack_file) - if network_authentication_id: - stack.addMetaDataEntry("network_authentication_id", network_authentication_id) - if network_authentication_key: - stack.addMetaDataEntry("network_authentication_key", network_authentication_key) - - elif self._resolve_strategies["machine"] == "new": - # create a new global stack - stack = GlobalStack(global_stack_id_new) - # Deserialize stack by converting read data from bytes to string - stack.deserialize(archive.open(global_stack_file).read().decode("utf-8"), - file_name = global_stack_file) - - # Ensure a unique ID and name - stack.setMetaDataEntry("id", global_stack_id_new) - - # Only machines need a new name, stacks may be non-unique - stack.setName(global_stack_name_new) - - container_stacks_added.append(stack) - # self._container_registry.addContainer(stack) - containers_added.append(stack) - else: - Logger.log("e", "Resolve strategy of %s for machine is not supported", self._resolve_strategies["machine"]) - - # Create a new definition_changes container if it was empty - if stack.definitionChanges == self._container_registry.getEmptyInstanceContainer(): - stack.setDefinitionChanges(CuraStackBuilder.createDefinitionChangesContainer(stack, stack.getId() + "_settings")) - global_stack = stack - Job.yieldThread() - except: - Logger.logException("w", "We failed to serialize the stack. Trying to clean up.") - # Something went really wrong. Try to remove any data that we added. - for container in containers_added: - self._container_registry.removeContainer(container.getId()) - return - - # load extruder stack files - has_extruder_stack_files = len(extruder_stack_files) > 0 - empty_quality_container = self._container_registry.findInstanceContainers(id = "empty_quality")[0] - empty_quality_changes_container = self._container_registry.findInstanceContainers(id = "empty_quality_changes")[0] - try: - for extruder_stack_file in extruder_stack_files: - container_id = self._stripFileToId(extruder_stack_file) - extruder_file_content = archive.open(extruder_stack_file, "r").read().decode("utf-8") - - if self._resolve_strategies["machine"] == "override": - # deserialize new extruder stack over the current ones (if any) - stack = self._overrideExtruderStack(global_stack, extruder_file_content, extruder_stack_file) - if stack is None: - continue - - elif self._resolve_strategies["machine"] == "new": - new_id = extruder_stack_id_map[container_id] - stack = ExtruderStack(new_id) - - # HACK: the global stack can have a new name, so we need to make sure that this extruder stack - # references to the new name instead of the old one. Normally, this can be done after - # deserialize() by setting the metadata, but in the case of ExtruderStack, deserialize() - # also does addExtruder() to its machine stack, so we have to make sure that it's pointing - # to the right machine BEFORE deserialization. - extruder_config = configparser.ConfigParser(interpolation = None) - extruder_config.read_string(extruder_file_content) - extruder_config.set("metadata", "machine", global_stack_id_new) - tmp_string_io = io.StringIO() - extruder_config.write(tmp_string_io) - extruder_file_content = tmp_string_io.getvalue() - - stack.deserialize(extruder_file_content, file_name = extruder_stack_file) - - # Ensure a unique ID and name - stack.setMetaDataEntry("id", new_id) - - self._container_registry.addContainer(stack) - extruder_stacks_added.append(stack) - containers_added.append(stack) - else: - Logger.log("w", "Unknown resolve strategy: %s", self._resolve_strategies["machine"]) - - # Create a new definition_changes container if it was empty - if stack.definitionChanges == self._container_registry.getEmptyInstanceContainer(): - stack.setDefinitionChanges(CuraStackBuilder.createDefinitionChangesContainer(stack, stack.getId() + "_settings")) - - if stack.getMetaDataEntry("type") == "extruder_train": - extruder_stacks.append(stack) - - # If not extruder stacks were saved in the project file (pre 3.1) create one manually - # We re-use the container registry's addExtruderStackForSingleExtrusionMachine method for this - if not extruder_stacks: - # If we choose to override a machine but to create a new custom quality profile, the custom quality - # profile is not immediately applied to the global_stack, so this fix for single extrusion machines - # will use the current custom quality profile on the existing machine. The extra optional argument - # in that function is used in this case to specify a new global stack quality_changes container so - # the fix can correctly create and copy over the custom quality settings to the newly created extruder. - new_global_quality_changes = None - if self._resolve_strategies["quality_changes"] == "new" and len(quality_changes_instance_containers) > 0: - new_global_quality_changes = quality_changes_instance_containers[0] - - # Depending if the strategy is to create a new or override, the ids must be or not be unique - stack = self._container_registry.addExtruderStackForSingleExtrusionMachine(global_stack, "fdmextruder", - new_global_quality_changes, - create_new_ids = self._resolve_strategies["machine"] == "new") - if new_global_quality_changes is not None: - quality_changes_instance_containers.append(stack.qualityChanges) - quality_and_definition_changes_instance_containers.append(stack.qualityChanges) - if global_stack.quality.getId() in ("empty", "empty_quality"): - stack.quality = empty_quality_container - if self._resolve_strategies["machine"] == "override": - # in case the extruder is newly created (for a single-extrusion machine), we need to override - # the existing extruder stack. - existing_extruder_stack = global_stack.extruders[stack.getMetaDataEntry("position")] - for idx in range(len(_ContainerIndexes.IndexTypeMap)): - existing_extruder_stack.replaceContainer(idx, stack._containers[idx], postpone_emit = True) - extruder_stacks.append(existing_extruder_stack) - else: - extruder_stacks.append(stack) - - except: - Logger.logException("w", "We failed to serialize the stack. Trying to clean up.") - # Something went really wrong. Try to remove any data that we added. - for container in containers_added: - self._container_registry.removeContainer(container.getId()) - return - - ## In case there is a new machine and once the extruders are created, the global stack is added to the registry, - # otherwise the addContainers function in CuraContainerRegistry will create an extruder stack and then creating - # useless files - if self._resolve_strategies["machine"] == "new": - self._container_registry.addContainer(global_stack) - - # Check quality profiles to make sure that if one stack has the "not supported" quality profile, - # all others should have the same. - # - # This block code tries to fix the following problems in Cura 3.0 and earlier: - # 1. The upgrade script can rename all "Not Supported" quality profiles to "empty_quality", but it cannot fix - # the problem that the global stack the extruder stacks may have different quality profiles. The code - # below loops over all stacks and make sure that if there is one stack with "Not Supported" profile, the - # rest should also use the "Not Supported" profile. - # 2. In earlier versions (at least 2.7 and 3.0), a wrong quality profile could be assigned to a stack. For - # example, a UM3 can have a BB 0.8 variant with "aa04_pla_fast" quality profile enabled. To fix this, - # in the code below we also check the actual available quality profiles for the machine. - # - has_not_supported = False - for stack in [global_stack] + extruder_stacks: - if stack.quality.getId() in ("empty", "empty_quality"): - has_not_supported = True - break - - # We filter out extruder stacks that are not actually used, for example the UM3 and custom FDM printer extruder count setting. - extruder_stacks_in_use = extruder_stacks - if machine_extruder_count is not None: - extruder_stacks_in_use = extruder_stacks[:machine_extruder_count] - - quality_manager = CuraApplication.getInstance()._quality_manager - all_quality_groups = quality_manager.getQualityGroups(global_stack) - available_quality_types = [qt for qt, qg in all_quality_groups.items() if qg.is_available] - if not has_not_supported: - has_not_supported = not available_quality_types - - quality_has_been_changed = False - - if has_not_supported: - for stack in [global_stack] + extruder_stacks_in_use: - stack.replaceContainer(_ContainerIndexes.Quality, empty_quality_container) - stack.replaceContainer(_ContainerIndexes.QualityChanges, empty_quality_changes_container) - quality_has_been_changed = True - - else: - # The machine in the project has non-empty quality and there are usable qualities for this machine. - # We need to check if the current quality_type is still usable for this machine, if not, then the quality - # will be reset to the "preferred quality" if present, otherwise "normal". - if global_stack.quality.getMetaDataEntry("quality_type") not in available_quality_types: - # We are here because the quality_type specified in the project is not supported any more, - # so we need to switch it to the "preferred quality" if present, otherwise "normal". - quality_has_been_changed = True - - # find the preferred quality - preferred_quality_id = global_stack.getMetaDataEntry("preferred_quality", None) - if preferred_quality_id is not None: - definition_id = global_stack.definition.getId() - definition_id = global_stack.definition.getMetaDataEntry("quality_definition", definition_id) - if not parseBool(global_stack.getMetaDataEntry("has_machine_quality", "False")): - definition_id = "fdmprinter" - - containers = self._container_registry.findInstanceContainers(id = preferred_quality_id, - type = "quality", - definition = definition_id) - containers = [c for c in containers if not c.getMetaDataEntry("material", "")] - if containers: - global_stack.quality = containers[0] - global_stack.qualityChanges = empty_quality_changes_container - # also find the quality containers for the extruders - for extruder_stack in extruder_stacks_in_use: - search_criteria = {"id": preferred_quality_id, - "type": "quality", - "definition": definition_id} - if global_stack.getMetaDataEntry("has_machine_materials") and extruder_stack.material.getId() not in ("empty", "empty_material"): - search_criteria["material"] = extruder_stack.material.getId() - containers = self._container_registry.findInstanceContainers(**search_criteria) - if containers: - extruder_stack.quality = containers[0] - extruder_stack.qualityChanges = empty_quality_changes_container - else: - Logger.log("e", "Cannot find preferred quality for extruder [%s].", extruder_stack.getId()) - - else: - # we cannot find the preferred quality. THIS SHOULD NOT HAPPEN - Logger.log("e", "Cannot find the preferred quality for machine [%s]", global_stack.getId()) - else: - # The quality_type specified in the project file is usable, but the quality container itself may not - # be correct. For example, for UM2, the quality container can be "draft" while it should be "um2_draft" - # instead. - # In this code branch, we try to fix those incorrect quality containers. - # - # ***IMPORTANT***: We only do this fix for single-extrusion machines. - # We will first find the correct quality profile for the extruder, then apply the same - # quality profile for the global stack. - # - if len(extruder_stacks) == 1: - extruder_stack = extruder_stacks[0] - - search_criteria = {"type": "quality", "quality_type": global_stack.quality.getMetaDataEntry("quality_type")} - search_criteria["definition"] = global_stack.definition.getId() - if not parseBool(global_stack.getMetaDataEntry("has_machine_quality", "False")): - search_criteria["definition"] = "fdmprinter" - - if global_stack.getMetaDataEntry("has_machine_materials") and extruder_stack.material.getId() not in ("empty", "empty_material"): - search_criteria["material"] = extruder_stack.material.getId() - containers = self._container_registry.findInstanceContainers(**search_criteria) - if containers: - new_quality_container = containers[0] - extruder_stack.quality = new_quality_container - global_stack.quality = new_quality_container - - # Now we are checking if the quality in the extruder stacks is the same as in the global. In other case, - # the quality is set to be the same. - definition_id = global_stack.definition.getId() - definition_id = global_stack.definition.getMetaDataEntry("quality_definition", definition_id) - if not parseBool(global_stack.getMetaDataEntry("has_machine_quality", "False")): - definition_id = "fdmprinter" - - for extruder_stack in extruder_stacks_in_use: - - # If the quality is different in the stacks, then the quality in the global stack is trusted - if extruder_stack.quality.getMetaDataEntry("quality_type") != global_stack.quality.getMetaDataEntry("quality_type"): - search_criteria = {"id": global_stack.quality.getId(), - "type": "quality", - "definition": definition_id} - if global_stack.getMetaDataEntry("has_machine_materials") and extruder_stack.material.getId() not in ("empty", "empty_material"): - search_criteria["material"] = extruder_stack.material.getId() - containers = self._container_registry.findInstanceContainers(**search_criteria) - if containers: - extruder_stack.quality = containers[0] - extruder_stack.qualityChanges = empty_quality_changes_container - else: - Logger.log("e", "Cannot find a suitable quality for extruder [%s].", extruder_stack.getId()) - - quality_has_been_changed = True - - else: - Logger.log("i", "The quality is the same for the global and the extruder stack [%s]", global_stack.quality.getId()) - - # Replacing the old containers if resolve is "new". - # When resolve is "new", some containers will get renamed, so all the other containers that reference to those - # MUST get updated too. - # - if self._resolve_strategies["machine"] == "new": - # A new machine was made, but it was serialized with the wrong user container. Fix that now. - for container in user_instance_containers: - # replacing the container ID for user instance containers for the extruders - extruder_id = container.getMetaDataEntry("extruder", None) - if extruder_id: - for extruder in extruder_stacks: - if extruder.getId() == extruder_id: - extruder.userChanges = container - continue - - # replacing the container ID for user instance containers for the machine - machine_id = container.getMetaDataEntry("machine", None) - if machine_id: - if global_stack.getId() == machine_id: - global_stack.userChanges = container - continue - - changes_container_types = ("quality_changes", "definition_changes") - if quality_has_been_changed: - # DO NOT replace quality_changes if the current quality_type is not supported - changes_container_types = ("definition_changes",) - for changes_container_type in changes_container_types: - if self._resolve_strategies[changes_container_type] == "new": - # Quality changes needs to get a new ID, added to registry and to the right stacks - for each_changes_container in quality_and_definition_changes_instance_containers: - # NOTE: The renaming and giving new IDs are possibly redundant because they are done in the - # instance container loading part. - new_id = each_changes_container.getId() - - # Find the old (current) changes container in the global stack - if changes_container_type == "quality_changes": - old_container = global_stack.qualityChanges - elif changes_container_type == "definition_changes": - old_container = global_stack.definitionChanges - - # sanity checks - # NOTE: The following cases SHOULD NOT happen!!!! - if old_container.getId() in ("empty_quality_changes", "empty_definition_changes", "empty"): - Logger.log("e", "We try to get [%s] from the global stack [%s] but we got None instead!", - changes_container_type, global_stack.getId()) - continue - - # Replace the quality/definition changes container if it's in the GlobalStack - # NOTE: we can get an empty container here, but the IDs will not match, - # so this comparison is fine. - if self._id_mapping.get(old_container.getId()) == new_id: - if changes_container_type == "quality_changes": - global_stack.qualityChanges = each_changes_container - elif changes_container_type == "definition_changes": - global_stack.definitionChanges = each_changes_container - continue - - # Replace the quality/definition changes container if it's in one of the ExtruderStacks - # Only apply the change if we have loaded extruder stacks from the project - if has_extruder_stack_files: - for each_extruder_stack in extruder_stacks: - changes_container = None - if changes_container_type == "quality_changes": - changes_container = each_extruder_stack.qualityChanges - elif changes_container_type == "definition_changes": - changes_container = each_extruder_stack.definitionChanges - - # sanity checks - # NOTE: The following cases SHOULD NOT happen!!!! - if changes_container.getId() in ("empty_quality_changes", "empty_definition_changes", "empty"): - Logger.log("e", "We try to get [%s] from the extruder stack [%s] but we got None instead!", - changes_container_type, each_extruder_stack.getId()) - continue - - # NOTE: we can get an empty container here, but the IDs will not match, - # so this comparison is fine. - if self._id_mapping.get(changes_container.getId()) == new_id: - if changes_container_type == "quality_changes": - each_extruder_stack.qualityChanges = each_changes_container - elif changes_container_type == "definition_changes": - each_extruder_stack.definitionChanges = each_changes_container - - if self._resolve_strategies["material"] == "new": - # the actual material instance container can have an ID such as - # __ - # which cannot be determined immediately, so here we use a HACK to find the right new material - # instance ID: - # - get the old material IDs for all material - # - find the old material with the longest common prefix in ID, that's the old material - # - update the name by replacing the old prefix with the new - # - find the new material container and set it to the stack - old_to_new_material_dict = {} - for each_material in material_containers: - # find the material's old name - for old_id, new_id in self._id_mapping.items(): - if each_material.getId() == new_id: - old_to_new_material_dict[old_id] = each_material - break - - global_stack.quality = empty_quality_container - - # replace old material in global and extruder stacks with new - self._replaceStackMaterialWithNew(global_stack, old_to_new_material_dict) - if extruder_stacks: - for extruder_stack in extruder_stacks: - if extruder_stack.material.getId() in ("empty", "empty_material"): - continue - old_root_material_id = extruder_stack.material.getMetaDataEntry("base_file") - if old_root_material_id in self._old_new_materials: - new_root_material_id = self._old_new_materials[old_root_material_id] - self._materials_to_select[extruder_stack.getMetaDataEntry("position")] = new_root_material_id - - if extruder_stacks: - for stack in extruder_stacks: - ExtruderManager.getInstance().registerExtruder(stack, global_stack.getId()) + # Prepare the machine + self._applyChangesToMachine(global_stack, extruder_stack_dict) Logger.log("d", "Workspace loading is notifying rest of the code of changes...") - - if self._resolve_strategies["machine"] == "new": - for stack in extruder_stacks: - stack.setNextStack(global_stack) - stack.containersChanged.emit(stack.getTop()) - else: - CuraApplication.getInstance().getMachineManager().activeQualityChanged.emit() - # Actually change the active machine. # # This is scheduled for later is because it depends on the Variant/Material/Qualitiy Managers to have the latest @@ -1137,7 +708,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # function is running on the main thread (Qt thread), although those "changed" signals have been emitted, but # they won't take effect until this function is done. # To solve this, we schedule _updateActiveMachine() for later so it will have the latest data. - CuraApplication.getInstance().callLater(self._updateActiveMachine, global_stack) + Application.getInstance().setGlobalContainerStack(global_stack) + self._updateActiveMachine(global_stack) # Load all the nodes / meshdata of the workspace nodes = self._3mf_mesh_reader.read(file_name) @@ -1150,85 +722,284 @@ class ThreeMFWorkspaceReader(WorkspaceReader): self.setWorkspaceName(base_file_name) return nodes + def _processQualityChanges(self, global_stack): + if self._machine_info.quality_changes_info is None: + return + + application = CuraApplication.getInstance() + quality_manager = application.getQualityManager() + + # If we have custom profiles, load them + quality_changes_name = self._machine_info.quality_changes_info.name + if self._machine_info.quality_changes_info is not None: + Logger.log("i", "Loading custom profile [%s] from project file", + self._machine_info.quality_changes_info.name) + + # Get the correct extruder definition IDs for quality changes + from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch + machine_definition_id_for_quality = getMachineDefinitionIDForQualitySearch(global_stack) + machine_definition_for_quality = self._container_registry.findDefinitionContainers(id = machine_definition_id_for_quality)[0] + extruder_dict_for_quality = machine_definition_for_quality.getMetaDataEntry("machine_extruder_trains") + + quality_changes_info = self._machine_info.quality_changes_info + quality_changes_quality_type = quality_changes_info.global_info.parser["metadata"]["quality_type"] + + quality_changes_name = quality_changes_info.name + create_new = self._resolve_strategies.get("quality_changes") != "override" + if create_new: + container_info_dict = {None: self._machine_info.quality_changes_info.global_info} + container_info_dict.update(quality_changes_info.extruder_info_dict) + + quality_changes_name = self._container_registry.uniqueName(quality_changes_name) + for position, container_info in container_info_dict.items(): + extruder_definition_id = None + if position is not None: + extruder_definition_id = extruder_dict_for_quality[position] + + container = quality_manager._createQualityChanges(quality_changes_quality_type, + quality_changes_name, + global_stack, extruder_definition_id) + container_info.container = container + container.setDirty(True) + self._container_registry.addContainer(container) + + Logger.log("d", "Created new quality changes container [%s]", container.getId()) + + else: + # Find the existing containers + quality_changes_containers = self._container_registry.findInstanceContainers(name = quality_changes_name, + type = "quality_changes") + for container in quality_changes_containers: + extruder_definition_id = container.getMetaDataEntry("extruder") + if not extruder_definition_id: + quality_changes_info.global_info.container = container + else: + extruder_definition_metadata = self._container_registry.findDefinitionContainersMetadata(id = extruder_definition_id)[0] + position = extruder_definition_metadata["position"] + if position not in quality_changes_info.extruder_info_dict: + quality_changes_info.extruder_info_dict[position] = ContainerInfo(None, None, None) + container_info = quality_changes_info.extruder_info_dict[position] + container_info.container = container + + for position, container_info in quality_changes_info.extruder_info_dict.items(): + container_info.definition_id = extruder_dict_for_quality[position] + + # If there is no quality changes for any extruder, create one. + if not quality_changes_info.extruder_info_dict: + container_info = ContainerInfo(None, None, None) + quality_changes_info.extruder_info_dict["0"] = container_info + extruder_definition_id = extruder_dict_for_quality["0"] + container_info.definition_id = extruder_definition_id + + container = quality_manager._createQualityChanges(quality_changes_quality_type, quality_changes_name, + global_stack, extruder_definition_id) + container_info.container = container + container.setDirty(True) + self._container_registry.addContainer(container) + + Logger.log("d", "Created new quality changes container [%s]", container.getId()) + + # Clear all existing containers + quality_changes_info.global_info.container.clear() + for container_info in quality_changes_info.extruder_info_dict.values(): + container_info.container.clear() + + # Loop over everything and override the existing containers + global_info = quality_changes_info.global_info + global_info.container.clear() # Clear all + for key, value in global_info.parser["values"].items(): + if not machine_definition_for_quality.getProperty(key, "settable_per_extruder"): + global_info.container.setProperty(key, "value", value) + else: + quality_changes_info.extruder_info_dict["0"].container.setProperty(key, "value", value) + + for position, container_info in quality_changes_info.extruder_info_dict.items(): + if container_info.parser is None: + continue + + if container_info.container is None: + extruder_definition_id = extruder_dict_for_quality[position] + container = quality_manager._createQualityChanges(quality_changes_quality_type, quality_changes_name, + global_stack, extruder_definition_id) + container_info.container = container + + for key, value in container_info.parser["values"].items(): + container_info.container.setProperty(key, "value", value) + + self._machine_info.quality_changes_info.name = quality_changes_name + + def _clearStack(self, stack): + application = CuraApplication.getInstance() + + stack.definitionChanges.clear() + stack.variant = application.empty_variant_container + stack.material = application.empty_material_container + stack.quality = application.empty_quality_container + stack.qualityChanges = application.empty_quality_changes_container + stack.userChanges.clear() + + def _applyDefinitionChanges(self, global_stack, extruder_stack_dict): + values_to_set_for_extruders = {} + if self._machine_info.definition_changes_info is not None: + parser = self._machine_info.definition_changes_info.parser + for key, value in parser["values"].items(): + if global_stack.getProperty(key, "settable_per_extruder"): + values_to_set_for_extruders[key] = value + else: + global_stack.definitionChanges.setProperty(key, "value", value) + + for position, extruder_stack in extruder_stack_dict.items(): + if position not in self._machine_info.extruder_info_dict: + continue + + extruder_info = self._machine_info.extruder_info_dict[position] + if extruder_info.definition_changes_info is None: + continue + parser = extruder_info.definition_changes_info.parser + for key, value in values_to_set_for_extruders.items(): + extruder_stack.definitionChanges.setProperty(key, "value", value) + if parser is not None: + for key, value in parser["values"].items(): + extruder_stack.definitionChanges.setProperty(key, "value", value) + + def _applyUserChanges(self, global_stack, extruder_stack_dict): + values_to_set_for_extruder_0 = {} + if self._machine_info.user_changes_info is not None: + parser = self._machine_info.user_changes_info.parser + for key, value in parser["values"].items(): + if global_stack.getProperty(key, "settable_per_extruder"): + values_to_set_for_extruder_0[key] = value + else: + global_stack.userChanges.setProperty(key, "value", value) + + for position, extruder_stack in extruder_stack_dict.items(): + if position not in self._machine_info.extruder_info_dict: + continue + + extruder_info = self._machine_info.extruder_info_dict[position] + if extruder_info.user_changes_info is not None: + parser = self._machine_info.extruder_info_dict[position].user_changes_info.parser + if position == "0": + for key, value in values_to_set_for_extruder_0.items(): + extruder_stack.userChanges.setProperty(key, "value", value) + if parser is not None: + for key, value in parser["values"].items(): + extruder_stack.userChanges.setProperty(key, "value", value) + + def _applyVariants(self, global_stack, extruder_stack_dict): + application = CuraApplication.getInstance() + variant_manager = application.getVariantManager() + + if self._machine_info.variant_info is not None: + parser = self._machine_info.variant_info.parser + variant_name = parser["general"]["name"] + + from cura.Machines.VariantManager import VariantType + variant_type = VariantType.BUILD_PLATE + + node = variant_manager.getVariantNode(global_stack.definition.getId(), variant_name, variant_type) + if node is not None: + global_stack.variant = node.getContainer() + + for position, extruder_stack in extruder_stack_dict.items(): + if position not in self._machine_info.extruder_info_dict: + continue + extruder_info = self._machine_info.extruder_info_dict[position] + if extruder_info.variant_info is None: + continue + parser = extruder_info.variant_info.parser + + variant_name = parser["general"]["name"] + from cura.Machines.VariantManager import VariantType + variant_type = VariantType.NOZZLE + + node = variant_manager.getVariantNode(global_stack.definition.getId(), variant_name, variant_type) + if node is not None: + extruder_stack.variant = node.getContainer() + + def _applyMaterials(self, global_stack, extruder_stack_dict): + application = CuraApplication.getInstance() + material_manager = application.getMaterialManager() + + # Force update lookup tables first + material_manager.initialize() + + for position, extruder_stack in extruder_stack_dict.items(): + if position not in self._machine_info.extruder_info_dict: + continue + extruder_info = self._machine_info.extruder_info_dict[position] + if extruder_info.root_material_id is None: + continue + + root_material_id = extruder_info.root_material_id + root_material_id = self._old_new_materials.get(root_material_id, root_material_id) + + # get material diameter of this extruder + machine_material_diameter = extruder_stack.materialDiameter + material_node = material_manager.getMaterialNode(global_stack.definition.getId(), + extruder_stack.variant.getName(), + machine_material_diameter, + root_material_id) + if material_node is not None: + extruder_stack.material = material_node.getContainer() + + def _applyChangesToMachine(self, global_stack, extruder_stack_dict): + # Clear all first + self._clearStack(global_stack) + for extruder_stack in extruder_stack_dict.values(): + self._clearStack(extruder_stack) + + self._applyDefinitionChanges(global_stack, extruder_stack_dict) + self._applyUserChanges(global_stack, extruder_stack_dict) + self._applyVariants(global_stack, extruder_stack_dict) + self._applyMaterials(global_stack, extruder_stack_dict) + + # prepare the quality to select + self._quality_changes_to_apply = None + self._quality_type_to_apply = None + if self._machine_info.quality_changes_info is not None: + self._quality_changes_to_apply = self._machine_info.quality_changes_info.name + else: + self._quality_type_to_apply = self._machine_info.quality_type + def _updateActiveMachine(self, global_stack): # Actually change the active machine. machine_manager = Application.getInstance().getMachineManager() material_manager = Application.getInstance().getMaterialManager() + quality_manager = Application.getInstance().getQualityManager() - # Switch materials if new materials are created due to conflicts - # We do it here because MaterialManager hasn't been updated in _read() yet. - for position, root_material_id in self._materials_to_select.items(): - extruder_stack = global_stack.extruders[position] - material_diameter = extruder_stack.materialDiameter - material_node = material_manager.getMaterialNode(global_stack.getMetaDataEntry("definition"), - extruder_stack.variant.getName(), - material_diameter, root_material_id) - if material_node is None: - Application.getInstance().callLater(self._updateActiveMachine, global_stack) - return - extruder_stack.material = material_node.getContainer() - Logger.log("d", "Changed extruder [%s] to material [%s]", position, root_material_id) + # Force update the lookup maps first + material_manager.initialize() + quality_manager.initialize() machine_manager.setActiveMachine(global_stack.getId()) + if self._quality_changes_to_apply: + quality_changes_group_dict = quality_manager.getQualityChangesGroups(global_stack) + if self._quality_changes_to_apply not in quality_changes_group_dict: + Logger.log("e", "Could not find quality_changes [%s]", self._quality_changes_to_apply) + return + quality_changes_group = quality_changes_group_dict[self._quality_changes_to_apply] + machine_manager.setQualityChangesGroup(quality_changes_group) + else: + self._quality_type_to_apply = self._quality_type_to_apply.lower() + quality_group_dict = quality_manager.getQualityGroups(global_stack) + if self._quality_type_to_apply in quality_group_dict: + quality_group = quality_group_dict[self._quality_type_to_apply] + else: + Logger.log("i", "Could not find quality type [%s], switch to default", self._quality_type_to_apply) + preferred_quality_type = global_stack.getMetaDataEntry("preferred_quality_type") + quality_group_dict = quality_manager.getQualityGroups(global_stack) + quality_group = quality_group_dict.get(preferred_quality_type) + if quality_group is None: + Logger.log("e", "Could not get preferred quality type [%s]", preferred_quality_type) + + if quality_group is not None: + machine_manager.setQualityGroup(quality_group) + # Notify everything/one that is to notify about changes. global_stack.containersChanged.emit(global_stack.getTop()) - ## HACK: Replaces the material container in the given stack with a newly created material container. - # This function is used when the user chooses to resolve material conflicts by creating new ones. - def _replaceStackMaterialWithNew(self, stack, old_new_material_dict): - # The material containers in the project file are 'parent' material such as "generic_pla", - # but a material container used in a global/extruder stack is a 'child' material, - # such as "generic_pla_ultimaker3_AA_0.4", which can be formalised as the following: - # - # __ - # - # In the project loading, when a user chooses to resolve material conflicts by creating new ones, - # the old 'parent' material ID and the new 'parent' material ID are known, but not the child material IDs. - # In this case, the global stack and the extruder stacks need to use the newly created material, but the - # material containers they use are 'child' material. So, here, we need to find the right 'child' material for - # the stacks. - # - # This hack approach works as follows: - # - No matter there is a child material or not, the actual material we are looking for has the prefix - # "", which is the old material name. For the material in a stack, we know that the new - # material's ID will be "_blabla..", so we just need to replace the old material ID - # with the new one to get the new 'child' material. - # - Because the material containers have IDs such as "m #nn", if we use simple prefix matching, there can - # be a problem in the following scenario: - # - there are two materials in the project file, namely "m #1" and "m #11" - # - the child materials in use are for example: "m #1_um3_aa04", "m #11_um3_aa04" - # - if we only check for a simple prefix match, then "m #11_um3_aa04" will match with "m #1", but they - # are not the same material - # To avoid this, when doing the prefix matching, we use the result with the longest mactching prefix. - - # find the old material ID - old_material_id_in_stack = stack.material.getId() - best_matching_old_material_id = None - best_matching_old_material_prefix_length = -1 - for old_parent_material_id in old_new_material_dict: - if len(old_parent_material_id) < best_matching_old_material_prefix_length: - continue - if len(old_parent_material_id) <= len(old_material_id_in_stack): - if old_parent_material_id == old_material_id_in_stack[0:len(old_parent_material_id)]: - best_matching_old_material_prefix_length = len(old_parent_material_id) - best_matching_old_material_id = old_parent_material_id - - if best_matching_old_material_id is None: - Logger.log("w", "Cannot find any matching old material ID for stack [%s] material [%s]. Something can go wrong", - stack.getId(), old_material_id_in_stack) - return - - # find the new material container - new_material_id = old_new_material_dict[best_matching_old_material_id].getId() + old_material_id_in_stack[len(best_matching_old_material_id):] - new_material_containers = self._container_registry.findInstanceContainers(id = new_material_id, type = "material") - if not new_material_containers: - Logger.log("e", "Cannot find new material container [%s]", new_material_id) - return - - # replace the material in the given stack - stack.material = new_material_containers[0] - def _stripFileToId(self, file): mime_type = MimeTypeDatabase.getMimeTypeForFile(file) file = mime_type.stripExtension(file) @@ -1239,7 +1010,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): ## Get the list of ID's of all containers in a container stack by partially parsing it's serialized data. def _getContainerIdListFromSerialized(self, serialized): - parser = configparser.ConfigParser(interpolation=None, empty_lines_in_values=False) + parser = ConfigParser(interpolation=None, empty_lines_in_values=False) parser.read_string(serialized) container_ids = [] @@ -1260,7 +1031,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): return container_ids def _getMachineNameFromSerializedStack(self, serialized): - parser = configparser.ConfigParser(interpolation=None, empty_lines_in_values=False) + parser = ConfigParser(interpolation=None, empty_lines_in_values=False) parser.read_string(serialized) return parser["general"].get("name", "") diff --git a/plugins/3MFReader/WorkspaceDialog.py b/plugins/3MFReader/WorkspaceDialog.py index 5b474843d5..bb31afd40b 100644 --- a/plugins/3MFReader/WorkspaceDialog.py +++ b/plugins/3MFReader/WorkspaceDialog.py @@ -52,7 +52,6 @@ class WorkspaceDialog(QObject): machineConflictChanged = pyqtSignal() qualityChangesConflictChanged = pyqtSignal() - definitionChangesConflictChanged = pyqtSignal() materialConflictChanged = pyqtSignal() numVisibleSettingsChanged = pyqtSignal() activeModeChanged = pyqtSignal() @@ -196,10 +195,6 @@ class WorkspaceDialog(QObject): def qualityChangesConflict(self): return self._has_quality_changes_conflict - @pyqtProperty(bool, notify=definitionChangesConflictChanged) - def definitionChangesConflict(self): - return self._has_definition_changes_conflict - @pyqtProperty(bool, notify=materialConflictChanged) def materialConflict(self): return self._has_material_conflict @@ -229,18 +224,11 @@ class WorkspaceDialog(QObject): self._has_quality_changes_conflict = quality_changes_conflict self.qualityChangesConflictChanged.emit() - def setDefinitionChangesConflict(self, definition_changes_conflict): - if self._has_definition_changes_conflict != definition_changes_conflict: - self._has_definition_changes_conflict = definition_changes_conflict - self.definitionChangesConflictChanged.emit() - def getResult(self): if "machine" in self._result and not self._has_machine_conflict: self._result["machine"] = None if "quality_changes" in self._result and not self._has_quality_changes_conflict: self._result["quality_changes"] = None - if "definition_changes" in self._result and not self._has_definition_changes_conflict: - self._result["definition_changes"] = None if "material" in self._result and not self._has_material_conflict: self._result["material"] = None From ef8cd304dc847a61fd45f3b69aa49d30774faac8 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 8 Mar 2018 20:00:19 +0100 Subject: [PATCH 184/446] No keep/discard setting dialog in project loading CURA-4966 --- cura/Settings/MachineManager.py | 8 ++++---- plugins/3MFReader/ThreeMFWorkspaceReader.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index f8692da0e3..1b3f01170e 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1012,13 +1012,13 @@ class MachineManager(QObject): self._updateQualityWithMaterial() @pyqtSlot(QObject) - def setQualityGroup(self, quality_group): + def setQualityGroup(self, quality_group, no_dialog = False): self.blurSettings.emit() with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): self._setQualityGroup(quality_group) # See if we need to show the Discard or Keep changes screen - if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1: + if not no_dialog and self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1: self._application.discardOrKeepProfileChanges() @pyqtProperty(QObject, fset = setQualityGroup, notify = activeQualityGroupChanged) @@ -1026,13 +1026,13 @@ class MachineManager(QObject): return self._current_quality_group @pyqtSlot(QObject) - def setQualityChangesGroup(self, quality_changes_group): + def setQualityChangesGroup(self, quality_changes_group, no_dialog = False): self.blurSettings.emit() with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): self._setQualityChangesGroup(quality_changes_group) # See if we need to show the Discard or Keep changes screen - if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1: + if not no_dialog and self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1: self._application.discardOrKeepProfileChanges() @pyqtProperty(QObject, fset = setQualityChangesGroup, notify = activeQualityChangesGroupChanged) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 4698d498d2..b02dda4b83 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -980,7 +980,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): Logger.log("e", "Could not find quality_changes [%s]", self._quality_changes_to_apply) return quality_changes_group = quality_changes_group_dict[self._quality_changes_to_apply] - machine_manager.setQualityChangesGroup(quality_changes_group) + machine_manager.setQualityChangesGroup(quality_changes_group, no_dialog = True) else: self._quality_type_to_apply = self._quality_type_to_apply.lower() quality_group_dict = quality_manager.getQualityGroups(global_stack) @@ -995,7 +995,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): Logger.log("e", "Could not get preferred quality type [%s]", preferred_quality_type) if quality_group is not None: - machine_manager.setQualityGroup(quality_group) + machine_manager.setQualityGroup(quality_group, no_dialog = True) # Notify everything/one that is to notify about changes. global_stack.containersChanged.emit(global_stack.getTop()) From a4f9c91d9526d62112f869bcedd6bbd348a22506 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 9 Mar 2018 09:30:32 +0100 Subject: [PATCH 185/446] Add acceleration/jerk data for TEVO Tarantula Thanks to @SuperBoppy in ticket #3323. --- resources/definitions/tevo_tarantula.def.json | 82 +++++++------------ 1 file changed, 30 insertions(+), 52 deletions(-) diff --git a/resources/definitions/tevo_tarantula.def.json b/resources/definitions/tevo_tarantula.def.json index a9f9cefff2..c3bfb38192 100644 --- a/resources/definitions/tevo_tarantula.def.json +++ b/resources/definitions/tevo_tarantula.def.json @@ -2,7 +2,8 @@ "version": 2, "name": "Tevo Tarantula", "inherits": "fdmprinter", - "metadata": { + "metadata": + { "visible": true, "author": "TheAssassin", "manufacturer": "Tevo", @@ -11,62 +12,39 @@ "platform": "prusai3_platform.stl" }, - "overrides": { - "machine_name": { - "default_value": "Tevo Tarantula" - }, - "machine_heated_bed": { - "default_value": true - }, - "machine_width": { - "default_value": 200 - }, - "machine_height": { - "default_value": 200 - }, - "machine_depth": { - "default_value": 200 - }, - "machine_center_is_zero": { - "default_value": false - }, - "machine_nozzle_size": { - "default_value": 0.4 - }, - "material_diameter": { - "default_value": 1.75 - }, - "machine_head_polygon": { - "default_value": [ + "overrides": + { + "machine_name": { "default_value": "Tevo Tarantula" }, + "machine_heated_bed": { "default_value": true }, + "machine_width": { "default_value": 200 }, + "machine_height": { "default_value": 200 }, + "machine_depth": { "default_value": 200 }, + "machine_center_is_zero": { "default_value": false }, + "machine_nozzle_size": { "default_value": 0.4 }, + "material_diameter": { "default_value": 1.75 }, + "machine_head_polygon": + { + "default_value": + [ [-75, -18], [-75, 35], [18, 35], [18, -18] ] }, - "gantry_height": { - "default_value": 55 - }, - "machine_gcode_flavor": { - "default_value": "RepRap (Marlin/Sprinter)" - }, - "machine_acceleration": { - "default_value": 500 - }, - "machine_max_jerk_xy": { - "default_value": 4.0 - }, - "machine_max_jerk_z": { - "default_value": 0.2 - }, - "machine_max_jerk_e": { - "default_value": 2.5 - }, - "machine_start_gcode": { - "default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15.0 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E3 ;extrude 3mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\n;Put printing message on LCD screen\nM117 Printing..." - }, - "machine_end_gcode": { - "default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG90 ;absolute positioning\nG1 X0 Y200 F3600 ;move extruder out of the way by moving the baseplate to the front for easier access to printed object\nM84 ;steppers off" - } + "gantry_height": { "default_value": 55 }, + "machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" }, + "machine_acceleration": { "default_value": 2650 }, + "machine_max_jerk_xy": { "default_value": 15.0 }, + "machine_max_jerk_z": { "default_value": 0.4 }, + "machine_max_jerk_e": { "default_value": 5 }, + "machine_max_feedrate_x": { "default_value": 255 }, + "machine_max_feedrate_y": { "default_value": 225 }, + "machine_max_feedrate_z": { "default_value": 3 }, + "machine_max_acceleration_x": { "default_value": 2620 }, + "machine_max_acceleration_y": { "default_value": 2650 }, + "acceleration_print": { "default_value": 2650 }, + "machine_start_gcode": { "default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15.0 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E3 ;extrude 3mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\n;Put printing message on LCD screen\nM117 Printing..." }, + "machine_end_gcode": { "default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG90 ;absolute positioning\nG1 X0 Y200 F3600 ;move extruder out of the way by moving the baseplate to the front for easier access to printed object\nM84 ;steppers off" } } } From 15f017b404576ae588013a74481b2231bc262c0a Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 9 Mar 2018 10:18:47 +0100 Subject: [PATCH 186/446] Set dirty for containers created in project loading CURA-5056 --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index b02dda4b83..ac61016de7 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -691,6 +691,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): if need_new_name: new_name = ContainerRegistry.getInstance().uniqueName(material_container.getName()) material_container.setName(new_name) + material_container.setDirty(True) self._container_registry.addContainer(material_container) Job.yieldThread() From c278942cecf980ff26d53ba29268e29eed06416e Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Fri, 9 Mar 2018 10:26:48 +0100 Subject: [PATCH 187/446] CURA-67 Don't enable by default `value` is set to !support and !tree support, both of which are typically disabled by default, making this setting's default value effectively `true` even though the line above says the default should be `false`. --- resources/definitions/fdmprinter.def.json | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index f7c014ad61..12ba59b8a1 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -6236,7 +6236,6 @@ "description": "Detect bridges and modify print speed, flow and fan settings while bridges are printed.", "type": "bool", "default_value": false, - "value": "not support_enable and not support_tree_enable", "settable_per_mesh": true, "settable_per_extruder": false, "settable_per_meshgroup": false From 6bee5bf1b034a0306ed54374153e2acb965f8466 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Fri, 9 Mar 2018 10:36:34 +0100 Subject: [PATCH 188/446] CURA-4972 Tweak per review comments --- plugins/CuraEngineBackend/StartSliceJob.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index afbc816cc5..31ea999161 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -139,7 +139,7 @@ class StartSliceJob(Job): # Don't slice if there is a per object setting with an error value. for node in DepthFirstIterator(self._scene.getRoot()): - if type(node) is not CuraSceneNode or not node.isSelectable(): + if not isinstance(node, CuraSceneNode) or not node.isSelectable(): continue if self._checkStackForErrors(node.callDecoration("getStack")): From 4be4d08d97a5f90ec5f981f7cab7a972cb00fcfb Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Fri, 9 Mar 2018 10:47:08 +0100 Subject: [PATCH 189/446] CURA-4870 Add the ability in Cura to switch between different types of printers. Create a new container stack if it doesn't exist with the same network connection key. --- cura/Settings/MachineManager.py | 47 ++++++++++++++++++------- resources/qml/Menus/PrinterTypeMenu.qml | 8 ++--- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index c95f9d28f9..c42a0152ef 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -352,12 +352,25 @@ class MachineManager(QObject): self.__emitChangedSignals() + ## Given a definition id, return the machine with this id. + # Optional: add a list of keys and values to filter the list of machines with the given definition id + # \param definition_id \type{str} definition id that needs to look for + # \param metadata_filter \type{dict} list of metadata keys and values used for filtering @staticmethod - def getMachine(definition_id: str) -> Optional["GlobalStack"]: + def getMachine(definition_id: str, metadata_filter: Dict[str, str] = None) -> Optional["GlobalStack"]: machines = ContainerRegistry.getInstance().findContainerStacks(type = "machine") for machine in machines: if machine.definition.getId() == definition_id: - return machine + if metadata_filter: + pass_all_filters = True + for key in metadata_filter: + if machine.getMetaDataEntry(key) != metadata_filter[key]: + pass_all_filters = False + break + if pass_all_filters: + return machine + else: + return machine return None @pyqtSlot(str, str) @@ -1044,21 +1057,31 @@ class MachineManager(QObject): self._setMaterial(position, new_material) continue - def switchPrinterType(self, machine_type): - container_registry = ContainerRegistry.getInstance() - machine_definition = container_registry.findDefinitionContainers(name = machine_type)[0] - self._global_container_stack.definition = machine_definition - self.globalContainerChanged.emit() - # machine_stack = CuraStackBuilder.createMachine("ultimaker_s5" + "_instance", "ultimaker_s5") - # # if not machine_stack: - # # raise Exception("No machine found for ID {}".format(machine_id)) - # Logger.log("d", "Setting active machine to %s", machine_stack.getId()) - # self.setActiveMachine(machine_stack.getId()) + ## Given a printer definition name, select the right machine instance. In case it doesn't exist, create a new + # instance with the same network key. + @pyqtSlot(str) + def switchPrinterType(self, machine_name): + # Don't switch if the user tries to change to the same type of printer + if self.activeMachineDefinitionName == machine_name: + return + # Get the definition id corresponding to this machine name + machine_definition_id = ContainerRegistry.getInstance().findDefinitionContainers(name = machine_name)[0].getId() + # Try to find a machine with the same network key + new_machine = self.getMachine(machine_definition_id, metadata_filter = {"um_network_key": self.activeMachineNetworkKey}) + # If there is no machine, then create a new one + if not new_machine: + new_machine = CuraStackBuilder.createMachine(machine_definition_id + "_instance", machine_definition_id) + new_machine.addMetaDataEntry("um_network_key", self.activeMachineNetworkKey) + else: + Logger.log("i", "Found a %s with the key %s. Let's use it!", machine_name, self.activeMachineNetworkKey) + + self.setActiveMachine(new_machine.getId()) @pyqtSlot(QObject) def applyRemoteConfiguration(self, configuration: ConfigurationModel): self.blurSettings.emit() with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): + self.switchPrinterType(configuration.printerType) for extruder_configuration in configuration.extruderConfigurations: position = str(extruder_configuration.position) variant_container_node = self._variant_manager.getVariantNode(self._global_container_stack.definition.getId(), extruder_configuration.hotendID) diff --git a/resources/qml/Menus/PrinterTypeMenu.qml b/resources/qml/Menus/PrinterTypeMenu.qml index e84f53a4ba..0cb98bc1aa 100644 --- a/resources/qml/Menus/PrinterTypeMenu.qml +++ b/resources/qml/Menus/PrinterTypeMenu.qml @@ -23,10 +23,10 @@ Menu checkable: true checked: Cura.MachineManager.activeMachineDefinitionName == modelData.machine_type exclusiveGroup: group -// onTriggered: -// { -// TODO -// } + onTriggered: + { + Cura.MachineManager.switchPrinterType(modelData.machine_type) + } } onObjectAdded: menu.insertItem(index, object) onObjectRemoved: menu.removeItem(object) From 3550ef80e0d6734320b46dd344b55e3a97462fb6 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 9 Mar 2018 10:59:33 +0100 Subject: [PATCH 190/446] Fix quality management page QML CURA-5063 --- cura/Machines/Models/QualitySettingsModel.py | 2 +- resources/qml/Preferences/ProfileTab.qml | 17 +++++++++++++---- resources/qml/Preferences/ProfilesPage.qml | 11 +++++++---- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/cura/Machines/Models/QualitySettingsModel.py b/cura/Machines/Models/QualitySettingsModel.py index 38b7ec28e4..e0b29d77a5 100644 --- a/cura/Machines/Models/QualitySettingsModel.py +++ b/cura/Machines/Models/QualitySettingsModel.py @@ -69,7 +69,7 @@ class QualitySettingsModel(ListModel): return self._selected_quality_item def _update(self): - if self._selected_quality_item is None: + if not self._selected_quality_item: self.setItems([]) return diff --git a/resources/qml/Preferences/ProfileTab.qml b/resources/qml/Preferences/ProfileTab.qml index 40f725e092..e202e933f3 100644 --- a/resources/qml/Preferences/ProfileTab.qml +++ b/resources/qml/Preferences/ProfileTab.qml @@ -14,6 +14,15 @@ Tab property string extruderPosition: "" property var qualityItem: null + property bool isQualityItemCurrentlyActivated: + { + if (qualityItem == null) + { + return false; + } + return qualityItem.name == Cura.MachineManager.activeQualityOrQualityChangesName; + } + TableView { anchors.fill: parent @@ -36,8 +45,8 @@ Tab anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.right: parent.right text: (styleData.value.substr(0,1) == "=") ? catalog.i18nc("@info:status", "Calculated") : styleData.value - font.strikeout: styleData.column == 1 && setting.user_value != "" && qualityItem.name == Cura.MachineManager.activeQualityOrQualityChangesName - font.italic: setting.profile_value_source == "quality_changes" || (setting.user_value != "" && qualityItem.name == Cura.MachineManager.activeQualityOrQualityChangesName) + font.strikeout: styleData.column == 1 && setting.user_value != "" && base.isQualityItemCurrentlyActivated + font.italic: setting.profile_value_source == "quality_changes" || (setting.user_value != "" && base.isQualityItemCurrentlyActivated) opacity: font.strikeout ? 0.5 : 1 color: styleData.textColor elide: Text.ElideRight @@ -63,7 +72,7 @@ Tab { role: "user_value" title: catalog.i18nc("@title:column", "Current"); - visible: qualityItem.name == Cura.MachineManager.activeQualityOrQualityChangesName + visible: base.isQualityItemCurrentlyActivated width: (parent.width * 0.18) | 0 delegate: itemDelegate } @@ -86,7 +95,7 @@ Tab { id: qualitySettings selectedPosition: base.extruderPosition - selectedQualityItem: base.qualityItem + selectedQualityItem: base.qualityItem == null ? {} : base.qualityItem } SystemPalette { id: palette } diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 3e10aca000..ff35e27eeb 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -36,13 +36,15 @@ Item text: catalog.i18nc("@title:tab", "Profiles") } - property var hasCurrentItem: qualityListView.currentItem != null + property var hasCurrentItem: base.currentItem != null property var currentItem: { var current_index = qualityListView.currentIndex; - return qualitiesModel.getItem(current_index); + return (current_index == -1) ? null : qualitiesModel.getItem(current_index); } + property var currentItemName: hasCurrentItem ? base.currentItem.name : "" + property var isCurrentItemActivated: { if (!base.currentItem) { return false; @@ -235,7 +237,7 @@ Item icon: StandardIcon.Question; title: catalog.i18nc("@title:window", "Confirm Remove") - text: catalog.i18nc("@label (%1 is object name)", "Are you sure you wish to remove %1? This cannot be undone!").arg(base.currentItem.name) + text: catalog.i18nc("@label (%1 is object name)", "Are you sure you wish to remove %1? This cannot be undone!").arg(base.currentItemName) standardButtons: StandardButton.Yes | StandardButton.No modality: Qt.ApplicationModal @@ -437,6 +439,7 @@ Item Item { anchors.fill: parent + visible: base.currentItem != null Item // Profile title Label { @@ -446,7 +449,7 @@ Item height: childrenRect.height Label { - text: base.currentItem.name + text: base.currentItemName font: UM.Theme.getFont("large") } } From d8853b8a98618ba18d050a9b893c84df987c8845 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 9 Mar 2018 11:39:40 +0100 Subject: [PATCH 191/446] Sort profile models case-insensitively Cast every sorting key to uppercase before doing this. Don't cast to lowercase or there will be problems with characters that don't have lowercase and with Turkish dotted i vs. undotted i. Fixes #3460. --- cura/Machines/Models/BrandMaterialsModel.py | 6 +++--- .../Models/CustomQualityProfilesDropDownMenuModel.py | 2 +- cura/Machines/Models/GenericMaterialsModel.py | 2 +- cura/Machines/Models/MaterialManagementModel.py | 2 +- cura/Machines/Models/NozzleModel.py | 2 +- cura/Machines/Models/QualityManagementModel.py | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cura/Machines/Models/BrandMaterialsModel.py b/cura/Machines/Models/BrandMaterialsModel.py index 2ef1425986..1146a8acee 100644 --- a/cura/Machines/Models/BrandMaterialsModel.py +++ b/cura/Machines/Models/BrandMaterialsModel.py @@ -122,17 +122,17 @@ class BrandMaterialsModel(ListModel): material_type_item["colors"].clear() # Sort materials by name - material_list = sorted(material_list, key = lambda x: x["name"]) + material_list = sorted(material_list, key = lambda x: x["name"].upper()) material_type_item["colors"].setItems(material_list) material_type_item_list.append(material_type_item) # Sort material type by name - material_type_item_list = sorted(material_type_item_list, key = lambda x: x["name"]) + material_type_item_list = sorted(material_type_item_list, key = lambda x: x["name"].upper()) brand_item["materials"].setItems(material_type_item_list) brand_item_list.append(brand_item) # Sort brand by name - brand_item_list = sorted(brand_item_list, key = lambda x: x["name"]) + brand_item_list = sorted(brand_item_list, key = lambda x: x["name"].upper()) self.setItems(brand_item_list) diff --git a/cura/Machines/Models/CustomQualityProfilesDropDownMenuModel.py b/cura/Machines/Models/CustomQualityProfilesDropDownMenuModel.py index 0d297379cd..a188a43e72 100644 --- a/cura/Machines/Models/CustomQualityProfilesDropDownMenuModel.py +++ b/cura/Machines/Models/CustomQualityProfilesDropDownMenuModel.py @@ -23,7 +23,7 @@ class CustomQualityProfilesDropDownMenuModel(QualityProfilesDropDownMenuModel): quality_changes_group_dict = self._quality_manager.getQualityChangesGroups(active_global_stack) item_list = [] - for key in sorted(quality_changes_group_dict): + for key in sorted(quality_changes_group_dict, key = lambda name: name.upper()): quality_changes_group = quality_changes_group_dict[key] item = {"name": quality_changes_group.name, diff --git a/cura/Machines/Models/GenericMaterialsModel.py b/cura/Machines/Models/GenericMaterialsModel.py index d20fc05b6e..47240ebffd 100644 --- a/cura/Machines/Models/GenericMaterialsModel.py +++ b/cura/Machines/Models/GenericMaterialsModel.py @@ -55,6 +55,6 @@ class GenericMaterialsModel(BaseMaterialsModel): item_list.append(item) # Sort the item list by material name alphabetically - item_list = sorted(item_list, key = lambda d: d["name"]) + item_list = sorted(item_list, key = lambda d: d["name"].upper()) self.setItems(item_list) diff --git a/cura/Machines/Models/MaterialManagementModel.py b/cura/Machines/Models/MaterialManagementModel.py index b250232282..1ea0fd9cf7 100644 --- a/cura/Machines/Models/MaterialManagementModel.py +++ b/cura/Machines/Models/MaterialManagementModel.py @@ -97,5 +97,5 @@ class MaterialManagementModel(ListModel): material_list.append(item) - material_list = sorted(material_list, key = lambda k: (k["brand"].lower(), k["name"])) + material_list = sorted(material_list, key = lambda k: (k["brand"].upper(), k["name"].upper())) self.setItems(material_list) diff --git a/cura/Machines/Models/NozzleModel.py b/cura/Machines/Models/NozzleModel.py index 19d4a800c8..27d190962b 100644 --- a/cura/Machines/Models/NozzleModel.py +++ b/cura/Machines/Models/NozzleModel.py @@ -45,7 +45,7 @@ class NozzleModel(ListModel): return item_list = [] - for hotend_name, container_node in sorted(variant_node_dict.items(), key = lambda i: i[0]): + for hotend_name, container_node in sorted(variant_node_dict.items(), key = lambda i: i[0].upper()): item = {"id": hotend_name, "hotend_name": hotend_name, "container_node": container_node diff --git a/cura/Machines/Models/QualityManagementModel.py b/cura/Machines/Models/QualityManagementModel.py index e089f92329..542016ab68 100644 --- a/cura/Machines/Models/QualityManagementModel.py +++ b/cura/Machines/Models/QualityManagementModel.py @@ -59,7 +59,7 @@ class QualityManagementModel(ListModel): "quality_changes_group": None} item_list.append(item) # Sort by quality names - item_list = sorted(item_list, key = lambda x: x["name"]) + item_list = sorted(item_list, key = lambda x: x["name"].upper()) # Create quality_changes group items quality_changes_item_list = [] @@ -74,7 +74,7 @@ class QualityManagementModel(ListModel): quality_changes_item_list.append(item) # Sort quality_changes items by names and append to the item list - quality_changes_item_list = sorted(quality_changes_item_list, key = lambda x: x["name"]) + quality_changes_item_list = sorted(quality_changes_item_list, key = lambda x: x["name"].upper()) item_list += quality_changes_item_list self.setItems(item_list) From 260cad36cb4dd09643b822ec177ae009c11a5161 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Fri, 9 Mar 2018 12:42:49 +0100 Subject: [PATCH 192/446] CURA-4870 Add name of the group and hidden property to the network printers. The printer menu shows the printers grouped by group and the hidden printers are never listed. --- cura/Settings/MachineManager.py | 10 +++++++++- .../UM3NetworkPrinting/DiscoverUM3Action.py | 18 ++++++++++++++++++ .../UM3NetworkPrinting/DiscoverUM3Action.qml | 6 ++++-- resources/qml/Menus/NetworkPrinterMenu.qml | 6 +++--- 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index c42a0152ef..0b9362af59 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -496,6 +496,12 @@ class MachineManager(QObject): return self._global_container_stack.getMetaDataEntry("um_network_key") return "" + @pyqtProperty(str, notify = globalContainerChanged) + def activeMachineNetworkGroupName(self) -> str: + if self._global_container_stack: + return self._global_container_stack.getMetaDataEntry("connect_group_name") + return "" + @pyqtProperty(QObject, notify = globalContainerChanged) def activeMachine(self) -> Optional["GlobalStack"]: return self._global_container_stack @@ -1070,8 +1076,10 @@ class MachineManager(QObject): new_machine = self.getMachine(machine_definition_id, metadata_filter = {"um_network_key": self.activeMachineNetworkKey}) # If there is no machine, then create a new one if not new_machine: - new_machine = CuraStackBuilder.createMachine(machine_definition_id + "_instance", machine_definition_id) + new_machine = CuraStackBuilder.createMachine(machine_definition_id + "_sync", machine_definition_id) new_machine.addMetaDataEntry("um_network_key", self.activeMachineNetworkKey) + new_machine.addMetaDataEntry("connect_group_name", self.activeMachineNetworkGroupName) + new_machine.addMetaDataEntry("hidden", True) else: Logger.log("i", "Found a %s with the key %s. Let's use it!", machine_name, self.activeMachineNetworkKey) diff --git a/plugins/UM3NetworkPrinting/DiscoverUM3Action.py b/plugins/UM3NetworkPrinting/DiscoverUM3Action.py index 0e872fed43..4b972e9040 100644 --- a/plugins/UM3NetworkPrinting/DiscoverUM3Action.py +++ b/plugins/UM3NetworkPrinting/DiscoverUM3Action.py @@ -97,6 +97,23 @@ class DiscoverUM3Action(MachineAction): else: return [] + @pyqtSlot(str) + def setGroupName(self, group_name): + Logger.log("d", "Attempting to set the group name of the active machine to %s", group_name) + global_container_stack = Application.getInstance().getGlobalContainerStack() + if global_container_stack: + meta_data = global_container_stack.getMetaData() + if "connect_group_name" in meta_data: + global_container_stack.setMetaDataEntry("connect_group_name", group_name) + # TODO Find all the places where there is the same group name and change it accordingly + else: + global_container_stack.addMetaDataEntry("connect_group_name", group_name) + global_container_stack.addMetaDataEntry("hidden", False) + + if self._network_plugin: + # Ensure that the connection states are refreshed. + self._network_plugin.reCheckConnections() + @pyqtSlot(str) def setKey(self, key): Logger.log("d", "Attempting to set the network key of the active machine to %s", key) @@ -109,6 +126,7 @@ class DiscoverUM3Action(MachineAction): Logger.log("d", "Removing old authentication id %s for device %s", global_container_stack.getMetaDataEntry("network_authentication_id", None), key) global_container_stack.removeMetaDataEntry("network_authentication_id") global_container_stack.removeMetaDataEntry("network_authentication_key") + # TODO Find all the places where there is the same key and change it accordingly else: global_container_stack.addMetaDataEntry("um_network_key", key) diff --git a/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml b/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml index a5d13b2cdf..079e5dcdd3 100644 --- a/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml +++ b/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml @@ -32,10 +32,12 @@ Cura.MachineAction if(base.selectedDevice && base.completeProperties) { var printerKey = base.selectedDevice.key + var printerName = base.selectedDevice.name // TODO To change when the groups have a name if(manager.getStoredKey() != printerKey) { - manager.setKey(printerKey); - completed(); + manager.setKey(printerKey) + manager.setGroupName(printerName) // TODO To change when the groups have a name + completed() } } } diff --git a/resources/qml/Menus/NetworkPrinterMenu.qml b/resources/qml/Menus/NetworkPrinterMenu.qml index 64539c9892..07a22202e4 100644 --- a/resources/qml/Menus/NetworkPrinterMenu.qml +++ b/resources/qml/Menus/NetworkPrinterMenu.qml @@ -9,14 +9,14 @@ import Cura 1.0 as Cura Instantiator { model: UM.ContainerStacksModel { - filter: {"type": "machine", "um_network_key": "*"} + filter: {"type": "machine", "um_network_key": "*", "hidden": "False"} } MenuItem { // TODO: Use printer_group icon when it's a cluster. Not use it for now since it doesn't look as expected // iconSource: UM.Theme.getIcon("printer_single") - text: model.name; + text: model.metadata["connect_group_name"] checkable: true; - checked: Cura.MachineManager.activeMachineId == model.id + checked: Cura.MachineManager.activeMachineNetworkGroupName == model.metadata["connect_group_name"] exclusiveGroup: group; onTriggered: Cura.MachineManager.setActiveMachine(model.id); } From ebbb30a5be75e4fc3c7f80e317d346e57302ee0a Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Fri, 9 Mar 2018 13:37:15 +0100 Subject: [PATCH 193/446] CURA-4870 Replace network key and connect group name metadata values when the connection changes. --- cura/Settings/MachineManager.py | 7 +++++++ plugins/UM3NetworkPrinting/DiscoverUM3Action.py | 7 +++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 0b9362af59..3bc2df0da1 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1115,6 +1115,13 @@ class MachineManager(QObject): self._global_container_stack.variant = self._empty_variant_container self._updateQualityWithMaterial() + ## Find all container stacks that has the pair 'key = value' in its metadata and replaces the value with 'new_value' + def replaceContainersMetadata(self, key: str, value: str, new_value: str): + machines = ContainerRegistry.getInstance().findContainerStacks(type = "machine") + for machine in machines: + if machine.getMetaDataEntry(key) == value: + machine.setMetaDataEntry(key, new_value) + @pyqtSlot("QVariant") def setGlobalVariant(self, container_node): self.blurSettings.emit() diff --git a/plugins/UM3NetworkPrinting/DiscoverUM3Action.py b/plugins/UM3NetworkPrinting/DiscoverUM3Action.py index 4b972e9040..76e8721fdd 100644 --- a/plugins/UM3NetworkPrinting/DiscoverUM3Action.py +++ b/plugins/UM3NetworkPrinting/DiscoverUM3Action.py @@ -104,8 +104,10 @@ class DiscoverUM3Action(MachineAction): if global_container_stack: meta_data = global_container_stack.getMetaData() if "connect_group_name" in meta_data: + previous_connect_group_name = meta_data["connect_group_name"] global_container_stack.setMetaDataEntry("connect_group_name", group_name) - # TODO Find all the places where there is the same group name and change it accordingly + # Find all the places where there is the same group name and change it accordingly + Application.getInstance().getMachineManager().replaceContainersMetadata(key = "connect_group_name", value = previous_connect_group_name, new_value = group_name) else: global_container_stack.addMetaDataEntry("connect_group_name", group_name) global_container_stack.addMetaDataEntry("hidden", False) @@ -121,12 +123,13 @@ class DiscoverUM3Action(MachineAction): if global_container_stack: meta_data = global_container_stack.getMetaData() if "um_network_key" in meta_data: + previous_network_key= meta_data["um_network_key"] global_container_stack.setMetaDataEntry("um_network_key", key) # Delete old authentication data. Logger.log("d", "Removing old authentication id %s for device %s", global_container_stack.getMetaDataEntry("network_authentication_id", None), key) global_container_stack.removeMetaDataEntry("network_authentication_id") global_container_stack.removeMetaDataEntry("network_authentication_key") - # TODO Find all the places where there is the same key and change it accordingly + Application.getInstance().getMachineManager().replaceContainersMetadata(key = "um_network_key", value = previous_network_key, new_value = key) else: global_container_stack.addMetaDataEntry("um_network_key", key) From fe2a08a46bc8817a5c967cd80f66f4e356e80423 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Fri, 9 Mar 2018 13:38:06 +0100 Subject: [PATCH 194/446] CURA-4870 Do not store buildplate information coming from connect if the printer don't have buildplate in its definition. --- plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py index 8eeb8d91e7..942bc82280 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py @@ -376,11 +376,14 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): # For some unknown reason the cluster wants UUID for everything, except for sending a job directly to a printer. # Then we suddenly need the unique name. So in order to not have to mess up all the other code, we save a mapping. self._printer_uuid_to_unique_name_mapping[data["uuid"]] = data["unique_name"] + machine_definition = ContainerRegistry.getInstance().findDefinitionContainers(name = data["machine_variant"])[0] printer.updateName(data["friendly_name"]) printer.updateKey(data["uuid"]) printer.updateType(data["machine_variant"]) - if "build_plate" in data: + + # Do not store the buildplate information that comes from connect if the current printer has not buildplate information + if "build_plate" in data and machine_definition.getMetaDataEntry("has_variant_buildplates", False): printer.updateBuildplate(data["build_plate"]["type"]) if not data["enabled"]: printer.updateState("disabled") From 970f1da810aee98673652b15f4df008824f11dd7 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 9 Mar 2018 13:47:19 +0100 Subject: [PATCH 195/446] Add missing getVersion and location for quality It worked out because older plug-ins still defined this, but let's properly put it in here too. Contributes to issue CURA-5054. --- plugins/VersionUpgrade/VersionUpgrade30to31/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/VersionUpgrade/VersionUpgrade30to31/__init__.py b/plugins/VersionUpgrade/VersionUpgrade30to31/__init__.py index b4b75dddf7..c853e2b93b 100644 --- a/plugins/VersionUpgrade/VersionUpgrade30to31/__init__.py +++ b/plugins/VersionUpgrade/VersionUpgrade30to31/__init__.py @@ -33,6 +33,10 @@ def getMetaData(): "get_version": upgrade.getCfgVersion, "location": {"./extruders"} }, + "quality": { + "get_version": upgrade.getCfgVersion, + "location": {"./quality"} + }, "quality_changes": { "get_version": upgrade.getCfgVersion, "location": {"./quality"} From 60de2aff657347553d011a6697958f97b43ad0ac Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 9 Mar 2018 13:59:31 +0100 Subject: [PATCH 196/446] Basic upgrade module from 3.2 to 3.3 implementation 'Basic' meaning no implementation at all. Contributes to issue CURA-5054. --- .../VersionUpgrade32to33.py | 18 +++++++++++++++ .../VersionUpgrade32to33/__init__.py | 23 +++++++++++++++++++ .../VersionUpgrade32to33/plugin.json | 8 +++++++ 3 files changed, 49 insertions(+) create mode 100644 plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py create mode 100644 plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py create mode 100644 plugins/VersionUpgrade/VersionUpgrade32to33/plugin.json diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py b/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py new file mode 100644 index 0000000000..64eded8b2e --- /dev/null +++ b/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py @@ -0,0 +1,18 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +import configparser #To parse preference files. +import io #To serialise the preference files afterwards. + +from UM.VersionUpgrade import VersionUpgrade #We're inheriting from this. + +## Upgrades configurations from the state they were in at version 3.2 to the +# state they should be in at version 3.3. +class VersionUpgrade32to33(VersionUpgrade): + ## Gets the version number from a CFG file. + def getCfgVersion(self, serialized): + raise NotImplementedError("This has not yet been implemented.") + + ## Upgrades a quality container to the new format. + def upgradeQuality(self, serialized, filename): + raise NotImplementedError("This has not yet been implemented.") \ No newline at end of file diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py b/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py new file mode 100644 index 0000000000..dbcad86ac4 --- /dev/null +++ b/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py @@ -0,0 +1,23 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from . import VersionUpgrade32to33 + +upgrade = VersionUpgrade32to33.VersionUpgrade32to33() + +def getMetaData(): + return { + "version_upgrade": { + # From To Upgrade function + ("quality", 2000004): ("quality", 3000004, upgrade.upgradeQuality), + }, + "sources": { + "quality": { + "get_version": upgrade.getCfgVersion, + "location": {"./quality"} + } + } + } + +def register(app): + return { "version_upgrade": upgrade } \ No newline at end of file diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/plugin.json b/plugins/VersionUpgrade/VersionUpgrade32to33/plugin.json new file mode 100644 index 0000000000..fbce09c807 --- /dev/null +++ b/plugins/VersionUpgrade/VersionUpgrade32to33/plugin.json @@ -0,0 +1,8 @@ + { + "name": "Version Upgrade 3.2 to 3.3", + "author": "Ultimaker B.V.", + "version": "1.0.0", + "description": "Upgrades configurations from Cura 3.2 to Cura 3.3.", + "api": 4, + "i18n-catalog": "cura" +} From af89209cdeb31eec4abf9ebcb30266239ac35676 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 9 Mar 2018 14:02:04 +0100 Subject: [PATCH 197/446] Changed rounding of prettyTime by accident --- resources/qml/PrintMonitor.qml | 2 +- resources/qml/Sidebar.qml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/qml/PrintMonitor.qml b/resources/qml/PrintMonitor.qml index 0841144043..ae74170004 100644 --- a/resources/qml/PrintMonitor.qml +++ b/resources/qml/PrintMonitor.qml @@ -122,7 +122,7 @@ Column { label: catalog.i18nc("@label", "Printing Time") value: activePrintJob != null ? getPrettyTime(activePrintJob.timeTotal) : "" - width:base.width + width: base.width visible: activePrinter != null } diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml index e04d8607da..e3107ea7f8 100644 --- a/resources/qml/Sidebar.qml +++ b/resources/qml/Sidebar.qml @@ -64,11 +64,11 @@ Rectangle function getPrettyTime(time) { - var hours = Math.round(time / 3600) + var hours = Math.floor(time / 3600) time -= hours * 3600 - var minutes = Math.round(time / 60); + var minutes = Math.floor(time / 60); time -= minutes * 60 - var seconds = Math.round(time); + var seconds = Math.floor(time); var finalTime = strPadLeft(hours, "0", 2) + ':' + strPadLeft(minutes,'0',2)+ ':' + strPadLeft(seconds,'0',2); return finalTime; From e30d15ab666087f6f8411196060a056b592a24ec Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 9 Mar 2018 14:02:15 +0100 Subject: [PATCH 198/446] Implement getCfgVersion Mostly copied from the implementation in the 3.0 to 3.1 upgrade. Contributes to issue CURA-5054. --- .../VersionUpgrade32to33.py | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py b/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py index 64eded8b2e..6f7dbeccef 100644 --- a/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py +++ b/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py @@ -9,9 +9,23 @@ from UM.VersionUpgrade import VersionUpgrade #We're inheriting from this. ## Upgrades configurations from the state they were in at version 3.2 to the # state they should be in at version 3.3. class VersionUpgrade32to33(VersionUpgrade): - ## Gets the version number from a CFG file. - def getCfgVersion(self, serialized): - raise NotImplementedError("This has not yet been implemented.") + ## Gets the version number from a CFG file in Uranium's 3.2 format. + # + # Since the format may change, this is implemented for the 3.2 format only + # and needs to be included in the version upgrade system rather than + # globally in Uranium. + # + # \param serialised The serialised form of a CFG file. + # \return The version number stored in the CFG file. + # \raises ValueError The format of the version number in the file is + # incorrect. + # \raises KeyError The format of the file is incorrect. + def getCfgVersion(self, serialised): + parser = configparser.ConfigParser(interpolation = None) + parser.read_string(serialised) + format_version = int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised. + setting_version = int(parser.get("metadata", "setting_version", fallback = 0)) + return format_version * 1000000 + setting_version ## Upgrades a quality container to the new format. def upgradeQuality(self, serialized, filename): From ae2a286e3f83f22e85f46a3abba64d1cfa6c6924 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Fri, 9 Mar 2018 14:07:29 +0100 Subject: [PATCH 199/446] Improved Icons & Styling --- resources/qml/MachineSelection.qml | 2 +- .../Menus/ConfigurationMenu/SyncButton.qml | 38 +++++++++---------- resources/qml/Menus/PrinterStatusIcon.qml | 4 +- resources/qml/Sidebar.qml | 2 +- .../themes/cura-light/icons/connected.svg | 14 +++++++ .../themes/cura-light/icons/disconnected.svg | 13 +++++++ resources/themes/cura-light/theme.json | 5 ++- 7 files changed, 53 insertions(+), 25 deletions(-) create mode 100644 resources/themes/cura-light/icons/connected.svg create mode 100644 resources/themes/cura-light/icons/disconnected.svg diff --git a/resources/qml/MachineSelection.qml b/resources/qml/MachineSelection.qml index cce2bbea7b..a48045fdbc 100644 --- a/resources/qml/MachineSelection.qml +++ b/resources/qml/MachineSelection.qml @@ -12,7 +12,7 @@ import "Menus" ToolButton { property var isNetworkPrinter: Cura.MachineManager.activeMachineNetworkKey ? true : false - property var printerStatus: Cura.MachineManager.printerOutputDevices.length != 0 ? "connected" : "unknown" + property var printerStatus: Cura.MachineManager.printerOutputDevices.length != 0 ? "connected" : "disconnected" text: Cura.MachineManager.activeMachineName tooltip: Cura.MachineManager.activeMachineName diff --git a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml index 4a92db6e6b..d22dcb1247 100644 --- a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml +++ b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml @@ -12,25 +12,22 @@ Button { id: base property var outputDevice: Cura.MachineManager.printerOutputDevices[0] - text: catalog.i18nc("@label:sync indicator", "No match") + property var matched: updateOnSync() + text: matched == true ? "Yes" : "No" width: parent.width height: parent.height - function updateOnSync() - { - if (outputDevice != undefined) - { - for (var index in outputDevice.uniqueConfigurations) - { + function updateOnSync() { + if (outputDevice != undefined) { + for (var index in outputDevice.uniqueConfigurations) { var configuration = outputDevice.uniqueConfigurations[index] - if (Cura.MachineManager.matchesConfiguration(configuration)) - { - base.text = catalog.i18nc("@label:sync indicator", "Matched") - return + if (Cura.MachineManager.matchesConfiguration(configuration)) { + base.matched = true; + return; } } } - base.text = catalog.i18nc("@label:sync indicator", "No match") + base.matched = false; } style: ButtonStyle @@ -67,18 +64,19 @@ Button color: UM.Theme.getColor("text_emphasis") source: UM.Theme.getIcon("arrow_bottom") } - Label - { + UM.RecolorImage { id: sidebarComboBoxLabel - color: UM.Theme.getColor("sidebar_header_text_active") - text: control.text - elide: Text.ElideRight anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("default_margin").width - anchors.right: downArrow.left - anchors.rightMargin: control.rightMargin anchors.verticalCenter: parent.verticalCenter; - font: UM.Theme.getFont("medium") + + width: UM.Theme.getSize("printer_status_icon").width + height: UM.Theme.getSize("printer_status_icon").height + + color: control.matched ? UM.Theme.getColor("printer_config_matched") : UM.Theme.getColor("printer_config_mismatch") + source: control.matched ? UM.Theme.getIcon("tab_status_connected") : UM.Theme.getIcon("tab_status_unknown") + sourceSize.width: width + sourceSize.height: height } } label: Label {} diff --git a/resources/qml/Menus/PrinterStatusIcon.qml b/resources/qml/Menus/PrinterStatusIcon.qml index 23459386d9..c76ed8bdcb 100644 --- a/resources/qml/Menus/PrinterStatusIcon.qml +++ b/resources/qml/Menus/PrinterStatusIcon.qml @@ -7,7 +7,7 @@ import UM 1.2 as UM import Cura 1.0 as Cura Item { - property var status: "unknown" + property var status: "disconnected" width: childrenRect.width height: childrenRect.height UM.RecolorImage { @@ -17,7 +17,7 @@ Item { sourceSize.width: width sourceSize.height: width color: UM.Theme.getColor("tab_status_" + parent.status ) - source: UM.Theme.getIcon("tab_status_" + parent.status ) + source: UM.Theme.getIcon( parent.status ) } } diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml index a93048cb26..d13de1f7e6 100644 --- a/resources/qml/Sidebar.qml +++ b/resources/qml/Sidebar.qml @@ -107,7 +107,7 @@ Rectangle ConfigurationSelection { id: configSelection visible: printerConnected && !sidebar.monitoringPrint && !sidebar.hideSettings - width: visible ? Math.round(base.width * 0.25) : 0 + width: visible ? Math.round(base.width * 0.15) : 0 height: UM.Theme.getSize("sidebar_header").height anchors.top: base.top anchors.right: parent.right diff --git a/resources/themes/cura-light/icons/connected.svg b/resources/themes/cura-light/icons/connected.svg new file mode 100644 index 0000000000..4f0f10bff4 --- /dev/null +++ b/resources/themes/cura-light/icons/connected.svg @@ -0,0 +1,14 @@ + + + Created with Sketch. + + + + + + + + + + + \ No newline at end of file diff --git a/resources/themes/cura-light/icons/disconnected.svg b/resources/themes/cura-light/icons/disconnected.svg new file mode 100644 index 0000000000..2a045c5f1d --- /dev/null +++ b/resources/themes/cura-light/icons/disconnected.svg @@ -0,0 +1,13 @@ + + + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json index 4cdff3c296..ce6b406d3d 100644 --- a/resources/themes/cura-light/theme.json +++ b/resources/themes/cura-light/theme.json @@ -314,7 +314,10 @@ "tab_status_finished": [255, 255, 255, 255], "tab_status_paused": [255, 255, 255, 255], "tab_status_stopped": [255, 255, 255, 255], - "tab_status_unknown": [200, 200, 200, 255] + "tab_status_disconnected": [200, 200, 200, 255], + + "printer_config_matched": [12, 169, 227, 255], + "printer_config_mismatch": [255, 145, 62, 255] }, "sizes": { From a40be0c64a919707d4c3b723d09560e9d8acc16f Mon Sep 17 00:00:00 2001 From: Andreea Scorojitu Date: Fri, 9 Mar 2018 14:25:35 +0100 Subject: [PATCH 200/446] Add default_build_plate to expert view, CURA-5032 The default build plate settings is now added in Expert view in SettingsVisibility --- resources/preset_setting_visibility_groups/expert.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/preset_setting_visibility_groups/expert.cfg b/resources/preset_setting_visibility_groups/expert.cfg index e180b831d8..d6989f8b26 100644 --- a/resources/preset_setting_visibility_groups/expert.cfg +++ b/resources/preset_setting_visibility_groups/expert.cfg @@ -103,6 +103,7 @@ material_print_temperature_layer_0 material_initial_print_temperature material_final_print_temperature material_extrusion_cool_down_speed +default_material_bed_temperature material_bed_temperature material_bed_temperature_layer_0 material_diameter From de72dd3455218a240acd0bbf4c25b423c6cc77ff Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 9 Mar 2018 14:26:14 +0100 Subject: [PATCH 201/446] Fix material update upon gcode flavour change CURA-5060 --- cura/Machines/MaterialManager.py | 4 +- cura/Settings/MachineManager.py | 6 ++- .../MachineSettingsAction.py | 43 ++++++++++--------- 3 files changed, 28 insertions(+), 25 deletions(-) diff --git a/cura/Machines/MaterialManager.py b/cura/Machines/MaterialManager.py index 89b3a76f9a..7c205c0084 100644 --- a/cura/Machines/MaterialManager.py +++ b/cura/Machines/MaterialManager.py @@ -357,10 +357,10 @@ class MaterialManager(QObject): else: return None - def getDefaultMaterial(self, global_stack: "GlobalStack", extruder_variant_name: str) -> Optional["MaterialNode"]: + def getDefaultMaterial(self, global_stack: "GlobalStack", extruder_variant_name: Optional[str]) -> Optional["MaterialNode"]: node = None machine_definition = global_stack.definition - if parseBool(machine_definition.getMetaDataEntry("has_materials", False)): + if parseBool(global_stack.getMetaDataEntry("has_materials", False)): material_diameter = machine_definition.getProperty("material_diameter", "value") if isinstance(material_diameter, SettingFunction): material_diameter = material_diameter(global_stack) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 1b3f01170e..144f495997 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -905,11 +905,13 @@ class MachineManager(QObject): def _setMaterial(self, position, container_node = None): if container_node: self._global_container_stack.extruders[position].material = container_node.getContainer() + root_material_id = container_node.metadata["base_file"] + root_material_name = container_node.getContainer().getName() else: self._global_container_stack.extruders[position].material = self._empty_material_container + root_material_id = None + root_material_name = None # The _current_root_material_id is used in the MaterialMenu to see which material is selected - root_material_id = container_node.metadata["base_file"] - root_material_name = container_node.getContainer().getName() if root_material_id != self._current_root_material_id[position]: self._current_root_material_id[position] = root_material_id self._current_root_material_name[position] = root_material_name diff --git a/plugins/MachineSettingsAction/MachineSettingsAction.py b/plugins/MachineSettingsAction/MachineSettingsAction.py index baa0639d3f..bac4af69cc 100755 --- a/plugins/MachineSettingsAction/MachineSettingsAction.py +++ b/plugins/MachineSettingsAction/MachineSettingsAction.py @@ -26,6 +26,8 @@ class MachineSettingsAction(MachineAction): super().__init__("MachineSettingsAction", catalog.i18nc("@action", "Machine Settings")) self._qml_url = "MachineSettingsAction.qml" + self._application = Application.getInstance() + self._global_container_stack = None from cura.Settings.CuraContainerStack import _ContainerIndexes @@ -34,16 +36,16 @@ class MachineSettingsAction(MachineAction): self._container_registry = ContainerRegistry.getInstance() self._container_registry.containerAdded.connect(self._onContainerAdded) self._container_registry.containerRemoved.connect(self._onContainerRemoved) - Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged) + self._application.globalContainerStackChanged.connect(self._onGlobalContainerChanged) self._empty_container = self._container_registry.getEmptyInstanceContainer() - self._backend = Application.getInstance().getBackend() + self._backend = self._application.getBackend() def _onContainerAdded(self, container): # Add this action as a supported action to all machine definitions if isinstance(container, DefinitionContainer) and container.getMetaDataEntry("type") == "machine": - Application.getInstance().getMachineActionManager().addSupportedAction(container.getId(), self.getKey()) + self._application.getMachineActionManager().addSupportedAction(container.getId(), self.getKey()) def _onContainerRemoved(self, container): # Remove definition_changes containers when a stack is removed @@ -61,11 +63,11 @@ class MachineSettingsAction(MachineAction): # Make sure there is a definition_changes container to store the machine settings definition_changes_container = self._global_container_stack.definitionChanges if definition_changes_container == self._empty_container: - definition_changes_container = CuraStackBuilder.createDefinitionChangesContainer( - self._global_container_stack, self._global_container_stack.getName() + "_settings") + CuraStackBuilder.createDefinitionChangesContainer(self._global_container_stack, + self._global_container_stack.getName() + "_settings") # Notify the UI in which container to store the machine settings data - from cura.Settings.CuraContainerStack import CuraContainerStack, _ContainerIndexes + from cura.Settings.CuraContainerStack import _ContainerIndexes container_index = _ContainerIndexes.DefinitionChanges if container_index != self._container_index: @@ -107,13 +109,13 @@ class MachineSettingsAction(MachineAction): def setMachineExtruderCount(self, extruder_count): # Note: this method was in this class before, but since it's quite generic and other plugins also need it # it was moved to the machine manager instead. Now this method just calls the machine manager. - Application.getInstance().getMachineManager().setActiveMachineExtruderCount(extruder_count) + self._application.getMachineManager().setActiveMachineExtruderCount(extruder_count) @pyqtSlot() def forceUpdate(self): # Force rebuilding the build volume by reloading the global container stack. # This is a bit of a hack, but it seems quick enough. - Application.getInstance().globalContainerStackChanged.emit() + self._application.globalContainerStackChanged.emit() @pyqtSlot() def updateHasMaterialsMetadata(self): @@ -126,9 +128,11 @@ class MachineSettingsAction(MachineAction): # In other words: only continue for the UM2 (extended), but not for the UM2+ return - stacks = ExtruderManager.getInstance().getExtruderStacks() + machine_manager = self._application.getMachineManager() + extruder_positions = list(self._global_container_stack.extruders.keys()) has_materials = self._global_container_stack.getProperty("machine_gcode_flavor", "value") != "UltiGCode" + material_node = None if has_materials: if "has_materials" in self._global_container_stack.getMetaData(): self._global_container_stack.setMetaDataEntry("has_materials", True) @@ -136,26 +140,23 @@ class MachineSettingsAction(MachineAction): self._global_container_stack.addMetaDataEntry("has_materials", True) # Set the material container for each extruder to a sane default - for stack in stacks: - material_container = stack.material - if material_container == self._empty_container: - machine_approximate_diameter = str(round(self._global_container_stack.getProperty("material_diameter", "value"))) - search_criteria = { "type": "material", "definition": "fdmprinter", "id": self._global_container_stack.getMetaDataEntry("preferred_material"), "approximate_diameter": machine_approximate_diameter} - materials = self._container_registry.findInstanceContainers(**search_criteria) - if materials: - stack.material = materials[0] + material_manager = self._application.getMaterialManager() + #material_manager.initialize() + material_node = material_manager.getDefaultMaterial(self._global_container_stack, None) + else: # The metadata entry is stored in an ini, and ini files are parsed as strings only. # Because any non-empty string evaluates to a boolean True, we have to remove the entry to make it False. if "has_materials" in self._global_container_stack.getMetaData(): self._global_container_stack.removeMetaDataEntry("has_materials") - for stack in stacks: - stack.material = ContainerRegistry.getInstance().getEmptyInstanceContainer() + # set materials + for position in extruder_positions: + machine_manager.setMaterial(position, material_node) - Application.getInstance().globalContainerStackChanged.emit() + self._application.globalContainerStackChanged.emit() @pyqtSlot(int) def updateMaterialForDiameter(self, extruder_position: int): # Updates the material container to a material that matches the material diameter set for the printer - Application.getInstance().getExtruderManager().updateMaterialForDiameter(extruder_position) + self._application.getExtruderManager().updateMaterialForDiameter(extruder_position) From 48dae7b6c79dc426692cb7e2ffb4c40a1d907f09 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 9 Mar 2018 14:35:37 +0100 Subject: [PATCH 202/446] Remove commented code CURA-5060 --- plugins/MachineSettingsAction/MachineSettingsAction.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/MachineSettingsAction/MachineSettingsAction.py b/plugins/MachineSettingsAction/MachineSettingsAction.py index bac4af69cc..a97f3b463f 100755 --- a/plugins/MachineSettingsAction/MachineSettingsAction.py +++ b/plugins/MachineSettingsAction/MachineSettingsAction.py @@ -141,7 +141,6 @@ class MachineSettingsAction(MachineAction): # Set the material container for each extruder to a sane default material_manager = self._application.getMaterialManager() - #material_manager.initialize() material_node = material_manager.getDefaultMaterial(self._global_container_stack, None) else: From 8c7e413038c0f1af6612b8e8d33b47d489e2ba3a Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 9 Mar 2018 14:37:41 +0100 Subject: [PATCH 203/446] Remove unnecessary setGlobalContainerStack() in project loading CURA-5073 --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index ac61016de7..7201df65e4 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -709,7 +709,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # function is running on the main thread (Qt thread), although those "changed" signals have been emitted, but # they won't take effect until this function is done. # To solve this, we schedule _updateActiveMachine() for later so it will have the latest data. - Application.getInstance().setGlobalContainerStack(global_stack) self._updateActiveMachine(global_stack) # Load all the nodes / meshdata of the workspace From fb814b6519764c6f94cfe9c330b81db884449368 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 9 Mar 2018 14:54:08 +0100 Subject: [PATCH 204/446] Implement upgrade for quality changes extruder metadata The metadata used to be the ID of the extruder. Now it's the position of the extruder stack. Contributes to issue CURA-5054. --- .../VersionUpgrade32to33.py | 71 ++++++++++++++++++- .../VersionUpgrade32to33/__init__.py | 6 +- 2 files changed, 71 insertions(+), 6 deletions(-) diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py b/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py index 6f7dbeccef..2b8818177f 100644 --- a/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py +++ b/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py @@ -6,6 +6,53 @@ import io #To serialise the preference files afterwards. from UM.VersionUpgrade import VersionUpgrade #We're inheriting from this. +## Mapping extruder definition IDs to the positions that they are in. +_EXTRUDER_TO_POSITION = { + "builder_premium_large_front": 1, + "builder_premium_large_rear": 0, + "builder_premium_medium_front": 1, + "builder_premium_medium_rear": 0, + "builder_premium_small_front": 1, + "builder_premium_small_rear": 0, + "cartesio_extruder_0": 0, + "cartesio_extruder_1": 1, + "cartesio_extruder_2": 2, + "cartesio_extruder_3": 3, + "custom_extruder_1": 0, #Warning, non-programmers are attempting to count here. + "custom_extruder_2": 1, + "custom_extruder_3": 2, + "custom_extruder_4": 3, + "custom_extruder_5": 4, + "custom_extruder_6": 5, + "custom_extruder_7": 6, + "custom_extruder_8": 7, + "hBp_extruder_left": 0, + "hBp_extruder_right": 1, + "makeit_dual_1st": 0, + "makeit_dual_2nd": 1, + "makeit_l_dual_1st": 0, + "makeit_l_dual_2nd": 1, + "ord_extruder_0": 0, + "ord_extruder_1": 1, + "ord_extruder_2": 2, + "ord_extruder_3": 3, + "ord_extruder_4": 4, + "punchtec_connect_xl_extruder_left": 0, + "punchtec_connect_xl_extruder_right": 1, + "raise3D_N2_dual_extruder_0": 0, + "raise3D_N2_dual_extruder_1": 1, + "raise3D_N2_plus_dual_extruder_0": 0, + "raise3D_N2_plus_dual_extruder_1": 1, + "ultimaker3_extended_extruder_left": 0, + "ultimaker3_extended_extruder_right": 1, + "ultimaker3_extruder_left": 0, + "ultimaker3_extruder_right": 1, + "ultimaker_original_dual_1st": 0, + "ultimaker_original_dual_2nd": 1, + "vertex_k8400_dual_1st": 0, + "vertex_k8400_dual_2nd": 1 +} + ## Upgrades configurations from the state they were in at version 3.2 to the # state they should be in at version 3.3. class VersionUpgrade32to33(VersionUpgrade): @@ -27,6 +74,24 @@ class VersionUpgrade32to33(VersionUpgrade): setting_version = int(parser.get("metadata", "setting_version", fallback = 0)) return format_version * 1000000 + setting_version - ## Upgrades a quality container to the new format. - def upgradeQuality(self, serialized, filename): - raise NotImplementedError("This has not yet been implemented.") \ No newline at end of file + ## Upgrades a quality changes container to the new format. + def upgradeQualityChanges(self, serialized, filename): + parser = configparser.ConfigParser(interpolation = None) + parser.read_string(serialized) + + #Extruder quality changes profiles have the extruder position instead of the ID of the extruder definition. + if "metadata" in parser and "extruder" in parser["metadata"]: #Only do this for extruder profiles. + extruder_id = parser["metadata"]["extruder"] + if extruder_id in _EXTRUDER_TO_POSITION: + extruder_position = _EXTRUDER_TO_POSITION[extruder_id] + else: + extruder_position = 0 #The user was using custom extruder definitions. He's on his own then. + + parser["metadata"]["extruder"] = str(extruder_position) + + #Update version number. + parser["general"]["version"] = "3" + + result = io.StringIO() + parser.write(result) + return [filename], [result.getvalue()] \ No newline at end of file diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py b/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py index dbcad86ac4..7465d79eb0 100644 --- a/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py +++ b/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py @@ -8,11 +8,11 @@ upgrade = VersionUpgrade32to33.VersionUpgrade32to33() def getMetaData(): return { "version_upgrade": { - # From To Upgrade function - ("quality", 2000004): ("quality", 3000004, upgrade.upgradeQuality), + # From To Upgrade function + ("quality_changes", 2000004): ("quality", 3000004, upgrade.upgradeQualityChanges), }, "sources": { - "quality": { + "quality_changes": { "get_version": upgrade.getCfgVersion, "location": {"./quality"} } From c9905449ebbb306e84217d6066e65e4c90bb2c81 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 9 Mar 2018 14:54:01 +0100 Subject: [PATCH 205/446] Clean up MachineSettingsAction imports CURA-5060 --- plugins/MachineSettingsAction/MachineSettingsAction.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/plugins/MachineSettingsAction/MachineSettingsAction.py b/plugins/MachineSettingsAction/MachineSettingsAction.py index a97f3b463f..26280a1f84 100755 --- a/plugins/MachineSettingsAction/MachineSettingsAction.py +++ b/plugins/MachineSettingsAction/MachineSettingsAction.py @@ -2,20 +2,16 @@ # Cura is released under the terms of the LGPLv3 or higher. from PyQt5.QtCore import pyqtProperty, pyqtSignal + +import UM.i18n from UM.FlameProfiler import pyqtSlot - -from cura.MachineAction import MachineAction - from UM.Application import Application from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.DefinitionContainer import DefinitionContainer -from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator -from UM.Logger import Logger -from cura.Settings.ExtruderManager import ExtruderManager +from cura.MachineAction import MachineAction from cura.Settings.CuraStackBuilder import CuraStackBuilder -import UM.i18n catalog = UM.i18n.i18nCatalog("cura") From 206d20c440af28afe62e188b372c2ae45fa5c541 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 9 Mar 2018 15:04:53 +0100 Subject: [PATCH 206/446] Fix empty definition_changes check in MachineSettingsAction CURA-5060 Should check for both "empty" and "empty_definition_changes". --- .../MachineSettingsAction.py | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/plugins/MachineSettingsAction/MachineSettingsAction.py b/plugins/MachineSettingsAction/MachineSettingsAction.py index 26280a1f84..ded59bf934 100755 --- a/plugins/MachineSettingsAction/MachineSettingsAction.py +++ b/plugins/MachineSettingsAction/MachineSettingsAction.py @@ -34,10 +34,16 @@ class MachineSettingsAction(MachineAction): self._container_registry.containerRemoved.connect(self._onContainerRemoved) self._application.globalContainerStackChanged.connect(self._onGlobalContainerChanged) - self._empty_container = self._container_registry.getEmptyInstanceContainer() - self._backend = self._application.getBackend() + self._empty_definition_container_id_list = [] + + def _isEmptyDefinitionChanges(self, container_id: str): + if not self._empty_definition_container_id_list: + self._empty_definition_container_id_list = [self._application.empty_container.getId(), + self._application.empty_definition_changes_container.getId()] + return container_id in self._empty_definition_container_id_list + def _onContainerAdded(self, container): # Add this action as a supported action to all machine definitions if isinstance(container, DefinitionContainer) and container.getMetaDataEntry("type") == "machine": @@ -46,19 +52,19 @@ class MachineSettingsAction(MachineAction): def _onContainerRemoved(self, container): # Remove definition_changes containers when a stack is removed if container.getMetaDataEntry("type") in ["machine", "extruder_train"]: - definition_changes_container = container.definitionChanges - if definition_changes_container == self._empty_container: + definition_changes_id = container.definitionChanges.getId() + if self._isEmptyDefinitionChanges(definition_changes_id): return - self._container_registry.removeContainer(definition_changes_container.getId()) + self._container_registry.removeContainer(definition_changes_id) def _reset(self): if not self._global_container_stack: return # Make sure there is a definition_changes container to store the machine settings - definition_changes_container = self._global_container_stack.definitionChanges - if definition_changes_container == self._empty_container: + definition_changes_id = self._global_container_stack.definitionChanges.getId() + if self._isEmptyDefinitionChanges(definition_changes_id): CuraStackBuilder.createDefinitionChangesContainer(self._global_container_stack, self._global_container_stack.getName() + "_settings") From 16a5b652f44469840408ea0655170b8d9306152b Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Fri, 9 Mar 2018 15:08:51 +0100 Subject: [PATCH 207/446] CURA-4870 Make the machine selection toolbutton react to changes in the output devices --- resources/qml/MachineSelection.qml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/resources/qml/MachineSelection.qml b/resources/qml/MachineSelection.qml index cce2bbea7b..96b40f7191 100644 --- a/resources/qml/MachineSelection.qml +++ b/resources/qml/MachineSelection.qml @@ -11,9 +11,10 @@ import Cura 1.0 as Cura import "Menus" ToolButton { - property var isNetworkPrinter: Cura.MachineManager.activeMachineNetworkKey ? true : false + id: base + property var isNetworkPrinter: Cura.MachineManager.activeMachineNetworkKey != "" property var printerStatus: Cura.MachineManager.printerOutputDevices.length != 0 ? "connected" : "unknown" - text: Cura.MachineManager.activeMachineName + text: isNetworkPrinter ? Cura.MachineManager.activeMachineNetworkGroupName : Cura.MachineManager.activeMachineName tooltip: Cura.MachineManager.activeMachineName @@ -73,4 +74,14 @@ ToolButton { } menu: PrinterMenu { } + + // Make the toolbutton react when the outputdevice changes + Connections + { + target: Cura.MachineManager + onOutputDevicesChanged: + { + base.isNetworkPrinter = Cura.MachineManager.activeMachineNetworkKey != "" + } + } } From 2962e0e282705ba3440f5aea6fc2e11b779d39e2 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 9 Mar 2018 15:20:20 +0100 Subject: [PATCH 208/446] Upgrade to quality_changes rather than quality Oops. Contributes to issue CURA-5054. --- plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py b/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py index 7465d79eb0..146ebbe95b 100644 --- a/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py +++ b/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py @@ -9,7 +9,7 @@ def getMetaData(): return { "version_upgrade": { # From To Upgrade function - ("quality_changes", 2000004): ("quality", 3000004, upgrade.upgradeQualityChanges), + ("quality_changes", 2000004): ("quality_changes", 3000004, upgrade.upgradeQualityChanges), }, "sources": { "quality_changes": { From 5caa92cf7a38493544797ebe3faee9bf2c290e7b Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 9 Mar 2018 15:21:45 +0100 Subject: [PATCH 209/446] Update current version for quality changes We now need to upgrade up to version 3000004. Contributes to issue CURA-5054. --- cura/CuraApplication.py | 12 +++++++----- cura/Machines/QualityChangesGroup.py | 2 ++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 438e8ffed7..9f37f09681 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1,5 +1,6 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. + #Type hinting. from typing import Dict @@ -55,6 +56,7 @@ from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.SettingFunction import SettingFunction from cura.Settings.MachineNameValidator import MachineNameValidator +from cura.Machines.QualityChangesGroup import QualityChangesGroup from cura.Machines.Models.BuildPlateModel import BuildPlateModel from cura.Machines.Models.NozzleModel import NozzleModel from cura.Machines.Models.QualityProfilesDropDownMenuModel import QualityProfilesDropDownMenuModel @@ -207,11 +209,11 @@ class CuraApplication(QtApplication): UM.VersionUpgradeManager.VersionUpgradeManager.getInstance().setCurrentVersions( { - ("quality_changes", InstanceContainer.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.QualityInstanceContainer, "application/x-uranium-instancecontainer"), - ("machine_stack", ContainerStack.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.MachineStack, "application/x-cura-globalstack"), - ("extruder_train", ContainerStack.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.ExtruderStack, "application/x-cura-extruderstack"), - ("preferences", Preferences.Version * 1000000 + self.SettingVersion): (Resources.Preferences, "application/x-uranium-preferences"), - ("user", InstanceContainer.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.UserInstanceContainer, "application/x-uranium-instancecontainer"), + ("quality_changes", QualityChangesGroup.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.QualityInstanceContainer, "application/x-uranium-instancecontainer"), + ("machine_stack", ContainerStack.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.MachineStack, "application/x-cura-globalstack"), + ("extruder_train", ContainerStack.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.ExtruderStack, "application/x-cura-extruderstack"), + ("preferences", Preferences.Version * 1000000 + self.SettingVersion): (Resources.Preferences, "application/x-uranium-preferences"), + ("user", InstanceContainer.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.UserInstanceContainer, "application/x-uranium-instancecontainer"), ("definition_changes", InstanceContainer.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.DefinitionChangesContainer, "application/x-uranium-instancecontainer"), } ) diff --git a/cura/Machines/QualityChangesGroup.py b/cura/Machines/QualityChangesGroup.py index f8de3d2011..c24a547e8c 100644 --- a/cura/Machines/QualityChangesGroup.py +++ b/cura/Machines/QualityChangesGroup.py @@ -7,6 +7,8 @@ from .QualityGroup import QualityGroup class QualityChangesGroup(QualityGroup): + ## The file format version of quality changes. + Version = 3 def __init__(self, name: str, quality_type: str, parent = None): super().__init__(name, quality_type, parent) From e18b1cde55b23615faaff6cc0c4546fe59da2eab Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 9 Mar 2018 15:37:30 +0100 Subject: [PATCH 210/446] Store extruder position under 'position' instead of 'extruder' Otherwise it thinks it is still an extruder ID. Contributes to issue CURA-5054. --- .../VersionUpgrade32to33/VersionUpgrade32to33.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py b/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py index 2b8818177f..df22d6bf32 100644 --- a/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py +++ b/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py @@ -87,7 +87,8 @@ class VersionUpgrade32to33(VersionUpgrade): else: extruder_position = 0 #The user was using custom extruder definitions. He's on his own then. - parser["metadata"]["extruder"] = str(extruder_position) + parser["metadata"]["position"] = str(extruder_position) + del parser["metadata"]["extruder"] #Update version number. parser["general"]["version"] = "3" From 5d2e98cdd472b2241ab3a348afd0b0ba228ae46d Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 9 Mar 2018 15:55:27 +0100 Subject: [PATCH 211/446] Translate to American English The spelling in AmE is with a Z. --- cura/CrashHandler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CrashHandler.py b/cura/CrashHandler.py index 7a94c69301..c082578218 100644 --- a/cura/CrashHandler.py +++ b/cura/CrashHandler.py @@ -259,7 +259,7 @@ class CrashHandler: opengl_instance = OpenGL.getInstance() if not opengl_instance: self.data["opengl"] = {"version": "n/a", "vendor": "n/a", "type": "n/a"} - return catalog.i18nc("@label", "not yet initialised
") + return catalog.i18nc("@label", "Not yet initialized
") info = "
    " info += catalog.i18nc("@label OpenGL version", "
  • OpenGL Version: {version}
  • ").format(version = opengl_instance.getOpenGLVersion()) From b797ac1a151854ea1a4cf9d504ace5450901ced1 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 9 Mar 2018 16:07:06 +0100 Subject: [PATCH 212/446] Read only position from metadata We now determine whether this is a global or an extruder profile based on whether the position metadata field is present, instead of whether the extruder metadata field is present. Contributes to issue CURA-5054. --- cura/Machines/QualityChangesGroup.py | 37 +++++----------------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/cura/Machines/QualityChangesGroup.py b/cura/Machines/QualityChangesGroup.py index c24a547e8c..e0591b082f 100644 --- a/cura/Machines/QualityChangesGroup.py +++ b/cura/Machines/QualityChangesGroup.py @@ -15,41 +15,16 @@ class QualityChangesGroup(QualityGroup): self._container_registry = Application.getInstance().getContainerRegistry() def addNode(self, node: "QualityNode"): - # TODO: in 3.2 and earlier, a quality_changes container may have a field called "extruder" which contains the - # extruder definition ID it belongs to. But, in fact, we only need to know the following things: - # 1. which machine a custom profile is suitable for, - # 2. if this profile is for the GlobalStack, - # 3. if this profile is for an ExtruderStack and which one (the position). - # - # So, it is preferred to have a field like this: - # extruder_position = 1 - # instead of this: - # extruder = custom_extruder_1 - # - # An upgrade needs to be done if we want to do it this way. Before that, we use the extruder's definition - # to figure out its position. - # - extruder_definition_id = node.metadata.get("extruder") - if extruder_definition_id: - metadata_list = self._container_registry.findDefinitionContainersMetadata(id = extruder_definition_id) - if not metadata_list: - raise RuntimeError("%s cannot get metadata for extruder definition [%s]" % - (self, extruder_definition_id)) - extruder_definition_metadata = metadata_list[0] - extruder_position = str(extruder_definition_metadata["position"]) - + extruder_position = node.metadata.get("position") + if not extruder_position: #Then we're a global quality changes profile. + if self.node_for_global is not None: + raise RuntimeError("{group} tries to overwrite the existing node_for_global {original_global} with {new_global}".format(group = self, original_global = self.node_for_global, new_global = node)) + self.node_for_global = node + else: #This is an extruder's quality changes profile. if extruder_position in self.nodes_for_extruders: raise RuntimeError("%s tries to overwrite the existing nodes_for_extruders position [%s] %s with %s" % (self, extruder_position, self.node_for_global, node)) - self.nodes_for_extruders[extruder_position] = node - else: - # This is a quality_changes for the GlobalStack - if self.node_for_global is not None: - raise RuntimeError("%s tries to overwrite the existing node_for_global %s with %s" % - (self, self.node_for_global, node)) - self.node_for_global = node - def __str__(self) -> str: return "%s[<%s>, available = %s]" % (self.__class__.__name__, self.name, self.is_available) From 3a832d66a9bf71f905d079ea4e50526dd6976a2c Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 9 Mar 2018 16:07:54 +0100 Subject: [PATCH 213/446] Safer check for extruder vs. global Because it might be an empty string. Contributes to issue CURA-5054. --- cura/Machines/QualityChangesGroup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Machines/QualityChangesGroup.py b/cura/Machines/QualityChangesGroup.py index e0591b082f..dac9de1b38 100644 --- a/cura/Machines/QualityChangesGroup.py +++ b/cura/Machines/QualityChangesGroup.py @@ -16,7 +16,7 @@ class QualityChangesGroup(QualityGroup): def addNode(self, node: "QualityNode"): extruder_position = node.metadata.get("position") - if not extruder_position: #Then we're a global quality changes profile. + if extruder_position is None: #Then we're a global quality changes profile. if self.node_for_global is not None: raise RuntimeError("{group} tries to overwrite the existing node_for_global {original_global} with {new_global}".format(group = self, original_global = self.node_for_global, new_global = node)) self.node_for_global = node From d8a066c1e733a0f3a2f995e484fa0c63b00b92ae Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 9 Mar 2018 16:14:24 +0100 Subject: [PATCH 214/446] Increment instance container version number instead of just quality_changes Otherwise when we load that quality_changes file we'll deny it because the instance container version number is wrong. Contributes to issue CURA-5054. --- cura/CuraApplication.py | 3 +-- cura/Machines/QualityChangesGroup.py | 3 --- resources/quality/abax_pri3/apri3_pla_fast.inst.cfg | 2 +- resources/quality/abax_pri3/apri3_pla_high.inst.cfg | 2 +- resources/quality/abax_pri3/apri3_pla_normal.inst.cfg | 2 +- resources/quality/abax_pri5/apri5_pla_fast.inst.cfg | 2 +- resources/quality/abax_pri5/apri5_pla_high.inst.cfg | 2 +- resources/quality/abax_pri5/apri5_pla_normal.inst.cfg | 2 +- resources/quality/abax_titan/atitan_pla_fast.inst.cfg | 2 +- resources/quality/abax_titan/atitan_pla_high.inst.cfg | 2 +- resources/quality/abax_titan/atitan_pla_normal.inst.cfg | 2 +- .../quality/anycubic_i3_mega/anycubic_i3_mega_draft.inst.cfg | 2 +- .../quality/anycubic_i3_mega/anycubic_i3_mega_high.inst.cfg | 2 +- .../quality/anycubic_i3_mega/anycubic_i3_mega_normal.inst.cfg | 2 +- .../quality/builder_premium/bp_BVOH_Coarse_Quality.inst.cfg | 2 +- .../quality/builder_premium/bp_BVOH_High_Quality.inst.cfg | 2 +- .../quality/builder_premium/bp_BVOH_Normal_Quality.inst.cfg | 2 +- .../builder_premium/bp_Innoflex60_Coarse_Quality.inst.cfg | 2 +- .../builder_premium/bp_Innoflex60_High_Quality.inst.cfg | 2 +- .../builder_premium/bp_Innoflex60_Normal_Quality.inst.cfg | 2 +- .../quality/builder_premium/bp_PET_Coarse_Quality.inst.cfg | 2 +- resources/quality/builder_premium/bp_PET_High_Quality.inst.cfg | 2 +- .../quality/builder_premium/bp_PET_Normal_Quality.inst.cfg | 2 +- .../quality/builder_premium/bp_PLA_Coarse_Quality.inst.cfg | 2 +- resources/quality/builder_premium/bp_PLA_High_Quality.inst.cfg | 2 +- .../quality/builder_premium/bp_PLA_Normal_Quality.inst.cfg | 2 +- .../quality/builder_premium/bp_PVA_Coarse_Quality.inst.cfg | 2 +- resources/quality/builder_premium/bp_PVA_High_Quality.inst.cfg | 2 +- .../quality/builder_premium/bp_PVA_Normal_Quality.inst.cfg | 2 +- .../quality/builder_premium/bp_global_Coarse_Quality.inst.cfg | 2 +- .../quality/builder_premium/bp_global_High_Quality.inst.cfg | 2 +- .../quality/builder_premium/bp_global_Normal_Quality.inst.cfg | 2 +- resources/quality/cartesio/abs/cartesio_0.25_abs_high.inst.cfg | 2 +- .../quality/cartesio/abs/cartesio_0.25_abs_normal.inst.cfg | 2 +- resources/quality/cartesio/abs/cartesio_0.4_abs_high.inst.cfg | 2 +- .../quality/cartesio/abs/cartesio_0.4_abs_normal.inst.cfg | 2 +- .../quality/cartesio/abs/cartesio_0.8_abs_coarse.inst.cfg | 2 +- .../cartesio/abs/cartesio_0.8_abs_extra_coarse.inst.cfg | 2 +- resources/quality/cartesio/abs/cartesio_0.8_abs_high.inst.cfg | 2 +- .../quality/cartesio/abs/cartesio_0.8_abs_normal.inst.cfg | 2 +- .../cartesio/arnitel/cartesio_0.4_arnitel2045_high.inst.cfg | 2 +- .../cartesio/arnitel/cartesio_0.4_arnitel2045_normal.inst.cfg | 2 +- .../quality/cartesio/cartesio_global_Coarse_Quality.inst.cfg | 2 +- .../cartesio/cartesio_global_Extra_Coarse_Quality.inst.cfg | 2 +- .../quality/cartesio/cartesio_global_High_Quality.inst.cfg | 2 +- .../quality/cartesio/cartesio_global_Normal_Quality.inst.cfg | 2 +- .../quality/cartesio/hips/cartesio_0.25_hips_high.inst.cfg | 2 +- .../quality/cartesio/hips/cartesio_0.25_hips_normal.inst.cfg | 2 +- .../quality/cartesio/hips/cartesio_0.4_hips_high.inst.cfg | 2 +- .../quality/cartesio/hips/cartesio_0.4_hips_normal.inst.cfg | 2 +- .../quality/cartesio/hips/cartesio_0.8_hips_coarse.inst.cfg | 2 +- .../cartesio/hips/cartesio_0.8_hips_extra_coarse.inst.cfg | 2 +- .../quality/cartesio/hips/cartesio_0.8_hips_high.inst.cfg | 2 +- .../quality/cartesio/hips/cartesio_0.8_hips_normal.inst.cfg | 2 +- .../quality/cartesio/nylon/cartesio_0.25_nylon_high.inst.cfg | 2 +- .../quality/cartesio/nylon/cartesio_0.25_nylon_normal.inst.cfg | 2 +- .../quality/cartesio/nylon/cartesio_0.4_nylon_high.inst.cfg | 2 +- .../quality/cartesio/nylon/cartesio_0.4_nylon_normal.inst.cfg | 2 +- .../quality/cartesio/nylon/cartesio_0.8_nylon_coarse.inst.cfg | 2 +- .../cartesio/nylon/cartesio_0.8_nylon_extra_coarse.inst.cfg | 2 +- .../quality/cartesio/nylon/cartesio_0.8_nylon_high.inst.cfg | 2 +- .../quality/cartesio/nylon/cartesio_0.8_nylon_normal.inst.cfg | 2 +- resources/quality/cartesio/pc/cartesio_0.25_pc_high.inst.cfg | 2 +- resources/quality/cartesio/pc/cartesio_0.25_pc_normal.inst.cfg | 2 +- resources/quality/cartesio/pc/cartesio_0.4_pc_high.inst.cfg | 2 +- resources/quality/cartesio/pc/cartesio_0.4_pc_normal.inst.cfg | 2 +- resources/quality/cartesio/pc/cartesio_0.8_pc_coarse.inst.cfg | 2 +- .../quality/cartesio/pc/cartesio_0.8_pc_extra_coarse.inst.cfg | 2 +- resources/quality/cartesio/pc/cartesio_0.8_pc_high.inst.cfg | 2 +- resources/quality/cartesio/pc/cartesio_0.8_pc_normal.inst.cfg | 2 +- .../quality/cartesio/petg/cartesio_0.25_petg_high.inst.cfg | 2 +- .../quality/cartesio/petg/cartesio_0.25_petg_normal.inst.cfg | 2 +- .../quality/cartesio/petg/cartesio_0.4_petg_high.inst.cfg | 2 +- .../quality/cartesio/petg/cartesio_0.4_petg_normal.inst.cfg | 2 +- .../quality/cartesio/petg/cartesio_0.8_petg_coarse.inst.cfg | 2 +- .../cartesio/petg/cartesio_0.8_petg_extra_coarse.inst.cfg | 2 +- .../quality/cartesio/petg/cartesio_0.8_petg_high.inst.cfg | 2 +- .../quality/cartesio/petg/cartesio_0.8_petg_normal.inst.cfg | 2 +- resources/quality/cartesio/pla/cartesio_0.25_pla_high.inst.cfg | 2 +- .../quality/cartesio/pla/cartesio_0.25_pla_normal.inst.cfg | 2 +- resources/quality/cartesio/pla/cartesio_0.4_pla_high.inst.cfg | 2 +- .../quality/cartesio/pla/cartesio_0.4_pla_normal.inst.cfg | 2 +- .../quality/cartesio/pla/cartesio_0.8_pla_coarse.inst.cfg | 2 +- .../cartesio/pla/cartesio_0.8_pla_extra_coarse.inst.cfg | 2 +- resources/quality/cartesio/pla/cartesio_0.8_pla_high.inst.cfg | 2 +- .../quality/cartesio/pla/cartesio_0.8_pla_normal.inst.cfg | 2 +- resources/quality/cartesio/pva/cartesio_0.25_pva_high.inst.cfg | 2 +- .../quality/cartesio/pva/cartesio_0.25_pva_normal.inst.cfg | 2 +- resources/quality/cartesio/pva/cartesio_0.4_pva_high.inst.cfg | 2 +- .../quality/cartesio/pva/cartesio_0.4_pva_normal.inst.cfg | 2 +- .../quality/cartesio/pva/cartesio_0.8_pva_coarse.inst.cfg | 2 +- .../cartesio/pva/cartesio_0.8_pva_extra_coarse.inst.cfg | 2 +- resources/quality/cartesio/pva/cartesio_0.8_pva_high.inst.cfg | 2 +- .../quality/cartesio/pva/cartesio_0.8_pva_normal.inst.cfg | 2 +- resources/quality/coarse.inst.cfg | 2 +- resources/quality/deltacomb/deltacomb_abs_fast.inst.cfg | 2 +- resources/quality/deltacomb/deltacomb_abs_high.inst.cfg | 2 +- resources/quality/deltacomb/deltacomb_abs_normal.inst.cfg | 2 +- resources/quality/deltacomb/deltacomb_nylon_fast.inst.cfg | 2 +- resources/quality/deltacomb/deltacomb_nylon_high.inst.cfg | 2 +- resources/quality/deltacomb/deltacomb_nylon_normal.inst.cfg | 2 +- resources/quality/deltacomb/deltacomb_pla_fast.inst.cfg | 2 +- resources/quality/deltacomb/deltacomb_pla_high.inst.cfg | 2 +- resources/quality/deltacomb/deltacomb_pla_normal.inst.cfg | 2 +- resources/quality/draft.inst.cfg | 2 +- resources/quality/extra_coarse.inst.cfg | 2 +- resources/quality/fabtotum/fabtotum_abs_fast.inst.cfg | 2 +- resources/quality/fabtotum/fabtotum_abs_high.inst.cfg | 2 +- resources/quality/fabtotum/fabtotum_abs_normal.inst.cfg | 2 +- resources/quality/fabtotum/fabtotum_nylon_fast.inst.cfg | 2 +- resources/quality/fabtotum/fabtotum_nylon_high.inst.cfg | 2 +- resources/quality/fabtotum/fabtotum_nylon_normal.inst.cfg | 2 +- resources/quality/fabtotum/fabtotum_pla_fast.inst.cfg | 2 +- resources/quality/fabtotum/fabtotum_pla_high.inst.cfg | 2 +- resources/quality/fabtotum/fabtotum_pla_normal.inst.cfg | 2 +- resources/quality/fabtotum/fabtotum_tpu_fast.inst.cfg | 2 +- resources/quality/fabtotum/fabtotum_tpu_high.inst.cfg | 2 +- resources/quality/fabtotum/fabtotum_tpu_normal.inst.cfg | 2 +- resources/quality/fast.inst.cfg | 2 +- .../quality/gmax15plus/gmax15plus_pla_dual_normal.inst.cfg | 2 +- .../quality/gmax15plus/gmax15plus_pla_dual_thick.inst.cfg | 2 +- resources/quality/gmax15plus/gmax15plus_pla_dual_thin.inst.cfg | 2 +- .../quality/gmax15plus/gmax15plus_pla_dual_very_thick.inst.cfg | 2 +- resources/quality/gmax15plus/gmax15plus_pla_normal.inst.cfg | 2 +- resources/quality/gmax15plus/gmax15plus_pla_thick.inst.cfg | 2 +- resources/quality/gmax15plus/gmax15plus_pla_thin.inst.cfg | 2 +- .../quality/gmax15plus/gmax15plus_pla_very_thick.inst.cfg | 2 +- resources/quality/high.inst.cfg | 2 +- .../quality/imade3d_jellybox/generic_petg_0.4_coarse.inst.cfg | 2 +- .../imade3d_jellybox/generic_petg_0.4_coarse_2-fans.inst.cfg | 2 +- .../quality/imade3d_jellybox/generic_petg_0.4_medium.inst.cfg | 2 +- .../imade3d_jellybox/generic_petg_0.4_medium_2-fans.inst.cfg | 2 +- .../quality/imade3d_jellybox/generic_pla_0.4_coarse.inst.cfg | 2 +- .../imade3d_jellybox/generic_pla_0.4_coarse_2-fans.inst.cfg | 2 +- .../quality/imade3d_jellybox/generic_pla_0.4_fine.inst.cfg | 2 +- .../imade3d_jellybox/generic_pla_0.4_fine_2-fans.inst.cfg | 2 +- .../quality/imade3d_jellybox/generic_pla_0.4_medium.inst.cfg | 2 +- .../imade3d_jellybox/generic_pla_0.4_medium_2-fans.inst.cfg | 2 +- .../imade3d_jellybox/generic_pla_0.4_ultrafine.inst.cfg | 2 +- .../imade3d_jellybox/generic_pla_0.4_ultrafine_2-fans.inst.cfg | 2 +- .../quality/imade3d_jellybox/imade3d_jellybox_coarse.inst.cfg | 2 +- .../quality/imade3d_jellybox/imade3d_jellybox_fine.inst.cfg | 2 +- .../quality/imade3d_jellybox/imade3d_jellybox_normal.inst.cfg | 2 +- .../imade3d_jellybox/imade3d_jellybox_ultrafine.inst.cfg | 2 +- resources/quality/kemiq_q2/kemiq_q2_beta_abs_draft.inst.cfg | 2 +- .../quality/kemiq_q2/kemiq_q2_beta_abs_extra_fine.inst.cfg | 2 +- resources/quality/kemiq_q2/kemiq_q2_beta_abs_fine.inst.cfg | 2 +- resources/quality/kemiq_q2/kemiq_q2_beta_abs_low.inst.cfg | 2 +- resources/quality/kemiq_q2/kemiq_q2_beta_abs_normal.inst.cfg | 2 +- resources/quality/kemiq_q2/kemiq_q2_beta_pla_draft.inst.cfg | 2 +- .../quality/kemiq_q2/kemiq_q2_beta_pla_extra_fine.inst.cfg | 2 +- resources/quality/kemiq_q2/kemiq_q2_beta_pla_fine.inst.cfg | 2 +- resources/quality/kemiq_q2/kemiq_q2_beta_pla_low.inst.cfg | 2 +- resources/quality/kemiq_q2/kemiq_q2_beta_pla_normal.inst.cfg | 2 +- resources/quality/kemiq_q2/kemiq_q2_gama_pla_draft.inst.cfg | 2 +- .../quality/kemiq_q2/kemiq_q2_gama_pla_extra_fine.inst.cfg | 2 +- resources/quality/kemiq_q2/kemiq_q2_gama_pla_fine.inst.cfg | 2 +- resources/quality/kemiq_q2/kemiq_q2_gama_pla_low.inst.cfg | 2 +- resources/quality/kemiq_q2/kemiq_q2_gama_pla_normal.inst.cfg | 2 +- .../quality/malyan_m200/abs/malyan_m200_abs_draft.inst.cfg | 2 +- .../quality/malyan_m200/abs/malyan_m200_abs_fast.inst.cfg | 2 +- .../quality/malyan_m200/abs/malyan_m200_abs_high.inst.cfg | 2 +- .../quality/malyan_m200/abs/malyan_m200_abs_normal.inst.cfg | 2 +- .../malyan_m200/abs/malyan_m200_abs_superdraft.inst.cfg | 2 +- .../malyan_m200/abs/malyan_m200_abs_thickerdraft.inst.cfg | 2 +- .../quality/malyan_m200/abs/malyan_m200_abs_ultra.inst.cfg | 2 +- .../quality/malyan_m200/abs/malyan_m200_abs_verydraft.inst.cfg | 2 +- resources/quality/malyan_m200/malyan_m200_0.04375.inst.cfg | 2 +- resources/quality/malyan_m200/malyan_m200_0.0875.inst.cfg | 2 +- resources/quality/malyan_m200/malyan_m200_0.13125.inst.cfg | 2 +- resources/quality/malyan_m200/malyan_m200_0.175.inst.cfg | 2 +- resources/quality/malyan_m200/malyan_m200_0.21875.inst.cfg | 2 +- resources/quality/malyan_m200/malyan_m200_0.2625.inst.cfg | 2 +- resources/quality/malyan_m200/malyan_m200_0.30625.inst.cfg | 2 +- resources/quality/malyan_m200/malyan_m200_0.35.inst.cfg | 2 +- .../malyan_m200/malyan_m200_global_Draft_Quality.inst.cfg | 2 +- .../malyan_m200/malyan_m200_global_Fast_Quality.inst.cfg | 2 +- .../malyan_m200/malyan_m200_global_High_Quality.inst.cfg | 2 +- .../malyan_m200/malyan_m200_global_Normal_Quality.inst.cfg | 2 +- .../malyan_m200/malyan_m200_global_SuperDraft_Quality.inst.cfg | 2 +- .../malyan_m200_global_ThickerDraft_Quality.inst.cfg | 2 +- .../malyan_m200/malyan_m200_global_Ultra_Quality.inst.cfg | 2 +- .../malyan_m200/malyan_m200_global_VeryDraft_Quality.inst.cfg | 2 +- .../quality/malyan_m200/petg/malyan_m200_petg_draft.inst.cfg | 2 +- .../quality/malyan_m200/petg/malyan_m200_petg_fast.inst.cfg | 2 +- .../quality/malyan_m200/petg/malyan_m200_petg_high.inst.cfg | 2 +- .../quality/malyan_m200/petg/malyan_m200_petg_normal.inst.cfg | 2 +- .../malyan_m200/petg/malyan_m200_petg_superdraft.inst.cfg | 2 +- .../malyan_m200/petg/malyan_m200_petg_thickerdraft.inst.cfg | 2 +- .../quality/malyan_m200/petg/malyan_m200_petg_ultra.inst.cfg | 2 +- .../malyan_m200/petg/malyan_m200_petg_verydraft.inst.cfg | 2 +- .../quality/malyan_m200/pla/malyan_m200_pla_draft.inst.cfg | 2 +- .../quality/malyan_m200/pla/malyan_m200_pla_fast.inst.cfg | 2 +- .../quality/malyan_m200/pla/malyan_m200_pla_high.inst.cfg | 2 +- .../quality/malyan_m200/pla/malyan_m200_pla_normal.inst.cfg | 2 +- .../malyan_m200/pla/malyan_m200_pla_superdraft.inst.cfg | 2 +- .../malyan_m200/pla/malyan_m200_pla_thickerdraft.inst.cfg | 2 +- .../quality/malyan_m200/pla/malyan_m200_pla_ultra.inst.cfg | 2 +- .../quality/malyan_m200/pla/malyan_m200_pla_verydraft.inst.cfg | 2 +- .../abs/monoprice_select_mini_v2_abs_draft.inst.cfg | 2 +- .../abs/monoprice_select_mini_v2_abs_fast.inst.cfg | 2 +- .../abs/monoprice_select_mini_v2_abs_high.inst.cfg | 2 +- .../abs/monoprice_select_mini_v2_abs_normal.inst.cfg | 2 +- .../abs/monoprice_select_mini_v2_abs_superdraft.inst.cfg | 2 +- .../abs/monoprice_select_mini_v2_abs_thickerdraft.inst.cfg | 2 +- .../abs/monoprice_select_mini_v2_abs_ultra.inst.cfg | 2 +- .../abs/monoprice_select_mini_v2_abs_verydraft.inst.cfg | 2 +- .../monoprice_select_mini_v2_global_Draft_Quality.inst.cfg | 2 +- .../monoprice_select_mini_v2_global_Fast_Quality.inst.cfg | 2 +- .../monoprice_select_mini_v2_global_High_Quality.inst.cfg | 2 +- .../monoprice_select_mini_v2_global_Normal_Quality.inst.cfg | 2 +- ...monoprice_select_mini_v2_global_SuperDraft_Quality.inst.cfg | 2 +- ...noprice_select_mini_v2_global_ThickerDraft_Quality.inst.cfg | 2 +- .../monoprice_select_mini_v2_global_Ultra_Quality.inst.cfg | 2 +- .../monoprice_select_mini_v2_global_VeryDraft_Quality.inst.cfg | 2 +- .../nylon/monoprice_select_mini_v2_nylon_draft.inst.cfg | 2 +- .../nylon/monoprice_select_mini_v2_nylon_fast.inst.cfg | 2 +- .../nylon/monoprice_select_mini_v2_nylon_high.inst.cfg | 2 +- .../nylon/monoprice_select_mini_v2_nylon_normal.inst.cfg | 2 +- .../nylon/monoprice_select_mini_v2_nylon_superdraft.inst.cfg | 2 +- .../nylon/monoprice_select_mini_v2_nylon_thickerdraft.inst.cfg | 2 +- .../nylon/monoprice_select_mini_v2_nylon_ultra.inst.cfg | 2 +- .../nylon/monoprice_select_mini_v2_nylon_verydraft.inst.cfg | 2 +- .../pc/monoprice_select_mini_v2_pc_draft.inst.cfg | 2 +- .../pc/monoprice_select_mini_v2_pc_fast.inst.cfg | 2 +- .../pc/monoprice_select_mini_v2_pc_high.inst.cfg | 2 +- .../pc/monoprice_select_mini_v2_pc_normal.inst.cfg | 2 +- .../pc/monoprice_select_mini_v2_pc_superdraft.inst.cfg | 2 +- .../pc/monoprice_select_mini_v2_pc_thickerdraft.inst.cfg | 2 +- .../pc/monoprice_select_mini_v2_pc_ultra.inst.cfg | 2 +- .../pc/monoprice_select_mini_v2_pc_verydraft.inst.cfg | 2 +- .../petg/monoprice_select_mini_v2_petg_draft.inst.cfg | 2 +- .../petg/monoprice_select_mini_v2_petg_fast.inst.cfg | 2 +- .../petg/monoprice_select_mini_v2_petg_high.inst.cfg | 2 +- .../petg/monoprice_select_mini_v2_petg_normal.inst.cfg | 2 +- .../petg/monoprice_select_mini_v2_petg_superdraft.inst.cfg | 2 +- .../petg/monoprice_select_mini_v2_petg_thickerdraft.inst.cfg | 2 +- .../petg/monoprice_select_mini_v2_petg_ultra.inst.cfg | 2 +- .../petg/monoprice_select_mini_v2_petg_verydraft.inst.cfg | 2 +- .../pla/monoprice_select_mini_v2_pla_draft.inst.cfg | 2 +- .../pla/monoprice_select_mini_v2_pla_fast.inst.cfg | 2 +- .../pla/monoprice_select_mini_v2_pla_high.inst.cfg | 2 +- .../pla/monoprice_select_mini_v2_pla_normal.inst.cfg | 2 +- .../pla/monoprice_select_mini_v2_pla_superdraft.inst.cfg | 2 +- .../pla/monoprice_select_mini_v2_pla_thickerdraft.inst.cfg | 2 +- .../pla/monoprice_select_mini_v2_pla_ultra.inst.cfg | 2 +- .../pla/monoprice_select_mini_v2_pla_verydraft.inst.cfg | 2 +- resources/quality/normal.inst.cfg | 2 +- resources/quality/peopoly_moai/peopoly_moai_high.inst.cfg | 2 +- resources/quality/peopoly_moai/peopoly_moai_max.inst.cfg | 2 +- resources/quality/peopoly_moai/peopoly_moai_normal.inst.cfg | 2 +- .../quality/tevo_blackwidow/tevo_blackwidow_draft.inst.cfg | 2 +- .../quality/tevo_blackwidow/tevo_blackwidow_high.inst.cfg | 2 +- .../quality/tevo_blackwidow/tevo_blackwidow_normal.inst.cfg | 2 +- resources/quality/ultimaker2/um2_draft.inst.cfg | 2 +- resources/quality/ultimaker2/um2_fast.inst.cfg | 2 +- resources/quality/ultimaker2/um2_high.inst.cfg | 2 +- resources/quality/ultimaker2/um2_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg | 2 +- resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg | 2 +- resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg | 2 +- .../quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg | 2 +- .../quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_cpep_0.4_draft.inst.cfg | 2 +- .../quality/ultimaker2_plus/um2p_cpep_0.4_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_cpep_0.6_draft.inst.cfg | 2 +- .../quality/ultimaker2_plus/um2p_cpep_0.6_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_cpep_0.8_draft.inst.cfg | 2 +- .../quality/ultimaker2_plus/um2p_cpep_0.8_normal.inst.cfg | 2 +- .../quality/ultimaker2_plus/um2p_nylon_0.25_high.inst.cfg | 2 +- .../quality/ultimaker2_plus/um2p_nylon_0.25_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_nylon_0.4_fast.inst.cfg | 2 +- .../quality/ultimaker2_plus/um2p_nylon_0.4_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_nylon_0.6_fast.inst.cfg | 2 +- .../quality/ultimaker2_plus/um2p_nylon_0.6_normal.inst.cfg | 2 +- .../quality/ultimaker2_plus/um2p_nylon_0.8_draft.inst.cfg | 2 +- .../quality/ultimaker2_plus/um2p_nylon_0.8_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_pc_0.25_high.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_pc_0.25_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_pc_0.4_fast.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_pc_0.4_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_pc_0.6_fast.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_pc_0.6_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_pc_0.8_draft.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_pc_0.8_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_pp_0.4_fast.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_pp_0.4_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_pp_0.6_draft.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_pp_0.6_fast.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_pp_0.8_draft.inst.cfg | 2 +- .../quality/ultimaker2_plus/um2p_pp_0.8_verydraft.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_tpu_0.25_high.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_tpu_0.4_normal.inst.cfg | 2 +- resources/quality/ultimaker2_plus/um2p_tpu_0.6_fast.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.25_ABS_Normal_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.25_CPE_Normal_Quality.inst.cfg | 2 +- .../ultimaker3/um3_aa0.25_Nylon_Normal_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.25_PC_Normal_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.25_PLA_Normal_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.25_PP_Normal_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_ABS_Draft_Print.inst.cfg | 2 +- resources/quality/ultimaker3/um3_aa0.4_ABS_Fast_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_ABS_High_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_ABS_Normal_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_BAM_Draft_Print.inst.cfg | 2 +- resources/quality/ultimaker3/um3_aa0.4_BAM_Fast_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_BAM_Normal_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_CPEP_Draft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_CPEP_Fast_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_CPEP_High_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_CPEP_Normal_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_CPE_Draft_Print.inst.cfg | 2 +- resources/quality/ultimaker3/um3_aa0.4_CPE_Fast_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_CPE_High_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_CPE_Normal_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_Nylon_Draft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_Nylon_Fast_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_Nylon_High_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_Nylon_Normal_Quality.inst.cfg | 2 +- resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg | 2 +- resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_PC_Normal_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_PLA_Draft_Print.inst.cfg | 2 +- resources/quality/ultimaker3/um3_aa0.4_PLA_Fast_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_PLA_High_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_PLA_Normal_Quality.inst.cfg | 2 +- resources/quality/ultimaker3/um3_aa0.4_PP_Draft_Print.inst.cfg | 2 +- resources/quality/ultimaker3/um3_aa0.4_PP_Fast_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_PP_Normal_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_TPU_Draft_Print.inst.cfg | 2 +- resources/quality/ultimaker3/um3_aa0.4_TPU_Fast_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.4_TPU_Normal_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.8_ABS_Draft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.8_ABS_Superdraft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.8_ABS_Verydraft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.8_CPEP_Fast_Print.inst.cfg | 2 +- .../ultimaker3/um3_aa0.8_CPEP_Superdraft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.8_CPEP_Verydraft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.8_CPE_Draft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.8_CPE_Superdraft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.8_CPE_Verydraft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.8_Nylon_Draft_Print.inst.cfg | 2 +- .../ultimaker3/um3_aa0.8_Nylon_Superdraft_Print.inst.cfg | 2 +- .../ultimaker3/um3_aa0.8_Nylon_Verydraft_Print.inst.cfg | 2 +- resources/quality/ultimaker3/um3_aa0.8_PC_Fast_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.8_PC_Superdraft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.8_PC_Verydraft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.8_PLA_Draft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.8_PLA_Superdraft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.8_PLA_Verydraft_Print.inst.cfg | 2 +- resources/quality/ultimaker3/um3_aa0.8_PP_Draft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.8_PP_Superdraft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.8_PP_Verydraft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.8_TPU_Draft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.8_TPU_Superdraft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_aa0.8_TPU_Verydraft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_bb0.4_PVA_Draft_Print.inst.cfg | 2 +- resources/quality/ultimaker3/um3_bb0.4_PVA_Fast_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_bb0.4_PVA_High_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_bb0.4_PVA_Normal_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_bb0.8_PVA_Draft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_bb0.8_PVA_Superdraft_Print.inst.cfg | 2 +- .../quality/ultimaker3/um3_bb0.8_PVA_Verydraft_Print.inst.cfg | 2 +- resources/quality/ultimaker3/um3_global_Draft_Quality.inst.cfg | 2 +- resources/quality/ultimaker3/um3_global_Fast_Quality.inst.cfg | 2 +- resources/quality/ultimaker3/um3_global_High_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_global_Normal_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_global_Superdraft_Quality.inst.cfg | 2 +- .../quality/ultimaker3/um3_global_Verydraft_Quality.inst.cfg | 2 +- .../vertex_delta_k8800/k8800_ABS_Extreme_Quality.inst.cfg | 2 +- .../quality/vertex_delta_k8800/k8800_ABS_High_Quality.inst.cfg | 2 +- .../vertex_delta_k8800/k8800_ABS_Normal_Quality.inst.cfg | 2 +- .../vertex_delta_k8800/k8800_PET_Extreme_Quality.inst.cfg | 2 +- .../quality/vertex_delta_k8800/k8800_PET_High_Quality.inst.cfg | 2 +- .../vertex_delta_k8800/k8800_PET_Normal_Quality.inst.cfg | 2 +- .../vertex_delta_k8800/k8800_PLA_Extreme_Quality.inst.cfg | 2 +- .../quality/vertex_delta_k8800/k8800_PLA_High_Quality.inst.cfg | 2 +- .../vertex_delta_k8800/k8800_PLA_Normal_Quality.inst.cfg | 2 +- .../vertex_delta_k8800/k8800_TPU_Extreme_Quality.inst.cfg | 2 +- .../quality/vertex_delta_k8800/k8800_TPU_High_Quality.inst.cfg | 2 +- .../vertex_delta_k8800/k8800_TPU_Normal_Quality.inst.cfg | 2 +- 395 files changed, 394 insertions(+), 398 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 9f37f09681..c9612321a5 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -56,7 +56,6 @@ from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.SettingFunction import SettingFunction from cura.Settings.MachineNameValidator import MachineNameValidator -from cura.Machines.QualityChangesGroup import QualityChangesGroup from cura.Machines.Models.BuildPlateModel import BuildPlateModel from cura.Machines.Models.NozzleModel import NozzleModel from cura.Machines.Models.QualityProfilesDropDownMenuModel import QualityProfilesDropDownMenuModel @@ -209,7 +208,7 @@ class CuraApplication(QtApplication): UM.VersionUpgradeManager.VersionUpgradeManager.getInstance().setCurrentVersions( { - ("quality_changes", QualityChangesGroup.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.QualityInstanceContainer, "application/x-uranium-instancecontainer"), + ("quality_changes", InstanceContainer.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.QualityInstanceContainer, "application/x-uranium-instancecontainer"), ("machine_stack", ContainerStack.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.MachineStack, "application/x-cura-globalstack"), ("extruder_train", ContainerStack.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.ExtruderStack, "application/x-cura-extruderstack"), ("preferences", Preferences.Version * 1000000 + self.SettingVersion): (Resources.Preferences, "application/x-uranium-preferences"), diff --git a/cura/Machines/QualityChangesGroup.py b/cura/Machines/QualityChangesGroup.py index dac9de1b38..ad320a7006 100644 --- a/cura/Machines/QualityChangesGroup.py +++ b/cura/Machines/QualityChangesGroup.py @@ -7,9 +7,6 @@ from .QualityGroup import QualityGroup class QualityChangesGroup(QualityGroup): - ## The file format version of quality changes. - Version = 3 - def __init__(self, name: str, quality_type: str, parent = None): super().__init__(name, quality_type, parent) self._container_registry = Application.getInstance().getContainerRegistry() diff --git a/resources/quality/abax_pri3/apri3_pla_fast.inst.cfg b/resources/quality/abax_pri3/apri3_pla_fast.inst.cfg index 7d1c1bf588..50ff90670f 100644 --- a/resources/quality/abax_pri3/apri3_pla_fast.inst.cfg +++ b/resources/quality/abax_pri3/apri3_pla_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = abax_pri3 diff --git a/resources/quality/abax_pri3/apri3_pla_high.inst.cfg b/resources/quality/abax_pri3/apri3_pla_high.inst.cfg index 46a4178dd9..0bcd5ef77d 100644 --- a/resources/quality/abax_pri3/apri3_pla_high.inst.cfg +++ b/resources/quality/abax_pri3/apri3_pla_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = abax_pri3 diff --git a/resources/quality/abax_pri3/apri3_pla_normal.inst.cfg b/resources/quality/abax_pri3/apri3_pla_normal.inst.cfg index 3f6f36cfe6..5ef275652d 100644 --- a/resources/quality/abax_pri3/apri3_pla_normal.inst.cfg +++ b/resources/quality/abax_pri3/apri3_pla_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = abax_pri3 diff --git a/resources/quality/abax_pri5/apri5_pla_fast.inst.cfg b/resources/quality/abax_pri5/apri5_pla_fast.inst.cfg index 517c767ac5..922da8e88e 100644 --- a/resources/quality/abax_pri5/apri5_pla_fast.inst.cfg +++ b/resources/quality/abax_pri5/apri5_pla_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = abax_pri5 diff --git a/resources/quality/abax_pri5/apri5_pla_high.inst.cfg b/resources/quality/abax_pri5/apri5_pla_high.inst.cfg index 01699e39f6..2b1c6b017b 100644 --- a/resources/quality/abax_pri5/apri5_pla_high.inst.cfg +++ b/resources/quality/abax_pri5/apri5_pla_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = abax_pri5 diff --git a/resources/quality/abax_pri5/apri5_pla_normal.inst.cfg b/resources/quality/abax_pri5/apri5_pla_normal.inst.cfg index ea1023dc43..23b21f597b 100644 --- a/resources/quality/abax_pri5/apri5_pla_normal.inst.cfg +++ b/resources/quality/abax_pri5/apri5_pla_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = abax_pri5 diff --git a/resources/quality/abax_titan/atitan_pla_fast.inst.cfg b/resources/quality/abax_titan/atitan_pla_fast.inst.cfg index ae489c3792..5d935a915a 100644 --- a/resources/quality/abax_titan/atitan_pla_fast.inst.cfg +++ b/resources/quality/abax_titan/atitan_pla_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = abax_titan diff --git a/resources/quality/abax_titan/atitan_pla_high.inst.cfg b/resources/quality/abax_titan/atitan_pla_high.inst.cfg index f9bf350814..8bd45034e3 100644 --- a/resources/quality/abax_titan/atitan_pla_high.inst.cfg +++ b/resources/quality/abax_titan/atitan_pla_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = abax_titan diff --git a/resources/quality/abax_titan/atitan_pla_normal.inst.cfg b/resources/quality/abax_titan/atitan_pla_normal.inst.cfg index c73d6901fb..081e5ad977 100644 --- a/resources/quality/abax_titan/atitan_pla_normal.inst.cfg +++ b/resources/quality/abax_titan/atitan_pla_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = abax_titan diff --git a/resources/quality/anycubic_i3_mega/anycubic_i3_mega_draft.inst.cfg b/resources/quality/anycubic_i3_mega/anycubic_i3_mega_draft.inst.cfg index caa6d8edb6..821205ca69 100644 --- a/resources/quality/anycubic_i3_mega/anycubic_i3_mega_draft.inst.cfg +++ b/resources/quality/anycubic_i3_mega/anycubic_i3_mega_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Draft definition = anycubic_i3_mega diff --git a/resources/quality/anycubic_i3_mega/anycubic_i3_mega_high.inst.cfg b/resources/quality/anycubic_i3_mega/anycubic_i3_mega_high.inst.cfg index 5d6f8d9013..e686ce50ac 100644 --- a/resources/quality/anycubic_i3_mega/anycubic_i3_mega_high.inst.cfg +++ b/resources/quality/anycubic_i3_mega/anycubic_i3_mega_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = anycubic_i3_mega diff --git a/resources/quality/anycubic_i3_mega/anycubic_i3_mega_normal.inst.cfg b/resources/quality/anycubic_i3_mega/anycubic_i3_mega_normal.inst.cfg index ca25afa424..3e855c1bbc 100644 --- a/resources/quality/anycubic_i3_mega/anycubic_i3_mega_normal.inst.cfg +++ b/resources/quality/anycubic_i3_mega/anycubic_i3_mega_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = anycubic_i3_mega diff --git a/resources/quality/builder_premium/bp_BVOH_Coarse_Quality.inst.cfg b/resources/quality/builder_premium/bp_BVOH_Coarse_Quality.inst.cfg index d83f2a1ccd..c5a92e3c93 100644 --- a/resources/quality/builder_premium/bp_BVOH_Coarse_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_BVOH_Coarse_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Coarse definition = builder_premium_small diff --git a/resources/quality/builder_premium/bp_BVOH_High_Quality.inst.cfg b/resources/quality/builder_premium/bp_BVOH_High_Quality.inst.cfg index f029a0206f..72ce4f3555 100644 --- a/resources/quality/builder_premium/bp_BVOH_High_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_BVOH_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High Quality definition = builder_premium_small diff --git a/resources/quality/builder_premium/bp_BVOH_Normal_Quality.inst.cfg b/resources/quality/builder_premium/bp_BVOH_Normal_Quality.inst.cfg index 640812b37d..daa1d8bc78 100644 --- a/resources/quality/builder_premium/bp_BVOH_Normal_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_BVOH_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = builder_premium_small diff --git a/resources/quality/builder_premium/bp_Innoflex60_Coarse_Quality.inst.cfg b/resources/quality/builder_premium/bp_Innoflex60_Coarse_Quality.inst.cfg index 905cf50518..827c726071 100644 --- a/resources/quality/builder_premium/bp_Innoflex60_Coarse_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_Innoflex60_Coarse_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Coarse definition = builder_premium_small diff --git a/resources/quality/builder_premium/bp_Innoflex60_High_Quality.inst.cfg b/resources/quality/builder_premium/bp_Innoflex60_High_Quality.inst.cfg index 835ce04d61..4c84d0ddfe 100644 --- a/resources/quality/builder_premium/bp_Innoflex60_High_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_Innoflex60_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High Quality definition = builder_premium_small diff --git a/resources/quality/builder_premium/bp_Innoflex60_Normal_Quality.inst.cfg b/resources/quality/builder_premium/bp_Innoflex60_Normal_Quality.inst.cfg index ba176dbc5c..23813f85b9 100644 --- a/resources/quality/builder_premium/bp_Innoflex60_Normal_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_Innoflex60_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = builder_premium_small diff --git a/resources/quality/builder_premium/bp_PET_Coarse_Quality.inst.cfg b/resources/quality/builder_premium/bp_PET_Coarse_Quality.inst.cfg index 736defd5c6..da0d40393c 100644 --- a/resources/quality/builder_premium/bp_PET_Coarse_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_PET_Coarse_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Coarse definition = builder_premium_small diff --git a/resources/quality/builder_premium/bp_PET_High_Quality.inst.cfg b/resources/quality/builder_premium/bp_PET_High_Quality.inst.cfg index 82c7fa7baf..b78a5a29d7 100644 --- a/resources/quality/builder_premium/bp_PET_High_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_PET_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High Quality definition = builder_premium_small diff --git a/resources/quality/builder_premium/bp_PET_Normal_Quality.inst.cfg b/resources/quality/builder_premium/bp_PET_Normal_Quality.inst.cfg index b1e9ff91df..600fbed476 100644 --- a/resources/quality/builder_premium/bp_PET_Normal_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_PET_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = builder_premium_small diff --git a/resources/quality/builder_premium/bp_PLA_Coarse_Quality.inst.cfg b/resources/quality/builder_premium/bp_PLA_Coarse_Quality.inst.cfg index 9b8078e266..d1c1d4d563 100644 --- a/resources/quality/builder_premium/bp_PLA_Coarse_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_PLA_Coarse_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Coarse definition = builder_premium_small diff --git a/resources/quality/builder_premium/bp_PLA_High_Quality.inst.cfg b/resources/quality/builder_premium/bp_PLA_High_Quality.inst.cfg index 2bbfb02e0d..1063342b89 100644 --- a/resources/quality/builder_premium/bp_PLA_High_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_PLA_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High Quality definition = builder_premium_small diff --git a/resources/quality/builder_premium/bp_PLA_Normal_Quality.inst.cfg b/resources/quality/builder_premium/bp_PLA_Normal_Quality.inst.cfg index b77ac747a8..6612c704f3 100644 --- a/resources/quality/builder_premium/bp_PLA_Normal_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_PLA_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = builder_premium_small diff --git a/resources/quality/builder_premium/bp_PVA_Coarse_Quality.inst.cfg b/resources/quality/builder_premium/bp_PVA_Coarse_Quality.inst.cfg index f626604f70..2717ffe998 100644 --- a/resources/quality/builder_premium/bp_PVA_Coarse_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_PVA_Coarse_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Coarse definition = builder_premium_small diff --git a/resources/quality/builder_premium/bp_PVA_High_Quality.inst.cfg b/resources/quality/builder_premium/bp_PVA_High_Quality.inst.cfg index caf0bd4bd7..3ab782af5c 100644 --- a/resources/quality/builder_premium/bp_PVA_High_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_PVA_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High Quality definition = builder_premium_small diff --git a/resources/quality/builder_premium/bp_PVA_Normal_Quality.inst.cfg b/resources/quality/builder_premium/bp_PVA_Normal_Quality.inst.cfg index 4f08010a6f..fe24e976c7 100644 --- a/resources/quality/builder_premium/bp_PVA_Normal_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_PVA_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = builder_premium_small diff --git a/resources/quality/builder_premium/bp_global_Coarse_Quality.inst.cfg b/resources/quality/builder_premium/bp_global_Coarse_Quality.inst.cfg index c9b2b3a654..708a135847 100644 --- a/resources/quality/builder_premium/bp_global_Coarse_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_global_Coarse_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Coarse definition = builder_premium_small diff --git a/resources/quality/builder_premium/bp_global_High_Quality.inst.cfg b/resources/quality/builder_premium/bp_global_High_Quality.inst.cfg index efad0f96e5..0c96206a7d 100644 --- a/resources/quality/builder_premium/bp_global_High_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_global_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High Quality definition = builder_premium_small diff --git a/resources/quality/builder_premium/bp_global_Normal_Quality.inst.cfg b/resources/quality/builder_premium/bp_global_Normal_Quality.inst.cfg index 69c6214aa8..833e7e8905 100644 --- a/resources/quality/builder_premium/bp_global_Normal_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_global_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = builder_premium_small diff --git a/resources/quality/cartesio/abs/cartesio_0.25_abs_high.inst.cfg b/resources/quality/cartesio/abs/cartesio_0.25_abs_high.inst.cfg index 82cbed79e3..5e713275c6 100644 --- a/resources/quality/cartesio/abs/cartesio_0.25_abs_high.inst.cfg +++ b/resources/quality/cartesio/abs/cartesio_0.25_abs_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/abs/cartesio_0.25_abs_normal.inst.cfg b/resources/quality/cartesio/abs/cartesio_0.25_abs_normal.inst.cfg index 4c8da554d3..d35dcf1c18 100644 --- a/resources/quality/cartesio/abs/cartesio_0.25_abs_normal.inst.cfg +++ b/resources/quality/cartesio/abs/cartesio_0.25_abs_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/abs/cartesio_0.4_abs_high.inst.cfg b/resources/quality/cartesio/abs/cartesio_0.4_abs_high.inst.cfg index 1e068c97c7..06ef74108b 100644 --- a/resources/quality/cartesio/abs/cartesio_0.4_abs_high.inst.cfg +++ b/resources/quality/cartesio/abs/cartesio_0.4_abs_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/abs/cartesio_0.4_abs_normal.inst.cfg b/resources/quality/cartesio/abs/cartesio_0.4_abs_normal.inst.cfg index 7019eb7a5b..8e5b6aadc0 100644 --- a/resources/quality/cartesio/abs/cartesio_0.4_abs_normal.inst.cfg +++ b/resources/quality/cartesio/abs/cartesio_0.4_abs_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/abs/cartesio_0.8_abs_coarse.inst.cfg b/resources/quality/cartesio/abs/cartesio_0.8_abs_coarse.inst.cfg index 7b12575e69..5da823a2d8 100644 --- a/resources/quality/cartesio/abs/cartesio_0.8_abs_coarse.inst.cfg +++ b/resources/quality/cartesio/abs/cartesio_0.8_abs_coarse.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Coarse definition = cartesio diff --git a/resources/quality/cartesio/abs/cartesio_0.8_abs_extra_coarse.inst.cfg b/resources/quality/cartesio/abs/cartesio_0.8_abs_extra_coarse.inst.cfg index bc25bf8d00..267857cff1 100644 --- a/resources/quality/cartesio/abs/cartesio_0.8_abs_extra_coarse.inst.cfg +++ b/resources/quality/cartesio/abs/cartesio_0.8_abs_extra_coarse.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Coarse definition = cartesio diff --git a/resources/quality/cartesio/abs/cartesio_0.8_abs_high.inst.cfg b/resources/quality/cartesio/abs/cartesio_0.8_abs_high.inst.cfg index b8ca55fa6e..e3219d145c 100644 --- a/resources/quality/cartesio/abs/cartesio_0.8_abs_high.inst.cfg +++ b/resources/quality/cartesio/abs/cartesio_0.8_abs_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/abs/cartesio_0.8_abs_normal.inst.cfg b/resources/quality/cartesio/abs/cartesio_0.8_abs_normal.inst.cfg index 409e0f9adf..111bef11dc 100644 --- a/resources/quality/cartesio/abs/cartesio_0.8_abs_normal.inst.cfg +++ b/resources/quality/cartesio/abs/cartesio_0.8_abs_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/arnitel/cartesio_0.4_arnitel2045_high.inst.cfg b/resources/quality/cartesio/arnitel/cartesio_0.4_arnitel2045_high.inst.cfg index 11d541831d..35dddeca91 100644 --- a/resources/quality/cartesio/arnitel/cartesio_0.4_arnitel2045_high.inst.cfg +++ b/resources/quality/cartesio/arnitel/cartesio_0.4_arnitel2045_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/arnitel/cartesio_0.4_arnitel2045_normal.inst.cfg b/resources/quality/cartesio/arnitel/cartesio_0.4_arnitel2045_normal.inst.cfg index d6a972b1cd..3234881c72 100644 --- a/resources/quality/cartesio/arnitel/cartesio_0.4_arnitel2045_normal.inst.cfg +++ b/resources/quality/cartesio/arnitel/cartesio_0.4_arnitel2045_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/cartesio_global_Coarse_Quality.inst.cfg b/resources/quality/cartesio/cartesio_global_Coarse_Quality.inst.cfg index 53cbb6bf06..017483f79a 100644 --- a/resources/quality/cartesio/cartesio_global_Coarse_Quality.inst.cfg +++ b/resources/quality/cartesio/cartesio_global_Coarse_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Coarse definition = cartesio diff --git a/resources/quality/cartesio/cartesio_global_Extra_Coarse_Quality.inst.cfg b/resources/quality/cartesio/cartesio_global_Extra_Coarse_Quality.inst.cfg index 4d612db89f..aadb582309 100644 --- a/resources/quality/cartesio/cartesio_global_Extra_Coarse_Quality.inst.cfg +++ b/resources/quality/cartesio/cartesio_global_Extra_Coarse_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Coarse definition = cartesio diff --git a/resources/quality/cartesio/cartesio_global_High_Quality.inst.cfg b/resources/quality/cartesio/cartesio_global_High_Quality.inst.cfg index b9e4f287a1..e4131dc3a2 100644 --- a/resources/quality/cartesio/cartesio_global_High_Quality.inst.cfg +++ b/resources/quality/cartesio/cartesio_global_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/cartesio_global_Normal_Quality.inst.cfg b/resources/quality/cartesio/cartesio_global_Normal_Quality.inst.cfg index 1b3af7c9ce..e29a98c980 100644 --- a/resources/quality/cartesio/cartesio_global_Normal_Quality.inst.cfg +++ b/resources/quality/cartesio/cartesio_global_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/hips/cartesio_0.25_hips_high.inst.cfg b/resources/quality/cartesio/hips/cartesio_0.25_hips_high.inst.cfg index df6ca1d0a0..b2dc76479f 100644 --- a/resources/quality/cartesio/hips/cartesio_0.25_hips_high.inst.cfg +++ b/resources/quality/cartesio/hips/cartesio_0.25_hips_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/hips/cartesio_0.25_hips_normal.inst.cfg b/resources/quality/cartesio/hips/cartesio_0.25_hips_normal.inst.cfg index 663276681f..c18167b97a 100644 --- a/resources/quality/cartesio/hips/cartesio_0.25_hips_normal.inst.cfg +++ b/resources/quality/cartesio/hips/cartesio_0.25_hips_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/hips/cartesio_0.4_hips_high.inst.cfg b/resources/quality/cartesio/hips/cartesio_0.4_hips_high.inst.cfg index 54b6edc507..506ff1807b 100644 --- a/resources/quality/cartesio/hips/cartesio_0.4_hips_high.inst.cfg +++ b/resources/quality/cartesio/hips/cartesio_0.4_hips_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/hips/cartesio_0.4_hips_normal.inst.cfg b/resources/quality/cartesio/hips/cartesio_0.4_hips_normal.inst.cfg index c843f1653d..1f2ee24064 100644 --- a/resources/quality/cartesio/hips/cartesio_0.4_hips_normal.inst.cfg +++ b/resources/quality/cartesio/hips/cartesio_0.4_hips_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/hips/cartesio_0.8_hips_coarse.inst.cfg b/resources/quality/cartesio/hips/cartesio_0.8_hips_coarse.inst.cfg index d848e3ee3b..d117df88a6 100644 --- a/resources/quality/cartesio/hips/cartesio_0.8_hips_coarse.inst.cfg +++ b/resources/quality/cartesio/hips/cartesio_0.8_hips_coarse.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Coarse definition = cartesio diff --git a/resources/quality/cartesio/hips/cartesio_0.8_hips_extra_coarse.inst.cfg b/resources/quality/cartesio/hips/cartesio_0.8_hips_extra_coarse.inst.cfg index 7f2d436f32..e833abcdad 100644 --- a/resources/quality/cartesio/hips/cartesio_0.8_hips_extra_coarse.inst.cfg +++ b/resources/quality/cartesio/hips/cartesio_0.8_hips_extra_coarse.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Coarse definition = cartesio diff --git a/resources/quality/cartesio/hips/cartesio_0.8_hips_high.inst.cfg b/resources/quality/cartesio/hips/cartesio_0.8_hips_high.inst.cfg index 0e529a97e9..eee5862fea 100644 --- a/resources/quality/cartesio/hips/cartesio_0.8_hips_high.inst.cfg +++ b/resources/quality/cartesio/hips/cartesio_0.8_hips_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/hips/cartesio_0.8_hips_normal.inst.cfg b/resources/quality/cartesio/hips/cartesio_0.8_hips_normal.inst.cfg index 7c4fcbcfdd..b0057d5b03 100644 --- a/resources/quality/cartesio/hips/cartesio_0.8_hips_normal.inst.cfg +++ b/resources/quality/cartesio/hips/cartesio_0.8_hips_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/nylon/cartesio_0.25_nylon_high.inst.cfg b/resources/quality/cartesio/nylon/cartesio_0.25_nylon_high.inst.cfg index 7690040f8c..6dce2b7ea2 100644 --- a/resources/quality/cartesio/nylon/cartesio_0.25_nylon_high.inst.cfg +++ b/resources/quality/cartesio/nylon/cartesio_0.25_nylon_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/nylon/cartesio_0.25_nylon_normal.inst.cfg b/resources/quality/cartesio/nylon/cartesio_0.25_nylon_normal.inst.cfg index fcff2b6e4b..169a7cab65 100644 --- a/resources/quality/cartesio/nylon/cartesio_0.25_nylon_normal.inst.cfg +++ b/resources/quality/cartesio/nylon/cartesio_0.25_nylon_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/nylon/cartesio_0.4_nylon_high.inst.cfg b/resources/quality/cartesio/nylon/cartesio_0.4_nylon_high.inst.cfg index 0cca726dcc..101fb595d5 100644 --- a/resources/quality/cartesio/nylon/cartesio_0.4_nylon_high.inst.cfg +++ b/resources/quality/cartesio/nylon/cartesio_0.4_nylon_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/nylon/cartesio_0.4_nylon_normal.inst.cfg b/resources/quality/cartesio/nylon/cartesio_0.4_nylon_normal.inst.cfg index d231b7c296..dc5522bda3 100644 --- a/resources/quality/cartesio/nylon/cartesio_0.4_nylon_normal.inst.cfg +++ b/resources/quality/cartesio/nylon/cartesio_0.4_nylon_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/nylon/cartesio_0.8_nylon_coarse.inst.cfg b/resources/quality/cartesio/nylon/cartesio_0.8_nylon_coarse.inst.cfg index 22eb78ec00..0b4ef88282 100644 --- a/resources/quality/cartesio/nylon/cartesio_0.8_nylon_coarse.inst.cfg +++ b/resources/quality/cartesio/nylon/cartesio_0.8_nylon_coarse.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Coarse definition = cartesio diff --git a/resources/quality/cartesio/nylon/cartesio_0.8_nylon_extra_coarse.inst.cfg b/resources/quality/cartesio/nylon/cartesio_0.8_nylon_extra_coarse.inst.cfg index 31f5d45a88..2fd9aa3220 100644 --- a/resources/quality/cartesio/nylon/cartesio_0.8_nylon_extra_coarse.inst.cfg +++ b/resources/quality/cartesio/nylon/cartesio_0.8_nylon_extra_coarse.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Coarse definition = cartesio diff --git a/resources/quality/cartesio/nylon/cartesio_0.8_nylon_high.inst.cfg b/resources/quality/cartesio/nylon/cartesio_0.8_nylon_high.inst.cfg index 9287ec9a4c..26f749e357 100644 --- a/resources/quality/cartesio/nylon/cartesio_0.8_nylon_high.inst.cfg +++ b/resources/quality/cartesio/nylon/cartesio_0.8_nylon_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/nylon/cartesio_0.8_nylon_normal.inst.cfg b/resources/quality/cartesio/nylon/cartesio_0.8_nylon_normal.inst.cfg index ecf83c29bd..4843c9cbf4 100644 --- a/resources/quality/cartesio/nylon/cartesio_0.8_nylon_normal.inst.cfg +++ b/resources/quality/cartesio/nylon/cartesio_0.8_nylon_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/pc/cartesio_0.25_pc_high.inst.cfg b/resources/quality/cartesio/pc/cartesio_0.25_pc_high.inst.cfg index 23df3d0451..d29c8c6801 100644 --- a/resources/quality/cartesio/pc/cartesio_0.25_pc_high.inst.cfg +++ b/resources/quality/cartesio/pc/cartesio_0.25_pc_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/pc/cartesio_0.25_pc_normal.inst.cfg b/resources/quality/cartesio/pc/cartesio_0.25_pc_normal.inst.cfg index 0ac876a538..35168f8ed7 100644 --- a/resources/quality/cartesio/pc/cartesio_0.25_pc_normal.inst.cfg +++ b/resources/quality/cartesio/pc/cartesio_0.25_pc_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/pc/cartesio_0.4_pc_high.inst.cfg b/resources/quality/cartesio/pc/cartesio_0.4_pc_high.inst.cfg index 0c92dc32fc..05bb623a90 100644 --- a/resources/quality/cartesio/pc/cartesio_0.4_pc_high.inst.cfg +++ b/resources/quality/cartesio/pc/cartesio_0.4_pc_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/pc/cartesio_0.4_pc_normal.inst.cfg b/resources/quality/cartesio/pc/cartesio_0.4_pc_normal.inst.cfg index 2d53790fe7..569ecb069a 100644 --- a/resources/quality/cartesio/pc/cartesio_0.4_pc_normal.inst.cfg +++ b/resources/quality/cartesio/pc/cartesio_0.4_pc_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/pc/cartesio_0.8_pc_coarse.inst.cfg b/resources/quality/cartesio/pc/cartesio_0.8_pc_coarse.inst.cfg index 5d807c5d65..b35681187d 100644 --- a/resources/quality/cartesio/pc/cartesio_0.8_pc_coarse.inst.cfg +++ b/resources/quality/cartesio/pc/cartesio_0.8_pc_coarse.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Coarse definition = cartesio diff --git a/resources/quality/cartesio/pc/cartesio_0.8_pc_extra_coarse.inst.cfg b/resources/quality/cartesio/pc/cartesio_0.8_pc_extra_coarse.inst.cfg index 75c72a1f56..75fe030443 100644 --- a/resources/quality/cartesio/pc/cartesio_0.8_pc_extra_coarse.inst.cfg +++ b/resources/quality/cartesio/pc/cartesio_0.8_pc_extra_coarse.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Coarse definition = cartesio diff --git a/resources/quality/cartesio/pc/cartesio_0.8_pc_high.inst.cfg b/resources/quality/cartesio/pc/cartesio_0.8_pc_high.inst.cfg index 0b1469fde4..05232ac1b3 100644 --- a/resources/quality/cartesio/pc/cartesio_0.8_pc_high.inst.cfg +++ b/resources/quality/cartesio/pc/cartesio_0.8_pc_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/pc/cartesio_0.8_pc_normal.inst.cfg b/resources/quality/cartesio/pc/cartesio_0.8_pc_normal.inst.cfg index 7842a91f61..106afcf992 100644 --- a/resources/quality/cartesio/pc/cartesio_0.8_pc_normal.inst.cfg +++ b/resources/quality/cartesio/pc/cartesio_0.8_pc_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/petg/cartesio_0.25_petg_high.inst.cfg b/resources/quality/cartesio/petg/cartesio_0.25_petg_high.inst.cfg index 5688828343..edeb791847 100644 --- a/resources/quality/cartesio/petg/cartesio_0.25_petg_high.inst.cfg +++ b/resources/quality/cartesio/petg/cartesio_0.25_petg_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/petg/cartesio_0.25_petg_normal.inst.cfg b/resources/quality/cartesio/petg/cartesio_0.25_petg_normal.inst.cfg index e47b9849ad..ca95ba4d55 100644 --- a/resources/quality/cartesio/petg/cartesio_0.25_petg_normal.inst.cfg +++ b/resources/quality/cartesio/petg/cartesio_0.25_petg_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/petg/cartesio_0.4_petg_high.inst.cfg b/resources/quality/cartesio/petg/cartesio_0.4_petg_high.inst.cfg index eb0cc83a63..47e4e74fba 100644 --- a/resources/quality/cartesio/petg/cartesio_0.4_petg_high.inst.cfg +++ b/resources/quality/cartesio/petg/cartesio_0.4_petg_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/petg/cartesio_0.4_petg_normal.inst.cfg b/resources/quality/cartesio/petg/cartesio_0.4_petg_normal.inst.cfg index 5b2e8bb687..737289f778 100644 --- a/resources/quality/cartesio/petg/cartesio_0.4_petg_normal.inst.cfg +++ b/resources/quality/cartesio/petg/cartesio_0.4_petg_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/petg/cartesio_0.8_petg_coarse.inst.cfg b/resources/quality/cartesio/petg/cartesio_0.8_petg_coarse.inst.cfg index c65551c56c..54abbbeb46 100644 --- a/resources/quality/cartesio/petg/cartesio_0.8_petg_coarse.inst.cfg +++ b/resources/quality/cartesio/petg/cartesio_0.8_petg_coarse.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Coarse definition = cartesio diff --git a/resources/quality/cartesio/petg/cartesio_0.8_petg_extra_coarse.inst.cfg b/resources/quality/cartesio/petg/cartesio_0.8_petg_extra_coarse.inst.cfg index 52099fc789..75ef0ed89b 100644 --- a/resources/quality/cartesio/petg/cartesio_0.8_petg_extra_coarse.inst.cfg +++ b/resources/quality/cartesio/petg/cartesio_0.8_petg_extra_coarse.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Coarse definition = cartesio diff --git a/resources/quality/cartesio/petg/cartesio_0.8_petg_high.inst.cfg b/resources/quality/cartesio/petg/cartesio_0.8_petg_high.inst.cfg index d6932f9c07..2a9542ce56 100644 --- a/resources/quality/cartesio/petg/cartesio_0.8_petg_high.inst.cfg +++ b/resources/quality/cartesio/petg/cartesio_0.8_petg_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/petg/cartesio_0.8_petg_normal.inst.cfg b/resources/quality/cartesio/petg/cartesio_0.8_petg_normal.inst.cfg index 6289073085..9f27c3c8d1 100644 --- a/resources/quality/cartesio/petg/cartesio_0.8_petg_normal.inst.cfg +++ b/resources/quality/cartesio/petg/cartesio_0.8_petg_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/pla/cartesio_0.25_pla_high.inst.cfg b/resources/quality/cartesio/pla/cartesio_0.25_pla_high.inst.cfg index 8b614f5bef..62cf3194c0 100644 --- a/resources/quality/cartesio/pla/cartesio_0.25_pla_high.inst.cfg +++ b/resources/quality/cartesio/pla/cartesio_0.25_pla_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/pla/cartesio_0.25_pla_normal.inst.cfg b/resources/quality/cartesio/pla/cartesio_0.25_pla_normal.inst.cfg index 56ea324826..5dd27477e1 100644 --- a/resources/quality/cartesio/pla/cartesio_0.25_pla_normal.inst.cfg +++ b/resources/quality/cartesio/pla/cartesio_0.25_pla_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/pla/cartesio_0.4_pla_high.inst.cfg b/resources/quality/cartesio/pla/cartesio_0.4_pla_high.inst.cfg index e83d26581d..b6bf3808be 100644 --- a/resources/quality/cartesio/pla/cartesio_0.4_pla_high.inst.cfg +++ b/resources/quality/cartesio/pla/cartesio_0.4_pla_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/pla/cartesio_0.4_pla_normal.inst.cfg b/resources/quality/cartesio/pla/cartesio_0.4_pla_normal.inst.cfg index 1c0b440904..a03b316e6f 100644 --- a/resources/quality/cartesio/pla/cartesio_0.4_pla_normal.inst.cfg +++ b/resources/quality/cartesio/pla/cartesio_0.4_pla_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/pla/cartesio_0.8_pla_coarse.inst.cfg b/resources/quality/cartesio/pla/cartesio_0.8_pla_coarse.inst.cfg index 9a6a517a93..6284ab3325 100644 --- a/resources/quality/cartesio/pla/cartesio_0.8_pla_coarse.inst.cfg +++ b/resources/quality/cartesio/pla/cartesio_0.8_pla_coarse.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Coarse definition = cartesio diff --git a/resources/quality/cartesio/pla/cartesio_0.8_pla_extra_coarse.inst.cfg b/resources/quality/cartesio/pla/cartesio_0.8_pla_extra_coarse.inst.cfg index 17ef04e0c0..58b4c347f3 100644 --- a/resources/quality/cartesio/pla/cartesio_0.8_pla_extra_coarse.inst.cfg +++ b/resources/quality/cartesio/pla/cartesio_0.8_pla_extra_coarse.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Coarse definition = cartesio diff --git a/resources/quality/cartesio/pla/cartesio_0.8_pla_high.inst.cfg b/resources/quality/cartesio/pla/cartesio_0.8_pla_high.inst.cfg index 6a4b88788a..f0d22251bb 100644 --- a/resources/quality/cartesio/pla/cartesio_0.8_pla_high.inst.cfg +++ b/resources/quality/cartesio/pla/cartesio_0.8_pla_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/pla/cartesio_0.8_pla_normal.inst.cfg b/resources/quality/cartesio/pla/cartesio_0.8_pla_normal.inst.cfg index 515e473bb0..44ed46ddd3 100644 --- a/resources/quality/cartesio/pla/cartesio_0.8_pla_normal.inst.cfg +++ b/resources/quality/cartesio/pla/cartesio_0.8_pla_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/pva/cartesio_0.25_pva_high.inst.cfg b/resources/quality/cartesio/pva/cartesio_0.25_pva_high.inst.cfg index dfbde35b9c..aa9ac8393d 100644 --- a/resources/quality/cartesio/pva/cartesio_0.25_pva_high.inst.cfg +++ b/resources/quality/cartesio/pva/cartesio_0.25_pva_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/pva/cartesio_0.25_pva_normal.inst.cfg b/resources/quality/cartesio/pva/cartesio_0.25_pva_normal.inst.cfg index ed1fa07207..b4de6b5730 100644 --- a/resources/quality/cartesio/pva/cartesio_0.25_pva_normal.inst.cfg +++ b/resources/quality/cartesio/pva/cartesio_0.25_pva_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/pva/cartesio_0.4_pva_high.inst.cfg b/resources/quality/cartesio/pva/cartesio_0.4_pva_high.inst.cfg index a2c4a21674..5a60dfbe17 100644 --- a/resources/quality/cartesio/pva/cartesio_0.4_pva_high.inst.cfg +++ b/resources/quality/cartesio/pva/cartesio_0.4_pva_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/pva/cartesio_0.4_pva_normal.inst.cfg b/resources/quality/cartesio/pva/cartesio_0.4_pva_normal.inst.cfg index 91164306fb..9cc57ac16a 100644 --- a/resources/quality/cartesio/pva/cartesio_0.4_pva_normal.inst.cfg +++ b/resources/quality/cartesio/pva/cartesio_0.4_pva_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/cartesio/pva/cartesio_0.8_pva_coarse.inst.cfg b/resources/quality/cartesio/pva/cartesio_0.8_pva_coarse.inst.cfg index 003f980901..df1bffeb41 100644 --- a/resources/quality/cartesio/pva/cartesio_0.8_pva_coarse.inst.cfg +++ b/resources/quality/cartesio/pva/cartesio_0.8_pva_coarse.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Coarse definition = cartesio diff --git a/resources/quality/cartesio/pva/cartesio_0.8_pva_extra_coarse.inst.cfg b/resources/quality/cartesio/pva/cartesio_0.8_pva_extra_coarse.inst.cfg index c328442ee8..30ade55494 100644 --- a/resources/quality/cartesio/pva/cartesio_0.8_pva_extra_coarse.inst.cfg +++ b/resources/quality/cartesio/pva/cartesio_0.8_pva_extra_coarse.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Coarse definition = cartesio diff --git a/resources/quality/cartesio/pva/cartesio_0.8_pva_high.inst.cfg b/resources/quality/cartesio/pva/cartesio_0.8_pva_high.inst.cfg index 4830d5bcc9..c8ab571baf 100644 --- a/resources/quality/cartesio/pva/cartesio_0.8_pva_high.inst.cfg +++ b/resources/quality/cartesio/pva/cartesio_0.8_pva_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = cartesio diff --git a/resources/quality/cartesio/pva/cartesio_0.8_pva_normal.inst.cfg b/resources/quality/cartesio/pva/cartesio_0.8_pva_normal.inst.cfg index f739f1668b..815694e410 100644 --- a/resources/quality/cartesio/pva/cartesio_0.8_pva_normal.inst.cfg +++ b/resources/quality/cartesio/pva/cartesio_0.8_pva_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = cartesio diff --git a/resources/quality/coarse.inst.cfg b/resources/quality/coarse.inst.cfg index 1accd77807..9dff2a02b3 100644 --- a/resources/quality/coarse.inst.cfg +++ b/resources/quality/coarse.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Coarse Quality definition = fdmprinter diff --git a/resources/quality/deltacomb/deltacomb_abs_fast.inst.cfg b/resources/quality/deltacomb/deltacomb_abs_fast.inst.cfg index 75774fc000..3863cb6940 100644 --- a/resources/quality/deltacomb/deltacomb_abs_fast.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_abs_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 definition = deltacomb name = Fast Quality (beta) diff --git a/resources/quality/deltacomb/deltacomb_abs_high.inst.cfg b/resources/quality/deltacomb/deltacomb_abs_high.inst.cfg index 65542f114a..715d8a6841 100644 --- a/resources/quality/deltacomb/deltacomb_abs_high.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_abs_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 definition = deltacomb name = High Quality (beta) diff --git a/resources/quality/deltacomb/deltacomb_abs_normal.inst.cfg b/resources/quality/deltacomb/deltacomb_abs_normal.inst.cfg index 55248345fa..7cddbb154a 100644 --- a/resources/quality/deltacomb/deltacomb_abs_normal.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_abs_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 definition = deltacomb name = Normal Quality (beta) diff --git a/resources/quality/deltacomb/deltacomb_nylon_fast.inst.cfg b/resources/quality/deltacomb/deltacomb_nylon_fast.inst.cfg index 5986c65872..72d2b30199 100644 --- a/resources/quality/deltacomb/deltacomb_nylon_fast.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_nylon_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast Quality (beta) definition = deltacomb diff --git a/resources/quality/deltacomb/deltacomb_nylon_high.inst.cfg b/resources/quality/deltacomb/deltacomb_nylon_high.inst.cfg index 158f903bab..2cd71a96b1 100644 --- a/resources/quality/deltacomb/deltacomb_nylon_high.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_nylon_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High Quality (beta) definition = deltacomb diff --git a/resources/quality/deltacomb/deltacomb_nylon_normal.inst.cfg b/resources/quality/deltacomb/deltacomb_nylon_normal.inst.cfg index 89024f30b7..d42fdee730 100644 --- a/resources/quality/deltacomb/deltacomb_nylon_normal.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_nylon_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal Quality (beta) definition = deltacomb diff --git a/resources/quality/deltacomb/deltacomb_pla_fast.inst.cfg b/resources/quality/deltacomb/deltacomb_pla_fast.inst.cfg index 98a5578d89..11fefbaed1 100644 --- a/resources/quality/deltacomb/deltacomb_pla_fast.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_pla_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 definition = deltacomb name = Fast Quality diff --git a/resources/quality/deltacomb/deltacomb_pla_high.inst.cfg b/resources/quality/deltacomb/deltacomb_pla_high.inst.cfg index 554312ce7b..4b7125dbb9 100644 --- a/resources/quality/deltacomb/deltacomb_pla_high.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_pla_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 definition = deltacomb name = High Quality diff --git a/resources/quality/deltacomb/deltacomb_pla_normal.inst.cfg b/resources/quality/deltacomb/deltacomb_pla_normal.inst.cfg index 3f22aa1200..e935c45567 100644 --- a/resources/quality/deltacomb/deltacomb_pla_normal.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_pla_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 definition = deltacomb name = Normal Quality diff --git a/resources/quality/draft.inst.cfg b/resources/quality/draft.inst.cfg index 2b375878b6..211525e7d6 100644 --- a/resources/quality/draft.inst.cfg +++ b/resources/quality/draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Draft Quality definition = fdmprinter diff --git a/resources/quality/extra_coarse.inst.cfg b/resources/quality/extra_coarse.inst.cfg index bc8257a97f..e25b813f2f 100644 --- a/resources/quality/extra_coarse.inst.cfg +++ b/resources/quality/extra_coarse.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Coarse Quality definition = fdmprinter diff --git a/resources/quality/fabtotum/fabtotum_abs_fast.inst.cfg b/resources/quality/fabtotum/fabtotum_abs_fast.inst.cfg index 54ad42537e..78a4eb6f9f 100644 --- a/resources/quality/fabtotum/fabtotum_abs_fast.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_abs_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 definition = fabtotum name = Fast Quality diff --git a/resources/quality/fabtotum/fabtotum_abs_high.inst.cfg b/resources/quality/fabtotum/fabtotum_abs_high.inst.cfg index a7a4e71709..786ae18fa5 100644 --- a/resources/quality/fabtotum/fabtotum_abs_high.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_abs_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 definition = fabtotum name = High Quality diff --git a/resources/quality/fabtotum/fabtotum_abs_normal.inst.cfg b/resources/quality/fabtotum/fabtotum_abs_normal.inst.cfg index 19d6062dfa..da75417c87 100644 --- a/resources/quality/fabtotum/fabtotum_abs_normal.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_abs_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 definition = fabtotum name = Normal Quality diff --git a/resources/quality/fabtotum/fabtotum_nylon_fast.inst.cfg b/resources/quality/fabtotum/fabtotum_nylon_fast.inst.cfg index 1983191e90..db86543322 100644 --- a/resources/quality/fabtotum/fabtotum_nylon_fast.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_nylon_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast Quality definition = fabtotum diff --git a/resources/quality/fabtotum/fabtotum_nylon_high.inst.cfg b/resources/quality/fabtotum/fabtotum_nylon_high.inst.cfg index 5f81c12f22..010298c472 100644 --- a/resources/quality/fabtotum/fabtotum_nylon_high.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_nylon_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High Quality definition = fabtotum diff --git a/resources/quality/fabtotum/fabtotum_nylon_normal.inst.cfg b/resources/quality/fabtotum/fabtotum_nylon_normal.inst.cfg index 834d9b8006..b9a80d82b3 100644 --- a/resources/quality/fabtotum/fabtotum_nylon_normal.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_nylon_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal Quality definition = fabtotum diff --git a/resources/quality/fabtotum/fabtotum_pla_fast.inst.cfg b/resources/quality/fabtotum/fabtotum_pla_fast.inst.cfg index 2f123bc05b..bea0ea4aff 100644 --- a/resources/quality/fabtotum/fabtotum_pla_fast.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_pla_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 definition = fabtotum name = Fast Quality diff --git a/resources/quality/fabtotum/fabtotum_pla_high.inst.cfg b/resources/quality/fabtotum/fabtotum_pla_high.inst.cfg index 4b3aff15d9..b77a0d8300 100644 --- a/resources/quality/fabtotum/fabtotum_pla_high.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_pla_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 definition = fabtotum name = High Quality diff --git a/resources/quality/fabtotum/fabtotum_pla_normal.inst.cfg b/resources/quality/fabtotum/fabtotum_pla_normal.inst.cfg index 44ddbcb085..11e5890cc5 100644 --- a/resources/quality/fabtotum/fabtotum_pla_normal.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_pla_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 definition = fabtotum name = Normal Quality diff --git a/resources/quality/fabtotum/fabtotum_tpu_fast.inst.cfg b/resources/quality/fabtotum/fabtotum_tpu_fast.inst.cfg index d8ee095d61..d689f704aa 100644 --- a/resources/quality/fabtotum/fabtotum_tpu_fast.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_tpu_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 definition = fabtotum name = Fast Quality diff --git a/resources/quality/fabtotum/fabtotum_tpu_high.inst.cfg b/resources/quality/fabtotum/fabtotum_tpu_high.inst.cfg index 315a56015d..6193b3b573 100644 --- a/resources/quality/fabtotum/fabtotum_tpu_high.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_tpu_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 definition = fabtotum name = High Quality diff --git a/resources/quality/fabtotum/fabtotum_tpu_normal.inst.cfg b/resources/quality/fabtotum/fabtotum_tpu_normal.inst.cfg index 3ce1592e70..7ccbe296e3 100644 --- a/resources/quality/fabtotum/fabtotum_tpu_normal.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_tpu_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 definition = fabtotum name = Normal Quality diff --git a/resources/quality/fast.inst.cfg b/resources/quality/fast.inst.cfg index 4b78cfcd75..56bc6be48d 100644 --- a/resources/quality/fast.inst.cfg +++ b/resources/quality/fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Low Quality definition = fdmprinter diff --git a/resources/quality/gmax15plus/gmax15plus_pla_dual_normal.inst.cfg b/resources/quality/gmax15plus/gmax15plus_pla_dual_normal.inst.cfg index e08a6ff421..ae31f92447 100644 --- a/resources/quality/gmax15plus/gmax15plus_pla_dual_normal.inst.cfg +++ b/resources/quality/gmax15plus/gmax15plus_pla_dual_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = gMax 1.5+ Dual Normal Layers definition = gmax15plus_dual diff --git a/resources/quality/gmax15plus/gmax15plus_pla_dual_thick.inst.cfg b/resources/quality/gmax15plus/gmax15plus_pla_dual_thick.inst.cfg index 86bfe2af6c..4e262d8ecf 100644 --- a/resources/quality/gmax15plus/gmax15plus_pla_dual_thick.inst.cfg +++ b/resources/quality/gmax15plus/gmax15plus_pla_dual_thick.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = gMax 1.5+ Dual Thick Layers definition = gmax15plus_dual diff --git a/resources/quality/gmax15plus/gmax15plus_pla_dual_thin.inst.cfg b/resources/quality/gmax15plus/gmax15plus_pla_dual_thin.inst.cfg index 0d19c6c9f0..a1b43d5d08 100644 --- a/resources/quality/gmax15plus/gmax15plus_pla_dual_thin.inst.cfg +++ b/resources/quality/gmax15plus/gmax15plus_pla_dual_thin.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = gMax 1.5+ Dual Thin Layers definition = gmax15plus_dual diff --git a/resources/quality/gmax15plus/gmax15plus_pla_dual_very_thick.inst.cfg b/resources/quality/gmax15plus/gmax15plus_pla_dual_very_thick.inst.cfg index 2b58120762..1d5c7eca91 100644 --- a/resources/quality/gmax15plus/gmax15plus_pla_dual_very_thick.inst.cfg +++ b/resources/quality/gmax15plus/gmax15plus_pla_dual_very_thick.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = gMax 1.5+ Dual Very Thick Layers definition = gmax15plus_dual diff --git a/resources/quality/gmax15plus/gmax15plus_pla_normal.inst.cfg b/resources/quality/gmax15plus/gmax15plus_pla_normal.inst.cfg index 70920b6f6a..1d01b82d3c 100644 --- a/resources/quality/gmax15plus/gmax15plus_pla_normal.inst.cfg +++ b/resources/quality/gmax15plus/gmax15plus_pla_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = gMax 1.5+ Normal Layers definition = gmax15plus diff --git a/resources/quality/gmax15plus/gmax15plus_pla_thick.inst.cfg b/resources/quality/gmax15plus/gmax15plus_pla_thick.inst.cfg index 0f1e8a3802..dd6b3e702b 100644 --- a/resources/quality/gmax15plus/gmax15plus_pla_thick.inst.cfg +++ b/resources/quality/gmax15plus/gmax15plus_pla_thick.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = gMax 1.5+ Thick Layers definition = gmax15plus diff --git a/resources/quality/gmax15plus/gmax15plus_pla_thin.inst.cfg b/resources/quality/gmax15plus/gmax15plus_pla_thin.inst.cfg index f548affc2c..f90cb27647 100644 --- a/resources/quality/gmax15plus/gmax15plus_pla_thin.inst.cfg +++ b/resources/quality/gmax15plus/gmax15plus_pla_thin.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = gMax 1.5+ Thin Layers definition = gmax15plus diff --git a/resources/quality/gmax15plus/gmax15plus_pla_very_thick.inst.cfg b/resources/quality/gmax15plus/gmax15plus_pla_very_thick.inst.cfg index 5db77a70ea..171cf2f28d 100644 --- a/resources/quality/gmax15plus/gmax15plus_pla_very_thick.inst.cfg +++ b/resources/quality/gmax15plus/gmax15plus_pla_very_thick.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = gMax 1.5+ Very Thick Layers definition = gmax15plus diff --git a/resources/quality/high.inst.cfg b/resources/quality/high.inst.cfg index 9ef90181a3..bb9e77ad38 100644 --- a/resources/quality/high.inst.cfg +++ b/resources/quality/high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = fdmprinter diff --git a/resources/quality/imade3d_jellybox/generic_petg_0.4_coarse.inst.cfg b/resources/quality/imade3d_jellybox/generic_petg_0.4_coarse.inst.cfg index 4d0493ae8b..020e9d9b0f 100644 --- a/resources/quality/imade3d_jellybox/generic_petg_0.4_coarse.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_petg_0.4_coarse.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Coarse definition = imade3d_jellybox diff --git a/resources/quality/imade3d_jellybox/generic_petg_0.4_coarse_2-fans.inst.cfg b/resources/quality/imade3d_jellybox/generic_petg_0.4_coarse_2-fans.inst.cfg index 9251ae43b4..3aba34126e 100644 --- a/resources/quality/imade3d_jellybox/generic_petg_0.4_coarse_2-fans.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_petg_0.4_coarse_2-fans.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Coarse definition = imade3d_jellybox diff --git a/resources/quality/imade3d_jellybox/generic_petg_0.4_medium.inst.cfg b/resources/quality/imade3d_jellybox/generic_petg_0.4_medium.inst.cfg index a10a3bcf0a..b235662e9f 100644 --- a/resources/quality/imade3d_jellybox/generic_petg_0.4_medium.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_petg_0.4_medium.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Medium definition = imade3d_jellybox diff --git a/resources/quality/imade3d_jellybox/generic_petg_0.4_medium_2-fans.inst.cfg b/resources/quality/imade3d_jellybox/generic_petg_0.4_medium_2-fans.inst.cfg index b851c2e17c..d5a9b09ed7 100644 --- a/resources/quality/imade3d_jellybox/generic_petg_0.4_medium_2-fans.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_petg_0.4_medium_2-fans.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Medium definition = imade3d_jellybox diff --git a/resources/quality/imade3d_jellybox/generic_pla_0.4_coarse.inst.cfg b/resources/quality/imade3d_jellybox/generic_pla_0.4_coarse.inst.cfg index bc86119eb8..797f77fa72 100644 --- a/resources/quality/imade3d_jellybox/generic_pla_0.4_coarse.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_pla_0.4_coarse.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Coarse definition = imade3d_jellybox diff --git a/resources/quality/imade3d_jellybox/generic_pla_0.4_coarse_2-fans.inst.cfg b/resources/quality/imade3d_jellybox/generic_pla_0.4_coarse_2-fans.inst.cfg index c05927fad5..61bb573a25 100644 --- a/resources/quality/imade3d_jellybox/generic_pla_0.4_coarse_2-fans.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_pla_0.4_coarse_2-fans.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Coarse definition = imade3d_jellybox diff --git a/resources/quality/imade3d_jellybox/generic_pla_0.4_fine.inst.cfg b/resources/quality/imade3d_jellybox/generic_pla_0.4_fine.inst.cfg index 1bec96f05c..3c37910112 100644 --- a/resources/quality/imade3d_jellybox/generic_pla_0.4_fine.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_pla_0.4_fine.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = imade3d_jellybox diff --git a/resources/quality/imade3d_jellybox/generic_pla_0.4_fine_2-fans.inst.cfg b/resources/quality/imade3d_jellybox/generic_pla_0.4_fine_2-fans.inst.cfg index 609662a149..eb31b07794 100644 --- a/resources/quality/imade3d_jellybox/generic_pla_0.4_fine_2-fans.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_pla_0.4_fine_2-fans.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = imade3d_jellybox diff --git a/resources/quality/imade3d_jellybox/generic_pla_0.4_medium.inst.cfg b/resources/quality/imade3d_jellybox/generic_pla_0.4_medium.inst.cfg index 5249f2dc2b..b8bbd674e0 100644 --- a/resources/quality/imade3d_jellybox/generic_pla_0.4_medium.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_pla_0.4_medium.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Medium definition = imade3d_jellybox diff --git a/resources/quality/imade3d_jellybox/generic_pla_0.4_medium_2-fans.inst.cfg b/resources/quality/imade3d_jellybox/generic_pla_0.4_medium_2-fans.inst.cfg index 1534d3a6fb..56ae48379f 100644 --- a/resources/quality/imade3d_jellybox/generic_pla_0.4_medium_2-fans.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_pla_0.4_medium_2-fans.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Medium definition = imade3d_jellybox diff --git a/resources/quality/imade3d_jellybox/generic_pla_0.4_ultrafine.inst.cfg b/resources/quality/imade3d_jellybox/generic_pla_0.4_ultrafine.inst.cfg index 1166bd70c9..16fb70252b 100644 --- a/resources/quality/imade3d_jellybox/generic_pla_0.4_ultrafine.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_pla_0.4_ultrafine.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = UltraFine definition = imade3d_jellybox diff --git a/resources/quality/imade3d_jellybox/generic_pla_0.4_ultrafine_2-fans.inst.cfg b/resources/quality/imade3d_jellybox/generic_pla_0.4_ultrafine_2-fans.inst.cfg index 5b05c10604..2cab1fad46 100644 --- a/resources/quality/imade3d_jellybox/generic_pla_0.4_ultrafine_2-fans.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_pla_0.4_ultrafine_2-fans.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = UltraFine definition = imade3d_jellybox diff --git a/resources/quality/imade3d_jellybox/imade3d_jellybox_coarse.inst.cfg b/resources/quality/imade3d_jellybox/imade3d_jellybox_coarse.inst.cfg index 2e940ea646..7a778a788f 100644 --- a/resources/quality/imade3d_jellybox/imade3d_jellybox_coarse.inst.cfg +++ b/resources/quality/imade3d_jellybox/imade3d_jellybox_coarse.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Coarse definition = imade3d_jellybox diff --git a/resources/quality/imade3d_jellybox/imade3d_jellybox_fine.inst.cfg b/resources/quality/imade3d_jellybox/imade3d_jellybox_fine.inst.cfg index 9979558963..51767e0c93 100644 --- a/resources/quality/imade3d_jellybox/imade3d_jellybox_fine.inst.cfg +++ b/resources/quality/imade3d_jellybox/imade3d_jellybox_fine.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = imade3d_jellybox diff --git a/resources/quality/imade3d_jellybox/imade3d_jellybox_normal.inst.cfg b/resources/quality/imade3d_jellybox/imade3d_jellybox_normal.inst.cfg index 0574099b63..407ae608a4 100644 --- a/resources/quality/imade3d_jellybox/imade3d_jellybox_normal.inst.cfg +++ b/resources/quality/imade3d_jellybox/imade3d_jellybox_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Medium definition = imade3d_jellybox diff --git a/resources/quality/imade3d_jellybox/imade3d_jellybox_ultrafine.inst.cfg b/resources/quality/imade3d_jellybox/imade3d_jellybox_ultrafine.inst.cfg index 39344ce7f4..f531d84234 100644 --- a/resources/quality/imade3d_jellybox/imade3d_jellybox_ultrafine.inst.cfg +++ b/resources/quality/imade3d_jellybox/imade3d_jellybox_ultrafine.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = UltraFine definition = imade3d_jellybox diff --git a/resources/quality/kemiq_q2/kemiq_q2_beta_abs_draft.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_beta_abs_draft.inst.cfg index add07c797a..69c2b328cf 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_beta_abs_draft.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_beta_abs_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Draft definition = kemiq_q2_beta diff --git a/resources/quality/kemiq_q2/kemiq_q2_beta_abs_extra_fine.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_beta_abs_extra_fine.inst.cfg index 8d31e439e1..0bb72ce073 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_beta_abs_extra_fine.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_beta_abs_extra_fine.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = kemiq_q2_beta diff --git a/resources/quality/kemiq_q2/kemiq_q2_beta_abs_fine.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_beta_abs_fine.inst.cfg index 936e9f8cd8..1fd5874b70 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_beta_abs_fine.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_beta_abs_fine.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = kemiq_q2_beta diff --git a/resources/quality/kemiq_q2/kemiq_q2_beta_abs_low.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_beta_abs_low.inst.cfg index 8f48616dbf..78f80c576d 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_beta_abs_low.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_beta_abs_low.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Low definition = kemiq_q2_beta diff --git a/resources/quality/kemiq_q2/kemiq_q2_beta_abs_normal.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_beta_abs_normal.inst.cfg index 947fd0774d..626de7bde6 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_beta_abs_normal.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_beta_abs_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = kemiq_q2_beta diff --git a/resources/quality/kemiq_q2/kemiq_q2_beta_pla_draft.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_beta_pla_draft.inst.cfg index d9ea0e6850..63a49e6bc1 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_beta_pla_draft.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_beta_pla_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Draft definition = kemiq_q2_beta diff --git a/resources/quality/kemiq_q2/kemiq_q2_beta_pla_extra_fine.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_beta_pla_extra_fine.inst.cfg index b1775b994f..2d49b01b92 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_beta_pla_extra_fine.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_beta_pla_extra_fine.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = kemiq_q2_beta diff --git a/resources/quality/kemiq_q2/kemiq_q2_beta_pla_fine.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_beta_pla_fine.inst.cfg index cf7e070cb8..e79a3188d7 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_beta_pla_fine.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_beta_pla_fine.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = kemiq_q2_beta diff --git a/resources/quality/kemiq_q2/kemiq_q2_beta_pla_low.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_beta_pla_low.inst.cfg index 8b40fabb7b..db391b95ca 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_beta_pla_low.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_beta_pla_low.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Low definition = kemiq_q2_beta diff --git a/resources/quality/kemiq_q2/kemiq_q2_beta_pla_normal.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_beta_pla_normal.inst.cfg index cc7d877c70..336b1f47b9 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_beta_pla_normal.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_beta_pla_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = kemiq_q2_beta diff --git a/resources/quality/kemiq_q2/kemiq_q2_gama_pla_draft.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_gama_pla_draft.inst.cfg index fcda1b081e..6044fa25a4 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_gama_pla_draft.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_gama_pla_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Draft definition = kemiq_q2_gama diff --git a/resources/quality/kemiq_q2/kemiq_q2_gama_pla_extra_fine.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_gama_pla_extra_fine.inst.cfg index 52e5e8df98..9962c554ca 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_gama_pla_extra_fine.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_gama_pla_extra_fine.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = kemiq_q2_gama diff --git a/resources/quality/kemiq_q2/kemiq_q2_gama_pla_fine.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_gama_pla_fine.inst.cfg index b3ea5b8967..4b5b3b62ed 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_gama_pla_fine.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_gama_pla_fine.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = kemiq_q2_gama diff --git a/resources/quality/kemiq_q2/kemiq_q2_gama_pla_low.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_gama_pla_low.inst.cfg index 08a3db0b1f..a187507632 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_gama_pla_low.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_gama_pla_low.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Low definition = kemiq_q2_gama diff --git a/resources/quality/kemiq_q2/kemiq_q2_gama_pla_normal.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_gama_pla_normal.inst.cfg index a71c3c731b..281f73393a 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_gama_pla_normal.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_gama_pla_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = kemiq_q2_gama diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_draft.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_draft.inst.cfg index c02e789dfe..104b747aea 100644 --- a/resources/quality/malyan_m200/abs/malyan_m200_abs_draft.inst.cfg +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = malyan_m200 diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_fast.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_fast.inst.cfg index 7f4f368e06..3f2eec9867 100644 --- a/resources/quality/malyan_m200/abs/malyan_m200_abs_fast.inst.cfg +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = malyan_m200 diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_high.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_high.inst.cfg index 37335b61ee..55a6c0d4ba 100644 --- a/resources/quality/malyan_m200/abs/malyan_m200_abs_high.inst.cfg +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Finer definition = malyan_m200 diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_normal.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_normal.inst.cfg index 138c31ab14..98587bdf7d 100644 --- a/resources/quality/malyan_m200/abs/malyan_m200_abs_normal.inst.cfg +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = malyan_m200 diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_superdraft.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_superdraft.inst.cfg index 2d748bd698..49fcd1e935 100644 --- a/resources/quality/malyan_m200/abs/malyan_m200_abs_superdraft.inst.cfg +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_superdraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Lowest Quality Draft definition = malyan_m200 diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_thickerdraft.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_thickerdraft.inst.cfg index ebf7798733..f9a9fe3d98 100644 --- a/resources/quality/malyan_m200/abs/malyan_m200_abs_thickerdraft.inst.cfg +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_thickerdraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Draft definition = malyan_m200 diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_ultra.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_ultra.inst.cfg index 5be92914be..dcc2813031 100644 --- a/resources/quality/malyan_m200/abs/malyan_m200_abs_ultra.inst.cfg +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_ultra.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Ultra Fine definition = malyan_m200 diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_verydraft.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_verydraft.inst.cfg index bfe92a98e1..251d024a85 100644 --- a/resources/quality/malyan_m200/abs/malyan_m200_abs_verydraft.inst.cfg +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_verydraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Low Detail Draft definition = malyan_m200 diff --git a/resources/quality/malyan_m200/malyan_m200_0.04375.inst.cfg b/resources/quality/malyan_m200/malyan_m200_0.04375.inst.cfg index 89d7f2f2ec..c9dd72f5f5 100644 --- a/resources/quality/malyan_m200/malyan_m200_0.04375.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_0.04375.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = M1 Quality definition = malyan_m200 diff --git a/resources/quality/malyan_m200/malyan_m200_0.0875.inst.cfg b/resources/quality/malyan_m200/malyan_m200_0.0875.inst.cfg index 555b280c1c..65d7d0d0b8 100644 --- a/resources/quality/malyan_m200/malyan_m200_0.0875.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_0.0875.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = M2 Quality definition = malyan_m200 diff --git a/resources/quality/malyan_m200/malyan_m200_0.13125.inst.cfg b/resources/quality/malyan_m200/malyan_m200_0.13125.inst.cfg index 7829f33086..89aea54fdc 100644 --- a/resources/quality/malyan_m200/malyan_m200_0.13125.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_0.13125.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = M3 Quality definition = malyan_m200 diff --git a/resources/quality/malyan_m200/malyan_m200_0.175.inst.cfg b/resources/quality/malyan_m200/malyan_m200_0.175.inst.cfg index e6fd4c9368..613988a437 100644 --- a/resources/quality/malyan_m200/malyan_m200_0.175.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_0.175.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = M4 Quality definition = malyan_m200 diff --git a/resources/quality/malyan_m200/malyan_m200_0.21875.inst.cfg b/resources/quality/malyan_m200/malyan_m200_0.21875.inst.cfg index 143693dbc4..75d7601af3 100644 --- a/resources/quality/malyan_m200/malyan_m200_0.21875.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_0.21875.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = M5 Quality definition = malyan_m200 diff --git a/resources/quality/malyan_m200/malyan_m200_0.2625.inst.cfg b/resources/quality/malyan_m200/malyan_m200_0.2625.inst.cfg index 3dc33a81a0..470af78595 100644 --- a/resources/quality/malyan_m200/malyan_m200_0.2625.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_0.2625.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = M6 Quality definition = malyan_m200 diff --git a/resources/quality/malyan_m200/malyan_m200_0.30625.inst.cfg b/resources/quality/malyan_m200/malyan_m200_0.30625.inst.cfg index c7d6911a67..32fa8c5641 100644 --- a/resources/quality/malyan_m200/malyan_m200_0.30625.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_0.30625.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = M7 Quality definition = malyan_m200 diff --git a/resources/quality/malyan_m200/malyan_m200_0.35.inst.cfg b/resources/quality/malyan_m200/malyan_m200_0.35.inst.cfg index 5d14204a1e..1e168e7690 100644 --- a/resources/quality/malyan_m200/malyan_m200_0.35.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_0.35.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = M8 Quality definition = malyan_m200 diff --git a/resources/quality/malyan_m200/malyan_m200_global_Draft_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_Draft_Quality.inst.cfg index fd999cc6c7..12796a140f 100644 --- a/resources/quality/malyan_m200/malyan_m200_global_Draft_Quality.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_global_Draft_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = malyan_m200 diff --git a/resources/quality/malyan_m200/malyan_m200_global_Fast_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_Fast_Quality.inst.cfg index 8027a7b01a..78f014bd9e 100644 --- a/resources/quality/malyan_m200/malyan_m200_global_Fast_Quality.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_global_Fast_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = malyan_m200 diff --git a/resources/quality/malyan_m200/malyan_m200_global_High_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_High_Quality.inst.cfg index 01fea67382..bf2f25b418 100644 --- a/resources/quality/malyan_m200/malyan_m200_global_High_Quality.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_global_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Finer definition = malyan_m200 diff --git a/resources/quality/malyan_m200/malyan_m200_global_Normal_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_Normal_Quality.inst.cfg index a705d187f1..cd9609cc2d 100644 --- a/resources/quality/malyan_m200/malyan_m200_global_Normal_Quality.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_global_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = malyan_m200 diff --git a/resources/quality/malyan_m200/malyan_m200_global_SuperDraft_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_SuperDraft_Quality.inst.cfg index 92f1eb2286..880eb5068d 100644 --- a/resources/quality/malyan_m200/malyan_m200_global_SuperDraft_Quality.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_global_SuperDraft_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Lowest Quality Draft definition = malyan_m200 diff --git a/resources/quality/malyan_m200/malyan_m200_global_ThickerDraft_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_ThickerDraft_Quality.inst.cfg index 246443503e..9ebc812738 100644 --- a/resources/quality/malyan_m200/malyan_m200_global_ThickerDraft_Quality.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_global_ThickerDraft_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Draft definition = malyan_m200 diff --git a/resources/quality/malyan_m200/malyan_m200_global_Ultra_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_Ultra_Quality.inst.cfg index 0bbe46be4e..f1841970af 100644 --- a/resources/quality/malyan_m200/malyan_m200_global_Ultra_Quality.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_global_Ultra_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Ultra Fine definition = malyan_m200 diff --git a/resources/quality/malyan_m200/malyan_m200_global_VeryDraft_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_VeryDraft_Quality.inst.cfg index 5cc85b9bc8..7da342c437 100644 --- a/resources/quality/malyan_m200/malyan_m200_global_VeryDraft_Quality.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_global_VeryDraft_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Low Detail Draft definition = malyan_m200 diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_draft.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_draft.inst.cfg index 038af5eec0..0434decedc 100644 --- a/resources/quality/malyan_m200/petg/malyan_m200_petg_draft.inst.cfg +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = malyan_m200 diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_fast.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_fast.inst.cfg index df341d195c..2049403af4 100644 --- a/resources/quality/malyan_m200/petg/malyan_m200_petg_fast.inst.cfg +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = malyan_m200 diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_high.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_high.inst.cfg index ff9dbc8227..00882f2418 100644 --- a/resources/quality/malyan_m200/petg/malyan_m200_petg_high.inst.cfg +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Finer definition = malyan_m200 diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_normal.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_normal.inst.cfg index 8531bbf98b..58ad4a1085 100644 --- a/resources/quality/malyan_m200/petg/malyan_m200_petg_normal.inst.cfg +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = malyan_m200 diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_superdraft.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_superdraft.inst.cfg index 8b065ecea8..09a72e261a 100644 --- a/resources/quality/malyan_m200/petg/malyan_m200_petg_superdraft.inst.cfg +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_superdraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Lowest Quality Draft definition = malyan_m200 diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_thickerdraft.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_thickerdraft.inst.cfg index 97672ee1c7..e57b1d24f2 100644 --- a/resources/quality/malyan_m200/petg/malyan_m200_petg_thickerdraft.inst.cfg +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_thickerdraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Draft definition = malyan_m200 diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_ultra.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_ultra.inst.cfg index 7b92f9d454..0c3de72835 100644 --- a/resources/quality/malyan_m200/petg/malyan_m200_petg_ultra.inst.cfg +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_ultra.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Ultra Fine definition = malyan_m200 diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_verydraft.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_verydraft.inst.cfg index 1a1b59d90f..0139e972f6 100644 --- a/resources/quality/malyan_m200/petg/malyan_m200_petg_verydraft.inst.cfg +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_verydraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Low Detail Draft definition = malyan_m200 diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_draft.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_draft.inst.cfg index f3ef39f009..c30df8a9b3 100644 --- a/resources/quality/malyan_m200/pla/malyan_m200_pla_draft.inst.cfg +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = malyan_m200 diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_fast.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_fast.inst.cfg index 0e047b140e..8e1b0478ad 100644 --- a/resources/quality/malyan_m200/pla/malyan_m200_pla_fast.inst.cfg +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = malyan_m200 diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_high.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_high.inst.cfg index e68ad90c6c..44713b2386 100644 --- a/resources/quality/malyan_m200/pla/malyan_m200_pla_high.inst.cfg +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Finer definition = malyan_m200 diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_normal.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_normal.inst.cfg index 78bdc826ba..cd6497d9bf 100644 --- a/resources/quality/malyan_m200/pla/malyan_m200_pla_normal.inst.cfg +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = malyan_m200 diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_superdraft.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_superdraft.inst.cfg index cc24c4a0b2..447de8a48b 100644 --- a/resources/quality/malyan_m200/pla/malyan_m200_pla_superdraft.inst.cfg +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_superdraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Lowest Quality Draft definition = malyan_m200 diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_thickerdraft.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_thickerdraft.inst.cfg index 5bfb82ee90..f2c5e3c9cc 100644 --- a/resources/quality/malyan_m200/pla/malyan_m200_pla_thickerdraft.inst.cfg +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_thickerdraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Draft definition = malyan_m200 diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_ultra.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_ultra.inst.cfg index d042fc7978..63f19bef41 100644 --- a/resources/quality/malyan_m200/pla/malyan_m200_pla_ultra.inst.cfg +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_ultra.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Ultra Fine definition = malyan_m200 diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_verydraft.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_verydraft.inst.cfg index 8e79071db4..6a96b3d678 100644 --- a/resources/quality/malyan_m200/pla/malyan_m200_pla_verydraft.inst.cfg +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_verydraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Low Detail Draft definition = malyan_m200 diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_draft.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_draft.inst.cfg index 3387b51d7d..6fec85b563 100644 --- a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_draft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_fast.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_fast.inst.cfg index da187c85ea..0d79f2cc72 100644 --- a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_fast.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_high.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_high.inst.cfg index a2efa54353..f02e3b5838 100644 --- a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_high.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Finer definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_normal.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_normal.inst.cfg index a331a63aaf..a046cfa561 100644 --- a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_normal.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_superdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_superdraft.inst.cfg index d328e353ac..f5861ce734 100644 --- a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_superdraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_superdraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Lowest Quality Draft definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_thickerdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_thickerdraft.inst.cfg index 8e64dae5aa..b63fd3cfad 100644 --- a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_thickerdraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_thickerdraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Draft definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_ultra.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_ultra.inst.cfg index 5757e57a3b..6aed450961 100644 --- a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_ultra.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_ultra.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Ultra Fine definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_verydraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_verydraft.inst.cfg index 77810c8809..1c462fd435 100644 --- a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_verydraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_verydraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Low Detail Draft definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Draft_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Draft_Quality.inst.cfg index d8aa07b779..c70ccc9946 100644 --- a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Draft_Quality.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Draft_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Fast_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Fast_Quality.inst.cfg index a0620d532a..1bc10e2186 100644 --- a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Fast_Quality.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Fast_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_High_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_High_Quality.inst.cfg index 7237dbc42a..24d5d5819f 100644 --- a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_High_Quality.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Finer definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Normal_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Normal_Quality.inst.cfg index bcb360d310..0a884c80ca 100644 --- a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Normal_Quality.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_SuperDraft_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_SuperDraft_Quality.inst.cfg index 81954f86e7..9a0928186c 100644 --- a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_SuperDraft_Quality.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_SuperDraft_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Lowest Quality Draft definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_ThickerDraft_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_ThickerDraft_Quality.inst.cfg index 1fe7ee22ab..994ec14a3e 100644 --- a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_ThickerDraft_Quality.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_ThickerDraft_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Draft definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Ultra_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Ultra_Quality.inst.cfg index 89e2f43dad..813d156588 100644 --- a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Ultra_Quality.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Ultra_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Ultra Fine definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_VeryDraft_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_VeryDraft_Quality.inst.cfg index c7fc09d9e8..0a461945f5 100644 --- a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_VeryDraft_Quality.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_VeryDraft_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Low Detail Draft definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_draft.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_draft.inst.cfg index 80905c64f7..d5ccd3070b 100644 --- a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_draft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_fast.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_fast.inst.cfg index eab42b728e..aca8884024 100644 --- a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_fast.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_high.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_high.inst.cfg index 1261eff697..080a06d84f 100644 --- a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_high.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Finer definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_normal.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_normal.inst.cfg index 6cf8709bf6..7f3222d229 100644 --- a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_normal.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_superdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_superdraft.inst.cfg index 3cf4efb73b..88777be100 100644 --- a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_superdraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_superdraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Lowest Quality Draft definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_thickerdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_thickerdraft.inst.cfg index 22f27ab084..8880d6defa 100644 --- a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_thickerdraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_thickerdraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Draft definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_ultra.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_ultra.inst.cfg index b3b80d651f..945964cfac 100644 --- a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_ultra.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_ultra.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Ultra Fine definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_verydraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_verydraft.inst.cfg index efd93a5381..fbebffde3a 100644 --- a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_verydraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_verydraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Low Detail Draft definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_draft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_draft.inst.cfg index 05283042c2..be4f438df5 100644 --- a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_draft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_fast.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_fast.inst.cfg index 07319fe4db..c81f19a03e 100644 --- a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_fast.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_high.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_high.inst.cfg index 668040c851..714cd66c1f 100644 --- a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_high.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Finer definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_normal.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_normal.inst.cfg index e9d907fabd..a314288364 100644 --- a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_normal.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_superdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_superdraft.inst.cfg index 5d1af5a430..4889d3fc7d 100644 --- a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_superdraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_superdraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Lowest Quality Draft definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_thickerdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_thickerdraft.inst.cfg index 06c4b4f405..12a5c2ac6f 100644 --- a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_thickerdraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_thickerdraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Draft definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_ultra.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_ultra.inst.cfg index 821658554d..3b70904476 100644 --- a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_ultra.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_ultra.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Ultra Fine definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_verydraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_verydraft.inst.cfg index 93dc04e13c..2ea13105ef 100644 --- a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_verydraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_verydraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Low Detail Draft definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_draft.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_draft.inst.cfg index 917e8b98a3..da8f6a7c9a 100644 --- a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_draft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_fast.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_fast.inst.cfg index aa98ea4de0..bc151b9635 100644 --- a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_fast.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_high.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_high.inst.cfg index 3db3af0db2..bc1101603e 100644 --- a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_high.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Finer definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_normal.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_normal.inst.cfg index e39fd54550..932bfdf97a 100644 --- a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_normal.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_superdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_superdraft.inst.cfg index 6d9e99d365..77fb261821 100644 --- a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_superdraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_superdraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Lowest Quality Draft definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_thickerdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_thickerdraft.inst.cfg index 5227aac686..096ff5c2f6 100644 --- a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_thickerdraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_thickerdraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Draft definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_ultra.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_ultra.inst.cfg index a58c05b004..9a3cc19a0c 100644 --- a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_ultra.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_ultra.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Ultra Fine definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_verydraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_verydraft.inst.cfg index 0fe38fb5df..c9e0aae2c4 100644 --- a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_verydraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_verydraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Low Detail Draft definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_draft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_draft.inst.cfg index 0b9f10a790..8f85c598bd 100644 --- a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_draft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_fast.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_fast.inst.cfg index d831890413..09e741ad07 100644 --- a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_fast.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_high.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_high.inst.cfg index f5049308f3..cf00fb02b0 100644 --- a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_high.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Finer definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_normal.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_normal.inst.cfg index f63c87a52c..eaa85450d8 100644 --- a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_normal.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_superdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_superdraft.inst.cfg index a8bd9a5179..66f888cd6e 100644 --- a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_superdraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_superdraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Lowest Quality Draft definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_thickerdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_thickerdraft.inst.cfg index df1ae97a16..c4c2a0c2d1 100644 --- a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_thickerdraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_thickerdraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Draft definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_ultra.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_ultra.inst.cfg index 3b3ec79692..b9b0fea26e 100644 --- a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_ultra.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_ultra.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Ultra Fine definition = monoprice_select_mini_v2 diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_verydraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_verydraft.inst.cfg index 5e63de3952..bd6febd83c 100644 --- a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_verydraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_verydraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Low Detail Draft definition = monoprice_select_mini_v2 diff --git a/resources/quality/normal.inst.cfg b/resources/quality/normal.inst.cfg index 2eeb91324f..0f1a4d6905 100644 --- a/resources/quality/normal.inst.cfg +++ b/resources/quality/normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = fdmprinter diff --git a/resources/quality/peopoly_moai/peopoly_moai_high.inst.cfg b/resources/quality/peopoly_moai/peopoly_moai_high.inst.cfg index 208fa453fe..57c955f4b7 100644 --- a/resources/quality/peopoly_moai/peopoly_moai_high.inst.cfg +++ b/resources/quality/peopoly_moai/peopoly_moai_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = peopoly_moai diff --git a/resources/quality/peopoly_moai/peopoly_moai_max.inst.cfg b/resources/quality/peopoly_moai/peopoly_moai_max.inst.cfg index cc764009a9..4cce7e2d85 100644 --- a/resources/quality/peopoly_moai/peopoly_moai_max.inst.cfg +++ b/resources/quality/peopoly_moai/peopoly_moai_max.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Maximum Quality definition = peopoly_moai diff --git a/resources/quality/peopoly_moai/peopoly_moai_normal.inst.cfg b/resources/quality/peopoly_moai/peopoly_moai_normal.inst.cfg index 2baa70be1e..a1465a86c9 100644 --- a/resources/quality/peopoly_moai/peopoly_moai_normal.inst.cfg +++ b/resources/quality/peopoly_moai/peopoly_moai_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = peopoly_moai diff --git a/resources/quality/tevo_blackwidow/tevo_blackwidow_draft.inst.cfg b/resources/quality/tevo_blackwidow/tevo_blackwidow_draft.inst.cfg index 2536cbba12..184205b1cd 100644 --- a/resources/quality/tevo_blackwidow/tevo_blackwidow_draft.inst.cfg +++ b/resources/quality/tevo_blackwidow/tevo_blackwidow_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Draft definition = tevo_blackwidow diff --git a/resources/quality/tevo_blackwidow/tevo_blackwidow_high.inst.cfg b/resources/quality/tevo_blackwidow/tevo_blackwidow_high.inst.cfg index 29599eaebc..d158af4123 100644 --- a/resources/quality/tevo_blackwidow/tevo_blackwidow_high.inst.cfg +++ b/resources/quality/tevo_blackwidow/tevo_blackwidow_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = tevo_blackwidow diff --git a/resources/quality/tevo_blackwidow/tevo_blackwidow_normal.inst.cfg b/resources/quality/tevo_blackwidow/tevo_blackwidow_normal.inst.cfg index 98dbf5a79a..a44ff8bcdb 100644 --- a/resources/quality/tevo_blackwidow/tevo_blackwidow_normal.inst.cfg +++ b/resources/quality/tevo_blackwidow/tevo_blackwidow_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = tevo_blackwidow diff --git a/resources/quality/ultimaker2/um2_draft.inst.cfg b/resources/quality/ultimaker2/um2_draft.inst.cfg index 88d3ed3520..dc761afc0b 100644 --- a/resources/quality/ultimaker2/um2_draft.inst.cfg +++ b/resources/quality/ultimaker2/um2_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Draft Quality definition = ultimaker2 diff --git a/resources/quality/ultimaker2/um2_fast.inst.cfg b/resources/quality/ultimaker2/um2_fast.inst.cfg index 36e4fe03c2..04c24dc4c2 100644 --- a/resources/quality/ultimaker2/um2_fast.inst.cfg +++ b/resources/quality/ultimaker2/um2_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Low Quality definition = ultimaker2 diff --git a/resources/quality/ultimaker2/um2_high.inst.cfg b/resources/quality/ultimaker2/um2_high.inst.cfg index 2fb7ead455..1c83ea350b 100644 --- a/resources/quality/ultimaker2/um2_high.inst.cfg +++ b/resources/quality/ultimaker2/um2_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = ultimaker2 diff --git a/resources/quality/ultimaker2/um2_normal.inst.cfg b/resources/quality/ultimaker2/um2_normal.inst.cfg index 51fe1f317c..bddbe6e243 100644 --- a/resources/quality/ultimaker2/um2_normal.inst.cfg +++ b/resources/quality/ultimaker2/um2_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker2 diff --git a/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg index 07e3dcd7db..eecaa2fa0f 100644 --- a/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg index 2a72e40d80..207d237fa3 100644 --- a/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg index ce41158378..83ffa99d07 100644 --- a/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg index edfe131ddf..683eab7166 100644 --- a/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg index 548c7478ba..80dea5f5fd 100644 --- a/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg index a257d3d6f8..5c898c74ec 100644 --- a/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg index e448b9d180..275a4595a0 100644 --- a/resources/quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg index 3fd2de3a36..a95417c711 100644 --- a/resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg index 2f119ae86b..97d35fe6bf 100644 --- a/resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg index 8416e69dba..162805f5c2 100644 --- a/resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg index 393e630299..5291356b4e 100644 --- a/resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg index d0dcbb0908..01c0b5467b 100644 --- a/resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg index 1047b0ca39..1b656eb4f1 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg index 7beaf2f229..8385800e15 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg index efd73655b1..6d810ee231 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg index 3badb3f191..1b6ab4edc5 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg index 727d68eede..7f79c013b3 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg index 1460d69b7a..df92d3e2dd 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_cpep_0.4_draft.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpep_0.4_draft.inst.cfg index be33739e72..e83ae78d36 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpep_0.4_draft.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpep_0.4_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_cpep_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpep_0.4_normal.inst.cfg index 58cf4bd0e3..ee0b659b91 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpep_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpep_0.4_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_cpep_0.6_draft.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpep_0.6_draft.inst.cfg index fe4f895611..0773a81834 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpep_0.6_draft.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpep_0.6_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_cpep_0.6_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpep_0.6_normal.inst.cfg index bcc507a3d9..4cea2db94e 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpep_0.6_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpep_0.6_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_cpep_0.8_draft.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpep_0.8_draft.inst.cfg index c27d90ead8..27c3052885 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpep_0.8_draft.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpep_0.8_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_cpep_0.8_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpep_0.8_normal.inst.cfg index 7eb8b1fd72..26d44f332b 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpep_0.8_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpep_0.8_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_nylon_0.25_high.inst.cfg b/resources/quality/ultimaker2_plus/um2p_nylon_0.25_high.inst.cfg index 33041f89ae..d2c9c9d8d3 100644 --- a/resources/quality/ultimaker2_plus/um2p_nylon_0.25_high.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_nylon_0.25_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_nylon_0.25_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_nylon_0.25_normal.inst.cfg index 88974491cb..115e4dd0d3 100644 --- a/resources/quality/ultimaker2_plus/um2p_nylon_0.25_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_nylon_0.25_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_nylon_0.4_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_nylon_0.4_fast.inst.cfg index 832fa12bc9..917715ef33 100644 --- a/resources/quality/ultimaker2_plus/um2p_nylon_0.4_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_nylon_0.4_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_nylon_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_nylon_0.4_normal.inst.cfg index c12573691e..125930991a 100644 --- a/resources/quality/ultimaker2_plus/um2p_nylon_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_nylon_0.4_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_nylon_0.6_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_nylon_0.6_fast.inst.cfg index eaa4f86e23..3602182288 100644 --- a/resources/quality/ultimaker2_plus/um2p_nylon_0.6_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_nylon_0.6_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_nylon_0.6_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_nylon_0.6_normal.inst.cfg index 5e3db4db22..c41a8b3612 100644 --- a/resources/quality/ultimaker2_plus/um2p_nylon_0.6_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_nylon_0.6_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_nylon_0.8_draft.inst.cfg b/resources/quality/ultimaker2_plus/um2p_nylon_0.8_draft.inst.cfg index 38a71c9109..6e68d79f34 100644 --- a/resources/quality/ultimaker2_plus/um2p_nylon_0.8_draft.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_nylon_0.8_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_nylon_0.8_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_nylon_0.8_normal.inst.cfg index 9d20a6d91f..e01006cf58 100644 --- a/resources/quality/ultimaker2_plus/um2p_nylon_0.8_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_nylon_0.8_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_pc_0.25_high.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pc_0.25_high.inst.cfg index 7829d7b7b9..91bc5e523a 100644 --- a/resources/quality/ultimaker2_plus/um2p_pc_0.25_high.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pc_0.25_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_pc_0.25_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pc_0.25_normal.inst.cfg index 168a308916..5407edf56d 100644 --- a/resources/quality/ultimaker2_plus/um2p_pc_0.25_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pc_0.25_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_pc_0.4_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pc_0.4_fast.inst.cfg index 46a349d81f..5e0cef44cc 100644 --- a/resources/quality/ultimaker2_plus/um2p_pc_0.4_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pc_0.4_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_pc_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pc_0.4_normal.inst.cfg index 0c2450f512..9e400a46e7 100644 --- a/resources/quality/ultimaker2_plus/um2p_pc_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pc_0.4_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_pc_0.6_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pc_0.6_fast.inst.cfg index 68528a0209..1741eb47e9 100644 --- a/resources/quality/ultimaker2_plus/um2p_pc_0.6_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pc_0.6_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_pc_0.6_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pc_0.6_normal.inst.cfg index a92110a149..17df729157 100644 --- a/resources/quality/ultimaker2_plus/um2p_pc_0.6_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pc_0.6_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_pc_0.8_draft.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pc_0.8_draft.inst.cfg index 8c8bff3846..87bad0bd64 100644 --- a/resources/quality/ultimaker2_plus/um2p_pc_0.8_draft.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pc_0.8_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_pc_0.8_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pc_0.8_normal.inst.cfg index db83d5181f..e1f208b2f1 100644 --- a/resources/quality/ultimaker2_plus/um2p_pc_0.8_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pc_0.8_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_pp_0.4_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pp_0.4_fast.inst.cfg index b7474044f3..cbb4f2f881 100644 --- a/resources/quality/ultimaker2_plus/um2p_pp_0.4_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pp_0.4_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_pp_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pp_0.4_normal.inst.cfg index f6d2c38161..ee38faa33a 100644 --- a/resources/quality/ultimaker2_plus/um2p_pp_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pp_0.4_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_pp_0.6_draft.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pp_0.6_draft.inst.cfg index 99fdf8346c..9fe8c72397 100644 --- a/resources/quality/ultimaker2_plus/um2p_pp_0.6_draft.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pp_0.6_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_pp_0.6_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pp_0.6_fast.inst.cfg index 7a9ec8e4e3..ba9052818c 100644 --- a/resources/quality/ultimaker2_plus/um2p_pp_0.6_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pp_0.6_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_pp_0.8_draft.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pp_0.8_draft.inst.cfg index 071c50c05b..2a6b4d1de8 100644 --- a/resources/quality/ultimaker2_plus/um2p_pp_0.8_draft.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pp_0.8_draft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_pp_0.8_verydraft.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pp_0.8_verydraft.inst.cfg index cbea59a879..92f605f557 100644 --- a/resources/quality/ultimaker2_plus/um2p_pp_0.8_verydraft.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pp_0.8_verydraft.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fast definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_tpu_0.25_high.inst.cfg b/resources/quality/ultimaker2_plus/um2p_tpu_0.25_high.inst.cfg index 2ad062bd31..b6fe1515c0 100644 --- a/resources/quality/ultimaker2_plus/um2p_tpu_0.25_high.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_tpu_0.25_high.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_tpu_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_tpu_0.4_normal.inst.cfg index 56ce55ee96..27e09bdf10 100644 --- a/resources/quality/ultimaker2_plus/um2p_tpu_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_tpu_0.4_normal.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker2_plus diff --git a/resources/quality/ultimaker2_plus/um2p_tpu_0.6_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_tpu_0.6_fast.inst.cfg index 6bcc5fa31f..6d0b1ef8de 100644 --- a/resources/quality/ultimaker2_plus/um2p_tpu_0.6_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_tpu_0.6_fast.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker2_plus diff --git a/resources/quality/ultimaker3/um3_aa0.25_ABS_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.25_ABS_Normal_Quality.inst.cfg index 0b100d8717..c79c831984 100644 --- a/resources/quality/ultimaker3/um3_aa0.25_ABS_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.25_ABS_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.25_CPE_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.25_CPE_Normal_Quality.inst.cfg index 77494d6339..83e77eb117 100644 --- a/resources/quality/ultimaker3/um3_aa0.25_CPE_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.25_CPE_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.25_Nylon_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.25_Nylon_Normal_Quality.inst.cfg index 0187084ff8..c3ead92b51 100644 --- a/resources/quality/ultimaker3/um3_aa0.25_Nylon_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.25_Nylon_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.25_PC_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.25_PC_Normal_Quality.inst.cfg index 0070419a4e..657e194398 100644 --- a/resources/quality/ultimaker3/um3_aa0.25_PC_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.25_PC_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine - Experimental definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.25_PLA_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.25_PLA_Normal_Quality.inst.cfg index b2347f1902..7f6fb9fa4d 100644 --- a/resources/quality/ultimaker3/um3_aa0.25_PLA_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.25_PLA_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.25_PP_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.25_PP_Normal_Quality.inst.cfg index 732289dedf..694f4a56d6 100644 --- a/resources/quality/ultimaker3/um3_aa0.25_PP_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.25_PP_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine - Experimental definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_ABS_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_ABS_Draft_Print.inst.cfg index a5cc4aaa0c..4b05943b64 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_ABS_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_ABS_Draft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_ABS_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_ABS_Fast_Print.inst.cfg index ba80ad588e..3b441942ac 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_ABS_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_ABS_Fast_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_ABS_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_ABS_High_Quality.inst.cfg index c84ef6dabe..79cdb4069d 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_ABS_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_ABS_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_ABS_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_ABS_Normal_Quality.inst.cfg index f3c9f6a892..412bc4c5a8 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_ABS_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_ABS_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_BAM_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_BAM_Draft_Print.inst.cfg index fbc0c599ef..e4ef572efb 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_BAM_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_BAM_Draft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_BAM_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_BAM_Fast_Print.inst.cfg index d6f64cb056..c896c74233 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_BAM_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_BAM_Fast_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_BAM_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_BAM_Normal_Quality.inst.cfg index 53fb52bff6..9fdcfb4cf3 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_BAM_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_BAM_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_CPEP_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_CPEP_Draft_Print.inst.cfg index dd089294de..14263ee800 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_CPEP_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_CPEP_Draft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_CPEP_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_CPEP_Fast_Print.inst.cfg index 373107d767..05d8988c36 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_CPEP_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_CPEP_Fast_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_CPEP_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_CPEP_High_Quality.inst.cfg index 67544db97b..6a6fa94730 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_CPEP_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_CPEP_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_CPEP_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_CPEP_Normal_Quality.inst.cfg index 183d05ce60..402e23436a 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_CPEP_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_CPEP_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_CPE_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_CPE_Draft_Print.inst.cfg index 74395628af..9a85ab9b3e 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_CPE_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_CPE_Draft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_CPE_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_CPE_Fast_Print.inst.cfg index dbcf7f3e42..7099062daf 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_CPE_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_CPE_Fast_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_CPE_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_CPE_High_Quality.inst.cfg index 89b5210631..00adfcc2d7 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_CPE_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_CPE_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_CPE_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_CPE_Normal_Quality.inst.cfg index 12927714ec..590eddf43b 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_CPE_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_CPE_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_Nylon_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_Nylon_Draft_Print.inst.cfg index ff938df8f8..8ade8d4fe4 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_Nylon_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_Nylon_Draft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_Nylon_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_Nylon_Fast_Print.inst.cfg index e9fd6df1e2..2fef1fb2a2 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_Nylon_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_Nylon_Fast_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_Nylon_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_Nylon_High_Quality.inst.cfg index 635cc573ea..9a320ecde3 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_Nylon_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_Nylon_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_Nylon_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_Nylon_Normal_Quality.inst.cfg index 778ace19e4..34efb4df95 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_Nylon_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_Nylon_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg index 437e4676b3..f0a420ff5c 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg index 320cf0a96f..eba8b84a1e 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg index 6d7e8f7976..833c771b6e 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PC_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PC_Normal_Quality.inst.cfg index c18e9dbbd5..a6290a4c65 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PC_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PC_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PLA_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PLA_Draft_Print.inst.cfg index 24b7c51fbc..3805d7a396 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PLA_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PLA_Draft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PLA_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PLA_Fast_Print.inst.cfg index 6b3d8642e0..3a8c6df621 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PLA_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PLA_Fast_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PLA_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PLA_High_Quality.inst.cfg index 6009031e0c..543391fd6b 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PLA_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PLA_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PLA_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PLA_Normal_Quality.inst.cfg index 3722134df6..c3c2a8d624 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PLA_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PLA_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PP_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PP_Draft_Print.inst.cfg index 265e068598..3f288618b7 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PP_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PP_Draft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PP_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PP_Fast_Print.inst.cfg index 7698c0a273..d4f84fc192 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PP_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PP_Fast_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PP_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PP_Normal_Quality.inst.cfg index 897ec993e7..329e84a531 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PP_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PP_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_TPU_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_TPU_Draft_Print.inst.cfg index d3654cb3e0..cace7e902e 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_TPU_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_TPU_Draft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_TPU_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_TPU_Fast_Print.inst.cfg index 3686fefdff..7dae439fab 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_TPU_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_TPU_Fast_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.4_TPU_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_TPU_Normal_Quality.inst.cfg index 18d7a5275a..71796eabc6 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_TPU_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_TPU_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_ABS_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_ABS_Draft_Print.inst.cfg index 78930b84e2..85e1415147 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_ABS_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_ABS_Draft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_ABS_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_ABS_Superdraft_Print.inst.cfg index 9470779bd4..3167473cc6 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_ABS_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_ABS_Superdraft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Sprint definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_ABS_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_ABS_Verydraft_Print.inst.cfg index d28e9b75b6..0414bf724c 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_ABS_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_ABS_Verydraft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_CPEP_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_CPEP_Fast_Print.inst.cfg index 6f84174c5a..c958cdd628 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_CPEP_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_CPEP_Fast_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast - Experimental definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_CPEP_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_CPEP_Superdraft_Print.inst.cfg index 09e59ee8ca..6a726c6079 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_CPEP_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_CPEP_Superdraft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Sprint - Experimental definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_CPEP_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_CPEP_Verydraft_Print.inst.cfg index 7b7d211c21..978f4fd732 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_CPEP_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_CPEP_Verydraft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fast - Experimental definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_CPE_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_CPE_Draft_Print.inst.cfg index ecce20d9a2..fd138ae2f2 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_CPE_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_CPE_Draft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_CPE_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_CPE_Superdraft_Print.inst.cfg index a14d4601ee..feba0b3160 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_CPE_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_CPE_Superdraft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Sprint definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_CPE_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_CPE_Verydraft_Print.inst.cfg index 7a6cbc7251..1d9537097e 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_CPE_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_CPE_Verydraft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_Nylon_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_Nylon_Draft_Print.inst.cfg index 9254894df3..e205720539 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_Nylon_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_Nylon_Draft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_Nylon_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_Nylon_Superdraft_Print.inst.cfg index f6e2787e65..f2853a8781 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_Nylon_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_Nylon_Superdraft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Sprint definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_Nylon_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_Nylon_Verydraft_Print.inst.cfg index 794ccd006d..442323877c 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_Nylon_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_Nylon_Verydraft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_PC_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PC_Fast_Print.inst.cfg index c0ae3852dc..b128fc952a 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PC_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PC_Fast_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast - Experimental definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_PC_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PC_Superdraft_Print.inst.cfg index ca58342847..d208afb2e1 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PC_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PC_Superdraft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Sprint - Experimental definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_PC_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PC_Verydraft_Print.inst.cfg index 6c69aa8ff5..fbbf9876e0 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PC_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PC_Verydraft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fast - Experimental definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_PLA_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PLA_Draft_Print.inst.cfg index c03cc1ad5f..3293fa8382 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PLA_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PLA_Draft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_PLA_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PLA_Superdraft_Print.inst.cfg index b1252a3662..b989d7e11a 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PLA_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PLA_Superdraft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Sprint definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_PLA_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PLA_Verydraft_Print.inst.cfg index 191a7a4b1d..684eb11c5b 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PLA_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PLA_Verydraft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_PP_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PP_Draft_Print.inst.cfg index fb67666dc7..8ed11c1946 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PP_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PP_Draft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_PP_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PP_Superdraft_Print.inst.cfg index 0fe9eb2bf9..01b947995d 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PP_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PP_Superdraft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Sprint definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_PP_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PP_Verydraft_Print.inst.cfg index 5ec1311987..ba1aa89c91 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PP_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PP_Verydraft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_TPU_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_TPU_Draft_Print.inst.cfg index be3ea7e06d..e133d335f8 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_TPU_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_TPU_Draft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_TPU_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_TPU_Superdraft_Print.inst.cfg index cc0e963a35..c835de26f4 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_TPU_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_TPU_Superdraft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Sprint definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_TPU_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_TPU_Verydraft_Print.inst.cfg index 3310c09ba7..2e3ad5cf44 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_TPU_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_TPU_Verydraft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_bb0.4_PVA_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_bb0.4_PVA_Draft_Print.inst.cfg index eacdaccffe..4fff8be5ee 100644 --- a/resources/quality/ultimaker3/um3_bb0.4_PVA_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_bb0.4_PVA_Draft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_bb0.4_PVA_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_bb0.4_PVA_Fast_Print.inst.cfg index c6ddd85181..8abce151bf 100644 --- a/resources/quality/ultimaker3/um3_bb0.4_PVA_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_bb0.4_PVA_Fast_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_bb0.4_PVA_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_bb0.4_PVA_High_Quality.inst.cfg index 0b1d0f9f8d..0caf36e51b 100644 --- a/resources/quality/ultimaker3/um3_bb0.4_PVA_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_bb0.4_PVA_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_bb0.4_PVA_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_bb0.4_PVA_Normal_Quality.inst.cfg index 9980e2b31c..0a8304a743 100644 --- a/resources/quality/ultimaker3/um3_bb0.4_PVA_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_bb0.4_PVA_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_bb0.8_PVA_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_bb0.8_PVA_Draft_Print.inst.cfg index edc960cc8c..d59f283eb6 100644 --- a/resources/quality/ultimaker3/um3_bb0.8_PVA_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_bb0.8_PVA_Draft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_bb0.8_PVA_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_bb0.8_PVA_Superdraft_Print.inst.cfg index 6fb66dab14..4039d39d6a 100644 --- a/resources/quality/ultimaker3/um3_bb0.8_PVA_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_bb0.8_PVA_Superdraft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Sprint definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_bb0.8_PVA_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_bb0.8_PVA_Verydraft_Print.inst.cfg index 12288919fe..247ee3d4da 100644 --- a/resources/quality/ultimaker3/um3_bb0.8_PVA_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_bb0.8_PVA_Verydraft_Print.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_global_Draft_Quality.inst.cfg b/resources/quality/ultimaker3/um3_global_Draft_Quality.inst.cfg index 9f13bbd3c2..49a514bff3 100644 --- a/resources/quality/ultimaker3/um3_global_Draft_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_global_Draft_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fast definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_global_Fast_Quality.inst.cfg b/resources/quality/ultimaker3/um3_global_Fast_Quality.inst.cfg index 073ae82a07..69a94be93a 100644 --- a/resources/quality/ultimaker3/um3_global_Fast_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_global_Fast_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_global_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_global_High_Quality.inst.cfg index 1daff86c49..2aebb18ab5 100644 --- a/resources/quality/ultimaker3/um3_global_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_global_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_global_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_global_Normal_Quality.inst.cfg index 91c5bab8b7..5effc44fc5 100644 --- a/resources/quality/ultimaker3/um3_global_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_global_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Fine definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_global_Superdraft_Quality.inst.cfg b/resources/quality/ultimaker3/um3_global_Superdraft_Quality.inst.cfg index da39b065d5..55f5796240 100644 --- a/resources/quality/ultimaker3/um3_global_Superdraft_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_global_Superdraft_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Sprint definition = ultimaker3 diff --git a/resources/quality/ultimaker3/um3_global_Verydraft_Quality.inst.cfg b/resources/quality/ultimaker3/um3_global_Verydraft_Quality.inst.cfg index 11e8315a7b..5d72a76c7c 100644 --- a/resources/quality/ultimaker3/um3_global_Verydraft_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_global_Verydraft_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extra Fast definition = ultimaker3 diff --git a/resources/quality/vertex_delta_k8800/k8800_ABS_Extreme_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_ABS_Extreme_Quality.inst.cfg index 50a1ef3415..30c2749ac6 100644 --- a/resources/quality/vertex_delta_k8800/k8800_ABS_Extreme_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_ABS_Extreme_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extreme definition = vertex_delta_k8800 diff --git a/resources/quality/vertex_delta_k8800/k8800_ABS_High_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_ABS_High_Quality.inst.cfg index e650f11afd..102901ab3d 100644 --- a/resources/quality/vertex_delta_k8800/k8800_ABS_High_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_ABS_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = vertex_delta_k8800 diff --git a/resources/quality/vertex_delta_k8800/k8800_ABS_Normal_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_ABS_Normal_Quality.inst.cfg index aa962190ce..f2e699f571 100644 --- a/resources/quality/vertex_delta_k8800/k8800_ABS_Normal_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_ABS_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = vertex_delta_k8800 diff --git a/resources/quality/vertex_delta_k8800/k8800_PET_Extreme_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_PET_Extreme_Quality.inst.cfg index 29a4170adf..1f98ded1db 100644 --- a/resources/quality/vertex_delta_k8800/k8800_PET_Extreme_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_PET_Extreme_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extreme definition = vertex_delta_k8800 diff --git a/resources/quality/vertex_delta_k8800/k8800_PET_High_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_PET_High_Quality.inst.cfg index fc92590da1..f050c741c2 100644 --- a/resources/quality/vertex_delta_k8800/k8800_PET_High_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_PET_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = vertex_delta_k8800 diff --git a/resources/quality/vertex_delta_k8800/k8800_PET_Normal_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_PET_Normal_Quality.inst.cfg index b02bfa5178..faeb8343fb 100644 --- a/resources/quality/vertex_delta_k8800/k8800_PET_Normal_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_PET_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = vertex_delta_k8800 diff --git a/resources/quality/vertex_delta_k8800/k8800_PLA_Extreme_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_PLA_Extreme_Quality.inst.cfg index 3cdad7a06f..f5ac232d06 100644 --- a/resources/quality/vertex_delta_k8800/k8800_PLA_Extreme_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_PLA_Extreme_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extreme definition = vertex_delta_k8800 diff --git a/resources/quality/vertex_delta_k8800/k8800_PLA_High_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_PLA_High_Quality.inst.cfg index 192750ef71..63ed8389db 100644 --- a/resources/quality/vertex_delta_k8800/k8800_PLA_High_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_PLA_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = vertex_delta_k8800 diff --git a/resources/quality/vertex_delta_k8800/k8800_PLA_Normal_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_PLA_Normal_Quality.inst.cfg index 1e519734bb..e84cbabade 100644 --- a/resources/quality/vertex_delta_k8800/k8800_PLA_Normal_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_PLA_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = vertex_delta_k8800 diff --git a/resources/quality/vertex_delta_k8800/k8800_TPU_Extreme_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_TPU_Extreme_Quality.inst.cfg index 9da37f2148..a2e8a334f7 100644 --- a/resources/quality/vertex_delta_k8800/k8800_TPU_Extreme_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_TPU_Extreme_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Extreme definition = vertex_delta_k8800 diff --git a/resources/quality/vertex_delta_k8800/k8800_TPU_High_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_TPU_High_Quality.inst.cfg index f5583d32b9..4598332ba6 100644 --- a/resources/quality/vertex_delta_k8800/k8800_TPU_High_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_TPU_High_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = High definition = vertex_delta_k8800 diff --git a/resources/quality/vertex_delta_k8800/k8800_TPU_Normal_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_TPU_Normal_Quality.inst.cfg index a520eb2473..7a8a964b1c 100644 --- a/resources/quality/vertex_delta_k8800/k8800_TPU_Normal_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_TPU_Normal_Quality.inst.cfg @@ -1,5 +1,5 @@ [general] -version = 2 +version = 3 name = Normal definition = vertex_delta_k8800 From cf21e7c74b2e68e9b37925df40b3b64bb7e96a0b Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 9 Mar 2018 16:21:42 +0100 Subject: [PATCH 215/446] Also upgrade definition_changes and user Because these files share their version numbers with quality changes. Contributes to issue CURA-5054. --- .../VersionUpgrade32to33/VersionUpgrade32to33.py | 13 +++++++++++++ .../VersionUpgrade/VersionUpgrade32to33/__init__.py | 12 +++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py b/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py index df22d6bf32..de2240a7c6 100644 --- a/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py +++ b/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py @@ -74,6 +74,19 @@ class VersionUpgrade32to33(VersionUpgrade): setting_version = int(parser.get("metadata", "setting_version", fallback = 0)) return format_version * 1000000 + setting_version + ## Upgrades non-quality-changes instance containers to have the new version + # number. + def upgradeInstanceContainer(self, serialized, filename): + parser = configparser.ConfigParser(interpolation = None) + parser.read_string(serialized) + + #Update version number. + parser["general"]["version"] = "3" + + result = io.StringIO() + parser.write(result) + return [filename], [result.getvalue()] + ## Upgrades a quality changes container to the new format. def upgradeQualityChanges(self, serialized, filename): parser = configparser.ConfigParser(interpolation = None) diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py b/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py index 146ebbe95b..acccfd88dd 100644 --- a/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py +++ b/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py @@ -9,12 +9,22 @@ def getMetaData(): return { "version_upgrade": { # From To Upgrade function - ("quality_changes", 2000004): ("quality_changes", 3000004, upgrade.upgradeQualityChanges), + ("definition_changes", 2000004): ("definition_changes", 3000004, upgrade.upgradeInstanceContainer), + ("quality_changes", 2000004): ("quality_changes", 3000004, upgrade.upgradeQualityChanges), + ("user", 2000004): ("user", 3000004, upgrade.upgradeInstanceContainer) }, "sources": { + "definition_changes": { + "get_version": upgrade.getCfgVersion, + "location": {"./definition_changes"} + }, "quality_changes": { "get_version": upgrade.getCfgVersion, "location": {"./quality"} + }, + "user": { + "get_version": upgrade.getCfgVersion, + "location": {"./user"} } } } From 2f1657f848c26022a78eb00e24388bce137d5c47 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 9 Mar 2018 16:23:38 +0100 Subject: [PATCH 216/446] Update version numbers in variants These didn't match on my initial search-and-replace so I missed them. Contributes to issue CURA-5054. --- resources/variants/cartesio_0.25.inst.cfg | 2 +- resources/variants/cartesio_0.4.inst.cfg | 2 +- resources/variants/cartesio_0.8.inst.cfg | 2 +- resources/variants/fabtotum_hyb35.inst.cfg | 2 +- resources/variants/fabtotum_lite04.inst.cfg | 2 +- resources/variants/fabtotum_lite06.inst.cfg | 2 +- resources/variants/fabtotum_pro02.inst.cfg | 2 +- resources/variants/fabtotum_pro04.inst.cfg | 2 +- resources/variants/fabtotum_pro06.inst.cfg | 2 +- resources/variants/fabtotum_pro08.inst.cfg | 2 +- resources/variants/gmax15plus_025_e3d.inst.cfg | 2 +- resources/variants/gmax15plus_04_e3d.inst.cfg | 2 +- resources/variants/gmax15plus_05_e3d.inst.cfg | 2 +- resources/variants/gmax15plus_05_jhead.inst.cfg | 2 +- resources/variants/gmax15plus_06_e3d.inst.cfg | 2 +- resources/variants/gmax15plus_08_e3d.inst.cfg | 2 +- resources/variants/gmax15plus_10_jhead.inst.cfg | 2 +- resources/variants/gmax15plus_dual_025_e3d.inst.cfg | 2 +- resources/variants/gmax15plus_dual_04_e3d.inst.cfg | 2 +- resources/variants/gmax15plus_dual_05_e3d.inst.cfg | 2 +- resources/variants/gmax15plus_dual_05_jhead.inst.cfg | 2 +- resources/variants/gmax15plus_dual_06_e3d.inst.cfg | 2 +- resources/variants/gmax15plus_dual_08_e3d.inst.cfg | 2 +- resources/variants/gmax15plus_dual_10_jhead.inst.cfg | 2 +- resources/variants/imade3d_jellybox_0.4.inst.cfg | 2 +- resources/variants/imade3d_jellybox_0.4_2-fans.inst.cfg | 2 +- resources/variants/ultimaker2_0.25.inst.cfg | 2 +- resources/variants/ultimaker2_0.4.inst.cfg | 2 +- resources/variants/ultimaker2_0.6.inst.cfg | 2 +- resources/variants/ultimaker2_0.8.inst.cfg | 2 +- resources/variants/ultimaker2_extended_0.25.inst.cfg | 2 +- resources/variants/ultimaker2_extended_0.4.inst.cfg | 2 +- resources/variants/ultimaker2_extended_0.6.inst.cfg | 2 +- resources/variants/ultimaker2_extended_0.8.inst.cfg | 2 +- resources/variants/ultimaker2_extended_plus_0.25.inst.cfg | 2 +- resources/variants/ultimaker2_extended_plus_0.4.inst.cfg | 2 +- resources/variants/ultimaker2_extended_plus_0.6.inst.cfg | 2 +- resources/variants/ultimaker2_extended_plus_0.8.inst.cfg | 2 +- resources/variants/ultimaker2_plus_0.25.inst.cfg | 2 +- resources/variants/ultimaker2_plus_0.4.inst.cfg | 2 +- resources/variants/ultimaker2_plus_0.6.inst.cfg | 2 +- resources/variants/ultimaker2_plus_0.8.inst.cfg | 2 +- resources/variants/ultimaker3_aa0.25.inst.cfg | 2 +- resources/variants/ultimaker3_aa0.8.inst.cfg | 2 +- resources/variants/ultimaker3_aa04.inst.cfg | 2 +- resources/variants/ultimaker3_bb0.8.inst.cfg | 2 +- resources/variants/ultimaker3_bb04.inst.cfg | 2 +- resources/variants/ultimaker3_extended_aa0.25.inst.cfg | 2 +- resources/variants/ultimaker3_extended_aa0.8.inst.cfg | 2 +- resources/variants/ultimaker3_extended_aa04.inst.cfg | 2 +- resources/variants/ultimaker3_extended_bb0.8.inst.cfg | 2 +- resources/variants/ultimaker3_extended_bb04.inst.cfg | 2 +- 52 files changed, 52 insertions(+), 52 deletions(-) diff --git a/resources/variants/cartesio_0.25.inst.cfg b/resources/variants/cartesio_0.25.inst.cfg index 014069451c..a3fbe67606 100644 --- a/resources/variants/cartesio_0.25.inst.cfg +++ b/resources/variants/cartesio_0.25.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.25 mm -version = 2 +version = 3 definition = cartesio [metadata] diff --git a/resources/variants/cartesio_0.4.inst.cfg b/resources/variants/cartesio_0.4.inst.cfg index 7b5dccd980..d5fbc4dc26 100644 --- a/resources/variants/cartesio_0.4.inst.cfg +++ b/resources/variants/cartesio_0.4.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.4 mm -version = 2 +version = 3 definition = cartesio [metadata] diff --git a/resources/variants/cartesio_0.8.inst.cfg b/resources/variants/cartesio_0.8.inst.cfg index 70271dbf75..a309c47424 100644 --- a/resources/variants/cartesio_0.8.inst.cfg +++ b/resources/variants/cartesio_0.8.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.8 mm -version = 2 +version = 3 definition = cartesio [metadata] diff --git a/resources/variants/fabtotum_hyb35.inst.cfg b/resources/variants/fabtotum_hyb35.inst.cfg index e036b2e474..d96189e88e 100644 --- a/resources/variants/fabtotum_hyb35.inst.cfg +++ b/resources/variants/fabtotum_hyb35.inst.cfg @@ -1,6 +1,6 @@ [general] name = Hybrid 0.35 mm -version = 2 +version = 3 definition = fabtotum [metadata] diff --git a/resources/variants/fabtotum_lite04.inst.cfg b/resources/variants/fabtotum_lite04.inst.cfg index defa6692a8..0309b81733 100644 --- a/resources/variants/fabtotum_lite04.inst.cfg +++ b/resources/variants/fabtotum_lite04.inst.cfg @@ -1,6 +1,6 @@ [general] name = Lite 0.4 mm -version = 2 +version = 3 definition = fabtotum [metadata] diff --git a/resources/variants/fabtotum_lite06.inst.cfg b/resources/variants/fabtotum_lite06.inst.cfg index d269092b42..c92e621bd2 100644 --- a/resources/variants/fabtotum_lite06.inst.cfg +++ b/resources/variants/fabtotum_lite06.inst.cfg @@ -1,6 +1,6 @@ [general] name = Lite 0.6 mm -version = 2 +version = 3 definition = fabtotum [metadata] diff --git a/resources/variants/fabtotum_pro02.inst.cfg b/resources/variants/fabtotum_pro02.inst.cfg index b705929c35..29d245a24a 100644 --- a/resources/variants/fabtotum_pro02.inst.cfg +++ b/resources/variants/fabtotum_pro02.inst.cfg @@ -1,6 +1,6 @@ [general] name = Pro 0.2 mm -version = 2 +version = 3 definition = fabtotum [metadata] diff --git a/resources/variants/fabtotum_pro04.inst.cfg b/resources/variants/fabtotum_pro04.inst.cfg index b835312324..42be71b89d 100644 --- a/resources/variants/fabtotum_pro04.inst.cfg +++ b/resources/variants/fabtotum_pro04.inst.cfg @@ -1,6 +1,6 @@ [general] name = Pro 0.4 mm -version = 2 +version = 3 definition = fabtotum [metadata] diff --git a/resources/variants/fabtotum_pro06.inst.cfg b/resources/variants/fabtotum_pro06.inst.cfg index 140b6618cf..9c17d83f47 100644 --- a/resources/variants/fabtotum_pro06.inst.cfg +++ b/resources/variants/fabtotum_pro06.inst.cfg @@ -1,6 +1,6 @@ [general] name = Pro 0.6 mm -version = 2 +version = 3 definition = fabtotum [metadata] diff --git a/resources/variants/fabtotum_pro08.inst.cfg b/resources/variants/fabtotum_pro08.inst.cfg index 421cd0b662..2fc5507024 100644 --- a/resources/variants/fabtotum_pro08.inst.cfg +++ b/resources/variants/fabtotum_pro08.inst.cfg @@ -1,6 +1,6 @@ [general] name = Pro 0.8 mm -version = 2 +version = 3 definition = fabtotum [metadata] diff --git a/resources/variants/gmax15plus_025_e3d.inst.cfg b/resources/variants/gmax15plus_025_e3d.inst.cfg index 3c7b2e4949..53e6a14b23 100644 --- a/resources/variants/gmax15plus_025_e3d.inst.cfg +++ b/resources/variants/gmax15plus_025_e3d.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.25mm E3D (Difficult) -version = 2 +version = 3 definition = gmax15plus [metadata] diff --git a/resources/variants/gmax15plus_04_e3d.inst.cfg b/resources/variants/gmax15plus_04_e3d.inst.cfg index e9c0cf1b18..a0b0d58b92 100644 --- a/resources/variants/gmax15plus_04_e3d.inst.cfg +++ b/resources/variants/gmax15plus_04_e3d.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.4mm E3D -version = 2 +version = 3 definition = gmax15plus [metadata] diff --git a/resources/variants/gmax15plus_05_e3d.inst.cfg b/resources/variants/gmax15plus_05_e3d.inst.cfg index 8575f3c539..333ab55f81 100644 --- a/resources/variants/gmax15plus_05_e3d.inst.cfg +++ b/resources/variants/gmax15plus_05_e3d.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.5mm E3D (Default) -version = 2 +version = 3 definition = gmax15plus [metadata] diff --git a/resources/variants/gmax15plus_05_jhead.inst.cfg b/resources/variants/gmax15plus_05_jhead.inst.cfg index 14d6ab5e9d..51902ffa0c 100644 --- a/resources/variants/gmax15plus_05_jhead.inst.cfg +++ b/resources/variants/gmax15plus_05_jhead.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.5mm J-Head -version = 2 +version = 3 definition = gmax15plus [metadata] diff --git a/resources/variants/gmax15plus_06_e3d.inst.cfg b/resources/variants/gmax15plus_06_e3d.inst.cfg index 5d3f5c63a9..3452e5e81f 100644 --- a/resources/variants/gmax15plus_06_e3d.inst.cfg +++ b/resources/variants/gmax15plus_06_e3d.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.6mm E3D -version = 2 +version = 3 definition = gmax15plus [metadata] diff --git a/resources/variants/gmax15plus_08_e3d.inst.cfg b/resources/variants/gmax15plus_08_e3d.inst.cfg index af08cd2c7c..cdee755efc 100644 --- a/resources/variants/gmax15plus_08_e3d.inst.cfg +++ b/resources/variants/gmax15plus_08_e3d.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.8mm E3D -version = 2 +version = 3 definition = gmax15plus [metadata] diff --git a/resources/variants/gmax15plus_10_jhead.inst.cfg b/resources/variants/gmax15plus_10_jhead.inst.cfg index df61d9729f..ee60c71cc2 100644 --- a/resources/variants/gmax15plus_10_jhead.inst.cfg +++ b/resources/variants/gmax15plus_10_jhead.inst.cfg @@ -1,6 +1,6 @@ [general] name = 1.0mm J-Head -version = 2 +version = 3 definition = gmax15plus [metadata] diff --git a/resources/variants/gmax15plus_dual_025_e3d.inst.cfg b/resources/variants/gmax15plus_dual_025_e3d.inst.cfg index 07bdfca9b7..002af1a0c5 100644 --- a/resources/variants/gmax15plus_dual_025_e3d.inst.cfg +++ b/resources/variants/gmax15plus_dual_025_e3d.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.25mm E3D (Difficult) -version = 2 +version = 3 definition = gmax15plus_dual [metadata] diff --git a/resources/variants/gmax15plus_dual_04_e3d.inst.cfg b/resources/variants/gmax15plus_dual_04_e3d.inst.cfg index 966fe9f224..a98637e9e1 100644 --- a/resources/variants/gmax15plus_dual_04_e3d.inst.cfg +++ b/resources/variants/gmax15plus_dual_04_e3d.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.4mm E3D -version = 2 +version = 3 definition = gmax15plus_dual [metadata] diff --git a/resources/variants/gmax15plus_dual_05_e3d.inst.cfg b/resources/variants/gmax15plus_dual_05_e3d.inst.cfg index 85464bd733..dc7d711043 100644 --- a/resources/variants/gmax15plus_dual_05_e3d.inst.cfg +++ b/resources/variants/gmax15plus_dual_05_e3d.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.5mm E3D (Default) -version = 2 +version = 3 definition = gmax15plus_dual [metadata] diff --git a/resources/variants/gmax15plus_dual_05_jhead.inst.cfg b/resources/variants/gmax15plus_dual_05_jhead.inst.cfg index 689c76541a..fc4f17d057 100644 --- a/resources/variants/gmax15plus_dual_05_jhead.inst.cfg +++ b/resources/variants/gmax15plus_dual_05_jhead.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.5mm J-Head -version = 2 +version = 3 definition = gmax15plus_dual [metadata] diff --git a/resources/variants/gmax15plus_dual_06_e3d.inst.cfg b/resources/variants/gmax15plus_dual_06_e3d.inst.cfg index 57641a4244..506f2df06e 100644 --- a/resources/variants/gmax15plus_dual_06_e3d.inst.cfg +++ b/resources/variants/gmax15plus_dual_06_e3d.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.6mm E3D -version = 2 +version = 3 definition = gmax15plus_dual [metadata] diff --git a/resources/variants/gmax15plus_dual_08_e3d.inst.cfg b/resources/variants/gmax15plus_dual_08_e3d.inst.cfg index 11523ccd67..d008df70f6 100644 --- a/resources/variants/gmax15plus_dual_08_e3d.inst.cfg +++ b/resources/variants/gmax15plus_dual_08_e3d.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.8mm E3D -version = 2 +version = 3 definition = gmax15plus_dual [metadata] diff --git a/resources/variants/gmax15plus_dual_10_jhead.inst.cfg b/resources/variants/gmax15plus_dual_10_jhead.inst.cfg index 26721d0169..825810997e 100644 --- a/resources/variants/gmax15plus_dual_10_jhead.inst.cfg +++ b/resources/variants/gmax15plus_dual_10_jhead.inst.cfg @@ -1,6 +1,6 @@ [general] name = 1.0mm J-Head -version = 2 +version = 3 definition = gmax15plus_dual [metadata] diff --git a/resources/variants/imade3d_jellybox_0.4.inst.cfg b/resources/variants/imade3d_jellybox_0.4.inst.cfg index 5baa8123f2..99b55866c7 100644 --- a/resources/variants/imade3d_jellybox_0.4.inst.cfg +++ b/resources/variants/imade3d_jellybox_0.4.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.4 mm -version = 2 +version = 3 definition = imade3d_jellybox [metadata] diff --git a/resources/variants/imade3d_jellybox_0.4_2-fans.inst.cfg b/resources/variants/imade3d_jellybox_0.4_2-fans.inst.cfg index 5d1a01c366..890c394a36 100644 --- a/resources/variants/imade3d_jellybox_0.4_2-fans.inst.cfg +++ b/resources/variants/imade3d_jellybox_0.4_2-fans.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.4 mm 2-fans -version = 2 +version = 3 definition = imade3d_jellybox [metadata] diff --git a/resources/variants/ultimaker2_0.25.inst.cfg b/resources/variants/ultimaker2_0.25.inst.cfg index 2b1b04f123..c4d778e5cf 100644 --- a/resources/variants/ultimaker2_0.25.inst.cfg +++ b/resources/variants/ultimaker2_0.25.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.25 mm -version = 2 +version = 3 definition = ultimaker2 [metadata] diff --git a/resources/variants/ultimaker2_0.4.inst.cfg b/resources/variants/ultimaker2_0.4.inst.cfg index 8886992f6f..2ce766a1ac 100644 --- a/resources/variants/ultimaker2_0.4.inst.cfg +++ b/resources/variants/ultimaker2_0.4.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.4 mm -version = 2 +version = 3 definition = ultimaker2 [metadata] diff --git a/resources/variants/ultimaker2_0.6.inst.cfg b/resources/variants/ultimaker2_0.6.inst.cfg index 42de9d3ee8..0c5bdca240 100644 --- a/resources/variants/ultimaker2_0.6.inst.cfg +++ b/resources/variants/ultimaker2_0.6.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.6 mm -version = 2 +version = 3 definition = ultimaker2 [metadata] diff --git a/resources/variants/ultimaker2_0.8.inst.cfg b/resources/variants/ultimaker2_0.8.inst.cfg index df2ca88ba2..fd11520eca 100644 --- a/resources/variants/ultimaker2_0.8.inst.cfg +++ b/resources/variants/ultimaker2_0.8.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.8 mm -version = 2 +version = 3 definition = ultimaker2 [metadata] diff --git a/resources/variants/ultimaker2_extended_0.25.inst.cfg b/resources/variants/ultimaker2_extended_0.25.inst.cfg index f04a28e5ba..b8a31641e3 100644 --- a/resources/variants/ultimaker2_extended_0.25.inst.cfg +++ b/resources/variants/ultimaker2_extended_0.25.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.25 mm -version = 2 +version = 3 definition = ultimaker2_extended [metadata] diff --git a/resources/variants/ultimaker2_extended_0.4.inst.cfg b/resources/variants/ultimaker2_extended_0.4.inst.cfg index c54202750a..dbceac2890 100644 --- a/resources/variants/ultimaker2_extended_0.4.inst.cfg +++ b/resources/variants/ultimaker2_extended_0.4.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.4 mm -version = 2 +version = 3 definition = ultimaker2_extended [metadata] diff --git a/resources/variants/ultimaker2_extended_0.6.inst.cfg b/resources/variants/ultimaker2_extended_0.6.inst.cfg index 67176632aa..6fbb489160 100644 --- a/resources/variants/ultimaker2_extended_0.6.inst.cfg +++ b/resources/variants/ultimaker2_extended_0.6.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.6 mm -version = 2 +version = 3 definition = ultimaker2_extended [metadata] diff --git a/resources/variants/ultimaker2_extended_0.8.inst.cfg b/resources/variants/ultimaker2_extended_0.8.inst.cfg index 61917309ef..94b38de8f2 100644 --- a/resources/variants/ultimaker2_extended_0.8.inst.cfg +++ b/resources/variants/ultimaker2_extended_0.8.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.8 mm -version = 2 +version = 3 definition = ultimaker2_extended [metadata] diff --git a/resources/variants/ultimaker2_extended_plus_0.25.inst.cfg b/resources/variants/ultimaker2_extended_plus_0.25.inst.cfg index 6386d71f50..89916470bb 100644 --- a/resources/variants/ultimaker2_extended_plus_0.25.inst.cfg +++ b/resources/variants/ultimaker2_extended_plus_0.25.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.25 mm -version = 2 +version = 3 definition = ultimaker2_extended_plus [metadata] diff --git a/resources/variants/ultimaker2_extended_plus_0.4.inst.cfg b/resources/variants/ultimaker2_extended_plus_0.4.inst.cfg index 1426f733cc..0de416da11 100644 --- a/resources/variants/ultimaker2_extended_plus_0.4.inst.cfg +++ b/resources/variants/ultimaker2_extended_plus_0.4.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.4 mm -version = 2 +version = 3 definition = ultimaker2_extended_plus [metadata] diff --git a/resources/variants/ultimaker2_extended_plus_0.6.inst.cfg b/resources/variants/ultimaker2_extended_plus_0.6.inst.cfg index 5ea4072022..4e6ace5a59 100644 --- a/resources/variants/ultimaker2_extended_plus_0.6.inst.cfg +++ b/resources/variants/ultimaker2_extended_plus_0.6.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.6 mm -version = 2 +version = 3 definition = ultimaker2_extended_plus [metadata] diff --git a/resources/variants/ultimaker2_extended_plus_0.8.inst.cfg b/resources/variants/ultimaker2_extended_plus_0.8.inst.cfg index 69b2b9b0d0..7540d5783a 100644 --- a/resources/variants/ultimaker2_extended_plus_0.8.inst.cfg +++ b/resources/variants/ultimaker2_extended_plus_0.8.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.8 mm -version = 2 +version = 3 definition = ultimaker2_extended_plus [metadata] diff --git a/resources/variants/ultimaker2_plus_0.25.inst.cfg b/resources/variants/ultimaker2_plus_0.25.inst.cfg index 2b40656cf4..d59476a4f7 100644 --- a/resources/variants/ultimaker2_plus_0.25.inst.cfg +++ b/resources/variants/ultimaker2_plus_0.25.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.25 mm -version = 2 +version = 3 definition = ultimaker2_plus [metadata] diff --git a/resources/variants/ultimaker2_plus_0.4.inst.cfg b/resources/variants/ultimaker2_plus_0.4.inst.cfg index 0aaf4f4e5a..a188d10d4a 100644 --- a/resources/variants/ultimaker2_plus_0.4.inst.cfg +++ b/resources/variants/ultimaker2_plus_0.4.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.4 mm -version = 2 +version = 3 definition = ultimaker2_plus [metadata] diff --git a/resources/variants/ultimaker2_plus_0.6.inst.cfg b/resources/variants/ultimaker2_plus_0.6.inst.cfg index 7988a949bc..b3aad334c3 100644 --- a/resources/variants/ultimaker2_plus_0.6.inst.cfg +++ b/resources/variants/ultimaker2_plus_0.6.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.6 mm -version = 2 +version = 3 definition = ultimaker2_plus [metadata] diff --git a/resources/variants/ultimaker2_plus_0.8.inst.cfg b/resources/variants/ultimaker2_plus_0.8.inst.cfg index 1a7824b0b1..3c5dec79f6 100644 --- a/resources/variants/ultimaker2_plus_0.8.inst.cfg +++ b/resources/variants/ultimaker2_plus_0.8.inst.cfg @@ -1,6 +1,6 @@ [general] name = 0.8 mm -version = 2 +version = 3 definition = ultimaker2_plus [metadata] diff --git a/resources/variants/ultimaker3_aa0.25.inst.cfg b/resources/variants/ultimaker3_aa0.25.inst.cfg index 8f06e73f91..447bf0e49c 100644 --- a/resources/variants/ultimaker3_aa0.25.inst.cfg +++ b/resources/variants/ultimaker3_aa0.25.inst.cfg @@ -1,6 +1,6 @@ [general] name = AA 0.25 -version = 2 +version = 3 definition = ultimaker3 [metadata] diff --git a/resources/variants/ultimaker3_aa0.8.inst.cfg b/resources/variants/ultimaker3_aa0.8.inst.cfg index 218c1ea3bf..9f011b9164 100644 --- a/resources/variants/ultimaker3_aa0.8.inst.cfg +++ b/resources/variants/ultimaker3_aa0.8.inst.cfg @@ -1,6 +1,6 @@ [general] name = AA 0.8 -version = 2 +version = 3 definition = ultimaker3 [metadata] diff --git a/resources/variants/ultimaker3_aa04.inst.cfg b/resources/variants/ultimaker3_aa04.inst.cfg index 2964ab74a0..d62e0e0d24 100644 --- a/resources/variants/ultimaker3_aa04.inst.cfg +++ b/resources/variants/ultimaker3_aa04.inst.cfg @@ -1,6 +1,6 @@ [general] name = AA 0.4 -version = 2 +version = 3 definition = ultimaker3 [metadata] diff --git a/resources/variants/ultimaker3_bb0.8.inst.cfg b/resources/variants/ultimaker3_bb0.8.inst.cfg index 03b38f225c..41c6419ec1 100644 --- a/resources/variants/ultimaker3_bb0.8.inst.cfg +++ b/resources/variants/ultimaker3_bb0.8.inst.cfg @@ -1,6 +1,6 @@ [general] name = BB 0.8 -version = 2 +version = 3 definition = ultimaker3 [metadata] diff --git a/resources/variants/ultimaker3_bb04.inst.cfg b/resources/variants/ultimaker3_bb04.inst.cfg index 78d201318d..529cabcc95 100644 --- a/resources/variants/ultimaker3_bb04.inst.cfg +++ b/resources/variants/ultimaker3_bb04.inst.cfg @@ -1,6 +1,6 @@ [general] name = BB 0.4 -version = 2 +version = 3 definition = ultimaker3 [metadata] diff --git a/resources/variants/ultimaker3_extended_aa0.25.inst.cfg b/resources/variants/ultimaker3_extended_aa0.25.inst.cfg index f45d90b762..b06ec0830b 100644 --- a/resources/variants/ultimaker3_extended_aa0.25.inst.cfg +++ b/resources/variants/ultimaker3_extended_aa0.25.inst.cfg @@ -1,6 +1,6 @@ [general] name = AA 0.25 -version = 2 +version = 3 definition = ultimaker3_extended [metadata] diff --git a/resources/variants/ultimaker3_extended_aa0.8.inst.cfg b/resources/variants/ultimaker3_extended_aa0.8.inst.cfg index 1f5709e504..2dfd64a94b 100644 --- a/resources/variants/ultimaker3_extended_aa0.8.inst.cfg +++ b/resources/variants/ultimaker3_extended_aa0.8.inst.cfg @@ -1,6 +1,6 @@ [general] name = AA 0.8 -version = 2 +version = 3 definition = ultimaker3_extended [metadata] diff --git a/resources/variants/ultimaker3_extended_aa04.inst.cfg b/resources/variants/ultimaker3_extended_aa04.inst.cfg index 4d9d2b4646..9ac7e1fdf9 100644 --- a/resources/variants/ultimaker3_extended_aa04.inst.cfg +++ b/resources/variants/ultimaker3_extended_aa04.inst.cfg @@ -1,6 +1,6 @@ [general] name = AA 0.4 -version = 2 +version = 3 definition = ultimaker3_extended [metadata] diff --git a/resources/variants/ultimaker3_extended_bb0.8.inst.cfg b/resources/variants/ultimaker3_extended_bb0.8.inst.cfg index 752083f42a..42d7d85728 100644 --- a/resources/variants/ultimaker3_extended_bb0.8.inst.cfg +++ b/resources/variants/ultimaker3_extended_bb0.8.inst.cfg @@ -1,6 +1,6 @@ [general] name = BB 0.8 -version = 2 +version = 3 definition = ultimaker3_extended [metadata] diff --git a/resources/variants/ultimaker3_extended_bb04.inst.cfg b/resources/variants/ultimaker3_extended_bb04.inst.cfg index 1ceaf58c5b..958180ede5 100644 --- a/resources/variants/ultimaker3_extended_bb04.inst.cfg +++ b/resources/variants/ultimaker3_extended_bb04.inst.cfg @@ -1,6 +1,6 @@ [general] name = BB 0.4 -version = 2 +version = 3 definition = ultimaker3_extended [metadata] From c41af83b4186401c8087d656e1299c527dd87384 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 9 Mar 2018 16:19:03 +0100 Subject: [PATCH 217/446] Fix create quality changes for extruders CURA-5054 --- cura/Machines/QualityManager.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cura/Machines/QualityManager.py b/cura/Machines/QualityManager.py index a2871880f0..ae7a177be4 100644 --- a/cura/Machines/QualityManager.py +++ b/cura/Machines/QualityManager.py @@ -428,11 +428,11 @@ class QualityManager(QObject): Logger.log("w", "No quality or quality changes container found in stack %s, ignoring it", stack.getId()) continue - extruder_definition_id = None - if isinstance(stack, ExtruderStack): - extruder_definition_id = stack.definition.getId() quality_type = quality_container.getMetaDataEntry("quality_type") - new_changes = self._createQualityChanges(quality_type, unique_name, global_stack, extruder_definition_id) + extruder_stack = None + if isinstance(stack, ExtruderStack): + extruder_stack = stack + new_changes = self._createQualityChanges(quality_type, unique_name, global_stack, extruder_stack) from cura.Settings.ContainerManager import ContainerManager ContainerManager.getInstance()._performMerge(new_changes, quality_changes_container, clear_settings = False) ContainerManager.getInstance()._performMerge(new_changes, user_container) @@ -443,8 +443,8 @@ class QualityManager(QObject): # Create a quality changes container with the given setup. # def _createQualityChanges(self, quality_type: str, new_name: str, machine: "GlobalStack", - extruder_id: Optional[str]) -> "InstanceContainer": - base_id = machine.definition.getId() if extruder_id is None else extruder_id + extruder_stack: Optional["ExtruderStack"]) -> "InstanceContainer": + base_id = machine.definition.getId() if extruder_stack is None else extruder_stack.getId() new_id = base_id + "_" + new_name new_id = new_id.lower().replace(" ", "_") new_id = self._container_registry.uniqueName(new_id) @@ -456,8 +456,8 @@ class QualityManager(QObject): quality_changes.addMetaDataEntry("quality_type", quality_type) # If we are creating a container for an extruder, ensure we add that to the container - if extruder_id is not None: - quality_changes.addMetaDataEntry("extruder", extruder_id) + if extruder_stack is not None: + quality_changes.addMetaDataEntry("position", extruder_stack.getMetaDataEntry("position")) # If the machine specifies qualities should be filtered, ensure we match the current criteria. machine_definition_id = getMachineDefinitionIDForQualitySearch(machine) From 472ae8e044bb45a884cbfb3be027e55ae10a3211 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Fri, 9 Mar 2018 16:35:23 +0100 Subject: [PATCH 218/446] CURA-4870 Create a custom model for the machines in order to show the printers grouped by local or networked. --- cura/CuraApplication.py | 8 +- .../Machines/Models/MachineManagementModel.py | 90 +++++++++++++++++++ resources/qml/Preferences/MachinesPage.qml | 5 +- 3 files changed, 95 insertions(+), 8 deletions(-) create mode 100644 cura/Machines/Models/MachineManagementModel.py diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 2ca321e4cc..965e3ed33d 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -59,18 +59,18 @@ from cura.Machines.Models.BuildPlateModel import BuildPlateModel from cura.Machines.Models.NozzleModel import NozzleModel from cura.Machines.Models.QualityProfilesDropDownMenuModel import QualityProfilesDropDownMenuModel from cura.Machines.Models.CustomQualityProfilesDropDownMenuModel import CustomQualityProfilesDropDownMenuModel - from cura.Machines.Models.MultiBuildPlateModel import MultiBuildPlateModel - from cura.Machines.Models.MaterialManagementModel import MaterialManagementModel from cura.Machines.Models.GenericMaterialsModel import GenericMaterialsModel from cura.Machines.Models.BrandMaterialsModel import BrandMaterialsModel +from cura.Machines.Models.QualityManagementModel import QualityManagementModel +from cura.Machines.Models.QualitySettingsModel import QualitySettingsModel +from cura.Machines.Models.MachineManagementModel import MachineManagementModel from cura.Settings.SettingInheritanceManager import SettingInheritanceManager from cura.Settings.SimpleModeSettingsManager import SimpleModeSettingsManager from cura.Machines.VariantManager import VariantManager -from cura.Machines.Models.QualityManagementModel import QualityManagementModel from . import PlatformPhysics from . import BuildVolume @@ -87,7 +87,6 @@ from cura.Settings.ExtruderManager import ExtruderManager from cura.Settings.UserChangesModel import UserChangesModel from cura.Settings.ExtrudersModel import ExtrudersModel from cura.Settings.MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler -from cura.Machines.Models.QualitySettingsModel import QualitySettingsModel from cura.Settings.ContainerManager import ContainerManager from cura.ObjectsModel import ObjectsModel @@ -960,6 +959,7 @@ class CuraApplication(QtApplication): qmlRegisterType(BrandMaterialsModel, "Cura", 1, 0, "BrandMaterialsModel") qmlRegisterType(MaterialManagementModel, "Cura", 1, 0, "MaterialManagementModel") qmlRegisterType(QualityManagementModel, "Cura", 1, 0, "QualityManagementModel") + qmlRegisterType(MachineManagementModel, "Cura", 1, 0, "MachineManagementModel") qmlRegisterSingletonType(QualityProfilesDropDownMenuModel, "Cura", 1, 0, "QualityProfilesDropDownMenuModel", self.getQualityProfilesDropDownMenuModel) diff --git a/cura/Machines/Models/MachineManagementModel.py b/cura/Machines/Models/MachineManagementModel.py new file mode 100644 index 0000000000..0ca47f2ef3 --- /dev/null +++ b/cura/Machines/Models/MachineManagementModel.py @@ -0,0 +1,90 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from UM.Qt.ListModel import ListModel + +from PyQt5.QtCore import pyqtSlot, pyqtProperty, Qt, pyqtSignal + +from UM.Settings.ContainerRegistry import ContainerRegistry +from UM.Settings.ContainerStack import ContainerStack + +from UM.i18n import i18nCatalog +catalog = i18nCatalog("cura") + +# +# This the QML model for the quality management page. +# +class MachineManagementModel(ListModel): + NameRole = Qt.UserRole + 1 + IdRole = Qt.UserRole + 2 + MetaDataRole = Qt.UserRole + 3 + GroupRole = Qt.UserRole + 4 + + def __init__(self, parent = None): + super().__init__(parent) + self.addRoleName(self.NameRole, "name") + self.addRoleName(self.IdRole, "id") + self.addRoleName(self.MetaDataRole, "metadata") + self.addRoleName(self.GroupRole, "group") + self._local_container_stacks = [] + self._network_container_stacks = [] + + # Listen to changes + ContainerRegistry.getInstance().containerAdded.connect(self._onContainerChanged) + ContainerRegistry.getInstance().containerMetaDataChanged.connect(self._onContainerChanged) + ContainerRegistry.getInstance().containerRemoved.connect(self._onContainerChanged) + self._filter_dict = {} + self._update() + + ## Handler for container added/removed events from registry + def _onContainerChanged(self, container): + # We only need to update when the added / removed container is a stack. + if isinstance(container, ContainerStack): + self._update() + + ## Handler for container name change events. + def _onContainerNameChanged(self): + self._update() + + ## Private convenience function to reset & repopulate the model. + def _update(self): + items = [] + # Remove all connections + for container in self._local_container_stacks: + container.nameChanged.disconnect(self._onContainerNameChanged) + for container in self._network_container_stacks: + container.nameChanged.disconnect(self._onContainerNameChanged) + + # Get first the network enabled printers + network_filter_printers = {"type": "machine", "um_network_key": "*", "hidden": "False"} + self._network_container_stacks = ContainerRegistry.getInstance().findContainerStacks(**network_filter_printers) + self._network_container_stacks.sort(key = lambda i: i.getMetaDataEntry("connect_group_name")) + + for container in self._network_container_stacks: + metadata = container.getMetaData().copy() + if container.getBottom(): + metadata["definition_name"] = container.getBottom().getName() + + container.nameChanged.connect(self._onContainerNameChanged) + items.append({"name": metadata["connect_group_name"], + "id": container.getId(), + "metadata": metadata, + "group": catalog.i18nc("@info:title", "Network enabled printers")}) + + # Get now the local printes + local_filter_printers = {"type": "machine", "um_network_key": None} + self._local_container_stacks = ContainerRegistry.getInstance().findContainerStacks(**local_filter_printers) + self._local_container_stacks.sort(key = lambda i: i.getName()) + + for container in self._local_container_stacks: + metadata = container.getMetaData().copy() + if container.getBottom(): + metadata["definition_name"] = container.getBottom().getName() + + container.nameChanged.connect(self._onContainerNameChanged) + items.append({"name": container.getName(), + "id": container.getId(), + "metadata": metadata, + "group": catalog.i18nc("@info:title", "Local printers")}) + + self.setItems(items) diff --git a/resources/qml/Preferences/MachinesPage.qml b/resources/qml/Preferences/MachinesPage.qml index 62e5ef98b4..df9482b84d 100644 --- a/resources/qml/Preferences/MachinesPage.qml +++ b/resources/qml/Preferences/MachinesPage.qml @@ -14,10 +14,7 @@ UM.ManagementPage id: base; title: catalog.i18nc("@title:tab", "Printers"); - model: UM.ContainerStacksModel - { - filter: {"type": "machine"} - } + model: Cura.MachineManagementModel { } activeId: Cura.MachineManager.activeMachineId activeIndex: activeMachineIndex() From a81981a27a0604eeb7b626709e5eebf1dadf0e80 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 9 Mar 2018 16:40:55 +0100 Subject: [PATCH 219/446] Better info on no profiles to import for gcode CIRA-4946 If a gcode is sliced with default profiles, there won't be any custom profiles to import from that gcode. In that case, we show a info message telling the user about this instead of showing an error message. --- cura/ProfileReader.py | 9 ++++++++- cura/Settings/CuraContainerRegistry.py | 3 +++ plugins/GCodeProfileReader/GCodeProfileReader.py | 7 ++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/cura/ProfileReader.py b/cura/ProfileReader.py index d4600ed99f..460fce823e 100644 --- a/cura/ProfileReader.py +++ b/cura/ProfileReader.py @@ -3,6 +3,13 @@ from UM.PluginObject import PluginObject + +# Exception when there is no profile to import from a given files. +# Note that this should not be treated as an exception but as an information instead. +class NoProfileException(Exception): + pass + + ## A type of plug-ins that reads profiles from a file. # # The profile is then stored as instance container of the type user profile. @@ -14,4 +21,4 @@ class ProfileReader(PluginObject): # # \return \type{Profile|Profile[]} The profile that was obtained from the file or a list of Profiles. def read(self, file_name): - raise NotImplementedError("Profile reader plug-in was not correctly implemented. The read function was not implemented.") \ No newline at end of file + raise NotImplementedError("Profile reader plug-in was not correctly implemented. The read function was not implemented.") diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index e79cfa5335..4b576a4207 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -29,6 +29,7 @@ from .ExtruderManager import ExtruderManager from cura.CuraApplication import CuraApplication from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch +from cura.ProfileReader import NoProfileException from UM.i18n import i18nCatalog catalog = i18nCatalog("cura") @@ -185,6 +186,8 @@ class CuraContainerRegistry(ContainerRegistry): profile_reader = plugin_registry.getPluginObject(plugin_id) try: profile_or_list = profile_reader.read(file_name) # Try to open the file with the profile reader. + except NoProfileException: + return { "status": "ok", "message": catalog.i18nc("@info:status Don't translate the XML tags or !", "No custom profile to import in file {0}", file_name)} except Exception as e: # Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None. Logger.log("e", "Failed to import profile from %s: %s while using profile reader. Got exception %s", file_name,profile_reader.getPluginId(), str(e)) diff --git a/plugins/GCodeProfileReader/GCodeProfileReader.py b/plugins/GCodeProfileReader/GCodeProfileReader.py index 2a10e01d43..d6bda85a48 100644 --- a/plugins/GCodeProfileReader/GCodeProfileReader.py +++ b/plugins/GCodeProfileReader/GCodeProfileReader.py @@ -9,7 +9,7 @@ from UM.Logger import Logger from UM.i18n import i18nCatalog catalog = i18nCatalog("cura") -from cura.ProfileReader import ProfileReader +from cura.ProfileReader import ProfileReader, NoProfileException ## A class that reads profile data from g-code files. # @@ -66,6 +66,11 @@ class GCodeProfileReader(ProfileReader): return None serialized = unescapeGcodeComment(serialized) + serialized = serialized.strip() + + if not serialized: + Logger.log("i", "No custom profile to import from this g-code: %s", file_name) + raise NoProfileException() # serialized data can be invalid JSON try: From 711d60e8c7e2948f80e50f7c339dcfa27e21d6ee Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 9 Mar 2018 16:30:37 +0100 Subject: [PATCH 220/446] Allow switching back to the "Custom" set --- .../Settings/SettingVisibilityPresetsModel.py | 27 ++++++++++++++++--- .../Menus/SettingVisibilityPresetsMenu.qml | 2 ++ .../qml/Preferences/SettingVisibilityPage.qml | 5 ++++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/cura/Settings/SettingVisibilityPresetsModel.py b/cura/Settings/SettingVisibilityPresetsModel.py index 9ec8875a39..e5a2e24412 100644 --- a/cura/Settings/SettingVisibilityPresetsModel.py +++ b/cura/Settings/SettingVisibilityPresetsModel.py @@ -29,10 +29,12 @@ class SettingVisibilityPresetsModel(ListModel): self._populate() - preferences = Preferences.getInstance() - preferences.addPreference("cura/active_setting_visibility_preset", "custom") + self._preferences = Preferences.getInstance() + self._preferences.addPreference("cura/active_setting_visibility_preset", "custom") # Preference to store which preset is currently selected + self._preferences.addPreference("cura/custom_visible_settings", "") # Preference that stores the "custom" set so it can always be restored (even after a restart) + self._preferences.preferenceChanged.connect(self._onPreferencesChanged) - self._active_preset = Preferences.getInstance().getValue("cura/active_setting_visibility_preset") + self._active_preset = self._preferences.getValue("cura/active_setting_visibility_preset") if self.find("id", self._active_preset) < 0: self._active_preset = "custom" @@ -90,7 +92,12 @@ class SettingVisibilityPresetsModel(ListModel): Logger.log("w", "Tried to set active preset to unknown id %s", preset_id) return - Preferences.getInstance().setValue("cura/active_setting_visibility_preset", preset_id); + if preset_id == "custom" and self._active_preset == "custom": + # Copy current visibility set to custom visibility set preference so it can be restored later + visibility_string = self._preferences.getValue("general/visible_settings") + self._preferences.setValue("cura/custom_visible_settings", visibility_string) + + self._preferences.setValue("cura/active_setting_visibility_preset", preset_id) self._active_preset = preset_id self.activePresetChanged.emit() @@ -101,6 +108,18 @@ class SettingVisibilityPresetsModel(ListModel): def activePreset(self): return self._active_preset + def _onPreferencesChanged(self, name): + if name != "general/visible_settings": + return + + if self._active_preset != "custom": + return + + # Copy current visibility set to custom visibility set preference so it can be restored later + visibility_string = self._preferences.getValue("general/visible_settings") + self._preferences.setValue("cura/custom_visible_settings", visibility_string) + + # Factory function, used by QML @staticmethod def createSettingVisibilityPresetsModel(engine, js_engine): diff --git a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml index de9eac08cf..19c36e6118 100644 --- a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml +++ b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml @@ -27,6 +27,8 @@ Menu onTriggered: { Cura.SettingVisibilityPresetsModel.setActivePreset("custom"); + // Restore custom set from preference + UM.Preferences.setValue("general/visible_settings", UM.Preferences.getValue("cura/custom_visible_settings")); showSettingVisibilityProfile(); } } diff --git a/resources/qml/Preferences/SettingVisibilityPage.qml b/resources/qml/Preferences/SettingVisibilityPage.qml index bc271971b4..f0c24e2cbe 100644 --- a/resources/qml/Preferences/SettingVisibilityPage.qml +++ b/resources/qml/Preferences/SettingVisibilityPage.qml @@ -164,6 +164,11 @@ UM.PreferencesPage UM.Preferences.setValue("general/visible_settings", Cura.SettingVisibilityPresetsModel.getItem(index - 1).settings.join(";")); // "Custom selection" entry is added in front, so index is off by 1 } + else + { + // Restore custom set from preference + UM.Preferences.setValue("general/visible_settings", UM.Preferences.getValue("cura/custom_visible_settings")); + } base.inhibitSwitchToCustom = false; } } From 87380e007c943f00ad3a15bf765aca978d4958d4 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Fri, 9 Mar 2018 16:44:46 +0100 Subject: [PATCH 221/446] CURA-4870 Switch the hidden metadata entry also when switching printes so the active printer is correctly shown in the machines page. --- cura/Settings/MachineManager.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 3bc2df0da1..1522e5f6c0 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1074,14 +1074,18 @@ class MachineManager(QObject): machine_definition_id = ContainerRegistry.getInstance().findDefinitionContainers(name = machine_name)[0].getId() # Try to find a machine with the same network key new_machine = self.getMachine(machine_definition_id, metadata_filter = {"um_network_key": self.activeMachineNetworkKey}) - # If there is no machine, then create a new one + # If there is no machine, then create a new one and set it to the non-hidden instance if not new_machine: new_machine = CuraStackBuilder.createMachine(machine_definition_id + "_sync", machine_definition_id) new_machine.addMetaDataEntry("um_network_key", self.activeMachineNetworkKey) new_machine.addMetaDataEntry("connect_group_name", self.activeMachineNetworkGroupName) - new_machine.addMetaDataEntry("hidden", True) + new_machine.addMetaDataEntry("hidden", False) else: Logger.log("i", "Found a %s with the key %s. Let's use it!", machine_name, self.activeMachineNetworkKey) + new_machine.setMetaDataEntry("hidden", False) + + # Set the current printer instance to hidden (the metadata entry must exist) + self._global_container_stack.setMetaDataEntry("hidden", True) self.setActiveMachine(new_machine.getId()) From 7123441db81819f8d46158e8b227ae18ab71fbbf Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 9 Mar 2018 16:51:46 +0100 Subject: [PATCH 222/446] Fix keeping settings visible when showing all settings --- resources/qml/Settings/SettingView.qml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 73a76a028f..1acc1845e5 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -18,7 +18,6 @@ Item property Action configureSettings property bool findingSettings property bool showingAllSettings - property bool inhibitSwitchToCustom: false signal showTooltip(Item item, point location, string text) signal hideTooltip() @@ -559,13 +558,13 @@ Item MenuItem { //: Settings context menu action - visible: !findingSettings; + visible: !(findingSettings || showingAllSettings); text: catalog.i18nc("@action:menu", "Hide this setting"); onTriggered: { definitionsModel.hide(contextMenu.key); // visible settings have changed, so we're no longer showing a preset - if (Cura.SettingVisibilityPresetsModel.activePreset != "") + if (Cura.SettingVisibilityPresetsModel.activePreset != "" && !showingAllSettings) { Cura.SettingVisibilityPresetsModel.setActivePreset("custom"); } @@ -585,7 +584,7 @@ Item return catalog.i18nc("@action:menu", "Keep this setting visible"); } } - visible: findingSettings; + visible: (findingSettings || showingAllSettings); onTriggered: { if (contextMenu.settingVisible) @@ -597,7 +596,7 @@ Item definitionsModel.show(contextMenu.key); } // visible settings have changed, so we're no longer showing a preset - if (Cura.SettingVisibilityPresetsModel.activePreset != "") + if (Cura.SettingVisibilityPresetsModel.activePreset != "" && !showingAllSettings) { Cura.SettingVisibilityPresetsModel.setActivePreset("custom"); } From e62ed62bdda71cd162dbb80cfeaa586a46e217bc Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 9 Mar 2018 16:57:09 +0100 Subject: [PATCH 223/446] Remove duplicate import --- cura/CuraApplication.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 903533aecf..64ef37b71d 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -70,7 +70,6 @@ from cura.Machines.Models.BrandMaterialsModel import BrandMaterialsModel from cura.Settings.SettingInheritanceManager import SettingInheritanceManager from cura.Settings.SimpleModeSettingsManager import SimpleModeSettingsManager -from cura.Settings.SettingVisibilityPresetsModel import SettingVisibilityPresetsModel from cura.Machines.VariantManager import VariantManager from cura.Machines.Models.QualityManagementModel import QualityManagementModel From e09325bf82de85d5c2336bc966fba7726ca7f31e Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 9 Mar 2018 17:16:24 +0100 Subject: [PATCH 224/446] Fix project loading for version upgrade CURA-5054 --- cura/Machines/QualityManager.py | 2 +- plugins/3MFReader/ThreeMFWorkspaceReader.py | 43 +++++++-------------- 2 files changed, 15 insertions(+), 30 deletions(-) diff --git a/cura/Machines/QualityManager.py b/cura/Machines/QualityManager.py index ae7a177be4..c11858d1e5 100644 --- a/cura/Machines/QualityManager.py +++ b/cura/Machines/QualityManager.py @@ -386,7 +386,7 @@ class QualityManager(QObject): if quality_changes_group is None: # create global quality changes only new_quality_changes = self._createQualityChanges(quality_group.quality_type, quality_changes_name, - global_stack, extruder_id = None) + global_stack, None) self._container_registry.addContainer(new_quality_changes) else: new_name = self._container_registry.uniqueName(quality_changes_name) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 7201df65e4..d8e2fd7609 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -216,11 +216,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader): archive = zipfile.ZipFile(file_name, "r") cura_file_names = [name for name in archive.namelist() if name.startswith("Cura/")] - # A few lists of containers in this project files. - # When loading the global stack file, it may be associated with those containers, which may or may not be - # in Cura already, so we need to provide them as alternative search lists. - instance_container_list = [] - resolve_strategy_keys = ["machine", "material", "quality_changes"] self._resolve_strategies = {k: None for k in resolve_strategy_keys} containers_found_dict = {k: False for k in resolve_strategy_keys} @@ -307,13 +302,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): container_info = ContainerInfo(instance_container_file_name, serialized, parser) instance_container_info_dict[container_id] = container_info - instance_container = InstanceContainer(container_id) - - # Deserialize InstanceContainer by converting read data from bytes to string - instance_container.deserialize(serialized, file_name = instance_container_file_name) - instance_container_list.append(instance_container) - - container_type = instance_container.getMetaDataEntry("type") + container_type = parser["metadata"]["type"] if container_type == "quality_changes": quality_changes_info_list.append(container_info) @@ -321,20 +310,22 @@ class ThreeMFWorkspaceReader(WorkspaceReader): self._machine_info.quality_changes_info.name = parser["general"]["name"] self._machine_info.quality_changes_info.global_info = container_info - quality_name = instance_container.getName() - num_settings_overriden_by_quality_changes += len(instance_container._instances) + quality_name = parser["general"]["name"] + num_settings_overriden_by_quality_changes += len(parser.get("values", {})) # Check if quality changes already exists. quality_changes = self._container_registry.findInstanceContainers(id = container_id) if quality_changes: containers_found_dict["quality_changes"] = True # Check if there really is a conflict by comparing the values + instance_container = InstanceContainer(container_id) + instance_container.deserialize(serialized, file_name = instance_container_file_name) if quality_changes[0] != instance_container: quality_changes_conflict = True elif container_type == "quality": if not quality_name: - quality_name = instance_container.getName() + quality_name = parser["general"]["name"] elif container_type == "user": - num_user_settings += len(instance_container._instances) + num_user_settings += len(parser["values"]) elif container_type in self._ignored_instance_container_types: # Ignore certain instance container types Logger.log("w", "Ignoring instance container [%s] with type [%s]", container_id, container_type) @@ -739,7 +730,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader): from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch machine_definition_id_for_quality = getMachineDefinitionIDForQualitySearch(global_stack) machine_definition_for_quality = self._container_registry.findDefinitionContainers(id = machine_definition_id_for_quality)[0] - extruder_dict_for_quality = machine_definition_for_quality.getMetaDataEntry("machine_extruder_trains") quality_changes_info = self._machine_info.quality_changes_info quality_changes_quality_type = quality_changes_info.global_info.parser["metadata"]["quality_type"] @@ -752,13 +742,12 @@ class ThreeMFWorkspaceReader(WorkspaceReader): quality_changes_name = self._container_registry.uniqueName(quality_changes_name) for position, container_info in container_info_dict.items(): - extruder_definition_id = None + extruder_stack = None if position is not None: - extruder_definition_id = extruder_dict_for_quality[position] - + extruder_stack = global_stack.extruders[position] container = quality_manager._createQualityChanges(quality_changes_quality_type, quality_changes_name, - global_stack, extruder_definition_id) + global_stack, extruder_stack) container_info.container = container container.setDirty(True) self._container_registry.addContainer(container) @@ -781,18 +770,14 @@ class ThreeMFWorkspaceReader(WorkspaceReader): container_info = quality_changes_info.extruder_info_dict[position] container_info.container = container - for position, container_info in quality_changes_info.extruder_info_dict.items(): - container_info.definition_id = extruder_dict_for_quality[position] - # If there is no quality changes for any extruder, create one. if not quality_changes_info.extruder_info_dict: container_info = ContainerInfo(None, None, None) quality_changes_info.extruder_info_dict["0"] = container_info - extruder_definition_id = extruder_dict_for_quality["0"] - container_info.definition_id = extruder_definition_id + extruder_stack = global_stack.extruders["0"] container = quality_manager._createQualityChanges(quality_changes_quality_type, quality_changes_name, - global_stack, extruder_definition_id) + global_stack, extruder_stack) container_info.container = container container.setDirty(True) self._container_registry.addContainer(container) @@ -818,9 +803,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader): continue if container_info.container is None: - extruder_definition_id = extruder_dict_for_quality[position] + extruder_stack = global_stack.extruders[position] container = quality_manager._createQualityChanges(quality_changes_quality_type, quality_changes_name, - global_stack, extruder_definition_id) + global_stack, extruder_stack) container_info.container = container for key, value in container_info.parser["values"].items(): From 7312ed8e3c32b8923744487b7bb4f39f0925d252 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 9 Mar 2018 19:35:21 +0100 Subject: [PATCH 225/446] Fix project loading for version upgrade CURA-5054 --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index d8e2fd7609..3c627a7655 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -306,12 +306,16 @@ class ThreeMFWorkspaceReader(WorkspaceReader): if container_type == "quality_changes": quality_changes_info_list.append(container_info) - if not parser.has_option("metadata", "extruder"): + if not parser.has_option("metadata", "position"): self._machine_info.quality_changes_info.name = parser["general"]["name"] self._machine_info.quality_changes_info.global_info = container_info + else: + position = parser["metadata"]["position"] + self._machine_info.quality_changes_info.extruder_info_dict[position] = container_info quality_name = parser["general"]["name"] - num_settings_overriden_by_quality_changes += len(parser.get("values", {})) + values = parser["values"] if parser.has_section("values") else dict() + num_settings_overriden_by_quality_changes += len(values) # Check if quality changes already exists. quality_changes = self._container_registry.findInstanceContainers(id = container_id) if quality_changes: @@ -444,15 +448,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader): machine_conflict = True break - if self._machine_info.quality_changes_info is not None: - for quality_changes_info in quality_changes_info_list: - if not quality_changes_info.parser.has_option("metadata", "extruder"): - continue - extruder_definition_id = quality_changes_info.parser["metadata"]["extruder"] - extruder_definition_metadata = self._container_registry.findDefinitionContainersMetadata(id = extruder_definition_id)[0] - position = extruder_definition_metadata["position"] - self._machine_info.quality_changes_info.extruder_info_dict[position] = quality_changes_info - num_visible_settings = 0 try: temp_preferences = Preferences() From 5e4e049c1f60d8fef670ddd53b84f0679cc21f5a Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Thu, 1 Mar 2018 20:57:15 -0600 Subject: [PATCH 226/446] Add definition for Printrbot Simple Maker's Kit 1405 The Printrbot Simple Maker's Kit, model 1405, was a low-cost FDM printer without a heated bed and a 10x10cm print area. The print area can be extended to 185x100mm with the "Printrbot Simple XL Upgrade with Spool Rack for Maker's Kit 1405". More information can be found at http://printrbot.com/project/simple-makers/ --- .../printrbot_simple_makers_kit.def.json | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 resources/definitions/printrbot_simple_makers_kit.def.json diff --git a/resources/definitions/printrbot_simple_makers_kit.def.json b/resources/definitions/printrbot_simple_makers_kit.def.json new file mode 100644 index 0000000000..61aecd9240 --- /dev/null +++ b/resources/definitions/printrbot_simple_makers_kit.def.json @@ -0,0 +1,39 @@ +{ + "version": 2, + "name": "Printrbot Simple Maker's Kit (1405)", + "inherits": "fdmprinter", + "metadata": { + "visible": true, + "author": "Timur Tabi", + "manufacturer": "Printrbot", + "file_formats": "text/x-gcode", + "preferred_material": "*pla*" + }, + + "overrides": { + "machine_name": { "default_value": "Printrbot Simple Maker's Kit (1405)" }, + "machine_heated_bed": { "default_value": false }, + "machine_width": { "default_value": 100 }, + "machine_depth": { "default_value": 100 }, + "machine_height": { "default_value": 115 }, + "material_diameter": { "default_value": 1.75 }, + "machine_nozzle_size": { "default_value": 0.4 }, + "machine_head_with_fans_polygon": { + "default_value": [ + [-40, 1000], + [-40, -10], + [60, 1000], + [60, -10] + ] + }, + "gantry_height": { "default_value": 1000 }, + "machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" }, + + "machine_start_gcode": { + "default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;home X/Y\nG28 Z0 ;home Z\nG92 E0 ;zero the extruded length\nG29 ;initiate auto bed leveling sequence" + }, + "machine_end_gcode": { + "default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nM106 S0 ;fan off\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit\nG1 Z+1 E-5 F9000 ;move Z up a bit and retract even more\nG28 X0 Y0 ;home X/Y, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning" + } + } +} From 4d5ace4564cb1a927312665f3c63321164da8be8 Mon Sep 17 00:00:00 2001 From: Ryan Date: Sun, 11 Mar 2018 10:27:57 -0400 Subject: [PATCH 227/446] Added default material diameter to SeeMeCNC printer definitions --- resources/definitions/seemecnc_artemis.def.json | 1 + resources/definitions/seemecnc_v32.def.json | 1 + 2 files changed, 2 insertions(+) diff --git a/resources/definitions/seemecnc_artemis.def.json b/resources/definitions/seemecnc_artemis.def.json index 88a1b28de6..0b31abfa41 100644 --- a/resources/definitions/seemecnc_artemis.def.json +++ b/resources/definitions/seemecnc_artemis.def.json @@ -25,6 +25,7 @@ "machine_nozzle_size": { "default_value": 0.5 }, "machine_shape": { "default_value": "elliptic" }, "machine_width": { "default_value": 290 }, + "material_diameter": { "default_value": 1.75 }, "relative_extrusion": { "default_value": false }, "retraction_amount": { "default_value": 3.2 }, "retraction_combing": { "default_value": "off" }, diff --git a/resources/definitions/seemecnc_v32.def.json b/resources/definitions/seemecnc_v32.def.json index 5932403bc5..3f46c1540a 100644 --- a/resources/definitions/seemecnc_v32.def.json +++ b/resources/definitions/seemecnc_v32.def.json @@ -25,6 +25,7 @@ "machine_nozzle_size": { "default_value": 0.5 }, "machine_shape": { "default_value": "elliptic" }, "machine_width": { "default_value": 265 }, + "material_diameter": { "default_value": 1.75 }, "relative_extrusion": { "default_value": false }, "retraction_amount": { "default_value": 3.2 }, "retraction_combing": { "default_value": "off" }, From aae8a31f00cf9db2b6190a43dbf1658db64311cf Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 09:22:59 +0100 Subject: [PATCH 228/446] Don't display extruder count if you can't use it If your printer can only handle one extruder, don't display this drop-down. Don't let users get confused. --- plugins/MachineSettingsAction/MachineSettingsAction.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/MachineSettingsAction/MachineSettingsAction.qml b/plugins/MachineSettingsAction/MachineSettingsAction.qml index 4d00904f76..f941ef87b4 100644 --- a/plugins/MachineSettingsAction/MachineSettingsAction.qml +++ b/plugins/MachineSettingsAction/MachineSettingsAction.qml @@ -244,6 +244,7 @@ Cura.MachineAction height: childrenRect.height width: childrenRect.width text: machineExtruderCountProvider.properties.description + visible: extruderCountModel.count >= 2 Row { From 15212d4426b1eb72777e33d9f04dd37127990413 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 09:38:20 +0100 Subject: [PATCH 229/446] Align for readability --- plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py b/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py index acccfd88dd..c411b4190e 100644 --- a/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py +++ b/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py @@ -8,10 +8,10 @@ upgrade = VersionUpgrade32to33.VersionUpgrade32to33() def getMetaData(): return { "version_upgrade": { - # From To Upgrade function + # From To Upgrade function ("definition_changes", 2000004): ("definition_changes", 3000004, upgrade.upgradeInstanceContainer), - ("quality_changes", 2000004): ("quality_changes", 3000004, upgrade.upgradeQualityChanges), - ("user", 2000004): ("user", 3000004, upgrade.upgradeInstanceContainer) + ("quality_changes", 2000004): ("quality_changes", 3000004, upgrade.upgradeQualityChanges), + ("user", 2000004): ("user", 3000004, upgrade.upgradeInstanceContainer) }, "sources": { "definition_changes": { From d98cab48ac464664da24510d981fa560ebbda4ad Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 09:48:03 +0100 Subject: [PATCH 230/446] Get scripts from either Resources or Preferences We must retain the old directory for legacy. People might still have scripts there. --- plugins/PostProcessingPlugin/PostProcessingPlugin.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/PostProcessingPlugin/PostProcessingPlugin.py b/plugins/PostProcessingPlugin/PostProcessingPlugin.py index dc2d93a788..c4b760724b 100644 --- a/plugins/PostProcessingPlugin/PostProcessingPlugin.py +++ b/plugins/PostProcessingPlugin/PostProcessingPlugin.py @@ -173,7 +173,10 @@ class PostProcessingPlugin(QObject, Extension): Logger.log("d", "Creating post processing plugin view.") ## Load all scripts in the scripts folders - for root in [PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), Resources.getStoragePath(Resources.Resources)]: + # The PostProcessingPlugin path is for built-in scripts. + # The Resources path is where the user should store custom scripts. + # The Preferences path is legacy, where the user may previously have stored scripts. + for root in [PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), Resources.getStoragePath(Resources.Resources), Resources.getStoragePath(Resources.Preferences)]: path = os.path.join(root, "scripts") if not os.path.isdir(path): try: From 552618fcd4066bad40a219e21e1ccca1999c2fe8 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 12 Mar 2018 09:56:08 +0100 Subject: [PATCH 231/446] CURA-4400 added function to find model index by extruder position in SettingExtruder --- cura/Settings/ExtrudersModel.py | 2 +- resources/qml/Settings/SettingExtruder.qml | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/cura/Settings/ExtrudersModel.py b/cura/Settings/ExtrudersModel.py index ae8cff3c9a..4ee5ab3c3b 100644 --- a/cura/Settings/ExtrudersModel.py +++ b/cura/Settings/ExtrudersModel.py @@ -1,7 +1,7 @@ # Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty, QTimer +from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot, pyqtProperty, QTimer from typing import Iterable from UM.i18n import i18nCatalog diff --git a/resources/qml/Settings/SettingExtruder.qml b/resources/qml/Settings/SettingExtruder.qml index 35ad198edf..2ddbb135c7 100644 --- a/resources/qml/Settings/SettingExtruder.qml +++ b/resources/qml/Settings/SettingExtruder.qml @@ -26,6 +26,20 @@ SettingItem textRole: "name" + // knowing the extruder position, try to find the item index in the model + function getIndexByPosition(position) + { + for (var item_index in model.items) + { + var item = model.getItem(item_index) + if (item.index == position) + { + return item_index + } + } + return -1 + } + onActivated: { if (model.getItem(index).enabled) @@ -83,8 +97,7 @@ SettingItem { if(propertyProvider.properties.value == -1) { - // TODO: accidently the extruder position is also the index. fix it - return Cura.MachineManager.defaultExtruderPosition; + return control.getIndexByPosition(Cura.MachineManager.defaultExtruderPosition); } return propertyProvider.properties.value } From 2c5cc17b490e311359df3bedcf293a9f530d6470 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 12 Mar 2018 10:33:40 +0100 Subject: [PATCH 232/446] Fix build plate compatibility check CURA-5078 --- cura/Settings/MachineManager.py | 14 ++++++++++++-- plugins/XmlMaterialProfile/XmlMaterialProfile.py | 3 ++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 144f495997..b09ff9e8bd 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -919,11 +919,21 @@ class MachineManager(QObject): def activeMaterialsCompatible(self): # check material - variant compatibility + result = True + machine_has_buildplate = Util.parseBool(self._global_container_stack.getMetaDataEntry("has_variant_buildplates", False)) if Util.parseBool(self._global_container_stack.getMetaDataEntry("has_materials", False)): for position, extruder in self._global_container_stack.extruders.items(): if not extruder.material.getMetaDataEntry("compatible"): - return False - return True + result = False + break + if machine_has_buildplate: + buildplate_compatibility_dict = extruder.material.getMetaDataEntry("buildplate_compatible") + if buildplate_compatibility_dict: + buildplate_name = self._global_container_stack.variant.getName() + result = buildplate_compatibility_dict.get(buildplate_name, True) + if not result: + break + return result ## Update current quality type and machine after setting material def _updateQualityWithMaterial(self): diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index a7ba423153..e8d0c9d2f0 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -617,7 +617,8 @@ class XmlMaterialProfile(InstanceContainer): from cura.Machines.VariantManager import VariantType variant_manager = CuraApplication.getInstance().getVariantManager() - variant_node = variant_manager.getVariantNode(machine_id, buildplate_id) + variant_node = variant_manager.getVariantNode(machine_id, buildplate_id, + variant_type = VariantType.BUILD_PLATE) if not variant_node: continue From 9613103591897cb436b140270136507650be8646 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 12 Mar 2018 10:45:49 +0100 Subject: [PATCH 233/446] CURA-4870 Remove Monitor stage status icons --- plugins/MonitorStage/MonitorStage.py | 63 ---------------------------- 1 file changed, 63 deletions(-) diff --git a/plugins/MonitorStage/MonitorStage.py b/plugins/MonitorStage/MonitorStage.py index 1a1d37cbdf..ed84a8d2ce 100644 --- a/plugins/MonitorStage/MonitorStage.py +++ b/plugins/MonitorStage/MonitorStage.py @@ -22,14 +22,7 @@ class MonitorStage(CuraStage): def _setActivePrintJob(self, print_job): if self._active_print_job != print_job: - if self._active_print_job: - self._active_print_job.stateChanged.disconnect(self._updateIconSource) self._active_print_job = print_job - if self._active_print_job: - self._active_print_job.stateChanged.connect(self._updateIconSource) - - # Ensure that the right icon source is returned. - self._updateIconSource() def _setActivePrinter(self, printer): if self._active_printer != printer: @@ -43,9 +36,6 @@ class MonitorStage(CuraStage): else: self._setActivePrintJob(None) - # Ensure that the right icon source is returned. - self._updateIconSource() - def _onActivePrintJobChanged(self): self._setActivePrintJob(self._active_printer.activePrintJob) @@ -58,22 +48,13 @@ class MonitorStage(CuraStage): new_output_device = Application.getInstance().getMachineManager().printerOutputDevices[0] if new_output_device != self._printer_output_device: if self._printer_output_device: - self._printer_output_device.acceptsCommandsChanged.disconnect(self._updateIconSource) - self._printer_output_device.connectionStateChanged.disconnect(self._updateIconSource) self._printer_output_device.printersChanged.disconnect(self._onActivePrinterChanged) self._printer_output_device = new_output_device - self._printer_output_device.acceptsCommandsChanged.connect(self._updateIconSource) self._printer_output_device.printersChanged.connect(self._onActivePrinterChanged) - self._printer_output_device.connectionStateChanged.connect(self._updateIconSource) self._setActivePrinter(self._printer_output_device.activePrinter) - - # Force an update of the icon source - self._updateIconSource() except IndexError: - #If index error occurs, then the icon on monitor button also should be updated - self._updateIconSource() pass def _onEngineCreated(self): @@ -82,7 +63,6 @@ class MonitorStage(CuraStage): self._onOutputDevicesChanged() self._updateMainOverlay() self._updateSidebar() - self._updateIconSource() def _updateMainOverlay(self): main_component_path = os.path.join(PluginRegistry.getInstance().getPluginPath("MonitorStage"), "MonitorMainView.qml") @@ -92,46 +72,3 @@ class MonitorStage(CuraStage): # TODO: currently the sidebar component for prepare and monitor stages is the same, this will change with the printer output device refactor! sidebar_component_path = os.path.join(Resources.getPath(Application.getInstance().ResourceTypes.QmlFiles), "Sidebar.qml") self.addDisplayComponent("sidebar", sidebar_component_path) - - def _updateIconSource(self): - if Application.getInstance().getTheme() is not None: - icon_name = self._getActiveOutputDeviceStatusIcon() - self.setIconSource(Application.getInstance().getTheme().getIcon(icon_name)) - - ## Find the correct status icon depending on the active output device state - def _getActiveOutputDeviceStatusIcon(self): - # We assume that you are monitoring the device with the highest priority. - try: - output_device = Application.getInstance().getMachineManager().printerOutputDevices[0] - except IndexError: - return "tab_status_unknown" - - if not output_device.acceptsCommands: - return "tab_status_unknown" - - if output_device.activePrinter is None: - return "tab_status_connected" - - # TODO: refactor to use enum instead of hardcoded strings? - if output_device.activePrinter.state == "maintenance": - return "tab_status_busy" - - if output_device.activePrinter.activePrintJob is None: - return "tab_status_connected" - - if output_device.activePrinter.activePrintJob.state in ["printing", "pre_print", "pausing", "resuming"]: - return "tab_status_busy" - - if output_device.activePrinter.activePrintJob.state == "wait_cleanup": - return "tab_status_finished" - - if output_device.activePrinter.activePrintJob.state in ["ready", ""]: - return "tab_status_connected" - - if output_device.activePrinter.activePrintJob.state == "paused": - return "tab_status_paused" - - if output_device.activePrinter.activePrintJob.state == "error": - return "tab_status_stopped" - - return "tab_status_unknown" From 3edc96ec8f16d0eb8724666f209d4d854aea07e6 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 12 Mar 2018 10:47:23 +0100 Subject: [PATCH 234/446] CURA-4400 fixed wrongly converted expression --- plugins/CuraEngineBackend/StartSliceJob.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index f84b20b522..63a345c13e 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -194,7 +194,7 @@ class StartSliceJob(Job): # Find a reason not to add the node if node.callDecoration("getBuildPlateNumber") != self._build_plate_number: continue - if getattr(node, "_outside_buildarea", False) and is_non_printing_mesh: + if getattr(node, "_outside_buildarea", False) and not is_non_printing_mesh: continue node_position = node.callDecoration("getActiveExtruderPosition") if not stack.extruders[str(node_position)].isEnabled: From 1f8be6ad3c6fb9dbf111d5f46b200f204b16dd78 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 12 Mar 2018 11:05:55 +0100 Subject: [PATCH 235/446] CURA-4400 moved default extruder value to value instead of default_value because of engine --- resources/definitions/fdmprinter.def.json | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 98909a3325..6d4688bb52 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -3470,7 +3470,8 @@ "label": "Support Extruder", "description": "The extruder train to use for printing the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": "-1", + "default_value": "0", + "value": "-1", "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, "settable_per_extruder": false, @@ -3480,7 +3481,7 @@ "label": "Support Infill Extruder", "description": "The extruder train to use for printing the infill of the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": "-1", + "default_value": "0", "value": "support_extruder_nr", "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, @@ -3491,7 +3492,7 @@ "label": "First Layer Support Extruder", "description": "The extruder train to use for printing the first layer of support infill. This is used in multi-extrusion.", "type": "extruder", - "default_value": "-1", + "default_value": "0", "value": "support_extruder_nr", "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, @@ -3502,7 +3503,7 @@ "label": "Support Interface Extruder", "description": "The extruder train to use for printing the roofs and floors of the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": "-1", + "default_value": "0", "value": "support_extruder_nr", "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, @@ -3514,7 +3515,7 @@ "label": "Support Roof Extruder", "description": "The extruder train to use for printing the roofs of the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": "-1", + "default_value": "0", "value": "support_interface_extruder_nr", "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, @@ -3525,7 +3526,7 @@ "label": "Support Floor Extruder", "description": "The extruder train to use for printing the floors of the support. This is used in multi-extrusion.", "type": "extruder", - "default_value": "-1", + "default_value": "0", "value": "support_interface_extruder_nr", "enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1", "settable_per_mesh": false, @@ -4196,7 +4197,8 @@ "label": "Build Plate Adhesion Extruder", "description": "The extruder train to use for printing the skirt/brim/raft. This is used in multi-extrusion.", "type": "extruder", - "default_value": "-1", + "default_value": "0", + "value": "-1", "enabled": "extruders_enabled_count > 1 and resolveOrValue('adhesion_type') != 'none'", "settable_per_mesh": false, "settable_per_extruder": false From a3d6127dcbd82405a2d960eb9766deb81ac4e80c Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 12 Mar 2018 11:33:54 +0100 Subject: [PATCH 236/446] CURA-4400 removed unnecessary correctExtruderSettings --- cura/Settings/ContainerManager.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index 00eda480b4..2c94afccef 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -338,8 +338,6 @@ class ContainerManager(QObject): container.clear() send_emits_containers.append(container) - Application.getInstance().getMachineManager().correctExtruderSettings() - for container in send_emits_containers: container.sendPostponedEmits() From ec2201b57c6c0638382932a0af43af394bb4f2b6 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 12 Mar 2018 11:57:53 +0100 Subject: [PATCH 237/446] CURA-4870 Move the printer type and the buildplate selector to the top of the sidebar and set them separate from the extruder related selectors. --- resources/qml/SidebarHeader.qml | 198 ++++++++++++++++---------------- 1 file changed, 97 insertions(+), 101 deletions(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 8e12cd017b..2323202305 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -26,16 +26,111 @@ Column Item { + id: initialSeparator anchors { left: parent.left right: parent.right } - visible: extruderSelectionRow.visible + visible: printerTypeSelectionRow.visible || buildplateRow.visible || extruderSelectionRow.visible height: UM.Theme.getSize("default_lining").height width: height } + // Printer Type Row + Item + { + id: printerTypeSelectionRow + height: UM.Theme.getSize("sidebar_setup").height + visible: printerConnected && hasManyPrinterTypes && !sidebar.monitoringPrint && !sidebar.hideSettings + + anchors + { + left: parent.left + leftMargin: UM.Theme.getSize("sidebar_margin").width + right: parent.right + rightMargin: UM.Theme.getSize("sidebar_margin").width + } + + Label + { + id: configurationLabel + text: catalog.i18nc("@label", "Printer type"); + width: Math.round(parent.width * 0.4 - UM.Theme.getSize("default_margin").width) + height: parent.height + verticalAlignment: Text.AlignVCenter + font: UM.Theme.getFont("default"); + color: UM.Theme.getColor("text"); + } + + ToolButton + { + id: printerTypeSelection + text: Cura.MachineManager.activeMachineDefinitionName + tooltip: Cura.MachineManager.activeMachineDefinitionName + height: UM.Theme.getSize("setting_control").height + width: Math.round(parent.width * 0.7) + UM.Theme.getSize("sidebar_margin").width + anchors.right: parent.right + style: UM.Theme.styles.sidebar_header_button + activeFocusOnPress: true; + + menu: PrinterTypeMenu { } + } + } + + //Buildplate row + Item + { + id: buildplateRow + height: UM.Theme.getSize("sidebar_setup").height + visible: Cura.MachineManager.hasVariantBuildplates && !sidebar.monitoringPrint && !sidebar.hideSettings + + anchors + { + left: parent.left + leftMargin: UM.Theme.getSize("sidebar_margin").width + right: parent.right + rightMargin: UM.Theme.getSize("sidebar_margin").width + } + + Label + { + id: bulidplateLabel + text: catalog.i18nc("@label", "Build plate"); + width: Math.floor(parent.width * 0.45 - UM.Theme.getSize("default_margin").width) + height: parent.height + verticalAlignment: Text.AlignVCenter + font: UM.Theme.getFont("default"); + color: UM.Theme.getColor("text"); + } + + ToolButton { + id: buildplateSelection + text: Cura.MachineManager.activeVariantBuildplateName + tooltip: Cura.MachineManager.activeVariantBuildplateName + visible: Cura.MachineManager.hasVariantBuildplates + + height: UM.Theme.getSize("setting_control").height + width: Math.floor(parent.width * 0.7 + UM.Theme.getSize("sidebar_margin").width) + anchors.right: parent.right + style: UM.Theme.styles.sidebar_header_button + activeFocusOnPress: true; + + menu: BuildplateMenu {} + + property var valueError: !Cura.MachineManager.variantBuildplateCompatible && !Cura.MachineManager.variantBuildplateUsable + property var valueWarning: Cura.MachineManager.variantBuildplateUsable + } + } + + Rectangle { + id: headerSeparator + width: parent.width + visible: printerTypeSelectionRow.visible || buildplateRow.visible + height: visible ? UM.Theme.getSize("sidebar_lining").height : 0 + color: UM.Theme.getColor("sidebar_lining") + } + // Extruder Row Item { @@ -223,48 +318,7 @@ Column id: variantRowSpacer height: Math.round(UM.Theme.getSize("sidebar_margin").height / 4) width: height - visible: !extruderSelectionRow.visible - } - - // Printer Type Row - Item - { - id: printerTypeSelectionRow - height: UM.Theme.getSize("sidebar_setup").height - visible: printerConnected && hasManyPrinterTypes && !sidebar.monitoringPrint && !sidebar.hideSettings - - anchors - { - left: parent.left - leftMargin: UM.Theme.getSize("sidebar_margin").width - right: parent.right - rightMargin: UM.Theme.getSize("sidebar_margin").width - } - - Label - { - id: configurationLabel - text: catalog.i18nc("@label", "Printer type"); - width: Math.round(parent.width * 0.4 - UM.Theme.getSize("default_margin").width) - height: parent.height - verticalAlignment: Text.AlignVCenter - font: UM.Theme.getFont("default"); - color: UM.Theme.getColor("text"); - } - - ToolButton - { - id: printerTypeSelection - text: Cura.MachineManager.activeMachineDefinitionName - tooltip: Cura.MachineManager.activeMachineDefinitionName - height: UM.Theme.getSize("setting_control").height - width: Math.round(parent.width * 0.7) + UM.Theme.getSize("sidebar_margin").width - anchors.right: parent.right - style: UM.Theme.styles.sidebar_header_button - activeFocusOnPress: true; - - menu: PrinterTypeMenu { } - } + visible: !extruderSelectionRow.visible && !initialSeparator.visible } // Material Row @@ -371,64 +425,6 @@ Column } } - //Buildplate row separator - Rectangle { - id: separator - - anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width - anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width - anchors.horizontalCenter: parent.horizontalCenter - visible: buildplateRow.visible - width: parent.width - UM.Theme.getSize("sidebar_margin").width * 2 - height: visible ? Math.floor(UM.Theme.getSize("sidebar_lining_thin").height / 2) : 0 - color: UM.Theme.getColor("sidebar_lining_thin") - } - - //Buildplate row - Item - { - id: buildplateRow - height: UM.Theme.getSize("sidebar_setup").height - visible: Cura.MachineManager.hasVariantBuildplates && !sidebar.monitoringPrint && !sidebar.hideSettings - - anchors - { - left: parent.left - leftMargin: UM.Theme.getSize("sidebar_margin").width - right: parent.right - rightMargin: UM.Theme.getSize("sidebar_margin").width - } - - Label - { - id: bulidplateLabel - text: catalog.i18nc("@label", "Build plate"); - width: Math.floor(parent.width * 0.45 - UM.Theme.getSize("default_margin").width) - height: parent.height - verticalAlignment: Text.AlignVCenter - font: UM.Theme.getFont("default"); - color: UM.Theme.getColor("text"); - } - - ToolButton { - id: buildplateSelection - text: Cura.MachineManager.activeVariantBuildplateName - tooltip: Cura.MachineManager.activeVariantBuildplateName - visible: Cura.MachineManager.hasVariantBuildplates - - height: UM.Theme.getSize("setting_control").height - width: Math.floor(parent.width * 0.7 + UM.Theme.getSize("sidebar_margin").width) - anchors.right: parent.right - style: UM.Theme.styles.sidebar_header_button - activeFocusOnPress: true; - - menu: BuildplateMenu {} - - property var valueError: !Cura.MachineManager.variantBuildplateCompatible && !Cura.MachineManager.variantBuildplateUsable - property var valueWarning: Cura.MachineManager.variantBuildplateUsable - } - } - // Material info row Item { From e0e2d3362baae5e1d28422710f58111fc6b89ad0 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 12 Mar 2018 13:30:31 +0100 Subject: [PATCH 238/446] CURA-4400 fix for change in fdmprinter: move -1 from default_value to value --- plugins/CuraEngineBackend/StartSliceJob.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 63a345c13e..f3f34f4c3d 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -278,12 +278,12 @@ class StartSliceJob(Job): # \return A dictionary of replacement tokens to the values they should be # replaced with. def _buildReplacementTokens(self, stack) -> dict: - default_extruder_position = Application.getInstance().getMachineManager().defaultExtruderPosition + default_extruder_position = int(Application.getInstance().getMachineManager().defaultExtruderPosition) result = {} for key in stack.getAllKeys(): setting_type = stack.getProperty(key, "type") value = stack.getProperty(key, "value") - if setting_type == "extruder" and value == "-1": + if setting_type == "extruder" and value == -1: # replace with the default value value = default_extruder_position result[key] = value From d8897957210c50777b96cb5688c845ab91e88b19 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 12 Mar 2018 14:15:49 +0100 Subject: [PATCH 239/446] CURA-4400 correctly cope with quality changes that conflict with the current enabled extruders --- cura/Settings/ContainerManager.py | 3 +++ cura/Settings/MachineManager.py | 40 +++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index 2c94afccef..7161169b22 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -338,6 +338,9 @@ class ContainerManager(QObject): container.clear() send_emits_containers.append(container) + # user changes are possibly added to make the current setup match the current enabled extruders + Application.getInstance().getMachineManager().correctExtruderSettings() + for container in send_emits_containers: container.sendPostponedEmits() diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 2df8c0d967..2b581d833d 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -705,26 +705,42 @@ class MachineManager(QObject): if containers: return containers[0].definition.getId() - ## Update extruder number to a valid value when the number of extruders are changed, or when an extruder is changed - def correctExtruderSettings(self): + def getIncompatibleSettingsOnEnabledExtruders(self, container): extruder_count = self._global_container_stack.getProperty("machine_extruder_count", "value") - - # reset all extruder number settings whose value is no longer valid - for setting_instance in self._global_container_stack.userChanges.findInstances(): + result = [] + for setting_instance in container.findInstances(): setting_key = setting_instance.definition.key - enabled = self._global_container_stack.getProperty(setting_key, "enabled") - if not enabled: - self._global_container_stack.userChanges.removeInstance(setting_key) - Logger.log("d", "Reset setting [%s] because the setting is no longer enabled", setting_key) + setting_enabled = self._global_container_stack.getProperty(setting_key, "enabled") + if not setting_enabled: + # A setting is not visible anymore + result.append(setting_key) + Logger.log("d", "Reset setting [%s] from [%s] because the setting is no longer enabled", setting_key, container) continue if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"): continue - old_value = self._global_container_stack.userChanges.getProperty(setting_key, "value") + old_value = container.getProperty(setting_key, "value") if int(old_value) >= extruder_count or not self._global_container_stack.extruders[str(old_value)].isEnabled: - self._global_container_stack.userChanges.removeInstance(setting_key) - Logger.log("d", "Reset setting [%s] because its old value [%s] is no longer valid", setting_key, old_value) + result.append(setting_key) + Logger.log("d", "Reset setting [%s] in [%s] because its old value [%s] is no longer valid", setting_key, container, old_value) + return result + + ## Update extruder number to a valid value when the number of extruders are changed, or when an extruder is changed + def correctExtruderSettings(self): + for setting_key in self.getIncompatibleSettingsOnEnabledExtruders(self._global_container_stack.userChanges): + self._global_container_stack.userChanges.removeInstance(setting_key) + add_user_changes = self.getIncompatibleSettingsOnEnabledExtruders(self._global_container_stack.qualityChanges) + for setting_key in add_user_changes: + # Apply quality changes that are incompatible to user changes, so we do not change the quality changes itself. + self._global_container_stack.userChanges.setProperty(setting_key, "value", self._default_extruder_position) + if add_user_changes: + caution_message = Message(catalog.i18nc( + "@info:generic", + "Settings have been changed to match the current availability of extruders: [%s]" % ", ".join(add_user_changes)), + lifetime=0, + title = catalog.i18nc("@info:title", "Settings updated")) + caution_message.show() ## Set the amount of extruders on the active machine (global stack) # \param extruder_count int the number of extruders to set From cc009a94eef9b2cd3970423ba5435d45cc59c8e7 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 12 Mar 2018 14:19:06 +0100 Subject: [PATCH 240/446] CURA-4870 Remove "check compatibility" message. Move the buildplate information to the bottom, below the extruders. --- resources/qml/SidebarHeader.qml | 136 +++++++++----------------------- 1 file changed, 39 insertions(+), 97 deletions(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 2323202305..c93dd3a89b 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -78,55 +78,10 @@ Column } } - //Buildplate row - Item - { - id: buildplateRow - height: UM.Theme.getSize("sidebar_setup").height - visible: Cura.MachineManager.hasVariantBuildplates && !sidebar.monitoringPrint && !sidebar.hideSettings - - anchors - { - left: parent.left - leftMargin: UM.Theme.getSize("sidebar_margin").width - right: parent.right - rightMargin: UM.Theme.getSize("sidebar_margin").width - } - - Label - { - id: bulidplateLabel - text: catalog.i18nc("@label", "Build plate"); - width: Math.floor(parent.width * 0.45 - UM.Theme.getSize("default_margin").width) - height: parent.height - verticalAlignment: Text.AlignVCenter - font: UM.Theme.getFont("default"); - color: UM.Theme.getColor("text"); - } - - ToolButton { - id: buildplateSelection - text: Cura.MachineManager.activeVariantBuildplateName - tooltip: Cura.MachineManager.activeVariantBuildplateName - visible: Cura.MachineManager.hasVariantBuildplates - - height: UM.Theme.getSize("setting_control").height - width: Math.floor(parent.width * 0.7 + UM.Theme.getSize("sidebar_margin").width) - anchors.right: parent.right - style: UM.Theme.styles.sidebar_header_button - activeFocusOnPress: true; - - menu: BuildplateMenu {} - - property var valueError: !Cura.MachineManager.variantBuildplateCompatible && !Cura.MachineManager.variantBuildplateUsable - property var valueWarning: Cura.MachineManager.variantBuildplateUsable - } - } - Rectangle { id: headerSeparator width: parent.width - visible: printerTypeSelectionRow.visible || buildplateRow.visible + visible: printerTypeSelectionRow.visible height: visible ? UM.Theme.getSize("sidebar_lining").height : 0 color: UM.Theme.getColor("sidebar_lining") } @@ -425,12 +380,22 @@ Column } } - // Material info row + Rectangle { + id: buildplateSeparator + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width + width: parent.width - 2 * UM.Theme.getSize("sidebar_margin").width + visible: buildplateRow.visible + height: visible ? UM.Theme.getSize("sidebar_lining_thin").height : 0 + color: UM.Theme.getColor("sidebar_lining") + } + + //Buildplate row Item { - id: materialInfoRow - height: Math.round(UM.Theme.getSize("sidebar_setup").height / 2) - visible: (Cura.MachineManager.hasVariants || Cura.MachineManager.hasMaterials) && !sidebar.monitoringPrint && !sidebar.hideSettings + id: buildplateRow + height: UM.Theme.getSize("sidebar_setup").height + visible: Cura.MachineManager.hasVariantBuildplates && !sidebar.monitoringPrint && !sidebar.hideSettings anchors { @@ -440,56 +405,33 @@ Column rightMargin: UM.Theme.getSize("sidebar_margin").width } - Item { - height: UM.Theme.getSize("sidebar_setup").height + Label + { + id: bulidplateLabel + text: catalog.i18nc("@label", "Build plate"); + width: Math.floor(parent.width * 0.45 - UM.Theme.getSize("default_margin").width) + height: parent.height + verticalAlignment: Text.AlignVCenter + font: UM.Theme.getFont("default"); + color: UM.Theme.getColor("text"); + } + + ToolButton { + id: buildplateSelection + text: Cura.MachineManager.activeVariantBuildplateName + tooltip: Cura.MachineManager.activeVariantBuildplateName + visible: Cura.MachineManager.hasVariantBuildplates + + height: UM.Theme.getSize("setting_control").height + width: Math.floor(parent.width * 0.7 + UM.Theme.getSize("sidebar_margin").width) anchors.right: parent.right - width: Math.round(parent.width * 0.7 + UM.Theme.getSize("sidebar_margin").width) + style: UM.Theme.styles.sidebar_header_button + activeFocusOnPress: true; - UM.RecolorImage { - id: warningImage - anchors.right: materialInfoLabel.left - anchors.rightMargin: UM.Theme.getSize("default_margin").width - anchors.verticalCenter: parent.Bottom - source: UM.Theme.getIcon("warning") - width: UM.Theme.getSize("section_icon").width - height: UM.Theme.getSize("section_icon").height - color: UM.Theme.getColor("material_compatibility_warning") - visible: !Cura.MachineManager.isCurrentSetupSupported - } + menu: BuildplateMenu {} - Label { - id: materialInfoLabel - wrapMode: Text.WordWrap - text: "" + catalog.i18nc("@label", "Check compatibility") + "" - font: UM.Theme.getFont("default") - color: UM.Theme.getColor("text") - linkColor: UM.Theme.getColor("text_link") - verticalAlignment: Text.AlignTop - anchors.top: parent.top - anchors.right: parent.right - anchors.bottom: parent.bottom - - MouseArea { - anchors.fill: parent - hoverEnabled: true - onClicked: { - // open the material URL with web browser - var version = UM.Application.version; - var machineName = Cura.MachineManager.activeMachine.definition.id; - var url = "https://ultimaker.com/materialcompatibility/" + version + "/" + machineName + "?utm_source=cura&utm_medium=software&utm_campaign=resources"; - Qt.openUrlExternally(url); - } - onEntered: { - var content = catalog.i18nc("@tooltip", "Click to check the material compatibility on Ultimaker.com."); - base.showTooltip( - materialInfoRow, - Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0), - catalog.i18nc("@tooltip", content) - ); - } - onExited: base.hideTooltip(); - } - } + property var valueError: !Cura.MachineManager.variantBuildplateCompatible && !Cura.MachineManager.variantBuildplateUsable + property var valueWarning: Cura.MachineManager.variantBuildplateUsable } } From a5ba4799f0ce613b92414db66b278036d4e88ffc Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Mon, 12 Mar 2018 14:48:39 +0100 Subject: [PATCH 241/446] CURA-4870 Final icon changes from Luke --- .../qml/Menus/ConfigurationMenu/SyncButton.qml | 6 +++--- resources/qml/Menus/PrinterStatusIcon.qml | 4 ++-- resources/themes/cura-light/icons/connected.svg | 15 +++------------ .../themes/cura-light/icons/disconnected.svg | 15 ++++----------- resources/themes/cura-light/theme.json | 9 +++------ 5 files changed, 15 insertions(+), 34 deletions(-) diff --git a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml index d22dcb1247..3748fd0cb4 100644 --- a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml +++ b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml @@ -70,11 +70,11 @@ Button anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.verticalCenter: parent.verticalCenter; - width: UM.Theme.getSize("printer_status_icon").width - height: UM.Theme.getSize("printer_status_icon").height + width: UM.Theme.getSize("printer_sync_icon").width + height: UM.Theme.getSize("printer_sync_icon").height color: control.matched ? UM.Theme.getColor("printer_config_matched") : UM.Theme.getColor("printer_config_mismatch") - source: control.matched ? UM.Theme.getIcon("tab_status_connected") : UM.Theme.getIcon("tab_status_unknown") + source: UM.Theme.getIcon("tab_status_connected") sourceSize.width: width sourceSize.height: height } diff --git a/resources/qml/Menus/PrinterStatusIcon.qml b/resources/qml/Menus/PrinterStatusIcon.qml index c76ed8bdcb..f66834d0c0 100644 --- a/resources/qml/Menus/PrinterStatusIcon.qml +++ b/resources/qml/Menus/PrinterStatusIcon.qml @@ -16,8 +16,8 @@ Item { height: UM.Theme.getSize("printer_status_icon").height sourceSize.width: width sourceSize.height: width - color: UM.Theme.getColor("tab_status_" + parent.status ) - source: UM.Theme.getIcon( parent.status ) + color: UM.Theme.getColor("tab_status_" + parent.status) + source: UM.Theme.getIcon(parent.status) } } diff --git a/resources/themes/cura-light/icons/connected.svg b/resources/themes/cura-light/icons/connected.svg index 4f0f10bff4..18423bb6c4 100644 --- a/resources/themes/cura-light/icons/connected.svg +++ b/resources/themes/cura-light/icons/connected.svg @@ -1,14 +1,5 @@ - - Created with Sketch. - - - - - - - - - - + + + \ No newline at end of file diff --git a/resources/themes/cura-light/icons/disconnected.svg b/resources/themes/cura-light/icons/disconnected.svg index 2a045c5f1d..019dff117e 100644 --- a/resources/themes/cura-light/icons/disconnected.svg +++ b/resources/themes/cura-light/icons/disconnected.svg @@ -1,13 +1,6 @@ - - Created with Sketch. - - - - - - - - - + + + + \ No newline at end of file diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json index ce6b406d3d..c0b71ac618 100644 --- a/resources/themes/cura-light/theme.json +++ b/resources/themes/cura-light/theme.json @@ -309,15 +309,11 @@ "configuration_item_border_active": [12, 169, 227, 32], "configuration_item_border_hover": [12, 169, 227, 255], - "tab_status_busy": [255, 255, 255, 255], "tab_status_connected": [12, 169, 227, 255], - "tab_status_finished": [255, 255, 255, 255], - "tab_status_paused": [255, 255, 255, 255], - "tab_status_stopped": [255, 255, 255, 255], "tab_status_disconnected": [200, 200, 200, 255], "printer_config_matched": [12, 169, 227, 255], - "printer_config_mismatch": [255, 145, 62, 255] + "printer_config_mismatch": [127, 127, 127, 255] }, "sizes": { @@ -370,7 +366,8 @@ "small_button": [2, 2], "small_button_icon": [1.5, 1.5], - "printer_status_icon": [1.2, 1.2], + "printer_status_icon": [1.8, 1.8], + "printer_sync_icon": [1.2, 1.2], "topbar_logo_right_margin": [3, 0], "topbar_button": [8, 4], From bb7fccbd486f076fba3e5a535e207d1c3f56d521 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 14:48:28 +0100 Subject: [PATCH 242/446] Add logging for every setting model update You can clearly see that some models are updated 4 times or so now. Contributes to issue CURA-4606. --- cura/Machines/Models/BrandMaterialsModel.py | 5 +++-- cura/Machines/Models/BuildPlateModel.py | 2 ++ .../Models/CustomQualityProfilesDropDownMenuModel.py | 2 +- cura/Machines/Models/GenericMaterialsModel.py | 5 ++++- cura/Machines/Models/MaterialManagementModel.py | 5 ++++- cura/Machines/Models/NozzleModel.py | 3 +++ cura/Machines/Models/QualityManagementModel.py | 4 +++- cura/Machines/Models/QualityProfilesDropDownMenuModel.py | 2 +- cura/Machines/Models/QualitySettingsModel.py | 2 ++ 9 files changed, 23 insertions(+), 7 deletions(-) diff --git a/cura/Machines/Models/BrandMaterialsModel.py b/cura/Machines/Models/BrandMaterialsModel.py index 1146a8acee..7c3c4c515d 100644 --- a/cura/Machines/Models/BrandMaterialsModel.py +++ b/cura/Machines/Models/BrandMaterialsModel.py @@ -4,8 +4,8 @@ from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty from UM.Qt.ListModel import ListModel - -from .BaseMaterialsModel import BaseMaterialsModel +from UM.Logger import Logger +from cura.Machines.Models.BaseMaterialsModel import BaseMaterialsModel # @@ -69,6 +69,7 @@ class BrandMaterialsModel(ListModel): return self._extruder_position def _update(self): + Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) global_stack = self._machine_manager.activeMachine if global_stack is None: self.setItems([]) diff --git a/cura/Machines/Models/BuildPlateModel.py b/cura/Machines/Models/BuildPlateModel.py index 1cb94216a6..e1b4f40d8e 100644 --- a/cura/Machines/Models/BuildPlateModel.py +++ b/cura/Machines/Models/BuildPlateModel.py @@ -4,6 +4,7 @@ from PyQt5.QtCore import Qt from UM.Application import Application +from UM.Logger import Logger from UM.Qt.ListModel import ListModel from UM.Util import parseBool @@ -29,6 +30,7 @@ class BuildPlateModel(ListModel): self._update() def _update(self): + Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) global_stack = self._machine_manager._global_container_stack if not global_stack: self.setItems([]) diff --git a/cura/Machines/Models/CustomQualityProfilesDropDownMenuModel.py b/cura/Machines/Models/CustomQualityProfilesDropDownMenuModel.py index a188a43e72..dcade8cb0d 100644 --- a/cura/Machines/Models/CustomQualityProfilesDropDownMenuModel.py +++ b/cura/Machines/Models/CustomQualityProfilesDropDownMenuModel.py @@ -12,7 +12,7 @@ from cura.Machines.Models.QualityProfilesDropDownMenuModel import QualityProfile class CustomQualityProfilesDropDownMenuModel(QualityProfilesDropDownMenuModel): def _update(self): - Logger.log("d", "Updating %s ...", self.__class__.__name__) + Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) active_global_stack = self._machine_manager.activeMachine if active_global_stack is None: diff --git a/cura/Machines/Models/GenericMaterialsModel.py b/cura/Machines/Models/GenericMaterialsModel.py index 47240ebffd..03343ba53b 100644 --- a/cura/Machines/Models/GenericMaterialsModel.py +++ b/cura/Machines/Models/GenericMaterialsModel.py @@ -1,7 +1,8 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from .BaseMaterialsModel import BaseMaterialsModel +from UM.Logger import Logger +from cura.Machines.Models.BaseMaterialsModel import BaseMaterialsModel class GenericMaterialsModel(BaseMaterialsModel): @@ -21,6 +22,8 @@ class GenericMaterialsModel(BaseMaterialsModel): self._update() def _update(self): + Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) + global_stack = self._machine_manager.activeMachine if global_stack is None: self.setItems([]) diff --git a/cura/Machines/Models/MaterialManagementModel.py b/cura/Machines/Models/MaterialManagementModel.py index 1ea0fd9cf7..46e9cb887a 100644 --- a/cura/Machines/Models/MaterialManagementModel.py +++ b/cura/Machines/Models/MaterialManagementModel.py @@ -1,8 +1,9 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from PyQt5.QtCore import Qt, pyqtProperty +from PyQt5.QtCore import Qt +from UM.Logger import Logger from UM.Qt.ListModel import ListModel @@ -60,6 +61,8 @@ class MaterialManagementModel(ListModel): self._update() def _update(self): + Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) + global_stack = self._machine_manager.activeMachine if global_stack is None: self.setItems([]) diff --git a/cura/Machines/Models/NozzleModel.py b/cura/Machines/Models/NozzleModel.py index 27d190962b..d4f9861e9d 100644 --- a/cura/Machines/Models/NozzleModel.py +++ b/cura/Machines/Models/NozzleModel.py @@ -4,6 +4,7 @@ from PyQt5.QtCore import Qt from UM.Application import Application +from UM.Logger import Logger from UM.Qt.ListModel import ListModel from UM.Util import parseBool @@ -26,6 +27,8 @@ class NozzleModel(ListModel): Application.getInstance().getMachineManager().activeMaterialChanged.connect(self._update) def _update(self): + Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) + self.items.clear() variant_manager = Application.getInstance()._variant_manager diff --git a/cura/Machines/Models/QualityManagementModel.py b/cura/Machines/Models/QualityManagementModel.py index 542016ab68..4d2b551805 100644 --- a/cura/Machines/Models/QualityManagementModel.py +++ b/cura/Machines/Models/QualityManagementModel.py @@ -4,7 +4,7 @@ from PyQt5.QtCore import Qt, pyqtSlot from UM.Qt.ListModel import ListModel - +from UM.Logger import Logger # # This the QML model for the quality management page. @@ -35,6 +35,8 @@ class QualityManagementModel(ListModel): self._update() def _update(self): + Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) + global_stack = self._machine_manager.activeMachine quality_group_dict = self._quality_manager.getQualityGroups(global_stack) diff --git a/cura/Machines/Models/QualityProfilesDropDownMenuModel.py b/cura/Machines/Models/QualityProfilesDropDownMenuModel.py index fd919639c3..40fdaaa410 100644 --- a/cura/Machines/Models/QualityProfilesDropDownMenuModel.py +++ b/cura/Machines/Models/QualityProfilesDropDownMenuModel.py @@ -46,7 +46,7 @@ class QualityProfilesDropDownMenuModel(ListModel): self._update() def _update(self): - Logger.log("d", "Updating quality profile model ...") + Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) global_stack = self._machine_manager.activeMachine if global_stack is None: diff --git a/cura/Machines/Models/QualitySettingsModel.py b/cura/Machines/Models/QualitySettingsModel.py index e0b29d77a5..15ebe37f05 100644 --- a/cura/Machines/Models/QualitySettingsModel.py +++ b/cura/Machines/Models/QualitySettingsModel.py @@ -69,6 +69,8 @@ class QualitySettingsModel(ListModel): return self._selected_quality_item def _update(self): + Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) + if not self._selected_quality_item: self.setItems([]) return From 809db6a4d9f5073dc9112c5f7f0b4281f67278fe Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 12 Mar 2018 15:09:56 +0100 Subject: [PATCH 243/446] CURA-5078 Remove material warning if the mismatch was the buildplate. --- cura/Settings/MachineManager.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index b09ff9e8bd..144f495997 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -919,21 +919,11 @@ class MachineManager(QObject): def activeMaterialsCompatible(self): # check material - variant compatibility - result = True - machine_has_buildplate = Util.parseBool(self._global_container_stack.getMetaDataEntry("has_variant_buildplates", False)) if Util.parseBool(self._global_container_stack.getMetaDataEntry("has_materials", False)): for position, extruder in self._global_container_stack.extruders.items(): if not extruder.material.getMetaDataEntry("compatible"): - result = False - break - if machine_has_buildplate: - buildplate_compatibility_dict = extruder.material.getMetaDataEntry("buildplate_compatible") - if buildplate_compatibility_dict: - buildplate_name = self._global_container_stack.variant.getName() - result = buildplate_compatibility_dict.get(buildplate_name, True) - if not result: - break - return result + return False + return True ## Update current quality type and machine after setting material def _updateQualityWithMaterial(self): From da54c93fda6a9c795020607d69718e292524cfb6 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 12 Mar 2018 15:12:27 +0100 Subject: [PATCH 244/446] CURA-4870 Remove commented code --- cura/Settings/MachineManager.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index ba93810b7c..7753dfced1 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -201,9 +201,6 @@ class MachineManager(QObject): @pyqtSlot(QObject, result = bool) def matchesConfiguration(self, configuration: ConfigurationModel) -> bool: - # print(configuration) - # print(self._current_printer_configuration) - # print("%%%%%%%%", configuration == self._current_printer_configuration) return self._current_printer_configuration == configuration @pyqtProperty("QVariantList", notify = outputDevicesChanged) From c3b659c5d4f8b1e63ee97f5883233ed09607717a Mon Sep 17 00:00:00 2001 From: Aleksei S Date: Mon, 12 Mar 2018 15:15:19 +0100 Subject: [PATCH 245/446] Fix: reset icon dissapears for default values CURA-5059 --- resources/qml/Settings/SettingView.qml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 615e66277b..2334033de8 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -372,10 +372,8 @@ Item containerStackId: Cura.MachineManager.activeMachineId key: model.key ? model.key : "" - watchedProperties: [ "value", "enabled", "state", "validationState", "settable_per_extruder", "resolve" ] + watchedProperties: [ "value", "enabled", "state", "validationState", "settable_per_extruder" ] storeIndex: 0 - // Due to the way setPropertyValue works, removeUnusedValue gives the correct output in case of resolve - removeUnusedValue: model.resolve == undefined } Connections From 220e4a64c6e9a11425f7d0ec6c0e81868002fd4c Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 12 Mar 2018 15:23:49 +0100 Subject: [PATCH 246/446] Fix VariantManager.getVariant() and simplify NozzleModel CURA-4606 --- cura/Machines/Models/NozzleModel.py | 22 +++++++++++++--------- cura/Machines/VariantManager.py | 12 ++++++++++-- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/cura/Machines/Models/NozzleModel.py b/cura/Machines/Models/NozzleModel.py index d4f9861e9d..d178b39475 100644 --- a/cura/Machines/Models/NozzleModel.py +++ b/cura/Machines/Models/NozzleModel.py @@ -21,28 +21,32 @@ class NozzleModel(ListModel): self.addRoleName(self.HotendNameRole, "hotend_name") self.addRoleName(self.ContainerNodeRole, "container_node") - Application.getInstance().globalContainerStackChanged.connect(self._update) - Application.getInstance().getMachineManager().activeVariantChanged.connect(self._update) - Application.getInstance().getMachineManager().activeStackChanged.connect(self._update) - Application.getInstance().getMachineManager().activeMaterialChanged.connect(self._update) + self._application = Application.getInstance() + self._machine_manager = self._application.getMachineManager() + self._variant_manager = self._application.getVariantManager() + + self._machine_manager.globalContainerChanged.connect(self._update) + self._machine_manager.activeVariantChanged.connect(self._update) + self._machine_manager.activeStackChanged.connect(self._update) + self._machine_manager.activeMaterialChanged.connect(self._update) def _update(self): Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) self.items.clear() - variant_manager = Application.getInstance()._variant_manager - active_global_stack = Application.getInstance().getMachineManager()._global_container_stack - if active_global_stack is None: + global_stack = self._machine_manager.activeMachine + if global_stack is None: self.setItems([]) return - has_variants = parseBool(active_global_stack.getMetaDataEntry("has_variants", False)) + has_variants = parseBool(global_stack.getMetaDataEntry("has_variants", False)) if not has_variants: self.setItems([]) return - variant_node_dict = variant_manager.getVariantNodes(active_global_stack) + from cura.Machines.VariantManager import VariantType + variant_node_dict = self._variant_manager.getVariantNodes(global_stack, VariantType.NOZZLE) if not variant_node_dict: self.setItems([]) return diff --git a/cura/Machines/VariantManager.py b/cura/Machines/VariantManager.py index 6cb0a3d7b2..1e6dcfe838 100644 --- a/cura/Machines/VariantManager.py +++ b/cura/Machines/VariantManager.py @@ -83,11 +83,19 @@ class VariantManager: # Almost the same as getVariantMetadata() except that this returns an InstanceContainer if present. # def getVariantNode(self, machine_definition_id: str, variant_name: str, - variant_type: Optional["VariantType"] = VariantType.NOZZLE) -> Optional["ContainerNode"]: + variant_type: Optional["VariantType"] = None) -> Optional["ContainerNode"]: + if variant_type is None: + variant_node = None + variant_type_dict = self._machine_to_variant_dict_map[machine_definition_id] + for variant_dict in variant_type_dict.values(): + if variant_name in variant_dict: + variant_node = variant_dict[variant_name] + break + return variant_node return self._machine_to_variant_dict_map[machine_definition_id].get(variant_type, {}).get(variant_name) def getVariantNodes(self, machine: "GlobalStack", - variant_type: Optional["VariantType"] = VariantType.NOZZLE) -> dict: + variant_type: Optional["VariantType"] = None) -> dict: machine_definition_id = machine.definition.getId() return self._machine_to_variant_dict_map.get(machine_definition_id, {}).get(variant_type, {}) From c54679ba2d76ff4febb85e56e0710c5f4e2c3a4b Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 12 Mar 2018 15:25:07 +0100 Subject: [PATCH 247/446] Gix buildplate handling in Material profile CURA-4606 --- .../XmlMaterialProfile/XmlMaterialProfile.py | 85 +++++++++++++------ 1 file changed, 60 insertions(+), 25 deletions(-) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index e8d0c9d2f0..bbf5dfe2ba 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -205,7 +205,7 @@ class XmlMaterialProfile(InstanceContainer): self._addSettingElement(builder, instance) machine_container_map = {} - machine_nozzle_map = {} + machine_variant_map = {} variant_manager = CuraApplication.getInstance().getVariantManager() material_manager = CuraApplication.getInstance().getMaterialManager() @@ -225,13 +225,14 @@ class XmlMaterialProfile(InstanceContainer): if definition_id not in machine_container_map: machine_container_map[definition_id] = container - if definition_id not in machine_nozzle_map: - machine_nozzle_map[definition_id] = {} + if definition_id not in machine_variant_map: + machine_variant_map[definition_id] = {} variant_name = container.getMetaDataEntry("variant_name") if variant_name: - machine_nozzle_map[definition_id][variant_name] = variant_manager.getVariantNode(definition_id, - variant_name) + variant_dict = {"variant_node": variant_manager.getVariantNode(definition_id, variant_name), + "material_container": container} + machine_variant_map[definition_id][variant_name] = variant_dict continue machine_container_map[definition_id] = container @@ -265,28 +266,60 @@ class XmlMaterialProfile(InstanceContainer): self._addSettingElement(builder, instance) # Find all hotend sub-profiles corresponding to this material and machine and add them to this profile. - for hotend_name, variant_node in machine_nozzle_map[definition_id].items(): - # The hotend identifier is not the containers name, but its "name". - builder.start("hotend", {"id": hotend_name}) + buildplate_dict = {} + for variant_name, variant_dict in machine_variant_map[definition_id].items(): + variant_type = variant_dict["variant_node"].metadata["hardware_type"] + from cura.Machines.VariantManager import VariantType + variant_type = VariantType(variant_type) + if variant_type == VariantType.NOZZLE: + # The hotend identifier is not the containers name, but its "name". + builder.start("hotend", {"id": variant_name}) - # Compatible is a special case, as it's added as a meta data entry (instead of an instance). - compatible = variant_node.metadata.get("compatible") - if compatible is not None: - builder.start("setting", {"key": "hardware compatible"}) - if compatible: - builder.data("yes") - else: - builder.data("no") - builder.end("setting") + # Compatible is a special case, as it's added as a meta data entry (instead of an instance). + material_container = variant_dict["material_container"] + compatible = container.getMetaDataEntry("compatible") + if compatible is not None: + builder.start("setting", {"key": "hardware compatible"}) + if compatible: + builder.data("yes") + else: + builder.data("no") + builder.end("setting") - for instance in variant_node.getContainer().findInstances(): - if container.getInstance(instance.definition.key) and container.getProperty(instance.definition.key, "value") == instance.value: - # If the settings match that of the machine profile, just skip since we inherit the machine profile. - continue + for instance in material_container.findInstances(): + if container.getInstance(instance.definition.key) and container.getProperty(instance.definition.key, "value") == instance.value: + # If the settings match that of the machine profile, just skip since we inherit the machine profile. + continue - self._addSettingElement(builder, instance) + self._addSettingElement(builder, instance) - builder.end("hotend") + if material_container.getMetaDataEntry("buildplate_compatible") and not buildplate_dict: + buildplate_dict["buildplate_compatible"] = material_container.getMetaDataEntry("buildplate_compatible") + buildplate_dict["buildplate_recommended"] = material_container.getMetaDataEntry("buildplate_recommended") + buildplate_dict["material_container"] = material_container + + builder.end("hotend") + + if buildplate_dict: + for variant_name in buildplate_dict["buildplate_compatible"]: + builder.start("buildplate", {"id": variant_name}) + + material_container = buildplate_dict["material_container"] + buildplate_compatible_dict = material_container.getMetaDataEntry("buildplate_compatible") + buildplate_recommended_dict = material_container.getMetaDataEntry("buildplate_recommended") + if buildplate_compatible_dict: + compatible = buildplate_compatible_dict[variant_name] + recommended = buildplate_recommended_dict[variant_name] + + builder.start("setting", {"key": "hardware compatible"}) + builder.data("yes" if compatible else "no") + builder.end("setting") + + builder.start("setting", {"key": "hardware recommended"}) + builder.data("yes" if recommended else "no") + builder.end("setting") + + builder.end("buildplate") builder.end("machine") @@ -842,6 +875,8 @@ class XmlMaterialProfile(InstanceContainer): continue settings = buildplate.iterfind("./um:setting", cls.__namespaces) + buildplate_compatibility = True + buildplate_recommended = True for entry in settings: key = entry.get("key") if key == "hardware compatible": @@ -849,8 +884,8 @@ class XmlMaterialProfile(InstanceContainer): elif key == "hardware recommended": buildplate_recommended = cls._parseCompatibleValue(entry.text) - buildplate_map["buildplate_compatible"][buildplate_id] = buildplate_map["buildplate_compatible"] - buildplate_map["buildplate_recommended"][buildplate_id] = buildplate_map["buildplate_recommended"] + buildplate_map["buildplate_compatible"][buildplate_id] = buildplate_compatibility + buildplate_map["buildplate_recommended"][buildplate_id] = buildplate_recommended for hotend in machine.iterfind("./um:hotend", cls.__namespaces): hotend_name = hotend.get("id") From 1512a8096b1e7d2e3c570675e42ae7086da32fdd Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 15:43:25 +0100 Subject: [PATCH 248/446] Require MaterialGroup to always have a base material The material group is loaded lazily whenever the base material is not yet in the dictionary. Contributes to issue CURA-4606. --- cura/Machines/MaterialGroup.py | 11 ++++++----- cura/Machines/MaterialManager.py | 16 +++++++--------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/cura/Machines/MaterialGroup.py b/cura/Machines/MaterialGroup.py index 009778943a..07b790c6bc 100644 --- a/cura/Machines/MaterialGroup.py +++ b/cura/Machines/MaterialGroup.py @@ -1,9 +1,10 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from typing import List +from cura.Machines.MaterialNode import MaterialNode #For type checking. -# -# A MaterialGroup represents a group of material InstanceContainers that are derived from a single material profile. +## A MaterialGroup represents a group of material InstanceContainers that are derived from a single material profile. # The main InstanceContainer which has the ID of the material profile file name is called the "root_material". For # example: "generic_abs" is the root material (ID) of "generic_abs_ultimaker3" and "generic_abs_ultimaker3_AA_0.4", # and "generic_abs_ultimaker3" and "generic_abs_ultimaker3_AA_0.4" are derived materials of "generic_abs". @@ -17,10 +18,10 @@ class MaterialGroup: __slots__ = ("name", "root_material_node", "derived_material_node_list") - def __init__(self, name: str): + def __init__(self, name: str, root_material_node: MaterialNode): self.name = name - self.root_material_node = None - self.derived_material_node_list = [] + self.root_material_node = root_material_node + self.derived_material_node_list = [] #type: List[MaterialNode] def __str__(self) -> str: return "%s[%s]" % (self.__class__.__name__, self.name) diff --git a/cura/Machines/MaterialManager.py b/cura/Machines/MaterialManager.py index 7c205c0084..b01d360ab6 100644 --- a/cura/Machines/MaterialManager.py +++ b/cura/Machines/MaterialManager.py @@ -72,29 +72,27 @@ class MaterialManager(QObject): def initialize(self): # Find all materials and put them in a matrix for quick search. - material_metadata_list = self._container_registry.findContainersMetadata(type = "material") + material_metadatas = {metadata["id"]: metadata for metadata in self._container_registry.findContainersMetadata(type = "material")} self._material_group_map = dict() # Map #1 # root_material_id -> MaterialGroup - for material_metadata in material_metadata_list: - material_id = material_metadata["id"] + for material_id, material_metadata in material_metadatas.items(): # We don't store empty material in the lookup tables if material_id == "empty_material": continue root_material_id = material_metadata.get("base_file") if root_material_id not in self._material_group_map: - self._material_group_map[root_material_id] = MaterialGroup(root_material_id) + self._material_group_map[root_material_id] = MaterialGroup(root_material_id, MaterialNode(material_metadatas[root_material_id])) group = self._material_group_map[root_material_id] - # We only add root materials here - if material_id == root_material_id: - group.root_material_node = MaterialNode(material_metadata) - else: + #Store this material in the group of the appropriate root material. + if material_id != root_material_id: new_node = MaterialNode(material_metadata) group.derived_material_node_list.append(new_node) + # Order this map alphabetically so it's easier to navigate in a debugger self._material_group_map = OrderedDict(sorted(self._material_group_map.items(), key = lambda x: x[0])) @@ -179,7 +177,7 @@ class MaterialManager(QObject): # "machine" -> "variant_name" -> "root material ID" -> specific material InstanceContainer # Construct the "machine" -> "variant" -> "root material ID" -> specific material InstanceContainer self._diameter_machine_variant_material_map = dict() - for material_metadata in material_metadata_list: + for material_metadata in material_metadatas.values(): # We don't store empty material in the lookup tables if material_metadata["id"] == "empty_material": continue From 7574ab088357b2a27708f6306058f6b4e4f9224f Mon Sep 17 00:00:00 2001 From: Aleksei S Date: Mon, 12 Mar 2018 15:52:16 +0100 Subject: [PATCH 249/446] Connect infill Lines checkbox did not work --- resources/qml/Settings/SettingView.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 2334033de8..7a967e211c 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -372,7 +372,7 @@ Item containerStackId: Cura.MachineManager.activeMachineId key: model.key ? model.key : "" - watchedProperties: [ "value", "enabled", "state", "validationState", "settable_per_extruder" ] + watchedProperties: [ "value", "enabled", "state", "validationState", "settable_per_extruder", "resolve" ] storeIndex: 0 } From 05c034558dfe88e4c3ca6e12b023ff1291baea27 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 16:03:42 +0100 Subject: [PATCH 250/446] Set default layer height via preferred quality type So the layer heights are correct for each quality type but the default is still 0.2mm. Contributes to issue CURA-4981. --- resources/definitions/ubuild-3d_mr_bot_280.def.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/definitions/ubuild-3d_mr_bot_280.def.json b/resources/definitions/ubuild-3d_mr_bot_280.def.json index 7f9069370c..4febdcd350 100644 --- a/resources/definitions/ubuild-3d_mr_bot_280.def.json +++ b/resources/definitions/ubuild-3d_mr_bot_280.def.json @@ -11,7 +11,8 @@ "file_formats": "text/x-gcode", "icon": "icon_uBuild-3D", "platform": "mr_bot_280_platform.stl", - "has_materials": true + "has_materials": true, + "preferred_quality_type": "draft" }, "overrides": { @@ -24,7 +25,6 @@ "material_diameter": { "default_value": 1.75 }, "material_bed_temperature": { "default_value": 70 }, "machine_nozzle_size": { "default_value": 0.4 }, - "layer_height": { "default_value": 0.2 }, "layer_height_0": { "default_value": 0.1 }, "retraction_amount": { "default_value": 2 }, "retraction_speed": { "default_value": 50 }, From 1f08accbecf117b5590d1fb417d16854ac564193 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 12 Mar 2018 16:14:35 +0100 Subject: [PATCH 251/446] Fix profile importing for version upgrade CURA-4946 --- cura/Settings/CuraContainerRegistry.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index 4b576a4207..828897b4dd 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -241,7 +241,7 @@ class CuraContainerRegistry(ContainerRegistry): profile.addMetaDataEntry("type", "quality_changes") profile.addMetaDataEntry("definition", global_profile.getMetaDataEntry("definition")) profile.addMetaDataEntry("quality_type", global_profile.getMetaDataEntry("quality_type")) - profile.addMetaDataEntry("extruder", extruder.getId()) + profile.addMetaDataEntry("position", "0") profile.setDirty(True) if idx == 0: # move all per-extruder settings to the first extruder's quality_changes @@ -273,10 +273,11 @@ class CuraContainerRegistry(ContainerRegistry): elif profile_index < len(machine_extruders) + 1: # This is assumed to be an extruder profile extruder_id = machine_extruders[profile_index - 1].definition.getId() - if not profile.getMetaDataEntry("extruder"): - profile.addMetaDataEntry("extruder", extruder_id) + extuder_position = str(profile_index - 1) + if not profile.getMetaDataEntry("position"): + profile.addMetaDataEntry("position", extuder_position) else: - profile.setMetaDataEntry("extruder", extruder_id) + profile.setMetaDataEntry("position", extuder_position) profile_id = (extruder_id + "_" + name_seed).lower().replace(" ", "_") else: #More extruders in the imported file than in the machine. From 00783401752a3bbc661fc6d65c15f6fd7861bdee Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 16:19:28 +0100 Subject: [PATCH 252/446] Only update NozzleModel when machine changes The available nozzles only change upon changing machines. Contributes to issue CURA-4606. --- cura/Machines/Models/NozzleModel.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cura/Machines/Models/NozzleModel.py b/cura/Machines/Models/NozzleModel.py index d178b39475..0879998b7d 100644 --- a/cura/Machines/Models/NozzleModel.py +++ b/cura/Machines/Models/NozzleModel.py @@ -26,9 +26,7 @@ class NozzleModel(ListModel): self._variant_manager = self._application.getVariantManager() self._machine_manager.globalContainerChanged.connect(self._update) - self._machine_manager.activeVariantChanged.connect(self._update) - self._machine_manager.activeStackChanged.connect(self._update) - self._machine_manager.activeMaterialChanged.connect(self._update) + self._update() def _update(self): Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) From 5afcf2beacfac24b56d11bab0da4a3f5efe6b1bf Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 16:28:41 +0100 Subject: [PATCH 253/446] Don't update brand and generic materials models upon switching active extruder Because the list of materials can't change by that action. Contributes to issue CURA-4606. --- cura/Machines/Models/BrandMaterialsModel.py | 2 -- cura/Machines/Models/GenericMaterialsModel.py | 2 -- 2 files changed, 4 deletions(-) diff --git a/cura/Machines/Models/BrandMaterialsModel.py b/cura/Machines/Models/BrandMaterialsModel.py index 7c3c4c515d..e36c6448d3 100644 --- a/cura/Machines/Models/BrandMaterialsModel.py +++ b/cura/Machines/Models/BrandMaterialsModel.py @@ -54,9 +54,7 @@ class BrandMaterialsModel(ListModel): self._material_manager = CuraApplication.getInstance().getMaterialManager() self._machine_manager.globalContainerChanged.connect(self._update) - self._extruder_manager.activeExtruderChanged.connect(self._update) self._material_manager.materialsUpdated.connect(self._update) - self._update() def setExtruderPosition(self, position: int): diff --git a/cura/Machines/Models/GenericMaterialsModel.py b/cura/Machines/Models/GenericMaterialsModel.py index 03343ba53b..6b149448ea 100644 --- a/cura/Machines/Models/GenericMaterialsModel.py +++ b/cura/Machines/Models/GenericMaterialsModel.py @@ -16,9 +16,7 @@ class GenericMaterialsModel(BaseMaterialsModel): self._material_manager = CuraApplication.getInstance().getMaterialManager() self._machine_manager.globalContainerChanged.connect(self._update) - self._extruder_manager.activeExtruderChanged.connect(self._update) self._material_manager.materialsUpdated.connect(self._update) - self._update() def _update(self): From f08407cf97370bf7b1465f856bfcd64db635113b Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 16:32:10 +0100 Subject: [PATCH 254/446] Document Available role Contributes to issue CURA-4606. --- cura/Machines/Models/QualityProfilesDropDownMenuModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Machines/Models/QualityProfilesDropDownMenuModel.py b/cura/Machines/Models/QualityProfilesDropDownMenuModel.py index 40fdaaa410..06231491c7 100644 --- a/cura/Machines/Models/QualityProfilesDropDownMenuModel.py +++ b/cura/Machines/Models/QualityProfilesDropDownMenuModel.py @@ -29,7 +29,7 @@ class QualityProfilesDropDownMenuModel(ListModel): self.addRoleName(self.QualityTypeRole, "quality_type") self.addRoleName(self.LayerHeightRole, "layer_height") self.addRoleName(self.LayerHeightUnitRole, "layer_height_unit") - self.addRoleName(self.AvailableRole, "available") + self.addRoleName(self.AvailableRole, "available") #Whether the quality profile is available in our current nozzle + material. self.addRoleName(self.QualityGroupRole, "quality_group") self.addRoleName(self.QualityChangesGroupRole, "quality_changes_group") From 522e2977110e74b64ad09b8b421e3421cf05e1c5 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 12 Mar 2018 16:33:32 +0100 Subject: [PATCH 255/446] Add some more states to check if print_job is active --- plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py index 7a4c590acc..bcd11b3cb7 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py @@ -301,8 +301,8 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): self._updatePrintJob(print_job, print_job_data) if print_job.state != "queued": # Print job should be assigned to a printer. - if print_job.state == "failed": - # Print job was failed, so don't attach it to a printer. + if print_job.state in ["failed", "finished", "aborted"]: + # Print job was already completed, so don't attach it to a printer. printer = None else: printer = self._getPrinterByKey(print_job_data["printer_uuid"]) From 39a7f5a53d55ba356efb3ebbb1ec170378a93060 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 12 Mar 2018 16:37:35 +0100 Subject: [PATCH 256/446] CURA-4870 Update the configuration also when the type or the buildplate changed signal is emitted. --- cura/PrinterOutput/PrinterOutputModel.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index 8d674c1c5f..3453eca608 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -46,6 +46,8 @@ class PrinterOutputModel(QObject): # Update the printer configuration every time any of the extruders changes its configuration for extruder in self._extruders: extruder.extruderConfigurationChanged.connect(self._updatePrinterConfiguration) + self.typeChanged.connect(self._updatePrinterConfiguration) + self.buildplateChanged.connect(self._updatePrinterConfiguration) self._camera = None From 981c47ed87aece4637f2026953d74175ed783850 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 12 Mar 2018 17:03:10 +0100 Subject: [PATCH 257/446] Put the support extruder dropdown behind the checkbox to prevent scrolling --- resources/qml/SidebarSimple.qml | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index eabc1d202a..7cc67be03a 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -786,21 +786,6 @@ Item } } - Label - { - id: supportExtruderLabel - visible: supportExtruderCombobox.visible - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width - anchors.right: infillCellLeft.right - anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width - anchors.verticalCenter: supportExtruderCombobox.verticalCenter - text: catalog.i18nc("@label", "Support Extruder"); - font: UM.Theme.getFont("default"); - color: UM.Theme.getColor("text"); - elide: Text.ElideRight - } - ComboBox { id: supportExtruderCombobox @@ -818,12 +803,13 @@ Item textRole: "text" // this solves that the combobox isn't populated in the first time Cura is started - anchors.top: enableSupportCheckBox.bottom - anchors.topMargin: ((supportEnabled.properties.value === "True") && (extrudersEnabledCount.properties.value > 1)) ? UM.Theme.getSize("sidebar_margin").height : 0 - anchors.left: infillCellRight.left + anchors.top: enableSupportCheckBox.top + //anchors.topMargin: ((supportEnabled.properties.value === "True") && (machineExtruderCount.properties.value > 1)) ? UM.Theme.getSize("sidebar_margin").height : 0 + anchors.left: enableSupportCheckBox.right + anchors.leftMargin: Math.round(UM.Theme.getSize("sidebar_margin").width / 2) - width: Math.round(UM.Theme.getSize("sidebar").width * .55) - height: ((supportEnabled.properties.value == "True") && (extrudersEnabledCount.properties.value > 1)) ? UM.Theme.getSize("setting_control").height : 0 + width: Math.round(UM.Theme.getSize("sidebar").width * .55) - Math.round(UM.Theme.getSize("sidebar_margin").width / 2) - enableSupportCheckBox.width + height: ((supportEnabled.properties.value == "True") && (machineExtruderCount.properties.value > 1)) ? UM.Theme.getSize("setting_control").height : 0 Behavior on height { NumberAnimation { duration: 100 } } @@ -889,7 +875,7 @@ Item id: adhesionCheckBox property alias _hovered: adhesionMouseArea.containsMouse - anchors.top: enableSupportCheckBox.visible ? supportExtruderCombobox.bottom : infillCellRight.bottom + anchors.top: enableSupportCheckBox.bottom anchors.topMargin: UM.Theme.getSize("sidebar_margin").height anchors.left: infillCellRight.left From d904f677bc2c8e0a4cf6ec9b66ca0bfe1b54eccc Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 17:07:52 +0100 Subject: [PATCH 258/446] Store extruder position of quality groups as int Instead of as a string with a number in it. For the actual global stack's extruders we still need to convert to string, sadly. I could go refactor that too, but then I won't be going home until 23 o'clock or something. Contributes to issue CURA-4606. --- cura/Machines/Models/QualitySettingsModel.py | 17 +++++++++-------- cura/Machines/QualityGroup.py | 4 ++-- cura/Settings/MachineManager.py | 4 ++-- resources/qml/Preferences/ProfileTab.qml | 2 +- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/cura/Machines/Models/QualitySettingsModel.py b/cura/Machines/Models/QualitySettingsModel.py index 15ebe37f05..5489ad0dd7 100644 --- a/cura/Machines/Models/QualitySettingsModel.py +++ b/cura/Machines/Models/QualitySettingsModel.py @@ -21,6 +21,8 @@ class QualitySettingsModel(ListModel): UserValueRole = Qt.UserRole + 6 CategoryRole = Qt.UserRole + 7 + GLOBAL_STACK_POSITION = -1 + def __init__(self, parent = None): super().__init__(parent = parent) @@ -36,8 +38,7 @@ class QualitySettingsModel(ListModel): self._application = Application.getInstance() self._quality_manager = self._application.getQualityManager() - self._selected_position = "" # empty string means GlobalStack - # strings such as "0", "1", etc. mean extruder positions + self._selected_position = self.GLOBAL_STACK_POSITION #Must be either GLOBAL_STACK_POSITION or an extruder position (0, 1, etc.) self._selected_quality_item = None # The selected quality in the quality management page self._i18n_catalog = None @@ -54,7 +55,7 @@ class QualitySettingsModel(ListModel): self.selectedPositionChanged.emit() self._update() - @pyqtProperty(str, fset = setSelectedPosition, notify = selectedPositionChanged) + @pyqtProperty(int, fset = setSelectedPosition, notify = selectedPositionChanged) def selectedPosition(self): return self._selected_position @@ -83,7 +84,7 @@ class QualitySettingsModel(ListModel): quality_group = self._selected_quality_item["quality_group"] quality_changes_group = self._selected_quality_item["quality_changes_group"] - if self._selected_position == "": + if self._selected_position == self.GLOBAL_STACK_POSITION: quality_node = quality_group.node_for_global else: quality_node = quality_group.nodes_for_extruders.get(self._selected_position) @@ -93,7 +94,7 @@ class QualitySettingsModel(ListModel): # Here, if the user has selected a quality changes, then "quality_changes_group" will not be None, and we fetch # the settings in that quality_changes_group. if quality_changes_group is not None: - if self._selected_position == "": + if self._selected_position == self.GLOBAL_STACK_POSITION: quality_changes_node = quality_changes_group.node_for_global else: quality_changes_node = quality_changes_group.nodes_for_extruders.get(self._selected_position) @@ -127,7 +128,7 @@ class QualitySettingsModel(ListModel): profile_value = new_value # Global tab should use resolve (if there is one) - if self._selected_position == "": + if self._selected_position == self.GLOBAL_STACK_POSITION: resolve_value = global_container_stack.getProperty(definition.key, "resolve") if resolve_value is not None and definition.key in settings_keys: profile_value = resolve_value @@ -135,10 +136,10 @@ class QualitySettingsModel(ListModel): if profile_value is not None: break - if not self._selected_position: + if self._selected_position == self.GLOBAL_STACK_POSITION: user_value = global_container_stack.userChanges.getProperty(definition.key, "value") else: - extruder_stack = global_container_stack.extruders[self._selected_position] + extruder_stack = global_container_stack.extruders[str(self._selected_position)] user_value = extruder_stack.userChanges.getProperty(definition.key, "value") if profile_value is None and user_value is None: diff --git a/cura/Machines/QualityGroup.py b/cura/Machines/QualityGroup.py index 6945162401..02096cfb36 100644 --- a/cura/Machines/QualityGroup.py +++ b/cura/Machines/QualityGroup.py @@ -1,7 +1,7 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from typing import Optional, List +from typing import Dict, Optional, List from PyQt5.QtCore import QObject, pyqtSlot @@ -25,7 +25,7 @@ class QualityGroup(QObject): super().__init__(parent) self.name = name self.node_for_global = None # type: Optional["QualityGroup"] - self.nodes_for_extruders = dict() # position str -> QualityGroup + self.nodes_for_extruders = {} # type: Dict[int, "QualityGroup"] self.quality_type = quality_type self.is_available = False diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 35ffc3c7d3..3a65b6df5d 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -939,9 +939,9 @@ class MachineManager(QObject): # Set quality and quality_changes for each ExtruderStack for position, node in quality_group.nodes_for_extruders.items(): - self._global_container_stack.extruders[position].quality = node.getContainer() + self._global_container_stack.extruders[str(position)].quality = node.getContainer() if empty_quality_changes: - self._global_container_stack.extruders[position].qualityChanges = self._empty_quality_changes_container + self._global_container_stack.extruders[str(position)].qualityChanges = self._empty_quality_changes_container self.activeQualityGroupChanged.emit() self.activeQualityChangesGroupChanged.emit() diff --git a/resources/qml/Preferences/ProfileTab.qml b/resources/qml/Preferences/ProfileTab.qml index e202e933f3..0ae0899051 100644 --- a/resources/qml/Preferences/ProfileTab.qml +++ b/resources/qml/Preferences/ProfileTab.qml @@ -11,7 +11,7 @@ Tab { id: base - property string extruderPosition: "" + property int extruderPosition: -1 //Denotes the global stack. property var qualityItem: null property bool isQualityItemCurrentlyActivated: From 1db8c967f2ffca588997cedb0c09eb506702054f Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 17:10:17 +0100 Subject: [PATCH 259/446] More specific exception catching So that we can still find programming errors in this code. Contributes to issue CURA-4606. --- cura/Machines/Models/QualitySettingsModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Machines/Models/QualitySettingsModel.py b/cura/Machines/Models/QualitySettingsModel.py index 5489ad0dd7..4470ffc80e 100644 --- a/cura/Machines/Models/QualitySettingsModel.py +++ b/cura/Machines/Models/QualitySettingsModel.py @@ -101,7 +101,7 @@ class QualitySettingsModel(ListModel): if quality_changes_node is not None: # it can be None if number of extruders are changed during runtime try: quality_containers.insert(0, quality_changes_node.getContainer()) - except: + except RuntimeError: # FIXME: This is to prevent incomplete update of QualityManager Logger.logException("d", "Failed to get container for quality changes node %s", quality_changes_node) return From f40e9bffa9aeee2e312fbe4cbe5cab7bfa8189f6 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Mar 2018 17:27:55 +0100 Subject: [PATCH 260/446] Use extruder positions directly ...instead of the keys in the _current_root_material_id map. Contributes to issue CURA-4606. --- cura/Settings/MachineManager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 3a65b6df5d..d79130e0c3 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -872,9 +872,9 @@ class MachineManager(QObject): container = extruder.userChanges container.setProperty(setting_name, property_name, property_value) - @pyqtProperty("QVariantList", notify = rootMaterialChanged) + @pyqtProperty("QVariantList", notify = globalContainerChanged) def currentExtruderPositions(self): - return sorted(list(self._current_root_material_id.keys())) + return sorted(list(self._global_container_stack.extruders.keys())) @pyqtProperty("QVariant", notify = rootMaterialChanged) def currentRootMaterialId(self): From a87db2d721e7779c4b6d3650aa60155e0de22ea4 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 13 Mar 2018 09:09:21 +0100 Subject: [PATCH 261/446] Always update root material even if not in QML Previously the _current_root_material_id and _current_root_material_name dictionaries were only updated if they are used anywhere in QML. This is unreliable. We're now directly connecting to the signal so that they are always updated, even when not in use by the GUI. This way we can rely on it in other places than the GUI. Contributes to issue CURA-4606. --- cura/Settings/MachineManager.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index d79130e0c3..afff8b96b3 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -125,6 +125,7 @@ class MachineManager(QObject): # When the materials lookup table gets updated, it can mean that a material has its name changed, which should # be reflected on the GUI. This signal emission makes sure that it happens. self._material_manager.materialsUpdated.connect(self.rootMaterialChanged) + self.rootMaterialChanged.connect(self._onRootMaterialChanged) activeQualityGroupChanged = pyqtSignal() activeQualityChangesGroupChanged = pyqtSignal() @@ -876,23 +877,26 @@ class MachineManager(QObject): def currentExtruderPositions(self): return sorted(list(self._global_container_stack.extruders.keys())) - @pyqtProperty("QVariant", notify = rootMaterialChanged) - def currentRootMaterialId(self): - # initial filling the current_root_material_id + ## Update _current_root_material_id and _current_root_material_name when + # the current root material was changed. + def _onRootMaterialChanged(self): self._current_root_material_id = {} for position in self._global_container_stack.extruders: self._current_root_material_id[position] = self._global_container_stack.extruders[position].material.getMetaDataEntry("base_file") - return self._current_root_material_id - @pyqtProperty("QVariant", notify = rootMaterialChanged) - def currentRootMaterialName(self): - # initial filling the current_root_material_name if self._global_container_stack: self._current_root_material_name = {} for position in self._global_container_stack.extruders: if position not in self._current_root_material_name: material = self._global_container_stack.extruders[position].material self._current_root_material_name[position] = material.getName() + + @pyqtProperty("QVariant", notify = rootMaterialChanged) + def currentRootMaterialId(self): + return self._current_root_material_id + + @pyqtProperty("QVariant", notify = rootMaterialChanged) + def currentRootMaterialName(self): return self._current_root_material_name ## Return the variant names in the extruder stack(s). From 69dc4fa5e018a874b69a554704e128847acbf460 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Tue, 13 Mar 2018 09:20:42 +0100 Subject: [PATCH 262/446] Concerning the unfortunate crash... ..of the morning of the 13th day of March, in the 2018th year of our lord. --- cura/Settings/MachineManager.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index afff8b96b3..75024ad395 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -875,6 +875,8 @@ class MachineManager(QObject): @pyqtProperty("QVariantList", notify = globalContainerChanged) def currentExtruderPositions(self): + if self._global_container_stack is None: + return [] return sorted(list(self._global_container_stack.extruders.keys())) ## Update _current_root_material_id and _current_root_material_name when From b4a40915bb45612edde6150da5b101c19d62dede Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 13 Mar 2018 09:23:40 +0100 Subject: [PATCH 263/446] Code style: Brackets on new line Contributes to issue CURA-4606. --- resources/qml/Preferences/MaterialsPage.qml | 69 ++++++++++++++------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml index 553cfe0423..7f06ffecde 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/MaterialsPage.qml @@ -19,14 +19,17 @@ Item UM.I18nCatalog { id: catalog; name: "cura"; } - Cura.MaterialManagementModel { + Cura.MaterialManagementModel + { id: materialsModel } - Label { + Label + { id: titleLabel - anchors { + anchors + { top: parent.top left: parent.left right: parent.right @@ -170,22 +173,27 @@ Item Connections { target: materialsModel - onItemsChanged: { + onItemsChanged: + { var currentItemId = base.currentItem == null ? "" : base.currentItem.root_material_id; var position = Cura.ExtruderManager.activeExtruderIndex; // try to pick the currently selected item; it may have been moved - if (base.newRootMaterialIdToSwitchTo == "") { + if (base.newRootMaterialIdToSwitchTo == "") + { base.newRootMaterialIdToSwitchTo = currentItemId; } - for (var idx = 0; idx < materialsModel.rowCount(); ++idx) { + for (var idx = 0; idx < materialsModel.rowCount(); ++idx) + { var item = materialsModel.getItem(idx); - if (item.root_material_id == base.newRootMaterialIdToSwitchTo) { + if (item.root_material_id == base.newRootMaterialIdToSwitchTo) + { // Switch to the newly created profile if needed materialListView.currentIndex = idx; materialListView.activateDetailsWithIndex(materialListView.currentIndex); - if (base.toActivateNewMaterial) { + if (base.toActivateNewMaterial) + { Cura.MachineManager.setMaterial(position, item.container_node); } base.newRootMaterialIdToSwitchTo = ""; @@ -196,7 +204,8 @@ Item materialListView.currentIndex = 0; materialListView.activateDetailsWithIndex(materialListView.currentIndex); - if (base.toActivateNewMaterial) { + if (base.toActivateNewMaterial) + { Cura.MachineManager.setMaterial(position, materialsModel.getItem(0).container_node); } base.newRootMaterialIdToSwitchTo = ""; @@ -233,14 +242,17 @@ Item messageDialog.title = catalog.i18nc("@title:window", "Import Material"); messageDialog.text = catalog.i18nc("@info:status Don't translate the XML tags or !", "Could not import material %1: %2").arg(fileUrl).arg(result.message); - if (result.status == "success") { + if (result.status == "success") + { messageDialog.icon = StandardIcon.Information; messageDialog.text = catalog.i18nc("@info:status Don't translate the XML tag !", "Successfully imported material %1").arg(fileUrl); } - else if (result.status == "duplicate") { + else if (result.status == "duplicate") + { messageDialog.icon = StandardIcon.Warning; } - else { + else + { messageDialog.icon = StandardIcon.Critical; } messageDialog.open(); @@ -260,12 +272,14 @@ Item var result = Cura.ContainerManager.exportContainer(base.currentItem.root_material_id, selectedNameFilter, fileUrl); messageDialog.title = catalog.i18nc("@title:window", "Export Material"); - if (result.status == "error") { + if (result.status == "error") + { messageDialog.icon = StandardIcon.Critical; messageDialog.text = catalog.i18nc("@info:status Don't translate the XML tags and !", "Failed to export material to %1: %2").arg(fileUrl).arg(result.message); messageDialog.open(); } - else if (result.status == "success") { + else if (result.status == "success") + { messageDialog.icon = StandardIcon.Information; messageDialog.text = catalog.i18nc("@info:status Don't translate the XML tag !", "Successfully exported material to %1").arg(result.path); messageDialog.open(); @@ -283,7 +297,8 @@ Item Item { id: contentsItem - anchors { + anchors + { top: titleLabel.bottom left: parent.left right: parent.right @@ -297,7 +312,8 @@ Item Item { - anchors { + anchors + { top: buttonRow.bottom topMargin: UM.Theme.getSize("default_margin").height left: parent.left @@ -310,12 +326,14 @@ Item Label { id: captionLabel - anchors { + anchors + { top: parent.top left: parent.left } visible: text != "" - text: { + text: + { var caption = catalog.i18nc("@action:label", "Printer") + ": " + Cura.MachineManager.activeMachineName; if (Cura.MachineManager.hasVariants) { @@ -330,14 +348,16 @@ Item ScrollView { id: materialScrollView - anchors { + anchors + { top: captionLabel.visible ? captionLabel.bottom : parent.top topMargin: captionLabel.visible ? UM.Theme.getSize("default_margin").height : 0 bottom: parent.bottom left: parent.left } - Rectangle { + Rectangle + { parent: viewport anchors.fill: parent color: palette.light @@ -418,13 +438,15 @@ Item MouseArea { anchors.fill: parent - onClicked: { + onClicked: + { parent.ListView.view.currentIndex = model.index; } } } - function activateDetailsWithIndex(index) { + function activateDetailsWithIndex(index) + { var model = materialsModel.getItem(index); base.currentItem = model; materialDetailsView.containerId = model.container_id; @@ -446,7 +468,8 @@ Item { id: detailsPanel - anchors { + anchors + { left: materialScrollView.right leftMargin: UM.Theme.getSize("default_margin").width top: parent.top From 54882402adcf00a7cd6a844173d34ef975f9656b Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 13 Mar 2018 09:41:26 +0100 Subject: [PATCH 264/446] CURA-4870 Change the name of the signal to be more related with the context. --- cura/PrinterOutput/PrinterOutputModel.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index 3453eca608..04f2c1eb62 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -22,7 +22,7 @@ class PrinterOutputModel(QObject): nameChanged = pyqtSignal() headPositionChanged = pyqtSignal() keyChanged = pyqtSignal() - typeChanged = pyqtSignal() + printerTypeChanged = pyqtSignal() buildplateChanged = pyqtSignal() cameraChanged = pyqtSignal() configurationChanged = pyqtSignal() @@ -41,12 +41,12 @@ class PrinterOutputModel(QObject): self._firmware_version = firmware_version self._printer_state = "unknown" self._is_preheating = False - self._type = "" + self._printer_type = "" self._buildplate_name = None # Update the printer configuration every time any of the extruders changes its configuration for extruder in self._extruders: extruder.extruderConfigurationChanged.connect(self._updatePrinterConfiguration) - self.typeChanged.connect(self._updatePrinterConfiguration) + self.printerTypeChanged.connect(self._updatePrinterConfiguration) self.buildplateChanged.connect(self._updatePrinterConfiguration) self._camera = None @@ -73,14 +73,14 @@ class PrinterOutputModel(QObject): def camera(self): return self._camera - @pyqtProperty(str, notify = typeChanged) + @pyqtProperty(str, notify = printerTypeChanged) def type(self): - return self._type + return self._printer_type - def updateType(self, type): - if self._type != type: - self._type = type - self.typeChanged.emit() + def updateType(self, printer_type): + if self._printer_type != printer_type: + self._printer_type = printer_type + self.printerTypeChanged.emit() @pyqtProperty(str, notify = buildplateChanged) def buildplate(self): @@ -263,7 +263,7 @@ class PrinterOutputModel(QObject): return self._printer_configuration def _updatePrinterConfiguration(self): - self._printer_configuration.printerType = self._type + self._printer_configuration.printerType = self._printer_type self._printer_configuration.extruderConfigurations = [extruder.extruderConfiguration for extruder in self._extruders] self._printer_configuration.buildplateConfiguration = self._buildplate_name self.configurationChanged.emit() From b3f9679a5fddd94bc6ca1e3ddccc221ad911f2a4 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 13 Mar 2018 09:43:44 +0100 Subject: [PATCH 265/446] CURA-4870 Style the __str__ function --- cura/PrinterOutput/ConfigurationModel.py | 17 +++++++++++------ cura/PrinterOutput/ExtruderOutputModel.py | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/cura/PrinterOutput/ConfigurationModel.py b/cura/PrinterOutput/ConfigurationModel.py index 30c95f2765..23ed687fb8 100644 --- a/cura/PrinterOutput/ConfigurationModel.py +++ b/cura/PrinterOutput/ConfigurationModel.py @@ -41,18 +41,22 @@ class ConfigurationModel(QObject): return self._buildplate_configuration def __str__(self): - info = "Printer type: " + self._printer_type + "\n" - info += "Extruders: [\n" + message_chunks = [] + message_chunks.append("Printer type: " + self._printer_type) + message_chunks.append("Extruders: [") for configuration in self._extruder_configurations: - info += " " + str(configuration) + "\n" - info += "]" + message_chunks.append(" " + str(configuration)) + message_chunks.append("]") if self._buildplate_configuration is not None: - info += "\nBuildplate: " + self._buildplate_configuration - return info + message_chunks.append("Buildplate: " + self._buildplate_configuration) + + return "\n".join(message_chunks) def __eq__(self, other): return hash(self) == hash(other) + ## The hash function is used to compare and create unique sets. The configuration is unique if the configuration + # of the extruders is unique (the order of the extruders matters), and the type and buildplate is the same. def __hash__(self): extruder_hash = hash(0) first_extruder = None @@ -60,6 +64,7 @@ class ConfigurationModel(QObject): extruder_hash ^= hash(configuration) if configuration.position == 0: first_extruder = configuration + # To ensure the correct order of the extruders, we add an "and" operation using the first extruder hash value if first_extruder: extruder_hash &= hash(first_extruder) diff --git a/cura/PrinterOutput/ExtruderOutputModel.py b/cura/PrinterOutput/ExtruderOutputModel.py index a639d428f9..df47bca71a 100644 --- a/cura/PrinterOutput/ExtruderOutputModel.py +++ b/cura/PrinterOutput/ExtruderOutputModel.py @@ -62,7 +62,7 @@ class ExtruderOutputModel(QObject): def targetHotendTemperature(self) -> float: return self._target_hotend_temperature - @pyqtProperty(float, notify=hotendTemperatureChanged) + @pyqtProperty(float, notify = hotendTemperatureChanged) def hotendTemperature(self) -> float: return self._hotend_temperature From b90a9c490d34a9a6ede53746d007fc4da33507a3 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Tue, 13 Mar 2018 09:57:07 +0100 Subject: [PATCH 266/446] Don't loop extruders before checking if there is a global extruder stack --- cura/Settings/MachineManager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 75024ad395..eb720000bf 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -883,10 +883,10 @@ class MachineManager(QObject): # the current root material was changed. def _onRootMaterialChanged(self): self._current_root_material_id = {} - for position in self._global_container_stack.extruders: - self._current_root_material_id[position] = self._global_container_stack.extruders[position].material.getMetaDataEntry("base_file") if self._global_container_stack: + for position in self._global_container_stack.extruders: + self._current_root_material_id[position] = self._global_container_stack.extruders[position].material.getMetaDataEntry("base_file") self._current_root_material_name = {} for position in self._global_container_stack.extruders: if position not in self._current_root_material_name: From fa2b5f141c9c87cc533e7cf3f355450c470a832a Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 13 Mar 2018 10:35:48 +0100 Subject: [PATCH 267/446] CURA-4870 Remove dinamic connections to the signals in the machine model. The model is still updated when the container changed. --- cura/Machines/Models/MachineManagementModel.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/cura/Machines/Models/MachineManagementModel.py b/cura/Machines/Models/MachineManagementModel.py index 0ca47f2ef3..481a692675 100644 --- a/cura/Machines/Models/MachineManagementModel.py +++ b/cura/Machines/Models/MachineManagementModel.py @@ -42,18 +42,9 @@ class MachineManagementModel(ListModel): if isinstance(container, ContainerStack): self._update() - ## Handler for container name change events. - def _onContainerNameChanged(self): - self._update() - ## Private convenience function to reset & repopulate the model. def _update(self): items = [] - # Remove all connections - for container in self._local_container_stacks: - container.nameChanged.disconnect(self._onContainerNameChanged) - for container in self._network_container_stacks: - container.nameChanged.disconnect(self._onContainerNameChanged) # Get first the network enabled printers network_filter_printers = {"type": "machine", "um_network_key": "*", "hidden": "False"} @@ -65,7 +56,6 @@ class MachineManagementModel(ListModel): if container.getBottom(): metadata["definition_name"] = container.getBottom().getName() - container.nameChanged.connect(self._onContainerNameChanged) items.append({"name": metadata["connect_group_name"], "id": container.getId(), "metadata": metadata, @@ -81,7 +71,6 @@ class MachineManagementModel(ListModel): if container.getBottom(): metadata["definition_name"] = container.getBottom().getName() - container.nameChanged.connect(self._onContainerNameChanged) items.append({"name": container.getName(), "id": container.getId(), "metadata": metadata, From d807ce57a51a010565bc42c3174da3fc6832d3ba Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 13 Mar 2018 10:49:29 +0100 Subject: [PATCH 268/446] CURA-4870 Disable rename button in MachinesPage when the selected item is a network printer since the name is the name of the host printer (or group) --- resources/qml/Preferences/MachinesPage.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Preferences/MachinesPage.qml b/resources/qml/Preferences/MachinesPage.qml index df9482b84d..665586d29f 100644 --- a/resources/qml/Preferences/MachinesPage.qml +++ b/resources/qml/Preferences/MachinesPage.qml @@ -54,7 +54,7 @@ UM.ManagementPage { text: catalog.i18nc("@action:button", "Rename"); iconName: "edit-rename"; - enabled: base.currentItem != null + enabled: base.currentItem != null && base.currentItem.metadata.connect_group_name == null onClicked: renameDialog.open(); } ] From 73517cd176d4ce33ae657a079cd655bc5ffe38c2 Mon Sep 17 00:00:00 2001 From: Aleksei S Date: Tue, 13 Mar 2018 11:41:48 +0100 Subject: [PATCH 269/446] The infill denstiy was updated twice, first in Custom view and then in Recomended view CURA-5071 --- resources/qml/SidebarSimple.qml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index 7cc67be03a..d24c047058 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -516,7 +516,11 @@ Item // Update the slider value to represent the rounded value infillSlider.value = roundedSliderValue - Cura.MachineManager.setSettingForAllExtruders("infill_sparse_density", "value", roundedSliderValue) + // Update value only if the Recomended mode is Active, + // Otherwise if I change the value in the Custom mode the Recomended view will try to repeat + // same operation + if (UM.Preferences.getValue("cura/active_mode") == 0) + Cura.MachineManager.setSettingForAllExtruders("infill_sparse_density", "value", roundedSliderValue) } style: SliderStyle From 4c61ea5ba9972d483f319a6fd8e3c4bc4bd3e27f Mon Sep 17 00:00:00 2001 From: THeijmans Date: Tue, 13 Mar 2018 11:45:19 +0100 Subject: [PATCH 270/446] Single extrusion settings for travels Updated single extrusion settings, so z hops are removed and travels are shortened for single extrusion. --- resources/definitions/ultimaker3.def.json | 4 ++-- .../quality/ultimaker3/um3_aa0.25_PC_Normal_Quality.inst.cfg | 1 - .../quality/ultimaker3/um3_aa0.25_PP_Normal_Quality.inst.cfg | 1 - .../quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg | 1 - resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg | 1 - .../quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg | 1 - .../quality/ultimaker3/um3_aa0.4_PC_Normal_Quality.inst.cfg | 1 - .../quality/ultimaker3/um3_aa0.4_PP_Draft_Print.inst.cfg | 2 -- resources/quality/ultimaker3/um3_aa0.4_PP_Fast_Print.inst.cfg | 2 -- .../quality/ultimaker3/um3_aa0.4_PP_Normal_Quality.inst.cfg | 2 -- .../quality/ultimaker3/um3_aa0.4_TPU_Draft_Print.inst.cfg | 1 - .../quality/ultimaker3/um3_aa0.4_TPU_Fast_Print.inst.cfg | 1 - .../quality/ultimaker3/um3_aa0.4_TPU_Normal_Quality.inst.cfg | 1 - .../quality/ultimaker3/um3_aa0.8_CPEP_Fast_Print.inst.cfg | 3 +-- .../ultimaker3/um3_aa0.8_CPEP_Superdraft_Print.inst.cfg | 3 +-- .../ultimaker3/um3_aa0.8_CPEP_Verydraft_Print.inst.cfg | 1 - resources/quality/ultimaker3/um3_aa0.8_PC_Fast_Print.inst.cfg | 1 - .../quality/ultimaker3/um3_aa0.8_PC_Superdraft_Print.inst.cfg | 1 - .../quality/ultimaker3/um3_aa0.8_PC_Verydraft_Print.inst.cfg | 1 - resources/variants/ultimaker3_aa04.inst.cfg | 1 + resources/variants/ultimaker3_bb04.inst.cfg | 1 + resources/variants/ultimaker3_extended_aa04.inst.cfg | 1 + resources/variants/ultimaker3_extended_bb04.inst.cfg | 1 + 23 files changed, 8 insertions(+), 25 deletions(-) diff --git a/resources/definitions/ultimaker3.def.json b/resources/definitions/ultimaker3.def.json index 29395e8fd5..1864a9b24a 100644 --- a/resources/definitions/ultimaker3.def.json +++ b/resources/definitions/ultimaker3.def.json @@ -126,7 +126,7 @@ "retraction_count_max": { "value": "10" }, "retraction_extrusion_window": { "value": "1" }, "retraction_hop": { "value": "2" }, - "retraction_hop_enabled": { "value": "True" }, + "retraction_hop_enabled": { "value": "extruders_enabled_count > 1" }, "retraction_hop_only_when_collides": { "value": "True" }, "retraction_min_travel": { "value": "5" }, "retraction_prime_speed": { "value": "15" }, @@ -150,7 +150,7 @@ "switch_extruder_prime_speed": { "value": "15" }, "switch_extruder_retraction_amount": { "value": "8" }, "top_bottom_thickness": { "value": "1" }, - "travel_avoid_distance": { "value": "3" }, + "travel_avoid_distance": { "value": "3 if extruders_enabled_count > 1 else machine_nozzle_tip_outer_diameter / 2 * 1.5" }, "wall_0_inset": { "value": "0" }, "wall_line_width_x": { "value": "round(wall_line_width * 0.3 / 0.35, 2)" }, "wall_thickness": { "value": "1" }, diff --git a/resources/quality/ultimaker3/um3_aa0.25_PC_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.25_PC_Normal_Quality.inst.cfg index 7c9fa32949..925af3f73c 100644 --- a/resources/quality/ultimaker3/um3_aa0.25_PC_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.25_PC_Normal_Quality.inst.cfg @@ -33,7 +33,6 @@ raft_airgap = 0.25 raft_interface_thickness = =max(layer_height * 1.5, 0.225) retraction_count_max = 80 retraction_hop = 2 -retraction_hop_enabled = True retraction_hop_only_when_collides = True retraction_min_travel = 0.8 retraction_prime_speed = 15 diff --git a/resources/quality/ultimaker3/um3_aa0.25_PP_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.25_PP_Normal_Quality.inst.cfg index 58e7fdc688..e12729878d 100644 --- a/resources/quality/ultimaker3/um3_aa0.25_PP_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.25_PP_Normal_Quality.inst.cfg @@ -37,7 +37,6 @@ retraction_count_max = 6 retraction_extra_prime_amount = 0.2 retraction_extrusion_window = 6.5 retraction_hop = 2 -retraction_hop_enabled = True retraction_hop_only_when_collides = True retraction_min_travel = 0.8 retraction_prime_speed = 13 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg index f8b4dd067c..fb185d95b8 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg @@ -43,7 +43,6 @@ raft_interface_thickness = =max(layer_height * 1.5, 0.225) retraction_count_max = 80 retraction_extrusion_window = 1 retraction_hop = 2 -retraction_hop_enabled = True retraction_hop_only_when_collides = True retraction_min_travel = 0.8 retraction_prime_speed = 15 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg index 1db3935180..ab53edfa73 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg @@ -42,7 +42,6 @@ raft_interface_thickness = =max(layer_height * 1.5, 0.225) retraction_count_max = 80 retraction_extrusion_window = 1 retraction_hop = 2 -retraction_hop_enabled = True retraction_hop_only_when_collides = True retraction_min_travel = 0.8 retraction_prime_speed = 15 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg index 0f9e9b15b0..9900aed7d2 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg @@ -43,7 +43,6 @@ raft_interface_thickness = =max(layer_height * 1.5, 0.225) retraction_count_max = 80 retraction_extrusion_window = 1 retraction_hop = 2 -retraction_hop_enabled = True retraction_hop_only_when_collides = True retraction_min_travel = 0.8 retraction_prime_speed = 15 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PC_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PC_Normal_Quality.inst.cfg index 26a3136069..63be70e4e2 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PC_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PC_Normal_Quality.inst.cfg @@ -40,7 +40,6 @@ raft_interface_thickness = =max(layer_height * 1.5, 0.225) retraction_count_max = 80 retraction_extrusion_window = 1 retraction_hop = 2 -retraction_hop_enabled = True retraction_hop_only_when_collides = True retraction_min_travel = 0.8 retraction_prime_speed = 15 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PP_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PP_Draft_Print.inst.cfg index 3fe25e563a..f543c3ae78 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PP_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PP_Draft_Print.inst.cfg @@ -44,7 +44,6 @@ retraction_count_max = 12 retraction_extra_prime_amount = 0.8 retraction_extrusion_window = 1 retraction_hop = 2 -retraction_hop_enabled = True retraction_hop_only_when_collides = True retraction_min_travel = 0.8 retraction_prime_speed = 18 @@ -60,7 +59,6 @@ support_angle = 50 switch_extruder_prime_speed = 15 switch_extruder_retraction_amount = 20 switch_extruder_retraction_speeds = 35 -travel_avoid_distance = 3 wall_0_inset = 0 wall_line_width_x = =line_width wall_thickness = =line_width * 3 \ No newline at end of file diff --git a/resources/quality/ultimaker3/um3_aa0.4_PP_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PP_Fast_Print.inst.cfg index 4c92c7a14b..0d1fb6af58 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PP_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PP_Fast_Print.inst.cfg @@ -43,7 +43,6 @@ retraction_count_max = 12 retraction_extra_prime_amount = 0.8 retraction_extrusion_window = 1 retraction_hop = 2 -retraction_hop_enabled = True retraction_hop_only_when_collides = True retraction_min_travel = 0.8 retraction_prime_speed = 18 @@ -60,7 +59,6 @@ switch_extruder_prime_speed = 15 switch_extruder_retraction_amount = 20 switch_extruder_retraction_speeds = 35 top_bottom_thickness = 1.1 -travel_avoid_distance = 3 wall_0_inset = 0 wall_line_width_x = =line_width wall_thickness = =line_width * 3 \ No newline at end of file diff --git a/resources/quality/ultimaker3/um3_aa0.4_PP_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PP_Normal_Quality.inst.cfg index db55956497..141015348f 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PP_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PP_Normal_Quality.inst.cfg @@ -42,7 +42,6 @@ retraction_count_max = 12 retraction_extra_prime_amount = 0.8 retraction_extrusion_window = 1 retraction_hop = 2 -retraction_hop_enabled = True retraction_hop_only_when_collides = True retraction_min_travel = 0.8 retraction_prime_speed = 18 @@ -59,7 +58,6 @@ switch_extruder_prime_speed = 15 switch_extruder_retraction_amount = 20 switch_extruder_retraction_speeds = 35 top_bottom_thickness = 1 -travel_avoid_distance = 3 wall_0_inset = 0 wall_line_width_x = =line_width wall_thickness = =line_width * 3 \ No newline at end of file diff --git a/resources/quality/ultimaker3/um3_aa0.4_TPU_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_TPU_Draft_Print.inst.cfg index e2751a13ac..8c8b9691df 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_TPU_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_TPU_Draft_Print.inst.cfg @@ -42,7 +42,6 @@ retraction_count_max = 12 retraction_extra_prime_amount = 0.8 retraction_extrusion_window = 1 retraction_hop = 1.5 -retraction_hop_enabled = True retraction_hop_only_when_collides = True retraction_min_travel = =line_width * 2 retraction_prime_speed = 15 diff --git a/resources/quality/ultimaker3/um3_aa0.4_TPU_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_TPU_Fast_Print.inst.cfg index 13ff46cef4..0e3ad215d6 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_TPU_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_TPU_Fast_Print.inst.cfg @@ -43,7 +43,6 @@ retraction_count_max = 12 retraction_extra_prime_amount = 0.8 retraction_extrusion_window = 1 retraction_hop = 1.5 -retraction_hop_enabled = True retraction_hop_only_when_collides = True retraction_min_travel = =line_width * 2 retraction_prime_speed = 15 diff --git a/resources/quality/ultimaker3/um3_aa0.4_TPU_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_TPU_Normal_Quality.inst.cfg index 04454a9ff3..7e338e6a47 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_TPU_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_TPU_Normal_Quality.inst.cfg @@ -40,7 +40,6 @@ retraction_count_max = 12 retraction_extra_prime_amount = 0.8 retraction_extrusion_window = 1 retraction_hop = 1.5 -retraction_hop_enabled = True retraction_hop_only_when_collides = True retraction_min_travel = =line_width * 2 retraction_prime_speed = 15 diff --git a/resources/quality/ultimaker3/um3_aa0.8_CPEP_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_CPEP_Fast_Print.inst.cfg index 0a05e9aafd..3d9b4bb798 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_CPEP_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_CPEP_Fast_Print.inst.cfg @@ -34,5 +34,4 @@ speed_wall_0 = =math.ceil(speed_wall * 35 / 40) support_bottom_distance = =support_z_distance support_line_width = =round(line_width * 0.6 / 0.7, 2) support_z_distance = =layer_height -top_bottom_thickness = 1.2 -travel_avoid_distance = 1.5 \ No newline at end of file +top_bottom_thickness = 1.2 \ No newline at end of file diff --git a/resources/quality/ultimaker3/um3_aa0.8_CPEP_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_CPEP_Superdraft_Print.inst.cfg index 82efb6a57b..ccd87313e7 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_CPEP_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_CPEP_Superdraft_Print.inst.cfg @@ -35,5 +35,4 @@ speed_wall_0 = =math.ceil(speed_wall * 35 / 40) support_bottom_distance = =support_z_distance support_line_width = =round(line_width * 0.6 / 0.7, 2) support_z_distance = =layer_height -top_bottom_thickness = 1.2 -travel_avoid_distance = 1.5 \ No newline at end of file +top_bottom_thickness = 1.2 \ No newline at end of file diff --git a/resources/quality/ultimaker3/um3_aa0.8_CPEP_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_CPEP_Verydraft_Print.inst.cfg index ff375b6e49..9ba6195df4 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_CPEP_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_CPEP_Verydraft_Print.inst.cfg @@ -36,4 +36,3 @@ support_bottom_distance = =support_z_distance support_line_width = =round(line_width * 0.6 / 0.7, 2) support_z_distance = =layer_height top_bottom_thickness = 1.2 -travel_avoid_distance = 1.5 \ No newline at end of file diff --git a/resources/quality/ultimaker3/um3_aa0.8_PC_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PC_Fast_Print.inst.cfg index 0b666d2e0b..1d0c094496 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PC_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PC_Fast_Print.inst.cfg @@ -28,4 +28,3 @@ speed_topbottom = =math.ceil(speed_print * 25 / 50) speed_wall = =math.ceil(speed_print * 40 / 50) speed_wall_0 = =math.ceil(speed_wall * 30 / 40) support_line_width = =round(line_width * 0.6 / 0.7, 2) -travel_avoid_distance = 3 \ No newline at end of file diff --git a/resources/quality/ultimaker3/um3_aa0.8_PC_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PC_Superdraft_Print.inst.cfg index de212df4af..23f654a586 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PC_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PC_Superdraft_Print.inst.cfg @@ -28,4 +28,3 @@ speed_topbottom = =math.ceil(speed_print * 25 / 50) speed_wall = =math.ceil(speed_print * 40 / 50) speed_wall_0 = =math.ceil(speed_wall * 30 / 40) support_line_width = =round(line_width * 0.6 / 0.7, 2) -travel_avoid_distance = 3 \ No newline at end of file diff --git a/resources/quality/ultimaker3/um3_aa0.8_PC_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PC_Verydraft_Print.inst.cfg index 3e0c669eeb..82986f68cf 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PC_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PC_Verydraft_Print.inst.cfg @@ -29,4 +29,3 @@ speed_topbottom = =math.ceil(speed_print * 25 / 50) speed_wall = =math.ceil(speed_print * 40 / 50) speed_wall_0 = =math.ceil(speed_wall * 30 / 40) support_line_width = =round(line_width * 0.6 / 0.7, 2) -travel_avoid_distance = 3 \ No newline at end of file diff --git a/resources/variants/ultimaker3_aa04.inst.cfg b/resources/variants/ultimaker3_aa04.inst.cfg index 0163024fa4..b9e15f5296 100644 --- a/resources/variants/ultimaker3_aa04.inst.cfg +++ b/resources/variants/ultimaker3_aa04.inst.cfg @@ -13,6 +13,7 @@ hardware_type = nozzle brim_width = 7 machine_nozzle_cool_down_speed = 0.9 machine_nozzle_id = AA 0.4 +machine_nozzle_tip_outer_diameter = 1.0 raft_acceleration = =acceleration_print raft_airgap = 0.3 raft_base_thickness = =resolveOrValue('layer_height_0') * 1.2 diff --git a/resources/variants/ultimaker3_bb04.inst.cfg b/resources/variants/ultimaker3_bb04.inst.cfg index 93b2025031..f3cb236c2b 100644 --- a/resources/variants/ultimaker3_bb04.inst.cfg +++ b/resources/variants/ultimaker3_bb04.inst.cfg @@ -21,6 +21,7 @@ jerk_support_interface = =math.ceil(jerk_support * 10 / 15) jerk_support_bottom = =math.ceil(jerk_support_interface * 1 / 10) machine_nozzle_heat_up_speed = 1.5 machine_nozzle_id = BB 0.4 +machine_nozzle_tip_outer_diameter = 1.0 prime_tower_purge_volume = 1 raft_base_speed = 20 raft_interface_speed = 20 diff --git a/resources/variants/ultimaker3_extended_aa04.inst.cfg b/resources/variants/ultimaker3_extended_aa04.inst.cfg index 94bee65b5d..8863088a8d 100644 --- a/resources/variants/ultimaker3_extended_aa04.inst.cfg +++ b/resources/variants/ultimaker3_extended_aa04.inst.cfg @@ -13,6 +13,7 @@ hardware_type = nozzle brim_width = 7 machine_nozzle_cool_down_speed = 0.9 machine_nozzle_id = AA 0.4 +machine_nozzle_tip_outer_diameter = 1.0 raft_acceleration = =acceleration_print raft_airgap = 0.3 raft_base_thickness = =resolveOrValue('layer_height_0') * 1.2 diff --git a/resources/variants/ultimaker3_extended_bb04.inst.cfg b/resources/variants/ultimaker3_extended_bb04.inst.cfg index a995acf77c..b5b35e85ac 100644 --- a/resources/variants/ultimaker3_extended_bb04.inst.cfg +++ b/resources/variants/ultimaker3_extended_bb04.inst.cfg @@ -21,6 +21,7 @@ jerk_support_interface = =math.ceil(jerk_support * 10 / 15) jerk_support_bottom = =math.ceil(jerk_support_interface * 1 / 10) machine_nozzle_heat_up_speed = 1.5 machine_nozzle_id = BB 0.4 +machine_nozzle_tip_outer_diameter = 1.0 prime_tower_purge_volume = 1 raft_base_speed = 20 raft_interface_speed = 20 From 0caea24afcb8d94fbf32ef330a0d2cc6788be16f Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 13 Mar 2018 11:54:32 +0100 Subject: [PATCH 271/446] Add depth pass for picking a location --- cura/DepthPass.py | 60 +++++++++++++++++ plugins/SupportEraser/SupportEraser.py | 27 +++++--- resources/shaders/camera_distance.shader | 83 ++++++++++++++++++++++++ 3 files changed, 160 insertions(+), 10 deletions(-) create mode 100644 cura/DepthPass.py create mode 100644 resources/shaders/camera_distance.shader diff --git a/cura/DepthPass.py b/cura/DepthPass.py new file mode 100644 index 0000000000..3fb57b0341 --- /dev/null +++ b/cura/DepthPass.py @@ -0,0 +1,60 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from UM.Application import Application +from UM.Math.Color import Color +from UM.Resources import Resources + +from UM.View.RenderPass import RenderPass +from UM.View.GL.OpenGL import OpenGL +from UM.View.RenderBatch import RenderBatch + +from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator + + +## A RenderPass subclass that renders a depthmap of selectable objects to a texture. +# It uses the active camera by default, but it can be overridden to use a different camera. +# +# Note that in order to increase precision, the 24 bit depth value is encoded into all three of the R,G & B channels +class DepthPass(RenderPass): + def __init__(self, width: int, height: int): + super().__init__("preview", width, height, 0) + + self._renderer = Application.getInstance().getRenderer() + + self._shader = None + self._scene = Application.getInstance().getController().getScene() + + + def render(self) -> None: + if not self._shader: + self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "camera_distance.shader")) + + self._gl.glClearColor(0.0, 0.0, 0.0, 0.0) + self._gl.glClear(self._gl.GL_COLOR_BUFFER_BIT | self._gl.GL_DEPTH_BUFFER_BIT) + + # Create a new batch to be rendered + batch = RenderBatch(self._shader) + + # Fill up the batch with objects that can be sliced. ` + for node in DepthFirstIterator(self._scene.getRoot()): + if node.callDecoration("isSliceable") and node.getMeshData() and node.isVisible(): + batch.addItem(node.getWorldTransformation(), node.getMeshData()) + + self.bind() + batch.render(self._scene.getActiveCamera()) + self.release() + + ## Get the distance in mm from the camera to at a certain pixel coordinate. + def getDepthAtPosition(self, x, y): + output = self.getOutput() + + window_size = self._renderer.getWindowSize() + + px = (0.5 + x / 2.0) * window_size[0] + py = (0.5 + y / 2.0) * window_size[1] + + if px < 0 or px > (output.width() - 1) or py < 0 or py > (output.height() - 1): + return None + + distance = output.pixel(px, py) # distance in micron, from in r, g & b channels + return distance / 1000. diff --git a/plugins/SupportEraser/SupportEraser.py b/plugins/SupportEraser/SupportEraser.py index 8b3ad0f4dd..119e598886 100644 --- a/plugins/SupportEraser/SupportEraser.py +++ b/plugins/SupportEraser/SupportEraser.py @@ -4,14 +4,16 @@ from UM.Math.Vector import Vector from UM.Tool import Tool from PyQt5.QtCore import Qt, QUrl from UM.Application import Application -from UM.Event import Event +from UM.Event import Event, MouseEvent from UM.Mesh.MeshBuilder import MeshBuilder from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation from UM.Settings.SettingInstance import SettingInstance from cura.Scene.CuraSceneNode import CuraSceneNode from cura.Scene.SliceableObjectDecorator import SliceableObjectDecorator from cura.Scene.BuildPlateDecorator import BuildPlateDecorator +from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator +from cura.DepthPass import DepthPass import os import os.path @@ -25,15 +27,22 @@ class SupportEraser(Tool): def event(self, event): super().event(event) - if event.type == Event.ToolActivateEvent: + if event.type == Event.MousePressEvent and self._controller.getToolsEnabled(): + active_camera = self._controller.getScene().getActiveCamera() - # Load the remover mesh: - self._createEraserMesh() + # Create depth pass for picking + render_width, render_height = active_camera.getWindowSize() + depth_pass = DepthPass(int(render_width), int(render_height)) + depth_pass.render() - # After we load the mesh, deactivate the tool again: - self.getController().setActiveTool(None) + distance = depth_pass.getDepthAtPosition(event.x, event.y) + ray = active_camera.getRay(event.x, event.y) + picked_position = ray.getPointAlongRay(distance) - def _createEraserMesh(self): + # Add the anto_overhang_mesh cube: + self._createEraserMesh(picked_position) + + def _createEraserMesh(self, position: Vector): node = CuraSceneNode() node.setName("Eraser") @@ -41,9 +50,7 @@ class SupportEraser(Tool): mesh = MeshBuilder() mesh.addCube(10,10,10) node.setMeshData(mesh.build()) - # Place the cube in the platform. Do it manually so it works if the "automatic drop models" is OFF - move_vector = Vector(0, 5, 0) - node.setPosition(move_vector) + node.setPosition(position) active_build_plate = Application.getInstance().getMultiBuildPlateModel().activeBuildPlate diff --git a/resources/shaders/camera_distance.shader b/resources/shaders/camera_distance.shader new file mode 100644 index 0000000000..2dd90e7f15 --- /dev/null +++ b/resources/shaders/camera_distance.shader @@ -0,0 +1,83 @@ +[shaders] +vertex = + uniform highp mat4 u_modelMatrix; + uniform highp mat4 u_viewProjectionMatrix; + + attribute highp vec4 a_vertex; + + varying highp vec3 v_vertex; + + void main() + { + vec4 world_space_vert = u_modelMatrix * a_vertex; + gl_Position = u_viewProjectionMatrix * world_space_vert; + + v_vertex = world_space_vert.xyz; + } + +fragment = + uniform highp vec3 u_viewPosition; + + varying highp vec3 v_vertex; + + void main() + { + highp float distance_to_camera = distance(v_vertex, u_viewPosition) * 1000.; // distance in micron + + vec3 encoded; // encode float into 3 8-bit channels; this gives a precision of a micron at a range of up to ~16 meter + encoded.b = floor(distance_to_camera / 65536.0); + encoded.g = floor((distance_to_camera - encoded.b * 65536.0) / 256.0); + encoded.r = floor(distance_to_camera - encoded.b * 65536.0 - encoded.g * 256.0); + + gl_FragColor.rgb = encoded / 255.; + gl_FragColor.a = 1.0; + } + +vertex41core = + #version 410 + uniform highp mat4 u_modelMatrix; + uniform highp mat4 u_viewProjectionMatrix; + + in highp vec4 a_vertex; + + out highp vec3 v_vertex; + + void main() + { + vec4 world_space_vert = u_modelMatrix * a_vertex; + gl_Position = u_viewProjectionMatrix * world_space_vert; + + v_vertex = world_space_vert.xyz; + } + +fragment41core = + #version 410 + uniform highp vec3 u_viewPosition; + + in highp vec3 v_vertex; + + out vec4 frag_color; + + void main() + { + highp float distance_to_camera = distance(v_vertex, u_viewPosition) * 1000.; // distance in micron + + vec3 encoded; // encode float into 3 8-bit channels; this gives a precision of a micron at a range of up to ~16 meter + encoded.b = floor(distance_to_camera / 65536.0); + encoded.g = floor((distance_to_camera - encoded.b * 65536.0) / 256.0); + encoded.r = floor(distance_to_camera - encoded.b * 65536.0 - encoded.g * 256.0); + + frag_color.rgb = encoded / 255.; + frag_color.a = 1.0; + } + +[defaults] + +[bindings] +u_modelMatrix = model_matrix +u_viewProjectionMatrix = view_projection_matrix +u_normalMatrix = normal_matrix +u_viewPosition = view_position + +[attributes] +a_vertex = vertex From 6d2d9c8fe2a1b5974babe2a64bc23fcc8fb304c4 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Tue, 13 Mar 2018 12:39:10 +0100 Subject: [PATCH 272/446] CURA-4946 Fixed typo --- cura/Settings/CuraContainerRegistry.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index 828897b4dd..81cbabc0c9 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -273,11 +273,11 @@ class CuraContainerRegistry(ContainerRegistry): elif profile_index < len(machine_extruders) + 1: # This is assumed to be an extruder profile extruder_id = machine_extruders[profile_index - 1].definition.getId() - extuder_position = str(profile_index - 1) + extruder_position = str(profile_index - 1) if not profile.getMetaDataEntry("position"): - profile.addMetaDataEntry("position", extuder_position) + profile.addMetaDataEntry("position", extruder_position) else: - profile.setMetaDataEntry("position", extuder_position) + profile.setMetaDataEntry("position", extruder_position) profile_id = (extruder_id + "_" + name_seed).lower().replace(" ", "_") else: #More extruders in the imported file than in the machine. From 0897c740b080b8f7ecc271b782bb18d983850dff Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 13 Mar 2018 12:57:03 +0100 Subject: [PATCH 273/446] Fix typo in log --- cura/Settings/MachineManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index eb720000bf..f52b90e80f 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -335,7 +335,7 @@ class MachineManager(QObject): return False if self._global_container_stack.hasErrors(): - Logger.log("d", "Checking global stack for errors took %0.2f s and we found and error" % (time.time() - time_start)) + Logger.log("d", "Checking global stack for errors took %0.2f s and we found an error" % (time.time() - time_start)) return True # Not a very pretty solution, but the extruder manager doesn't really know how many extruders there are From dfb903fb8113b2694085d95f80d3982ab4707a16 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 13 Mar 2018 13:14:29 +0100 Subject: [PATCH 274/446] CURA-4870 Wait until the configuration has all the mandatory data before add it to the list of unique configurations. Remove some connections to signals and reuse already defined listeners. --- cura/PrinterOutput/ConfigurationModel.py | 10 ++++++++++ .../ExtruderConfigurationModel.py | 7 ++++++- cura/PrinterOutput/ExtruderOutputModel.py | 18 ++++++++---------- cura/PrinterOutput/PrinterOutputModel.py | 18 ++++++++++-------- cura/PrinterOutputDevice.py | 2 +- .../ClusterUM3OutputDevice.py | 2 +- 6 files changed, 36 insertions(+), 21 deletions(-) diff --git a/cura/PrinterOutput/ConfigurationModel.py b/cura/PrinterOutput/ConfigurationModel.py index 23ed687fb8..c03d968b9e 100644 --- a/cura/PrinterOutput/ConfigurationModel.py +++ b/cura/PrinterOutput/ConfigurationModel.py @@ -40,6 +40,16 @@ class ConfigurationModel(QObject): def buildplateConfiguration(self): return self._buildplate_configuration + ## This method is intended to indicate whether the configuration is valid or not. + # The method checks if the mandatory fields are or not set + def isValid(self): + if not self._extruder_configurations: + return False + for configuration in self._extruder_configurations: + if configuration is None: + return False + return self._printer_type is not None + def __str__(self): message_chunks = [] message_chunks.append("Printer type: " + self._printer_type) diff --git a/cura/PrinterOutput/ExtruderConfigurationModel.py b/cura/PrinterOutput/ExtruderConfigurationModel.py index 34eddb3038..e49ffe13d7 100644 --- a/cura/PrinterOutput/ExtruderConfigurationModel.py +++ b/cura/PrinterOutput/ExtruderConfigurationModel.py @@ -35,8 +35,13 @@ class ExtruderConfigurationModel(QObject): def hotendID(self): return self._hotend_id + ## This method is intended to indicate whether the configuration is valid or not. + # The method checks if the mandatory fields are or not set + def isValid(self): + return self._material is not None and self._hotend_id is not None and self.material.guid is not None + def __str__(self): - if self._material is None or self._hotend_id is None or self.material.type is None: + if not self.isValid(): return "No information" return "Position: " + str(self._position) + " - Material: " + self._material.type + " - HotendID: " + self._hotend_id diff --git a/cura/PrinterOutput/ExtruderOutputModel.py b/cura/PrinterOutput/ExtruderOutputModel.py index df47bca71a..e4c7f1608e 100644 --- a/cura/PrinterOutput/ExtruderOutputModel.py +++ b/cura/PrinterOutput/ExtruderOutputModel.py @@ -28,9 +28,7 @@ class ExtruderOutputModel(QObject): self._hotend_id = "" self._active_material = None # type: Optional[MaterialOutputModel] self._extruder_configuration = ExtruderConfigurationModel() - # Update the configuration every time the hotend or the active material change - self.hotendIDChanged.connect(self._updateExtruderConfiguration) - self.activeMaterialChanged.connect(self._updateExtruderConfiguration) + self._extruder_configuration.position = self._position @pyqtProperty(QObject, notify = activeMaterialChanged) def activeMaterial(self) -> "MaterialOutputModel": @@ -39,7 +37,9 @@ class ExtruderOutputModel(QObject): def updateActiveMaterial(self, material: Optional["MaterialOutputModel"]): if self._active_material != material: self._active_material = material + self._extruder_configuration.material = self._active_material self.activeMaterialChanged.emit() + self.extruderConfigurationChanged.emit() ## Update the hotend temperature. This only changes it locally. def updateHotendTemperature(self, temperature: float): @@ -73,14 +73,12 @@ class ExtruderOutputModel(QObject): def updateHotendID(self, id: str): if self._hotend_id != id: self._hotend_id = id + self._extruder_configuration.hotendID = self._hotend_id self.hotendIDChanged.emit() + self.extruderConfigurationChanged.emit() @pyqtProperty(QObject, notify = extruderConfigurationChanged) def extruderConfiguration(self): - return self._extruder_configuration - - def _updateExtruderConfiguration(self): - self._extruder_configuration.position = self._position - self._extruder_configuration.material = self._active_material - self._extruder_configuration.hotendID = self._hotend_id - self.extruderConfigurationChanged.emit() + if self._extruder_configuration.isValid(): + return self._extruder_configuration + return None diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index 04f2c1eb62..712f9b5b1e 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -45,9 +45,7 @@ class PrinterOutputModel(QObject): self._buildplate_name = None # Update the printer configuration every time any of the extruders changes its configuration for extruder in self._extruders: - extruder.extruderConfigurationChanged.connect(self._updatePrinterConfiguration) - self.printerTypeChanged.connect(self._updatePrinterConfiguration) - self.buildplateChanged.connect(self._updatePrinterConfiguration) + extruder.extruderConfigurationChanged.connect(self._updateExtruderConfiguration) self._camera = None @@ -80,16 +78,20 @@ class PrinterOutputModel(QObject): def updateType(self, printer_type): if self._printer_type != printer_type: self._printer_type = printer_type + self._printer_configuration.printerType = self._printer_type self.printerTypeChanged.emit() + self.configurationChanged.emit() @pyqtProperty(str, notify = buildplateChanged) def buildplate(self): return self._buildplate_name - def updateBuildplate(self, buildplate_name): + def updateBuildplateName(self, buildplate_name): if self._buildplate_name != buildplate_name: self._buildplate_name = buildplate_name + self._printer_configuration.buildplateConfiguration = self._buildplate_name self.buildplateChanged.emit() + self.configurationChanged.emit() @pyqtProperty(str, notify=keyChanged) def key(self): @@ -260,10 +262,10 @@ class PrinterOutputModel(QObject): # Returns the configuration (material, variant and buildplate) of the current printer @pyqtProperty(QObject, notify = configurationChanged) def printerConfiguration(self): - return self._printer_configuration + if self._printer_configuration.isValid(): + return self._printer_configuration + return None - def _updatePrinterConfiguration(self): - self._printer_configuration.printerType = self._printer_type + def _updateExtruderConfiguration(self): self._printer_configuration.extruderConfigurations = [extruder.extruderConfiguration for extruder in self._extruders] - self._printer_configuration.buildplateConfiguration = self._buildplate_name self.configurationChanged.emit() diff --git a/cura/PrinterOutputDevice.py b/cura/PrinterOutputDevice.py index 453cb4d78a..4d6ddb8dfa 100644 --- a/cura/PrinterOutputDevice.py +++ b/cura/PrinterOutputDevice.py @@ -187,7 +187,7 @@ class PrinterOutputDevice(QObject, OutputDevice): return self._unique_configurations def _updateUniqueConfigurations(self): - self._unique_configurations = list(set([printer.printerConfiguration for printer in self._printers])) + self._unique_configurations = list(set([printer.printerConfiguration for printer in self._printers if printer.printerConfiguration is not None])) self._unique_configurations.sort(key = lambda k: k.printerType) self.uniqueConfigurationsChanged.emit() diff --git a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py index 942bc82280..77b64ee080 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py @@ -384,7 +384,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): # Do not store the buildplate information that comes from connect if the current printer has not buildplate information if "build_plate" in data and machine_definition.getMetaDataEntry("has_variant_buildplates", False): - printer.updateBuildplate(data["build_plate"]["type"]) + printer.updateBuildplateName(data["build_plate"]["type"]) if not data["enabled"]: printer.updateState("disabled") else: From d6979bc89ad3d8c90be0336a294e08d69cea98e8 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 13 Mar 2018 13:14:33 +0100 Subject: [PATCH 275/446] CURA-4400 using an intermediate variable prevents an empty popup that occured now and then --- resources/qml/SidebarHeader.qml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 473f4c5cc8..4bda8074b1 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -91,6 +91,8 @@ Column exclusiveGroup: extruderMenuGroup checked: base.currentExtruderIndex == index + property bool extruder_enabled: true + MouseArea { anchors.fill: parent @@ -102,6 +104,7 @@ Column Cura.ExtruderManager.setActiveExtruderIndex(index); break; case Qt.RightButton: + extruder_enabled = Cura.MachineManager.getExtruder(model.index).isEnabled extruderMenu.popup(); break; } @@ -116,13 +119,13 @@ Column MenuItem { text: catalog.i18nc("@action:inmenu", "Enable Extruder") onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, true) - visible: !Cura.MachineManager.getExtruder(model.index).isEnabled + visible: !extruder_enabled // using an intermediate variable prevents an empty popup that occured now and then } MenuItem { text: catalog.i18nc("@action:inmenu", "Disable Extruder") onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false) - visible: Cura.MachineManager.getExtruder(model.index).isEnabled + visible: extruder_enabled } } From 934d297e6c657e3b10962bae5bd40556fb84da22 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 13 Mar 2018 13:21:41 +0100 Subject: [PATCH 276/446] Split error checking into smaller sub-tasks CURA-5059 Split stack error checking into smaller sub-tasks so running them on the Qt thread will not block GUI updates from happening for too long. --- cura/CuraApplication.py | 25 ++- cura/Machines/MachineErrorChecker.py | 184 ++++++++++++++++++ cura/Settings/MachineManager.py | 29 +-- .../CuraEngineBackend/CuraEngineBackend.py | 75 ++++--- 4 files changed, 253 insertions(+), 60 deletions(-) create mode 100644 cura/Machines/MachineErrorChecker.py diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index f39c2ba554..e8d38d3942 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -67,6 +67,8 @@ from cura.Machines.Models.MaterialManagementModel import MaterialManagementModel from cura.Machines.Models.GenericMaterialsModel import GenericMaterialsModel from cura.Machines.Models.BrandMaterialsModel import BrandMaterialsModel +from cura.Machines.MachineErrorChecker import MachineErrorChecker + from cura.Settings.SettingInheritanceManager import SettingInheritanceManager from cura.Settings.SimpleModeSettingsManager import SimpleModeSettingsManager @@ -142,12 +144,6 @@ class CuraApplication(QtApplication): Q_ENUMS(ResourceTypes) - # FIXME: This signal belongs to the MachineManager, but the CuraEngineBackend plugin requires on it. - # Because plugins are initialized before the ContainerRegistry, putting this signal in MachineManager - # will make it initialized before ContainerRegistry does, and it won't find the active machine, thus - # Cura will always show the Add Machine Dialog upon start. - stacksValidationFinished = pyqtSignal() # Emitted whenever a validation is finished - def __init__(self, **kwargs): # this list of dir names will be used by UM to detect an old cura directory for dir_name in ["extruders", "machine_instances", "materials", "plugins", "quality", "user", "variants"]: @@ -224,12 +220,14 @@ class CuraApplication(QtApplication): self._machine_manager = None # This is initialized on demand. self._extruder_manager = None self._material_manager = None + self._quality_manager = None self._object_manager = None self._build_plate_model = None self._multi_build_plate_model = None self._setting_inheritance_manager = None self._simple_mode_settings_manager = None self._cura_scene_controller = None + self._machine_error_checker = None self._additional_components = {} # Components to add to certain areas in the interface @@ -743,19 +741,28 @@ class CuraApplication(QtApplication): self.preRun() container_registry = ContainerRegistry.getInstance() + + Logger.log("i", "Initializing variant manager") self._variant_manager = VariantManager(container_registry) self._variant_manager.initialize() + Logger.log("i", "Initializing material manager") from cura.Machines.MaterialManager import MaterialManager self._material_manager = MaterialManager(container_registry, parent = self) self._material_manager.initialize() + Logger.log("i", "Initializing quality manager") from cura.Machines.QualityManager import QualityManager self._quality_manager = QualityManager(container_registry, parent = self) self._quality_manager.initialize() + Logger.log("i", "Initializing machine manager") self._machine_manager = MachineManager(self) + Logger.log("i", "Initializing machine error checker") + self._machine_error_checker = MachineErrorChecker(self) + self._machine_error_checker.initialize() + # Check if we should run as single instance or not self._setUpSingleInstanceServer() @@ -781,8 +788,11 @@ class CuraApplication(QtApplication): self._openFile(file_name) self.started = True + self.initializationFinished.emit() self.exec_() + initializationFinished = pyqtSignal() + ## Run Cura without GUI elements and interaction (server mode). def runWithoutGUI(self): self._use_gui = False @@ -847,6 +857,9 @@ class CuraApplication(QtApplication): def hasGui(self): return self._use_gui + def getMachineErrorChecker(self, *args) -> MachineErrorChecker: + return self._machine_error_checker + def getMachineManager(self, *args) -> MachineManager: if self._machine_manager is None: self._machine_manager = MachineManager(self) diff --git a/cura/Machines/MachineErrorChecker.py b/cura/Machines/MachineErrorChecker.py new file mode 100644 index 0000000000..871e70310b --- /dev/null +++ b/cura/Machines/MachineErrorChecker.py @@ -0,0 +1,184 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from collections import deque + +from PyQt5.QtCore import QObject, QTimer, pyqtSignal, pyqtProperty + +from UM.Application import Application +from UM.Logger import Logger + + +# +# This class performs setting error checks for the currently active machine. +# +# The whole error checking process is pretty heavy which can take ~0.5 secs, so it can cause GUI to lag. +# The idea here is to split the whole error check into small tasks, each of which only checks a single setting key +# in a stack. According to my profiling results, the maximal runtime for such a sub-task is <0.03 secs, which should +# be good enough. Moreover, if any changes happened to the machine, we can cancel the check in progress without wait +# for it to finish the complete work. +# +class MachineErrorChecker(QObject): + + def __init__(self, parent = None): + super().__init__(parent) + + self._global_stack = None + + self._has_errors = True # Result of the error check, indicating whether there are errors in the stack + self._error_keys = set() # A set of settings keys that have errors + self._error_keys_in_progress = set() # The variable that stores the results of the currently in progress check + + self._stacks_to_check = None # a FIFO queue of stacks to check for errors + self._keys_to_check = None # a FIFO queue of setting keys to check for errors + + self._need_to_check = False # Whether we need to schedule a new check or not. This flag is set when a new + # error check needs to take place while there is already one running at the moment. + self._check_in_progress = False # Whether there is an error check running in progress at the moment. + + self._application = Application.getInstance() + self._machine_manager = self._application.getMachineManager() + + # This timer delays the starting of error check so we can react less frequently if the user is frequently + # changing settings. + self._error_check_timer = QTimer(self) + self._error_check_timer.setInterval(300) + self._error_check_timer.setSingleShot(True) + + def initialize(self): + self._error_check_timer.timeout.connect(self._rescheduleCheck) + + # Reconnect all signals when the active machine gets changed. + self._machine_manager.globalContainerChanged.connect(self._onMachineChanged) + + # Whenever the machine settings get changed, we schedule an error check. + self._machine_manager.globalContainerChanged.connect(self.startErrorCheck) + self._machine_manager.globalValueChanged.connect(self.startErrorCheck) + + self._onMachineChanged() + + def _onMachineChanged(self): + if self._global_stack: + self._global_stack.propertyChanged.disconnect(self.startErrorCheck) + self._global_stack.containersChanged.disconnect(self.startErrorCheck) + + for extruder in self._global_stack.extruders.values(): + extruder.propertyChanged.disconnect(self.startErrorCheck) + extruder.containersChanged.disconnect(self.startErrorCheck) + + self._global_stack = self._machine_manager.activeMachine + + if self._global_stack: + self._global_stack.propertyChanged.connect(self.startErrorCheck) + self._global_stack.containersChanged.connect(self.startErrorCheck) + + for extruder in self._global_stack.extruders.values(): + extruder.propertyChanged.connect(self.startErrorCheck) + extruder.containersChanged.connect(self.startErrorCheck) + + hasErrorUpdated = pyqtSignal() + needToWaitForResultChanged = pyqtSignal() + errorCheckFinished = pyqtSignal() + + @pyqtProperty(bool, notify = hasErrorUpdated) + def hasError(self) -> bool: + return self._has_errors + + @pyqtProperty(bool, notify = needToWaitForResultChanged) + def needToWaitForResult(self) -> bool: + return self._need_to_check or self._check_in_progress + + # Starts the error check timer to schedule a new error check. + def startErrorCheck(self, *args): + if not self._check_in_progress: + self._need_to_check = True + self.needToWaitForResultChanged.emit() + self._error_check_timer.start() + + # This function is called by the timer to reschedule a new error check. + # If there is no check in progress, it will start a new one. If there is any, it sets the "_need_to_check" flag + # to notify the current check to stop and start a new one. + def _rescheduleCheck(self): + if self._check_in_progress and not self._need_to_check: + self._need_to_check = True + self.needToWaitForResultChanged.emit() + return + + self._error_keys_in_progress = set() + self._need_to_check = False + self.needToWaitForResultChanged.emit() + + global_stack = self._machine_manager.activeMachine + if global_stack is None: + Logger.log("i", "No active machine, nothing to check.") + return + + self._stacks_to_check = deque([global_stack] + list(global_stack.extruders.values())) + self._keys_to_check = deque(global_stack.getAllKeys()) + + self._application.callLater(self._checkStack) + Logger.log("d", "New error check scheduled.") + + def _checkStack(self): + from UM.Settings.SettingDefinition import SettingDefinition + from UM.Settings.Validator import ValidatorState + + if self._need_to_check: + Logger.log("d", "Need to check for errors again. Discard the current progress and reschedule a check.") + self._check_in_progress = False + self._application.callLater(self.startErrorCheck) + return + + self._check_in_progress = True + + # If there is nothing to check any more, it means there is no error. + if not self._stacks_to_check or not self._keys_to_check: + # Finish + self._setResult(False) + return + + stack = self._stacks_to_check[0] + key = self._keys_to_check.popleft() + + # If there is no key left in this stack, check the next stack later. + if not self._keys_to_check: + if len(self._stacks_to_check) == 1: + stacks = None + keys = None + else: + stack = self._stacks_to_check.popleft() + self._keys_to_check = deque(stack.getAllKeys()) + + enabled = stack.getProperty(key, "enabled") + if not enabled: + self._application.callLater(self._checkStack) + return + + validation_state = stack.getProperty(key, "validationState") + if validation_state is None: + # Setting is not validated. This can happen if there is only a setting definition. + # We do need to validate it, because a setting definitions value can be set by a function, which could + # be an invalid setting. + definition = stack.getSettingDefinition(key) + validator_type = SettingDefinition.getValidatorForType(definition.type) + if validator_type: + validator = validator_type(key) + validation_state = validator(stack) + if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError): + # Finish + self._setResult(True) + return + + # Schedule the check for the next key + self._application.callLater(self._checkStack) + + def _setResult(self, result: bool): + if result != self._has_errors: + self._has_errors = result + self.hasErrorUpdated.emit() + self._machine_manager.stacksValidationChanged.emit() + self._need_to_check = False + self._check_in_progress = False + self.needToWaitForResultChanged.emit() + self.errorCheckFinished.emit() + Logger.log("i", "Error check finished, result = %s", result) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index eb720000bf..f543910447 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -4,7 +4,7 @@ import collections import time #Type hinting. -from typing import Union, List, Dict, TYPE_CHECKING, Optional +from typing import List, Dict, TYPE_CHECKING, Optional from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Signal import Signal @@ -20,7 +20,6 @@ from UM.Logger import Logger from UM.Message import Message from UM.Settings.ContainerRegistry import ContainerRegistry -from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.SettingFunction import SettingFunction from UM.Signal import postponeSignals, CompressTechnique @@ -56,11 +55,6 @@ class MachineManager(QObject): self.machine_extruder_material_update_dict = collections.defaultdict(list) - self._error_check_timer = QTimer() - self._error_check_timer.setInterval(250) - self._error_check_timer.setSingleShot(True) - self._error_check_timer.timeout.connect(self._updateStacksHaveErrors) - self._instance_container_timer = QTimer() self._instance_container_timer.setInterval(250) self._instance_container_timer.setSingleShot(True) @@ -228,15 +222,6 @@ class MachineManager(QObject): del self.machine_extruder_material_update_dict[self._global_container_stack.getId()] self.activeQualityGroupChanged.emit() - self._error_check_timer.start() - - ## Update self._stacks_valid according to _checkStacksForErrors and emit if change. - def _updateStacksHaveErrors(self) -> None: - old_stacks_have_errors = self._stacks_have_errors - self._stacks_have_errors = self._checkStacksHaveErrors() - if old_stacks_have_errors != self._stacks_have_errors: - self.stacksValidationChanged.emit() - Application.getInstance().stacksValidationFinished.emit() def _onActiveExtruderStackChanged(self) -> None: self.blurSettings.emit() # Ensure no-one has focus. @@ -256,8 +241,6 @@ class MachineManager(QObject): self.rootMaterialChanged.emit() - self._error_check_timer.start() - def _onInstanceContainersChanged(self, container) -> None: self._instance_container_timer.start() @@ -266,9 +249,6 @@ class MachineManager(QObject): # Notify UI items, such as the "changed" star in profile pull down menu. self.activeStackValueChanged.emit() - elif property_name == "validationState": - self._error_check_timer.start() - ## Given a global_stack, make sure that it's all valid by searching for this quality group and applying it again def _initMachineState(self, global_stack): material_dict = {} @@ -832,9 +812,10 @@ class MachineManager(QObject): ## This will fire the propertiesChanged for all settings so they will be updated in the front-end def forceUpdateAllSettings(self): - property_names = ["value", "resolve"] - for setting_key in self._global_container_stack.getAllKeys(): - self._global_container_stack.propertiesChanged.emit(setting_key, property_names) + with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): + property_names = ["value", "resolve"] + for setting_key in self._global_container_stack.getAllKeys(): + self._global_container_stack.propertiesChanged.emit(setting_key, property_names) @pyqtSlot(int, bool) def setExtruderEnabled(self, position: int, enabled) -> None: diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index 2f57e634e0..af6162c8d5 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -10,7 +10,6 @@ from UM.Logger import Logger from UM.Message import Message from UM.PluginRegistry import PluginRegistry from UM.Resources import Resources -from UM.Settings.Validator import ValidatorState #To find if a setting is in an error state. We can't slice then. from UM.Platform import Platform from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Qt.Duration import DurationFormat @@ -32,6 +31,7 @@ import Arcus from UM.i18n import i18nCatalog catalog = i18nCatalog("cura") + class CuraEngineBackend(QObject, Backend): backendError = Signal() @@ -62,23 +62,26 @@ class CuraEngineBackend(QObject, Backend): default_engine_location = execpath break + self._application = Application.getInstance() + self._multi_build_plate_model = None + self._machine_error_checker = None + if not default_engine_location: raise EnvironmentError("Could not find CuraEngine") - Logger.log("i", "Found CuraEngine at: %s" %(default_engine_location)) + Logger.log("i", "Found CuraEngine at: %s", default_engine_location) default_engine_location = os.path.abspath(default_engine_location) Preferences.getInstance().addPreference("backend/location", default_engine_location) # Workaround to disable layer view processing if layer view is not active. self._layer_view_active = False - Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged) - Application.getInstance().getMultiBuildPlateModel().activeBuildPlateChanged.connect(self._onActiveViewChanged) self._onActiveViewChanged() + self._stored_layer_data = [] self._stored_optimized_layer_data = {} # key is build plate number, then arrays are stored until they go to the ProcessSlicesLayersJob - self._scene = Application.getInstance().getController().getScene() + self._scene = self._application.getController().getScene() self._scene.sceneChanged.connect(self._onSceneChanged) # Triggers for auto-slicing. Auto-slicing is triggered as follows: @@ -86,20 +89,10 @@ class CuraEngineBackend(QObject, Backend): # - whenever there is a value change, we start the timer # - sometimes an error check can get scheduled for a value change, in that case, we ONLY want to start the # auto-slicing timer when that error check is finished - # If there is an error check, it will set the "_is_error_check_scheduled" flag, stop the auto-slicing timer, - # and only wait for the error check to be finished to start the auto-slicing timer again. + # If there is an error check, stop the auto-slicing timer, and only wait for the error check to be finished + # to start the auto-slicing timer again. # self._global_container_stack = None - Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged) - self._onGlobalStackChanged() - - Application.getInstance().stacksValidationFinished.connect(self._onStackErrorCheckFinished) - # extruder enable / disable. Actually wanted to use machine manager here, but the initialization order causes it to crash - ExtruderManager.getInstance().extrudersChanged.connect(self._extruderChanged) - - # A flag indicating if an error check was scheduled - # If so, we will stop the auto-slice timer and start upon the error check - self._is_error_check_scheduled = False # Listeners for receiving messages from the back-end. self._message_handlers["cura.proto.Layer"] = self._onLayerMessage @@ -125,13 +118,6 @@ class CuraEngineBackend(QObject, Backend): self._last_num_objects = defaultdict(int) # Count number of objects to see if there is something changed self._postponed_scene_change_sources = [] # scene change is postponed (by a tool) - self.backendQuit.connect(self._onBackendQuit) - self.backendConnected.connect(self._onBackendConnected) - - # When a tool operation is in progress, don't slice. So we need to listen for tool operations. - Application.getInstance().getController().toolOperationStarted.connect(self._onToolOperationStarted) - Application.getInstance().getController().toolOperationStopped.connect(self._onToolOperationStopped) - self._slice_start_time = None Preferences.getInstance().addPreference("general/auto_slice", True) @@ -146,6 +132,30 @@ class CuraEngineBackend(QObject, Backend): self.determineAutoSlicing() Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged) + self._application.initializationFinished.connect(self.initialize) + + def initialize(self): + self._multi_build_plate_model = self._application.getMultiBuildPlateModel() + + self._application.getController().activeViewChanged.connect(self._onActiveViewChanged) + self._multi_build_plate_model.activeBuildPlateChanged.connect(self._onActiveViewChanged) + + self._application.globalContainerStackChanged.connect(self._onGlobalStackChanged) + self._onGlobalStackChanged() + + # extruder enable / disable. Actually wanted to use machine manager here, but the initialization order causes it to crash + ExtruderManager.getInstance().extrudersChanged.connect(self._extruderChanged) + + self.backendQuit.connect(self._onBackendQuit) + self.backendConnected.connect(self._onBackendConnected) + + # When a tool operation is in progress, don't slice. So we need to listen for tool operations. + self._application.getController().toolOperationStarted.connect(self._onToolOperationStarted) + self._application.getController().toolOperationStopped.connect(self._onToolOperationStopped) + + self._machine_error_checker = self._application.getMachineErrorChecker() + self._machine_error_checker.errorCheckFinished.connect(self._onStackErrorCheckFinished) + ## Terminate the engine process. # # This function should terminate the engine process. @@ -531,11 +541,9 @@ class CuraEngineBackend(QObject, Backend): elif property == "validationState": if self._use_timer: - self._is_error_check_scheduled = True self._change_timer.stop() def _onStackErrorCheckFinished(self): - self._is_error_check_scheduled = False if not self._slicing and self._build_plates_to_be_sliced: self.needsSlicing() self._onChanged() @@ -561,12 +569,15 @@ class CuraEngineBackend(QObject, Backend): self.processingProgress.emit(message.amount) self.backendStateChange.emit(BackendState.Processing) - # testing def _invokeSlice(self): if self._use_timer: # if the error check is scheduled, wait for the error check finish signal to trigger auto-slice, # otherwise business as usual - if self._is_error_check_scheduled: + if self._machine_error_checker is None: + self._change_timer.stop() + return + + if self._machine_error_checker.needToWaitForResult: self._change_timer.stop() else: self._change_timer.start() @@ -632,7 +643,11 @@ class CuraEngineBackend(QObject, Backend): if self._use_timer: # if the error check is scheduled, wait for the error check finish signal to trigger auto-slice, # otherwise business as usual - if self._is_error_check_scheduled: + if self._machine_error_checker is None: + self._change_timer.stop() + return + + if self._machine_error_checker.needToWaitForResult: self._change_timer.stop() else: self._change_timer.start() @@ -786,7 +801,7 @@ class CuraEngineBackend(QObject, Backend): self._change_timer.start() def _extruderChanged(self): - for build_plate_number in range(Application.getInstance().getMultiBuildPlateModel().maxBuildPlate + 1): + for build_plate_number in range(self._multi_build_plate_model.maxBuildPlate + 1): if build_plate_number not in self._build_plates_to_be_sliced: self._build_plates_to_be_sliced.append(build_plate_number) self._invokeSlice() From d10f0f7781a1767ed41a6dd13edff31d15d15d67 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Tue, 13 Mar 2018 13:29:00 +0100 Subject: [PATCH 277/446] CURA-5071 Added brackets --- resources/qml/SidebarSimple.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index d24c047058..a7c8a1b8c5 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -519,8 +519,9 @@ Item // Update value only if the Recomended mode is Active, // Otherwise if I change the value in the Custom mode the Recomended view will try to repeat // same operation - if (UM.Preferences.getValue("cura/active_mode") == 0) + if (UM.Preferences.getValue("cura/active_mode") == 0) { Cura.MachineManager.setSettingForAllExtruders("infill_sparse_density", "value", roundedSliderValue) + } } style: SliderStyle From 9196802e8353a832f35a7a2fbc19c30f9deda449 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 13 Mar 2018 13:40:31 +0100 Subject: [PATCH 278/446] CURA-4870 Clean the error messages from qml by not rendering components if there is no outputDevice defined. --- .../qml/Menus/ConfigurationMenu/ConfigurationListView.qml | 4 ++-- .../qml/Menus/ConfigurationMenu/ConfigurationSelection.qml | 5 ++++- resources/qml/Menus/ConfigurationMenu/SyncButton.qml | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml index 1bb81656a3..4a2d4cd062 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -11,7 +11,7 @@ import Cura 1.0 as Cura Column { id: base - property var outputDevice: Cura.MachineManager.printerOutputDevices[0] + property var outputDevice: null property var computedHeight: container.height + configurationListHeading.height + 3 * padding height: childrenRect.height + 2 * padding padding: UM.Theme.getSize("default_margin").width @@ -78,7 +78,7 @@ Column onUniqueConfigurationsChanged: { // FIXME For now the model should be removed and then created again, otherwise changes in the printer don't automatically update the UI - configurationList.model = null + configurationList.model = [] configurationList.model = outputDevice.uniqueConfigurations } } diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml index 3b053afb15..eb0d5f5cff 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml @@ -11,11 +11,13 @@ import Cura 1.0 as Cura Item { id: configurationSelector + property var connectedDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null property var panelWidth: control.width property var panelVisible: false SyncButton { onClicked: configurationSelector.state == "open" ? configurationSelector.state = "closed" : configurationSelector.state = "open" + outputDevice: connectedDevice } Popup { @@ -24,11 +26,12 @@ Item y: configurationSelector.height - UM.Theme.getSize("default_lining").height x: configurationSelector.width - width width: panelWidth - visible: panelVisible + visible: panelVisible && connectedDevice != null padding: UM.Theme.getSize("default_lining").width contentItem: ConfigurationListView { id: configList width: panelWidth - 2 * popup.padding + outputDevice: connectedDevice } background: Rectangle { color: UM.Theme.getColor("setting_control") diff --git a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml index 3748fd0cb4..a2d1d53b78 100644 --- a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml +++ b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml @@ -11,7 +11,7 @@ import Cura 1.0 as Cura Button { id: base - property var outputDevice: Cura.MachineManager.printerOutputDevices[0] + property var outputDevice: null property var matched: updateOnSync() text: matched == true ? "Yes" : "No" width: parent.width From 09d01f2207e01246e8714fad7df7fd006dce912f Mon Sep 17 00:00:00 2001 From: Aleksei S Date: Tue, 13 Mar 2018 13:51:19 +0100 Subject: [PATCH 279/446] Fix: Group models were not slicable CURA-5082 --- cura/BuildVolume.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 275fce6995..0b81a5183f 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -239,7 +239,7 @@ class BuildVolume(SceneNode): # Group nodes should override the _outside_buildarea property of their children. for group_node in group_nodes: for child_node in group_node.getAllChildren(): - child_node.setOutsideBuildArea(group_node.isOutsideBuildArea) + child_node.setOutsideBuildArea(group_node.isOutsideBuildArea()) ## Update the outsideBuildArea of a single node, given bounds or current build volume def checkBoundsAndUpdate(self, node: CuraSceneNode, bounds: Optional[AxisAlignedBox] = None): From cf3032605c70ba5eefba856f306214aa8be5994b Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 13 Mar 2018 13:53:41 +0100 Subject: [PATCH 280/446] CURA-4400 fix extruderValue / getExtruderValue for extruder_index -1 --- cura/Settings/ExtruderManager.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index 0ac3e4bd66..2b422ec406 100755 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -668,6 +668,8 @@ class ExtruderManager(QObject): # global stack if not found. @staticmethod def getExtruderValue(extruder_index, key): + if extruder_index == -1: + extruder_index = int(Application.getInstance().getMachineManager().defaultExtruderPosition) extruder = ExtruderManager.getInstance().getExtruderStack(extruder_index) if extruder: From 6b7fc8b90355766795639cbf3a8f529cec1cf6e4 Mon Sep 17 00:00:00 2001 From: THeijmans Date: Tue, 13 Mar 2018 15:00:24 +0100 Subject: [PATCH 281/446] Removed retraction z hops from variants To make single extrusion mode work. --- resources/variants/ultimaker3_aa0.8.inst.cfg | 1 - resources/variants/ultimaker3_extended_aa0.8.inst.cfg | 1 - resources/variants/ultimaker3_extended_bb0.8.inst.cfg | 1 - 3 files changed, 3 deletions(-) diff --git a/resources/variants/ultimaker3_aa0.8.inst.cfg b/resources/variants/ultimaker3_aa0.8.inst.cfg index 9f011b9164..0bccf91b7c 100644 --- a/resources/variants/ultimaker3_aa0.8.inst.cfg +++ b/resources/variants/ultimaker3_aa0.8.inst.cfg @@ -45,7 +45,6 @@ retraction_amount = 6.5 retraction_count_max = 25 retraction_extrusion_window = 1 retraction_hop = 2 -retraction_hop_enabled = True retraction_hop_only_when_collides = True skin_overlap = 5 speed_equalize_flow_enabled = True diff --git a/resources/variants/ultimaker3_extended_aa0.8.inst.cfg b/resources/variants/ultimaker3_extended_aa0.8.inst.cfg index 2dfd64a94b..184416b06e 100644 --- a/resources/variants/ultimaker3_extended_aa0.8.inst.cfg +++ b/resources/variants/ultimaker3_extended_aa0.8.inst.cfg @@ -45,7 +45,6 @@ retraction_amount = 6.5 retraction_count_max = 25 retraction_extrusion_window = 1 retraction_hop = 2 -retraction_hop_enabled = True retraction_hop_only_when_collides = True skin_overlap = 5 speed_equalize_flow_enabled = True diff --git a/resources/variants/ultimaker3_extended_bb0.8.inst.cfg b/resources/variants/ultimaker3_extended_bb0.8.inst.cfg index 42d7d85728..8a1a9373f3 100644 --- a/resources/variants/ultimaker3_extended_bb0.8.inst.cfg +++ b/resources/variants/ultimaker3_extended_bb0.8.inst.cfg @@ -56,7 +56,6 @@ retraction_amount = 4.5 retraction_count_max = 15 retraction_extrusion_window = =retraction_amount retraction_hop = 2 -retraction_hop_enabled = True retraction_hop_only_when_collides = True retraction_min_travel = 5 retraction_prime_speed = 15 From 180139090a085be88ce4aa2e8b5ff2712589917f Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 13 Mar 2018 15:54:00 +0100 Subject: [PATCH 282/446] CURA-4870 Reuse the filter in findContainerStacks to find specific printers. Allow to show configurations with empty material or variant. --- cura/PrinterOutput/ExtruderConfigurationModel.py | 13 +++++++++---- cura/Settings/MachineManager.py | 13 ++----------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/cura/PrinterOutput/ExtruderConfigurationModel.py b/cura/PrinterOutput/ExtruderConfigurationModel.py index e49ffe13d7..bc7f1a7c07 100644 --- a/cura/PrinterOutput/ExtruderConfigurationModel.py +++ b/cura/PrinterOutput/ExtruderConfigurationModel.py @@ -37,13 +37,18 @@ class ExtruderConfigurationModel(QObject): ## This method is intended to indicate whether the configuration is valid or not. # The method checks if the mandatory fields are or not set + # At this moment is always valid since we allow to have empty material and variants. def isValid(self): - return self._material is not None and self._hotend_id is not None and self.material.guid is not None + return True def __str__(self): - if not self.isValid(): - return "No information" - return "Position: " + str(self._position) + " - Material: " + self._material.type + " - HotendID: " + self._hotend_id + message_chunks = [] + message_chunks.append("Position: " + str(self._position)) + message_chunks.append("-") + message_chunks.append("Material: " + self.material.type if self.material else "empty") + message_chunks.append("-") + message_chunks.append("HotendID: " + self.hotendID if self.hotendID else "empty") + return " ".join(message_chunks) def __eq__(self, other): return hash(self) == hash(other) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index e8ee0b6657..cc7852ede4 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -361,19 +361,10 @@ class MachineManager(QObject): # \param metadata_filter \type{dict} list of metadata keys and values used for filtering @staticmethod def getMachine(definition_id: str, metadata_filter: Dict[str, str] = None) -> Optional["GlobalStack"]: - machines = ContainerRegistry.getInstance().findContainerStacks(type = "machine") + machines = ContainerRegistry.getInstance().findContainerStacks(type = "machine", **metadata_filter) for machine in machines: if machine.definition.getId() == definition_id: - if metadata_filter: - pass_all_filters = True - for key in metadata_filter: - if machine.getMetaDataEntry(key) != metadata_filter[key]: - pass_all_filters = False - break - if pass_all_filters: - return machine - else: - return machine + return machine return None @pyqtSlot(str, str) From 9e0a78929a0168233e757725a90e774b9bfcccef Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 13 Mar 2018 16:02:57 +0100 Subject: [PATCH 283/446] CURA-5059 changed error check timer interval and added measured time in logging --- cura/Machines/MachineErrorChecker.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cura/Machines/MachineErrorChecker.py b/cura/Machines/MachineErrorChecker.py index 871e70310b..6006289744 100644 --- a/cura/Machines/MachineErrorChecker.py +++ b/cura/Machines/MachineErrorChecker.py @@ -1,6 +1,8 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +import time + from collections import deque from PyQt5.QtCore import QObject, QTimer, pyqtSignal, pyqtProperty @@ -39,10 +41,12 @@ class MachineErrorChecker(QObject): self._application = Application.getInstance() self._machine_manager = self._application.getMachineManager() + self._start_time = 0 # measure checking time + # This timer delays the starting of error check so we can react less frequently if the user is frequently # changing settings. self._error_check_timer = QTimer(self) - self._error_check_timer.setInterval(300) + self._error_check_timer.setInterval(100) self._error_check_timer.setSingleShot(True) def initialize(self): @@ -117,6 +121,7 @@ class MachineErrorChecker(QObject): self._keys_to_check = deque(global_stack.getAllKeys()) self._application.callLater(self._checkStack) + self._start_time = time.time() Logger.log("d", "New error check scheduled.") def _checkStack(self): @@ -181,4 +186,4 @@ class MachineErrorChecker(QObject): self._check_in_progress = False self.needToWaitForResultChanged.emit() self.errorCheckFinished.emit() - Logger.log("i", "Error check finished, result = %s", result) + Logger.log("i", "Error check finished, result = %s, time = %0.1fs", result, time.time() - self._start_time) From c8a882849f5451db3f3c9dbbff08ae38f51239f8 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 13 Mar 2018 16:08:45 +0100 Subject: [PATCH 284/446] Simplify task queue for machine error check CURA-5059 --- cura/Machines/MachineErrorChecker.py | 30 ++++++++++------------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/cura/Machines/MachineErrorChecker.py b/cura/Machines/MachineErrorChecker.py index 6006289744..37de4f30ce 100644 --- a/cura/Machines/MachineErrorChecker.py +++ b/cura/Machines/MachineErrorChecker.py @@ -9,6 +9,8 @@ from PyQt5.QtCore import QObject, QTimer, pyqtSignal, pyqtProperty from UM.Application import Application from UM.Logger import Logger +from UM.Settings.SettingDefinition import SettingDefinition +from UM.Settings.Validator import ValidatorState # @@ -31,8 +33,7 @@ class MachineErrorChecker(QObject): self._error_keys = set() # A set of settings keys that have errors self._error_keys_in_progress = set() # The variable that stores the results of the currently in progress check - self._stacks_to_check = None # a FIFO queue of stacks to check for errors - self._keys_to_check = None # a FIFO queue of setting keys to check for errors + self._stacks_and_keys_to_check = None # a FIFO queue of tuples (stack, key) to check for errors self._need_to_check = False # Whether we need to schedule a new check or not. This flag is set when a new # error check needs to take place while there is already one running at the moment. @@ -117,17 +118,17 @@ class MachineErrorChecker(QObject): Logger.log("i", "No active machine, nothing to check.") return - self._stacks_to_check = deque([global_stack] + list(global_stack.extruders.values())) - self._keys_to_check = deque(global_stack.getAllKeys()) + # Populate the (stack, key) tuples to check + self._stacks_and_keys_to_check = deque() + for stack in [global_stack] + list(global_stack.extruders.values()): + for key in stack.getAllKeys(): + self._stacks_and_keys_to_check.append((stack, key)) self._application.callLater(self._checkStack) self._start_time = time.time() Logger.log("d", "New error check scheduled.") def _checkStack(self): - from UM.Settings.SettingDefinition import SettingDefinition - from UM.Settings.Validator import ValidatorState - if self._need_to_check: Logger.log("d", "Need to check for errors again. Discard the current progress and reschedule a check.") self._check_in_progress = False @@ -137,22 +138,13 @@ class MachineErrorChecker(QObject): self._check_in_progress = True # If there is nothing to check any more, it means there is no error. - if not self._stacks_to_check or not self._keys_to_check: + if not self._stacks_and_keys_to_check: # Finish self._setResult(False) return - stack = self._stacks_to_check[0] - key = self._keys_to_check.popleft() - - # If there is no key left in this stack, check the next stack later. - if not self._keys_to_check: - if len(self._stacks_to_check) == 1: - stacks = None - keys = None - else: - stack = self._stacks_to_check.popleft() - self._keys_to_check = deque(stack.getAllKeys()) + # Get the next stack and key to check + stack, key = self._stacks_and_keys_to_check.popleft() enabled = stack.getProperty(key, "enabled") if not enabled: From 855df814d83b368907e7c537bbdd18b161f6ffb5 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 13 Mar 2018 16:11:51 +0100 Subject: [PATCH 285/446] CURA-4870 Fix some style with brackets in QML --- resources/qml/Menus/PrinterStatusIcon.qml | 6 ++++-- resources/qml/Menus/PrinterTypeMenu.qml | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/resources/qml/Menus/PrinterStatusIcon.qml b/resources/qml/Menus/PrinterStatusIcon.qml index f66834d0c0..6ff6b07af8 100644 --- a/resources/qml/Menus/PrinterStatusIcon.qml +++ b/resources/qml/Menus/PrinterStatusIcon.qml @@ -6,11 +6,13 @@ import QtQuick 2.2 import UM 1.2 as UM import Cura 1.0 as Cura -Item { +Item +{ property var status: "disconnected" width: childrenRect.width height: childrenRect.height - UM.RecolorImage { + UM.RecolorImage + { id: statusIcon width: UM.Theme.getSize("printer_status_icon").width height: UM.Theme.getSize("printer_status_icon").height diff --git a/resources/qml/Menus/PrinterTypeMenu.qml b/resources/qml/Menus/PrinterTypeMenu.qml index 0cb98bc1aa..28bdca54d9 100644 --- a/resources/qml/Menus/PrinterTypeMenu.qml +++ b/resources/qml/Menus/PrinterTypeMenu.qml @@ -18,7 +18,8 @@ Menu id: printerTypeInstantiator model: outputDevice != null ? outputDevice.connectedPrintersTypeCount : [] - MenuItem { + MenuItem + { text: modelData.machine_type checkable: true checked: Cura.MachineManager.activeMachineDefinitionName == modelData.machine_type From 493bfb6b17e0fb61859d18e552697216e621119c Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 13 Mar 2018 16:37:03 +0100 Subject: [PATCH 286/446] Fix material serialization CURA-5086 --- plugins/XmlMaterialProfile/XmlMaterialProfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index bbf5dfe2ba..333e2546b0 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -277,7 +277,7 @@ class XmlMaterialProfile(InstanceContainer): # Compatible is a special case, as it's added as a meta data entry (instead of an instance). material_container = variant_dict["material_container"] - compatible = container.getMetaDataEntry("compatible") + compatible = material_container.getMetaDataEntry("compatible") if compatible is not None: builder.start("setting", {"key": "hardware compatible"}) if compatible: From e2cbfa8cec49dd4fa105eb6f76aaf35b581cf737 Mon Sep 17 00:00:00 2001 From: Aleksei S Date: Tue, 13 Mar 2018 16:37:09 +0100 Subject: [PATCH 287/446] Fix: Retrieve printer type during creating outputDevice CURA-5053 --- cura/PrinterOutput/NetworkedPrinterOutputDevice.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cura/PrinterOutput/NetworkedPrinterOutputDevice.py b/cura/PrinterOutput/NetworkedPrinterOutputDevice.py index 315b195e2a..a4934b7f74 100644 --- a/cura/PrinterOutput/NetworkedPrinterOutputDevice.py +++ b/cura/PrinterOutput/NetworkedPrinterOutputDevice.py @@ -55,6 +55,14 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice): self._connection_state_before_timeout = None # type: Optional[ConnectionState] + printer_type = self._properties.get(b"machine", b"").decode("utf-8") + if printer_type.startswith("9511"): + self._printer_type = "ultimaker3_extended" + elif printer_type.startswith("9066"): + self._printer_type = "ultimaker3" + else: + self._printer_type = "unknown" + def requestWrite(self, nodes, file_name=None, filter_by_machine=False, file_handler=None, **kwargs) -> None: raise NotImplementedError("requestWrite needs to be implemented") @@ -301,6 +309,10 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice): def firmwareVersion(self) -> str: return self._properties.get(b"firmware_version", b"").decode("utf-8") + @pyqtProperty(str, constant=True) + def printerType(self) -> str: + return self._printer_type + ## IPadress of this printer @pyqtProperty(str, constant=True) def ipAddress(self) -> str: From 40d300f5ccf9915ec7df62f17e2df835ba38a179 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 13 Mar 2018 16:46:02 +0100 Subject: [PATCH 288/446] Change default direction of snapshot, so robot looks in the same direction as our beautifull logo; the ultibot --- cura/Snapshot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Snapshot.py b/cura/Snapshot.py index 2a2a49d6cf..afc8818116 100644 --- a/cura/Snapshot.py +++ b/cura/Snapshot.py @@ -66,7 +66,7 @@ class Snapshot: size = max(bbox.width, bbox.height, bbox.depth * 0.5) # Looking from this direction (x, y, z) in OGL coordinates - looking_from_offset = Vector(1, 1, 2) + looking_from_offset = Vector(1, 1, -2) if size > 0: # determine the watch distance depending on the size looking_from_offset = looking_from_offset * size * 1.3 From 5adb769cf8ebc828bb017c55acfe60b7a9e20b7c Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 13 Mar 2018 16:48:17 +0100 Subject: [PATCH 289/446] Fix value function for extruders_enabled_count CIRA-5056 --- resources/definitions/fdmprinter.def.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 6d4688bb52..8567dab08b 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -215,7 +215,7 @@ { "label": "Number of Extruders that are enabled", "description": "Number of extruder trains that are enabled; automatically set in software", - "default_value": "machine_extruder_count", + "value": "machine_extruder_count", "minimum_value": "1", "maximum_value": "16", "type": "int", From 00f5e6ff7c3f88f762649afa26f56a51071c1f5a Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 13 Mar 2018 16:53:28 +0100 Subject: [PATCH 290/446] Only trigger platform physics update if the node has meshdata --- cura/PlatformPhysics.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cura/PlatformPhysics.py b/cura/PlatformPhysics.py index 69890178e4..3d9d5d5027 100755 --- a/cura/PlatformPhysics.py +++ b/cura/PlatformPhysics.py @@ -40,6 +40,8 @@ class PlatformPhysics: Preferences.getInstance().addPreference("physics/automatic_drop_down", True) def _onSceneChanged(self, source): + if not source.getMeshData(): + return self._change_timer.start() def _onChangeTimerFinished(self): From 406e546195cd803499e9b112d5696e071bab77a4 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 13 Mar 2018 17:29:20 +0100 Subject: [PATCH 291/446] CURA-5048 fixed nozzle dependent settings to update after setting machine nozzle diameter in a crude way --- cura/Settings/MachineManager.py | 6 ++++-- plugins/MachineSettingsAction/MachineSettingsAction.qml | 7 ++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index f52b90e80f..3c227fc04e 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -831,10 +831,12 @@ class MachineManager(QObject): return self._default_extruder_position ## This will fire the propertiesChanged for all settings so they will be updated in the front-end + @pyqtSlot() def forceUpdateAllSettings(self): property_names = ["value", "resolve"] - for setting_key in self._global_container_stack.getAllKeys(): - self._global_container_stack.propertiesChanged.emit(setting_key, property_names) + for container in [self._global_container_stack] + list(self._global_container_stack.extruders.values()): + for setting_key in container.getAllKeys(): + container.propertiesChanged.emit(setting_key, property_names) @pyqtSlot(int, bool) def setExtruderEnabled(self, position: int, enabled) -> None: diff --git a/plugins/MachineSettingsAction/MachineSettingsAction.qml b/plugins/MachineSettingsAction/MachineSettingsAction.qml index f941ef87b4..b12f8f8696 100644 --- a/plugins/MachineSettingsAction/MachineSettingsAction.qml +++ b/plugins/MachineSettingsAction/MachineSettingsAction.qml @@ -382,6 +382,11 @@ Cura.MachineAction property string settingKey: "machine_nozzle_size" property string label: catalog.i18nc("@label", "Nozzle size") property string unit: catalog.i18nc("@label", "mm") + function afterOnEditingFinished() + { + // Somehow the machine_nozzle_size dependent settings are not updated otherwise + Cura.MachineManager.forceUpdateAllSettings() + } property bool isExtruderSetting: true } @@ -889,4 +894,4 @@ Cura.MachineAction watchedProperties: [ "value" ] storeIndex: manager.containerIndex } -} \ No newline at end of file +} From d2eb01d13778372590e81339820f0b01670008d9 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 13 Mar 2018 17:00:30 +0100 Subject: [PATCH 292/446] Fix material name update on sidebar CURA-5084 --- cura/Settings/MachineManager.py | 14 +------------- resources/qml/SidebarHeader.qml | 13 +++---------- resources/qml/WorkspaceSummaryDialog.qml | 2 +- 3 files changed, 5 insertions(+), 24 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index cd9e75f33d..a6c70ee15f 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -50,7 +50,6 @@ class MachineManager(QObject): self._global_container_stack = None # type: GlobalStack self._current_root_material_id = {} - self._current_root_material_name = {} self._current_quality_group = None self._current_quality_changes_group = None @@ -926,28 +925,18 @@ class MachineManager(QObject): return [] return sorted(list(self._global_container_stack.extruders.keys())) - ## Update _current_root_material_id and _current_root_material_name when - # the current root material was changed. + ## Update _current_root_material_id when the current root material was changed. def _onRootMaterialChanged(self): self._current_root_material_id = {} if self._global_container_stack: for position in self._global_container_stack.extruders: self._current_root_material_id[position] = self._global_container_stack.extruders[position].material.getMetaDataEntry("base_file") - self._current_root_material_name = {} - for position in self._global_container_stack.extruders: - if position not in self._current_root_material_name: - material = self._global_container_stack.extruders[position].material - self._current_root_material_name[position] = material.getName() @pyqtProperty("QVariant", notify = rootMaterialChanged) def currentRootMaterialId(self): return self._current_root_material_id - @pyqtProperty("QVariant", notify = rootMaterialChanged) - def currentRootMaterialName(self): - return self._current_root_material_name - ## Return the variant names in the extruder stack(s). ## For the variant in the global stack, use activeVariantBuildplateName @pyqtProperty("QVariant", notify = activeVariantChanged) @@ -1052,7 +1041,6 @@ class MachineManager(QObject): # The _current_root_material_id is used in the MaterialMenu to see which material is selected if root_material_id != self._current_root_material_id[position]: self._current_root_material_id[position] = root_material_id - self._current_root_material_name[position] = root_material_name self.rootMaterialChanged.emit() def activeMaterialsCompatible(self): diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index baceb5f683..74e189789d 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -346,15 +346,8 @@ Column { id: materialSelection - property var currentRootMaterialName: - { - var materials = Cura.MachineManager.currentRootMaterialName; - var materialName = ""; - if (base.currentExtruderIndex in materials) { - materialName = materials[base.currentExtruderIndex]; - } - return materialName; - } + property var activeExtruder: Cura.MachineManager.activeStack + property var currentRootMaterialName: activeExtruder.material.name text: currentRootMaterialName tooltip: currentRootMaterialName @@ -373,7 +366,7 @@ Column property var valueWarning: ! Cura.MachineManager.isActiveQualitySupported function isMaterialSupported () { - return Cura.ContainerManager.getContainerMetaDataEntry(Cura.MachineManager.activeMaterialId, "compatible") == "True" + return Cura.ContainerManager.getContainerMetaDataEntry(activeExtruder.material.id, "compatible") == "True" } } } diff --git a/resources/qml/WorkspaceSummaryDialog.qml b/resources/qml/WorkspaceSummaryDialog.qml index 1cfe36d14b..12eba13dd9 100644 --- a/resources/qml/WorkspaceSummaryDialog.qml +++ b/resources/qml/WorkspaceSummaryDialog.qml @@ -173,7 +173,7 @@ UM.Dialog } Label { - text: Cura.MachineManager.activeVariantNames[modelData] + ", " + Cura.MachineManager.currentRootMaterialName[modelData] + text: Cura.MachineManager.activeVariantNames[modelData] + ", " + Cura.MachineManager.getExtruder(modelData).material.name width: (parent.width / 3) | 0 } } From b83fd17038ce1baf3cc146ca68dd59ae474bda8c Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 13 Mar 2018 17:37:55 +0100 Subject: [PATCH 293/446] Fix GUI update upon material data change CURA-5084 --- cura/Settings/MachineManager.py | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index a6c70ee15f..ebfee39329 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -128,6 +128,9 @@ class MachineManager(QObject): # When the materials lookup table gets updated, it can mean that a material has its name changed, which should # be reflected on the GUI. This signal emission makes sure that it happens. self._material_manager.materialsUpdated.connect(self.rootMaterialChanged) + # When the materials get updated, it can be that an activated material's diameter gets changed. In that case, + # a material update should be triggered to make sure that the machine still has compatible materials activated. + self._material_manager.materialsUpdated.connect(self._updateUponMaterialMetadataChange) self.rootMaterialChanged.connect(self._onRootMaterialChanged) activeQualityGroupChanged = pyqtSignal() @@ -1033,11 +1036,9 @@ class MachineManager(QObject): if container_node: self._global_container_stack.extruders[position].material = container_node.getContainer() root_material_id = container_node.metadata["base_file"] - root_material_name = container_node.getContainer().getName() else: self._global_container_stack.extruders[position].material = self._empty_material_container root_material_id = None - root_material_name = None # The _current_root_material_id is used in the MaterialMenu to see which material is selected if root_material_id != self._current_root_material_id[position]: self._current_root_material_id[position] = root_material_id @@ -1054,7 +1055,7 @@ class MachineManager(QObject): return True ## Update current quality type and machine after setting material - def _updateQualityWithMaterial(self): + def _updateQualityWithMaterial(self, *args): Logger.log("i", "Updating quality/quality_changes due to material change") current_quality_type = None if self._current_quality_group: @@ -1099,9 +1100,15 @@ class MachineManager(QObject): extruder = self._global_container_stack.extruders[position] current_material_base_name = extruder.material.getMetaDataEntry("base_file") - current_variant_name = extruder.variant.getMetaDataEntry("name") + current_variant_name = None + if extruder.variant.getId() != self._empty_variant_container.getId(): + current_variant_name = extruder.variant.getMetaDataEntry("name") - material_diameter = self._global_container_stack.getProperty("material_diameter", "value") + from UM.Settings.Interfaces import PropertyEvaluationContext + from cura.Settings.CuraContainerStack import _ContainerIndexes + context = PropertyEvaluationContext(extruder) + context.context["evaluate_from_container_index"] = _ContainerIndexes.DefinitionChanges + material_diameter = self._global_container_stack.getProperty("material_diameter", "value", context) candidate_materials = self._material_manager.getAvailableMaterials( self._global_container_stack.definition.getId(), current_variant_name, @@ -1116,6 +1123,11 @@ class MachineManager(QObject): self._setMaterial(position, new_material) continue + # The current material is not available, find the preferred one + material_node = self._material_manager.getDefaultMaterial(self._global_container_stack, current_variant_name) + if material_node is not None: + self._setMaterial(position, material_node) + ## Given a printer definition name, select the right machine instance. In case it doesn't exist, create a new # instance with the same network key. @pyqtSlot(str) @@ -1240,3 +1252,8 @@ class MachineManager(QObject): elif self._current_quality_group: name = self._current_quality_group.name return name + + def _updateUponMaterialMetadataChange(self): + with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): + self._updateMaterialWithVariant(None) + self._updateQualityWithMaterial() From 73558c9e3695335008cda045c4293e837e1ef3f0 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 13 Mar 2018 19:44:53 +0100 Subject: [PATCH 294/446] Fix rendering depth pass --- cura/DepthPass.py | 9 ++++++--- plugins/SupportEraser/SupportEraser.py | 3 +-- resources/shaders/camera_distance.shader | 6 +++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/cura/DepthPass.py b/cura/DepthPass.py index 3fb57b0341..a2cfdbaab0 100644 --- a/cura/DepthPass.py +++ b/cura/DepthPass.py @@ -17,7 +17,7 @@ from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator # Note that in order to increase precision, the 24 bit depth value is encoded into all three of the R,G & B channels class DepthPass(RenderPass): def __init__(self, width: int, height: int): - super().__init__("preview", width, height, 0) + super().__init__("depth", width, height) self._renderer = Application.getInstance().getRenderer() @@ -29,7 +29,9 @@ class DepthPass(RenderPass): if not self._shader: self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "camera_distance.shader")) - self._gl.glClearColor(0.0, 0.0, 0.0, 0.0) + width, height = self.getSize() + self._gl.glViewport(0, 0, width, height) + self._gl.glClearColor(1.0, 1.0, 1.0, 0.0) self._gl.glClear(self._gl.GL_COLOR_BUFFER_BIT | self._gl.GL_DEPTH_BUFFER_BIT) # Create a new batch to be rendered @@ -57,4 +59,5 @@ class DepthPass(RenderPass): return None distance = output.pixel(px, py) # distance in micron, from in r, g & b channels - return distance / 1000. + distance = (distance & 0x00ffffff) / 1000. # drop the alpha channel and covert to mm + return distance diff --git a/plugins/SupportEraser/SupportEraser.py b/plugins/SupportEraser/SupportEraser.py index 119e598886..4034b524b8 100644 --- a/plugins/SupportEraser/SupportEraser.py +++ b/plugins/SupportEraser/SupportEraser.py @@ -31,8 +31,7 @@ class SupportEraser(Tool): active_camera = self._controller.getScene().getActiveCamera() # Create depth pass for picking - render_width, render_height = active_camera.getWindowSize() - depth_pass = DepthPass(int(render_width), int(render_height)) + depth_pass = DepthPass(active_camera.getViewportWidth(), active_camera.getViewportHeight()) depth_pass.render() distance = depth_pass.getDepthAtPosition(event.x, event.y) diff --git a/resources/shaders/camera_distance.shader b/resources/shaders/camera_distance.shader index 2dd90e7f15..e6e894a2f6 100644 --- a/resources/shaders/camera_distance.shader +++ b/resources/shaders/camera_distance.shader @@ -63,9 +63,9 @@ fragment41core = highp float distance_to_camera = distance(v_vertex, u_viewPosition) * 1000.; // distance in micron vec3 encoded; // encode float into 3 8-bit channels; this gives a precision of a micron at a range of up to ~16 meter - encoded.b = floor(distance_to_camera / 65536.0); - encoded.g = floor((distance_to_camera - encoded.b * 65536.0) / 256.0); - encoded.r = floor(distance_to_camera - encoded.b * 65536.0 - encoded.g * 256.0); + encoded.r = floor(distance_to_camera / 65536.0); + encoded.g = floor((distance_to_camera - encoded.r * 65536.0) / 256.0); + encoded.b = floor(distance_to_camera - encoded.r * 65536.0 - encoded.g * 256.0); frag_color.rgb = encoded / 255.; frag_color.a = 1.0; From d88724aff539748dbdb0001bacbe6785cae68ba1 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 13 Mar 2018 20:05:49 +0100 Subject: [PATCH 295/446] Move ray picking to DepthPass --- cura/DepthPass.py | 15 +++++++++++---- plugins/SupportEraser/SupportEraser.py | 4 +--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/cura/DepthPass.py b/cura/DepthPass.py index a2cfdbaab0..4435d533ff 100644 --- a/cura/DepthPass.py +++ b/cura/DepthPass.py @@ -1,7 +1,7 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from UM.Application import Application -from UM.Math.Color import Color +from UM.Math.Vector import Vector from UM.Resources import Resources from UM.View.RenderPass import RenderPass @@ -11,8 +11,8 @@ from UM.View.RenderBatch import RenderBatch from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator -## A RenderPass subclass that renders a depthmap of selectable objects to a texture. -# It uses the active camera by default, but it can be overridden to use a different camera. +## A RenderPass subclass that renders a the distance of selectable objects from the active camera to a texture. +# The texture is used to map a 2d location (eg the mouse location) to a world space position # # Note that in order to increase precision, the 24 bit depth value is encoded into all three of the R,G & B channels class DepthPass(RenderPass): @@ -47,7 +47,7 @@ class DepthPass(RenderPass): self.release() ## Get the distance in mm from the camera to at a certain pixel coordinate. - def getDepthAtPosition(self, x, y): + def getPickedDepth(self, x, y) -> float: output = self.getOutput() window_size = self._renderer.getWindowSize() @@ -61,3 +61,10 @@ class DepthPass(RenderPass): distance = output.pixel(px, py) # distance in micron, from in r, g & b channels distance = (distance & 0x00ffffff) / 1000. # drop the alpha channel and covert to mm return distance + + ## Get the world coordinates of a picked point + def getPickedPosition(self, x, y) -> Vector: + distance = self.getPickedDepth(x, y) + ray = self._scene.getActiveCamera().getRay(x, y) + + return ray.getPointAlongRay(distance) diff --git a/plugins/SupportEraser/SupportEraser.py b/plugins/SupportEraser/SupportEraser.py index 4034b524b8..0ddfed0cf1 100644 --- a/plugins/SupportEraser/SupportEraser.py +++ b/plugins/SupportEraser/SupportEraser.py @@ -34,9 +34,7 @@ class SupportEraser(Tool): depth_pass = DepthPass(active_camera.getViewportWidth(), active_camera.getViewportHeight()) depth_pass.render() - distance = depth_pass.getDepthAtPosition(event.x, event.y) - ray = active_camera.getRay(event.x, event.y) - picked_position = ray.getPointAlongRay(distance) + picked_position = depth_pass.getPickedPosition(event.x, event.y) # Add the anto_overhang_mesh cube: self._createEraserMesh(picked_position) From a536da503bf374f5db0fec5180e9989294f77c22 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 13 Mar 2018 20:40:41 +0100 Subject: [PATCH 296/446] Rename DepthPass to PickingPass The map created by the shader is not strictly a depth map; not only is the "depth" encoded in the rgb channels, but it is also a distance to the camera instead of a "scene depth". --- cura/{DepthPass.py => PickingPass.py} | 4 ++-- plugins/SupportEraser/SupportEraser.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) rename cura/{DepthPass.py => PickingPass.py} (97%) diff --git a/cura/DepthPass.py b/cura/PickingPass.py similarity index 97% rename from cura/DepthPass.py rename to cura/PickingPass.py index 4435d533ff..4bd893e926 100644 --- a/cura/DepthPass.py +++ b/cura/PickingPass.py @@ -15,9 +15,9 @@ from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator # The texture is used to map a 2d location (eg the mouse location) to a world space position # # Note that in order to increase precision, the 24 bit depth value is encoded into all three of the R,G & B channels -class DepthPass(RenderPass): +class PickingPass(RenderPass): def __init__(self, width: int, height: int): - super().__init__("depth", width, height) + super().__init__("picking", width, height) self._renderer = Application.getInstance().getRenderer() diff --git a/plugins/SupportEraser/SupportEraser.py b/plugins/SupportEraser/SupportEraser.py index 0ddfed0cf1..35713805bc 100644 --- a/plugins/SupportEraser/SupportEraser.py +++ b/plugins/SupportEraser/SupportEraser.py @@ -13,7 +13,7 @@ from cura.Scene.SliceableObjectDecorator import SliceableObjectDecorator from cura.Scene.BuildPlateDecorator import BuildPlateDecorator from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator -from cura.DepthPass import DepthPass +from cura.PickingPass import PickingPass import os import os.path @@ -30,13 +30,13 @@ class SupportEraser(Tool): if event.type == Event.MousePressEvent and self._controller.getToolsEnabled(): active_camera = self._controller.getScene().getActiveCamera() - # Create depth pass for picking - depth_pass = DepthPass(active_camera.getViewportWidth(), active_camera.getViewportHeight()) - depth_pass.render() + # Create a pass for picking a world-space location from the mouse location + picking_pass = PickingPass(active_camera.getViewportWidth(), active_camera.getViewportHeight()) + picking_pass.render() - picked_position = depth_pass.getPickedPosition(event.x, event.y) + picked_position = picking_pass.getPickedPosition(event.x, event.y) - # Add the anto_overhang_mesh cube: + # Add the anti_overhang_mesh cube at the picked location self._createEraserMesh(picked_position) def _createEraserMesh(self, position: Vector): From 9f89678e42ba3e13f547e9ed8ded23024508372f Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 13 Mar 2018 13:40:17 +0100 Subject: [PATCH 297/446] Update when switching printers I confused globalContainerChanged with activeStackChanged. Contributes to issue CURA-4606. --- cura/Machines/Models/BrandMaterialsModel.py | 4 ++-- cura/Machines/Models/GenericMaterialsModel.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cura/Machines/Models/BrandMaterialsModel.py b/cura/Machines/Models/BrandMaterialsModel.py index e36c6448d3..f6c9a14632 100644 --- a/cura/Machines/Models/BrandMaterialsModel.py +++ b/cura/Machines/Models/BrandMaterialsModel.py @@ -53,8 +53,8 @@ class BrandMaterialsModel(ListModel): self._extruder_manager = CuraApplication.getInstance().getExtruderManager() self._material_manager = CuraApplication.getInstance().getMaterialManager() - self._machine_manager.globalContainerChanged.connect(self._update) - self._material_manager.materialsUpdated.connect(self._update) + self._machine_manager.activeStackChanged.connect(self._update) #Update when switching machines. + self._material_manager.materialsUpdated.connect(self._update) #Update when the list of materials changes. self._update() def setExtruderPosition(self, position: int): diff --git a/cura/Machines/Models/GenericMaterialsModel.py b/cura/Machines/Models/GenericMaterialsModel.py index 6b149448ea..2fac919f3e 100644 --- a/cura/Machines/Models/GenericMaterialsModel.py +++ b/cura/Machines/Models/GenericMaterialsModel.py @@ -15,8 +15,8 @@ class GenericMaterialsModel(BaseMaterialsModel): self._extruder_manager = CuraApplication.getInstance().getExtruderManager() self._material_manager = CuraApplication.getInstance().getMaterialManager() - self._machine_manager.globalContainerChanged.connect(self._update) - self._material_manager.materialsUpdated.connect(self._update) + self._machine_manager.activeStackChanged.connect(self._update) #Update when switching machines. + self._material_manager.materialsUpdated.connect(self._update) #Update when the list of materials changes. self._update() def _update(self): From 3cefacdfccf78222959b8d76ad70502969dd4cfa Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 14 Mar 2018 09:28:33 +0100 Subject: [PATCH 298/446] Remove root_material_nod is None check in MaterialManager CURA-5056 This will no longer happen. --- cura/Machines/MaterialManager.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cura/Machines/MaterialManager.py b/cura/Machines/MaterialManager.py index 61b8bcd8e6..0a82fcc764 100644 --- a/cura/Machines/MaterialManager.py +++ b/cura/Machines/MaterialManager.py @@ -101,13 +101,6 @@ class MaterialManager(QObject): # GUID -> material group list self._guid_material_groups_map = defaultdict(list) for root_material_id, material_group in self._material_group_map.items(): - # This can happen when we are updating with incomplete data. - if material_group.root_material_node is None: - Logger.log("e", "Missing root material node for [%s]. Probably caused by update using incomplete data." - " Check all related signals for further debugging.", - material_group.name) - self._update_timer.start() - return guid = material_group.root_material_node.metadata["GUID"] self._guid_material_groups_map[guid].append(material_group) From 7e4cb1c36ecb4aed44bc9da4aab676eed21e1ae3 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Sun, 11 Mar 2018 13:06:30 +0100 Subject: [PATCH 299/446] Disable Support Eraser if anti_overhang_mesh is disabled --- plugins/SupportEraser/SupportEraser.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/plugins/SupportEraser/SupportEraser.py b/plugins/SupportEraser/SupportEraser.py index 35713805bc..65d22bcdfd 100644 --- a/plugins/SupportEraser/SupportEraser.py +++ b/plugins/SupportEraser/SupportEraser.py @@ -24,6 +24,8 @@ class SupportEraser(Tool): self._shortcut_key = Qt.Key_G self._controller = Application.getInstance().getController() + Application.getInstance().globalContainerStackChanged.connect(self._updateEnabled) + def event(self, event): super().event(event) @@ -73,3 +75,12 @@ class SupportEraser(Tool): op = AddSceneNodeOperation(node, scene.getRoot()) op.push() Application.getInstance().getController().getScene().sceneChanged.emit(node) + + def _updateEnabled(self): + plugin_enabled = False + + global_container_stack = Application.getInstance().getGlobalContainerStack() + if global_container_stack: + plugin_enabled = global_container_stack.getProperty("anti_overhang_mesh", "enabled") + + Application.getInstance().getController().toolEnabledChanged.emit(self._plugin_id, plugin_enabled) From 7ebd83f81527f157d679bd564a013a1811b2888f Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 14 Mar 2018 10:21:10 +0100 Subject: [PATCH 300/446] CURA-4400 get setting type from definition instead of whole stack improves speed of this call by a factor of 10 --- plugins/CuraEngineBackend/StartSliceJob.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index f3f34f4c3d..96124a3514 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -281,7 +281,7 @@ class StartSliceJob(Job): default_extruder_position = int(Application.getInstance().getMachineManager().defaultExtruderPosition) result = {} for key in stack.getAllKeys(): - setting_type = stack.getProperty(key, "type") + setting_type = stack.definition.getProperty(key, "type") value = stack.getProperty(key, "value") if setting_type == "extruder" and value == -1: # replace with the default value From dc427488a26fe829f8d55ca186d1b19ac02fee75 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 14 Mar 2018 10:29:48 +0100 Subject: [PATCH 301/446] Fix extruder position check in project loading CURA-5056 The field is now "position" instead of "extruder" --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 3c627a7655..c943fcd879 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -754,15 +754,13 @@ class ThreeMFWorkspaceReader(WorkspaceReader): quality_changes_containers = self._container_registry.findInstanceContainers(name = quality_changes_name, type = "quality_changes") for container in quality_changes_containers: - extruder_definition_id = container.getMetaDataEntry("extruder") - if not extruder_definition_id: + extruder_position = container.getMetaDataEntry("position") + if extruder_position is None: quality_changes_info.global_info.container = container else: - extruder_definition_metadata = self._container_registry.findDefinitionContainersMetadata(id = extruder_definition_id)[0] - position = extruder_definition_metadata["position"] - if position not in quality_changes_info.extruder_info_dict: - quality_changes_info.extruder_info_dict[position] = ContainerInfo(None, None, None) - container_info = quality_changes_info.extruder_info_dict[position] + if extruder_position not in quality_changes_info.extruder_info_dict: + quality_changes_info.extruder_info_dict[extruder_position] = ContainerInfo(None, None, None) + container_info = quality_changes_info.extruder_info_dict[extruder_position] container_info.container = container # If there is no quality changes for any extruder, create one. From 86afd6f5ff3d8d8f77d325ee80068c0fc08a90ac Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 14 Mar 2018 10:32:53 +0100 Subject: [PATCH 302/446] Do not overwrite existing metadata with in material deserializeMetadata() CURA-5056 --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 8 ++--- .../XmlMaterialProfile/XmlMaterialProfile.py | 36 +++++++------------ 2 files changed, 15 insertions(+), 29 deletions(-) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index c943fcd879..19e6b89f07 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -265,13 +265,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader): for material_container_file in material_container_files: container_id = self._stripFileToId(material_container_file) - from hashlib import sha1 - hex_container_id = sha1(container_id.encode('utf-8')).hexdigest() - serialized = archive.open(material_container_file).read().decode("utf-8") - metadata_list = xml_material_profile.deserializeMetadata(serialized, hex_container_id) - reverse_map = {metadata["id"].replace(hex_container_id, container_id): container_id.replace(hex_container_id, container_id) - for metadata in metadata_list} + metadata_list = xml_material_profile.deserializeMetadata(serialized, container_id) + reverse_map = {metadata["id"]: container_id for metadata in metadata_list} reverse_material_id_dict.update(reverse_map) material_labels.append(self._getMaterialLabelFromSerialized(serialized)) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index 333e2546b0..8b17721794 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -838,15 +838,11 @@ class XmlMaterialProfile(InstanceContainer): if machine_compatibility: new_material_id = container_id + "_" + machine_id - # The child or derived material container may already exist. This can happen when a material in a - # project file and the a material in Cura have the same ID. - # In the case if a derived material already exists, override that material container because if - # the data in the parent material has been changed, the derived ones should be updated too. - found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_material_id) - if found_materials: - new_material_metadata = found_materials[0] - else: - new_material_metadata = {} + # Do not look for existing container/container metadata with the same ID although they may exist. + # In project loading and perhaps some other places, we only want to get information (metadata) + # from a file without changing the current state of the system. If we overwrite the existing + # metadata here, deserializeMetadata() will not be safe for retrieving information. + new_material_metadata = {} new_material_metadata.update(base_metadata) new_material_metadata["id"] = new_material_id @@ -854,8 +850,7 @@ class XmlMaterialProfile(InstanceContainer): new_material_metadata["machine_manufacturer"] = machine_manufacturer new_material_metadata["definition"] = machine_id - if len(found_materials) == 0: #This is a new material. - result_metadata.append(new_material_metadata) + result_metadata.append(new_material_metadata) buildplates = machine.iterfind("./um:buildplate", cls.__namespaces) buildplate_map = {} @@ -866,12 +861,12 @@ class XmlMaterialProfile(InstanceContainer): if buildplate_id is None: continue - variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = buildplate_id) - if not variant_containers: + variant_metadata = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = buildplate_id) + if not variant_metadata: # It is not really properly defined what "ID" is so also search for variants by name. - variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(definition = machine_id, name = buildplate_id) + variant_metadata = ContainerRegistry.getInstance().findInstanceContainersMetadata(definition = machine_id, name = buildplate_id) - if not variant_containers: + if not variant_metadata: continue settings = buildplate.iterfind("./um:setting", cls.__namespaces) @@ -900,12 +895,8 @@ class XmlMaterialProfile(InstanceContainer): new_hotend_specific_material_id = container_id + "_" + machine_id + "_" + hotend_name.replace(" ", "_") - # Same as machine compatibility, keep the derived material containers consistent with the parent material - found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_hotend_specific_material_id) - if found_materials: - new_hotend_material_metadata = found_materials[0] - else: - new_hotend_material_metadata = {} + # Same as above, do not overwrite existing metadata. + new_hotend_material_metadata = {} new_hotend_material_metadata.update(base_metadata) new_hotend_material_metadata["variant_name"] = hotend_name @@ -917,8 +908,7 @@ class XmlMaterialProfile(InstanceContainer): new_hotend_material_metadata["buildplate_compatible"] = buildplate_map["buildplate_compatible"] new_hotend_material_metadata["buildplate_recommended"] = buildplate_map["buildplate_recommended"] - if len(found_materials) == 0: - result_metadata.append(new_hotend_material_metadata) + result_metadata.append(new_hotend_material_metadata) # there is only one ID for a machine. Once we have reached here, it means we have already found # a workable ID for that machine, so there is no need to continue From cff1e8639dd2b0b12c628be7d513ee530cb8cf6a Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 14 Mar 2018 10:47:58 +0100 Subject: [PATCH 303/446] Fix preferred material PLA for printrbot simple makers kit CURA-5089 --- resources/definitions/printrbot_simple_makers_kit.def.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/resources/definitions/printrbot_simple_makers_kit.def.json b/resources/definitions/printrbot_simple_makers_kit.def.json index 61aecd9240..e2afd57826 100644 --- a/resources/definitions/printrbot_simple_makers_kit.def.json +++ b/resources/definitions/printrbot_simple_makers_kit.def.json @@ -6,8 +6,7 @@ "visible": true, "author": "Timur Tabi", "manufacturer": "Printrbot", - "file_formats": "text/x-gcode", - "preferred_material": "*pla*" + "file_formats": "text/x-gcode" }, "overrides": { From 4a16d04dd79fe8639f8381d44297e0bf3f74e8de Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Wed, 14 Mar 2018 10:50:54 +0100 Subject: [PATCH 304/446] CURA-5053 Changed printer type checking "Still hard coded but at least doesn't use `elif` because `elif`/`else if` should not exist in any programming language." - Grumpy Pedants & Ian >:[ --- .../PrinterOutput/NetworkedPrinterOutputDevice.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/cura/PrinterOutput/NetworkedPrinterOutputDevice.py b/cura/PrinterOutput/NetworkedPrinterOutputDevice.py index a4934b7f74..eefbd9ae12 100644 --- a/cura/PrinterOutput/NetworkedPrinterOutputDevice.py +++ b/cura/PrinterOutput/NetworkedPrinterOutputDevice.py @@ -56,12 +56,15 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice): self._connection_state_before_timeout = None # type: Optional[ConnectionState] printer_type = self._properties.get(b"machine", b"").decode("utf-8") - if printer_type.startswith("9511"): - self._printer_type = "ultimaker3_extended" - elif printer_type.startswith("9066"): - self._printer_type = "ultimaker3" - else: - self._printer_type = "unknown" + printer_type_identifiers = { + "9066": "ultimaker3", + "9511": "ultimaker3_extended" + } + self._printer_type = "Unknown" + for key, value in printer_type_identifiers.items(): + if printer_type.startswith(key): + self._printer_type = value + break def requestWrite(self, nodes, file_name=None, filter_by_machine=False, file_handler=None, **kwargs) -> None: raise NotImplementedError("requestWrite needs to be implemented") From f5f8bf19ecdd0e463b8eb3626639637cfd76e8d8 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 14 Mar 2018 11:05:32 +0100 Subject: [PATCH 305/446] Fix QML warnings --- resources/qml/SidebarHeader.qml | 7 ++++++- resources/qml/WorkspaceSummaryDialog.qml | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 74e189789d..dcb351e866 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -347,7 +347,8 @@ Column id: materialSelection property var activeExtruder: Cura.MachineManager.activeStack - property var currentRootMaterialName: activeExtruder.material.name + property var hasActiveExtruder: activeExtruder != null + property var currentRootMaterialName: hasActiveExtruder ? activeExtruder.material.name : "" text: currentRootMaterialName tooltip: currentRootMaterialName @@ -366,6 +367,10 @@ Column property var valueWarning: ! Cura.MachineManager.isActiveQualitySupported function isMaterialSupported () { + if (!hasActiveExtruder) + { + return false; + } return Cura.ContainerManager.getContainerMetaDataEntry(activeExtruder.material.id, "compatible") == "True" } } diff --git a/resources/qml/WorkspaceSummaryDialog.qml b/resources/qml/WorkspaceSummaryDialog.qml index 12eba13dd9..cf19e45fdd 100644 --- a/resources/qml/WorkspaceSummaryDialog.qml +++ b/resources/qml/WorkspaceSummaryDialog.qml @@ -101,7 +101,7 @@ UM.Dialog } Label { - text: Cura.MachineManager.activeMachine.definition.name + text: (Cura.MachineManager.activeMachine == null) ? "" : Cura.MachineManager.activeMachine.definition.name width: (parent.width / 3) | 0 } } From 9f40e3925dcb02028fee554a78cdadf52ac4f47e Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 14 Mar 2018 11:07:38 +0100 Subject: [PATCH 306/446] CURA-5090 added timer to SettingInheritanceManager._update --- cura/Settings/SettingInheritanceManager.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cura/Settings/SettingInheritanceManager.py b/cura/Settings/SettingInheritanceManager.py index 0d4cd02cdb..e317b20f68 100644 --- a/cura/Settings/SettingInheritanceManager.py +++ b/cura/Settings/SettingInheritanceManager.py @@ -1,7 +1,7 @@ # Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal +from PyQt5.QtCore import QObject, QTimer, pyqtProperty, pyqtSignal from UM.FlameProfiler import pyqtSlot from UM.Application import Application from UM.Logger import Logger @@ -30,6 +30,11 @@ class SettingInheritanceManager(QObject): ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderChanged) self._onActiveExtruderChanged() + self._update_timer = QTimer() + self._update_timer.setInterval(500) + self._update_timer.setSingleShot(True) + self._update_timer.timeout.connect(self._update) + settingsWithIntheritanceChanged = pyqtSignal() ## Get the keys of all children settings with an override. @@ -226,9 +231,7 @@ class SettingInheritanceManager(QObject): self._onActiveExtruderChanged() def _onContainersChanged(self, container): - # TODO: Multiple container changes in sequence now cause quite a few recalculations. - # This isn't that big of an issue, but it could be in the future. - self._update() + self._update_timer.start() @staticmethod def createSettingInheritanceManager(engine=None, script_engine=None): From c69987b8240ba82464bb04a4e5c7057f664a5c22 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 14 Mar 2018 11:26:22 +0100 Subject: [PATCH 307/446] CURA-4870 Reintroduce the "Check compatibility" link in the sidebar --- resources/qml/SidebarHeader.qml | 68 +++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 74e189789d..5591f49797 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -468,6 +468,74 @@ Column } } + // Material info row + Item + { + id: materialInfoRow + height: Math.round(UM.Theme.getSize("sidebar_setup").height / 2) + visible: (Cura.MachineManager.hasVariants || Cura.MachineManager.hasMaterials) && !sidebar.monitoringPrint && !sidebar.hideSettings + + anchors + { + left: parent.left + leftMargin: UM.Theme.getSize("sidebar_margin").width + right: parent.right + rightMargin: UM.Theme.getSize("sidebar_margin").width + } + + Item { + height: UM.Theme.getSize("sidebar_setup").height + anchors.right: parent.right + width: Math.round(parent.width * 0.7 + UM.Theme.getSize("sidebar_margin").width) + + UM.RecolorImage { + id: warningImage + anchors.right: materialInfoLabel.left + anchors.rightMargin: UM.Theme.getSize("default_margin").width + anchors.verticalCenter: parent.Bottom + source: UM.Theme.getIcon("warning") + width: UM.Theme.getSize("section_icon").width + height: UM.Theme.getSize("section_icon").height + color: UM.Theme.getColor("material_compatibility_warning") + visible: !Cura.MachineManager.isCurrentSetupSupported + } + + Label { + id: materialInfoLabel + wrapMode: Text.WordWrap + text: "" + catalog.i18nc("@label", "Check compatibility") + "" + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + linkColor: UM.Theme.getColor("text_link") + verticalAlignment: Text.AlignTop + anchors.top: parent.top + anchors.right: parent.right + anchors.bottom: parent.bottom + + MouseArea { + anchors.fill: parent + hoverEnabled: true + onClicked: { + // open the material URL with web browser + var version = UM.Application.version; + var machineName = Cura.MachineManager.activeMachine.definition.id; + var url = "https://ultimaker.com/materialcompatibility/" + version + "/" + machineName + "?utm_source=cura&utm_medium=software&utm_campaign=resources"; + Qt.openUrlExternally(url); + } + onEntered: { + var content = catalog.i18nc("@tooltip", "Click to check the material compatibility on Ultimaker.com."); + base.showTooltip( + materialInfoRow, + Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0), + catalog.i18nc("@tooltip", content) + ); + } + onExited: base.hideTooltip(); + } + } + } + } + UM.SettingPropertyProvider { id: machineExtruderCount From 8dd2243399b509858c7b0753c4cb11a94ca4cf3e Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 14 Mar 2018 11:32:36 +0100 Subject: [PATCH 308/446] Fixed stupid mistake that made all snapshots be taken from the back of model --- cura/Snapshot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Snapshot.py b/cura/Snapshot.py index afc8818116..1f2a24aecd 100644 --- a/cura/Snapshot.py +++ b/cura/Snapshot.py @@ -66,7 +66,7 @@ class Snapshot: size = max(bbox.width, bbox.height, bbox.depth * 0.5) # Looking from this direction (x, y, z) in OGL coordinates - looking_from_offset = Vector(1, 1, -2) + looking_from_offset = Vector(-1, 1, 2) if size > 0: # determine the watch distance depending on the size looking_from_offset = looking_from_offset * size * 1.3 From 160a59191b883a6de4567b7e18ab8acf68c587e7 Mon Sep 17 00:00:00 2001 From: Aleksei S Date: Wed, 14 Mar 2018 11:45:00 +0100 Subject: [PATCH 309/446] Show Tooltip for the unavailable slider's area CURA-5044 --- resources/qml/SidebarSimple.qml | 69 +++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index a7c8a1b8c5..ca3f5fb5d8 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -243,6 +243,75 @@ Item anchors.top: parent.top anchors.topMargin: UM.Theme.getSize("sidebar_margin").height + // This Item is used only for tooltip, for slider area which is unavailable + Item{ + + function showTooltip (showTooltip) { + if(showTooltip){ + var content = catalog.i18nc("@tooltip","This quality profile is not available for you current material and nozzle configuration. Please change these to enable this quality profile") + base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("sidebar_margin").width, customisedSettings.height), content) + } + else + base.hideTooltip(); + } + + id: unavailableLineToolTip + height: 20 // hovered area height + z: parent.z + 1 // should be higher, otherwise the area can be hovered + x: 0 + anchors.verticalCenter: qualitySlider.verticalCenter + + Rectangle{ + id: leftArea + width: { + if(qualityModel.availableTotalTicks == 0) + return 0 + + return qualityModel.qualitySliderStepWidth * qualityModel.qualitySliderAvailableMin - 10 + } + height: parent.height + color: "transparent" + + MouseArea { + anchors.fill: parent + hoverEnabled: true + enabled: Cura.SimpleModeSettingsManager.isProfileUserCreated == false + onEntered: unavailableLineToolTip.showTooltip(true) + onExited: unavailableLineToolTip.showTooltip(false) + } + } + + Rectangle{ + id: rightArea + width: { + if(qualityModel.availableTotalTicks == 0) + return 0 + + return qualityModel.qualitySliderMarginRight - 10 + } + height: parent.height + color: "transparent" + x: { + if(qualityModel.availableTotalTicks == 0){ + return 0 + } + + var leftUnavailableArea = qualityModel.qualitySliderStepWidth * qualityModel.qualitySliderAvailableMin + var totalGap = qualityModel.qualitySliderStepWidth * (qualityModel.availableTotalTicks -1) + leftUnavailableArea + 10 + + return totalGap + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + enabled: Cura.SimpleModeSettingsManager.isProfileUserCreated == false + onEntered: unavailableLineToolTip.showTooltip(true) + onExited: unavailableLineToolTip.showTooltip(false) + } + } + } + // Draw Unavailable line Rectangle { From 23a2b6e0f7ef86454904e67590b10725c6bf5d4b Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 14 Mar 2018 11:54:10 +0100 Subject: [PATCH 310/446] CURA-4870 Don't show the configuration selector if the printer is not a network printer (for example don't show if is USB) --- resources/qml/MachineSelection.qml | 2 +- resources/qml/Menus/ConfigurationMenu/SyncButton.qml | 12 ++++++++---- resources/qml/Sidebar.qml | 3 ++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/resources/qml/MachineSelection.qml b/resources/qml/MachineSelection.qml index 4bddd20b2b..b3f9629703 100644 --- a/resources/qml/MachineSelection.qml +++ b/resources/qml/MachineSelection.qml @@ -12,7 +12,7 @@ import "Menus" ToolButton { id: base - property var isNetworkPrinter: Cura.MachineManager.activeMachineNetworkKey != "" + property bool isNetworkPrinter: Cura.MachineManager.activeMachineNetworkKey != "" property var printerStatus: Cura.MachineManager.printerOutputDevices.length != 0 ? "connected" : "disconnected" text: isNetworkPrinter ? Cura.MachineManager.activeMachineNetworkGroupName : Cura.MachineManager.activeMachineName diff --git a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml index a2d1d53b78..f0394cc107 100644 --- a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml +++ b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml @@ -17,11 +17,15 @@ Button width: parent.width height: parent.height - function updateOnSync() { - if (outputDevice != undefined) { - for (var index in outputDevice.uniqueConfigurations) { + function updateOnSync() + { + if (outputDevice != undefined) + { + for (var index in outputDevice.uniqueConfigurations) + { var configuration = outputDevice.uniqueConfigurations[index] - if (Cura.MachineManager.matchesConfiguration(configuration)) { + if (Cura.MachineManager.matchesConfiguration(configuration)) + { base.matched = true; return; } diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml index 47882c9ecc..5211ee5a1d 100644 --- a/resources/qml/Sidebar.qml +++ b/resources/qml/Sidebar.qml @@ -19,6 +19,7 @@ Rectangle property bool hideView: Cura.MachineManager.activeMachineName == "" // Is there an output device for this printer? + property bool isNetworkPrinter: Cura.MachineManager.activeMachineNetworkKey != "" property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0 property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands property var connectedPrinter: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null @@ -106,7 +107,7 @@ Rectangle ConfigurationSelection { id: configSelection - visible: printerConnected && !sidebar.monitoringPrint && !sidebar.hideSettings + visible: isNetworkPrinter && !sidebar.monitoringPrint && !sidebar.hideSettings width: visible ? Math.round(base.width * 0.15) : 0 height: UM.Theme.getSize("sidebar_header").height anchors.top: base.top From b8c32eb166a58c8fba86d97aa8a94c19d113791d Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 14 Mar 2018 12:59:31 +0100 Subject: [PATCH 311/446] Fix typo in ConfigurationListView.qml --- resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml index 4a2d4cd062..52fd0e6556 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -59,7 +59,7 @@ Column section.criteria: ViewSection.FullString section.delegate: sectionHeading - model: (ouputDevice != null) ? outputDevice.uniqueConfigurations : [] + model: (outputDevice != null) ? outputDevice.uniqueConfigurations : [] delegate: ConfigurationItem { width: parent.width - UM.Theme.getSize("default_margin").width From 53626d3c67100682b97dff30e9cfe17440e25cf4 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 14 Mar 2018 13:02:51 +0100 Subject: [PATCH 312/446] Also force update validationState CURA-5048 --- cura/Settings/MachineManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index b41cdc9799..019354ad40 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -882,7 +882,7 @@ class MachineManager(QObject): @pyqtSlot() def forceUpdateAllSettings(self): with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): - property_names = ["value", "resolve"] + property_names = ["value", "resolve", "validationState"] for container in [self._global_container_stack] + list(self._global_container_stack.extruders.values()): for setting_key in container.getAllKeys(): container.propertiesChanged.emit(setting_key, property_names) From fcd50b0cf21a1e0755213685f7a89fa4f61964be Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 14 Mar 2018 13:10:56 +0100 Subject: [PATCH 313/446] Fix code style CURA-5044 --- resources/qml/SidebarSimple.qml | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index ca3f5fb5d8..2ee0a9e9f1 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -244,15 +244,17 @@ Item anchors.topMargin: UM.Theme.getSize("sidebar_margin").height // This Item is used only for tooltip, for slider area which is unavailable - Item{ - - function showTooltip (showTooltip) { - if(showTooltip){ - var content = catalog.i18nc("@tooltip","This quality profile is not available for you current material and nozzle configuration. Please change these to enable this quality profile") - base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("sidebar_margin").width, customisedSettings.height), content) + Item + { + function showTooltip (showTooltip) + { + if (showTooltip) { + var content = catalog.i18nc("@tooltip", "This quality profile is not available for you current material and nozzle configuration. Please change these to enable this quality profile") + base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("sidebar_margin").width, customisedSettings.height), content) + } + else { + base.hideTooltip() } - else - base.hideTooltip(); } id: unavailableLineToolTip @@ -261,7 +263,8 @@ Item x: 0 anchors.verticalCenter: qualitySlider.verticalCenter - Rectangle{ + Rectangle + { id: leftArea width: { if(qualityModel.availableTotalTicks == 0) @@ -272,7 +275,8 @@ Item height: parent.height color: "transparent" - MouseArea { + MouseArea + { anchors.fill: parent hoverEnabled: true enabled: Cura.SimpleModeSettingsManager.isProfileUserCreated == false @@ -281,7 +285,8 @@ Item } } - Rectangle{ + Rectangle + { id: rightArea width: { if(qualityModel.availableTotalTicks == 0) @@ -292,7 +297,7 @@ Item height: parent.height color: "transparent" x: { - if(qualityModel.availableTotalTicks == 0){ + if (qualityModel.availableTotalTicks == 0) { return 0 } From d6b270954adb4c116c947f95e644f4643768662a Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 14 Mar 2018 13:11:22 +0100 Subject: [PATCH 314/446] Fix the case when no quality is available CURA-5044 The tooltip should also show up if there is no quality available. --- resources/qml/SidebarSimple.qml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index 2ee0a9e9f1..41ecb529eb 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -266,10 +266,11 @@ Item Rectangle { id: leftArea - width: { - if(qualityModel.availableTotalTicks == 0) - return 0 - + width: + { + if (qualityModel.availableTotalTicks == 0) { + return qualityModel.qualitySliderStepWidth * qualityModel.totalTicks + } return qualityModel.qualitySliderStepWidth * qualityModel.qualitySliderAvailableMin - 10 } height: parent.height From 05c59ddaa763277de44e56d0855e827fe5a357ee Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Wed, 14 Mar 2018 13:29:48 +0100 Subject: [PATCH 315/446] CURA-4946 Handle gcode with wrong quality definition Some gcode has its quality definition set to, say, UM2 extended, which is _actually_ just UM2 gcode. Thus, we check if the definition in the profile matches the current machine or what it in theory should be, either one being valid. See comments in code for details. --- cura/Settings/CuraContainerRegistry.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index 81cbabc0c9..07ba2db1e5 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -212,12 +212,20 @@ class CuraContainerRegistry(ContainerRegistry): return { "status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags or !", "This profile {0} contains incorrect data, could not import it.", file_name)} profile_definition = global_profile.getMetaDataEntry("definition") - expected_machine_definition = "fdmprinter" - if parseBool(global_container_stack.getMetaDataEntry("has_machine_quality", "False")): - expected_machine_definition = global_container_stack.getMetaDataEntry("quality_definition") - if not expected_machine_definition: - expected_machine_definition = global_container_stack.definition.getId() - if expected_machine_definition is not None and profile_definition is not None and profile_definition != expected_machine_definition: + + # Make sure we have a profile_definition in the file: + if profile_definition is None: + break + + # Get the expected machine definition. + # i.e.: We expect gcode for a UM2 Extended to be defined as normal UM2 gcode... + expected_machine_definition = getMachineDefinitionIDForQualitySearch(global_container_stack.definition) + + # ...but that's not always the case for Cura 3.1 and older, so also get the current machine: + current_machine_definition = global_container_stack.definition.getId() + + # And check if the profile_definition matches either one (showing error if not): + if profile_definition not in (expected_machine_definition, current_machine_definition): Logger.log("e", "Profile [%s] is for machine [%s] but the current active machine is [%s]. Will not import the profile", file_name, profile_definition, expected_machine_definition) return { "status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags or !", "The machine defined in profile {0} ({1}) doesn't match with your current machine ({2}), could not import it.", file_name, profile_definition, expected_machine_definition)} From 474db38ddf1c7f0193fa8486c0294e2eaf9f44e9 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Wed, 14 Mar 2018 13:30:20 +0100 Subject: [PATCH 316/446] Fix failing test for um3_extended 0.8 variant --- resources/variants/ultimaker3_bb0.8.inst.cfg | 1 - tests/TestProfileRequirements.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/resources/variants/ultimaker3_bb0.8.inst.cfg b/resources/variants/ultimaker3_bb0.8.inst.cfg index 41c6419ec1..ef6dc625ac 100644 --- a/resources/variants/ultimaker3_bb0.8.inst.cfg +++ b/resources/variants/ultimaker3_bb0.8.inst.cfg @@ -56,7 +56,6 @@ retraction_amount = 4.5 retraction_count_max = 15 retraction_extrusion_window = =retraction_amount retraction_hop = 2 -retraction_hop_enabled = True retraction_hop_only_when_collides = True retraction_min_travel = 5 retraction_prime_speed = 15 diff --git a/tests/TestProfileRequirements.py b/tests/TestProfileRequirements.py index a91a08172c..edeec909f2 100644 --- a/tests/TestProfileRequirements.py +++ b/tests/TestProfileRequirements.py @@ -22,4 +22,4 @@ def test_ultimaker3extended_variants(um3_file, um3e_file): um3.read_file(open(os.path.join(directory, um3_file))) um3e = configparser.ConfigParser() um3e.read_file(open(os.path.join(directory, um3e_file))) - assert um3["values"] == um3e["values"] \ No newline at end of file + assert um3["values"] == um3e["values"] From 191faaba19b71cabacfde4c391961863493fe87f Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 14 Mar 2018 13:49:13 +0100 Subject: [PATCH 317/446] Fix machine definition in quality importing CURA-4946 --- cura/Settings/CuraContainerRegistry.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index 07ba2db1e5..4e8ece0504 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -230,6 +230,11 @@ class CuraContainerRegistry(ContainerRegistry): return { "status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags or !", "The machine defined in profile {0} ({1}) doesn't match with your current machine ({2}), could not import it.", file_name, profile_definition, expected_machine_definition)} + # Fix the global quality profile's definition field in case it's not correct + global_profile.setMetaDataEntry("definition", expected_machine_definition) + quality_name = global_profile.getName() + quality_type = global_profile.getMetaDataEntry("quality_type") + name_seed = os.path.splitext(os.path.basename(file_name))[0] new_name = self.uniqueName(name_seed) @@ -244,11 +249,11 @@ class CuraContainerRegistry(ContainerRegistry): for idx, extruder in enumerate(global_container_stack.extruders.values()): profile_id = ContainerRegistry.getInstance().uniqueName(global_container_stack.getId() + "_extruder_" + str(idx + 1)) profile = InstanceContainer(profile_id) - profile.setName(global_profile.getName()) + profile.setName(quality_name) profile.addMetaDataEntry("setting_version", CuraApplication.SettingVersion) profile.addMetaDataEntry("type", "quality_changes") - profile.addMetaDataEntry("definition", global_profile.getMetaDataEntry("definition")) - profile.addMetaDataEntry("quality_type", global_profile.getMetaDataEntry("quality_type")) + profile.addMetaDataEntry("definition", expected_machine_definition) + profile.addMetaDataEntry("quality_type", quality_type) profile.addMetaDataEntry("position", "0") profile.setDirty(True) if idx == 0: From 1111fbaa78113071e13b477373af1ad0ca22454a Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 14 Mar 2018 13:53:04 +0100 Subject: [PATCH 318/446] CURA-4870 Changing the version upgrade to include new metadata entries for the container stacks. --- .../VersionUpgrade32to33.py | 24 +++++++++++++++++++ .../VersionUpgrade32to33/__init__.py | 11 +++++++++ 2 files changed, 35 insertions(+) diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py b/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py index de2240a7c6..620f367e25 100644 --- a/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py +++ b/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py @@ -56,6 +56,8 @@ _EXTRUDER_TO_POSITION = { ## Upgrades configurations from the state they were in at version 3.2 to the # state they should be in at version 3.3. class VersionUpgrade32to33(VersionUpgrade): + + temporary_group_name_counter = 1 ## Gets the version number from a CFG file in Uranium's 3.2 format. # # Since the format may change, this is implemented for the 3.2 format only @@ -74,6 +76,28 @@ class VersionUpgrade32to33(VersionUpgrade): setting_version = int(parser.get("metadata", "setting_version", fallback = 0)) return format_version * 1000000 + setting_version + ## Upgrades a container stack from version 3.2 to 3.3. + # + # \param serialised The serialised form of a container stack. + # \param filename The name of the file to upgrade. + def upgradeStack(self, serialized, filename): + parser = configparser.ConfigParser(interpolation = None) + parser.read_string(serialized) + + if "metadata" in parser and "um_network_key" in parser["metadata"]: + if "hidden" not in parser["metadata"]: + parser["metadata"]["hidden"] = "False" + if "connect_group_name" not in parser["metadata"]: + parser["metadata"]["connect_group_name"] = "Temporary group name #" + str(self.temporary_group_name_counter) + self.temporary_group_name_counter += 1 + + #Update version number. + parser["general"]["version"] = "4" + + result = io.StringIO() + parser.write(result) + return [filename], [result.getvalue()] + ## Upgrades non-quality-changes instance containers to have the new version # number. def upgradeInstanceContainer(self, serialized, filename): diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py b/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py index c411b4190e..72ff6e1de9 100644 --- a/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py +++ b/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py @@ -9,11 +9,22 @@ def getMetaData(): return { "version_upgrade": { # From To Upgrade function + ("machine_stack", 3000004): ("machine_stack", 4000004, upgrade.upgradeStack), + ("extruder_train", 3000004): ("extruder_train", 4000004, upgrade.upgradeStack), + ("definition_changes", 2000004): ("definition_changes", 3000004, upgrade.upgradeInstanceContainer), ("quality_changes", 2000004): ("quality_changes", 3000004, upgrade.upgradeQualityChanges), ("user", 2000004): ("user", 3000004, upgrade.upgradeInstanceContainer) }, "sources": { + "machine_stack": { + "get_version": upgrade.getCfgVersion, + "location": {"./machine_instances"} + }, + "extruder_train": { + "get_version": upgrade.getCfgVersion, + "location": {"./extruders"} + }, "definition_changes": { "get_version": upgrade.getCfgVersion, "location": {"./definition_changes"} From fa9dc7a1df691a282a3ebacc5b5d7bc0ba817ea3 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 14 Mar 2018 14:20:03 +0100 Subject: [PATCH 319/446] Fixed send custom firmware --- plugins/USBPrinting/USBPrinterOutputDevice.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index 5d99f61a51..a17b2af3c3 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -116,7 +116,8 @@ class USBPrinterOutputDevice(PrinterOutputDevice): @pyqtSlot(str) def updateFirmware(self, file): - self._firmware_location = file + # the file path is qurl encoded. + self._firmware_location = file.replace("file://", "") self.showFirmwareInterface() self.setFirmwareUpdateState(FirmwareUpdateState.updating) self._update_firmware_thread.start() From 0655ef0bc52efa03b6892d417e79e3dbe26d638e Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 14 Mar 2018 14:22:19 +0100 Subject: [PATCH 320/446] Fix quality profile import CURA-4946 --- cura/Settings/CuraContainerRegistry.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index 4e8ece0504..ebe8007955 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -204,7 +204,7 @@ class CuraContainerRegistry(ContainerRegistry): global_profile = profile_or_list[0] else: for profile in profile_or_list: - if not profile.getMetaDataEntry("extruder"): + if not profile.getMetaDataEntry("position"): global_profile = profile break if not global_profile: @@ -296,7 +296,7 @@ class CuraContainerRegistry(ContainerRegistry): else: #More extruders in the imported file than in the machine. continue #Delete the additional profiles. - result = self._configureProfile(profile, profile_id, new_name) + result = self._configureProfile(profile, profile_id, new_name, expected_machine_definition) if result is not None: return {"status": "error", "message": catalog.i18nc( "@info:status Don't translate the XML tags or !", @@ -324,7 +324,7 @@ class CuraContainerRegistry(ContainerRegistry): # \param new_name The new name for the profile. # # \return None if configuring was successful or an error message if an error occurred. - def _configureProfile(self, profile: InstanceContainer, id_seed: str, new_name: str) -> Optional[str]: + def _configureProfile(self, profile: InstanceContainer, id_seed: str, new_name: str, machine_definition_id: str) -> Optional[str]: profile.setDirty(True) # Ensure the profiles are correctly saved new_id = self.createUniqueName("quality_changes", "", id_seed, catalog.i18nc("@label", "Custom profile")) @@ -334,6 +334,7 @@ class CuraContainerRegistry(ContainerRegistry): # Set the unique Id to the profile, so it's generating a new one even if the user imports the same profile # It also solves an issue with importing profiles from G-Codes profile.setMetaDataEntry("id", new_id) + profile.setMetaDataEntry("definition", machine_definition_id) if "type" in profile.getMetaData(): profile.setMetaDataEntry("type", "quality_changes") From 877d061a1b19b16cda66c81989a6000c9b1018b5 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 14 Mar 2018 14:23:40 +0100 Subject: [PATCH 321/446] Catch FileNotFoundError when updating custom firmware In case there is a bug there, we won't crash the thread. --- plugins/USBPrinting/USBPrinterOutputDevice.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index a17b2af3c3..14098b66f8 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -127,9 +127,11 @@ class USBPrinterOutputDevice(PrinterOutputDevice): if self._connection_state != ConnectionState.closed: self.close() - hex_file = intelHex.readHex(self._firmware_location) - if len(hex_file) == 0: - Logger.log("e", "Unable to read provided hex file. Could not update firmware") + try: + hex_file = intelHex.readHex(self._firmware_location) + assert len(hex_file) > 0 + except (FileNotFoundError, AssertionError): + Logger.log("e", "Unable to read provided hex file. Could not update firmware.") self.setFirmwareUpdateState(FirmwareUpdateState.firmware_not_found_error) return From 22573a685d5cd771202e950c2c0e2dc48da25fcc Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 14 Mar 2018 14:31:07 +0100 Subject: [PATCH 322/446] Fix quality definition comparison in quality importing CURA-4946 --- cura/Machines/QualityManager.py | 18 ++++++++++-------- cura/Settings/CuraContainerRegistry.py | 16 ++++++++++------ cura/Settings/MachineManager.py | 2 +- plugins/3MFReader/ThreeMFReader.py | 2 +- plugins/3MFReader/ThreeMFWorkspaceReader.py | 2 +- 5 files changed, 23 insertions(+), 17 deletions(-) diff --git a/cura/Machines/QualityManager.py b/cura/Machines/QualityManager.py index efb940b857..8d972c9192 100644 --- a/cura/Machines/QualityManager.py +++ b/cura/Machines/QualityManager.py @@ -16,6 +16,7 @@ from .QualityGroup import QualityGroup from .QualityNode import QualityNode if TYPE_CHECKING: + from UM.Settings.DefinitionContainer import DefinitionContainer from cura.Settings.GlobalStack import GlobalStack from .QualityChangesGroup import QualityChangesGroup @@ -178,7 +179,7 @@ class QualityManager(QObject): # Returns a dict of "custom profile name" -> QualityChangesGroup def getQualityChangesGroups(self, machine: "GlobalStack") -> dict: - machine_definition_id = getMachineDefinitionIDForQualitySearch(machine) + machine_definition_id = getMachineDefinitionIDForQualitySearch(machine.definition) machine_node = self._machine_quality_type_to_quality_changes_dict.get(machine_definition_id) if not machine_node: @@ -206,7 +207,7 @@ class QualityManager(QObject): # For more details, see QualityGroup. # def getQualityGroups(self, machine: "GlobalStack") -> dict: - machine_definition_id = getMachineDefinitionIDForQualitySearch(machine) + machine_definition_id = getMachineDefinitionIDForQualitySearch(machine.definition) # This determines if we should only get the global qualities for the global stack and skip the global qualities for the extruder stacks has_variant_materials = parseBool(machine.getMetaDataEntry("has_variant_materials", False)) @@ -315,7 +316,7 @@ class QualityManager(QObject): return quality_group_dict def getQualityGroupsForMachineDefinition(self, machine: "GlobalStack") -> dict: - machine_definition_id = getMachineDefinitionIDForQualitySearch(machine) + machine_definition_id = getMachineDefinitionIDForQualitySearch(machine.definition) # To find the quality container for the GlobalStack, check in the following fall-back manner: # (1) the machine-specific node @@ -460,7 +461,7 @@ class QualityManager(QObject): quality_changes.addMetaDataEntry("position", extruder_stack.getMetaDataEntry("position")) # If the machine specifies qualities should be filtered, ensure we match the current criteria. - machine_definition_id = getMachineDefinitionIDForQualitySearch(machine) + machine_definition_id = getMachineDefinitionIDForQualitySearch(machine.definition) quality_changes.setDefinition(machine_definition_id) quality_changes.addMetaDataEntry("setting_version", self._application.SettingVersion) @@ -480,12 +481,13 @@ class QualityManager(QObject): # Example: for an Ultimaker 3 Extended, it has "quality_definition = ultimaker3". This means Ultimaker 3 Extended # shares the same set of qualities profiles as Ultimaker 3. # -def getMachineDefinitionIDForQualitySearch(machine: "GlobalStack", default_definition_id: str = "fdmprinter") -> str: +def getMachineDefinitionIDForQualitySearch(machine_definition: "DefinitionContainer", + default_definition_id: str = "fdmprinter") -> str: machine_definition_id = default_definition_id - if parseBool(machine.getMetaDataEntry("has_machine_quality", False)): + if parseBool(machine_definition.getMetaDataEntry("has_machine_quality", False)): # Only use the machine's own quality definition ID if this machine has machine quality. - machine_definition_id = machine.getMetaDataEntry("quality_definition") + machine_definition_id = machine_definition.getMetaDataEntry("quality_definition") if machine_definition_id is None: - machine_definition_id = machine.definition.getId() + machine_definition_id = machine_definition.getId() return machine_definition_id diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index ebe8007955..0cf1c7399f 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -216,16 +216,21 @@ class CuraContainerRegistry(ContainerRegistry): # Make sure we have a profile_definition in the file: if profile_definition is None: break + machine_definition = self.findDefinitionContainers(id = profile_definition) + if not machine_definition: + Logger.log("e", "Incorrect profile [%s]. Unknown machine type [%s]", file_name, profile_definition) + return {"status": "error", + "message": catalog.i18nc("@info:status Don't translate the XML tags or !", "This profile {0} contains incorrect data, could not import it.", file_name) + } + machine_definition = machine_definition[0] # Get the expected machine definition. # i.e.: We expect gcode for a UM2 Extended to be defined as normal UM2 gcode... + profile_definition = getMachineDefinitionIDForQualitySearch(machine_definition) expected_machine_definition = getMachineDefinitionIDForQualitySearch(global_container_stack.definition) - # ...but that's not always the case for Cura 3.1 and older, so also get the current machine: - current_machine_definition = global_container_stack.definition.getId() - # And check if the profile_definition matches either one (showing error if not): - if profile_definition not in (expected_machine_definition, current_machine_definition): + if profile_definition != expected_machine_definition: Logger.log("e", "Profile [%s] is for machine [%s] but the current active machine is [%s]. Will not import the profile", file_name, profile_definition, expected_machine_definition) return { "status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags or !", "The machine defined in profile {0} ({1}) doesn't match with your current machine ({2}), could not import it.", file_name, profile_definition, expected_machine_definition)} @@ -345,9 +350,8 @@ class CuraContainerRegistry(ContainerRegistry): if not quality_type: return catalog.i18nc("@info:status", "Profile is missing a quality type.") - quality_type_criteria = {"quality_type": quality_type} global_stack = Application.getInstance().getGlobalContainerStack() - definition_id = getMachineDefinitionIDForQualitySearch(global_stack) + definition_id = getMachineDefinitionIDForQualitySearch(global_stack.definition) profile.setDefinition(definition_id) # Check to make sure the imported profile actually makes sense in context of the current configuration. diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 019354ad40..3af6f70e5f 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -628,7 +628,7 @@ class MachineManager(QObject): @pyqtProperty(str, notify = globalContainerChanged) def activeQualityDefinitionId(self) -> str: if self._global_container_stack: - return getMachineDefinitionIDForQualitySearch(self._global_container_stack) + return getMachineDefinitionIDForQualitySearch(self._global_container_stack.definition) return "" ## Gets how the active definition calls variants diff --git a/plugins/3MFReader/ThreeMFReader.py b/plugins/3MFReader/ThreeMFReader.py index ec590a0212..3a1298bdba 100755 --- a/plugins/3MFReader/ThreeMFReader.py +++ b/plugins/3MFReader/ThreeMFReader.py @@ -122,7 +122,7 @@ class ThreeMFReader(MeshReader): um_node.callDecoration("setActiveExtruder", default_stack.getId()) # Get the definition & set it - definition_id = getMachineDefinitionIDForQualitySearch(global_container_stack) + definition_id = getMachineDefinitionIDForQualitySearch(global_container_stack.definition) um_node.callDecoration("getStack").getTop().setDefinition(definition_id) setting_container = um_node.callDecoration("getStack").getTop() diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index f20b9ab181..f5daa77bb0 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -719,7 +719,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # Get the correct extruder definition IDs for quality changes from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch - machine_definition_id_for_quality = getMachineDefinitionIDForQualitySearch(global_stack) + machine_definition_id_for_quality = getMachineDefinitionIDForQualitySearch(global_stack.definition) machine_definition_for_quality = self._container_registry.findDefinitionContainers(id = machine_definition_id_for_quality)[0] quality_changes_info = self._machine_info.quality_changes_info From 962c5f32604b314aa4cd71a7b13350a23ac32025 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 14 Mar 2018 14:39:06 +0100 Subject: [PATCH 323/446] Added bit of defensive coding to cluster output device --- plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py index 70a5607071..d69d787eab 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py @@ -372,11 +372,17 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): print_job.updateState(data["status"]) print_job.updateOwner(data["owner"]) - def _updatePrinter(self, printer, data): + def _updatePrinter(self, printer, data) -> None: # For some unknown reason the cluster wants UUID for everything, except for sending a job directly to a printer. # Then we suddenly need the unique name. So in order to not have to mess up all the other code, we save a mapping. self._printer_uuid_to_unique_name_mapping[data["uuid"]] = data["unique_name"] - machine_definition = ContainerRegistry.getInstance().findDefinitionContainers(name = data["machine_variant"])[0] + + definitions = ContainerRegistry.getInstance().findDefinitionContainers(name = data["machine_variant"]) + if not definitions: + Logger.log("w", "Unable to find definition for machine variant %s", data["machine_variant"]) + return + + machine_definition = definitions[0] printer.updateName(data["friendly_name"]) printer.updateKey(data["uuid"]) From 241611546e643ab50a2145b7186e6d3c5d4a2f1b Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 14 Mar 2018 14:41:43 +0100 Subject: [PATCH 324/446] Fix quality details view CURA-5054 --- cura/Machines/Models/QualitySettingsModel.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cura/Machines/Models/QualitySettingsModel.py b/cura/Machines/Models/QualitySettingsModel.py index 4470ffc80e..b38f6f65c8 100644 --- a/cura/Machines/Models/QualitySettingsModel.py +++ b/cura/Machines/Models/QualitySettingsModel.py @@ -87,9 +87,11 @@ class QualitySettingsModel(ListModel): if self._selected_position == self.GLOBAL_STACK_POSITION: quality_node = quality_group.node_for_global else: - quality_node = quality_group.nodes_for_extruders.get(self._selected_position) + quality_node = quality_group.nodes_for_extruders.get(str(self._selected_position)) settings_keys = quality_group.getAllKeys() - quality_containers = [quality_node.getContainer()] + quality_containers = [] + if quality_node is not None: + quality_containers.append(quality_node.getContainer()) # Here, if the user has selected a quality changes, then "quality_changes_group" will not be None, and we fetch # the settings in that quality_changes_group. @@ -97,7 +99,7 @@ class QualitySettingsModel(ListModel): if self._selected_position == self.GLOBAL_STACK_POSITION: quality_changes_node = quality_changes_group.node_for_global else: - quality_changes_node = quality_changes_group.nodes_for_extruders.get(self._selected_position) + quality_changes_node = quality_changes_group.nodes_for_extruders.get(str(self._selected_position)) if quality_changes_node is not None: # it can be None if number of extruders are changed during runtime try: quality_containers.insert(0, quality_changes_node.getContainer()) From ad3c5466d1078640f3b509f570aa3b0fde99ec6b Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 14 Mar 2018 14:45:01 +0100 Subject: [PATCH 325/446] Added bunch of typing to clusteroutput device --- .../ClusterUM3OutputDevice.py | 51 +++++++++---------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py index d69d787eab..c19c86d6ce 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py @@ -22,7 +22,7 @@ from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal, pyqtProperty, QObject from time import time from datetime import datetime -from typing import Optional +from typing import Optional, Dict, List import json import os @@ -79,7 +79,6 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): self._latest_reply_handler = None - def requestWrite(self, nodes, file_name=None, filter_by_machine=False, file_handler=None, **kwargs): self.writeStarted.emit(self) @@ -116,7 +115,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): @pyqtSlot() @pyqtSlot(str) - def sendPrintJob(self, target_printer = ""): + def sendPrintJob(self, target_printer: str = ""): Logger.log("i", "Sending print job to printer.") if self._sending_gcode: self._error_message = Message( @@ -157,11 +156,11 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): return True @pyqtProperty(QObject, notify=activePrinterChanged) - def activePrinter(self) -> Optional["PrinterOutputModel"]: + def activePrinter(self) -> Optional[PrinterOutputModel]: return self._active_printer @pyqtSlot(QObject) - def setActivePrinter(self, printer): + def setActivePrinter(self, printer: Optional[PrinterOutputModel]): if self._active_printer != printer: if self._active_printer and self._active_printer.camera: self._active_printer.camera.stop() @@ -173,7 +172,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): self._compressing_gcode = False self._sending_gcode = False - def _onUploadPrintJobProgress(self, bytes_sent, bytes_total): + def _onUploadPrintJobProgress(self, bytes_sent:int, bytes_total:int): if bytes_total > 0: new_progress = bytes_sent / bytes_total * 100 # Treat upload progress as response. Uploading can take more than 10 seconds, so if we don't, we can get @@ -186,7 +185,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): self._progress_message.setProgress(0) self._progress_message.hide() - def _progressMessageActionTriggered(self, message_id=None, action_id=None): + def _progressMessageActionTriggered(self, message_id: Optional[str]=None, action_id: Optional[str]=None) -> None: if action_id == "Abort": Logger.log("d", "User aborted sending print to remote.") self._progress_message.hide() @@ -202,29 +201,29 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): @pyqtSlot() - def openPrintJobControlPanel(self): + def openPrintJobControlPanel(self) -> None: Logger.log("d", "Opening print job control panel...") QDesktopServices.openUrl(QUrl("http://" + self._address + "/print_jobs")) @pyqtSlot() - def openPrinterControlPanel(self): + def openPrinterControlPanel(self) -> None: Logger.log("d", "Opening printer control panel...") QDesktopServices.openUrl(QUrl("http://" + self._address + "/printers")) @pyqtProperty("QVariantList", notify=printJobsChanged) - def printJobs(self): + def printJobs(self)-> List[PrintJobOutputModel] : return self._print_jobs @pyqtProperty("QVariantList", notify=printJobsChanged) - def queuedPrintJobs(self): + def queuedPrintJobs(self) -> List[PrintJobOutputModel]: return [print_job for print_job in self._print_jobs if print_job.assignedPrinter is None or print_job.state == "queued"] @pyqtProperty("QVariantList", notify=printJobsChanged) - def activePrintJobs(self): + def activePrintJobs(self) -> List[PrintJobOutputModel]: return [print_job for print_job in self._print_jobs if print_job.assignedPrinter is not None and print_job.state != "queued"] @pyqtProperty("QVariantList", notify=clusterPrintersChanged) - def connectedPrintersTypeCount(self): + def connectedPrintersTypeCount(self) -> List[PrinterOutputModel]: printer_count = {} for printer in self._printers: if printer.type in printer_count: @@ -237,22 +236,22 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): return result @pyqtSlot(int, result=str) - def formatDuration(self, seconds): + def formatDuration(self, seconds: int) -> str: return Duration(seconds).getDisplayString(DurationFormat.Format.Short) @pyqtSlot(int, result=str) - def getTimeCompleted(self, time_remaining): + def getTimeCompleted(self, time_remaining: int) -> str: current_time = time() datetime_completed = datetime.fromtimestamp(current_time + time_remaining) return "{hour:02d}:{minute:02d}".format(hour=datetime_completed.hour, minute=datetime_completed.minute) @pyqtSlot(int, result=str) - def getDateCompleted(self, time_remaining): + def getDateCompleted(self, time_remaining: int) -> str: current_time = time() datetime_completed = datetime.fromtimestamp(current_time + time_remaining) return (datetime_completed.strftime("%a %b ") + "{day}".format(day=datetime_completed.day)).upper() - def _printJobStateChanged(self): + def _printJobStateChanged(self) -> None: username = self._getUserName() if username is None: @@ -275,13 +274,13 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): # Keep a list of all completed jobs so we know if something changed next time. self._finished_jobs = finished_jobs - def _update(self): + def _update(self) -> None: if not super()._update(): return self.get("printers/", onFinished=self._onGetPrintersDataFinished) self.get("print_jobs/", onFinished=self._onGetPrintJobsFinished) - def _onGetPrintJobsFinished(self, reply: QNetworkReply): + def _onGetPrintJobsFinished(self, reply: QNetworkReply) -> None: if not checkValidGetReply(reply): return @@ -323,7 +322,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): if job_list_changed: self.printJobsChanged.emit() # Do a single emit for all print job changes. - def _onGetPrintersDataFinished(self, reply: QNetworkReply): + def _onGetPrintersDataFinished(self, reply: QNetworkReply) -> None: if not checkValidGetReply(reply): return @@ -352,27 +351,27 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): if removed_printers or printer_list_changed: self.printersChanged.emit() - def _createPrinterModel(self, data): + def _createPrinterModel(self, data: Dict) -> PrinterOutputModel: printer = PrinterOutputModel(output_controller=ClusterUM3PrinterOutputController(self), number_of_extruders=self._number_of_extruders) printer.setCamera(NetworkCamera("http://" + data["ip_address"] + ":8080/?action=stream")) self._printers.append(printer) return printer - def _createPrintJobModel(self, data): + def _createPrintJobModel(self, data: Dict) -> PrintJobOutputModel: print_job = PrintJobOutputModel(output_controller=ClusterUM3PrinterOutputController(self), key=data["uuid"], name= data["name"]) print_job.stateChanged.connect(self._printJobStateChanged) self._print_jobs.append(print_job) return print_job - def _updatePrintJob(self, print_job, data): + def _updatePrintJob(self, print_job: PrintJobOutputModel, data: Dict) -> None: print_job.updateTimeTotal(data["time_total"]) print_job.updateTimeElapsed(data["time_elapsed"]) print_job.updateState(data["status"]) print_job.updateOwner(data["owner"]) - def _updatePrinter(self, printer, data) -> None: + def _updatePrinter(self, printer: PrinterOutputModel, data: Dict) -> None: # For some unknown reason the cluster wants UUID for everything, except for sending a job directly to a printer. # Then we suddenly need the unique name. So in order to not have to mess up all the other code, we save a mapping. self._printer_uuid_to_unique_name_mapping[data["uuid"]] = data["unique_name"] @@ -427,7 +426,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): brand=brand, color=color, name=name) extruder.updateActiveMaterial(material) - def _removeJob(self, job): + def _removeJob(self, job: PrintJobOutputModel): if job not in self._print_jobs: return False @@ -438,7 +437,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): return True - def _removePrinter(self, printer): + def _removePrinter(self, printer: PrinterOutputModel): self._printers.remove(printer) if self._active_printer == printer: self._active_printer = None From 61ce0c3154a2398f775b0a0c92865adf6b19f05f Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 14 Mar 2018 15:15:43 +0100 Subject: [PATCH 326/446] CURA-4870 Make the configuration pop-up open and close with one click. Before it was the case in which sometimes the user needs two clicks for that. Also collapse the dropdown when the configuration is applied. --- .../ConfigurationListView.qml | 1 + .../ConfigurationSelection.qml | 62 +++++++++---------- .../Menus/ConfigurationMenu/SyncButton.qml | 5 -- 3 files changed, 32 insertions(+), 36 deletions(-) diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml index 52fd0e6556..999fecd7fd 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -66,6 +66,7 @@ Column configuration: modelData onActivateConfiguration: { + switchPopupState() Cura.MachineManager.applyRemoteConfiguration(configuration) } } diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml index eb0d5f5cff..a3cf10168b 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml @@ -13,54 +13,54 @@ Item id: configurationSelector property var connectedDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null property var panelWidth: control.width - property var panelVisible: false - SyncButton { - onClicked: configurationSelector.state == "open" ? configurationSelector.state = "closed" : configurationSelector.state = "open" + function switchPopupState() + { + popup.opened ? popup.close() : popup.open() + } + + SyncButton + { + id: syncButton + onClicked: switchPopupState() outputDevice: connectedDevice } - Popup { + Popup + { + // TODO Change once updating to Qt5.10 - This property is already in 5.10 but is manually implemented until upgrade + property bool opened: false id: popup clip: true + closePolicy: Popup.CloseOnPressOutsideParent y: configurationSelector.height - UM.Theme.getSize("default_lining").height x: configurationSelector.width - width width: panelWidth - visible: panelVisible && connectedDevice != null + visible: opened padding: UM.Theme.getSize("default_lining").width - contentItem: ConfigurationListView { + transformOrigin: Popup.Top + contentItem: ConfigurationListView + { id: configList width: panelWidth - 2 * popup.padding outputDevice: connectedDevice } - background: Rectangle { + background: Rectangle + { color: UM.Theme.getColor("setting_control") border.color: UM.Theme.getColor("setting_control_border") } - } - - states: [ - // This adds a second state to the container where the rectangle is farther to the right - State { - name: "open" - PropertyChanges { - target: popup - height: configList.computedHeight - } - }, - State { - name: "closed" - PropertyChanges { - target: popup - height: 0 - } - } - ] - transitions: [ - // This adds a transition that defaults to applying to all state changes - Transition { + exit: Transition + { // This applies a default NumberAnimation to any changes a state change makes to x or y properties - NumberAnimation { properties: "height"; duration: 200; easing.type: Easing.InOutQuad; } + NumberAnimation { property: "visible"; duration: 75; } } - ] + enter: Transition + { + // This applies a default NumberAnimation to any changes a state change makes to x or y properties + NumberAnimation { property: "visible"; duration: 75; } + } + onClosed: opened = false + onOpened: opened = true + } } \ No newline at end of file diff --git a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml index f0394cc107..c292a792db 100644 --- a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml +++ b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml @@ -86,11 +86,6 @@ Button label: Label {} } - onClicked: - { - panelVisible = !panelVisible - } - Connections { target: outputDevice onUniqueConfigurationsChanged: { From e3dd7a449d396cadd97835cb531fe74dc0264b13 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 14 Mar 2018 16:09:59 +0100 Subject: [PATCH 327/446] CURA-5090 speedups by using qtimers on updating mostly visual elements --- cura/BuildVolume.py | 2 +- cura/CuraApplication.py | 15 +++++++++++--- cura/Machines/Models/MultiBuildPlateModel.py | 12 +++++++++-- cura/ObjectsModel.py | 17 ++++++++++++++-- cura/Scene/ConvexHullDecorator.py | 21 +++++++++++++++++++- plugins/SimulationView/SimulationView.py | 7 ++++--- 6 files changed, 62 insertions(+), 12 deletions(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 0b81a5183f..d93ce1107d 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -136,6 +136,7 @@ class BuildVolume(SceneNode): if active_extruder_changed is not None: node.callDecoration("getActiveExtruderChangedSignal").disconnect(self._updateDisallowedAreasAndRebuild) node.decoratorsChanged.disconnect(self._updateNodeListeners) + self._updateDisallowedAreasAndRebuild() # make sure we didn't miss anything before we updated the node listeners self._scene_objects = new_scene_objects self._onSettingPropertyChanged("print_sequence", "value") # Create fake event, so right settings are triggered. @@ -150,7 +151,6 @@ class BuildVolume(SceneNode): active_extruder_changed = node.callDecoration("getActiveExtruderChangedSignal") if active_extruder_changed is not None: active_extruder_changed.connect(self._updateDisallowedAreasAndRebuild) - self._updateDisallowedAreasAndRebuild() def setWidth(self, width): if width is not None: diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 84ec787cd7..99cc30a12b 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -4,7 +4,7 @@ #Type hinting. from typing import Dict -from PyQt5.QtCore import QObject +from PyQt5.QtCore import QObject, QTimer from PyQt5.QtNetwork import QLocalServer from PyQt5.QtNetwork import QLocalSocket @@ -283,10 +283,15 @@ class CuraApplication(QtApplication): self._preferred_mimetype = "" self._i18n_catalog = i18nCatalog("cura") - self.getController().getScene().sceneChanged.connect(self.updatePlatformActivity) + self._update_platform_activity_timer = QTimer() + self._update_platform_activity_timer.setInterval(500) + self._update_platform_activity_timer.setSingleShot(True) + self._update_platform_activity_timer.timeout.connect(self.updatePlatformActivity) + + self.getController().getScene().sceneChanged.connect(self.updatePlatformActivityDelayed) self.getController().toolOperationStopped.connect(self._onToolOperationStopped) self.getController().contextMenuRequested.connect(self._onContextMenuRequested) - self.getCuraSceneController().activeBuildPlateChanged.connect(self.updatePlatformActivity) + self.getCuraSceneController().activeBuildPlateChanged.connect(self.updatePlatformActivityDelayed) Resources.addType(self.ResourceTypes.QmlFiles, "qml") Resources.addType(self.ResourceTypes.Firmware, "firmware") @@ -1061,6 +1066,10 @@ class CuraApplication(QtApplication): def getSceneBoundingBoxString(self): return self._i18n_catalog.i18nc("@info 'width', 'depth' and 'height' are variable names that must NOT be translated; just translate the format of ##x##x## mm.", "%(width).1f x %(depth).1f x %(height).1f mm") % {'width' : self._scene_bounding_box.width.item(), 'depth': self._scene_bounding_box.depth.item(), 'height' : self._scene_bounding_box.height.item()} + def updatePlatformActivityDelayed(self, node = None): + if node is not None and node.getMeshData() is not None: + self._update_platform_activity_timer.start() + ## Update scene bounding box for current build plate def updatePlatformActivity(self, node = None): count = 0 diff --git a/cura/Machines/Models/MultiBuildPlateModel.py b/cura/Machines/Models/MultiBuildPlateModel.py index f0f4997014..958e93837a 100644 --- a/cura/Machines/Models/MultiBuildPlateModel.py +++ b/cura/Machines/Models/MultiBuildPlateModel.py @@ -1,7 +1,7 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from PyQt5.QtCore import pyqtSignal, pyqtProperty +from PyQt5.QtCore import QTimer, pyqtSignal, pyqtProperty from UM.Application import Application from UM.Scene.Selection import Selection @@ -21,8 +21,13 @@ class MultiBuildPlateModel(ListModel): def __init__(self, parent = None): super().__init__(parent) + self._update_timer = QTimer() + self._update_timer.setInterval(100) + self._update_timer.setSingleShot(True) + self._update_timer.timeout.connect(self._updateSelectedObjectBuildPlateNumbers) + self._application = Application.getInstance() - self._application.getController().getScene().sceneChanged.connect(self._updateSelectedObjectBuildPlateNumbers) + self._application.getController().getScene().sceneChanged.connect(self._updateSelectedObjectBuildPlateNumbersDelayed) Selection.selectionChanged.connect(self._updateSelectedObjectBuildPlateNumbers) self._max_build_plate = 1 # default @@ -45,6 +50,9 @@ class MultiBuildPlateModel(ListModel): def activeBuildPlate(self): return self._active_build_plate + def _updateSelectedObjectBuildPlateNumbersDelayed(self, *args): + self._update_timer.start() + def _updateSelectedObjectBuildPlateNumbers(self, *args): result = set() for node in Selection.getAllSelectedObjects(): diff --git a/cura/ObjectsModel.py b/cura/ObjectsModel.py index f02e8b4db5..cfe4320e28 100644 --- a/cura/ObjectsModel.py +++ b/cura/ObjectsModel.py @@ -1,3 +1,8 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from PyQt5.QtCore import QTimer + from UM.Application import Application from UM.Qt.ListModel import ListModel from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator @@ -14,8 +19,13 @@ class ObjectsModel(ListModel): def __init__(self): super().__init__() - Application.getInstance().getController().getScene().sceneChanged.connect(self._update) - Preferences.getInstance().preferenceChanged.connect(self._update) + Application.getInstance().getController().getScene().sceneChanged.connect(self._updateDelayed) + Preferences.getInstance().preferenceChanged.connect(self._updateDelayed) + + self._update_timer = QTimer() + self._update_timer.setInterval(100) + self._update_timer.setSingleShot(True) + self._update_timer.timeout.connect(self._update) self._build_plate_number = -1 @@ -23,6 +33,9 @@ class ObjectsModel(ListModel): self._build_plate_number = nr self._update() + def _updateDelayed(self, *args): + self._update_timer.start() + def _update(self, *args): nodes = [] filter_current_build_plate = Preferences.getInstance().getValue("view/filter_current_build_plate") diff --git a/cura/Scene/ConvexHullDecorator.py b/cura/Scene/ConvexHullDecorator.py index 3a563c2764..66bc8a7fc3 100644 --- a/cura/Scene/ConvexHullDecorator.py +++ b/cura/Scene/ConvexHullDecorator.py @@ -1,6 +1,8 @@ # Copyright (c) 2016 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from PyQt5.QtCore import QTimer + from UM.Application import Application from UM.Math.Polygon import Polygon from UM.Scene.SceneNodeDecorator import SceneNodeDecorator @@ -22,6 +24,10 @@ class ConvexHullDecorator(SceneNodeDecorator): self._global_stack = None + # Make sure the timer is created on the main thread + self._recompute_convex_hull_timer = None + Application.getInstance().callLater(self.createRecomputeConvexHullTimer) + self._raft_thickness = 0.0 # For raft thickness, DRY self._build_volume = Application.getInstance().getBuildVolume() @@ -33,6 +39,12 @@ class ConvexHullDecorator(SceneNodeDecorator): self._onGlobalStackChanged() + def createRecomputeConvexHullTimer(self): + self._recompute_convex_hull_timer = QTimer() + self._recompute_convex_hull_timer.setInterval(200) + self._recompute_convex_hull_timer.setSingleShot(True) + self._recompute_convex_hull_timer.timeout.connect(self.recomputeConvexHull) + def setNode(self, node): previous_node = self._node # Disconnect from previous node signals @@ -99,6 +111,12 @@ class ConvexHullDecorator(SceneNodeDecorator): return self._compute2DConvexHull() return None + def recomputeConvexHullDelayed(self): + if self._recompute_convex_hull_timer is not None: + self._recompute_convex_hull_timer.start() + else: + self.recomputeConvexHull() + def recomputeConvexHull(self): controller = Application.getInstance().getController() root = controller.getScene().getRoot() @@ -279,7 +297,8 @@ class ConvexHullDecorator(SceneNodeDecorator): def _onChanged(self, *args): self._raft_thickness = self._build_volume.getRaftThickness() - self.recomputeConvexHull() + if not args or args[0] == self._node: + self.recomputeConvexHullDelayed() def _onGlobalStackChanged(self): if self._global_stack: diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 35ce9cc37a..5c3dca9fae 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -158,9 +158,10 @@ class SimulationView(View): return self._nozzle_node def _onSceneChanged(self, node): - self.setActivity(False) - self.calculateMaxLayers() - self.calculateMaxPathsOnLayer(self._current_layer_num) + if node.getMeshData() is not None: + self.setActivity(False) + self.calculateMaxLayers() + self.calculateMaxPathsOnLayer(self._current_layer_num) def isBusy(self): return self._busy From 6909c9263a050010f1f69a5b66930ad50641ce4c Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 14 Mar 2018 16:32:53 +0100 Subject: [PATCH 328/446] CURA-4400 fix setting extruder number on a group printed with mixed extruders --- cura/CuraActions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cura/CuraActions.py b/cura/CuraActions.py index f517ec4217..75338f17b6 100644 --- a/cura/CuraActions.py +++ b/cura/CuraActions.py @@ -109,10 +109,6 @@ class CuraActions(QObject): nodes_to_change = [] for node in Selection.getAllSelectedObjects(): - # Do not change any nodes that already have the right extruder set. - if node.callDecoration("getActiveExtruder") == extruder_id: - continue - # If the node is a group, apply the active extruder to all children of the group. if node.callDecoration("isGroup"): for grouped_node in BreadthFirstIterator(node): @@ -125,6 +121,10 @@ class CuraActions(QObject): nodes_to_change.append(grouped_node) continue + # Do not change any nodes that already have the right extruder set. + if node.callDecoration("getActiveExtruder") == extruder_id: + continue + nodes_to_change.append(node) if not nodes_to_change: From 2fdd51fc231cadb2c1ee8d6eacfccf2b1fd7c105 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 14 Mar 2018 16:47:01 +0100 Subject: [PATCH 329/446] CURA-4870 Bind the network information with the output devices changed signal. --- cura/Settings/MachineManager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 3af6f70e5f..c79d352dcb 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -467,13 +467,13 @@ class MachineManager(QObject): return self._global_container_stack.getId() return "" - @pyqtProperty(str, notify = globalContainerChanged) + @pyqtProperty(str, notify = outputDevicesChanged) def activeMachineNetworkKey(self) -> str: if self._global_container_stack: return self._global_container_stack.getMetaDataEntry("um_network_key") return "" - @pyqtProperty(str, notify = globalContainerChanged) + @pyqtProperty(str, notify = outputDevicesChanged) def activeMachineNetworkGroupName(self) -> str: if self._global_container_stack: return self._global_container_stack.getMetaDataEntry("connect_group_name") From e6c5bd28b2de4b4759cbd3e643882b927675a2e5 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 14 Mar 2018 16:53:51 +0100 Subject: [PATCH 330/446] CURA-4870 Use the visible property instead of a Qt5.10 existing 'opened' property. This is needed to avoid a crashing for those that are using 5.10 running from source. --- .../ConfigurationMenu/ConfigurationSelection.qml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml index a3cf10168b..d7ee2c68ee 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml @@ -16,7 +16,7 @@ Item function switchPopupState() { - popup.opened ? popup.close() : popup.open() + popup.visible ? popup.close() : popup.open() } SyncButton @@ -28,15 +28,14 @@ Item Popup { - // TODO Change once updating to Qt5.10 - This property is already in 5.10 but is manually implemented until upgrade - property bool opened: false + // TODO Change once updating to Qt5.10 - The 'opened' property is in 5.10 but the behavior is now implemented with the visible property id: popup clip: true closePolicy: Popup.CloseOnPressOutsideParent y: configurationSelector.height - UM.Theme.getSize("default_lining").height x: configurationSelector.width - width width: panelWidth - visible: opened + visible: false padding: UM.Theme.getSize("default_lining").width transformOrigin: Popup.Top contentItem: ConfigurationListView @@ -60,7 +59,7 @@ Item // This applies a default NumberAnimation to any changes a state change makes to x or y properties NumberAnimation { property: "visible"; duration: 75; } } - onClosed: opened = false - onOpened: opened = true + onClosed: visible = false + onOpened: visible = true } } \ No newline at end of file From 1cf832653ce5012de855bc2e3d5833c968ecf7a6 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 14 Mar 2018 17:00:39 +0100 Subject: [PATCH 331/446] CURA-4870 Make the configuration selector only available for network printers. Show the connection icon also for printers connected via USB or Octoprint. --- resources/qml/MachineSelection.qml | 37 +++++++++++++++--------------- resources/qml/Sidebar.qml | 8 ++++--- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/resources/qml/MachineSelection.qml b/resources/qml/MachineSelection.qml index b3f9629703..357e7870a7 100644 --- a/resources/qml/MachineSelection.qml +++ b/resources/qml/MachineSelection.qml @@ -10,17 +10,22 @@ import UM 1.2 as UM import Cura 1.0 as Cura import "Menus" -ToolButton { +ToolButton +{ id: base property bool isNetworkPrinter: Cura.MachineManager.activeMachineNetworkKey != "" + property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0 property var printerStatus: Cura.MachineManager.printerOutputDevices.length != 0 ? "connected" : "disconnected" text: isNetworkPrinter ? Cura.MachineManager.activeMachineNetworkGroupName : Cura.MachineManager.activeMachineName tooltip: Cura.MachineManager.activeMachineName - style: ButtonStyle { - background: Rectangle { - color: { + style: ButtonStyle + { + background: Rectangle + { + color: + { if (control.pressed) { return UM.Theme.getColor("sidebar_header_active"); } @@ -33,7 +38,8 @@ ToolButton { } Behavior on color { ColorAnimation { duration: 50; } } - UM.RecolorImage { + UM.RecolorImage + { id: downArrow anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right @@ -46,18 +52,21 @@ ToolButton { source: UM.Theme.getIcon("arrow_bottom") } - PrinterStatusIcon { + PrinterStatusIcon + { id: printerStatusIcon - visible: isNetworkPrinter + visible: printerConnected status: printerStatus - anchors { + anchors + { verticalCenter: parent.verticalCenter left: parent.left leftMargin: UM.Theme.getSize("sidebar_margin").width } } - Label { + Label + { id: sidebarComboBoxLabel color: UM.Theme.getColor("sidebar_header_text_active") text: control.text; @@ -74,14 +83,4 @@ ToolButton { } menu: PrinterMenu { } - - // Make the toolbutton react when the outputdevice changes - Connections - { - target: Cura.MachineManager - onOutputDevicesChanged: - { - base.isNetworkPrinter = Cura.MachineManager.activeMachineNetworkKey != "" - } - } } diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml index 5211ee5a1d..4744bbfda0 100644 --- a/resources/qml/Sidebar.qml +++ b/resources/qml/Sidebar.qml @@ -87,7 +87,8 @@ Rectangle } } - MachineSelection { + MachineSelection + { id: machineSelection width: base.width - configSelection.width - separator.width height: UM.Theme.getSize("sidebar_header").height @@ -105,9 +106,10 @@ Rectangle anchors.left: machineSelection.right } - ConfigurationSelection { + ConfigurationSelection + { id: configSelection - visible: isNetworkPrinter && !sidebar.monitoringPrint && !sidebar.hideSettings + visible: isNetworkPrinter width: visible ? Math.round(base.width * 0.15) : 0 height: UM.Theme.getSize("sidebar_header").height anchors.top: base.top From e4a416258b96c2927adba04d0c8ffd89abc3a8a7 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 15 Mar 2018 09:03:50 +0100 Subject: [PATCH 332/446] Fix code-style and type hinting --- cura/PickingPass.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cura/PickingPass.py b/cura/PickingPass.py index 4bd893e926..2a1abe8f63 100644 --- a/cura/PickingPass.py +++ b/cura/PickingPass.py @@ -24,7 +24,6 @@ class PickingPass(RenderPass): self._shader = None self._scene = Application.getInstance().getController().getScene() - def render(self) -> None: if not self._shader: self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "camera_distance.shader")) @@ -47,7 +46,7 @@ class PickingPass(RenderPass): self.release() ## Get the distance in mm from the camera to at a certain pixel coordinate. - def getPickedDepth(self, x, y) -> float: + def getPickedDepth(self, x: int, y: int) -> float: output = self.getOutput() window_size = self._renderer.getWindowSize() @@ -56,14 +55,14 @@ class PickingPass(RenderPass): py = (0.5 + y / 2.0) * window_size[1] if px < 0 or px > (output.width() - 1) or py < 0 or py > (output.height() - 1): - return None + return -1 distance = output.pixel(px, py) # distance in micron, from in r, g & b channels distance = (distance & 0x00ffffff) / 1000. # drop the alpha channel and covert to mm return distance ## Get the world coordinates of a picked point - def getPickedPosition(self, x, y) -> Vector: + def getPickedPosition(self, x: int, y: int) -> Vector: distance = self.getPickedDepth(x, y) ray = self._scene.getActiveCamera().getRay(x, y) From a477b8cdc245b6f0f6572997a7c126031d100bdd Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 15 Mar 2018 09:57:46 +0100 Subject: [PATCH 333/446] Fix malyan m180 definitions CURA-4696 --- resources/definitions/malyan_m180.def.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/definitions/malyan_m180.def.json b/resources/definitions/malyan_m180.def.json index c1a424f0c9..11b61328ed 100644 --- a/resources/definitions/malyan_m180.def.json +++ b/resources/definitions/malyan_m180.def.json @@ -38,16 +38,16 @@ "machine_max_feedrate_z": { "default_value": 400 }, - "steps_per_mm_x": { + "machine_steps_per_mm_x": { "default_value": 93 }, - "steps_per_mm_y": { + "machine_steps_per_mm_y": { "default_value": 93 }, - "steps_per_mm_z": { + "machine_steps_per_mm_z": { "default_value": 1600 }, - "steps_per_mm_e": { + "machine_steps_per_mm_e": { "default_value": 92 }, "gantry_height": { From 0155a20994daedf9acf12080ba82a0c879e2ca23 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Thu, 15 Mar 2018 10:33:06 +0100 Subject: [PATCH 334/446] CURA-4870 Fix visibility in the status icon --- resources/qml/MachineSelection.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/MachineSelection.qml b/resources/qml/MachineSelection.qml index 357e7870a7..b959e20bb7 100644 --- a/resources/qml/MachineSelection.qml +++ b/resources/qml/MachineSelection.qml @@ -55,7 +55,7 @@ ToolButton PrinterStatusIcon { id: printerStatusIcon - visible: printerConnected + visible: printerConnected || isNetworkPrinter status: printerStatus anchors { From 496c8f2f7911af896de05728711f2f9ae25a1e92 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 15 Mar 2018 10:43:05 +0100 Subject: [PATCH 335/446] Cleanup MachineManagementModel --- .../Machines/Models/MachineManagementModel.py | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/cura/Machines/Models/MachineManagementModel.py b/cura/Machines/Models/MachineManagementModel.py index 481a692675..7dc51f07f7 100644 --- a/cura/Machines/Models/MachineManagementModel.py +++ b/cura/Machines/Models/MachineManagementModel.py @@ -3,7 +3,7 @@ from UM.Qt.ListModel import ListModel -from PyQt5.QtCore import pyqtSlot, pyqtProperty, Qt, pyqtSignal +from PyQt5.QtCore import Qt from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.ContainerStack import ContainerStack @@ -11,6 +11,7 @@ from UM.Settings.ContainerStack import ContainerStack from UM.i18n import i18nCatalog catalog = i18nCatalog("cura") + # # This the QML model for the quality management page. # @@ -39,7 +40,7 @@ class MachineManagementModel(ListModel): ## Handler for container added/removed events from registry def _onContainerChanged(self, container): # We only need to update when the added / removed container is a stack. - if isinstance(container, ContainerStack): + if isinstance(container, ContainerStack) and container.getMetaDataEntry("type") == "machine": self._update() ## Private convenience function to reset & repopulate the model. @@ -47,7 +48,9 @@ class MachineManagementModel(ListModel): items = [] # Get first the network enabled printers - network_filter_printers = {"type": "machine", "um_network_key": "*", "hidden": "False"} + network_filter_printers = {"type": "machine", + "um_network_key": "*", + "hidden": "False"} self._network_container_stacks = ContainerRegistry.getInstance().findContainerStacks(**network_filter_printers) self._network_container_stacks.sort(key = lambda i: i.getMetaDataEntry("connect_group_name")) @@ -57,11 +60,11 @@ class MachineManagementModel(ListModel): metadata["definition_name"] = container.getBottom().getName() items.append({"name": metadata["connect_group_name"], - "id": container.getId(), - "metadata": metadata, - "group": catalog.i18nc("@info:title", "Network enabled printers")}) + "id": container.getId(), + "metadata": metadata, + "group": catalog.i18nc("@info:title", "Network enabled printers")}) - # Get now the local printes + # Get now the local printers local_filter_printers = {"type": "machine", "um_network_key": None} self._local_container_stacks = ContainerRegistry.getInstance().findContainerStacks(**local_filter_printers) self._local_container_stacks.sort(key = lambda i: i.getName()) @@ -72,8 +75,8 @@ class MachineManagementModel(ListModel): metadata["definition_name"] = container.getBottom().getName() items.append({"name": container.getName(), - "id": container.getId(), - "metadata": metadata, - "group": catalog.i18nc("@info:title", "Local printers")}) + "id": container.getId(), + "metadata": metadata, + "group": catalog.i18nc("@info:title", "Local printers")}) self.setItems(items) From 15ff4045bf6957cd0b38b55dc7a09000165c7613 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Thu, 15 Mar 2018 11:02:29 +0100 Subject: [PATCH 336/446] CURA-4870 When removing a network connected printer, also remove all the other machines that were (possibly) created in the background so that there is no orphan containers. --- cura/Settings/MachineManager.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index c79d352dcb..100c7c3c31 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -470,13 +470,13 @@ class MachineManager(QObject): @pyqtProperty(str, notify = outputDevicesChanged) def activeMachineNetworkKey(self) -> str: if self._global_container_stack: - return self._global_container_stack.getMetaDataEntry("um_network_key") + return self._global_container_stack.getMetaDataEntry("um_network_key", "") return "" @pyqtProperty(str, notify = outputDevicesChanged) def activeMachineNetworkGroupName(self) -> str: if self._global_container_stack: - return self._global_container_stack.getMetaDataEntry("connect_group_name") + return self._global_container_stack.getMetaDataEntry("connect_group_name", "") return "" @pyqtProperty(QObject, notify = globalContainerChanged) @@ -662,12 +662,22 @@ class MachineManager(QObject): if other_machine_stacks: self.setActiveMachine(other_machine_stacks[0]["id"]) + metadata = ContainerRegistry.getInstance().findContainerStacksMetadata(id = machine_id)[0] + network_key = metadata["um_network_key"] if "um_network_key" in metadata else None ExtruderManager.getInstance().removeMachineExtruders(machine_id) containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(type = "user", machine = machine_id) for container in containers: ContainerRegistry.getInstance().removeContainer(container["id"]) ContainerRegistry.getInstance().removeContainer(machine_id) + # If the printer that is being removed is a network printer, the hidden printers have to be also removed + if network_key: + metadata_filter = {"um_network_key": network_key} + hidden_containers = ContainerRegistry.getInstance().findContainerStacks(type = "machine", **metadata_filter) + if hidden_containers: + # This reuses the method and remove all printers recursively + self.removeMachine(hidden_containers[0].getId()) + @pyqtProperty(bool, notify = globalContainerChanged) def hasMaterials(self) -> bool: if self._global_container_stack: From dee70f35f4f3a228d00c3a40a6dd643693f3a1bd Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 15 Mar 2018 11:03:27 +0100 Subject: [PATCH 337/446] Fix setting visibility when searching --- .../PerObjectSettingsPanel.qml | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index 7872908ee8..a2790dcf08 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -384,7 +384,6 @@ Item { title: catalog.i18nc("@title:window", "Select Settings to Customize for this model") width: screenScaleFactor * 360 - property string labelFilter: "" property var additional_excluded_settings onVisibilityChanged: @@ -395,11 +394,33 @@ Item { // Set skip setting, it will prevent from resetting selected mesh_type contents.model.visibilityHandler.addSkipResetSetting(meshTypeSelection.model.get(meshTypeSelection.currentIndex).type) listview.model.forceUpdate() + + updateFilter() } } + function updateFilter() + { + var new_filter = {}; + if (printSequencePropertyProvider.properties.value == "one_at_a_time") + { + new_filter["settable_per_meshgroup"] = true; + } + else + { + new_filter["settable_per_mesh"] = true; + } + + if(filterInput.text != "") + { + new_filter["i18n_label"] = "*" + filterInput.text; + } + + listview.model.filter = new_filter; + } + TextField { - id: filter + id: filterInput anchors { top: parent.top @@ -410,17 +431,7 @@ Item { placeholderText: catalog.i18nc("@label:textbox", "Filter..."); - onTextChanged: - { - if(text != "") - { - listview.model.filter = {"settable_per_mesh": true, "i18n_label": "*" + text} - } - else - { - listview.model.filter = {"settable_per_mesh": true} - } - } + onTextChanged: settingPickDialog.updateFilter() } CheckBox @@ -446,7 +457,7 @@ Item { anchors { - top: filter.bottom; + top: filterInput.bottom; left: parent.left; right: parent.right; bottom: parent.bottom; @@ -458,14 +469,6 @@ Item { { id: definitionsModel; containerId: Cura.MachineManager.activeDefinitionId - filter: - { - if (printSequencePropertyProvider.properties.value == "one_at_a_time") - { - return {"settable_per_meshgroup": true}; - } - return {"settable_per_mesh": true}; - } visibilityHandler: UM.SettingPreferenceVisibilityHandler {} expanded: [ "*" ] exclude: @@ -497,6 +500,7 @@ Item { } } } + Component.onCompleted: settingPickDialog.updateFilter() } } From 584f98cb071cc140d4fa9dd299f5820796d27a50 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 15 Mar 2018 11:27:48 +0100 Subject: [PATCH 338/446] Fix code style --- cura/PrinterOutput/ExtruderOutputModel.py | 3 ++- cura/PrinterOutput/GenericOutputController.py | 3 --- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/cura/PrinterOutput/ExtruderOutputModel.py b/cura/PrinterOutput/ExtruderOutputModel.py index 92b3ad6d7c..75b9cc98ac 100644 --- a/cura/PrinterOutput/ExtruderOutputModel.py +++ b/cura/PrinterOutput/ExtruderOutputModel.py @@ -20,7 +20,7 @@ class ExtruderOutputModel(QObject): extruderConfigurationChanged = pyqtSignal() isPreheatingChanged = pyqtSignal() - def __init__(self, printer: "PrinterOutputModel", position: int, parent=None): + def __init__(self, printer: "PrinterOutputModel", position, parent=None): super().__init__(parent) self._printer = printer self._position = position @@ -98,6 +98,7 @@ class ExtruderOutputModel(QObject): if self._extruder_configuration.isValid(): return self._extruder_configuration return None + def updateIsPreheating(self, pre_heating): if self._is_preheating != pre_heating: self._is_preheating = pre_heating diff --git a/cura/PrinterOutput/GenericOutputController.py b/cura/PrinterOutput/GenericOutputController.py index 106c1e3a44..a21425af92 100644 --- a/cura/PrinterOutput/GenericOutputController.py +++ b/cura/PrinterOutput/GenericOutputController.py @@ -52,7 +52,6 @@ class GenericOutputController(PrinterOutputController): extruder.updateIsPreheating(False) self._preheat_hotends = set() - def moveHead(self, printer: "PrinterOutputModel", x, y, z, speed): self._output_device.sendCommand("G91") self._output_device.sendCommand("G0 X%s Y%s Z%s F%s" % (x, y, z, speed)) @@ -76,7 +75,6 @@ class GenericOutputController(PrinterOutputController): self._output_device.cancelPrint() pass - def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int): self._output_device.sendCommand("M140 S%s" % temperature) @@ -107,7 +105,6 @@ class GenericOutputController(PrinterOutputController): self.setTargetBedTemperature(self._preheat_printer, 0) self._preheat_printer.updateIsPreheating(False) - def setTargetHotendTemperature(self, printer: "PrinterOutputModel", position: int, temperature: int): self._output_device.sendCommand("M104 S%s T%s" % (temperature, position)) From c25711797e6ccb9d7924ea7c724c5a40529dcf9f Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 15 Mar 2018 12:46:22 +0100 Subject: [PATCH 339/446] Click support eraser mesh to remove it from the scene --- plugins/SupportEraser/SupportEraser.py | 27 +++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/plugins/SupportEraser/SupportEraser.py b/plugins/SupportEraser/SupportEraser.py index 65d22bcdfd..bbb3fefca5 100644 --- a/plugins/SupportEraser/SupportEraser.py +++ b/plugins/SupportEraser/SupportEraser.py @@ -7,6 +7,7 @@ from UM.Application import Application from UM.Event import Event, MouseEvent from UM.Mesh.MeshBuilder import MeshBuilder from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation +from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation from UM.Settings.SettingInstance import SettingInstance from cura.Scene.CuraSceneNode import CuraSceneNode from cura.Scene.SliceableObjectDecorator import SliceableObjectDecorator @@ -24,24 +25,39 @@ class SupportEraser(Tool): self._shortcut_key = Qt.Key_G self._controller = Application.getInstance().getController() + self._selection_pass = None Application.getInstance().globalContainerStackChanged.connect(self._updateEnabled) def event(self, event): super().event(event) if event.type == Event.MousePressEvent and self._controller.getToolsEnabled(): - active_camera = self._controller.getScene().getActiveCamera() + + if self._selection_pass is None: + # The selection renderpass is used to identify objects in the current view + self._selection_pass = Application.getInstance().getRenderer().getRenderPass("selection") + picked_node = self._controller.getScene().findObject(self._selection_pass.getIdAtPosition(event.x, event.y)) + + node_stack = picked_node.callDecoration("getStack") + if node_stack: + if node_stack.getProperty("anti_overhang_mesh", "value"): + self._removeEraserMesh(picked_node) + return + + elif node_stack.getProperty("support_mesh", "value") or node_stack.getProperty("infill_mesh", "value") or node_stack.getProperty("cutting_mesh", "value"): + return # Create a pass for picking a world-space location from the mouse location + active_camera = self._controller.getScene().getActiveCamera() picking_pass = PickingPass(active_camera.getViewportWidth(), active_camera.getViewportHeight()) picking_pass.render() picked_position = picking_pass.getPickedPosition(event.x, event.y) # Add the anti_overhang_mesh cube at the picked location - self._createEraserMesh(picked_position) + self._createEraserMesh(picked_node, picked_position) - def _createEraserMesh(self, position: Vector): + def _createEraserMesh(self, parent: CuraSceneNode, position: Vector): node = CuraSceneNode() node.setName("Eraser") @@ -76,6 +92,11 @@ class SupportEraser(Tool): op.push() Application.getInstance().getController().getScene().sceneChanged.emit(node) + def _removeEraserMesh(self, node: CuraSceneNode): + op = RemoveSceneNodeOperation(node) + op.push() + Application.getInstance().getController().getScene().sceneChanged.emit(node) + def _updateEnabled(self): plugin_enabled = False From a0c44192da1f1455d7ba8b564d95676d369cdb17 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 15 Mar 2018 14:17:59 +0100 Subject: [PATCH 340/446] Add support eraser meshes to group so it does not drop --- plugins/SupportEraser/SupportEraser.py | 82 +++++++++++++++++--------- 1 file changed, 54 insertions(+), 28 deletions(-) diff --git a/plugins/SupportEraser/SupportEraser.py b/plugins/SupportEraser/SupportEraser.py index bbb3fefca5..8f8e9deb52 100644 --- a/plugins/SupportEraser/SupportEraser.py +++ b/plugins/SupportEraser/SupportEraser.py @@ -1,24 +1,35 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from UM.Math.Vector import Vector -from UM.Tool import Tool -from PyQt5.QtCore import Qt, QUrl -from UM.Application import Application -from UM.Event import Event, MouseEvent -from UM.Mesh.MeshBuilder import MeshBuilder -from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation -from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation -from UM.Settings.SettingInstance import SettingInstance -from cura.Scene.CuraSceneNode import CuraSceneNode -from cura.Scene.SliceableObjectDecorator import SliceableObjectDecorator -from cura.Scene.BuildPlateDecorator import BuildPlateDecorator -from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator -from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator -from cura.PickingPass import PickingPass import os import os.path +from PyQt5.QtCore import Qt, QUrl + +from UM.Math.Vector import Vector +from UM.Tool import Tool +from UM.Application import Application +from UM.Event import Event, MouseEvent + +from UM.Mesh.MeshBuilder import MeshBuilder +from UM.Scene.Selection import Selection +from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator +from cura.Scene.CuraSceneNode import CuraSceneNode + +from cura.PickingPass import PickingPass + +from UM.Operations.GroupedOperation import GroupedOperation +from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation +from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation +from cura.Operations.SetParentOperation import SetParentOperation + +from cura.Scene.SliceableObjectDecorator import SliceableObjectDecorator +from cura.Scene.BuildPlateDecorator import BuildPlateDecorator +from UM.Scene.GroupDecorator import GroupDecorator +from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator + +from UM.Settings.SettingInstance import SettingInstance + class SupportEraser(Tool): def __init__(self): super().__init__() @@ -45,6 +56,7 @@ class SupportEraser(Tool): return elif node_stack.getProperty("support_mesh", "value") or node_stack.getProperty("infill_mesh", "value") or node_stack.getProperty("cutting_mesh", "value"): + # Only "normal" meshes can have anti_overhang_meshes added to them return # Create a pass for picking a world-space location from the mouse location @@ -73,22 +85,36 @@ class SupportEraser(Tool): node.addDecorator(BuildPlateDecorator(active_build_plate)) node.addDecorator(SliceableObjectDecorator()) - stack = node.callDecoration("getStack") #Don't try to get the active extruder since it may be None anyway. - if not stack: - node.addDecorator(SettingOverrideDecorator()) - stack = node.callDecoration("getStack") - + stack = node.callDecoration("getStack") # created by SettingOverrideDecorator settings = stack.getTop() - if not (settings.getInstance("anti_overhang_mesh") and settings.getProperty("anti_overhang_mesh", "value")): - definition = stack.getSettingDefinition("anti_overhang_mesh") - new_instance = SettingInstance(definition, settings) - new_instance.setProperty("value", True) - new_instance.resetState() # Ensure that the state is not seen as a user state. - settings.addInstance(new_instance) + definition = stack.getSettingDefinition("anti_overhang_mesh") + new_instance = SettingInstance(definition, settings) + new_instance.setProperty("value", True) + new_instance.resetState() # Ensure that the state is not seen as a user state. + settings.addInstance(new_instance) - scene = self._controller.getScene() - op = AddSceneNodeOperation(node, scene.getRoot()) + root = self._controller.getScene().getRoot() + + op = GroupedOperation() + # First add the node to the scene, so it gets the expected transform + op.addOperation(AddSceneNodeOperation(node, root)) + + # Determine the parent group the node should be put in + if parent.getParent().callDecoration("isGroup"): + group = parent.getParent() + else: + # Create a group-node + group = CuraSceneNode() + group.addDecorator(GroupDecorator()) + group.addDecorator(BuildPlateDecorator(active_build_plate)) + group.setParent(root) + center = parent.getPosition() + group.setPosition(center) + group.setCenterPosition(center) + op.addOperation(SetParentOperation(parent, group)) + + op.addOperation(SetParentOperation(node, group)) op.push() Application.getInstance().getController().getScene().sceneChanged.emit(node) From 097c97b6f8640df7151fa47c5ca5e0e591e803a8 Mon Sep 17 00:00:00 2001 From: Aleksei S Date: Thu, 15 Mar 2018 14:33:27 +0100 Subject: [PATCH 341/446] Fix: Refresh list of available printers in network after clicking refresh button. --- plugins/UM3NetworkPrinting/UM3OutputDevicePlugin.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/UM3NetworkPrinting/UM3OutputDevicePlugin.py b/plugins/UM3NetworkPrinting/UM3OutputDevicePlugin.py index 5ff5eb9e3e..089b9038f7 100644 --- a/plugins/UM3NetworkPrinting/UM3OutputDevicePlugin.py +++ b/plugins/UM3NetworkPrinting/UM3OutputDevicePlugin.py @@ -82,6 +82,9 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): self._zero_conf_browser.cancel() self._zero_conf_browser = None # Force the old ServiceBrowser to be destroyed. + for instance_name in list(self._discovered_devices): + self._onRemoveDevice(instance_name) + self._zero_conf = Zeroconf() self._zero_conf_browser = ServiceBrowser(self._zero_conf, u'_ultimaker._tcp.local.', [self._appendServiceChangedRequest]) From 1f2602a2f4c32447b421d7de4e43b59544639361 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 15 Mar 2018 10:41:50 +0100 Subject: [PATCH 342/446] Move SettingVisibilityPresetsModel to Machines.Models CURA-5088 --- cura/CuraApplication.py | 6 +----- .../Models}/SettingVisibilityPresetsModel.py | 0 2 files changed, 1 insertion(+), 5 deletions(-) rename cura/{Settings => Machines/Models}/SettingVisibilityPresetsModel.py (100%) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index b7731c5c8c..243bb2eb8a 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1,9 +1,6 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -#Type hinting. -from typing import Dict - from PyQt5.QtCore import QObject, QTimer from PyQt5.QtNetwork import QLocalServer from PyQt5.QtNetwork import QLocalSocket @@ -91,7 +88,7 @@ from cura.Settings.UserChangesModel import UserChangesModel from cura.Settings.ExtrudersModel import ExtrudersModel from cura.Settings.MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler from cura.Settings.ContainerManager import ContainerManager -from cura.Settings.SettingVisibilityPresetsModel import SettingVisibilityPresetsModel +from cura.Machines.Models.SettingVisibilityPresetsModel import SettingVisibilityPresetsModel from cura.ObjectsModel import ObjectsModel @@ -101,7 +98,6 @@ from PyQt5.QtGui import QColor, QIcon from PyQt5.QtWidgets import QMessageBox from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qmlRegisterType -from configparser import ConfigParser import sys import os.path import numpy diff --git a/cura/Settings/SettingVisibilityPresetsModel.py b/cura/Machines/Models/SettingVisibilityPresetsModel.py similarity index 100% rename from cura/Settings/SettingVisibilityPresetsModel.py rename to cura/Machines/Models/SettingVisibilityPresetsModel.py From 83175b00c282a6f63943522ff70e7447775b74f1 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 15 Mar 2018 10:59:23 +0100 Subject: [PATCH 343/446] Change SettingVisibilityPresetsModel to non-singleton CURA-5088 --- cura/CuraApplication.py | 19 +++++++++++++------ .../Models/SettingVisibilityPresetsModel.py | 16 ---------------- .../Menus/SettingVisibilityPresetsMenu.qml | 11 ++++++----- .../qml/Preferences/SettingVisibilityPage.qml | 17 +++++++++-------- resources/qml/Settings/SettingView.qml | 11 ++++++----- 5 files changed, 34 insertions(+), 40 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 243bb2eb8a..1b5de89c2b 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -65,6 +65,8 @@ from cura.Machines.Models.QualityManagementModel import QualityManagementModel from cura.Machines.Models.QualitySettingsModel import QualitySettingsModel from cura.Machines.Models.MachineManagementModel import MachineManagementModel +from cura.Machines.Models.SettingVisibilityPresetsModel import SettingVisibilityPresetsModel + from cura.Machines.MachineErrorChecker import MachineErrorChecker from cura.Settings.SettingInheritanceManager import SettingInheritanceManager @@ -88,7 +90,6 @@ from cura.Settings.UserChangesModel import UserChangesModel from cura.Settings.ExtrudersModel import ExtrudersModel from cura.Settings.MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler from cura.Settings.ContainerManager import ContainerManager -from cura.Machines.Models.SettingVisibilityPresetsModel import SettingVisibilityPresetsModel from cura.ObjectsModel import ObjectsModel @@ -222,6 +223,7 @@ class CuraApplication(QtApplication): self._object_manager = None self._build_plate_model = None self._multi_build_plate_model = None + self._setting_visibility_presets_model = None self._setting_inheritance_manager = None self._simple_mode_settings_manager = None self._cura_scene_controller = None @@ -377,10 +379,6 @@ class CuraApplication(QtApplication): preferences.setDefault("local_file/last_used_type", "text/x-gcode") - default_visibility_profile = SettingVisibilityPresetsModel.getInstance().getItem(0) - - preferences.setDefault("general/visible_settings", ";".join(default_visibility_profile["settings"])) - self.applicationShuttingDown.connect(self.saveSettings) self.engineCreatedSignal.connect(self._onEngineCreated) @@ -683,6 +681,11 @@ class CuraApplication(QtApplication): self._print_information = PrintInformation.PrintInformation() self._cura_actions = CuraActions.CuraActions(self) + # Initialize setting visibility presets model + self._setting_visibility_presets_model = SettingVisibilityPresetsModel(self) + default_visibility_profile = self._setting_visibility_presets_model.getItem(0) + Preferences.getInstance().setDefault("general/visible_settings", ";".join(default_visibility_profile["settings"])) + # Detect in which mode to run and execute that mode if self.getCommandLineOption("headless", False): self.runWithoutGUI() @@ -765,6 +768,10 @@ class CuraApplication(QtApplication): def hasGui(self): return self._use_gui + @pyqtSlot(result = QObject) + def getSettingVisibilityPresetsModel(self, *args) -> SettingVisibilityPresetsModel: + return self._setting_visibility_presets_model + def getMachineErrorChecker(self, *args) -> MachineErrorChecker: return self._machine_error_checker @@ -891,11 +898,11 @@ class CuraApplication(QtApplication): qmlRegisterType(NozzleModel, "Cura", 1, 0, "NozzleModel") qmlRegisterType(MaterialSettingsVisibilityHandler, "Cura", 1, 0, "MaterialSettingsVisibilityHandler") + qmlRegisterType(SettingVisibilityPresetsModel, "Cura", 1, 0, "SettingVisibilityPresetsModel") qmlRegisterType(QualitySettingsModel, "Cura", 1, 0, "QualitySettingsModel") qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator") qmlRegisterType(UserChangesModel, "Cura", 1, 0, "UserChangesModel") qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.createContainerManager) - qmlRegisterSingletonType(SettingVisibilityPresetsModel, "Cura", 1, 0, "SettingVisibilityPresetsModel", SettingVisibilityPresetsModel.createSettingVisibilityPresetsModel) # As of Qt5.7, it is necessary to get rid of any ".." in the path for the singleton to work. actions_url = QUrl.fromLocalFile(os.path.abspath(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml"))) diff --git a/cura/Machines/Models/SettingVisibilityPresetsModel.py b/cura/Machines/Models/SettingVisibilityPresetsModel.py index e5a2e24412..ace78ae093 100644 --- a/cura/Machines/Models/SettingVisibilityPresetsModel.py +++ b/cura/Machines/Models/SettingVisibilityPresetsModel.py @@ -118,19 +118,3 @@ class SettingVisibilityPresetsModel(ListModel): # Copy current visibility set to custom visibility set preference so it can be restored later visibility_string = self._preferences.getValue("general/visible_settings") self._preferences.setValue("cura/custom_visible_settings", visibility_string) - - - # Factory function, used by QML - @staticmethod - def createSettingVisibilityPresetsModel(engine, js_engine): - return SettingVisibilityPresetsModel.getInstance() - - ## Get the singleton instance for this class. - @classmethod - def getInstance(cls) -> "SettingVisibilityPresetsModel": - # Note: Explicit use of class name to prevent issues with inheritance. - if not SettingVisibilityPresetsModel.__instance: - SettingVisibilityPresetsModel.__instance = cls() - return SettingVisibilityPresetsModel.__instance - - __instance = None # type: "SettingVisibilityPresetsModel" \ No newline at end of file diff --git a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml index 19c36e6118..d39d65e96c 100644 --- a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml +++ b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml @@ -12,6 +12,7 @@ Menu id: menu title: catalog.i18nc("@action:inmenu", "Visible Settings") + property QtObject settingVisibilityPresetsModel: CuraApplication.getSettingVisibilityPresetsModel() property bool showingSearchResults property bool showingAllSettings @@ -22,11 +23,11 @@ Menu { text: catalog.i18nc("@action:inmenu", "Custom selection") checkable: true - checked: !showingSearchResults && !showingAllSettings && Cura.SettingVisibilityPresetsModel.activePreset == "custom" + checked: !showingSearchResults && !showingAllSettings && settingVisibilityPresetsModel.activePreset == "custom" exclusiveGroup: group onTriggered: { - Cura.SettingVisibilityPresetsModel.setActivePreset("custom"); + settingVisibilityPresetsModel.setActivePreset("custom"); // Restore custom set from preference UM.Preferences.setValue("general/visible_settings", UM.Preferences.getValue("cura/custom_visible_settings")); showSettingVisibilityProfile(); @@ -36,17 +37,17 @@ Menu Instantiator { - model: Cura.SettingVisibilityPresetsModel + model: settingVisibilityPresetsModel MenuItem { text: model.name checkable: true - checked: model.id == Cura.SettingVisibilityPresetsModel.activePreset + checked: model.id == settingVisibilityPresetsModel.activePreset exclusiveGroup: group onTriggered: { - Cura.SettingVisibilityPresetsModel.setActivePreset(model.id); + settingVisibilityPresetsModel.setActivePreset(model.id); UM.Preferences.setValue("general/visible_settings", model.settings.join(";")); diff --git a/resources/qml/Preferences/SettingVisibilityPage.qml b/resources/qml/Preferences/SettingVisibilityPage.qml index f0c24e2cbe..7f6a58367d 100644 --- a/resources/qml/Preferences/SettingVisibilityPage.qml +++ b/resources/qml/Preferences/SettingVisibilityPage.qml @@ -13,6 +13,8 @@ UM.PreferencesPage { title: catalog.i18nc("@title:tab", "Setting Visibility"); + property QtObject settingVisibilityPresetsModel: CuraApplication.getSettingVisibilityPresetsModel() + property int scrollToIndex: 0 signal scrollToSection( string key ) @@ -132,10 +134,9 @@ UM.PreferencesPage { visibilityPresetsModel.append({text: catalog.i18nc("@action:inmenu", "Custom selection"), id: "custom"}); - var presets = Cura.SettingVisibilityPresetsModel; - for(var i = 0; i < presets.rowCount(); i++) + for(var i = 0; i < settingVisibilityPresetsModel.rowCount(); i++) { - visibilityPresetsModel.append({text: presets.getItem(i)["name"], id: presets.getItem(i)["id"]}); + visibilityPresetsModel.append({text: settingVisibilityPresetsModel.getItem(i)["name"], id: settingVisibilityPresetsModel.getItem(i)["id"]}); } } } @@ -143,7 +144,7 @@ UM.PreferencesPage currentIndex: { // Load previously selected preset. - var index = Cura.SettingVisibilityPresetsModel.find("id", Cura.SettingVisibilityPresetsModel.activePreset); + var index = settingVisibilityPresetsModel.find("id", settingVisibilityPresetsModel.activePreset); if(index == -1) { return 0; @@ -156,12 +157,12 @@ UM.PreferencesPage { base.inhibitSwitchToCustom = true; var preset_id = visibilityPresetsModel.get(index).id; - Cura.SettingVisibilityPresetsModel.setActivePreset(preset_id); + settingVisibilityPresetsModel.setActivePreset(preset_id); UM.Preferences.setValue("cura/active_setting_visibility_preset", preset_id); if (preset_id != "custom") { - UM.Preferences.setValue("general/visible_settings", Cura.SettingVisibilityPresetsModel.getItem(index - 1).settings.join(";")); + UM.Preferences.setValue("general/visible_settings", settingVisibilityPresetsModel.getItem(index - 1).settings.join(";")); // "Custom selection" entry is added in front, so index is off by 1 } else @@ -203,9 +204,9 @@ UM.PreferencesPage { onVisibilityChanged: { - if(Cura.SettingVisibilityPresetsModel.activePreset != "" && !base.inhibitSwitchToCustom) + if(settingVisibilityPresetsModel.activePreset != "" && !base.inhibitSwitchToCustom) { - Cura.SettingVisibilityPresetsModel.setActivePreset("custom"); + settingVisibilityPresetsModel.setActivePreset("custom"); } } } diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 235dfac91a..a6d7b3a71e 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -15,6 +15,7 @@ Item { id: base; + property QtObject settingVisibilityPresetsModel: CuraApplication.getSettingVisibilityPresetsModel() property Action configureSettings property bool findingSettings property bool showingAllSettings @@ -562,9 +563,9 @@ Item { definitionsModel.hide(contextMenu.key); // visible settings have changed, so we're no longer showing a preset - if (Cura.SettingVisibilityPresetsModel.activePreset != "" && !showingAllSettings) + if (settingVisibilityPresetsModel.activePreset != "" && !showingAllSettings) { - Cura.SettingVisibilityPresetsModel.setActivePreset("custom"); + settingVisibilityPresetsModel.setActivePreset("custom"); } } } @@ -594,16 +595,16 @@ Item definitionsModel.show(contextMenu.key); } // visible settings have changed, so we're no longer showing a preset - if (Cura.SettingVisibilityPresetsModel.activePreset != "" && !showingAllSettings) + if (settingVisibilityPresetsModel.activePreset != "" && !showingAllSettings) { - Cura.SettingVisibilityPresetsModel.setActivePreset("custom"); + settingVisibilityPresetsModel.setActivePreset("custom"); } } } MenuItem { //: Settings context menu action - text: catalog.i18nc("@action:menu", "Configure setting visiblity..."); + text: catalog.i18nc("@action:menu", "Configure setting visibility..."); onTriggered: Cura.Actions.configureSettingVisibility.trigger(contextMenu); } From 8e39849aadd34fcd93a37dffbdae837bd700ca21 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 15 Mar 2018 12:04:14 +0100 Subject: [PATCH 344/446] Refactor setting visibility preset CURA-5088 --- .../Models/SettingVisibilityPresetsModel.py | 140 ++++++++++++------ .../Menus/SettingVisibilityPresetsMenu.qml | 23 +-- .../qml/Preferences/SettingVisibilityPage.qml | 60 ++------ 3 files changed, 109 insertions(+), 114 deletions(-) diff --git a/cura/Machines/Models/SettingVisibilityPresetsModel.py b/cura/Machines/Models/SettingVisibilityPresetsModel.py index ace78ae093..e281d81c39 100644 --- a/cura/Machines/Models/SettingVisibilityPresetsModel.py +++ b/cura/Machines/Models/SettingVisibilityPresetsModel.py @@ -1,11 +1,12 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from typing import Optional import os -import urllib +import urllib.parse from configparser import ConfigParser -from PyQt5.QtCore import pyqtProperty, Qt, pyqtSignal, pyqtSlot, QUrl +from PyQt5.QtCore import pyqtProperty, Qt, pyqtSignal, pyqtSlot from UM.Logger import Logger from UM.Qt.ListModel import ListModel @@ -13,13 +14,14 @@ from UM.Preferences import Preferences from UM.Resources import Resources from UM.MimeTypeDatabase import MimeTypeDatabase, MimeTypeNotFoundError -import cura.CuraApplication +from UM.i18n import i18nCatalog +catalog = i18nCatalog("cura") class SettingVisibilityPresetsModel(ListModel): IdRole = Qt.UserRole + 1 NameRole = Qt.UserRole + 2 - SettingsRole = Qt.UserRole + 4 + SettingsRole = Qt.UserRole + 3 def __init__(self, parent = None): super().__init__(parent) @@ -28,39 +30,51 @@ class SettingVisibilityPresetsModel(ListModel): self.addRoleName(self.SettingsRole, "settings") self._populate() + basic_item = self.items[1] + basic_visibile_settings = ";".join(basic_item["settings"]) self._preferences = Preferences.getInstance() - self._preferences.addPreference("cura/active_setting_visibility_preset", "custom") # Preference to store which preset is currently selected - self._preferences.addPreference("cura/custom_visible_settings", "") # Preference that stores the "custom" set so it can always be restored (even after a restart) + # Preference to store which preset is currently selected + self._preferences.addPreference("cura/active_setting_visibility_preset", "basic") + # Preference that stores the "custom" set so it can always be restored (even after a restart) + self._preferences.addPreference("cura/custom_visible_settings", basic_visibile_settings) self._preferences.preferenceChanged.connect(self._onPreferencesChanged) - self._active_preset = self._preferences.getValue("cura/active_setting_visibility_preset") - if self.find("id", self._active_preset) < 0: - self._active_preset = "custom" + self._active_preset_item = self._getItem(self._preferences.getValue("cura/active_setting_visibility_preset")) + # Initialize visible settings if it is not done yet + visible_settings = self._preferences.getValue("general/visible_settings") + if not visible_settings: + self._preferences.setValue("general/visible_settings", ";".join(self._active_preset_item["settings"])) self.activePresetChanged.emit() + def _getItem(self, item_id: str) -> Optional[dict]: + result = None + for item in self.items: + if item["id"] == item_id: + result = item + break + return result def _populate(self): + from cura.CuraApplication import CuraApplication items = [] - for item in Resources.getAllResourcesOfType(cura.CuraApplication.CuraApplication.ResourceTypes.SettingVisibilityPreset): + for file_path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.SettingVisibilityPreset): try: - mime_type = MimeTypeDatabase.getMimeTypeForFile(item) + mime_type = MimeTypeDatabase.getMimeTypeForFile(file_path) except MimeTypeNotFoundError: - Logger.log("e", "Could not determine mime type of file %s", item) + Logger.log("e", "Could not determine mime type of file %s", file_path) continue - id = urllib.parse.unquote_plus(mime_type.stripExtension(os.path.basename(item))) - - if not os.path.isfile(item): + item_id = urllib.parse.unquote_plus(mime_type.stripExtension(os.path.basename(file_path))) + if not os.path.isfile(file_path): + Logger.log("e", "[%s] is not a file", file_path) continue - parser = ConfigParser(allow_no_value=True) # accept options without any value, - + parser = ConfigParser(allow_no_value = True) # accept options without any value, try: - parser.read([item]) - - if not parser.has_option("general", "name") and not parser.has_option("general", "weight"): + parser.read([file_path]) + if not parser.has_option("general", "name") or not parser.has_option("general", "weight"): continue settings = [] @@ -73,48 +87,90 @@ class SettingVisibilityPresetsModel(ListModel): settings.append(option) items.append({ - "id": id, - "name": parser["general"]["name"], + "id": item_id, + "name": catalog.i18nc("@action:inmenu", parser["general"]["name"]), "weight": parser["general"]["weight"], - "settings": settings + "settings": settings, }) - except Exception as e: - Logger.log("e", "Failed to load setting preset %s: %s", file_path, str(e)) + except Exception: + Logger.logException("e", "Failed to load setting preset %s", file_path) + items.sort(key = lambda k: (int(k["weight"]), k["id"])) + # Put "custom" at the top + items.insert(0, {"id": "custom", + "name": "Custom selection", + "weight": -100, + "settings": []}) - items.sort(key = lambda k: (k["weight"], k["id"])) self.setItems(items) @pyqtSlot(str) - def setActivePreset(self, preset_id): - if preset_id != "custom" and self.find("id", preset_id) == -1: - Logger.log("w", "Tried to set active preset to unknown id %s", preset_id) + def setActivePreset(self, preset_id: str): + if preset_id == self._active_preset_item["id"]: + Logger.log("d", "Same setting visibility preset [%s] selected, do nothing.", preset_id) return - if preset_id == "custom" and self._active_preset == "custom": - # Copy current visibility set to custom visibility set preference so it can be restored later - visibility_string = self._preferences.getValue("general/visible_settings") - self._preferences.setValue("cura/custom_visible_settings", visibility_string) + preset_item = None + for item in self.items: + if item["id"] == preset_id: + preset_item = item + break + if preset_item is None: + Logger.log("w", "Tried to set active preset to unknown id [%s]", preset_id) + return + + need_to_save_to_custom = self._active_preset_item["id"] == "custom" and preset_id != "custom" + if need_to_save_to_custom: + # Save the current visibility settings to custom + current_visibility_string = self._preferences.getValue("general/visible_settings") + if current_visibility_string: + self._preferences.setValue("cura/custom_visible_settings", current_visibility_string) + + new_visibility_string = ";".join(preset_item["settings"]) + if preset_id == "custom": + # Get settings from the stored custom data + new_visibility_string = self._preferences.getValue("cura/custom_visible_settings") + if new_visibility_string is None: + new_visibility_string = self._preferences.getValue("general/visible_settings") + self._preferences.setValue("general/visible_settings", new_visibility_string) self._preferences.setValue("cura/active_setting_visibility_preset", preset_id) - - self._active_preset = preset_id + self._active_preset_item = preset_item self.activePresetChanged.emit() activePresetChanged = pyqtSignal() @pyqtProperty(str, notify = activePresetChanged) - def activePreset(self): - return self._active_preset + def activePreset(self) -> str: + return self._active_preset_item["id"] - def _onPreferencesChanged(self, name): + def _onPreferencesChanged(self, name: str): if name != "general/visible_settings": return - if self._active_preset != "custom": + # Find the preset that matches with the current visible settings setup + visibility_string = self._preferences.getValue("general/visible_settings") + if not visibility_string: return - # Copy current visibility set to custom visibility set preference so it can be restored later - visibility_string = self._preferences.getValue("general/visible_settings") - self._preferences.setValue("cura/custom_visible_settings", visibility_string) + visibility_set = set(visibility_string.split(";")) + matching_preset_item = None + for item in self.items: + if item["id"] == "custom": + continue + if set(item["settings"]) == visibility_set: + matching_preset_item = item + break + + if matching_preset_item is None: + # The new visibility setup is "custom" should be custom + if self._active_preset_item["id"] == "custom": + # We are already in custom, just save the settings + self._preferences.setValue("cura/custom_visible_settings", visibility_string) + else: + self._active_preset_item = self.items[0] # 0 is custom + self.activePresetChanged.emit() + else: + self._active_preset_item = matching_preset_item + self.activePresetChanged.emit() diff --git a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml index d39d65e96c..0753c83b17 100644 --- a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml +++ b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml @@ -1,8 +1,8 @@ // Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. -import QtQuick 2.2 -import QtQuick.Controls 1.1 +import QtQuick 2.7 +import QtQuick.Controls 1.4 import UM 1.2 as UM import Cura 1.0 as Cura @@ -19,22 +19,6 @@ Menu signal showAllSettings() signal showSettingVisibilityProfile() - MenuItem - { - text: catalog.i18nc("@action:inmenu", "Custom selection") - checkable: true - checked: !showingSearchResults && !showingAllSettings && settingVisibilityPresetsModel.activePreset == "custom" - exclusiveGroup: group - onTriggered: - { - settingVisibilityPresetsModel.setActivePreset("custom"); - // Restore custom set from preference - UM.Preferences.setValue("general/visible_settings", UM.Preferences.getValue("cura/custom_visible_settings")); - showSettingVisibilityProfile(); - } - } - MenuSeparator { } - Instantiator { model: settingVisibilityPresetsModel @@ -48,9 +32,6 @@ Menu onTriggered: { settingVisibilityPresetsModel.setActivePreset(model.id); - - UM.Preferences.setValue("general/visible_settings", model.settings.join(";")); - showSettingVisibilityProfile(); } } diff --git a/resources/qml/Preferences/SettingVisibilityPage.qml b/resources/qml/Preferences/SettingVisibilityPage.qml index 7f6a58367d..b6b1c133ed 100644 --- a/resources/qml/Preferences/SettingVisibilityPage.qml +++ b/resources/qml/Preferences/SettingVisibilityPage.qml @@ -29,8 +29,7 @@ UM.PreferencesPage // After calling this function update Setting visibility preset combobox. // Reset should set default setting preset ("Basic") - visibilityPreset.setDefaultPreset() - + visibilityPreset.currentIndex = 1 } resetEnabled: true; @@ -39,8 +38,6 @@ UM.PreferencesPage id: base; anchors.fill: parent; - property bool inhibitSwitchToCustom: false - CheckBox { id: toggleVisibleSettings @@ -114,11 +111,6 @@ UM.PreferencesPage ComboBox { - function setDefaultPreset() - { - visibilityPreset.currentIndex = 0 - } - id: visibilityPreset width: 150 * screenScaleFactor anchors @@ -127,50 +119,25 @@ UM.PreferencesPage right: parent.right } - model: ListModel - { - id: visibilityPresetsModel - Component.onCompleted: - { - visibilityPresetsModel.append({text: catalog.i18nc("@action:inmenu", "Custom selection"), id: "custom"}); - - for(var i = 0; i < settingVisibilityPresetsModel.rowCount(); i++) - { - visibilityPresetsModel.append({text: settingVisibilityPresetsModel.getItem(i)["name"], id: settingVisibilityPresetsModel.getItem(i)["id"]}); - } - } - } + model: settingVisibilityPresetsModel + textRole: "name" currentIndex: { // Load previously selected preset. - var index = settingVisibilityPresetsModel.find("id", settingVisibilityPresetsModel.activePreset); - if(index == -1) + var index = settingVisibilityPresetsModel.find("id", settingVisibilityPresetsModel.activePreset) + if (index == -1) { - return 0; + return 0 } - return index + 1; // "Custom selection" entry is added in front, so index is off by 1 + return index } onActivated: { - base.inhibitSwitchToCustom = true; - var preset_id = visibilityPresetsModel.get(index).id; + var preset_id = settingVisibilityPresetsModel.getItem(index).id; settingVisibilityPresetsModel.setActivePreset(preset_id); - - UM.Preferences.setValue("cura/active_setting_visibility_preset", preset_id); - if (preset_id != "custom") - { - UM.Preferences.setValue("general/visible_settings", settingVisibilityPresetsModel.getItem(index - 1).settings.join(";")); - // "Custom selection" entry is added in front, so index is off by 1 - } - else - { - // Restore custom set from preference - UM.Preferences.setValue("general/visible_settings", UM.Preferences.getValue("cura/custom_visible_settings")); - } - base.inhibitSwitchToCustom = false; } } @@ -200,16 +167,7 @@ UM.PreferencesPage exclude: ["machine_settings", "command_line_settings"] showAncestors: true expanded: ["*"] - visibilityHandler: UM.SettingPreferenceVisibilityHandler - { - onVisibilityChanged: - { - if(settingVisibilityPresetsModel.activePreset != "" && !base.inhibitSwitchToCustom) - { - settingVisibilityPresetsModel.setActivePreset("custom"); - } - } - } + visibilityHandler: UM.SettingPreferenceVisibilityHandler {} } delegate: Loader From cbe929242ec59b227dc03079272978e1327ec786 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Thu, 15 Mar 2018 14:44:01 +0100 Subject: [PATCH 345/446] CURA-4870 Update the names of the groups in the container stacks when there is temporary name after upgrading from 3.2 --- .../NetworkedPrinterOutputDevice.py | 16 ++++++++++++++++ cura/Settings/MachineManager.py | 2 -- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/cura/PrinterOutput/NetworkedPrinterOutputDevice.py b/cura/PrinterOutput/NetworkedPrinterOutputDevice.py index eefbd9ae12..0dca149e5a 100644 --- a/cura/PrinterOutput/NetworkedPrinterOutputDevice.py +++ b/cura/PrinterOutput/NetworkedPrinterOutputDevice.py @@ -3,6 +3,7 @@ from UM.Application import Application from UM.Logger import Logger +from UM.Settings.ContainerRegistry import ContainerRegistry from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState @@ -254,6 +255,21 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice): self._last_manager_create_time = time() self._manager.authenticationRequired.connect(self._onAuthenticationRequired) + self._checkCorrectGroupName() + + ## This method checks if the name of the group stored in the definition container is correct. + # After updating from 3.2 to 3.3 some group names may be temporary. If there is a mismatch in the name of the group + # then all the container stacks are updated, both the current and the hidden ones. + def _checkCorrectGroupName(self): + global_container_stack = Application.getInstance().getGlobalContainerStack() + if global_container_stack and self.getId() == global_container_stack.getMetaDataEntry("um_network_key"): + # Check if the connect_group_name is correct. If not, update all the containers connected to the same printer + if global_container_stack.getMetaDataEntry("connect_group_name") != self.name: + metadata_filter = {"um_network_key": global_container_stack.getMetaDataEntry("um_network_key")} + hidden_containers = ContainerRegistry.getInstance().findContainerStacks(type = "machine", **metadata_filter) + for container in hidden_containers: + container.setMetaDataEntry("connect_group_name", self.name) + def _registerOnFinishedCallback(self, reply: QNetworkReply, onFinished: Optional[Callable[[Any, QNetworkReply], None]]) -> None: if onFinished is not None: self._onFinishedCallbacks[reply.url().toString() + str(reply.operation())] = onFinished diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 100c7c3c31..1cf3fae161 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -10,7 +10,6 @@ from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Signal import Signal from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, QTimer -import UM.FlameProfiler from UM.FlameProfiler import pyqtSlot from UM import Util @@ -24,7 +23,6 @@ from UM.Settings.SettingFunction import SettingFunction from UM.Signal import postponeSignals, CompressTechnique from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch -from cura.Machines.VariantManager import VariantType from cura.PrinterOutputDevice import PrinterOutputDevice from cura.PrinterOutput.ConfigurationModel import ConfigurationModel from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationModel From 98b325c9d5334b5a6a0eff6c7918207c6a054d21 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 15 Mar 2018 14:54:09 +0100 Subject: [PATCH 346/446] Fix material serialization crash --- plugins/XmlMaterialProfile/XmlMaterialProfile.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index 8b17721794..5ff6838373 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -208,14 +208,9 @@ class XmlMaterialProfile(InstanceContainer): machine_variant_map = {} variant_manager = CuraApplication.getInstance().getVariantManager() - material_manager = CuraApplication.getInstance().getMaterialManager() root_material_id = self.getMetaDataEntry("base_file") # if basefile is self.getId, this is a basefile. - material_group = material_manager.getMaterialGroup(root_material_id) - - all_containers = [] - for node in [material_group.root_material_node] + material_group.derived_material_node_list: - all_containers.append(node.getContainer()) + all_containers = registry.findInstanceContainers(base_file = root_material_id) for container in all_containers: definition_id = container.getMetaDataEntry("definition") @@ -242,7 +237,7 @@ class XmlMaterialProfile(InstanceContainer): for definition_id, container in machine_container_map.items(): definition_id = container.getMetaDataEntry("definition") - definition_metadata = ContainerRegistry.getInstance().findDefinitionContainersMetadata(id = definition_id)[0] + definition_metadata = registry.findDefinitionContainersMetadata(id = definition_id)[0] product = definition_id for product_name, product_id_list in product_id_map.items(): From c3c096aaa015936441d8e7360c427f5af67c18aa Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 15 Mar 2018 14:55:15 +0100 Subject: [PATCH 347/446] Select the picked node so the group does not get drawn --- plugins/SupportEraser/SupportEraser.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/SupportEraser/SupportEraser.py b/plugins/SupportEraser/SupportEraser.py index 8f8e9deb52..d87a887d1b 100644 --- a/plugins/SupportEraser/SupportEraser.py +++ b/plugins/SupportEraser/SupportEraser.py @@ -118,6 +118,12 @@ class SupportEraser(Tool): op.push() Application.getInstance().getController().getScene().sceneChanged.emit(node) + # Select the picked node so the group does not get drawn as a wireframe (yet) + if Selection.isSelected(group): + Selection.remove(group) + if not Selection.isSelected(parent): + Selection.add(parent) + def _removeEraserMesh(self, node: CuraSceneNode): op = RemoveSceneNodeOperation(node) op.push() From 05cd937df35335744524cd5268f089a1296ebf0c Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 15 Mar 2018 15:00:13 +0100 Subject: [PATCH 348/446] CURA-4400 optional_extruders cannot be set to disabled extruders anymore --- cura/Settings/ExtrudersModel.py | 1 + resources/qml/Settings/SettingExtruder.qml | 3 ++- .../qml/Settings/SettingOptionalExtruder.qml | 24 ++++++++++++++++--- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/cura/Settings/ExtrudersModel.py b/cura/Settings/ExtrudersModel.py index 4ee5ab3c3b..f179dabd5a 100644 --- a/cura/Settings/ExtrudersModel.py +++ b/cura/Settings/ExtrudersModel.py @@ -210,6 +210,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): item = { "id": "", "name": catalog.i18nc("@menuitem", "Not overridden"), + "enabled": True, "color": "#ffffff", "index": -1, "definition": "" diff --git a/resources/qml/Settings/SettingExtruder.qml b/resources/qml/Settings/SettingExtruder.qml index 2ddbb135c7..38b1c2cab0 100644 --- a/resources/qml/Settings/SettingExtruder.qml +++ b/resources/qml/Settings/SettingExtruder.qml @@ -215,7 +215,8 @@ SettingItem { text: model.name renderType: Text.NativeRendering - color: { + color: + { if (model.enabled) { UM.Theme.getColor("setting_control_text") } else { diff --git a/resources/qml/Settings/SettingOptionalExtruder.qml b/resources/qml/Settings/SettingOptionalExtruder.qml index f49b7035d7..a370ec6259 100644 --- a/resources/qml/Settings/SettingOptionalExtruder.qml +++ b/resources/qml/Settings/SettingOptionalExtruder.qml @@ -27,8 +27,19 @@ SettingItem onActivated: { - forceActiveFocus(); - propertyProvider.setPropertyValue("value", model.getItem(index).index); + if (model.getItem(index).enabled) + { + forceActiveFocus(); + propertyProvider.setPropertyValue("value", model.getItem(index).index); + } else + { + if (propertyProvider.properties.value == -1) + { + control.currentIndex = model.rowCount() - 1; // we know the last item is "Not overriden" + } else { + control.currentIndex = propertyProvider.properties.value; // revert to the old value + } + } } onActiveFocusChanged: @@ -192,7 +203,14 @@ SettingItem { text: model.name renderType: Text.NativeRendering - color: UM.Theme.getColor("setting_control_text") + color: + { + if (model.enabled) { + UM.Theme.getColor("setting_control_text") + } else { + UM.Theme.getColor("action_button_disabled_text"); + } + } font: UM.Theme.getFont("default") elide: Text.ElideRight verticalAlignment: Text.AlignVCenter From b9bf78d36ce67bbcd5163d479778b69b362b51ce Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 15 Mar 2018 15:05:56 +0100 Subject: [PATCH 349/446] Remove group when "parent" is the only node in the group --- plugins/SupportEraser/SupportEraser.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/plugins/SupportEraser/SupportEraser.py b/plugins/SupportEraser/SupportEraser.py index d87a887d1b..ee59fc5258 100644 --- a/plugins/SupportEraser/SupportEraser.py +++ b/plugins/SupportEraser/SupportEraser.py @@ -125,10 +125,24 @@ class SupportEraser(Tool): Selection.add(parent) def _removeEraserMesh(self, node: CuraSceneNode): - op = RemoveSceneNodeOperation(node) + group = node.getParent() + if group.callDecoration("isGroup"): + parent = group.getChildren()[0] + + op = GroupedOperation() + op.addOperation(RemoveSceneNodeOperation(node)) + if len(group.getChildren()) == 2: + op.addOperation(SetParentOperation(parent, group.getParent())) + op.push() Application.getInstance().getController().getScene().sceneChanged.emit(node) + # Select the picked node so the group does not get drawn as a wireframe (yet) + if Selection.isSelected(group): + Selection.remove(group) + if parent and not Selection.isSelected(parent): + Selection.add(parent) + def _updateEnabled(self): plugin_enabled = False From dcb68bb33ef2e65fc3b63c7ac1196fd45105822c Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Thu, 15 Mar 2018 15:13:35 +0100 Subject: [PATCH 350/446] CURA-4870 Move the checkCorrectGroupName to the machine manager, where it must belong to. --- .../NetworkedPrinterOutputDevice.py | 17 +++-------------- cura/Settings/MachineManager.py | 12 ++++++++++++ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/cura/PrinterOutput/NetworkedPrinterOutputDevice.py b/cura/PrinterOutput/NetworkedPrinterOutputDevice.py index 0dca149e5a..1537d51919 100644 --- a/cura/PrinterOutput/NetworkedPrinterOutputDevice.py +++ b/cura/PrinterOutput/NetworkedPrinterOutputDevice.py @@ -4,6 +4,7 @@ from UM.Application import Application from UM.Logger import Logger from UM.Settings.ContainerRegistry import ContainerRegistry +from cura.CuraApplication import CuraApplication from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState @@ -255,20 +256,8 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice): self._last_manager_create_time = time() self._manager.authenticationRequired.connect(self._onAuthenticationRequired) - self._checkCorrectGroupName() - - ## This method checks if the name of the group stored in the definition container is correct. - # After updating from 3.2 to 3.3 some group names may be temporary. If there is a mismatch in the name of the group - # then all the container stacks are updated, both the current and the hidden ones. - def _checkCorrectGroupName(self): - global_container_stack = Application.getInstance().getGlobalContainerStack() - if global_container_stack and self.getId() == global_container_stack.getMetaDataEntry("um_network_key"): - # Check if the connect_group_name is correct. If not, update all the containers connected to the same printer - if global_container_stack.getMetaDataEntry("connect_group_name") != self.name: - metadata_filter = {"um_network_key": global_container_stack.getMetaDataEntry("um_network_key")} - hidden_containers = ContainerRegistry.getInstance().findContainerStacks(type = "machine", **metadata_filter) - for container in hidden_containers: - container.setMetaDataEntry("connect_group_name", self.name) + machine_manager = CuraApplication.getInstance().getMachineManager() + machine_manager.checkCorrectGroupName(self.getId(), self.name) def _registerOnFinishedCallback(self, reply: QNetworkReply, onFinished: Optional[Callable[[Any, QNetworkReply], None]]) -> None: if onFinished is not None: diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 1cf3fae161..3a6015e90f 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1201,6 +1201,18 @@ class MachineManager(QObject): if machine.getMetaDataEntry(key) == value: machine.setMetaDataEntry(key, new_value) + ## This method checks if the name of the group stored in the definition container is correct. + # After updating from 3.2 to 3.3 some group names may be temporary. If there is a mismatch in the name of the group + # then all the container stacks are updated, both the current and the hidden ones. + def checkCorrectGroupName(self, device_id: str, group_name: str): + if self._global_container_stack and device_id == self.activeMachineNetworkKey: + # Check if the connect_group_name is correct. If not, update all the containers connected to the same printer + if self.activeMachineNetworkGroupName != group_name: + metadata_filter = {"um_network_key": self.activeMachineNetworkKey} + hidden_containers = ContainerRegistry.getInstance().findContainerStacks(type = "machine", **metadata_filter) + for container in hidden_containers: + container.setMetaDataEntry("connect_group_name", group_name) + @pyqtSlot("QVariant") def setGlobalVariant(self, container_node): self.blurSettings.emit() From 08f43f6b2e719cad4ac0c42efdfaa7d82af0dc37 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 15 Mar 2018 15:27:13 +0100 Subject: [PATCH 351/446] Fix profile ordering in profile importing CURA-5054 --- cura/Settings/CuraContainerRegistry.py | 28 ++++++++++++++++---------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index 0cf1c7399f..ab48eaddd2 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -173,12 +173,13 @@ class CuraContainerRegistry(ContainerRegistry): plugin_registry = PluginRegistry.getInstance() extension = file_name.split(".")[-1] - global_container_stack = Application.getInstance().getGlobalContainerStack() - if not global_container_stack: + global_stack = Application.getInstance().getGlobalContainerStack() + if not global_stack: return - machine_extruders = list(ExtruderManager.getInstance().getMachineExtruders(global_container_stack.getId())) - machine_extruders.sort(key = lambda k: k.getMetaDataEntry("position")) + machine_extruders = [] + for position in sorted(global_stack.extruders): + machine_extruders.append(global_stack.extruders[position]) for plugin_id, meta_data in self._getIOPlugins("profile_reader"): if meta_data["profile_reader"][0]["extension"] != extension: @@ -200,13 +201,18 @@ class CuraContainerRegistry(ContainerRegistry): # First check if this profile is suitable for this machine global_profile = None + extruder_profiles = [] if len(profile_or_list) == 1: global_profile = profile_or_list[0] else: for profile in profile_or_list: if not profile.getMetaDataEntry("position"): global_profile = profile - break + else: + extruder_profiles.append(profile) + extruder_profiles = sorted(extruder_profiles, key = lambda x: int(x.getMetaDataEntry("position"))) + profile_or_list = [global_profile] + extruder_profiles + if not global_profile: Logger.log("e", "Incorrect profile [%s]. Could not find global profile", file_name) return { "status": "error", @@ -227,7 +233,7 @@ class CuraContainerRegistry(ContainerRegistry): # Get the expected machine definition. # i.e.: We expect gcode for a UM2 Extended to be defined as normal UM2 gcode... profile_definition = getMachineDefinitionIDForQualitySearch(machine_definition) - expected_machine_definition = getMachineDefinitionIDForQualitySearch(global_container_stack.definition) + expected_machine_definition = getMachineDefinitionIDForQualitySearch(global_stack.definition) # And check if the profile_definition matches either one (showing error if not): if profile_definition != expected_machine_definition: @@ -251,8 +257,8 @@ class CuraContainerRegistry(ContainerRegistry): if len(profile_or_list) == 1: global_profile = profile_or_list[0] extruder_profiles = [] - for idx, extruder in enumerate(global_container_stack.extruders.values()): - profile_id = ContainerRegistry.getInstance().uniqueName(global_container_stack.getId() + "_extruder_" + str(idx + 1)) + for idx, extruder in enumerate(global_stack.extruders.values()): + profile_id = ContainerRegistry.getInstance().uniqueName(global_stack.getId() + "_extruder_" + str(idx + 1)) profile = InstanceContainer(profile_id) profile.setName(quality_name) profile.addMetaDataEntry("setting_version", CuraApplication.SettingVersion) @@ -264,12 +270,12 @@ class CuraContainerRegistry(ContainerRegistry): if idx == 0: # move all per-extruder settings to the first extruder's quality_changes for qc_setting_key in global_profile.getAllKeys(): - settable_per_extruder = global_container_stack.getProperty(qc_setting_key, + settable_per_extruder = global_stack.getProperty(qc_setting_key, "settable_per_extruder") if settable_per_extruder: setting_value = global_profile.getProperty(qc_setting_key, "value") - setting_definition = global_container_stack.getSettingDefinition(qc_setting_key) + setting_definition = global_stack.getSettingDefinition(qc_setting_key) new_instance = SettingInstance(setting_definition, profile) new_instance.setProperty("value", setting_value) new_instance.resetState() # Ensure that the state is not seen as a user state. @@ -286,7 +292,7 @@ class CuraContainerRegistry(ContainerRegistry): for profile_index, profile in enumerate(profile_or_list): if profile_index == 0: # This is assumed to be the global profile - profile_id = (global_container_stack.getBottom().getId() + "_" + name_seed).lower().replace(" ", "_") + profile_id = (global_stack.getBottom().getId() + "_" + name_seed).lower().replace(" ", "_") elif profile_index < len(machine_extruders) + 1: # This is assumed to be an extruder profile From 4b060f297f2a386ad8193f6795c1608ce5ec5830 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 15 Mar 2018 15:44:27 +0100 Subject: [PATCH 352/446] CURA-4400 grey out disabled extruder in context menu --- resources/qml/Menus/ContextMenu.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Menus/ContextMenu.qml b/resources/qml/Menus/ContextMenu.qml index 83302f9463..e35aef5f20 100644 --- a/resources/qml/Menus/ContextMenu.qml +++ b/resources/qml/Menus/ContextMenu.qml @@ -31,7 +31,7 @@ Menu MenuItem { text: "%1: %2 - %3".arg(model.name).arg(model.material).arg(model.variant) visible: base.shouldShowExtruders - enabled: UM.Selection.hasSelection + enabled: UM.Selection.hasSelection && model.enabled checkable: true checked: Cura.ExtruderManager.selectedObjectExtruders.indexOf(model.id) != -1 onTriggered: CuraActions.setExtruderForSelection(model.id) From 8af82cc3f459e39abedd534e4295b0fd8ac1f04a Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 15 Mar 2018 15:54:44 +0100 Subject: [PATCH 353/446] CURA-4400 prevent disabling last enabled extruder --- cura/Settings/MachineManager.py | 9 ++++++++- resources/qml/Cura.qml | 1 + resources/qml/SidebarHeader.qml | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 3a6015e90f..50c3c53734 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -145,6 +145,7 @@ class MachineManager(QObject): activeStackValueChanged = pyqtSignal() # Emitted whenever a value inside the active stack is changed. activeStackValidationChanged = pyqtSignal() # Emitted whenever a validation inside active container is changed stacksValidationChanged = pyqtSignal() # Emitted whenever a validation is changed + numberExtrudersEnabledChanged = pyqtSignal() # Emitted when the number of extruders that are enabled changed blurSettings = pyqtSignal() # Emitted to force fields in the advanced sidebar to un-focus, so they update properly @@ -880,7 +881,13 @@ class MachineManager(QObject): for position, extruder in self._global_container_stack.extruders.items(): if extruder.isEnabled: extruder_count += 1 - definition_changes_container.setProperty("extruders_enabled_count", "value", extruder_count) + if self.numberExtrudersEnabled != extruder_count: + definition_changes_container.setProperty("extruders_enabled_count", "value", extruder_count) + self.numberExtrudersEnabledChanged.emit() + + @pyqtProperty(int, notify = numberExtrudersEnabledChanged) + def numberExtrudersEnabled(self): + return self._global_container_stack.definitionChanges.getProperty("extruders_enabled_count", "value") @pyqtProperty(str, notify = extruderChanged) def defaultExtruderPosition(self): diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index cff4399073..c4ebb790e8 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -217,6 +217,7 @@ UM.MainWindow text: catalog.i18nc("@action:inmenu", "Disable Extruder") onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false) visible: Cura.MachineManager.getExtruder(model.index).isEnabled + enabled: Cura.MachineManager.numberExtrudersEnabled > 1 } } diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 5cd0446b36..92af6e9cc9 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -178,6 +178,7 @@ Column text: catalog.i18nc("@action:inmenu", "Disable Extruder") onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false) visible: extruder_enabled + enabled: Cura.MachineManager.numberExtrudersEnabled > 1 } } From b1c1b04f0d96c5b43795f44581691f8f3d634f7c Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 15 Mar 2018 16:08:40 +0100 Subject: [PATCH 354/446] Restore change to SettingView removeUnusedValue --- resources/qml/Settings/SettingView.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index a6d7b3a71e..cf9697210b 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -440,6 +440,7 @@ Item key: model.key ? model.key : "" watchedProperties: [ "value", "enabled", "state", "validationState", "settable_per_extruder", "resolve" ] storeIndex: 0 + removeUnusedValue: model.resolve == undefined } Connections From f127660cfc84819d61a58727fd7e7fe96c1f4b8d Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 15 Mar 2018 16:12:32 +0100 Subject: [PATCH 355/446] Remove whitespace at the end of the lines Someone put tabs there. --- resources/definitions/ultimaker3.def.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/definitions/ultimaker3.def.json b/resources/definitions/ultimaker3.def.json index 57cfbe960f..ef41686752 100644 --- a/resources/definitions/ultimaker3.def.json +++ b/resources/definitions/ultimaker3.def.json @@ -110,9 +110,9 @@ "material_bed_temperature": { "maximum_value": "115" }, "material_bed_temperature_layer_0": { "maximum_value": "115" }, "material_standby_temperature": { "value": "100" }, - "meshfix_maximum_resolution": { "value": "0.04" }, + "meshfix_maximum_resolution": { "value": "0.04" }, "multiple_mesh_overlap": { "value": "0" }, - "optimize_wall_printing_order": { "value": "True" }, + "optimize_wall_printing_order": { "value": "True" }, "prime_tower_enable": { "default_value": true }, "raft_airgap": { "value": "0" }, "raft_base_thickness": { "value": "0.3" }, From 3ce51bb25554ef70c695302d36927fbbde7a4761 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Thu, 15 Mar 2018 16:14:20 +0100 Subject: [PATCH 356/446] CURA-4870 Correctly align the name with the connection icon when the printer is connected to USB --- resources/qml/MachineSelection.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/qml/MachineSelection.qml b/resources/qml/MachineSelection.qml index b959e20bb7..d075486eb2 100644 --- a/resources/qml/MachineSelection.qml +++ b/resources/qml/MachineSelection.qml @@ -71,8 +71,8 @@ ToolButton color: UM.Theme.getColor("sidebar_header_text_active") text: control.text; elide: Text.ElideRight; - anchors.left: isNetworkPrinter ? printerStatusIcon.right : parent.left; - anchors.leftMargin: isNetworkPrinter ? UM.Theme.getSize("sidebar_lining").width : UM.Theme.getSize("sidebar_margin").width + anchors.left: printerStatusIcon.visible ? printerStatusIcon.right : parent.left; + anchors.leftMargin: printerStatusIcon.visible ? UM.Theme.getSize("sidebar_lining").width : UM.Theme.getSize("sidebar_margin").width anchors.right: downArrow.left; anchors.rightMargin: control.rightMargin; anchors.verticalCenter: parent.verticalCenter; From 440a56b7fa6d4f09eb64f3969c85d4d8309b0c37 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 15 Mar 2018 16:41:50 +0100 Subject: [PATCH 357/446] Fix settings export in gcode --- plugins/GCodeWriter/GCodeWriter.py | 63 ++++++++++++++++++------------ 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/plugins/GCodeWriter/GCodeWriter.py b/plugins/GCodeWriter/GCodeWriter.py index 1b3b7264a1..4b78a2a72a 100644 --- a/plugins/GCodeWriter/GCodeWriter.py +++ b/plugins/GCodeWriter/GCodeWriter.py @@ -1,17 +1,17 @@ # Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +import re # For escaping characters in the settings. +import json +import copy + from UM.Mesh.MeshWriter import MeshWriter from UM.Logger import Logger from UM.Application import Application from UM.Settings.InstanceContainer import InstanceContainer -from UM.Util import parseBool -from cura.Settings.ExtruderManager import ExtruderManager +from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch -import re #For escaping characters in the settings. -import json -import copy ## Writes g-code to a file. # @@ -45,6 +45,8 @@ class GCodeWriter(MeshWriter): def __init__(self): super().__init__() + self._application = Application.getInstance() + ## Writes the g-code for the entire scene to a stream. # # Note that even though the function accepts a collection of nodes, the @@ -94,7 +96,6 @@ class GCodeWriter(MeshWriter): return flat_container - ## Serialises a container stack to prepare it for writing at the end of the # g-code. # @@ -104,15 +105,21 @@ class GCodeWriter(MeshWriter): # \param settings A container stack to serialise. # \return A serialised string of the settings. def _serialiseSettings(self, stack): + container_registry = self._application.getContainerRegistry() + quality_manager = self._application.getQualityManager() + prefix = ";SETTING_" + str(GCodeWriter.version) + " " # The prefix to put before each line. prefix_length = len(prefix) + quality_name = stack.qualityChanges.getName() + quality_type = stack.quality.getMetaDataEntry("quality_type") container_with_profile = stack.qualityChanges if container_with_profile.getId() == "empty_quality_changes": - Logger.log("e", "No valid quality profile found, not writing settings to g-code!") - return "" + # If the global quality changes is empty, create a new one + quality_name = container_registry.uniqueName(stack.quality.getName()) + container_with_profile = quality_manager._createQualityChanges(quality_type, quality_name, stack, None) - flat_global_container = self._createFlattenedContainerInstance(stack.getTop(), container_with_profile) + flat_global_container = self._createFlattenedContainerInstance(stack.userChanges, container_with_profile) # If the quality changes is not set, we need to set type manually if flat_global_container.getMetaDataEntry("type", None) is None: flat_global_container.addMetaDataEntry("type", "quality_changes") @@ -121,41 +128,47 @@ class GCodeWriter(MeshWriter): if flat_global_container.getMetaDataEntry("quality_type", None) is None: flat_global_container.addMetaDataEntry("quality_type", stack.quality.getMetaDataEntry("quality_type", "normal")) - # Change the default defintion - default_machine_definition = "fdmprinter" - if parseBool(stack.getMetaDataEntry("has_machine_quality", "False")): - default_machine_definition = stack.getMetaDataEntry("quality_definition") - if not default_machine_definition: - default_machine_definition = stack.definition.getId() - flat_global_container.setMetaDataEntry("definition", default_machine_definition) + # Get the machine definition ID for quality profiles + machine_definition_id_for_quality = getMachineDefinitionIDForQualitySearch(stack.definition) + flat_global_container.setMetaDataEntry("definition", machine_definition_id_for_quality) serialized = flat_global_container.serialize() data = {"global_quality": serialized} - for extruder in sorted(stack.extruders.values(), key = lambda k: k.getMetaDataEntry("position")): + all_setting_keys = set(flat_global_container.getAllKeys()) + for extruder in sorted(stack.extruders.values(), key = lambda k: int(k.getMetaDataEntry("position"))): extruder_quality = extruder.qualityChanges if extruder_quality.getId() == "empty_quality_changes": - Logger.log("w", "No extruder quality profile found, not writing quality for extruder %s to file!", extruder.getId()) - continue - flat_extruder_quality = self._createFlattenedContainerInstance(extruder.getTop(), extruder_quality) + # Same story, if quality changes is empty, create a new one + quality_name = container_registry.uniqueName(stack.quality.getName()) + extruder_quality = quality_manager._createQualityChanges(quality_type, quality_name, stack, None) + + flat_extruder_quality = self._createFlattenedContainerInstance(extruder.userChanges, extruder_quality) # If the quality changes is not set, we need to set type manually if flat_extruder_quality.getMetaDataEntry("type", None) is None: flat_extruder_quality.addMetaDataEntry("type", "quality_changes") # Ensure that extruder is set. (Can happen if we have empty quality changes). - if flat_extruder_quality.getMetaDataEntry("extruder", None) is None: - flat_extruder_quality.addMetaDataEntry("extruder", extruder.getBottom().getId()) + if flat_extruder_quality.getMetaDataEntry("position", None) is None: + flat_extruder_quality.addMetaDataEntry("position", extruder.getMetaDataEntry("position")) # Ensure that quality_type is set. (Can happen if we have empty quality changes). if flat_extruder_quality.getMetaDataEntry("quality_type", None) is None: flat_extruder_quality.addMetaDataEntry("quality_type", extruder.quality.getMetaDataEntry("quality_type", "normal")) - # Change the default defintion - flat_extruder_quality.setMetaDataEntry("definition", default_machine_definition) + # Change the default definition + flat_extruder_quality.setMetaDataEntry("definition", machine_definition_id_for_quality) extruder_serialized = flat_extruder_quality.serialize() data.setdefault("extruder_quality", []).append(extruder_serialized) + all_setting_keys.update(set(flat_extruder_quality.getAllKeys())) + + # Check if there is any profiles + if not all_setting_keys: + Logger.log("i", "No custom settings found, not writing settings to g-code.") + return "" + json_string = json.dumps(data) # Escape characters that have a special meaning in g-code comments. @@ -169,5 +182,5 @@ class GCodeWriter(MeshWriter): # Lines have 80 characters, so the payload of each line is 80 - prefix. for pos in range(0, len(escaped_string), 80 - prefix_length): - result += prefix + escaped_string[pos : pos + 80 - prefix_length] + "\n" + result += prefix + escaped_string[pos: pos + 80 - prefix_length] + "\n" return result From d0e6e59845266fcb8c35cb1f9a11feec1d45139c Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Thu, 15 Mar 2018 16:46:25 +0100 Subject: [PATCH 358/446] Set the frame visible for the materials and profiles page in preferences. --- resources/qml/Preferences/MaterialsPage.qml | 1 + resources/qml/Preferences/ProfilesPage.qml | 1 + 2 files changed, 2 insertions(+) diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml index 7f06ffecde..042bd09828 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/MaterialsPage.qml @@ -364,6 +364,7 @@ Item } width: true ? (parent.width * 0.4) | 0 : parent.width + frameVisible: true ListView { diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index ff35e27eeb..1726087e97 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -369,6 +369,7 @@ Item } width: true ? (parent.width * 0.4) | 0 : parent.width + frameVisible: true ListView { From 9de114c73ab5976466cc222851666525c054bd6d Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 15 Mar 2018 16:47:51 +0100 Subject: [PATCH 359/446] Simplify discardOrKeepProfileChangesClosed() --- cura/CuraApplication.py | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 1b5de89c2b..6056745c75 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -451,27 +451,18 @@ class CuraApplication(QtApplication): @pyqtSlot(str) def discardOrKeepProfileChangesClosed(self, option): + global_stack = self.getGlobalContainerStack() if option == "discard": - global_stack = self.getGlobalContainerStack() - for extruder in self._extruder_manager.getMachineExtruders(global_stack.getId()): - extruder.getTop().clear() - global_stack.getTop().clear() + for extruder in global_stack.extruders.values(): + extruder.userChanges.clear() + global_stack.userChanges.clear() # if the user decided to keep settings then the user settings should be re-calculated and validated for errors # before slicing. To ensure that slicer uses right settings values elif option == "keep": - global_stack = self.getGlobalContainerStack() - for extruder in self._extruder_manager.getMachineExtruders(global_stack.getId()): - user_extruder_container = extruder.getTop() - if user_extruder_container: - user_extruder_container.update() - - user_global_container = global_stack.getTop() - if user_global_container: - user_global_container.update() - - # notify listeners that quality has changed (after user selected discard or keep) - self.getMachineManager().activeQualityChanged.emit() + for extruder in global_stack.extruders.values(): + extruder.userChanges.update() + global_stack.userChanges.update() @pyqtSlot(int) def messageBoxClosed(self, button): From 40ba06f011eccbe0f12d1b42beccc4dfe83f7cb2 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 15 Mar 2018 16:45:04 +0100 Subject: [PATCH 360/446] Fix output type of BQ Hephestos That application/x-code may actually be the XCode application or something? Whatever, it should be x-gcode... --- resources/definitions/bq_hephestos_xl.def.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/definitions/bq_hephestos_xl.def.json b/resources/definitions/bq_hephestos_xl.def.json index 75b756c71e..08be4b8d34 100644 --- a/resources/definitions/bq_hephestos_xl.def.json +++ b/resources/definitions/bq_hephestos_xl.def.json @@ -6,7 +6,7 @@ "visible": true, "manufacturer": "BQ", "author": "BQ", - "file_formats": "text/x-code", + "file_formats": "text/x-gcode", "platform": "bq_hephestos_platform.stl", "platform_offset": [ 0, -82, 0] }, From b0f7a5b3588966ae088df610626b1578c17e9540 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 15 Mar 2018 16:52:16 +0100 Subject: [PATCH 361/446] Fix translation of there being no file formats available This entry said that it had a context, but it had none. As a result, the whole string was seen as a context. --- .../RemovableDriveOutputDevice/RemovableDriveOutputDevice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py b/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py index ff930e2c31..1bfdbd4117 100644 --- a/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py +++ b/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py @@ -60,7 +60,7 @@ class RemovableDriveOutputDevice(OutputDevice): if len(file_formats) == 0: Logger.log("e", "There are no file formats available to write with!") - raise OutputDeviceError.WriteRequestFailedError(catalog.i18nc("There are no file formats available to write with!")) + raise OutputDeviceError.WriteRequestFailedError(catalog.i18nc("@info:status", "There are no file formats available to write with!")) # Just take the first file format available. if file_handler is not None: From b8ab623c803f343e09e1f1a69412e54c2ca13ad5 Mon Sep 17 00:00:00 2001 From: Aleksei S Date: Thu, 15 Mar 2018 16:54:39 +0100 Subject: [PATCH 362/446] Fix: Infill slider did not work at first Cura start CURA-5071 --- resources/qml/SidebarSimple.qml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index 41ecb529eb..c02337d1f5 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -594,7 +594,9 @@ Item // Update value only if the Recomended mode is Active, // Otherwise if I change the value in the Custom mode the Recomended view will try to repeat // same operation - if (UM.Preferences.getValue("cura/active_mode") == 0) { + var active_mode = UM.Preferences.getValue("cura/active_mode") + + if (active_mode == 0 || active_mode == "simple") { Cura.MachineManager.setSettingForAllExtruders("infill_sparse_density", "value", roundedSliderValue) } } From 3bb0a481f1a4e2ba26d494fc803d5394877d3ac8 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 15 Mar 2018 17:00:45 +0100 Subject: [PATCH 363/446] Simplify default quality reset --- cura/Settings/MachineManager.py | 9 +++++++++ resources/qml/SidebarSimple.qml | 15 ++------------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 50c3c53734..b614e1e1e8 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1269,6 +1269,15 @@ class MachineManager(QObject): if not no_dialog and self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1: self._application.discardOrKeepProfileChanges() + @pyqtSlot() + def clearQualityChangesGroup(self): + with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): + self._setQualityGroup(self._current_quality_group) + + # See if we need to show the Discard or Keep changes screen + if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1: + self._application.discardOrKeepProfileChanges() + @pyqtProperty(QObject, fset = setQualityChangesGroup, notify = activeQualityChangesGroupChanged) def activeQualityChangesGroup(self): return self._current_quality_changes_group diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index c02337d1f5..a8af3fc3dd 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -19,7 +19,7 @@ Item property Action configureSettings; property variant minimumPrintTime: PrintInformation.minimumPrintTime; property variant maximumPrintTime: PrintInformation.maximumPrintTime; - property bool settingsEnabled: Cura.ExtruderManager.activeExtruderStackId || extrudersEnabledCount.properties.value == 1 + property bool settingsEnabled: extrudersEnabledCount.properties.value == 1 Component.onCompleted: PrintInformation.enabled = true Component.onDestruction: PrintInformation.enabled = false @@ -474,18 +474,7 @@ Item onClicked: { // if the current profile is user-created, switch to a built-in quality - if (Cura.SimpleModeSettingsManager.isProfileUserCreated) - { - if (Cura.QualityProfilesDropDownMenuModel.rowCount() > 0) - { - var item = Cura.QualityProfilesDropDownMenuModel.getItem(0); - Cura.MachineManager.activeQualityGroup = item.quality_group; - } - } - if (Cura.SimpleModeSettingsManager.isProfileCustomized) - { - discardOrKeepProfileChangesDialog.show() - } + Cura.MachineManager.clearQualityChangesGroup() } onEntered: { From f8709b6d1af90483c7216cfe28635a4e633f1079 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Thu, 15 Mar 2018 17:02:36 +0100 Subject: [PATCH 364/446] CURA-4400 improved enabled / disabled extruder visually, improved colors of dark theme --- resources/qml/SidebarHeader.qml | 44 ++++++++++++++++++++------- resources/themes/cura-dark/theme.json | 6 ++-- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 92af6e9cc9..7baf13ca97 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -186,22 +186,34 @@ Column { background: Item { - Rectangle + function buttonBackgroundColor(index) { - anchors.fill: parent - border.width: control.checked ? UM.Theme.getSize("default_lining").width * 2 : UM.Theme.getSize("default_lining").width - border.color: (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_border") : - control.hovered ? UM.Theme.getColor("action_button_hovered_border") : - UM.Theme.getColor("action_button_border") - color: (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active") : - control.hovered ? UM.Theme.getColor("action_button_hovered") : - UM.Theme.getColor("action_button") - Behavior on color { ColorAnimation { duration: 50; } } + var extruder = Cura.MachineManager.getExtruder(index) + if (extruder.isEnabled) { + return (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active") : + control.hovered ? UM.Theme.getColor("action_button_hovered") : + UM.Theme.getColor("action_button") + } else { + return UM.Theme.getColor("action_button_disabled") + } + } + + function buttonBorderColor(index) + { + var extruder = Cura.MachineManager.getExtruder(index) + if (extruder.isEnabled) { + return (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_border") : + control.hovered ? UM.Theme.getColor("action_button_hovered_border") : + UM.Theme.getColor("action_button_border") + } else { + return UM.Theme.getColor("action_button_disabled_border") + } } function buttonColor(index) { var extruder = Cura.MachineManager.getExtruder(index); - if (extruder.isEnabled) { + if (extruder.isEnabled) + { return ( control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_text") : control.hovered ? UM.Theme.getColor("action_button_hovered_text") : @@ -211,10 +223,20 @@ Column } } + Rectangle + { + anchors.fill: parent + border.width: control.checked ? UM.Theme.getSize("default_lining").width * 2 : UM.Theme.getSize("default_lining").width + border.color: buttonBorderColor(index) + color: buttonBackgroundColor(index) + Behavior on color { ColorAnimation { duration: 50; } } + } + Item { id: extruderButtonFace anchors.centerIn: parent + width: { var extruderTextWidth = extruderStaticText.visible ? extruderStaticText.width : 0; var iconWidth = extruderIconItem.width; diff --git a/resources/themes/cura-dark/theme.json b/resources/themes/cura-dark/theme.json index 80a5eec09c..5fbe36fcdb 100644 --- a/resources/themes/cura-dark/theme.json +++ b/resources/themes/cura-dark/theme.json @@ -84,16 +84,16 @@ "tab_background": [39, 44, 48, 255], "action_button": [39, 44, 48, 255], - "action_button_text": [255, 255, 255, 101], + "action_button_text": [255, 255, 255, 200], "action_button_border": [255, 255, 255, 30], "action_button_hovered": [39, 44, 48, 255], "action_button_hovered_text": [255, 255, 255, 255], "action_button_hovered_border": [255, 255, 255, 30], "action_button_active": [39, 44, 48, 30], "action_button_active_text": [255, 255, 255, 255], - "action_button_active_border": [255, 255, 255, 30], + "action_button_active_border": [255, 255, 255, 100], "action_button_disabled": [39, 44, 48, 255], - "action_button_disabled_text": [255, 255, 255, 101], + "action_button_disabled_text": [255, 255, 255, 80], "action_button_disabled_border": [255, 255, 255, 30], "scrollbar_background": [39, 44, 48, 0], From f14ddb8711ac1cdcb91aa33cc82e7ca890ed2c14 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 15 Mar 2018 17:08:44 +0100 Subject: [PATCH 365/446] Fix reset to default quality --- cura/Settings/MachineManager.py | 8 +++----- cura/Settings/SimpleModeSettingsManager.py | 3 ++- resources/qml/SidebarSimple.qml | 3 +-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index b614e1e1e8..9619329e59 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1270,13 +1270,11 @@ class MachineManager(QObject): self._application.discardOrKeepProfileChanges() @pyqtSlot() - def clearQualityChangesGroup(self): + def resetToUseDefaultQuality(self): with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): self._setQualityGroup(self._current_quality_group) - - # See if we need to show the Discard or Keep changes screen - if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1: - self._application.discardOrKeepProfileChanges() + for stack in [self._global_container_stack] + list(self._global_container_stack.extruders.values()): + stack.userChanges.clear() @pyqtProperty(QObject, fset = setQualityChangesGroup, notify = activeQualityChangesGroupChanged) def activeQualityChangesGroup(self): diff --git a/cura/Settings/SimpleModeSettingsManager.py b/cura/Settings/SimpleModeSettingsManager.py index 867a21702c..a337d8b04e 100644 --- a/cura/Settings/SimpleModeSettingsManager.py +++ b/cura/Settings/SimpleModeSettingsManager.py @@ -16,7 +16,8 @@ class SimpleModeSettingsManager(QObject): self._is_profile_user_created = False # True when profile was custom created by user self._machine_manager.activeStackValueChanged.connect(self._updateIsProfileCustomized) - self._machine_manager.activeQualityChanged.connect(self._updateIsProfileUserCreated) + self._machine_manager.activeQualityGroupChanged.connect(self._updateIsProfileUserCreated) + self._machine_manager.activeQualityChangesGroupChanged.connect(self._updateIsProfileUserCreated) # update on create as the activeQualityChanged signal is emitted before this manager is created when Cura starts self._updateIsProfileCustomized() diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index a8af3fc3dd..aa6f3ce1de 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -111,7 +111,6 @@ Item // Set selected value if (Cura.MachineManager.activeQualityType == qualityItem.quality_type) { - // set to -1 when switching to user created profile so all ticks are clickable if (Cura.SimpleModeSettingsManager.isProfileUserCreated) { qualityModel.qualitySliderActiveIndex = -1 @@ -474,7 +473,7 @@ Item onClicked: { // if the current profile is user-created, switch to a built-in quality - Cura.MachineManager.clearQualityChangesGroup() + Cura.MachineManager.resetToUseDefaultQuality() } onEntered: { From 99d653cea5f04b346341fd4dffe4c7b7d87b3a13 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Thu, 15 Mar 2018 20:01:47 +0100 Subject: [PATCH 366/446] CURA-4870 Don't allow to connect more than one instance to the same group. --- cura/Settings/MachineManager.py | 8 ++++++ .../UM3NetworkPrinting/DiscoverUM3Action.py | 4 +++ .../UM3NetworkPrinting/DiscoverUM3Action.qml | 28 ++++++++++++++++--- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 9619329e59..b69d91c0d4 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1220,6 +1220,14 @@ class MachineManager(QObject): for container in hidden_containers: container.setMetaDataEntry("connect_group_name", group_name) + ## This method checks if there is an instance connected to the given network_key + def existNetworkInstances(self, network_key: str) -> bool: + metadata_filter = {"um_network_key": network_key} + containers = ContainerRegistry.getInstance().findContainerStacks(type = "machine", **metadata_filter) + if containers: + return True + return False + @pyqtSlot("QVariant") def setGlobalVariant(self, container_node): self.blurSettings.emit() diff --git a/plugins/UM3NetworkPrinting/DiscoverUM3Action.py b/plugins/UM3NetworkPrinting/DiscoverUM3Action.py index 76e8721fdd..0b8d6e9f53 100644 --- a/plugins/UM3NetworkPrinting/DiscoverUM3Action.py +++ b/plugins/UM3NetworkPrinting/DiscoverUM3Action.py @@ -147,6 +147,10 @@ class DiscoverUM3Action(MachineAction): return "" + @pyqtSlot(str, result = bool) + def existsKey(self, key) -> bool: + return Application.getInstance().getMachineManager().existNetworkInstances(network_key = key) + @pyqtSlot() def loadConfigurationFromPrinter(self): machine_manager = Application.getInstance().getMachineManager() diff --git a/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml b/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml index 079e5dcdd3..e7df22b546 100644 --- a/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml +++ b/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml @@ -5,6 +5,7 @@ import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Layouts 1.1 import QtQuick.Window 2.1 +import QtQuick.Dialogs 1.2 Cura.MachineAction { @@ -33,15 +34,34 @@ Cura.MachineAction { var printerKey = base.selectedDevice.key var printerName = base.selectedDevice.name // TODO To change when the groups have a name - if(manager.getStoredKey() != printerKey) + if (manager.getStoredKey() != printerKey) { - manager.setKey(printerKey) - manager.setGroupName(printerName) // TODO To change when the groups have a name - completed() + // Check if there is another instance with the same key + if (!manager.existsKey(printerKey)) + { + manager.setKey(printerKey) + manager.setGroupName(printerName) // TODO To change when the groups have a name + completed() + } + else + { + existingConnectionDialog.open() + } } } } + MessageDialog + { + id: existingConnectionDialog + title: catalog.i18nc("@window:title", "Existing Connection") + icon: StandardIcon.Information + text: catalog.i18nc("@message:text", "There is an instance already connected to this group") + detailedText: catalog.i18nc("@message:description", "You can't connect two instances to the same group. Please use the other instance or connect to another group.") + standardButtons: StandardButton.Ok + modality: Qt.ApplicationModal + } + Column { anchors.fill: parent; From 2a811c62d8c2b3dcb07ab84378a33047a232c092 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 15 Mar 2018 23:58:22 +0100 Subject: [PATCH 367/446] Ignore the first press after the selection has been cleared if the selection is cleared with this tool active, there is no way to switch to another tool than to re-select an object (by clicking it) because the tool buttons in the toolbar will have been disabled. The mouse-event happens after the selection is changed, so we need to keep track of what the selection was previously by monitoring the selection state. --- plugins/SupportEraser/SupportEraser.py | 47 +++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/plugins/SupportEraser/SupportEraser.py b/plugins/SupportEraser/SupportEraser.py index ee59fc5258..2afb3dfaab 100644 --- a/plugins/SupportEraser/SupportEraser.py +++ b/plugins/SupportEraser/SupportEraser.py @@ -4,7 +4,7 @@ import os import os.path -from PyQt5.QtCore import Qt, QUrl +from PyQt5.QtCore import Qt, QTimer from UM.Math.Vector import Vector from UM.Tool import Tool @@ -39,10 +39,28 @@ class SupportEraser(Tool): self._selection_pass = None Application.getInstance().globalContainerStackChanged.connect(self._updateEnabled) + # Note: if the selection is cleared with this tool active, there is no way to switch to + # another tool than to reselect an object (by clicking it) because the tool buttons in the + # toolbar will have been disabled. That is why we need to ignore the first press event + # after the selection has been cleared. + Selection.selectionChanged.connect(self._onSelectionChanged) + self._had_selection = False + self._skip_press = False + + self._had_selection_timer = QTimer() + self._had_selection_timer.setInterval(0) + self._had_selection_timer.setSingleShot(True) + self._had_selection_timer.timeout.connect(self._selectionChangeDelay) + def event(self, event): super().event(event) if event.type == Event.MousePressEvent and self._controller.getToolsEnabled(): + if self._skip_press: + # The selection was previously cleared, do not add/remove an anti-support mesh but + # use this click for selection and reactivating this tool only. + self._skip_press = False + return if self._selection_pass is None: # The selection renderpass is used to identify objects in the current view @@ -119,10 +137,10 @@ class SupportEraser(Tool): Application.getInstance().getController().getScene().sceneChanged.emit(node) # Select the picked node so the group does not get drawn as a wireframe (yet) - if Selection.isSelected(group): - Selection.remove(group) if not Selection.isSelected(parent): Selection.add(parent) + if Selection.isSelected(group): + Selection.remove(group) def _removeEraserMesh(self, node: CuraSceneNode): group = node.getParent() @@ -138,10 +156,10 @@ class SupportEraser(Tool): Application.getInstance().getController().getScene().sceneChanged.emit(node) # Select the picked node so the group does not get drawn as a wireframe (yet) - if Selection.isSelected(group): - Selection.remove(group) if parent and not Selection.isSelected(parent): Selection.add(parent) + if Selection.isSelected(group): + Selection.remove(group) def _updateEnabled(self): plugin_enabled = False @@ -151,3 +169,22 @@ class SupportEraser(Tool): plugin_enabled = global_container_stack.getProperty("anti_overhang_mesh", "enabled") Application.getInstance().getController().toolEnabledChanged.emit(self._plugin_id, plugin_enabled) + + + + def _onSelectionChanged(self): + # When selection is passed from one object to another object, first the selection is cleared + # and then it is set to the new object. We are only interested in the change from no selection + # to a selection or vice-versa, not in a change from one object to another. A timer is used to + # "merge" a possible clear/select action in a single frame + if Selection.hasSelection() != self._had_selection: + self._had_selection_timer.start() + + def _selectionChangeDelay(self): + has_selection = Selection.hasSelection() + if not has_selection and self._had_selection: + self._skip_press = True + else: + self._skip_press = False + + self._had_selection = has_selection From 579df7537be4a48be1f7e07bc119e5211e92b58f Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 16 Mar 2018 10:03:36 +0100 Subject: [PATCH 368/446] Fix upgrade from 26 to 27 Missing definition changes container. --- .../VersionUpgrade26to27/VersionUpgrade26to27.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/VersionUpgrade/VersionUpgrade26to27/VersionUpgrade26to27.py b/plugins/VersionUpgrade/VersionUpgrade26to27/VersionUpgrade26to27.py index a2d78d8d9f..2037a0211d 100644 --- a/plugins/VersionUpgrade/VersionUpgrade26to27/VersionUpgrade26to27.py +++ b/plugins/VersionUpgrade/VersionUpgrade26to27/VersionUpgrade26to27.py @@ -153,6 +153,10 @@ class VersionUpgrade26to27(VersionUpgrade): if new_id is not None: parser.set("containers", key, new_id) + if "6" not in parser["containers"]: + parser["containers"]["6"] = parser["containers"]["5"] + parser["containers"]["5"] = "empty" + for each_section in ("general", "metadata"): if not parser.has_section(each_section): parser.add_section(each_section) From 518423f25b5a7d84c684ba52cce2451152689124 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 16 Mar 2018 10:14:08 +0100 Subject: [PATCH 369/446] Fix broken settingsEnabled --- resources/qml/SidebarSimple.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index aa6f3ce1de..1feabfb40f 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -19,7 +19,7 @@ Item property Action configureSettings; property variant minimumPrintTime: PrintInformation.minimumPrintTime; property variant maximumPrintTime: PrintInformation.maximumPrintTime; - property bool settingsEnabled: extrudersEnabledCount.properties.value == 1 + property bool settingsEnabled: Cura.ExtruderManager.activeExtruderStackId || extrudersEnabledCount.properties.value == 1 Component.onCompleted: PrintInformation.enabled = true Component.onDestruction: PrintInformation.enabled = false From d78e2d56f7b49527a654083490cfabccd3fdecf3 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 16 Mar 2018 10:33:20 +0100 Subject: [PATCH 370/446] Fix quality and variant processing in project loading From version 22 to 24, there is an upgrade for "quality" that changes it to "quality_changes", but for "quality", we don't have any upgrades. --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index f5daa77bb0..214623c92d 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -280,6 +280,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # Check if any quality_changes instance container is in conflict. instance_container_files = [name for name in cura_file_names if name.endswith(self._instance_container_suffix)] quality_name = "" + custom_quality_name = "" num_settings_overriden_by_quality_changes = 0 # How many settings are changed by the quality changes num_user_settings = 0 quality_changes_conflict = False @@ -292,7 +293,14 @@ class ThreeMFWorkspaceReader(WorkspaceReader): container_id = self._stripFileToId(instance_container_file_name) serialized = archive.open(instance_container_file_name).read().decode("utf-8") - serialized = InstanceContainer._updateSerialized(serialized, instance_container_file_name) + + # Qualities and variants don't have upgrades, so don't upgrade them + parser = ConfigParser(interpolation = None) + parser.read_string(serialized) + container_type = parser["metadata"]["type"] + if container_type not in ("quality", "variant"): + serialized = InstanceContainer._updateSerialized(serialized, instance_container_file_name) + parser = ConfigParser(interpolation = None) parser.read_string(serialized) container_info = ContainerInfo(instance_container_file_name, serialized, parser) @@ -309,7 +317,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): position = parser["metadata"]["position"] self._machine_info.quality_changes_info.extruder_info_dict[position] = container_info - quality_name = parser["general"]["name"] + custom_quality_name = parser["general"]["name"] values = parser["values"] if parser.has_section("values") else dict() num_settings_overriden_by_quality_changes += len(values) # Check if quality changes already exists. @@ -473,6 +481,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader): extruders = num_extruders * [""] + quality_name = custom_quality_name if custom_quality_name else quality_name + self._machine_info.container_id = global_stack_id self._machine_info.name = machine_name self._machine_info.definition_id = machine_definition_id From a11595657518bf9436725c06b083bc3e854c3430 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 16 Mar 2018 10:40:16 +0100 Subject: [PATCH 371/446] Do not show a material itself in its linked material list --- cura/Settings/ContainerManager.py | 7 +++++-- resources/qml/Preferences/MaterialView.qml | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index 7161169b22..760a288b7b 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -348,15 +348,18 @@ class ContainerManager(QObject): # # \param material_id \type{str} the id of the material for which to get the linked materials. # \return \type{list} a list of names of materials with the same GUID - @pyqtSlot("QVariant", result = "QStringList") - def getLinkedMaterials(self, material_node): + @pyqtSlot("QVariant", bool, result = "QStringList") + def getLinkedMaterials(self, material_node, exclude_self = False): guid = material_node.metadata["GUID"] + self_root_material_id = material_node.metadata["base_file"] material_group_list = self._material_manager.getMaterialGroupListByGUID(guid) linked_material_names = [] if material_group_list: for material_group in material_group_list: + if exclude_self and material_group.name == self_root_material_id: + continue linked_material_names.append(material_group.root_material_node.metadata["name"]) return linked_material_names diff --git a/resources/qml/Preferences/MaterialView.qml b/resources/qml/Preferences/MaterialView.qml index d2f653e650..50dc6b65a4 100644 --- a/resources/qml/Preferences/MaterialView.qml +++ b/resources/qml/Preferences/MaterialView.qml @@ -36,8 +36,8 @@ TabView if (!base.containerId || !base.editingEnabled) { return "" } - var linkedMaterials = Cura.ContainerManager.getLinkedMaterials(base.currentMaterialNode); - if (linkedMaterials.length <= 1) { + var linkedMaterials = Cura.ContainerManager.getLinkedMaterials(base.currentMaterialNode, true); + if (linkedMaterials.length == 0) { return "" } return linkedMaterials.join(", "); From 06d028652d3b58aebf93b0b2653cde8af203a744 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Fri, 16 Mar 2018 10:58:31 +0100 Subject: [PATCH 372/446] CURA-4870 Change code style --- cura/Settings/MachineManager.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index b69d91c0d4..77cce9cddb 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1224,9 +1224,7 @@ class MachineManager(QObject): def existNetworkInstances(self, network_key: str) -> bool: metadata_filter = {"um_network_key": network_key} containers = ContainerRegistry.getInstance().findContainerStacks(type = "machine", **metadata_filter) - if containers: - return True - return False + return bool(containers) @pyqtSlot("QVariant") def setGlobalVariant(self, container_node): From 6058f632df6226a27f8a21b21ed7ac252ddab1b9 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 16 Mar 2018 11:05:13 +0100 Subject: [PATCH 373/446] Fix Enter key handling on material management page --- resources/qml/Preferences/MaterialView.qml | 11 +++++++++++ resources/qml/Preferences/ReadOnlySpinBox.qml | 2 ++ resources/qml/Preferences/ReadOnlyTextField.qml | 2 ++ 3 files changed, 15 insertions(+) diff --git a/resources/qml/Preferences/MaterialView.qml b/resources/qml/Preferences/MaterialView.qml index 50dc6b65a4..ffc4eaba3a 100644 --- a/resources/qml/Preferences/MaterialView.qml +++ b/resources/qml/Preferences/MaterialView.qml @@ -99,6 +99,7 @@ TabView property var new_diameter_value: null; property var old_diameter_value: null; property var old_approximate_diameter_value: null; + property bool keyPressed: false onYes: { @@ -112,6 +113,16 @@ TabView properties.diameter = old_diameter_value; diameterSpinBox.value = properties.diameter; } + + onVisibilityChanged: + { + if (!visible && !keyPressed) + { + // If the user closes this dialog without clicking on any button, it's the same as clicking "No". + no(); + } + keyPressed = false; + } } Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Display Name") } diff --git a/resources/qml/Preferences/ReadOnlySpinBox.qml b/resources/qml/Preferences/ReadOnlySpinBox.qml index 5d0666d306..1bbef82b1e 100644 --- a/resources/qml/Preferences/ReadOnlySpinBox.qml +++ b/resources/qml/Preferences/ReadOnlySpinBox.qml @@ -34,6 +34,8 @@ Item anchors.fill: parent onEditingFinished: base.editingFinished() + Keys.onEnterPressed: base.editingFinished() + Keys.onReturnPressed: base.editingFinished() } Label diff --git a/resources/qml/Preferences/ReadOnlyTextField.qml b/resources/qml/Preferences/ReadOnlyTextField.qml index 9407475a9b..38d07d7d6a 100644 --- a/resources/qml/Preferences/ReadOnlyTextField.qml +++ b/resources/qml/Preferences/ReadOnlyTextField.qml @@ -29,6 +29,8 @@ Item anchors.fill: parent onEditingFinished: base.editingFinished() + Keys.onEnterPressed: base.editingFinished() + Keys.onReturnPressed: base.editingFinished() } Label From a03a57fd60c71a31ed1dabbacfaf6a1a54462837 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Fri, 16 Mar 2018 11:10:35 +0100 Subject: [PATCH 374/446] Change the URL for redirect when checking material compatibility. --- resources/qml/SidebarHeader.qml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 7baf13ca97..1ba04c387e 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -524,6 +524,8 @@ Column source: UM.Theme.getIcon("warning") width: UM.Theme.getSize("section_icon").width height: UM.Theme.getSize("section_icon").height + sourceSize.width: width + sourceSize.height: height color: UM.Theme.getColor("material_compatibility_warning") visible: !Cura.MachineManager.isCurrentSetupSupported } @@ -545,9 +547,7 @@ Column hoverEnabled: true onClicked: { // open the material URL with web browser - var version = UM.Application.version; - var machineName = Cura.MachineManager.activeMachine.definition.id; - var url = "https://ultimaker.com/materialcompatibility/" + version + "/" + machineName + "?utm_source=cura&utm_medium=software&utm_campaign=resources"; + var url = "https://ultimaker.com/incoming-links/cura/material-compatibilty" Qt.openUrlExternally(url); } onEntered: { From 32cee75e47560d5a5f87524e653a7c8b09c0d50c Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 15 Mar 2018 17:14:06 +0100 Subject: [PATCH 375/446] Respect order of preference of output formats Contributes to issue CURA-5097. --- .../RemovableDriveOutputDevice.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py b/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py index 1bfdbd4117..e719ba3286 100644 --- a/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py +++ b/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import os.path @@ -39,7 +39,7 @@ class RemovableDriveOutputDevice(OutputDevice): # MIME types available to the currently active machine? # def requestWrite(self, nodes, file_name = None, filter_by_machine = False, file_handler = None, **kwargs): - filter_by_machine = True # This plugin is indended to be used by machine (regardless of what it was told to do) + filter_by_machine = True # This plugin is intended to be used by machine (regardless of what it was told to do) if self._writing: raise OutputDeviceError.DeviceBusyError() @@ -56,7 +56,8 @@ class RemovableDriveOutputDevice(OutputDevice): machine_file_formats = [file_type.strip() for file_type in container.getMetaDataEntry("file_formats").split(";")] # Take the intersection between file_formats and machine_file_formats. - file_formats = list(filter(lambda file_format: file_format["mime_type"] in machine_file_formats, file_formats)) + format_by_mimetype = {format["mime_type"]: format for format in file_formats} + file_formats = [format_by_mimetype[mimetype] for mimetype in machine_file_formats] #Keep them ordered according to the preference in machine_file_formats. if len(file_formats) == 0: Logger.log("e", "There are no file formats available to write with!") From 747efda52b6b69be4871956b7248e1870d55ad6a Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Fri, 16 Mar 2018 11:51:52 +0100 Subject: [PATCH 376/446] CURA-4870 Hide the configuration selector if the connection is lost. --- .../qml/Menus/ConfigurationMenu/SyncButton.qml | 17 ++++++++--------- resources/qml/Sidebar.qml | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml index c292a792db..8fe9dacf9a 100644 --- a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml +++ b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml @@ -68,7 +68,8 @@ Button color: UM.Theme.getColor("text_emphasis") source: UM.Theme.getIcon("arrow_bottom") } - UM.RecolorImage { + UM.RecolorImage + { id: sidebarComboBoxLabel anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("default_margin").width @@ -86,17 +87,15 @@ Button label: Label {} } - Connections { + Connections + { target: outputDevice - onUniqueConfigurationsChanged: { - updateOnSync() - } + onUniqueConfigurationsChanged: updateOnSync() } - Connections { + Connections + { target: Cura.MachineManager - onCurrentConfigurationChanged: { - updateOnSync() - } + onCurrentConfigurationChanged: updateOnSync() } } \ No newline at end of file diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml index 4744bbfda0..1c1bfca7c3 100644 --- a/resources/qml/Sidebar.qml +++ b/resources/qml/Sidebar.qml @@ -109,7 +109,7 @@ Rectangle ConfigurationSelection { id: configSelection - visible: isNetworkPrinter + visible: isNetworkPrinter && printerConnected width: visible ? Math.round(base.width * 0.15) : 0 height: UM.Theme.getSize("sidebar_header").height anchors.top: base.top From 36c5e0ad15365c1b48f0f64fcda7741eb6187440 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Fri, 16 Mar 2018 12:07:05 +0100 Subject: [PATCH 377/446] CURA-4870 Change message of the dialog when the connection with a printer/group already exists --- plugins/UM3NetworkPrinting/DiscoverUM3Action.qml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml b/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml index e7df22b546..0aaeef8fbd 100644 --- a/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml +++ b/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml @@ -56,8 +56,7 @@ Cura.MachineAction id: existingConnectionDialog title: catalog.i18nc("@window:title", "Existing Connection") icon: StandardIcon.Information - text: catalog.i18nc("@message:text", "There is an instance already connected to this group") - detailedText: catalog.i18nc("@message:description", "You can't connect two instances to the same group. Please use the other instance or connect to another group.") + text: catalog.i18nc("@message:text", "This printer/group is already added to Cura. Please select another printer/group.") standardButtons: StandardButton.Ok modality: Qt.ApplicationModal } From 8e26d27e805ad030a2623f89dcfd6f75451d5211 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 16 Mar 2018 13:15:24 +0100 Subject: [PATCH 378/446] Fix crash when clicking a non-slicable node --- plugins/SupportEraser/SupportEraser.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/SupportEraser/SupportEraser.py b/plugins/SupportEraser/SupportEraser.py index 2afb3dfaab..58624ea058 100644 --- a/plugins/SupportEraser/SupportEraser.py +++ b/plugins/SupportEraser/SupportEraser.py @@ -66,6 +66,9 @@ class SupportEraser(Tool): # The selection renderpass is used to identify objects in the current view self._selection_pass = Application.getInstance().getRenderer().getRenderPass("selection") picked_node = self._controller.getScene().findObject(self._selection_pass.getIdAtPosition(event.x, event.y)) + if not picked_node: + # There is no slicable object at the picked location + return node_stack = picked_node.callDecoration("getStack") if node_stack: From ee4a6dc704ed0021812bad7c7c3de7ad06dd8499 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 16 Mar 2018 13:21:22 +0100 Subject: [PATCH 379/446] Always show confirm dialog upon material diameter change --- cura/Settings/MachineManager.py | 16 ---------------- resources/qml/Preferences/MaterialView.qml | 2 +- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 77cce9cddb..d3e85db107 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -738,22 +738,6 @@ class MachineManager(QObject): return result - ## Property to indicate if a machine has "specialized" material profiles. - # Some machines have their own material profiles that "override" the default catch all profiles. - @pyqtProperty(bool, notify = globalContainerChanged) - def filterMaterialsByMachine(self) -> bool: - if self._global_container_stack: - return Util.parseBool(self._global_container_stack.getMetaDataEntry("has_machine_materials", False)) - return False - - ## Property to indicate if a machine has "specialized" quality profiles. - # Some machines have their own quality profiles that "override" the default catch all profiles. - @pyqtProperty(bool, notify = globalContainerChanged) - def filterQualityByMachine(self) -> bool: - if self._global_container_stack: - return Util.parseBool(self._global_container_stack.getMetaDataEntry("has_machine_quality", False)) - return False - ## Get the Definition ID of a machine (specified by ID) # \param machine_id string machine id to get the definition ID of # \returns DefinitionID (string) if found, None otherwise diff --git a/resources/qml/Preferences/MaterialView.qml b/resources/qml/Preferences/MaterialView.qml index ffc4eaba3a..3b1c10fbbd 100644 --- a/resources/qml/Preferences/MaterialView.qml +++ b/resources/qml/Preferences/MaterialView.qml @@ -233,7 +233,7 @@ TabView var old_diameter = Cura.ContainerManager.getContainerProperty(base.containerId, "material_diameter", "value").toString(); var old_approximate_diameter = Cura.ContainerManager.getContainerMetaDataEntry(base.containerId, "approximate_diameter"); var new_approximate_diameter = getApproximateDiameter(value); - if (Cura.MachineManager.filterMaterialsByMachine && new_approximate_diameter != Cura.ExtruderManager.getActiveExtruderStack().approximateMaterialDiameter) + if (new_approximate_diameter != Cura.ExtruderManager.getActiveExtruderStack().approximateMaterialDiameter) { confirmDiameterChangeDialog.old_diameter_value = old_diameter; confirmDiameterChangeDialog.new_diameter_value = value; From 83168886d6cfafffc88ec9d7c55770f8631c3afe Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 16 Mar 2018 13:22:43 +0100 Subject: [PATCH 380/446] Parent added meshes to the parent node instead of creating a group This requires a small change in PlatformPhysics, or otherwise the added mesh would still drop down. --- cura/PlatformPhysics.py | 2 +- plugins/SupportEraser/SupportEraser.py | 41 +++----------------------- 2 files changed, 5 insertions(+), 38 deletions(-) diff --git a/cura/PlatformPhysics.py b/cura/PlatformPhysics.py index 3d9d5d5027..1a5d6ef837 100755 --- a/cura/PlatformPhysics.py +++ b/cura/PlatformPhysics.py @@ -71,7 +71,7 @@ class PlatformPhysics: # Move it downwards if bottom is above platform move_vector = Vector() - if Preferences.getInstance().getValue("physics/automatic_drop_down") and not (node.getParent() and node.getParent().callDecoration("isGroup")) and node.isEnabled(): #If an object is grouped, don't move it down + if Preferences.getInstance().getValue("physics/automatic_drop_down") 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 z_offset = node.callDecoration("getZOffset") if node.getDecorator(ZOffsetDecorator.ZOffsetDecorator) else 0 move_vector = move_vector.set(y = -bbox.bottom + z_offset) diff --git a/plugins/SupportEraser/SupportEraser.py b/plugins/SupportEraser/SupportEraser.py index 58624ea058..22dd9b6d9c 100644 --- a/plugins/SupportEraser/SupportEraser.py +++ b/plugins/SupportEraser/SupportEraser.py @@ -120,49 +120,16 @@ class SupportEraser(Tool): op = GroupedOperation() # First add the node to the scene, so it gets the expected transform op.addOperation(AddSceneNodeOperation(node, root)) - - # Determine the parent group the node should be put in - if parent.getParent().callDecoration("isGroup"): - group = parent.getParent() - else: - # Create a group-node - group = CuraSceneNode() - group.addDecorator(GroupDecorator()) - group.addDecorator(BuildPlateDecorator(active_build_plate)) - group.setParent(root) - center = parent.getPosition() - group.setPosition(center) - group.setCenterPosition(center) - op.addOperation(SetParentOperation(parent, group)) - - op.addOperation(SetParentOperation(node, group)) + op.addOperation(SetParentOperation(node, parent)) op.push() - Application.getInstance().getController().getScene().sceneChanged.emit(node) - # Select the picked node so the group does not get drawn as a wireframe (yet) - if not Selection.isSelected(parent): - Selection.add(parent) - if Selection.isSelected(group): - Selection.remove(group) + Application.getInstance().getController().getScene().sceneChanged.emit(node) def _removeEraserMesh(self, node: CuraSceneNode): - group = node.getParent() - if group.callDecoration("isGroup"): - parent = group.getChildren()[0] - - op = GroupedOperation() - op.addOperation(RemoveSceneNodeOperation(node)) - if len(group.getChildren()) == 2: - op.addOperation(SetParentOperation(parent, group.getParent())) - + op = RemoveSceneNodeOperation(node) op.push() - Application.getInstance().getController().getScene().sceneChanged.emit(node) - # Select the picked node so the group does not get drawn as a wireframe (yet) - if parent and not Selection.isSelected(parent): - Selection.add(parent) - if Selection.isSelected(group): - Selection.remove(group) + Application.getInstance().getController().getScene().sceneChanged.emit(node) def _updateEnabled(self): plugin_enabled = False From 78a7299fc59b8b665e49d370512442c02c2efadb Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 16 Mar 2018 14:38:56 +0100 Subject: [PATCH 381/446] Maintain a selection when removing a mesh, so the tool stays active --- plugins/SupportEraser/SupportEraser.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/SupportEraser/SupportEraser.py b/plugins/SupportEraser/SupportEraser.py index 22dd9b6d9c..8f89d212d0 100644 --- a/plugins/SupportEraser/SupportEraser.py +++ b/plugins/SupportEraser/SupportEraser.py @@ -126,9 +126,16 @@ class SupportEraser(Tool): Application.getInstance().getController().getScene().sceneChanged.emit(node) def _removeEraserMesh(self, node: CuraSceneNode): + parent = node.getParent() + if parent == self._controller.getScene().getRoot(): + parent = None + op = RemoveSceneNodeOperation(node) op.push() + if parent and not Selection.isSelected(parent): + Selection.add(parent) + Application.getInstance().getController().getScene().sceneChanged.emit(node) def _updateEnabled(self): From 4940f3b88baa5ec579cccb68d4beb80074b16dc1 Mon Sep 17 00:00:00 2001 From: THeijmans Date: Fri, 16 Mar 2018 14:39:01 +0100 Subject: [PATCH 382/446] Retraction minimum travel update Changed it to 2 or 3 times line width, similar as with the 0.4mm profiles. Was 5mm standard for all profiles with the 0.8mm printcore, except TPU. --- resources/variants/ultimaker3_aa0.8.inst.cfg | 1 + resources/variants/ultimaker3_bb0.8.inst.cfg | 2 +- resources/variants/ultimaker3_extended_aa0.8.inst.cfg | 1 + resources/variants/ultimaker3_extended_bb0.8.inst.cfg | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/resources/variants/ultimaker3_aa0.8.inst.cfg b/resources/variants/ultimaker3_aa0.8.inst.cfg index 0bccf91b7c..97ee3587cf 100644 --- a/resources/variants/ultimaker3_aa0.8.inst.cfg +++ b/resources/variants/ultimaker3_aa0.8.inst.cfg @@ -46,6 +46,7 @@ retraction_count_max = 25 retraction_extrusion_window = 1 retraction_hop = 2 retraction_hop_only_when_collides = True +retraction_min_travel = =line_width * 2 skin_overlap = 5 speed_equalize_flow_enabled = True speed_layer_0 = 20 diff --git a/resources/variants/ultimaker3_bb0.8.inst.cfg b/resources/variants/ultimaker3_bb0.8.inst.cfg index 41c6419ec1..828e3f35fe 100644 --- a/resources/variants/ultimaker3_bb0.8.inst.cfg +++ b/resources/variants/ultimaker3_bb0.8.inst.cfg @@ -58,7 +58,7 @@ retraction_extrusion_window = =retraction_amount retraction_hop = 2 retraction_hop_enabled = True retraction_hop_only_when_collides = True -retraction_min_travel = 5 +retraction_min_travel = =line_width * 3 retraction_prime_speed = 15 skin_overlap = 5 speed_layer_0 = 20 diff --git a/resources/variants/ultimaker3_extended_aa0.8.inst.cfg b/resources/variants/ultimaker3_extended_aa0.8.inst.cfg index 184416b06e..149b832514 100644 --- a/resources/variants/ultimaker3_extended_aa0.8.inst.cfg +++ b/resources/variants/ultimaker3_extended_aa0.8.inst.cfg @@ -46,6 +46,7 @@ retraction_count_max = 25 retraction_extrusion_window = 1 retraction_hop = 2 retraction_hop_only_when_collides = True +retraction_min_travel = =line_width * 2 skin_overlap = 5 speed_equalize_flow_enabled = True speed_layer_0 = 20 diff --git a/resources/variants/ultimaker3_extended_bb0.8.inst.cfg b/resources/variants/ultimaker3_extended_bb0.8.inst.cfg index 8a1a9373f3..541034f119 100644 --- a/resources/variants/ultimaker3_extended_bb0.8.inst.cfg +++ b/resources/variants/ultimaker3_extended_bb0.8.inst.cfg @@ -57,7 +57,7 @@ retraction_count_max = 15 retraction_extrusion_window = =retraction_amount retraction_hop = 2 retraction_hop_only_when_collides = True -retraction_min_travel = 5 +retraction_min_travel = =line_width * 3 retraction_prime_speed = 15 skin_overlap = 5 speed_layer_0 = 20 From f05944bf299bb31ecb0b45f3c282329317f89d10 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 16 Mar 2018 14:47:01 +0100 Subject: [PATCH 383/446] Switch to translate tool when ctrl-clicking --- plugins/SupportEraser/SupportEraser.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/SupportEraser/SupportEraser.py b/plugins/SupportEraser/SupportEraser.py index 8f89d212d0..615c52ff89 100644 --- a/plugins/SupportEraser/SupportEraser.py +++ b/plugins/SupportEraser/SupportEraser.py @@ -5,6 +5,7 @@ import os import os.path from PyQt5.QtCore import Qt, QTimer +from PyQt5.QtWidgets import QApplication from UM.Math.Vector import Vector from UM.Tool import Tool @@ -34,7 +35,7 @@ class SupportEraser(Tool): def __init__(self): super().__init__() self._shortcut_key = Qt.Key_G - self._controller = Application.getInstance().getController() + self._controller = self.getController() self._selection_pass = None Application.getInstance().globalContainerStackChanged.connect(self._updateEnabled) @@ -54,8 +55,14 @@ class SupportEraser(Tool): def event(self, event): super().event(event) + modifiers = QApplication.keyboardModifiers() + ctrl_is_active = modifiers & Qt.ControlModifier if event.type == Event.MousePressEvent and self._controller.getToolsEnabled(): + if ctrl_is_active: + self._controller.setActiveTool("TranslateTool") + return + if self._skip_press: # The selection was previously cleared, do not add/remove an anti-support mesh but # use this click for selection and reactivating this tool only. From e74191f2dbb814eab228060c5e867a9634edceac Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 16 Mar 2018 14:05:40 +0100 Subject: [PATCH 384/446] Cache preferred format I think that makes the code a bit easier to read. This is not really done to make it faster, just more semantic. Contributes to issue CURA-5097. --- .../RemovableDriveOutputDevice.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py b/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py index e719ba3286..184b6b8a20 100644 --- a/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py +++ b/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py @@ -62,14 +62,15 @@ class RemovableDriveOutputDevice(OutputDevice): if len(file_formats) == 0: Logger.log("e", "There are no file formats available to write with!") raise OutputDeviceError.WriteRequestFailedError(catalog.i18nc("@info:status", "There are no file formats available to write with!")) + preferred_format = file_formats[0] # Just take the first file format available. if file_handler is not None: - writer = file_handler.getWriterByMimeType(file_formats[0]["mime_type"]) + writer = file_handler.getWriterByMimeType(preferred_format["mime_type"]) else: - writer = Application.getInstance().getMeshFileHandler().getWriterByMimeType(file_formats[0]["mime_type"]) + writer = Application.getInstance().getMeshFileHandler().getWriterByMimeType(preferred_format["mime_type"]) - extension = file_formats[0]["extension"] + extension = preferred_format["extension"] if file_name is None: file_name = self._automaticFileName(nodes) From 5a5766f11a83b189831336587133f4aa972abcdf Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 16 Mar 2018 14:37:08 +0100 Subject: [PATCH 385/446] Choose correct stream depending on output mode We need a binary stream if we're writing in a binary format. Contributes to issue CURA-5097. --- .../RemovableDriveOutputDevice.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py b/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py index 184b6b8a20..c81e4a76bc 100644 --- a/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py +++ b/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py @@ -7,7 +7,7 @@ from UM.Application import Application from UM.Logger import Logger from UM.Message import Message from UM.FileHandler.WriteFileJob import WriteFileJob -from UM.Mesh.MeshWriter import MeshWriter +from UM.FileHandler.FileWriter import FileWriter #To check against the write modes (text vs. binary). from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator from UM.OutputDevice.OutputDevice import OutputDevice from UM.OutputDevice import OutputDeviceError @@ -82,8 +82,11 @@ class RemovableDriveOutputDevice(OutputDevice): try: Logger.log("d", "Writing to %s", file_name) # Using buffering greatly reduces the write time for many lines of gcode - self._stream = open(file_name, "wt", buffering = 1, encoding = "utf-8") - job = WriteFileJob(writer, self._stream, nodes, MeshWriter.OutputMode.TextMode) + if preferred_format["mode"] == FileWriter.OutputMode.TextMode: + self._stream = open(file_name, "wt", buffering = 1, encoding = "utf-8") + else: #Binary mode. + self._stream = open(file_name, "wb", buffering = 1) + job = WriteFileJob(writer, self._stream, nodes, preferred_format["mode"]) job.setFileName(file_name) job.progress.connect(self._onProgress) job.finished.connect(self._onFinished) From 4be947af5548d6131d59810f6962ed745e46b228 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 16 Mar 2018 14:55:20 +0100 Subject: [PATCH 386/446] Fix codestyle --- plugins/SupportEraser/SupportEraser.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/SupportEraser/SupportEraser.py b/plugins/SupportEraser/SupportEraser.py index 615c52ff89..3332b4181d 100644 --- a/plugins/SupportEraser/SupportEraser.py +++ b/plugins/SupportEraser/SupportEraser.py @@ -154,8 +154,6 @@ class SupportEraser(Tool): Application.getInstance().getController().toolEnabledChanged.emit(self._plugin_id, plugin_enabled) - - def _onSelectionChanged(self): # When selection is passed from one object to another object, first the selection is cleared # and then it is set to the new object. We are only interested in the change from no selection From 2aaaf106b40e79b4acc354cdf1f723a20391d6e6 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 16 Mar 2018 15:05:03 +0100 Subject: [PATCH 387/446] Fix update material in MachineManager CURA-5098 --- cura/Settings/MachineManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index d3e85db107..07548e21dd 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1109,7 +1109,7 @@ class MachineManager(QObject): from cura.Settings.CuraContainerStack import _ContainerIndexes context = PropertyEvaluationContext(extruder) context.context["evaluate_from_container_index"] = _ContainerIndexes.DefinitionChanges - material_diameter = self._global_container_stack.getProperty("material_diameter", "value", context) + material_diameter = extruder.getProperty("material_diameter", "value", context) candidate_materials = self._material_manager.getAvailableMaterials( self._global_container_stack.definition.getId(), current_variant_name, From 4d5013d3adb9ac7573eb5f62422c039c40ad6f92 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 16 Mar 2018 15:08:30 +0100 Subject: [PATCH 388/446] Remove unused variable The variable name is re-used lower in the code. This value is unused though. --- plugins/GCodeWriter/GCodeWriter.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/GCodeWriter/GCodeWriter.py b/plugins/GCodeWriter/GCodeWriter.py index 4b78a2a72a..ccd881afdc 100644 --- a/plugins/GCodeWriter/GCodeWriter.py +++ b/plugins/GCodeWriter/GCodeWriter.py @@ -111,7 +111,6 @@ class GCodeWriter(MeshWriter): prefix = ";SETTING_" + str(GCodeWriter.version) + " " # The prefix to put before each line. prefix_length = len(prefix) - quality_name = stack.qualityChanges.getName() quality_type = stack.quality.getMetaDataEntry("quality_type") container_with_profile = stack.qualityChanges if container_with_profile.getId() == "empty_quality_changes": From 5ca420394050bab6055ee9bb287e09b2bc04c54e Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 16 Mar 2018 15:12:26 +0100 Subject: [PATCH 389/446] Remove material types that have no fallbacks from fallback_materials_map CURA-5098 --- cura/Machines/MaterialManager.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cura/Machines/MaterialManager.py b/cura/Machines/MaterialManager.py index 0a82fcc764..b854dbf29e 100644 --- a/cura/Machines/MaterialManager.py +++ b/cura/Machines/MaterialManager.py @@ -107,6 +107,7 @@ class MaterialManager(QObject): # Map #2 # Lookup table for material type -> fallback material metadata, only for read-only materials grouped_by_type_dict = dict() + material_types_without_fallback = set() for root_material_id, material_node in self._material_group_map.items(): if not self._container_registry.isReadOnly(root_material_id): continue @@ -114,6 +115,7 @@ class MaterialManager(QObject): if material_type not in grouped_by_type_dict: grouped_by_type_dict[material_type] = {"generic": None, "others": []} + material_types_without_fallback.add(material_type) brand = material_node.root_material_node.metadata["brand"] if brand.lower() == "generic": to_add = True @@ -123,6 +125,10 @@ class MaterialManager(QObject): to_add = False # don't add if it's not the default diameter if to_add: grouped_by_type_dict[material_type] = material_node.root_material_node.metadata + material_types_without_fallback.remove(material_type) + # Remove the materials that have no fallback materials + for material_type in material_types_without_fallback: + del grouped_by_type_dict[material_type] self._fallback_materials_map = grouped_by_type_dict # Map #3 From 43ac565c20f0b65d8a8bd81a418333fdbba33d3b Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 16 Mar 2018 15:45:15 +0100 Subject: [PATCH 390/446] Fix visibility preset initialization CURA-5088 --- cura/Machines/Models/SettingVisibilityPresetsModel.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cura/Machines/Models/SettingVisibilityPresetsModel.py b/cura/Machines/Models/SettingVisibilityPresetsModel.py index e281d81c39..599dd982a8 100644 --- a/cura/Machines/Models/SettingVisibilityPresetsModel.py +++ b/cura/Machines/Models/SettingVisibilityPresetsModel.py @@ -45,6 +45,8 @@ class SettingVisibilityPresetsModel(ListModel): visible_settings = self._preferences.getValue("general/visible_settings") if not visible_settings: self._preferences.setValue("general/visible_settings", ";".join(self._active_preset_item["settings"])) + else: + self._onPreferencesChanged("general/visible_settings") self.activePresetChanged.emit() From 22d3cd928f653d69e061ea0adeba810f1efebcfc Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Fri, 16 Mar 2018 15:57:19 +0100 Subject: [PATCH 391/446] CURA-5090 Remove layer view data after clearing buildplate --- plugins/SimulationView/SimulationView.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 5c3dca9fae..456d64e250 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -158,7 +158,9 @@ class SimulationView(View): return self._nozzle_node def _onSceneChanged(self, node): - if node.getMeshData() is not None: + if node.getMeshData() is None: + self.resetLayerData() + else: self.setActivity(False) self.calculateMaxLayers() self.calculateMaxPathsOnLayer(self._current_layer_num) From 1c7344fb92319c366f3d64f422bb05531d389b82 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 16 Mar 2018 15:58:29 +0100 Subject: [PATCH 392/446] Fix for monitor stage ocasionally crashing --- plugins/MonitorStage/MonitorStage.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/MonitorStage/MonitorStage.py b/plugins/MonitorStage/MonitorStage.py index ed84a8d2ce..931c205fff 100644 --- a/plugins/MonitorStage/MonitorStage.py +++ b/plugins/MonitorStage/MonitorStage.py @@ -48,7 +48,11 @@ class MonitorStage(CuraStage): new_output_device = Application.getInstance().getMachineManager().printerOutputDevices[0] if new_output_device != self._printer_output_device: if self._printer_output_device: - self._printer_output_device.printersChanged.disconnect(self._onActivePrinterChanged) + try: + self._printer_output_device.printersChanged.disconnect(self._onActivePrinterChanged) + except TypeError: + # Ignore stupid "Not connected" errors. + pass self._printer_output_device = new_output_device From c1ea1320f08cf8a4c1a4e961675e4f449ebc4e38 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 16 Mar 2018 15:55:49 +0100 Subject: [PATCH 393/446] Implement GCodeGzWriter This plug-in outputs g-code to a gzipped archive. It is used for sending prints to the Ultimaker 3 family faster. Contributes to issue CURA-5097. --- plugins/GCodeGzWriter/GCodeGzWriter.py | 41 ++++++++++++++++++++++++++ plugins/GCodeGzWriter/__init__.py | 22 ++++++++++++++ plugins/GCodeGzWriter/plugin.json | 8 +++++ 3 files changed, 71 insertions(+) create mode 100644 plugins/GCodeGzWriter/GCodeGzWriter.py create mode 100644 plugins/GCodeGzWriter/__init__.py create mode 100644 plugins/GCodeGzWriter/plugin.json diff --git a/plugins/GCodeGzWriter/GCodeGzWriter.py b/plugins/GCodeGzWriter/GCodeGzWriter.py new file mode 100644 index 0000000000..4ced6d03ba --- /dev/null +++ b/plugins/GCodeGzWriter/GCodeGzWriter.py @@ -0,0 +1,41 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +import gzip +from io import StringIO, BufferedIOBase #To write the g-code to a temporary buffer, and for typing. +from typing import List + +from UM.Logger import Logger +from UM.Mesh.MeshWriter import MeshWriter #The class we're extending/implementing. +from UM.PluginRegistry import PluginRegistry +from UM.Scene.SceneNode import SceneNode #For typing. + +## A file writer that writes gzipped g-code. +# +# If you're zipping g-code, you might as well use gzip! +class GCodeGzWriter(MeshWriter): + ## Writes the gzipped g-code to a stream. + # + # Note that even though the function accepts a collection of nodes, the + # entire scene is always written to the file since it is not possible to + # separate the g-code for just specific nodes. + # + # \param stream The stream to write the gzipped g-code to. + # \param nodes This is ignored. + # \param mode Additional information on what type of stream to use. This + # must always be binary mode. + # \return Whether the write was successful. + def write(self, stream: BufferedIOBase, nodes: List[SceneNode], mode = MeshWriter.OutputMode.BinaryMode) -> bool: + if mode != MeshWriter.OutputMode.BinaryMode: + Logger.log("e", "GCodeGzWriter does not support text mode.") + return False + + #Get the g-code from the g-code writer. + gcode_textio = StringIO() #We have to convert the g-code into bytes. + success = PluginRegistry.getInstance().getPluginObject("GCodeWriter").write(gcode_textio, None) + if not success: #Writing the g-code failed. Then I can also not write the gzipped g-code. + return False + + result = gzip.compress(gcode_textio.getvalue()) + stream.write(result) + return True diff --git a/plugins/GCodeGzWriter/__init__.py b/plugins/GCodeGzWriter/__init__.py new file mode 100644 index 0000000000..c001467b3d --- /dev/null +++ b/plugins/GCodeGzWriter/__init__.py @@ -0,0 +1,22 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from . import GCodeGzWriter + +from UM.i18n import i18nCatalog +catalog = i18nCatalog("cura") + +def getMetaData(): + return { + "mesh_writer": { + "output": [{ + "extension": "gcode.gz", + "description": catalog.i18nc("@item:inlistbox", "Compressed G-code File"), + "mime_type": "application/gzip", + "mode": GCodeGzWriter.GCodeGzWriter.OutputMode.BinaryMode + }] + } + } + +def register(app): + return { "mesh_writer": GCodeGzWriter.GCodeGzWriter() } diff --git a/plugins/GCodeGzWriter/plugin.json b/plugins/GCodeGzWriter/plugin.json new file mode 100644 index 0000000000..9774e9a25c --- /dev/null +++ b/plugins/GCodeGzWriter/plugin.json @@ -0,0 +1,8 @@ +{ + "name": "Compressed G-code Writer", + "author": "Ultimaker B.V.", + "version": "1.0.0", + "description": "Writes g-code to a compressed archive.", + "api": 4, + "i18n-catalog": "cura" +} From 88912e39735ab8ea25a9823ebc49c970efcc5e04 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 16 Mar 2018 16:05:51 +0100 Subject: [PATCH 394/446] Encode as UTF-8 before writing to gz Turns out that gzip only accepts bytes as input, not str. Contributes to issue CURA-5097. --- plugins/GCodeGzWriter/GCodeGzWriter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/GCodeGzWriter/GCodeGzWriter.py b/plugins/GCodeGzWriter/GCodeGzWriter.py index 4ced6d03ba..06fafb5995 100644 --- a/plugins/GCodeGzWriter/GCodeGzWriter.py +++ b/plugins/GCodeGzWriter/GCodeGzWriter.py @@ -36,6 +36,6 @@ class GCodeGzWriter(MeshWriter): if not success: #Writing the g-code failed. Then I can also not write the gzipped g-code. return False - result = gzip.compress(gcode_textio.getvalue()) + result = gzip.compress(gcode_textio.getvalue().encode("utf-8")) stream.write(result) return True From 0efde6bae647d74868a98fdb6b4d9133df2b8405 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 16 Mar 2018 16:08:49 +0100 Subject: [PATCH 395/446] Use gzipped gcode by default for UM3 For the network printing output device this doesn't work yet, but for removable drives it will now put g-code in a gz archive when storing it. Contributes to issue CURA-5097. --- resources/definitions/ultimaker3.def.json | 2 +- resources/definitions/ultimaker3_extended.def.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/definitions/ultimaker3.def.json b/resources/definitions/ultimaker3.def.json index ef41686752..05f74c6342 100644 --- a/resources/definitions/ultimaker3.def.json +++ b/resources/definitions/ultimaker3.def.json @@ -6,7 +6,7 @@ "author": "Ultimaker", "manufacturer": "Ultimaker B.V.", "visible": true, - "file_formats": "text/x-gcode", + "file_formats": "application/gzip;text/x-gcode", "platform": "ultimaker3_platform.obj", "platform_texture": "Ultimaker3backplate.png", "platform_offset": [0, 0, 0], diff --git a/resources/definitions/ultimaker3_extended.def.json b/resources/definitions/ultimaker3_extended.def.json index 3a1be3a303..1e6c322c73 100644 --- a/resources/definitions/ultimaker3_extended.def.json +++ b/resources/definitions/ultimaker3_extended.def.json @@ -7,7 +7,7 @@ "manufacturer": "Ultimaker B.V.", "quality_definition": "ultimaker3", "visible": true, - "file_formats": "text/x-gcode", + "file_formats": "application/gzip;text/x-gcode", "platform": "ultimaker3_platform.obj", "platform_texture": "Ultimaker3Extendedbackplate.png", "platform_offset": [0, 0, 0], From 7bf8e399ffbcb71b1592f4a1385ef2568e421662 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 19 Mar 2018 09:45:29 +0100 Subject: [PATCH 396/446] Should always reslice upon settings changed CURA-5115 When we switch a model from "support mesh" for example to "normal", there will be no setting values in the per-object settings container, but we should still trigger a reslice because settings have been changed. --- cura/Settings/SettingOverrideDecorator.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/cura/Settings/SettingOverrideDecorator.py b/cura/Settings/SettingOverrideDecorator.py index 9054d9d04f..d7ae43f938 100644 --- a/cura/Settings/SettingOverrideDecorator.py +++ b/cura/Settings/SettingOverrideDecorator.py @@ -94,12 +94,7 @@ class SettingOverrideDecorator(SceneNodeDecorator): return any(bool(self._stack.getProperty(setting, "value")) for setting in self._non_printing_mesh_settings) def _onSettingChanged(self, instance, property_name): # Reminder: 'property' is a built-in function - object_has_instance_setting = False - for container in self._stack.getContainers(): - if container.hasProperty(instance, "value"): - object_has_instance_setting = True - break - if property_name == "value" and object_has_instance_setting: + if property_name == "value": # Trigger slice/need slicing if the value has changed. self._is_non_printing_mesh = self.evaluateIsNonPrintingMesh() From bd775cf32eeaf328a4bdf7ca319393c0cd43bb4c Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 19 Mar 2018 10:56:40 +0100 Subject: [PATCH 397/446] CURA-4400 fix support_extruder_nr values in overhang angle and SliceInfo --- cura/Scene/CuraSceneNode.py | 2 +- cura/Settings/CuraContainerStack.py | 8 ++++++++ plugins/SliceInfoPlugin/SliceInfo.py | 4 ++-- plugins/SolidView/SolidView.py | 4 ++-- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/cura/Scene/CuraSceneNode.py b/cura/Scene/CuraSceneNode.py index b29108d636..48d271a2f2 100644 --- a/cura/Scene/CuraSceneNode.py +++ b/cura/Scene/CuraSceneNode.py @@ -41,7 +41,7 @@ class CuraSceneNode(SceneNode): # Use the support extruder instead of the active extruder if this is a support_mesh if per_mesh_stack: if per_mesh_stack.getProperty("support_mesh", "value"): - return extruders[int(global_container_stack.getProperty("support_extruder_nr", "value"))] + return extruders[int(global_container_stack.getExtruderPositionValueWithDefault("support_extruder_nr"))] # It's only set if you explicitly choose an extruder extruder_id = self.callDecoration("getActiveExtruder") diff --git a/cura/Settings/CuraContainerStack.py b/cura/Settings/CuraContainerStack.py index 00db4f57c7..ca4f866598 100755 --- a/cura/Settings/CuraContainerStack.py +++ b/cura/Settings/CuraContainerStack.py @@ -8,6 +8,7 @@ from typing import Any, Optional from PyQt5.QtCore import pyqtProperty, pyqtSignal, QObject from UM.FlameProfiler import pyqtSlot +from UM.Application import Application from UM.Decorators import override from UM.Logger import Logger from UM.Settings.ContainerStack import ContainerStack, InvalidContainerStackError @@ -314,6 +315,13 @@ class CuraContainerStack(ContainerStack): return cls._findInstanceContainerDefinitionId(definitions[0]) + ## getProperty for extruder positions, with translation from -1 to default extruder number + def getExtruderPositionValueWithDefault(self, key): + value = self.getProperty(key, "value") + if value == -1: + value = int(Application.getInstance().getMachineManager().defaultExtruderPosition) + return value + ## private: # Private helper class to keep track of container positions and their types. diff --git a/plugins/SliceInfoPlugin/SliceInfo.py b/plugins/SliceInfoPlugin/SliceInfo.py index 971a324aa2..e1c990c596 100755 --- a/plugins/SliceInfoPlugin/SliceInfo.py +++ b/plugins/SliceInfoPlugin/SliceInfo.py @@ -146,7 +146,7 @@ class SliceInfo(Extension): model_stack = node.callDecoration("getStack") if model_stack: model_settings["support_enabled"] = model_stack.getProperty("support_enable", "value") - model_settings["support_extruder_nr"] = int(model_stack.getProperty("support_extruder_nr", "value")) + model_settings["support_extruder_nr"] = int(model_stack.getExtruderPositionValueWithDefault("support_extruder_nr")) # Mesh modifiers; model_settings["infill_mesh"] = model_stack.getProperty("infill_mesh", "value") @@ -177,7 +177,7 @@ class SliceInfo(Extension): # Support settings print_settings["support_enabled"] = global_container_stack.getProperty("support_enable", "value") - print_settings["support_extruder_nr"] = int(global_container_stack.getProperty("support_extruder_nr", "value")) + print_settings["support_extruder_nr"] = int(global_container_stack.getExtruderPositionValueWithDefault("support_extruder_nr")) # Platform adhesion settings print_settings["adhesion_type"] = global_container_stack.getProperty("adhesion_type", "value") diff --git a/plugins/SolidView/SolidView.py b/plugins/SolidView/SolidView.py index de9f922267..ff5aab96d2 100644 --- a/plugins/SolidView/SolidView.py +++ b/plugins/SolidView/SolidView.py @@ -62,7 +62,7 @@ class SolidView(View): global_container_stack = Application.getInstance().getGlobalContainerStack() if global_container_stack: - support_extruder_nr = global_container_stack.getProperty("support_extruder_nr", "value") + support_extruder_nr = global_container_stack.getExtruderPositionValueWithDefault("support_extruder_nr") support_angle_stack = Application.getInstance().getExtruderManager().getExtruderStack(support_extruder_nr) if support_angle_stack is not None and Preferences.getInstance().getValue("view/show_overhang"): @@ -89,7 +89,7 @@ class SolidView(View): # Use the support extruder instead of the active extruder if this is a support_mesh if per_mesh_stack: if per_mesh_stack.getProperty("support_mesh", "value"): - extruder_index = int(global_container_stack.getProperty("support_extruder_nr", "value")) + extruder_index = int(global_container_stack.getExtruderPositionValueWithDefault("support_extruder_nr")) try: material_color = self._extruders_model.getItem(extruder_index)["color"] From 2660d158570e44958aee278f5e8699f7bf8023d2 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 19 Mar 2018 10:42:46 +0100 Subject: [PATCH 398/446] Make "show all settings" work CURA-5088 "Show All Settings" in setting visibility menu now sets all settings to be visible. --- .../Menus/SettingVisibilityPresetsMenu.qml | 5 +--- .../qml/Preferences/SettingVisibilityPage.qml | 4 +-- resources/qml/Settings/SettingView.qml | 29 ++++--------------- 3 files changed, 9 insertions(+), 29 deletions(-) diff --git a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml index 0753c83b17..47f8846050 100644 --- a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml +++ b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml @@ -13,11 +13,8 @@ Menu title: catalog.i18nc("@action:inmenu", "Visible Settings") property QtObject settingVisibilityPresetsModel: CuraApplication.getSettingVisibilityPresetsModel() - property bool showingSearchResults - property bool showingAllSettings signal showAllSettings() - signal showSettingVisibilityProfile() Instantiator { @@ -43,7 +40,7 @@ Menu MenuSeparator {} MenuItem { - text: catalog.i18nc("@action:inmenu", "All Settings") + text: catalog.i18nc("@action:inmenu", "Show All Settings") checkable: true checked: showingAllSettings exclusiveGroup: group diff --git a/resources/qml/Preferences/SettingVisibilityPage.qml b/resources/qml/Preferences/SettingVisibilityPage.qml index b6b1c133ed..d5ff57cb7c 100644 --- a/resources/qml/Preferences/SettingVisibilityPage.qml +++ b/resources/qml/Preferences/SettingVisibilityPage.qml @@ -72,11 +72,11 @@ UM.PreferencesPage { if(parent.checkedState == Qt.Unchecked || parent.checkedState == Qt.PartiallyChecked) { - definitionsModel.setAllVisible(true) + definitionsModel.setAllExpandedVisible(true) } else { - definitionsModel.setAllVisible(false) + definitionsModel.setAllExpandedVisible(false) } // After change set "Custom" option diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index cf9697210b..199db1bbaa 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -18,7 +18,6 @@ Item property QtObject settingVisibilityPresetsModel: CuraApplication.getSettingVisibilityPresetsModel() property Action configureSettings property bool findingSettings - property bool showingAllSettings signal showTooltip(Item item, point location, string text) signal hideTooltip() @@ -140,21 +139,9 @@ Item } menu: SettingVisibilityPresetsMenu { - showingSearchResults: findingSettings - showingAllSettings: showingAllSettings - onShowAllSettings: { - base.showingAllSettings = true; - base.findingSettings = false; - filter.text = ""; - filter.updateDefinitionModel(); - } - onShowSettingVisibilityProfile: - { - base.showingAllSettings = false; - base.findingSettings = false; - filter.text = ""; + definitionsModel.setAllVisible(true); filter.updateDefinitionModel(); } } @@ -219,10 +206,6 @@ Item findingSettings = (text.length > 0); if(findingSettings != lastFindingSettings) { - if(findingSettings) - { - showingAllSettings = false; - } updateDefinitionModel(); lastFindingSettings = findingSettings; } @@ -235,7 +218,7 @@ Item function updateDefinitionModel() { - if(findingSettings || showingAllSettings) + if(findingSettings) { expandedCategories = definitionsModel.expanded.slice(); definitionsModel.expanded = [""]; // keep categories closed while to prevent render while making settings visible one by one @@ -558,13 +541,13 @@ Item MenuItem { //: Settings context menu action - visible: !(findingSettings || showingAllSettings); + visible: !findingSettings text: catalog.i18nc("@action:menu", "Hide this setting"); onTriggered: { definitionsModel.hide(contextMenu.key); // visible settings have changed, so we're no longer showing a preset - if (settingVisibilityPresetsModel.activePreset != "" && !showingAllSettings) + if (settingVisibilityPresetsModel.activePreset != "") { settingVisibilityPresetsModel.setActivePreset("custom"); } @@ -584,7 +567,7 @@ Item return catalog.i18nc("@action:menu", "Keep this setting visible"); } } - visible: (findingSettings || showingAllSettings); + visible: findingSettings onTriggered: { if (contextMenu.settingVisible) @@ -596,7 +579,7 @@ Item definitionsModel.show(contextMenu.key); } // visible settings have changed, so we're no longer showing a preset - if (settingVisibilityPresetsModel.activePreset != "" && !showingAllSettings) + if (settingVisibilityPresetsModel.activePreset != "") { settingVisibilityPresetsModel.setActivePreset("custom"); } From d676b852899bf28d32d9bf8e4075f4962b82129a Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 19 Mar 2018 11:09:03 +0100 Subject: [PATCH 399/446] Fix createMaterial() for non-2.85 diameter materials CURA-5113 --- cura/Machines/MaterialManager.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cura/Machines/MaterialManager.py b/cura/Machines/MaterialManager.py index b854dbf29e..24c7ccb8c0 100644 --- a/cura/Machines/MaterialManager.py +++ b/cura/Machines/MaterialManager.py @@ -498,8 +498,10 @@ class MaterialManager(QObject): # Ensure all settings are saved. self._application.saveSettings() - global_stack = self._application.getGlobalContainerStack() - approximate_diameter = str(round(global_stack.getProperty("material_diameter", "value"))) + machine_manager = self._application.getMachineManager() + extruder_stack = machine_manager.activeStack + + approximate_diameter = str(extruder_stack.approximateMaterialDiameter) root_material_id = "generic_pla" root_material_id = self.getRootMaterialIDForDiameter(root_material_id, approximate_diameter) material_group = self.getMaterialGroup(root_material_id) From c1f9b455bbe0630e9c4e04f1622352ee8c3fd9ce Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 19 Mar 2018 11:22:55 +0100 Subject: [PATCH 400/446] Remove unnecessary import This import is not used. Contributes to issue CURA-5097. --- cura/PrinterOutput/NetworkedPrinterOutputDevice.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cura/PrinterOutput/NetworkedPrinterOutputDevice.py b/cura/PrinterOutput/NetworkedPrinterOutputDevice.py index 1537d51919..9da57a812e 100644 --- a/cura/PrinterOutput/NetworkedPrinterOutputDevice.py +++ b/cura/PrinterOutput/NetworkedPrinterOutputDevice.py @@ -1,9 +1,8 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from UM.Application import Application from UM.Logger import Logger -from UM.Settings.ContainerRegistry import ContainerRegistry from cura.CuraApplication import CuraApplication from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState @@ -232,7 +231,6 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice): reply.uploadProgress.connect(onProgress) self._registerOnFinishedCallback(reply, onFinished) - return reply def postForm(self, target: str, header_data: str, body_data: bytes, onFinished: Optional[Callable[[Any, QNetworkReply], None]], onProgress: Callable = None) -> None: From 5bb20f61334c6b3c3a1e82ff1c27d02e7adf3286 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 19 Mar 2018 11:24:15 +0100 Subject: [PATCH 401/446] Use preferred output writer This introduces a greenlet to allow optional interrupting of a function for waiting on the selectPrinter function. Contributes to issue CURA-5097. --- .../ClusterUM3OutputDevice.py | 115 +++++++++++++----- 1 file changed, 86 insertions(+), 29 deletions(-) diff --git a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py index c19c86d6ce..dfde76b233 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py @@ -1,12 +1,16 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from UM.FileHandler.FileWriter import FileWriter #To choose based on the output file mode (text vs. binary). +from UM.FileHandler.WriteFileJob import WriteFileJob #To call the file writer asynchronously. from UM.Logger import Logger from UM.Application import Application from UM.Settings.ContainerRegistry import ContainerRegistry from UM.i18n import i18nCatalog from UM.Message import Message from UM.Qt.Duration import Duration, DurationFormat +from UM.OutputDevice import OutputDeviceError #To show that something went wrong when writing. +from UM.Scene.SceneNode import SceneNode #For typing. from cura.PrinterOutput.NetworkedPrinterOutputDevice import NetworkedPrinterOutputDevice, AuthState from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel @@ -20,10 +24,11 @@ from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply from PyQt5.QtGui import QDesktopServices from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal, pyqtProperty, QObject -from time import time +from time import time, sleep from datetime import datetime from typing import Optional, Dict, List +import io #To create the correct buffers for sending data to the printer. import json import os @@ -79,24 +84,44 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): self._latest_reply_handler = None - def requestWrite(self, nodes, file_name=None, filter_by_machine=False, file_handler=None, **kwargs): + def requestWrite(self, nodes: List[SceneNode], file_name=None, filter_by_machine=False, file_handler=None, **kwargs): self.writeStarted.emit(self) - gcode_dict = getattr(Application.getInstance().getController().getScene(), "gcode_dict", []) - active_build_plate_id = Application.getInstance().getMultiBuildPlateModel().activeBuildPlate - gcode_list = gcode_dict[active_build_plate_id] - - if not gcode_list: - # Unable to find g-code. Nothing to send - return - - self._gcode = gcode_list - - is_job_sent = True - if len(self._printers) > 1: - self._spawnPrinterSelectionDialog() + #Formats supported by this application (file types that we can actually write). + if file_handler: + file_formats = file_handler.getSupportedFileTypesWrite() else: - is_job_sent = self.sendPrintJob() + file_formats = Application.getInstance().getMeshFileHandler().getSupportedFileTypesWrite() + + #Create a list from the supported file formats string. + container = Application.getInstance().getGlobalContainerStack().findContainer({"file_formats": "*"}) + machine_file_formats = [file_type.strip() for file_type in container.getMetaDataEntry("file_formats").split(";")] + + # Take the intersection between file_formats and machine_file_formats. + format_by_mimetype = {format["mime_type"]: format for format in file_formats} + file_formats = [format_by_mimetype[mimetype] for mimetype in machine_file_formats] #Keep them ordered according to the preference in machine_file_formats. + + if len(file_formats) == 0: + Logger.log("e", "There are no file formats available to write with!") + raise OutputDeviceError.WriteRequestFailedError(i18n_catalog.i18nc("@info:status", "There are no file formats available to write with!")) + preferred_format = file_formats[0] + + #Just take the first file format available. + if file_handler is not None: + writer = file_handler.getWriterByMimeType(preferred_format["mime_type"]) + else: + writer = Application.getInstance().getMeshFileHandler().getWriterByMimeType(preferred_format["mime_type"]) + + #This function pauses with the yield, waiting on instructions on which printer it needs to print with. + self._sending_job = self._sendPrintJob(writer, preferred_format, nodes) + self._sending_job.send(None) #Start the generator. + + if len(self._printers) > 1: #We need to ask the user. + self._spawnPrinterSelectionDialog() + is_job_sent = True + else: #Just immediately continue. + self._sending_job.send("") #No specifically selected printer. + is_job_sent = self._sending_job.send(None) # Notify the UI that a switch to the print monitor should happen if is_job_sent: @@ -113,29 +138,54 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): def clusterSize(self): return self._cluster_size - @pyqtSlot() + ## Allows the user to choose a printer to print with from the printer + # selection dialogue. + # \param target_printer The name of the printer to target. @pyqtSlot(str) - def sendPrintJob(self, target_printer: str = ""): + def selectPrinter(self, target_printer: str = "") -> None: + self._sending_job.send(target_printer) + + ## Greenlet to send a job to the printer over the network. + # + # This greenlet gets called asynchronously in requestWrite. It is a + # greenlet in order to optionally wait for selectPrinter() to select a + # printer. + # The greenlet yields exactly three times: First time None, + # \param writer The file writer to use to create the data. + # \param preferred_format A dictionary containing some information about + # what format to write to. This is necessary to create the correct buffer + # types and file extension and such. + def _sendPrintJob(self, writer: FileWriter, preferred_format: Dict, nodes: List[SceneNode]): Logger.log("i", "Sending print job to printer.") if self._sending_gcode: self._error_message = Message( i18n_catalog.i18nc("@info:status", "Sending new jobs (temporarily) blocked, still sending the previous print job.")) self._error_message.show() - return False + yield #Wait on the user to select a target printer. + yield #Wait for the write job to be finished. + yield False #Return whether this was a success or not. + yield #Prevent StopIteration. self._sending_gcode = True - self._progress_message = Message(i18n_catalog.i18nc("@info:status", "Sending data to printer"), 0, False, -1, - i18n_catalog.i18nc("@info:title", "Sending Data")) - self._progress_message.addAction("Abort", i18n_catalog.i18nc("@action:button", "Cancel"), None, "") + target_printer = yield #Potentially wait on the user to select a target printer. + + # Using buffering greatly reduces the write time for many lines of gcode + if preferred_format["mode"] == FileWriter.OutputMode.TextMode: + stream = io.StringIO() + else: #Binary mode. + stream = io.BytesIO() + + job = WriteFileJob(writer, stream, nodes, preferred_format["mode"]) + + self._progress_message = Message(i18n_catalog.i18nc("@info:status", "Sending data to printer"), lifetime = 0, dismissable = False, progress = -1, + title = i18n_catalog.i18nc("@info:title", "Sending Data")) + self._progress_message.addAction("Abort", i18n_catalog.i18nc("@action:button", "Cancel"), icon = None, description = "") self._progress_message.actionTriggered.connect(self._progressMessageActionTriggered) self._progress_message.show() - compressed_gcode = self._compressGCode() - if compressed_gcode is None: - # Abort was called. - return False + job.start() parts = [] @@ -149,11 +199,18 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): file_name = "%s.gcode.gz" % Application.getInstance().getPrintInformation().jobName - parts.append(self._createFormPart("name=\"file\"; filename=\"%s\"" % file_name, compressed_gcode)) + while not job.isFinished(): + sleep(0.1) + output = stream.getvalue() #Either str or bytes depending on the output mode. + if isinstance(stream, io.StringIO): + output = output.encode("utf-8") + + parts.append(self._createFormPart("name=\"file\"; filename=\"%s\"" % file_name, output)) self._latest_reply_handler = self.postFormWithParts("print_jobs/", parts, onFinished=self._onPostPrintJobFinished, onProgress=self._onUploadPrintJobProgress) - return True + yield True #Return that we had success! + yield #To prevent having to catch the StopIteration exception. @pyqtProperty(QObject, notify=activePrinterChanged) def activePrinter(self) -> Optional[PrinterOutputModel]: From af637d5acc34ffff87cf0ef3f6e2a7c3cffe1821 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 19 Mar 2018 11:33:17 +0100 Subject: [PATCH 402/446] Don't explode all nested groups when ungrouping groups of groups --- cura/CuraApplication.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 6056745c75..2e641f145a 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1401,6 +1401,10 @@ class CuraApplication(QtApplication): group_parent = node.getParent() children = node.getChildren().copy() for child in children: + # Ungroup only 1 level deep + if child.getParent() != node: + continue + # Set the parent of the children to the parent of the group-node op.addOperation(SetParentOperation(child, group_parent)) From 7a464a92ca6c8a630abeca75457e54902b301685 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 19 Mar 2018 11:39:41 +0100 Subject: [PATCH 403/446] Fix callback to output device with selected printer This is a new function that just selects the printer. Contributes to issue CURA-5097. --- plugins/UM3NetworkPrinting/PrintWindow.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/UM3NetworkPrinting/PrintWindow.qml b/plugins/UM3NetworkPrinting/PrintWindow.qml index d84b0f30ec..43afbcdfe0 100644 --- a/plugins/UM3NetworkPrinting/PrintWindow.qml +++ b/plugins/UM3NetworkPrinting/PrintWindow.qml @@ -101,7 +101,7 @@ UM.Dialog enabled: true onClicked: { base.visible = false; - OutputDevice.sendPrintJob(printerSelectionCombobox.model.get(printerSelectionCombobox.currentIndex).key) + OutputDevice.selectPrinter(printerSelectionCombobox.model.get(printerSelectionCombobox.currentIndex).key) // reset to defaults printerSelectionCombobox.currentIndex = 0 } From 906ebe12e168ba8887fb7c258ec702b9dff947a7 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 19 Mar 2018 11:46:43 +0100 Subject: [PATCH 404/446] CURA-4400 fix disallowed areas by fixing the limit_to_extruder -1 value --- cura/Settings/ExtruderStack.py | 3 +++ cura/Settings/GlobalStack.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/cura/Settings/ExtruderStack.py b/cura/Settings/ExtruderStack.py index 5cdcba68b0..1b12814ab0 100644 --- a/cura/Settings/ExtruderStack.py +++ b/cura/Settings/ExtruderStack.py @@ -5,6 +5,7 @@ from typing import Any, TYPE_CHECKING, Optional from PyQt5.QtCore import pyqtProperty, pyqtSignal +from UM.Application import Application from UM.Decorators import override from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase from UM.Settings.ContainerStack import ContainerStack @@ -111,6 +112,8 @@ class ExtruderStack(CuraContainerStack): limit_to_extruder = super().getProperty(key, "limit_to_extruder", context) if limit_to_extruder is not None: + if limit_to_extruder == -1: + limit_to_extruder = int(Application.getInstance().getMachineManager().defaultExtruderPosition) limit_to_extruder = str(limit_to_extruder) if (limit_to_extruder is not None and limit_to_extruder != "-1") and self.getMetaDataEntry("position") != str(limit_to_extruder): if str(limit_to_extruder) in self.getNextStack().extruders: diff --git a/cura/Settings/GlobalStack.py b/cura/Settings/GlobalStack.py index ae1f1370ed..5d8a4505a5 100755 --- a/cura/Settings/GlobalStack.py +++ b/cura/Settings/GlobalStack.py @@ -7,6 +7,7 @@ from typing import Any, Dict, Optional from PyQt5.QtCore import pyqtProperty +from UM.Application import Application from UM.Decorators import override from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase @@ -104,6 +105,8 @@ class GlobalStack(CuraContainerStack): # Handle the "limit_to_extruder" property. limit_to_extruder = super().getProperty(key, "limit_to_extruder", context) if limit_to_extruder is not None: + if limit_to_extruder == -1: + limit_to_extruder = int(Application.getInstance().getMachineManager().defaultExtruderPosition) limit_to_extruder = str(limit_to_extruder) if limit_to_extruder is not None and limit_to_extruder != "-1" and limit_to_extruder in self._extruders: if super().getProperty(key, "settable_per_extruder", context): From ba678511052ddcb7822390b1687c77140d658cc5 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 19 Mar 2018 12:08:18 +0100 Subject: [PATCH 405/446] Don't add a SettingOverrideDecorator twice CuraSceneNodes get a SettingOverrideDecorator automatically when constructed --- plugins/SupportEraser/SupportEraser.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/SupportEraser/SupportEraser.py b/plugins/SupportEraser/SupportEraser.py index 3332b4181d..cdb1c28414 100644 --- a/plugins/SupportEraser/SupportEraser.py +++ b/plugins/SupportEraser/SupportEraser.py @@ -108,12 +108,10 @@ class SupportEraser(Tool): node.setPosition(position) active_build_plate = Application.getInstance().getMultiBuildPlateModel().activeBuildPlate - - node.addDecorator(SettingOverrideDecorator()) node.addDecorator(BuildPlateDecorator(active_build_plate)) node.addDecorator(SliceableObjectDecorator()) - stack = node.callDecoration("getStack") # created by SettingOverrideDecorator + stack = node.callDecoration("getStack") # created by SettingOverrideDecorator that is automatically added to CuraSceneNode settings = stack.getTop() definition = stack.getSettingDefinition("anti_overhang_mesh") From 4a0b3ace9efa2a0ccff45801ba7b25a5768e6009 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 19 Mar 2018 12:23:35 +0100 Subject: [PATCH 406/446] Fix missing getExtruderPositionValueWithDefault() error PerObjectContainerStack was not a PerObjectContainerStack so it didn't have getExtruderPositionValueWithDefault(), and this will break SliceInfo. --- cura/Settings/PerObjectContainerStack.py | 11 ++++++----- cura/Settings/SettingOverrideDecorator.py | 7 ++++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/cura/Settings/PerObjectContainerStack.py b/cura/Settings/PerObjectContainerStack.py index 6c54ed46d5..33111cbed7 100644 --- a/cura/Settings/PerObjectContainerStack.py +++ b/cura/Settings/PerObjectContainerStack.py @@ -3,13 +3,14 @@ from typing import Any, Optional from UM.Application import Application from UM.Decorators import override from UM.Settings.Interfaces import PropertyEvaluationContext -from UM.Settings.ContainerStack import ContainerStack from UM.Settings.SettingInstance import InstanceState +from .CuraContainerStack import CuraContainerStack -class PerObjectContainerStack(ContainerStack): - @override(ContainerStack) +class PerObjectContainerStack(CuraContainerStack): + + @override(CuraContainerStack) def getProperty(self, key: str, property_name: str, context: Optional[PropertyEvaluationContext] = None) -> Any: if context is None: context = PropertyEvaluationContext() @@ -51,8 +52,8 @@ class PerObjectContainerStack(ContainerStack): context.popContainer() return result - @override(ContainerStack) - def setNextStack(self, stack: ContainerStack): + @override(CuraContainerStack) + def setNextStack(self, stack: CuraContainerStack): super().setNextStack(stack) # trigger signal to re-evaluate all default settings diff --git a/cura/Settings/SettingOverrideDecorator.py b/cura/Settings/SettingOverrideDecorator.py index d7ae43f938..e853a3a979 100644 --- a/cura/Settings/SettingOverrideDecorator.py +++ b/cura/Settings/SettingOverrideDecorator.py @@ -3,7 +3,6 @@ import copy -from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Scene.SceneNodeDecorator import SceneNodeDecorator from UM.Signal import Signal, signalemitter from UM.Settings.InstanceContainer import InstanceContainer @@ -33,9 +32,11 @@ class SettingOverrideDecorator(SceneNodeDecorator): def __init__(self): super().__init__() - self._stack = PerObjectContainerStack(stack_id = "per_object_stack_" + str(id(self))) + self._stack = PerObjectContainerStack(container_id = "per_object_stack_" + str(id(self))) self._stack.setDirty(False) # This stack does not need to be saved. - self._stack.addContainer(InstanceContainer(container_id = "SettingOverrideInstanceContainer")) + user_container = InstanceContainer(container_id = "SettingOverrideInstanceContainer") + user_container.addMetaDataEntry("type", "user") + self._stack.userChanges = user_container self._extruder_stack = ExtruderManager.getInstance().getExtruderStack(0).getId() self._is_non_printing_mesh = False From b13bfaa8e14b690cb036f8af2f5ac22c0f6f9868 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 19 Mar 2018 12:27:12 +0100 Subject: [PATCH 407/446] Rename setVariantGroup() -> setVariant() There is no such thing as VariantGroup. --- cura/Settings/MachineManager.py | 2 +- resources/qml/Menus/NozzleMenu.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 07548e21dd..6debd8d68e 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1227,7 +1227,7 @@ class MachineManager(QObject): self._updateQualityWithMaterial() @pyqtSlot(str, "QVariant") - def setVariantGroup(self, position, container_node): + def setVariant(self, position, container_node): position = str(position) self.blurSettings.emit() with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): diff --git a/resources/qml/Menus/NozzleMenu.qml b/resources/qml/Menus/NozzleMenu.qml index 43f3b79dd4..886216dab0 100644 --- a/resources/qml/Menus/NozzleMenu.qml +++ b/resources/qml/Menus/NozzleMenu.qml @@ -32,7 +32,7 @@ Menu } exclusiveGroup: group onTriggered: { - Cura.MachineManager.setVariantGroup(menu.extruderIndex, model.container_node); + Cura.MachineManager.setVariant(menu.extruderIndex, model.container_node); } } From e861a8a11234e9c65aad74df83963551ddbac4ea Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 19 Mar 2018 12:32:52 +0100 Subject: [PATCH 408/446] Add children to correct buildplate when multiplying --- cura/MultiplyObjectsJob.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/cura/MultiplyObjectsJob.py b/cura/MultiplyObjectsJob.py index 441d4c96c3..b9f37ec6f8 100644 --- a/cura/MultiplyObjectsJob.py +++ b/cura/MultiplyObjectsJob.py @@ -33,6 +33,7 @@ class MultiplyObjectsJob(Job): root = scene.getRoot() arranger = Arrange.create(scene_root=root) nodes = [] + for node in self._objects: # If object is part of a group, multiply group current_node = node @@ -49,18 +50,20 @@ class MultiplyObjectsJob(Job): for i in range(self._count): # We do place the nodes one by one, as we want to yield in between. if not node_too_big: - node, solution_found = arranger.findNodePlacement(current_node, offset_shape_arr, hull_shape_arr) + new_node, solution_found = arranger.findNodePlacement(current_node, offset_shape_arr, hull_shape_arr) if node_too_big or not solution_found: found_solution_for_all = False - new_location = node.getPosition() + new_location = new_node.getPosition() new_location = new_location.set(z = 100 - i * 20) - node.setPosition(new_location) + new_node.setPosition(new_location) # Same build plate build_plate_number = current_node.callDecoration("getBuildPlateNumber") - node.callDecoration("setBuildPlateNumber", build_plate_number) + new_node.callDecoration("setBuildPlateNumber", build_plate_number) + for child in new_node.getChildren(): + child.callDecoration("setBuildPlateNumber", build_plate_number) - nodes.append(node) + nodes.append(new_node) current_progress += 1 status_message.setProgress((current_progress / total_progress) * 100) Job.yieldThread() From 64d72c9d51584d9011497820f23420e620004582 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 19 Mar 2018 13:15:17 +0100 Subject: [PATCH 409/446] Fix where number of queued print jobs would be too big --- plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py index c19c86d6ce..a68eabe305 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py @@ -216,7 +216,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): @pyqtProperty("QVariantList", notify=printJobsChanged) def queuedPrintJobs(self) -> List[PrintJobOutputModel]: - return [print_job for print_job in self._print_jobs if print_job.assignedPrinter is None or print_job.state == "queued"] + return [print_job for print_job in self._print_jobs if print_job.state == "queued"] @pyqtProperty("QVariantList", notify=printJobsChanged) def activePrintJobs(self) -> List[PrintJobOutputModel]: From 6620909f3ddd5fd7b78ec4379ceefa7a84ac0521 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 19 Mar 2018 13:46:04 +0100 Subject: [PATCH 410/446] Remove non-existing showingAllSettings CURA-5088 --- resources/qml/Menus/SettingVisibilityPresetsMenu.qml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml index 47f8846050..2175cfa402 100644 --- a/resources/qml/Menus/SettingVisibilityPresetsMenu.qml +++ b/resources/qml/Menus/SettingVisibilityPresetsMenu.qml @@ -41,8 +41,7 @@ Menu MenuItem { text: catalog.i18nc("@action:inmenu", "Show All Settings") - checkable: true - checked: showingAllSettings + checkable: false exclusiveGroup: group onTriggered: { From 10ba9004498aa2ede128dc0c33274bd1cec7475d Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Mon, 19 Mar 2018 14:02:02 +0100 Subject: [PATCH 411/446] CURA-5090 empty layer data when new sliced data is empty and prevent some layer data to be processed if it is outdated --- .../CuraEngineBackend/CuraEngineBackend.py | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index af6162c8d5..e55abe59a2 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -224,7 +224,11 @@ class CuraEngineBackend(QObject, Backend): active_build_plate = Application.getInstance().getMultiBuildPlateModel().activeBuildPlate build_plate_to_be_sliced = self._build_plates_to_be_sliced.pop(0) Logger.log("d", "Going to slice build plate [%s]!" % build_plate_to_be_sliced) - num_objects = self._numObjects() + num_objects = self._numObjectsPerBuildPlate() + + self._stored_layer_data = [] + self._stored_optimized_layer_data[build_plate_to_be_sliced] = [] + if build_plate_to_be_sliced not in num_objects or num_objects[build_plate_to_be_sliced] == 0: self._scene.gcode_dict[build_plate_to_be_sliced] = [] Logger.log("d", "Build plate %s has no objects to be sliced, skipping", build_plate_to_be_sliced) @@ -232,9 +236,6 @@ class CuraEngineBackend(QObject, Backend): self.slice() return - self._stored_layer_data = [] - self._stored_optimized_layer_data[build_plate_to_be_sliced] = [] - if Application.getInstance().getPrintInformation() and build_plate_to_be_sliced == active_build_plate: Application.getInstance().getPrintInformation().setToZeroPrintInformation(build_plate_to_be_sliced) @@ -426,7 +427,7 @@ class CuraEngineBackend(QObject, Backend): return False ## Return a dict with number of objects per build plate - def _numObjects(self): + def _numObjectsPerBuildPlate(self): num_objects = defaultdict(int) for node in DepthFirstIterator(self._scene.getRoot()): # Only count sliceable objects @@ -453,7 +454,7 @@ class CuraEngineBackend(QObject, Backend): source_build_plate_number = source.callDecoration("getBuildPlateNumber") if source == self._scene.getRoot(): # we got the root node - num_objects = self._numObjects() + num_objects = self._numObjectsPerBuildPlate() for build_plate_number in list(self._last_num_objects.keys()) + list(num_objects.keys()): if build_plate_number not in self._last_num_objects or num_objects[build_plate_number] != self._last_num_objects[build_plate_number]: self._last_num_objects[build_plate_number] = num_objects[build_plate_number] @@ -604,7 +605,12 @@ class CuraEngineBackend(QObject, Backend): # See if we need to process the sliced layers job. active_build_plate = Application.getInstance().getMultiBuildPlateModel().activeBuildPlate - if self._layer_view_active and (self._process_layers_job is None or not self._process_layers_job.isRunning()) and active_build_plate == self._start_slice_job_build_plate: + if ( + self._layer_view_active and + (self._process_layers_job is None or not self._process_layers_job.isRunning()) and + active_build_plate == self._start_slice_job_build_plate and + active_build_plate not in self._build_plates_to_be_sliced): + self._startProcessSlicedLayersJob(active_build_plate) # self._onActiveViewChanged() self._start_slice_job_build_plate = None @@ -733,7 +739,11 @@ class CuraEngineBackend(QObject, Backend): # There is data and we're not slicing at the moment # if we are slicing, there is no need to re-calculate the data as it will be invalid in a moment. # TODO: what build plate I am slicing - if active_build_plate in self._stored_optimized_layer_data and not self._slicing and not self._process_layers_job: + if (active_build_plate in self._stored_optimized_layer_data and + not self._slicing and + not self._process_layers_job and + active_build_plate not in self._build_plates_to_be_sliced): + self._startProcessSlicedLayersJob(active_build_plate) else: self._layer_view_active = False From f0dc138b37858fb3e5b50df3d37e9a366548d8f0 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 19 Mar 2018 14:13:55 +0100 Subject: [PATCH 412/446] Fix visibilty preset update CURA-5088 --- cura/Machines/Models/SettingVisibilityPresetsModel.py | 10 +++++++--- resources/qml/Preferences/SettingVisibilityPage.qml | 9 --------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/cura/Machines/Models/SettingVisibilityPresetsModel.py b/cura/Machines/Models/SettingVisibilityPresetsModel.py index 599dd982a8..8880ac5ce1 100644 --- a/cura/Machines/Models/SettingVisibilityPresetsModel.py +++ b/cura/Machines/Models/SettingVisibilityPresetsModel.py @@ -165,14 +165,18 @@ class SettingVisibilityPresetsModel(ListModel): matching_preset_item = item break + item_to_set = self._active_preset_item if matching_preset_item is None: # The new visibility setup is "custom" should be custom if self._active_preset_item["id"] == "custom": # We are already in custom, just save the settings self._preferences.setValue("cura/custom_visible_settings", visibility_string) else: - self._active_preset_item = self.items[0] # 0 is custom - self.activePresetChanged.emit() + item_to_set = self.items[0] # 0 is custom else: - self._active_preset_item = matching_preset_item + item_to_set = matching_preset_item + + if self._active_preset_item is None or self._active_preset_item["id"] != item_to_set["id"]: + self._active_preset_item = item_to_set + self._preferences.setValue("cura/active_setting_visibility_preset", self._active_preset_item["id"]) self.activePresetChanged.emit() diff --git a/resources/qml/Preferences/SettingVisibilityPage.qml b/resources/qml/Preferences/SettingVisibilityPage.qml index d5ff57cb7c..0f39a3c047 100644 --- a/resources/qml/Preferences/SettingVisibilityPage.qml +++ b/resources/qml/Preferences/SettingVisibilityPage.qml @@ -78,15 +78,6 @@ UM.PreferencesPage { definitionsModel.setAllExpandedVisible(false) } - - // After change set "Custom" option - - // If already "Custom" then don't do nothing - if (visibilityPreset.currentIndex != visibilityPreset.model.count - 1) - { - visibilityPreset.currentIndex = visibilityPreset.model.count - 1 - UM.Preferences.setValue("cura/active_setting_visibility_preset", visibilityPreset.model.getItem(visibilityPreset.currentIndex).id) - } } } } From c9a23d5ca35452a7b366a28263020495439d6bf6 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 19 Mar 2018 14:21:41 +0100 Subject: [PATCH 413/446] Get the file formats directly from the stack Instead of finding the container that contains the entry first and then getting the metadata from there. Contributes to issue CURA-5097. --- plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py index dfde76b233..431adec145 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py @@ -94,8 +94,8 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): file_formats = Application.getInstance().getMeshFileHandler().getSupportedFileTypesWrite() #Create a list from the supported file formats string. - container = Application.getInstance().getGlobalContainerStack().findContainer({"file_formats": "*"}) - machine_file_formats = [file_type.strip() for file_type in container.getMetaDataEntry("file_formats").split(";")] + machine_file_formats = Application.getInstance().getGlobalContainerStack().getMetaDataEntry("file_formats").split(";") + machine_file_formats = [file_type.strip() for file_type in machine_file_formats] # Take the intersection between file_formats and machine_file_formats. format_by_mimetype = {format["mime_type"]: format for format in file_formats} From 91e1ae69ec52c954b2ad9c20b1254a32c0ed55c1 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 19 Mar 2018 14:35:08 +0100 Subject: [PATCH 414/446] Don't reparent nodes that are children of a selected node when grouping selection --- cura/CuraApplication.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 2e641f145a..6351d43c79 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1383,6 +1383,12 @@ class CuraApplication(QtApplication): group_node.setPosition(center) group_node.setCenterPosition(center) + # Remove nodes that are directly parented to another selected node from the selection so they remain parented + selected_nodes = Selection.getAllSelectedObjects().copy() + for node in selected_nodes: + if node.getParent() in selected_nodes and not node.getParent().callDecoration("isGroup"): + Selection.remove(node) + # Move selected nodes into the group-node Selection.applyOperation(SetParentOperation, group_node) From 6f9e0431bb5352f6b63dead481f16621e6019f38 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 19 Mar 2018 15:17:10 +0100 Subject: [PATCH 415/446] Fix extension when sending to printer It should use the extension of the preferred format. Contributes to issue CURA-5097. --- plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py index 431adec145..eda5841310 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py @@ -197,7 +197,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): # Add user name to the print_job parts.append(self._createFormPart("name=owner", bytes(self._getUserName(), "utf-8"), "text/plain")) - file_name = "%s.gcode.gz" % Application.getInstance().getPrintInformation().jobName + file_name = Application.getInstance().getPrintInformation().jobName + "." + preferred_format["extension"] while not job.isFinished(): sleep(0.1) From 4fc3c00e1d2a18b80592cbafa89acc7727db109d Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 19 Mar 2018 15:46:43 +0100 Subject: [PATCH 416/446] Fix position of added anti support meshes in group --- plugins/SupportEraser/SupportEraser.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/plugins/SupportEraser/SupportEraser.py b/plugins/SupportEraser/SupportEraser.py index cdb1c28414..7884ca30c7 100644 --- a/plugins/SupportEraser/SupportEraser.py +++ b/plugins/SupportEraser/SupportEraser.py @@ -19,10 +19,8 @@ from cura.Scene.CuraSceneNode import CuraSceneNode from cura.PickingPass import PickingPass -from UM.Operations.GroupedOperation import GroupedOperation from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation -from cura.Operations.SetParentOperation import SetParentOperation from cura.Scene.SliceableObjectDecorator import SliceableObjectDecorator from cura.Scene.BuildPlateDecorator import BuildPlateDecorator @@ -105,7 +103,6 @@ class SupportEraser(Tool): mesh = MeshBuilder() mesh.addCube(10,10,10) node.setMeshData(mesh.build()) - node.setPosition(position) active_build_plate = Application.getInstance().getMultiBuildPlateModel().activeBuildPlate node.addDecorator(BuildPlateDecorator(active_build_plate)) @@ -120,13 +117,9 @@ class SupportEraser(Tool): new_instance.resetState() # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) - root = self._controller.getScene().getRoot() - - op = GroupedOperation() - # First add the node to the scene, so it gets the expected transform - op.addOperation(AddSceneNodeOperation(node, root)) - op.addOperation(SetParentOperation(node, parent)) + op = AddSceneNodeOperation(node, parent) op.push() + node.setPosition(position, CuraSceneNode.TransformSpace.World) Application.getInstance().getController().getScene().sceneChanged.emit(node) From 864cbe9c636c3a88fbdd8516307cd995fb938941 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 19 Mar 2018 16:24:07 +0100 Subject: [PATCH 417/446] Add exception for UM3 to add UFP as supported format We can't just add it to the supported file formats in the definition because we don't want the removable drive output to write it. Contributes to issue CURA-5097. --- plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py index eda5841310..c804200701 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py @@ -11,6 +11,7 @@ from UM.Message import Message from UM.Qt.Duration import Duration, DurationFormat from UM.OutputDevice import OutputDeviceError #To show that something went wrong when writing. from UM.Scene.SceneNode import SceneNode #For typing. +from UM.Version import Version #To check against firmware versions for support. from cura.PrinterOutput.NetworkedPrinterOutputDevice import NetworkedPrinterOutputDevice, AuthState from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel @@ -96,6 +97,9 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): #Create a list from the supported file formats string. machine_file_formats = Application.getInstance().getGlobalContainerStack().getMetaDataEntry("file_formats").split(";") machine_file_formats = [file_type.strip() for file_type in machine_file_formats] + #Exception for UM3 firmware version >=4.4: UFP is now supported and should be the preferred file format. + if "application/x-ufp" not in machine_file_formats and self.printerType == "ultimaker3" and Version(self.firmwareVersion) >= Version("4.4"): + machine_file_formats = ["application/x-ufp"] + machine_file_formats # Take the intersection between file_formats and machine_file_formats. format_by_mimetype = {format["mime_type"]: format for format in file_formats} From 51e7a18d1cb246a4920e812a19fa9f2dc6e8e9ec Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 19 Mar 2018 17:25:49 +0100 Subject: [PATCH 418/446] Add high level functions for setting the variant, material and quality using the name, id and quality_type respectively. --- cura/Settings/MachineManager.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 6debd8d68e..e9c777cd4d 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1218,6 +1218,16 @@ class MachineManager(QObject): self._updateMaterialWithVariant(None) # Update all materials self._updateQualityWithMaterial() + @pyqtSlot(str, str) + def setMaterialById(self, position, root_material_id): + machine_definition_id = self._global_container_stack.definition.id + position = str(position) + extruder_stack = self._global_container_stack.extruders[position] + variant_name = extruder_stack.variant.getName() + material_diameter = extruder_stack.approximateMaterialDiameter + material_node = self._material_manager.getMaterialNode(machine_definition_id, variant_name, material_diameter, root_material_id) + self.setMaterial(position, material_node) + @pyqtSlot(str, "QVariant") def setMaterial(self, position, container_node): position = str(position) @@ -1226,6 +1236,12 @@ class MachineManager(QObject): self._setMaterial(position, container_node) self._updateQualityWithMaterial() + @pyqtSlot(str, str) + def setVariantByName(self, position, variant_name): + machine_definition_id = self._global_container_stack.definition.id + variant_node = self._variant_manager.getVariantNode(machine_definition_id, variant_name) + self.setVariant(position, variant_node) + @pyqtSlot(str, "QVariant") def setVariant(self, position, container_node): position = str(position) @@ -1235,6 +1251,13 @@ class MachineManager(QObject): self._updateMaterialWithVariant(position) self._updateQualityWithMaterial() + @pyqtSlot(str) + def setQualityGroupByQualityType(self, quality_type): + # Get all the quality groups for this global stack and filter out by quality_type + quality_group_dict = self._quality_manager.getQualityGroups(self._global_container_stack) + quality_group = quality_group_dict[quality_type] + self.setQualityGroup(quality_group) + @pyqtSlot(QObject) def setQualityGroup(self, quality_group, no_dialog = False): self.blurSettings.emit() From fff0a2519a885ed5edbd0915c793948ec392dd02 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 19 Mar 2018 17:28:09 +0100 Subject: [PATCH 419/446] Don't add a SettingOverrideDecorator twice --- plugins/3MFReader/ThreeMFReader.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/plugins/3MFReader/ThreeMFReader.py b/plugins/3MFReader/ThreeMFReader.py index 3a1298bdba..9b7b979e8a 100755 --- a/plugins/3MFReader/ThreeMFReader.py +++ b/plugins/3MFReader/ThreeMFReader.py @@ -16,7 +16,6 @@ from UM.Mesh.MeshBuilder import MeshBuilder from UM.Mesh.MeshReader import MeshReader from UM.Scene.GroupDecorator import GroupDecorator -from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator from cura.Settings.ExtruderManager import ExtruderManager from cura.Scene.CuraSceneNode import CuraSceneNode from cura.Scene.BuildPlateDecorator import BuildPlateDecorator @@ -81,7 +80,7 @@ class ThreeMFReader(MeshReader): active_build_plate = Application.getInstance().getMultiBuildPlateModel().activeBuildPlate - um_node = CuraSceneNode() + um_node = CuraSceneNode() # This adds a SettingOverrideDecorator um_node.addDecorator(BuildPlateDecorator(active_build_plate)) um_node.setName(node_name) transformation = self._createMatrixFromTransformationString(savitar_node.getTransformation()) @@ -110,8 +109,6 @@ class ThreeMFReader(MeshReader): # Add the setting override decorator, so we can add settings to this node. if settings: - um_node.addDecorator(SettingOverrideDecorator()) - global_container_stack = Application.getInstance().getGlobalContainerStack() # Ensure the correct next container for the SettingOverride decorator is set. From 5a9bcf446e9b34db6d54127e8847126f696a6ba5 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 19 Mar 2018 17:52:40 +0100 Subject: [PATCH 420/446] Do not select parented nodes when selecting all --- cura/CuraApplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 6351d43c79..98c682a8a3 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1105,7 +1105,7 @@ class CuraApplication(QtApplication): continue if not node.getMeshData() and not node.callDecoration("isGroup"): continue # Node that doesnt have a mesh and is not a group. - if node.getParent() and node.getParent().callDecoration("isGroup"): + if node.getParent() and node.getParent().callDecoration("isGroup") or node.getParent().callDecoration("isSliceable"): continue # Grouped nodes don't need resetting as their parent (the group) is resetted) if not node.isSelectable(): continue # i.e. node with layer data From 311b5ac7915b38b02e69c68ede4048d6d86d3c0f Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 19 Mar 2018 18:00:48 +0100 Subject: [PATCH 421/446] CURA-4870 Force update the list model also when the output device changes. --- .../ConfigurationListView.qml | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml index 999fecd7fd..88173195be 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -17,6 +17,13 @@ Column padding: UM.Theme.getSize("default_margin").width spacing: Math.round(UM.Theme.getSize("default_margin").height / 2) + function forceModelUpdate() + { + // FIXME For now the model should be removed and then created again, otherwise changes in the printer don't automatically update the UI + configurationList.model = [] + configurationList.model = outputDevice.uniqueConfigurations + } + Label { id: configurationListHeading @@ -78,9 +85,16 @@ Column target: outputDevice onUniqueConfigurationsChanged: { - // FIXME For now the model should be removed and then created again, otherwise changes in the printer don't automatically update the UI - configurationList.model = [] - configurationList.model = outputDevice.uniqueConfigurations + forceModelUpdate() + } + } + + Connections + { + target: Cura.MachineManager + onOutputDevicesChanged: + { + forceModelUpdate() } } } \ No newline at end of file From d123efd3eb97b9cef8d97d98b9c1a482c7f839b9 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 19 Mar 2018 18:25:40 +0100 Subject: [PATCH 422/446] Fix loading parented objects from 3mf files --- cura/Scene/BuildPlateDecorator.py | 2 +- plugins/3MFReader/ThreeMFReader.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/Scene/BuildPlateDecorator.py b/cura/Scene/BuildPlateDecorator.py index c2fd3145dd..dfb465b7ad 100644 --- a/cura/Scene/BuildPlateDecorator.py +++ b/cura/Scene/BuildPlateDecorator.py @@ -15,7 +15,7 @@ class BuildPlateDecorator(SceneNodeDecorator): self._build_plate_number = nr if isinstance(self._node, CuraSceneNode): self._node.transformChanged() # trigger refresh node without introducing a new signal - if self._node and self._node.callDecoration("isGroup"): + if self._node: for child in self._node.getChildren(): child.callDecoration("setBuildPlateNumber", nr) diff --git a/plugins/3MFReader/ThreeMFReader.py b/plugins/3MFReader/ThreeMFReader.py index 9b7b979e8a..6c2fb9a59d 100755 --- a/plugins/3MFReader/ThreeMFReader.py +++ b/plugins/3MFReader/ThreeMFReader.py @@ -137,7 +137,7 @@ class ThreeMFReader(MeshReader): continue setting_container.setProperty(key, "value", setting_value) - if len(um_node.getChildren()) > 0: + if len(um_node.getChildren()) > 0 and um_node.getMeshData() is None: group_decorator = GroupDecorator() um_node.addDecorator(group_decorator) um_node.setSelectable(True) From d7b0f11ddf9a762ffd4a8427b96ade21f54211e2 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Tue, 20 Mar 2018 11:17:39 +0100 Subject: [PATCH 423/446] CURA-4400 Fixed project loading "enabled" metadata is now read from saved projects (.3mf) --- cura/Settings/ExtruderStack.py | 2 ++ plugins/3MFReader/ThreeMFWorkspaceReader.py | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/cura/Settings/ExtruderStack.py b/cura/Settings/ExtruderStack.py index 1b12814ab0..8dcaaf302e 100644 --- a/cura/Settings/ExtruderStack.py +++ b/cura/Settings/ExtruderStack.py @@ -136,6 +136,8 @@ class ExtruderStack(CuraContainerStack): @override(CuraContainerStack) def deserialize(self, contents: str, file_name: Optional[str] = None) -> None: super().deserialize(contents, file_name) + if "enabled" not in self.getMetaData(): + self.addMetaDataEntry("enabled", "True") stacks = ContainerRegistry.getInstance().findContainerStacks(id=self.getMetaDataEntry("machine", "")) if stacks: self.setNextStack(stacks[0]) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 214623c92d..5c312e7c5a 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -99,6 +99,7 @@ class MachineInfo: class ExtruderInfo: def __init__(self): self.position = None + self.enabled = True self.variant_info = None self.root_material_id = None @@ -425,6 +426,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader): extruder_info = ExtruderInfo() extruder_info.position = position + if parser.has_option("metadata", "enabled"): + extruder_info.enabled = parser["metadata"]["enabled"] if variant_id not in ("empty", "empty_variant"): extruder_info.variant_info = instance_container_info_dict[variant_id] if material_id not in ("empty", "empty_material"): @@ -946,6 +949,15 @@ class ThreeMFWorkspaceReader(WorkspaceReader): else: self._quality_type_to_apply = self._machine_info.quality_type + # Set enabled/disabled for extruders + for position, extruder_stack in extruder_stack_dict.items(): + extruder_info = self._machine_info.extruder_info_dict.get(position) + if not extruder_info: + continue + if "enabled" not in extruder_stack.getMetaData(): + extruder_stack.addMetaDataEntry("enabled", "True") + extruder_stack.setMetaDataEntry("enabled", str(extruder_info.enabled)) + def _updateActiveMachine(self, global_stack): # Actually change the active machine. machine_manager = Application.getInstance().getMachineManager() From f97e615634fac81c85cc67ca543343c71c830bff Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 20 Mar 2018 11:29:43 +0100 Subject: [PATCH 424/446] Fix file name update CURA-5122 --- cura/PrintInformation.py | 13 ++++++------- resources/qml/JobSpecs.qml | 19 +++++-------------- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index 05b740637d..6d73489448 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -309,16 +309,13 @@ class PrintInformation(QObject): self.jobNameChanged.emit() - @pyqtProperty(str) - def baseName(self): - return self._base_name - @pyqtSlot(str) def setProjectName(self, name): self.setBaseName(name, is_project_file = True) - @pyqtSlot(str) - def setBaseName(self, base_name, is_project_file = False): + baseNameChanged = pyqtSignal() + + def setBaseName(self, base_name: str, is_project_file: bool = False): # Ensure that we don't use entire path but only filename name = os.path.basename(base_name) @@ -336,6 +333,9 @@ class PrintInformation(QObject): self._base_name = name self._updateJobName() + @pyqtProperty(str, fset = setBaseName, notify = baseNameChanged) + def baseName(self): + return self._base_name ## Created an acronymn-like abbreviated machine name from the currently active machine name # Called each time the global stack is switched @@ -395,7 +395,6 @@ class PrintInformation(QObject): ## Listen to scene changes to check if we need to reset the print information def _onSceneChanged(self, scene_node): - # Ignore any changes that are not related to sliceable objects if not isinstance(scene_node, SceneNode)\ or not scene_node.callDecoration("isSliceable")\ diff --git a/resources/qml/JobSpecs.qml b/resources/qml/JobSpecs.qml index 04e8ec397f..742e8d6765 100644 --- a/resources/qml/JobSpecs.qml +++ b/resources/qml/JobSpecs.qml @@ -13,7 +13,7 @@ Item { id: base property bool activity: CuraApplication.platformActivity - property string fileBaseName: "" + property string fileBaseName: PrintInformation.baseName UM.I18nCatalog { id: catalog; name:"cura"} @@ -24,26 +24,17 @@ Item { target: backgroundItem onHasMesh: { - if (base.fileBaseName == "") + if (PrintInformation.baseName == "") { - base.fileBaseName = name; + PrintInformation.baseName = name; } } } onActivityChanged: { - if (activity == true && base.fileBaseName == ''){ - //this only runs when you open a file from the terminal (or something that works the same way; for example when you drag a file on the icon in MacOS or use 'open with' on Windows) - base.fileBaseName = PrintInformation.baseName; //get the fileBaseName from PrintInformation.py because this saves the filebase when the file is opened using the terminal (or something alike) - PrintInformation.setBaseName(base.fileBaseName); - } - if (activity == true && base.fileBaseName != ''){ - //this runs in all other cases where there is a mesh on the buildplate (activity == true). It uses the fileBaseName from the hasMesh signal - PrintInformation.setBaseName(base.fileBaseName); - } - if (activity == false){ + if (activity == false) { //When there is no mesh in the buildplate; the printJobTextField is set to an empty string so it doesn't set an empty string as a jobName (which is later used for saving the file) - PrintInformation.setBaseName('') + PrintInformation.baseName = '' } } From cd9531b74682b6989c11b7c043a15a87438b83c0 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 20 Mar 2018 11:42:42 +0100 Subject: [PATCH 425/446] Add the correct value to the setting viewer when the type is unknown. Contributes to CURA-4495 --- resources/qml/Settings/SettingUnknown.qml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/resources/qml/Settings/SettingUnknown.qml b/resources/qml/Settings/SettingUnknown.qml index 704964eda2..8eeb2fb6a0 100644 --- a/resources/qml/Settings/SettingUnknown.qml +++ b/resources/qml/Settings/SettingUnknown.qml @@ -11,9 +11,10 @@ SettingItem contents: Label { anchors.fill: parent - text: value + " " + unit; - color: UM.Theme.getColor("setting_control_text") - - verticalAlignment: Qt.AlignVCenter + text: propertyProvider.properties.value + " " + unit + renderType: Text.NativeRendering + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + verticalAlignment: Text.AlignVCenter } } From a7b263273968bdf0da49235a76c9f2e90118da85 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Tue, 20 Mar 2018 13:14:48 +0100 Subject: [PATCH 426/446] CURA-4400 Recommended mode shows support extruders --- plugins/CuraEngineBackend/StartSliceJob.py | 23 +++++++++++++++++----- resources/qml/SidebarSimple.qml | 18 ++++++++++++++++- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 96124a3514..63e8034859 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -196,9 +196,10 @@ class StartSliceJob(Job): continue if getattr(node, "_outside_buildarea", False) and not is_non_printing_mesh: continue - node_position = node.callDecoration("getActiveExtruderPosition") - if not stack.extruders[str(node_position)].isEnabled: - continue + + #node_position = node.callDecoration("getActiveExtruderPosition") + #if not stack.extruders[str(node_position)].isEnabled: + # continue temp_list.append(node) if not is_non_printing_mesh: @@ -214,10 +215,22 @@ class StartSliceJob(Job): if temp_list: object_groups.append(temp_list) + extruders_enabled = {position: stack.isEnabled for position, stack in Application.getInstance().getGlobalContainerStack().extruders.items()} + filtered_object_groups = [] + for group in object_groups: + stack = Application.getInstance().getGlobalContainerStack() + skip_group = False + for node in group: + if not extruders_enabled[node.callDecoration("getActiveExtruderPosition")]: + skip_group = True + break + if not skip_group: + filtered_object_groups.append(group) + # There are cases when there is nothing to slice. This can happen due to one at a time slicing not being # able to find a possible sequence or because there are no objects on the build plate (or they are outside # the build volume) - if not object_groups: + if not filtered_object_groups: self.setResult(StartJobResult.NothingToSlice) return @@ -228,7 +241,7 @@ class StartSliceJob(Job): for extruder_stack in ExtruderManager.getInstance().getMachineExtruders(stack.getId()): self._buildExtruderMessage(extruder_stack) - for group in object_groups: + for group in filtered_object_groups: group_message = self._slice_message.addRepeatedMessage("object_lists") if group[0].getParent().callDecoration("isGroup"): self._handlePerObjectSettings(group[0].getParent(), group_message) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index 1feabfb40f..c32b8ba957 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -887,7 +887,23 @@ Item enabled: base.settingsEnabled property alias _hovered: supportExtruderMouseArea.containsMouse - currentIndex: supportExtruderNr.properties !== null ? parseFloat(supportExtruderNr.properties.value) : 0 + currentIndex: + { + if (supportExtruderNr.properties == null) + { + return Cura.MachineManager.defaultExtruderPosition; + } + else + { + var extruder = parseInt(supportExtruderNr.properties.value); + if ( extruder === -1) + { + return Cura.MachineManager.defaultExtruderPosition; + } + return extruder; + } + } + onActivated: { // Send the extruder nr as a string. From 877032584e5fa0e3d0b64dd47b63e45bc95ce511 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 20 Mar 2018 13:22:18 +0100 Subject: [PATCH 427/446] Correct documentation This code was obviously copied from the pre-heat functionality. Let's fix the code duplication next as far as possible. Contributes to issue CURA-4879. --- resources/qml/PrinterOutput/ManualPrinterControl.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/qml/PrinterOutput/ManualPrinterControl.qml b/resources/qml/PrinterOutput/ManualPrinterControl.qml index 777213811e..70961a2eb2 100644 --- a/resources/qml/PrinterOutput/ManualPrinterControl.qml +++ b/resources/qml/PrinterOutput/ManualPrinterControl.qml @@ -460,13 +460,13 @@ Item visible: printerModel != null ? printerModel.canSendRawGcode: true enabled: { if (printerModel == null) { - return false // Can't preheat if not connected + return false // Can't send custom commands if not connected. } if (!connectedPrinter.acceptsCommands) { return false // Not allowed to do anything } if (connectedPrinter.jobState == "printing" || connectedPrinter.jobState == "pre_print" || connectedPrinter.jobState == "resuming" || connectedPrinter.jobState == "pausing" || connectedPrinter.jobState == "paused" || connectedPrinter.jobState == "error" || connectedPrinter.jobState == "offline") { - return false // Printer is in a state where it can't react to pre-heating + return false // Printer is in a state where it can't react to custom commands. } return true } From a2b03a2ac1a146d03152411de6782ed7a5f83d65 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Tue, 20 Mar 2018 13:30:48 +0100 Subject: [PATCH 428/446] CURA-4400 fix setting extruders_enabled_count so print_sequence for Custom FDM printer is available again --- cura/Settings/MachineManager.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index e9c777cd4d..54abaca86e 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -861,9 +861,10 @@ class MachineManager(QObject): def updateNumberExtrudersEnabled(self): definition_changes_container = self._global_container_stack.definitionChanges + machine_extruder_count = self._global_container_stack.getProperty("machine_extruder_count", "value") extruder_count = 0 for position, extruder in self._global_container_stack.extruders.items(): - if extruder.isEnabled: + if extruder.isEnabled and int(position) < machine_extruder_count: extruder_count += 1 if self.numberExtrudersEnabled != extruder_count: definition_changes_container.setProperty("extruders_enabled_count", "value", extruder_count) From ae1ea9fc48707ea86ae93797861e6d4e91fe0364 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 20 Mar 2018 15:27:04 +0100 Subject: [PATCH 429/446] Change minimum and maximum layer heights into a warning Because it's possible to try this, but the print result will probably be terrible. This keeps it consistent with the rest of Cura's behaviour. Fixes #3406. --- resources/definitions/malyan_m200.def.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/resources/definitions/malyan_m200.def.json b/resources/definitions/malyan_m200.def.json index a3f4f81ecf..ec3237a7e6 100644 --- a/resources/definitions/malyan_m200.def.json +++ b/resources/definitions/malyan_m200.def.json @@ -30,7 +30,12 @@ "speed_infill": { "value": "speed_print" }, "speed_topbottom": {"value": "speed_print / 2"}, - "layer_height": { "minimum_value": "0.04375", "maximum_value": "machine_nozzle_size * 0.875", "maximum_value_warning": "machine_nozzle_size * 0.48125 + 0.0875", "default_value": 0.13125 }, + "layer_height": + { + "minimum_value_warning": "0.04375", + "maximum_value_warning": "machine_nozzle_size * 0.48125 + 0.0875", + "default_value": 0.13125 + }, "line_width": { "value": "round(machine_nozzle_size * 0.875, 2)" }, "material_print_temperature": { "minimum_value": "0" }, From 6d21a6bddbf6fa33ebce023cecefafbe1a4c8311 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 20 Mar 2018 16:19:40 +0100 Subject: [PATCH 430/446] Show printer group and which machine to update in project loading CURA-5125 --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 10 ++++++++++ plugins/3MFReader/WorkspaceDialog.py | 11 +++++++++++ plugins/3MFReader/WorkspaceDialog.qml | 19 +++++++++++++++++-- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 5c312e7c5a..633142187c 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -358,8 +358,10 @@ class ThreeMFWorkspaceReader(WorkspaceReader): machine_name = self._getMachineNameFromSerializedStack(serialized) stacks = self._container_registry.findContainerStacks(name = machine_name, type = "machine") self._is_same_machine_type = True + existing_global_stack = None if stacks: global_stack = stacks[0] + existing_global_stack = global_stack containers_found_dict["machine"] = True # Check if there are any changes at all in any of the container stacks. id_list = self._getContainerIdListFromSerialized(serialized) @@ -495,8 +497,16 @@ class ThreeMFWorkspaceReader(WorkspaceReader): if machine_conflict and not self._is_same_machine_type: machine_conflict = False + is_printer_group = False + if machine_conflict: + group_name = existing_global_stack.getMetaDataEntry("connect_group_name") + if group_name is not None: + is_printer_group = True + machine_name = group_name + # Show the dialog, informing the user what is about to happen. self._dialog.setMachineConflict(machine_conflict) + self._dialog.setIsPrinterGroup(is_printer_group) self._dialog.setQualityChangesConflict(quality_changes_conflict) self._dialog.setMaterialConflict(material_conflict) self._dialog.setHasVisibleSettingsField(has_visible_settings_string) diff --git a/plugins/3MFReader/WorkspaceDialog.py b/plugins/3MFReader/WorkspaceDialog.py index bb31afd40b..da682a6fc0 100644 --- a/plugins/3MFReader/WorkspaceDialog.py +++ b/plugins/3MFReader/WorkspaceDialog.py @@ -49,6 +49,7 @@ class WorkspaceDialog(QObject): self._material_labels = [] self._extruders = [] self._objects_on_plate = False + self._is_printer_group = False machineConflictChanged = pyqtSignal() qualityChangesConflictChanged = pyqtSignal() @@ -66,6 +67,16 @@ class WorkspaceDialog(QObject): machineTypeChanged = pyqtSignal() variantTypeChanged = pyqtSignal() extrudersChanged = pyqtSignal() + isPrinterGroupChanged = pyqtSignal() + + @pyqtProperty(bool, notify = isPrinterGroupChanged) + def isPrinterGroup(self) -> bool: + return self._is_printer_group + + def setIsPrinterGroup(self, value: bool): + if value != self._is_printer_group: + self._is_printer_group = value + self.isPrinterGroupChanged.emit() @pyqtProperty(str, notify=variantTypeChanged) def variantType(self): diff --git a/plugins/3MFReader/WorkspaceDialog.qml b/plugins/3MFReader/WorkspaceDialog.qml index 5418dcef6d..58d881c915 100644 --- a/plugins/3MFReader/WorkspaceDialog.qml +++ b/plugins/3MFReader/WorkspaceDialog.qml @@ -108,7 +108,22 @@ UM.Dialog text: catalog.i18nc("@info:tooltip", "How should the conflict in the machine be resolved?") ComboBox { - model: resolveStrategiesModel + model: ListModel + { + Component.onCompleted: + { + append({"key": "override", "label": catalog.i18nc("@action:ComboBox option", "Update") + " " + manager.machineName}); + append({"key": "new", "label": catalog.i18nc("@action:ComboBox option", "Create new")}); + } + } + Connections + { + target: manager + onMachineNameChanged: + { + machineResolveComboBox.model.get(0).label = catalog.i18nc("@action:ComboBox option", "Update") + " " + manager.machineName; + } + } textRole: "label" id: machineResolveComboBox width: parent.width @@ -141,7 +156,7 @@ UM.Dialog height: childrenRect.height Label { - text: catalog.i18nc("@action:label", "Name") + text: catalog.i18nc("@action:label", manager.isPrinterGroup ? "Printer Group" : "Printer Name") width: (parent.width / 3) | 0 } Label From 5993847c4aada98e07edaba2bd2a813ff977da3f Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 20 Mar 2018 16:22:55 +0100 Subject: [PATCH 431/446] Show printer group or machine name in workspace summary CURA-5125 --- resources/qml/WorkspaceSummaryDialog.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/qml/WorkspaceSummaryDialog.qml b/resources/qml/WorkspaceSummaryDialog.qml index cf19e45fdd..4d15860257 100644 --- a/resources/qml/WorkspaceSummaryDialog.qml +++ b/resources/qml/WorkspaceSummaryDialog.qml @@ -111,12 +111,12 @@ UM.Dialog height: childrenRect.height Label { - text: catalog.i18nc("@action:label", "Name") + text: catalog.i18nc("@action:label", Cura.MachineManager.activeMachineNetworkGroupName != "" ? "Printer Group" : "Name") width: (parent.width / 3) | 0 } Label { - text: Cura.MachineManager.activeMachineName + text: Cura.MachineManager.activeMachineNetworkGroupName != "" ? Cura.MachineManager.activeMachineNetworkGroupName : Cura.MachineManager.activeMachineName width: (parent.width / 3) | 0 } } From 9dc50ec73f12270a7629fcf0b548e93891bdf717 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Tue, 20 Mar 2018 16:54:34 +0100 Subject: [PATCH 432/446] CURA-4400 Apply correct shader to grouped nodes --- cura/BuildVolume.py | 11 ++++++++++- plugins/CuraEngineBackend/StartSliceJob.py | 4 ---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index d93ce1107d..6da8f33fff 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -238,7 +238,16 @@ class BuildVolume(SceneNode): # Group nodes should override the _outside_buildarea property of their children. for group_node in group_nodes: - for child_node in group_node.getAllChildren(): + children = group_node.getAllChildren() + + # Check if one or more children are non-printable and if so, set the parent as non-printable: + for child_node in children: + if child_node.isOutsideBuildArea(): + group_node.setOutsideBuildArea(True) + break + + # Apply results of the check to all children of the group: + for child_node in children: child_node.setOutsideBuildArea(group_node.isOutsideBuildArea()) ## Update the outsideBuildArea of a single node, given bounds or current build volume diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 63e8034859..89f9a144b0 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -197,10 +197,6 @@ class StartSliceJob(Job): if getattr(node, "_outside_buildarea", False) and not is_non_printing_mesh: continue - #node_position = node.callDecoration("getActiveExtruderPosition") - #if not stack.extruders[str(node_position)].isEnabled: - # continue - temp_list.append(node) if not is_non_printing_mesh: has_printing_mesh = True From 7f6a89e6aa97d5d7c61d470298b16ef00d59e179 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Wed, 21 Mar 2018 09:52:03 +0100 Subject: [PATCH 433/446] Fixed bug that didn't do anything Sometimes `None` was in the grouped objects which threw an error when trying to use `.callDecoration("isGroup")` on it. Nothing seems to break before, apart from the error message, and nothing breaks now either. But no error message. So that's good. --- plugins/CuraEngineBackend/StartSliceJob.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 89f9a144b0..0297a34385 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -239,7 +239,7 @@ class StartSliceJob(Job): for group in filtered_object_groups: group_message = self._slice_message.addRepeatedMessage("object_lists") - if group[0].getParent().callDecoration("isGroup"): + if group[0].getParent() is not None and group[0].getParent().callDecoration("isGroup"): self._handlePerObjectSettings(group[0].getParent(), group_message) for object in group: mesh_data = object.getMeshData() From 46e53ff0c3bef0413b25cc4681193b47dc1b3455 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 21 Mar 2018 10:26:23 +0100 Subject: [PATCH 434/446] Clarify text CURA-4833 --- cura/CrashHandler.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cura/CrashHandler.py b/cura/CrashHandler.py index c082578218..f51174aec0 100644 --- a/cura/CrashHandler.py +++ b/cura/CrashHandler.py @@ -85,14 +85,14 @@ class CrashHandler: dialog = QDialog() dialog.setMinimumWidth(500) dialog.setMinimumHeight(170) - dialog.setWindowTitle(catalog.i18nc("@title:window", "Cura Crashed")) + dialog.setWindowTitle(catalog.i18nc("@title:window", "Cura can't startup")) dialog.finished.connect(self._closeEarlyCrashDialog) layout = QVBoxLayout(dialog) label = QLabel() - label.setText(catalog.i18nc("@label crash message", """

    A fatal error has occurred.

    -

    Unfortunately, Cura encountered an unrecoverable error during start up. It was possibly caused by some incorrect configuration files. We suggest to backup and reset your configuration.

    + label.setText(catalog.i18nc("@label crash message", """

    Oops, Ultimaker Cura has encountered something that doesn't seem right.

    +

    We encountered an unrecoverable error during start up. It was possibly caused by some incorrect configuration files. We suggest to backup and reset your configuration.

    Backups can be found in the configuration folder.

    Please send us this Crash Report to fix the problem.

    """)) @@ -220,7 +220,7 @@ class CrashHandler: def _messageWidget(self): label = QLabel() - label.setText(catalog.i18nc("@label crash message", """

    A fatal error has occurred. Please send us this Crash Report to fix the problem

    + label.setText(catalog.i18nc("@label crash message", """

    A fatal error has occurred in Cura. Please send us this Crash Report to fix the problem

    Please use the "Send report" button to post a bug report automatically to our servers

    """)) From 42b40a713d58e12eecd8b5e0c960dc866a23bf8c Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 21 Mar 2018 10:34:25 +0100 Subject: [PATCH 435/446] CURA-4870 Adapt the colors of the configuration list for the Ultimaker dark theme. --- .../qml/Menus/ConfigurationMenu/ConfigurationListView.qml | 2 ++ resources/themes/cura-dark/theme.json | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml index 88173195be..331d78ead9 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -30,6 +30,7 @@ Column text: catalog.i18nc("@label:header configurations", "Available configurations") font: UM.Theme.getFont("large") width: parent.width - 2 * parent.padding + color: UM.Theme.getColor("configuration_item_text") } Component @@ -42,6 +43,7 @@ Column { text: section font: UM.Theme.getFont("default_bold") + color: UM.Theme.getColor("configuration_item_text") } } } diff --git a/resources/themes/cura-dark/theme.json b/resources/themes/cura-dark/theme.json index 5fbe36fcdb..26e6c2ac8b 100644 --- a/resources/themes/cura-dark/theme.json +++ b/resources/themes/cura-dark/theme.json @@ -207,6 +207,14 @@ "layerview_support_interface": [64, 192, 255, 255], "layerview_nozzle": [181, 166, 66, 120], + "configuration_item": [0, 0, 0, 0], + "configuration_item_active": [12, 169, 227, 179], + "configuration_item_text": [255, 255, 255, 255], + "configuration_item_text_active": [255, 255, 255, 255], + "configuration_item_border": [255, 255, 255, 255], + "configuration_item_border_active": [12, 169, 227, 179], + "configuration_item_border_hover": [12, 169, 227, 179], + "material_compatibility_warning": [255, 255, 255, 255], "quality_slider_unavailable": [179, 179, 179, 255], From db316708d6c0bfd0623aefb07a1a8947ae29be6b Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Wed, 21 Mar 2018 10:48:03 +0100 Subject: [PATCH 436/446] CURA-4902 Challenging network message fix This bug was very complicated to fix and involved careful troubleshooting of networked printers and eventual application of text-based message parsing and case switching. Should work now though. --- plugins/UM3NetworkPrinting/PrinterInfoBlock.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/UM3NetworkPrinting/PrinterInfoBlock.qml b/plugins/UM3NetworkPrinting/PrinterInfoBlock.qml index 54a34fae46..74670766ff 100644 --- a/plugins/UM3NetworkPrinting/PrinterInfoBlock.qml +++ b/plugins/UM3NetworkPrinting/PrinterInfoBlock.qml @@ -41,7 +41,8 @@ Rectangle return catalog.i18nc("@label:status", "Available"); case "unreachable": return catalog.i18nc("@label:MonitorStatus", "Lost connection with the printer"); - case "maintenance": // TODO: new string + case "maintenance": + return catalog.i18nc("@label:status", "Unavailable"); case "unknown": default: return catalog.i18nc("@label Printer status", "Unknown"); From 3e7e828f4bb5d14f47a6fd05fab9f4385df1c73c Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Wed, 21 Mar 2018 11:31:01 +0100 Subject: [PATCH 437/446] CURA-4902 Standardized i18nc message labels This one goes out to @fieldofview. :heart: --- plugins/UM3NetworkPrinting/PrinterInfoBlock.qml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/UM3NetworkPrinting/PrinterInfoBlock.qml b/plugins/UM3NetworkPrinting/PrinterInfoBlock.qml index 74670766ff..f55bc30d2e 100644 --- a/plugins/UM3NetworkPrinting/PrinterInfoBlock.qml +++ b/plugins/UM3NetworkPrinting/PrinterInfoBlock.qml @@ -34,18 +34,18 @@ Rectangle switch (printer.state) { case "pre_print": - return catalog.i18nc("@label", "Preparing to print") + return catalog.i18nc("@label:status", "Preparing to print") case "printing": return catalog.i18nc("@label:status", "Printing"); case "idle": return catalog.i18nc("@label:status", "Available"); case "unreachable": - return catalog.i18nc("@label:MonitorStatus", "Lost connection with the printer"); + return catalog.i18nc("@label:status", "Lost connection with the printer"); case "maintenance": return catalog.i18nc("@label:status", "Unavailable"); case "unknown": default: - return catalog.i18nc("@label Printer status", "Unknown"); + return catalog.i18nc("@label:status", "Unknown"); } } From 6443db5853b97319766654135e3d085065c85f6d Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Wed, 21 Mar 2018 11:32:52 +0100 Subject: [PATCH 438/446] CURA-4902 Removed useless case Default case _is_ unknown! --- plugins/UM3NetworkPrinting/PrinterInfoBlock.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/UM3NetworkPrinting/PrinterInfoBlock.qml b/plugins/UM3NetworkPrinting/PrinterInfoBlock.qml index f55bc30d2e..0217767a40 100644 --- a/plugins/UM3NetworkPrinting/PrinterInfoBlock.qml +++ b/plugins/UM3NetworkPrinting/PrinterInfoBlock.qml @@ -43,7 +43,6 @@ Rectangle return catalog.i18nc("@label:status", "Lost connection with the printer"); case "maintenance": return catalog.i18nc("@label:status", "Unavailable"); - case "unknown": default: return catalog.i18nc("@label:status", "Unknown"); } From c6e5123c2df17a7354d804596330e165544f6e60 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 21 Mar 2018 13:23:33 +0100 Subject: [PATCH 439/446] Update the link so we can see how many people use it --- plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerJob.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerJob.py b/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerJob.py index fd6c4680e8..66ee43209f 100644 --- a/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerJob.py +++ b/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerJob.py @@ -69,7 +69,7 @@ class FirmwareUpdateCheckerJob(Job): # If we do this in a cool way, the download url should be available in the JSON file if self._set_download_url_callback: - self._set_download_url_callback("https://ultimaker.com/en/resources/20500-upgrade-firmware") + self._set_download_url_callback("https://ultimaker.com/en/resources/23129-updating-the-firmware?utm_source=cura&utm_medium=software&utm_campaign=hw-update") message.actionTriggered.connect(self._callback) message.show() From 143ee07228235594ca5278f23c62d8606b3e75a1 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 21 Mar 2018 13:25:05 +0100 Subject: [PATCH 440/446] Fix quality_type "Extra coarse" -> "extra coarse" CURA-5129 --- .../VersionUpgrade32to33/VersionUpgrade32to33.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py b/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py index 620f367e25..e39266884d 100644 --- a/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py +++ b/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py @@ -127,6 +127,9 @@ class VersionUpgrade32to33(VersionUpgrade): parser["metadata"]["position"] = str(extruder_position) del parser["metadata"]["extruder"] + quality_type = parser["metadata"]["quality_type"] + parser["metadata"]["quality_type"] = quality_type.lower() + #Update version number. parser["general"]["version"] = "3" From da00bdf9c325e9e124ea1c20f351470bf01e3b4e Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 21 Mar 2018 13:50:56 +0100 Subject: [PATCH 441/446] Fix SimulationView onSceneChanged signal binding CURA-5130 --- plugins/SimulationView/SimulationView.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 456d64e250..3697e38661 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -74,7 +74,7 @@ class SimulationView(View): self._global_container_stack = None self._proxy = SimulationViewProxy() - self._controller.getScene().getRoot().childrenChanged.connect(self._onSceneChanged) + self._controller.getScene().sceneChanged.connect(self._onSceneChanged) self._resetSettings() self._legend_items = None From 3eb9969d6db64172be406d416a8da2edc8924eb9 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 21 Mar 2018 15:08:34 +0100 Subject: [PATCH 442/446] CURA-4870 Make the Sync button react when the output device changed, otherwise can show a wrong value (not updated). --- resources/qml/Menus/ConfigurationMenu/SyncButton.qml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml index 8fe9dacf9a..6654708482 100644 --- a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml +++ b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml @@ -98,4 +98,10 @@ Button target: Cura.MachineManager onCurrentConfigurationChanged: updateOnSync() } + + Connections + { + target: Cura.MachineManager + onOutputDevicesChanged: updateOnSync() + } } \ No newline at end of file From 5e3cf921973e9e45ec4161ba86c662b17f8d290e Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 21 Mar 2018 16:57:48 +0100 Subject: [PATCH 443/446] CURA-5134 Add funtionality to lazily remove plugins --- cura/CuraApplication.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 98c682a8a3..1bbfa7be58 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -498,8 +498,13 @@ class CuraApplication(QtApplication): def getStaticVersion(cls): return CuraVersion + ## Handle removing the unneeded plugins + # \sa PluginRegistry + def _removePlugins(self): + self._plugin_registry.removePlugins() + ## Handle loading of all plugin types (and the backend explicitly) - # \sa PluginRegistery + # \sa PluginRegistry def _loadPlugins(self): self._plugin_registry.addType("profile_reader", self._addProfileReader) self._plugin_registry.addType("profile_writer", self._addProfileWriter) From 4226f3641b26ec233e751f662c11a3db64daa594 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 21 Mar 2018 17:12:36 +0100 Subject: [PATCH 444/446] Better defaults for filament change And better descriptions. --- plugins/PostProcessingPlugin/scripts/FilamentChange.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/PostProcessingPlugin/scripts/FilamentChange.py b/plugins/PostProcessingPlugin/scripts/FilamentChange.py index 2bb7891634..07e887b082 100644 --- a/plugins/PostProcessingPlugin/scripts/FilamentChange.py +++ b/plugins/PostProcessingPlugin/scripts/FilamentChange.py @@ -27,18 +27,18 @@ class FilamentChange(Script): "initial_retract": { "label": "Initial Retraction", - "description": "Initial filament retraction distance", + "description": "Initial filament retraction distance. The filament will be retracted with this amount before moving the nozzle away from the ongoing print.", "unit": "mm", "type": "float", - "default_value": 300.0 + "default_value": 30.0 }, "later_retract": { "label": "Later Retraction Distance", - "description": "Later filament retraction distance for removal", + "description": "Later filament retraction distance for removal. The filament will be retracted all the way out of the printer so that you can change the filament.", "unit": "mm", "type": "float", - "default_value": 30.0 + "default_value": 300.0 } } }""" From 4fa195894de40d94787718be1bef21d05b5a5e3f Mon Sep 17 00:00:00 2001 From: Aleksei S Date: Wed, 21 Mar 2018 17:21:11 +0100 Subject: [PATCH 445/446] Fix: After reloading merged models they do not update origin position CURA-4846 --- cura/CuraApplication.py | 61 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 98c682a8a3..aefadcba95 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1280,8 +1280,11 @@ class CuraApplication(QtApplication): def reloadAll(self): Logger.log("i", "Reloading all loaded mesh data.") nodes = [] + has_merged_nodes = False for node in DepthFirstIterator(self.getController().getScene().getRoot()): - if not isinstance(node, CuraSceneNode) or not node.getMeshData(): + if not isinstance(node, CuraSceneNode) or not node.getMeshData() : + if node.getName() == 'MergedMesh': + has_merged_nodes = True continue nodes.append(node) @@ -1295,10 +1298,14 @@ class CuraApplication(QtApplication): job = ReadMeshJob(file_name) job._node = node job.finished.connect(self._reloadMeshFinished) + if has_merged_nodes: + job.finished.connect(self.centerMergedMeshes) + job.start() else: Logger.log("w", "Unable to reload data because we don't have a filename.") + ## Get logging data of the backend engine # \returns \type{string} Logging data @pyqtSlot(result = str) @@ -1368,6 +1375,58 @@ class CuraApplication(QtApplication): # Use the previously found center of the group bounding box as the new location of the group group_node.setPosition(group_node.getBoundingBox().center) + group_node.setName("MergedMesh") # add a specific name to destinguis this node + + + ## Updates center position of all merged meshes + # \param jobNode \type{Job} empty object which passed which is required by JobQueue + def centerMergedMeshes(self, jobNode): + group_nodes = [] + for node in DepthFirstIterator(self.getController().getScene().getRoot()): + if isinstance(node, CuraSceneNode) and node.getName() == "MergedMesh": + + #checking by name might be not enough, the merged mesh should has "GroupDecorator" decorator + for decorator in node.getDecorators(): + if isinstance(decorator, GroupDecorator): + group_nodes.append(node) + break + + for group_node in group_nodes: + meshes = [node.getMeshData() for node in group_node.getAllChildren() if node.getMeshData()] + + # Compute the center of the objects + object_centers = [] + # Forget about the translation that the original objects have + zero_translation = Matrix(data=numpy.zeros(3)) + for mesh, node in zip(meshes, group_node.getChildren()): + transformation = node.getLocalTransformation() + transformation.setTranslation(zero_translation) + transformed_mesh = mesh.getTransformed(transformation) + center = transformed_mesh.getCenterPosition() + if center is not None: + object_centers.append(center) + + if object_centers and len(object_centers) > 0: + middle_x = sum([v.x for v in object_centers]) / len(object_centers) + middle_y = sum([v.y for v in object_centers]) / len(object_centers) + middle_z = sum([v.z for v in object_centers]) / len(object_centers) + offset = Vector(middle_x, middle_y, middle_z) + else: + offset = Vector(0, 0, 0) + + # Move each node to the same position. + for mesh, node in zip(meshes, group_node.getChildren()): + transformation = node.getLocalTransformation() + transformation.setTranslation(zero_translation) + transformed_mesh = mesh.getTransformed(transformation) + + # Align the object around its zero position + # and also apply the offset to center it inside the group. + node.setPosition(-transformed_mesh.getZeroPosition() - offset) + + # Use the previously found center of the group bounding box as the new location of the group + group_node.setPosition(group_node.getBoundingBox().center) + @pyqtSlot() def groupSelected(self): From 47417c86a3c7bafaea932ecbcdc078a231daba79 Mon Sep 17 00:00:00 2001 From: Aleksei S Date: Wed, 21 Mar 2018 17:25:23 +0100 Subject: [PATCH 446/446] Rename method name CURA-4846 --- cura/CuraApplication.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index aa5811041c..6d5bd34ee4 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1304,7 +1304,7 @@ class CuraApplication(QtApplication): job._node = node job.finished.connect(self._reloadMeshFinished) if has_merged_nodes: - job.finished.connect(self.centerMergedMeshes) + job.finished.connect(self.updateOriginOfMergedMeshes) job.start() else: @@ -1383,9 +1383,9 @@ class CuraApplication(QtApplication): group_node.setName("MergedMesh") # add a specific name to destinguis this node - ## Updates center position of all merged meshes + ## Updates origin position of all merged meshes # \param jobNode \type{Job} empty object which passed which is required by JobQueue - def centerMergedMeshes(self, jobNode): + def updateOriginOfMergedMeshes(self, jobNode): group_nodes = [] for node in DepthFirstIterator(self.getController().getScene().getRoot()): if isinstance(node, CuraSceneNode) and node.getName() == "MergedMesh":