From 4bb67fbd82e65c24b55efcab550a0e943c68fb86 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 25 Oct 2017 17:04:23 +0200 Subject: [PATCH 001/158] 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/158] 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/158] 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/158] 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/158] 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/158] 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/158] 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/158] 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 2703474861f50269228fd34f0ef2d4dc5cbb645c Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Sat, 27 Jan 2018 21:49:19 +0100 Subject: [PATCH 009/158] 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 872efd16b238e17d546db25b6f6fc308b5bc3762 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 8 Feb 2018 17:13:59 +0100 Subject: [PATCH 010/158] 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 011/158] 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 012/158] 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 013/158] 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 014/158] 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 015/158] 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 016/158] 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 112bb260acb8655e929cf377b18f505d62608eb1 Mon Sep 17 00:00:00 2001 From: Simon Lundell Date: Sun, 18 Feb 2018 11:44:04 +0100 Subject: [PATCH 017/158] 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 d62dbe51876da7c8715b54ec1b30774914a782fa Mon Sep 17 00:00:00 2001 From: Simon Lundell Date: Fri, 23 Feb 2018 16:12:01 +0100 Subject: [PATCH 018/158] 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 019/158] 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 020/158] 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 021/158] 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 022/158] 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 023/158] 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 024/158] 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 025/158] 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 ac635ba748239d0f91d85879f659eb0229082db9 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 27 Feb 2018 17:10:19 +0100 Subject: [PATCH 026/158] 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 3aa37296358192ca34f767e1de175dc4d4f2df34 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 28 Feb 2018 13:36:39 +0100 Subject: [PATCH 027/158] 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 6952e3f5c16985375d24ede3246fde985ea3ced2 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 28 Feb 2018 19:41:23 +0100 Subject: [PATCH 028/158] 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 135208bfeef1de9834e0c00f52c5c168fece6930 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Fri, 2 Mar 2018 13:26:04 +0100 Subject: [PATCH 029/158] 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 dead2122dd0db7c34dfb507462f3839c2bcb9a08 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Sat, 3 Mar 2018 20:29:06 +0100 Subject: [PATCH 030/158] 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 6e35fc5035b5333157adcd78797de3e0578c8b67 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Sun, 4 Mar 2018 12:53:16 +0100 Subject: [PATCH 031/158] 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 032/158] 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 033/158] 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 034/158] 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 b8ad0959a744785360a29b0b4824b1952a906521 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 5 Mar 2018 09:41:22 +0100 Subject: [PATCH 035/158] 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 036/158] 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 037/158] 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 a992487589ec0992c5b20bb594afe9c11e97031c Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 5 Mar 2018 14:39:49 +0100 Subject: [PATCH 038/158] 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 51686943e6a3867a265fa7451b2420e23c26c18b Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 5 Mar 2018 17:15:09 +0100 Subject: [PATCH 039/158] 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 d9eb4406bfa3560e0f2042d506705968ccab1d55 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 5 Mar 2018 23:25:33 +0100 Subject: [PATCH 040/158] 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 041/158] 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 042/158] 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 043/158] 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 044/158] 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 731a1092c521a363c6f0fbc3b53ea21848af5ccf Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 6 Mar 2018 10:18:54 +0100 Subject: [PATCH 045/158] 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 046/158] 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 f625fa8a90e97a7486ef15f6f264c5f74a56b3b6 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 6 Mar 2018 16:08:50 +0100 Subject: [PATCH 047/158] 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 987794c5158930e76a771dc4b2f4d5315d9f91e3 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 6 Mar 2018 16:59:51 +0100 Subject: [PATCH 048/158] 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 5b2ff705e79ea365a476e195b8a2b2ac0a7eeb07 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Tue, 6 Mar 2018 17:03:44 +0100 Subject: [PATCH 049/158] 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 813f4e83e048679617fd529d7615b9337d79dfca Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 7 Mar 2018 09:56:38 +0100 Subject: [PATCH 050/158] 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 bb3d706c9265f098a2c1523f8c8311c342128ba9 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 7 Mar 2018 11:24:02 +0100 Subject: [PATCH 051/158] 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 052/158] 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 0beee79c3a844d8cd6c1890e276b063052fb9381 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Wed, 7 Mar 2018 13:17:55 +0100 Subject: [PATCH 053/158] 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 054/158] 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 a02486e85a71a4aa04cc4820dc649d62fef5041c Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Wed, 7 Mar 2018 17:15:56 +0100 Subject: [PATCH 055/158] 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 056/158] 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 057/158] 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 058/158] 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 059/158] 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 060/158] 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 061/158] 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 4c7ec3920d4acb178e037f7c9ba2defe210be34b Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Thu, 8 Mar 2018 09:25:14 +0100 Subject: [PATCH 062/158] 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 ffccdd99c03d74f060a49a608009f7e706876fa8 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Thu, 8 Mar 2018 10:55:29 +0100 Subject: [PATCH 063/158] 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 064/158] 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 1bde7a6228cef6b9ba7ac87d531ec239ca8dd01a Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Thu, 8 Mar 2018 14:01:19 +0100 Subject: [PATCH 065/158] 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 066/158] 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 591d3f29ec860a940e5c1ba73a23ea26b4ca95b1 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Thu, 8 Mar 2018 15:36:12 +0100 Subject: [PATCH 067/158] 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 a2773ca8974471d768e59d1584984ea662f8c749 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Thu, 8 Mar 2018 16:30:05 +0100 Subject: [PATCH 068/158] 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 069/158] 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 4be4d08d97a5f90ec5f981f7cab7a972cb00fcfb Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Fri, 9 Mar 2018 10:47:08 +0100 Subject: [PATCH 070/158] 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 260cad36cb4dd09643b822ec177ae009c11a5161 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Fri, 9 Mar 2018 12:42:49 +0100 Subject: [PATCH 071/158] 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 072/158] 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 073/158] 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 ae2a286e3f83f22e85f46a3abba64d1cfa6c6924 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Fri, 9 Mar 2018 14:07:29 +0100 Subject: [PATCH 074/158] 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 16a5b652f44469840408ea0655170b8d9306152b Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Fri, 9 Mar 2018 15:08:51 +0100 Subject: [PATCH 075/158] 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 472ae8e044bb45a884cbfb3be027e55ae10a3211 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Fri, 9 Mar 2018 16:35:23 +0100 Subject: [PATCH 076/158] 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 711d60e8c7e2948f80e50f7c339dcfa27e21d6ee Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 9 Mar 2018 16:30:37 +0100 Subject: [PATCH 077/158] 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 078/158] 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 079/158] 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 080/158] 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 5e4e049c1f60d8fef670ddd53b84f0679cc21f5a Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Thu, 1 Mar 2018 20:57:15 -0600 Subject: [PATCH 081/158] 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 9613103591897cb436b140270136507650be8646 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 12 Mar 2018 10:45:49 +0100 Subject: [PATCH 082/158] 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 ec2201b57c6c0638382932a0af43af394bb4f2b6 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 12 Mar 2018 11:57:53 +0100 Subject: [PATCH 083/158] 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 cc009a94eef9b2cd3970423ba5435d45cc59c8e7 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 12 Mar 2018 14:19:06 +0100 Subject: [PATCH 084/158] 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 085/158] 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 da54c93fda6a9c795020607d69718e292524cfb6 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 12 Mar 2018 15:12:27 +0100 Subject: [PATCH 086/158] 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 087/158] 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 7574ab088357b2a27708f6306058f6b4e4f9224f Mon Sep 17 00:00:00 2001 From: Aleksei S Date: Mon, 12 Mar 2018 15:52:16 +0100 Subject: [PATCH 088/158] 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 39a7f5a53d55ba356efb3ebbb1ec170378a93060 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Mon, 12 Mar 2018 16:37:35 +0100 Subject: [PATCH 089/158] 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 a87db2d721e7779c4b6d3650aa60155e0de22ea4 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 13 Mar 2018 09:09:21 +0100 Subject: [PATCH 090/158] 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 091/158] 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 092/158] 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 093/158] 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 094/158] 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 095/158] 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 096/158] 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 097/158] 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 098/158] 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 099/158] 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 6d2d9c8fe2a1b5974babe2a64bc23fcc8fb304c4 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Tue, 13 Mar 2018 12:39:10 +0100 Subject: [PATCH 100/158] 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 101/158] 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 102/158] 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 103/158] 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 104/158] 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 105/158] 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 106/158] 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 107/158] 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 108/158] 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 109/158] 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 110/158] 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 111/158] 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 112/158] 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 113/158] 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 114/158] 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 115/158] 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 116/158] 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 117/158] 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 118/158] 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 119/158] 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 120/158] 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 121/158] 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 9f89678e42ba3e13f547e9ed8ded23024508372f Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 13 Mar 2018 13:40:17 +0100 Subject: [PATCH 122/158] 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 123/158] 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 7ebd83f81527f157d679bd564a013a1811b2888f Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 14 Mar 2018 10:21:10 +0100 Subject: [PATCH 124/158] 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 125/158] 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 126/158] 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 127/158] 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 128/158] 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 129/158] 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 130/158] 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 131/158] 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 132/158] 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 133/158] 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 134/158] 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 135/158] 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 136/158] 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 137/158] 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 138/158] 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 139/158] 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 140/158] 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 141/158] 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 142/158] 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 143/158] 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 144/158] 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 145/158] 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 146/158] 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 147/158] 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 148/158] 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 149/158] 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 150/158] 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 151/158] 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 152/158] 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 153/158] 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 154/158] 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 155/158] 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 a477b8cdc245b6f0f6572997a7c126031d100bdd Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 15 Mar 2018 09:57:46 +0100 Subject: [PATCH 156/158] 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 157/158] 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 158/158] 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)