Cura/resources/qml/Preferences/MaterialView.qml

516 lines
21 KiB
QML

// Copyright (c) 2017 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.8
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2
import UM 1.2 as UM
import Cura 1.0 as Cura
TabView
{
id: base
property QtObject properties
property var currentMaterialNode: null
property bool editingEnabled: false;
property string currency: UM.Preferences.getValue("cura/currency") ? UM.Preferences.getValue("cura/currency") : "€"
property real firstColumnWidth: (width * 0.50) | 0
property real secondColumnWidth: (width * 0.40) | 0
property string containerId: ""
property var materialPreferenceValues: UM.Preferences.getValue("cura/material_settings") ? JSON.parse(UM.Preferences.getValue("cura/material_settings")) : {}
property double spoolLength: calculateSpoolLength()
property real costPerMeter: calculateCostPerMeter()
property bool reevaluateLinkedMaterials: false
property string linkedMaterialNames:
{
if (reevaluateLinkedMaterials) {
reevaluateLinkedMaterials = false;
}
if (!base.containerId || !base.editingEnabled) {
return ""
}
var linkedMaterials = Cura.ContainerManager.getLinkedMaterials(base.currentMaterialNode);
if (linkedMaterials.length <= 1) {
return ""
}
return linkedMaterials.join(", ");
}
function getApproximateDiameter(diameter) {
return Math.round(diameter);
}
Tab
{
title: catalog.i18nc("@title", "Information")
anchors.margins: UM.Theme.getSize("default_margin").width
ScrollView
{
id: scrollView
anchors.fill: parent
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
flickableItem.flickableDirection: Flickable.VerticalFlick
frameVisible: true
property real columnWidth: (viewport.width * 0.5 - UM.Theme.getSize("default_margin").width) | 0
Flow
{
id: containerGrid
x: UM.Theme.getSize("default_margin").width
y: UM.Theme.getSize("default_lining").height
width: base.width
property real rowHeight: textField.height + UM.Theme.getSize("default_lining").height
MessageDialog
{
id: confirmDiameterChangeDialog
icon: StandardIcon.Question;
title: catalog.i18nc("@title:window", "Confirm Diameter Change")
text: catalog.i18nc("@label (%1 is object name)", "The new material diameter is set to %1 mm, which is not compatible to the current machine. Do you wish to continue?".arg(new_diameter_value))
standardButtons: StandardButton.Yes | StandardButton.No
modality: Qt.ApplicationModal
property var new_diameter_value: null;
property var old_diameter_value: null;
property var old_approximate_diameter_value: null;
onYes:
{
Cura.ContainerManager.setContainerProperty(base.containerId, "material_diameter", "value", new_diameter_value);
base.setMetaDataEntry("approximate_diameter", old_approximate_diameter_value, getApproximateDiameter(new_diameter_value).toString());
base.setMetaDataEntry("properties/diameter", properties.diameter, new_diameter_value);
}
onNo:
{
properties.diameter = old_diameter_value;
diameterSpinBox.value = properties.diameter;
}
}
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Display Name") }
ReadOnlyTextField
{
id: displayNameTextField;
width: scrollView.columnWidth;
text: properties.name;
readOnly: !base.editingEnabled;
onEditingFinished: base.updateMaterialDisplayName(properties.name, text)
}
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Brand") }
ReadOnlyTextField
{
id: textField;
width: scrollView.columnWidth;
text: properties.brand;
readOnly: !base.editingEnabled;
onEditingFinished: base.updateMaterialBrand(properties.brand, text)
}
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Material Type") }
ReadOnlyTextField
{
width: scrollView.columnWidth;
text: properties.material;
readOnly: !base.editingEnabled;
onEditingFinished: base.updateMaterialType(properties.material, text)
}
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Color") }
Row {
width: scrollView.columnWidth
height: parent.rowHeight
spacing: Math.round(UM.Theme.getSize("default_margin").width / 2)
// color indicator square
Rectangle {
id: colorSelector
color: properties.color_code
width: Math.round(colorLabel.height * 0.75)
height: Math.round(colorLabel.height * 0.75)
border.width: UM.Theme.getSize("default_lining").height
anchors.verticalCenter: parent.verticalCenter
// open the color selection dialog on click
MouseArea {
anchors.fill: parent
onClicked: colorDialog.open()
enabled: base.editingEnabled
}
}
// pretty color name text field
ReadOnlyTextField {
id: colorLabel;
text: properties.color_name;
readOnly: !base.editingEnabled
onEditingFinished: base.setMetaDataEntry("color_name", properties.color_name, text)
}
// popup dialog to select a new color
// if successful it sets the properties.color_code value to the new color
ColorDialog {
id: colorDialog
color: properties.color_code
onAccepted: base.setMetaDataEntry("color_code", properties.color_code, color)
}
}
Item { width: parent.width; height: UM.Theme.getSize("default_margin").height }
Label { width: parent.width; height: parent.rowHeight; font.bold: true; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Properties") }
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Density") }
ReadOnlySpinBox
{
id: densitySpinBox
width: scrollView.columnWidth
value: properties.density
decimals: 2
suffix: " g/cm³"
stepSize: 0.01
readOnly: !base.editingEnabled
onEditingFinished: base.setMetaDataEntry("properties/density", properties.density, value)
onValueChanged: updateCostPerMeter()
}
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Diameter") }
ReadOnlySpinBox
{
id: diameterSpinBox
width: scrollView.columnWidth
value: properties.diameter
decimals: 2
suffix: " mm"
stepSize: 0.01
readOnly: !base.editingEnabled
onEditingFinished:
{
// This does not use a SettingPropertyProvider, because we need to make the change to all containers
// which derive from the same base_file
var old_diameter = Cura.ContainerManager.getContainerProperty(base.containerId, "material_diameter", "value").toString();
var old_approximate_diameter = Cura.ContainerManager.getContainerMetaDataEntry(base.containerId, "approximate_diameter");
var new_approximate_diameter = getApproximateDiameter(value);
if (Cura.MachineManager.filterMaterialsByMachine && new_approximate_diameter != Cura.ExtruderManager.getActiveExtruderStack().approximateMaterialDiameter)
{
confirmDiameterChangeDialog.old_diameter_value = old_diameter;
confirmDiameterChangeDialog.new_diameter_value = value;
confirmDiameterChangeDialog.old_approximate_diameter_value = old_approximate_diameter;
confirmDiameterChangeDialog.open()
} else {
Cura.ContainerManager.setContainerProperty(base.containerId, "material_diameter", "value", value);
base.setMetaDataEntry("approximate_diameter", old_approximate_diameter, getApproximateDiameter(value).toString());
base.setMetaDataEntry("properties/diameter", properties.diameter, value);
}
}
onValueChanged: updateCostPerMeter()
}
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament Cost") }
SpinBox
{
id: spoolCostSpinBox
width: scrollView.columnWidth
value: base.getMaterialPreferenceValue(properties.guid, "spool_cost")
prefix: base.currency + " "
decimals: 2
maximumValue: 100000000
onValueChanged: {
base.setMaterialPreferenceValue(properties.guid, "spool_cost", parseFloat(value))
updateCostPerMeter()
}
}
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament weight") }
SpinBox
{
id: spoolWeightSpinBox
width: scrollView.columnWidth
value: base.getMaterialPreferenceValue(properties.guid, "spool_weight")
suffix: " g"
stepSize: 100
decimals: 0
maximumValue: 10000
onValueChanged: {
base.setMaterialPreferenceValue(properties.guid, "spool_weight", parseFloat(value))
updateCostPerMeter()
}
}
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament length") }
Label
{
width: scrollView.columnWidth
text: "~ %1 m".arg(Math.round(base.spoolLength))
verticalAlignment: Qt.AlignVCenter
height: parent.rowHeight
}
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Cost per Meter") }
Label
{
width: scrollView.columnWidth
text: "~ %1 %2/m".arg(base.costPerMeter.toFixed(2)).arg(base.currency)
verticalAlignment: Qt.AlignVCenter
height: parent.rowHeight
}
Item { width: parent.width; height: UM.Theme.getSize("default_margin").height; visible: unlinkMaterialButton.visible }
Label
{
width: 2 * scrollView.columnWidth
verticalAlignment: Qt.AlignVCenter
text: catalog.i18nc("@label", "This material is linked to %1 and shares some of its properties.").arg(base.linkedMaterialNames)
wrapMode: Text.WordWrap
visible: unlinkMaterialButton.visible
}
Button
{
id: unlinkMaterialButton
text: catalog.i18nc("@label", "Unlink Material")
visible: base.linkedMaterialNames != ""
onClicked:
{
Cura.ContainerManager.unlinkMaterial(base.currentMaterialNode)
base.reevaluateLinkedMaterials = true
}
}
Item { width: parent.width; height: UM.Theme.getSize("default_margin").height }
Label { width: parent.width; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Description") }
ReadOnlyTextArea
{
text: properties.description;
width: 2 * scrollView.columnWidth
wrapMode: Text.WordWrap
readOnly: !base.editingEnabled;
onEditingFinished: base.setMetaDataEntry("description", properties.description, text)
}
Label { width: parent.width; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Adhesion Information") }
ReadOnlyTextArea
{
text: properties.adhesion_info;
width: 2 * scrollView.columnWidth
wrapMode: Text.WordWrap
readOnly: !base.editingEnabled;
onEditingFinished: base.setMetaDataEntry("adhesion_info", properties.adhesion_info, text)
}
Item { width: parent.width; height: UM.Theme.getSize("default_margin").height }
}
function updateCostPerMeter()
{
base.spoolLength = calculateSpoolLength(diameterSpinBox.value, densitySpinBox.value, spoolWeightSpinBox.value);
base.costPerMeter = calculateCostPerMeter(spoolCostSpinBox.value);
}
}
}
Tab
{
title: catalog.i18nc("@label", "Print settings")
anchors
{
leftMargin: UM.Theme.getSize("default_margin").width
topMargin: UM.Theme.getSize("default_margin").height
bottomMargin: UM.Theme.getSize("default_margin").height
rightMargin: 0
}
ScrollView
{
anchors.fill: parent;
ListView
{
model: UM.SettingDefinitionsModel
{
containerId: Cura.MachineManager.activeDefinitionId
visibilityHandler: Cura.MaterialSettingsVisibilityHandler { }
expanded: ["*"]
}
delegate: UM.TooltipArea
{
width: childrenRect.width
height: childrenRect.height
text: model.description
Label
{
id: label
width: base.firstColumnWidth;
height: spinBox.height + UM.Theme.getSize("default_lining").height
text: model.label
elide: Text.ElideRight
verticalAlignment: Qt.AlignVCenter
}
ReadOnlySpinBox
{
id: spinBox
anchors.left: label.right
value: {
if (!isNaN(parseFloat(materialPropertyProvider.properties.value)))
{
return parseFloat(materialPropertyProvider.properties.value);
}
if (!isNaN(parseFloat(machinePropertyProvider.properties.value)))
{
return parseFloat(machinePropertyProvider.properties.value);
}
return 0;
}
width: base.secondColumnWidth
readOnly: !base.editingEnabled
suffix: " " + model.unit
maximumValue: 99999
decimals: model.unit == "mm" ? 2 : 0
onEditingFinished: materialPropertyProvider.setPropertyValue("value", value)
}
UM.ContainerPropertyProvider {
id: materialPropertyProvider
containerId: base.containerId
watchedProperties: [ "value" ]
key: model.key
}
UM.ContainerPropertyProvider {
id: machinePropertyProvider
containerId: Cura.MachineManager.activeDefinitionId
watchedProperties: [ "value" ]
key: model.key
}
}
}
}
}
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) {
if (old_value != new_value) {
Cura.ContainerManager.setContainerMetaDataEntry(base.currentMaterialNode, entry_name, new_value)
// make sure the UI properties are updated as well since we don't re-fetch the entire model here
// When the entry_name is something like properties/diameter, we take the last part of the entry_name
var list = entry_name.split("/")
var key = list[list.length - 1]
properties[key] = new_value
}
}
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;
}
// update the display name of the material
function updateMaterialDisplayName (old_name, new_name) {
// don't change when new name is the same
if (old_name == new_name) {
return
}
// update the values
Cura.ContainerManager.setMaterialName(base.currentMaterialNode, new_name)
materialProperties.name = new_name
}
// update the type of the material
function updateMaterialType (old_type, new_type) {
base.setMetaDataEntry("material", old_type, new_type)
materialProperties.material= new_type
}
// update the brand of the material
function updateMaterialBrand (old_brand, new_brand) {
base.setMetaDataEntry("brand", old_brand, new_brand)
materialProperties.brand = new_brand
}
}