From 7516fb6056bbd182f20af6739a4ee90834304612 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 13 Dec 2016 14:16:04 +0100 Subject: [PATCH 01/11] Store cost & weight as preference values independent of material definition Users need to be able to set these values independent of the xml definition, as it is not a material property but something that depends on the reseller etc. It must also be settable for read-only materials. --- cura/CuraApplication.py | 4 + resources/qml/Preferences/MaterialView.qml | 87 ++++++++++++++------- resources/qml/Preferences/MaterialsPage.qml | 2 + 3 files changed, 65 insertions(+), 28 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 2ab7837352..41b1625e61 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -217,6 +217,10 @@ class CuraApplication(QtApplication): Preferences.getInstance().addPreference("mesh/scale_tiny_meshes", True) Preferences.getInstance().addPreference("cura/dialog_on_project_save", True) Preferences.getInstance().addPreference("cura/asked_dialog_on_project_save", False) + + Preferences.getInstance().addPreference("cura/currency", "€") + Preferences.getInstance().addPreference("cura/material_settings", "{}") + for key in [ "dialog_load_path", # dialog_save_path is in LocalFileOutputDevicePlugin "dialog_profile_path", diff --git a/resources/qml/Preferences/MaterialView.qml b/resources/qml/Preferences/MaterialView.qml index 7ea363454b..d3efef353c 100644 --- a/resources/qml/Preferences/MaterialView.qml +++ b/resources/qml/Preferences/MaterialView.qml @@ -15,10 +15,11 @@ TabView property QtObject properties; property bool editingEnabled: false; - property string currency: UM.Preferences.getValue("general/currency") ? UM.Preferences.getValue("general/currency") : "€" + property string currency: UM.Preferences.getValue("cura/currency") ? UM.Preferences.getValue("cura/currency") : "€" property real firstColumnWidth: width * 0.45 property real secondColumnWidth: width * 0.45 property string containerId: "" + property var materialPreferenceValues: UM.Preferences.getValue("cura/material_settings") ? JSON.parse(UM.Preferences.getValue("cura/material_settings")) : {} Tab { @@ -112,12 +113,12 @@ TabView Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Density") } ReadOnlySpinBox { - width: base.secondColumnWidth; - value: properties.density; + width: base.secondColumnWidth + value: properties.density decimals: 2 - suffix: "g/cm³" + suffix: " g/cm³" stepSize: 0.01 - readOnly: !base.editingEnabled; + readOnly: !base.editingEnabled onEditingFinished: base.setMetaDataEntry("properties/density", properties.density, value) } @@ -125,12 +126,12 @@ TabView Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Diameter") } ReadOnlySpinBox { - width: base.secondColumnWidth; - value: properties.diameter; + width: base.secondColumnWidth + value: properties.diameter decimals: 2 - suffix: "mm" + suffix: " mm" stepSize: 0.01 - readOnly: !base.editingEnabled; + readOnly: !base.editingEnabled onEditingFinished: base.setMetaDataEntry("properties/diameter", properties.diameter, value) } @@ -138,38 +139,42 @@ TabView Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament Cost") } SpinBox { - width: base.secondColumnWidth; - value: properties.spool_cost; - prefix: base.currency - enabled: false + width: base.secondColumnWidth + value: base.getMaterialPreferenceValue(properties.guid, "spool_cost") + prefix: base.currency + " " + decimals: 2 + maximumValue: 1000 + onEditingFinished: base.setMaterialPreferenceValue(properties.guid, "spool_cost", parseFloat(value)) } Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament weight") } SpinBox { - width: base.secondColumnWidth; - value: properties.spool_weight; - suffix: "g"; - stepSize: 10 - enabled: false + width: base.secondColumnWidth + value: base.getMaterialPreferenceValue(properties.guid, "spool_weight") + suffix: " g" + stepSize: 100 + decimals: 0 + maximumValue: 10000 + onEditingFinished: base.setMaterialPreferenceValue(properties.guid, "spool_weight", parseFloat(value)) } Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament length") } - SpinBox + Label { - width: base.secondColumnWidth; - value: parseFloat(properties.spool_length); - suffix: "m"; - enabled: false + width: base.secondColumnWidth + text: "%1 m".arg(properties.spool_length) + verticalAlignment: Qt.AlignVCenter + height: parent.rowHeight } Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Cost per Meter (Approx.)") } - SpinBox + Label { - width: base.secondColumnWidth; - value: parseFloat(properties.cost_per_meter); - suffix: catalog.i18nc("@label", "%1/m".arg(base.currency)); - enabled: false + width: base.secondColumnWidth + text: "%1 %2/m".arg(parseFloat(properties.cost_per_meter).toFixed(2)).arg(base.currency) + verticalAlignment: Qt.AlignVCenter + height: parent.rowHeight } Item { width: parent.width; height: UM.Theme.getSize("default_margin").height } @@ -268,6 +273,32 @@ TabView } } + function setMaterialPreferenceValue(material_guid, entry_name, new_value) + { + if(!(material_guid in materialPreferenceValues)) + { + materialPreferenceValues[material_guid] = {}; + } + if(entry_name in materialPreferenceValues[material_guid] && materialPreferenceValues[material_guid][entry_name] == new_value) + { + // value has not changed + return + } + materialPreferenceValues[material_guid][entry_name] = new_value; + + // store preference + UM.Preferences.setValue("cura/material_settings", JSON.stringify(materialPreferenceValues)); + } + + function getMaterialPreferenceValue(material_guid, entry_name) + { + if(material_guid in materialPreferenceValues && entry_name in materialPreferenceValues[material_guid]) + { + return materialPreferenceValues[material_guid][entry_name]; + } + return 0; + } + function setName(old_value, new_value) { if(old_value != new_value) diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml index 264bc182e6..0c780d165d 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/MaterialsPage.qml @@ -219,6 +219,7 @@ UM.ManagementPage { id: materialProperties + property string guid: "00000000-0000-0000-0000-000000000000" property string name: "Unknown"; property string profile_type: "Unknown"; property string supplier: "Unknown"; @@ -344,6 +345,7 @@ UM.ManagementPage return } materialProperties.name = currentItem.name; + materialProperties.guid = Cura.ContainerManager.getContainerMetaDataEntry(base.currentItem.id, "GUID"); if(currentItem.metadata != undefined && currentItem.metadata != null) { From a06f66305f35a13e938c77652b54763e8bb69363 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 13 Dec 2016 14:46:03 +0100 Subject: [PATCH 02/11] Calculate spool length and cost per meter --- resources/qml/Preferences/MaterialView.qml | 26 ++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/resources/qml/Preferences/MaterialView.qml b/resources/qml/Preferences/MaterialView.qml index d3efef353c..acdf076706 100644 --- a/resources/qml/Preferences/MaterialView.qml +++ b/resources/qml/Preferences/MaterialView.qml @@ -21,6 +21,28 @@ TabView property string containerId: "" property var materialPreferenceValues: UM.Preferences.getValue("cura/material_settings") ? JSON.parse(UM.Preferences.getValue("cura/material_settings")) : {} + property double spoolLength: + { + if (properties.diameter == 0 || properties.density == 0 || getMaterialPreferenceValue(properties.guid, "spool_weight") == 0) + { + return 0; + } + print(properties.diameter / 2); + var area = Math.PI * Math.pow(properties.diameter / 2, 2); // in mm2 + var volume = (getMaterialPreferenceValue(properties.guid, "spool_weight") / properties.density); // in cm3 + return volume / area; // in m + } + + property real costPerMeter: + { + if (spoolLength == 0) + { + return 0; + } + return getMaterialPreferenceValue(properties.guid, "spool_cost") / spoolLength; + } + + Tab { title: catalog.i18nc("@title","Information") @@ -163,7 +185,7 @@ TabView Label { width: base.secondColumnWidth - text: "%1 m".arg(properties.spool_length) + text: "%1 m".arg(Math.round(base.spoolLength)) verticalAlignment: Qt.AlignVCenter height: parent.rowHeight } @@ -172,7 +194,7 @@ TabView Label { width: base.secondColumnWidth - text: "%1 %2/m".arg(parseFloat(properties.cost_per_meter).toFixed(2)).arg(base.currency) + text: "%1 %2/m".arg(base.costPerMeter.toFixed(2)).arg(base.currency) verticalAlignment: Qt.AlignVCenter height: parent.rowHeight } From 4429825d155a2fa7f9996864dac8899717bda39f Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 13 Dec 2016 14:53:21 +0100 Subject: [PATCH 03/11] Show the calculated values are an approximation --- resources/qml/Preferences/MaterialView.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/qml/Preferences/MaterialView.qml b/resources/qml/Preferences/MaterialView.qml index acdf076706..3e05ef0746 100644 --- a/resources/qml/Preferences/MaterialView.qml +++ b/resources/qml/Preferences/MaterialView.qml @@ -185,7 +185,7 @@ TabView Label { width: base.secondColumnWidth - text: "%1 m".arg(Math.round(base.spoolLength)) + text: "~ %1 m".arg(Math.round(base.spoolLength)) verticalAlignment: Qt.AlignVCenter height: parent.rowHeight } @@ -194,7 +194,7 @@ TabView Label { width: base.secondColumnWidth - text: "%1 %2/m".arg(base.costPerMeter.toFixed(2)).arg(base.currency) + text: "~ %1 %2/m".arg(base.costPerMeter.toFixed(2)).arg(base.currency) verticalAlignment: Qt.AlignVCenter height: parent.rowHeight } From ac34fe89eeee9017f993e8a41d3069ceefc39b37 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 13 Dec 2016 15:02:36 +0100 Subject: [PATCH 04/11] Make currency preference settable --- resources/qml/Preferences/GeneralPage.qml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/resources/qml/Preferences/GeneralPage.qml b/resources/qml/Preferences/GeneralPage.qml index eab5dbe938..69342563a0 100644 --- a/resources/qml/Preferences/GeneralPage.qml +++ b/resources/qml/Preferences/GeneralPage.qml @@ -128,6 +128,19 @@ UM.PreferencesPage currentIndex -= 1; } } + + Label + { + id: currencyLabel + text: catalog.i18nc("@label","Currency:") + anchors.verticalCenter: languageComboBox.verticalCenter + } + TextField + { + id: currencyField + text: UM.Preferences.getValue("cura/currency") + onTextChanged: UM.Preferences.setValue("cura/currency", text) + } } Label From 27cf300ba6b1b561bb1673ee4cabf27adc52f204 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 13 Dec 2016 15:59:00 +0100 Subject: [PATCH 05/11] Remove lingering debug statement --- resources/qml/Preferences/MaterialView.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/qml/Preferences/MaterialView.qml b/resources/qml/Preferences/MaterialView.qml index 3e05ef0746..d430f8deb3 100644 --- a/resources/qml/Preferences/MaterialView.qml +++ b/resources/qml/Preferences/MaterialView.qml @@ -27,7 +27,6 @@ TabView { return 0; } - print(properties.diameter / 2); var area = Math.PI * Math.pow(properties.diameter / 2, 2); // in mm2 var volume = (getMaterialPreferenceValue(properties.guid, "spool_weight") / properties.density); // in cm3 return volume / area; // in m From a83c397d690da8691692ecbc0c2920835f2b72e9 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 13 Dec 2016 16:22:29 +0100 Subject: [PATCH 06/11] Show material cost in Job Specs area... ...if weight/price information is available --- cura/PrintInformation.py | 30 ++++++++++++++++++++++- resources/qml/JobSpecs.qml | 49 +++++++++++++++++++++++++++++--------- 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index b65101ecc7..cabba1bb25 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -12,6 +12,7 @@ import cura.Settings.ExtruderManager import math import os.path import unicodedata +import json ## A class for processing and calculating minimum, current and maximum print time as well as managing the job name # @@ -48,6 +49,7 @@ class PrintInformation(QObject): self._material_lengths = [] self._material_weights = [] + self._material_costs = [] self._backend = Application.getInstance().getBackend() if self._backend: @@ -77,6 +79,12 @@ class PrintInformation(QObject): def materialWeights(self): return self._material_weights + materialCostsChanged = pyqtSignal() + + @pyqtProperty("QVariantList", notify = materialCostsChanged) + def materialCosts(self): + return self._material_costs + def _onPrintDurationMessage(self, total_time, material_amounts): self._current_print_time.setDuration(total_time) self.currentPrintTimeChanged.emit() @@ -85,20 +93,40 @@ class PrintInformation(QObject): r = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") / 2 self._material_lengths = [] self._material_weights = [] + self._material_costs = [] + + material_preference_values = json.loads(Preferences.getInstance().getValue("cura/material_settings")) + extruder_stacks = list(cura.Settings.ExtruderManager.getInstance().getMachineExtruders(Application.getInstance().getGlobalContainerStack().getId())) for index, amount in enumerate(material_amounts): ## Find the right extruder stack. As the list isn't sorted because it's a annoying generator, we do some # list comprehension filtering to solve this for us. + material = None if extruder_stacks: # Multi extrusion machine extruder_stack = [extruder for extruder in extruder_stacks if extruder.getMetaDataEntry("position") == str(index)][0] density = extruder_stack.getMetaDataEntry("properties", {}).get("density", 0) + material = extruder_stack.findContainer({"type": "material"}) else: # Machine with no extruder stacks density = Application.getInstance().getGlobalContainerStack().getMetaDataEntry("properties", {}).get("density", 0) + material = Application.getInstance().getGlobalContainerStack().findContainer({"type": "material"}) - self._material_weights.append(float(amount) * float(density) / 1000) + weight = float(amount) * float(density) / 1000 + cost = 0 + if material: + material_guid = material.getMetaDataEntry("GUID") + if material_guid in material_preference_values: + weight_per_spool = float(material_preference_values[material_guid]["spool_weight"]) + cost_per_spool = float(material_preference_values[material_guid]["spool_cost"]) + + cost = cost_per_spool * weight / weight_per_spool + + self._material_weights.append(weight) self._material_lengths.append(round((amount / (math.pi * r ** 2)) / 1000, 2)) + self._material_costs.append(cost) + self.materialLengthsChanged.emit() self.materialWeightsChanged.emit() + self.materialCostsChanged.emit() @pyqtSlot(str) def setJobName(self, name): diff --git a/resources/qml/JobSpecs.qml b/resources/qml/JobSpecs.qml index 78f184f13c..00d22ae8a8 100644 --- a/resources/qml/JobSpecs.qml +++ b/resources/qml/JobSpecs.qml @@ -26,6 +26,7 @@ Rectangle { property variant printDuration: PrintInformation.currentPrintTime property variant printMaterialLengths: PrintInformation.materialLengths property variant printMaterialWeights: PrintInformation.materialWeights + property variant printMaterialCosts: PrintInformation.materialCosts height: childrenRect.height color: "transparent" @@ -133,7 +134,8 @@ Rectangle { } } - Label{ + Label + { id: boundingSpec anchors.top: jobNameRow.bottom anchors.right: parent.right @@ -144,17 +146,20 @@ Rectangle { text: Printer.getSceneBoundingBoxString } - Rectangle { + Rectangle + { id: specsRow anchors.top: boundingSpec.bottom anchors.right: parent.right height: UM.Theme.getSize("jobspecs_line").height - Item{ + Item + { width: parent.width height: parent.height - UM.RecolorImage { + UM.RecolorImage + { id: timeIcon anchors.right: timeSpec.left anchors.rightMargin: UM.Theme.getSize("default_margin").width/2 @@ -166,7 +171,8 @@ Rectangle { color: UM.Theme.getColor("text_subtext") source: UM.Theme.getIcon("print_time") } - Label{ + Label + { id: timeSpec anchors.right: lengthIcon.left anchors.rightMargin: UM.Theme.getSize("default_margin").width @@ -175,7 +181,8 @@ Rectangle { color: UM.Theme.getColor("text_subtext") text: (!base.printDuration || !base.printDuration.valid) ? catalog.i18nc("@label", "00h 00min") : base.printDuration.getDisplayString(UM.DurationFormat.Short) } - UM.RecolorImage { + UM.RecolorImage + { id: lengthIcon anchors.right: lengthSpec.left anchors.rightMargin: UM.Theme.getSize("default_margin").width/2 @@ -187,7 +194,8 @@ Rectangle { color: UM.Theme.getColor("text_subtext") source: UM.Theme.getIcon("category_material") } - Label{ + Label + { id: lengthSpec anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter @@ -197,19 +205,38 @@ Rectangle { { var lengths = []; var weights = []; + var costs = []; + var someCostsKnown = false; if(base.printMaterialLengths) { - for(var index = 0; index < base.printMaterialLengths.length; index++) { - if(base.printMaterialLengths[index] > 0) { + for(var index = 0; index < base.printMaterialLengths.length; index++) + { + if(base.printMaterialLengths[index] > 0) + { lengths.push(base.printMaterialLengths[index].toFixed(2)); weights.push(String(Math.floor(base.printMaterialWeights[index]))); + costs.push(base.printMaterialCosts[index].toFixed(2)); + if(base.printMaterialCosts[index] > 0) + { + someCostsKnown = true; + } } } } - if(lengths.length == 0) { + if(lengths.length == 0) + { lengths = ["0.00"]; weights = ["0"]; + costs = ["0.00"]; + } + if(someCostsKnown) + { + return catalog.i18nc("@label", "%1 m / ~ %2 g / ~ %4 %3").arg(lengths.join(" + ")) + .arg(weights.join(" + ")).arg(costs.join(" + ")).arg(UM.Preferences.getValue("cura/currency")); + } + else + { + return catalog.i18nc("@label", "%1 m / ~ %2 g").arg(lengths.join(" + ")).arg(weights.join(" + ")); } - return catalog.i18nc("@label", "%1 m / ~ %2 g").arg(lengths.join(" + ")).arg(weights.join(" + ")); } } } From 6479f2f9388585540d12045b34435ba72d0c4500 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 3 Jan 2017 11:11:57 +0100 Subject: [PATCH 07/11] Remove redundant "(Approx.)" It is made redundant by the ~, and Approx. is an ugly abbreviation anyway --- resources/qml/Preferences/MaterialView.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Preferences/MaterialView.qml b/resources/qml/Preferences/MaterialView.qml index d430f8deb3..ee07586073 100644 --- a/resources/qml/Preferences/MaterialView.qml +++ b/resources/qml/Preferences/MaterialView.qml @@ -189,7 +189,7 @@ TabView height: parent.rowHeight } - Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Cost per Meter (Approx.)") } + Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Cost per Meter") } Label { width: base.secondColumnWidth From ebbe37a6cdadf0cf16cf05be9ebe489b8115d694 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 3 Jan 2017 11:23:31 +0100 Subject: [PATCH 08/11] Remove "Edit" button from materials page The "Edit" button is an unnecessary barrier. Read-only materials are still uneditable. --- resources/qml/Preferences/MaterialsPage.qml | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml index 0c780d165d..6072541976 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/MaterialsPage.qml @@ -185,17 +185,6 @@ UM.ManagementPage height: childrenRect.height Label { text: materialProperties.name; font: UM.Theme.getFont("large"); } - Button - { - id: editButton - anchors.right: parent.right; - text: catalog.i18nc("@action:button", "Edit"); - iconName: "document-edit"; - - enabled: base.currentItem != null && !base.currentItem.readOnly - - checkable: enabled - } } MaterialView @@ -209,7 +198,7 @@ UM.ManagementPage bottom: parent.bottom } - editingEnabled: editButton.checkable && editButton.checked; + editingEnabled: base.currentItem != null && !base.currentItem.readOnly properties: materialProperties containerId: base.currentItem != null ? base.currentItem.id : "" From 4ba8b4e7c80c44487490cec3484f774a6db0d7db Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 9 Jan 2017 14:08:50 +0100 Subject: [PATCH 09/11] Update spool length and cost per meter when editing values in materials dialog --- resources/qml/Preferences/MaterialView.qml | 77 ++++++++++++++++------ 1 file changed, 57 insertions(+), 20 deletions(-) diff --git a/resources/qml/Preferences/MaterialView.qml b/resources/qml/Preferences/MaterialView.qml index ee07586073..11df30e116 100644 --- a/resources/qml/Preferences/MaterialView.qml +++ b/resources/qml/Preferences/MaterialView.qml @@ -21,30 +21,13 @@ TabView property string containerId: "" property var materialPreferenceValues: UM.Preferences.getValue("cura/material_settings") ? JSON.parse(UM.Preferences.getValue("cura/material_settings")) : {} - property double spoolLength: - { - if (properties.diameter == 0 || properties.density == 0 || getMaterialPreferenceValue(properties.guid, "spool_weight") == 0) - { - return 0; - } - var area = Math.PI * Math.pow(properties.diameter / 2, 2); // in mm2 - var volume = (getMaterialPreferenceValue(properties.guid, "spool_weight") / properties.density); // in cm3 - return volume / area; // in m - } - - property real costPerMeter: - { - if (spoolLength == 0) - { - return 0; - } - return getMaterialPreferenceValue(properties.guid, "spool_cost") / spoolLength; - } - + property double spoolLength: calculateSpoolLength() + property real costPerMeter: calculateCostPerMeter() Tab { title: catalog.i18nc("@title","Information") + anchors { leftMargin: UM.Theme.getSize("default_margin").width @@ -134,6 +117,7 @@ TabView Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Density") } ReadOnlySpinBox { + id: densitySpinBox width: base.secondColumnWidth value: properties.density decimals: 2 @@ -142,11 +126,13 @@ TabView readOnly: !base.editingEnabled onEditingFinished: base.setMetaDataEntry("properties/density", properties.density, value) + onValueChanged: updateCostPerMeter() } Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Diameter") } ReadOnlySpinBox { + id: diameterSpinBox width: base.secondColumnWidth value: properties.diameter decimals: 2 @@ -155,29 +141,36 @@ TabView readOnly: !base.editingEnabled onEditingFinished: base.setMetaDataEntry("properties/diameter", properties.diameter, value) + onValueChanged: updateCostPerMeter() } Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament Cost") } SpinBox { + id: spoolCostSpinBox width: base.secondColumnWidth value: base.getMaterialPreferenceValue(properties.guid, "spool_cost") prefix: base.currency + " " decimals: 2 maximumValue: 1000 + onEditingFinished: base.setMaterialPreferenceValue(properties.guid, "spool_cost", parseFloat(value)) + onValueChanged: updateCostPerMeter() } Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament weight") } SpinBox { + id: spoolWeightSpinBox width: base.secondColumnWidth value: base.getMaterialPreferenceValue(properties.guid, "spool_weight") suffix: " g" stepSize: 100 decimals: 0 maximumValue: 10000 + onEditingFinished: base.setMaterialPreferenceValue(properties.guid, "spool_weight", parseFloat(value)) + onValueChanged: updateCostPerMeter() } Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament length") } @@ -226,6 +219,12 @@ TabView onEditingFinished: base.setMetaDataEntry("adhesion_info", properties.adhesion_info, text) } } + function updateCostPerMeter() + { + base.spoolLength = calculateSpoolLength(diameterSpinBox.value, densitySpinBox.value, spoolWeightSpinBox.value); + base.costPerMeter = calculateCostPerMeter(spoolCostSpinBox.value); + } + } } @@ -285,6 +284,44 @@ TabView } } + function calculateSpoolLength(diameter, density, spoolWeight) + { + if(!diameter) + { + diameter = properties.diameter; + } + if(!density) + { + density = properties.density; + } + if(!spoolWeight) + { + spoolWeight = base.getMaterialPreferenceValue(properties.guid, "spool_weight"); + } + + if (diameter == 0 || density == 0 || spoolWeight == 0) + { + return 0; + } + var area = Math.PI * Math.pow(diameter / 2, 2); // in mm2 + var volume = (spoolWeight / density); // in cm3 + return volume / area; // in m + } + + function calculateCostPerMeter(spoolCost) + { + if(!spoolCost) + { + spoolCost = base.getMaterialPreferenceValue(properties.guid, "spool_cost"); + } + + if (spoolLength == 0) + { + return 0; + } + return spoolCost / spoolLength; + } + // Tiny convenience function to check if a value really changed before trying to set it. function setMetaDataEntry(entry_name, old_value, new_value) { From c48f02a7ebc29d57d35cf40bb167392b64b3917d Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 9 Jan 2017 14:19:22 +0100 Subject: [PATCH 10/11] Fix horizontal scrolling/flicking of materialview (probably windows-only) --- resources/qml/Preferences/MaterialView.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/qml/Preferences/MaterialView.qml b/resources/qml/Preferences/MaterialView.qml index 11df30e116..17f76466ab 100644 --- a/resources/qml/Preferences/MaterialView.qml +++ b/resources/qml/Preferences/MaterialView.qml @@ -40,6 +40,7 @@ TabView { anchors.fill: parent horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + flickableItem.flickableDirection: Flickable.VerticalFlick Flow { @@ -219,12 +220,12 @@ TabView onEditingFinished: base.setMetaDataEntry("adhesion_info", properties.adhesion_info, text) } } + function updateCostPerMeter() { base.spoolLength = calculateSpoolLength(diameterSpinBox.value, densitySpinBox.value, spoolWeightSpinBox.value); base.costPerMeter = calculateCostPerMeter(spoolCostSpinBox.value); } - } } From 6f06e9b3202b08b681d33f13be32a01cfc8e14e8 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 9 Jan 2017 15:24:20 +0100 Subject: [PATCH 11/11] Update material costs in slice info area when changing material settings (without reslicing) --- cura/PrintInformation.py | 43 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index cabba1bb25..b9593d57ee 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -6,6 +6,7 @@ from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty, pyqtSlot from UM.Application import Application from UM.Qt.Duration import Duration from UM.Preferences import Preferences +from UM.Settings import ContainerRegistry import cura.Settings.ExtruderManager @@ -61,6 +62,12 @@ class PrintInformation(QObject): Application.getInstance().globalContainerStackChanged.connect(self._setAbbreviatedMachineName) Application.getInstance().fileLoaded.connect(self.setJobName) + Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged) + + self._active_material_container = None + Application.getInstance().getMachineManager().activeMaterialChanged.connect(self._onActiveMaterialChanged) + self._onActiveMaterialChanged() + currentPrintTimeChanged = pyqtSignal() @pyqtProperty(Duration, notify = currentPrintTimeChanged) @@ -89,6 +96,10 @@ class PrintInformation(QObject): self._current_print_time.setDuration(total_time) self.currentPrintTimeChanged.emit() + self._material_amounts = material_amounts + self._calculateInformation() + + def _calculateInformation(self): # Material amount is sent as an amount of mm^3, so calculate length from that r = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") / 2 self._material_lengths = [] @@ -98,7 +109,7 @@ class PrintInformation(QObject): material_preference_values = json.loads(Preferences.getInstance().getValue("cura/material_settings")) extruder_stacks = list(cura.Settings.ExtruderManager.getInstance().getMachineExtruders(Application.getInstance().getGlobalContainerStack().getId())) - for index, amount in enumerate(material_amounts): + for index, amount in enumerate(self._material_amounts): ## Find the right extruder stack. As the list isn't sorted because it's a annoying generator, we do some # list comprehension filtering to solve this for us. material = None @@ -115,10 +126,15 @@ class PrintInformation(QObject): if material: material_guid = material.getMetaDataEntry("GUID") if material_guid in material_preference_values: - weight_per_spool = float(material_preference_values[material_guid]["spool_weight"]) - cost_per_spool = float(material_preference_values[material_guid]["spool_cost"]) + material_values = material_preference_values[material_guid] - cost = cost_per_spool * weight / weight_per_spool + weight_per_spool = float(material_values["spool_weight"] if material_values and "spool_weight" in material_values else 0) + cost_per_spool = float(material_values["spool_cost"] if material_values and "spool_cost" in material_values else 0) + + if weight_per_spool != 0: + cost = cost_per_spool * weight / weight_per_spool + else: + cost = 0 self._material_weights.append(weight) self._material_lengths.append(round((amount / (math.pi * r ** 2)) / 1000, 2)) @@ -128,6 +144,25 @@ class PrintInformation(QObject): self.materialWeightsChanged.emit() self.materialCostsChanged.emit() + def _onPreferencesChanged(self, preference): + if preference != "cura/material_settings": + return + + self._calculateInformation() + + def _onActiveMaterialChanged(self): + if self._active_material_container: + self._active_material_container.metaDataChanged.disconnect(self._onMaterialMetaDataChanged) + + active_material_id = Application.getInstance().getMachineManager().activeMaterialId + self._active_material_container = ContainerRegistry.getInstance().findInstanceContainers(id=active_material_id)[0] + + if self._active_material_container: + self._active_material_container.metaDataChanged.connect(self._onMaterialMetaDataChanged) + + def _onMaterialMetaDataChanged(self): + self._calculateInformation() + @pyqtSlot(str) def setJobName(self, name): # Ensure that we don't use entire path but only filename