MaterialView.qml 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. // Copyright (c) 2017 Ultimaker B.V.
  2. // Cura is released under the terms of the LGPLv3 or higher.
  3. import QtQuick 2.1
  4. import QtQuick.Controls 1.3
  5. import QtQuick.Dialogs 1.2
  6. import UM 1.2 as UM
  7. import Cura 1.0 as Cura
  8. TabView
  9. {
  10. id: base
  11. property QtObject properties;
  12. property bool editingEnabled: false;
  13. property string currency: UM.Preferences.getValue("cura/currency") ? UM.Preferences.getValue("cura/currency") : "€"
  14. property real firstColumnWidth: (width * 0.50) | 0
  15. property real secondColumnWidth: (width * 0.40) | 0
  16. property string containerId: ""
  17. property var materialPreferenceValues: UM.Preferences.getValue("cura/material_settings") ? JSON.parse(UM.Preferences.getValue("cura/material_settings")) : {}
  18. property double spoolLength: calculateSpoolLength()
  19. property real costPerMeter: calculateCostPerMeter()
  20. property bool reevaluateLinkedMaterials: false
  21. property string linkedMaterialNames:
  22. {
  23. if (reevaluateLinkedMaterials)
  24. {
  25. reevaluateLinkedMaterials = false;
  26. }
  27. if(!base.containerId || !base.editingEnabled)
  28. {
  29. return ""
  30. }
  31. var linkedMaterials = Cura.ContainerManager.getLinkedMaterials(base.containerId);
  32. return linkedMaterials.join(", ");
  33. }
  34. Tab
  35. {
  36. title: catalog.i18nc("@title", "Information")
  37. anchors.margins: UM.Theme.getSize("default_margin").width
  38. ScrollView
  39. {
  40. id: scrollView
  41. anchors.fill: parent
  42. horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
  43. flickableItem.flickableDirection: Flickable.VerticalFlick
  44. frameVisible: true
  45. property real columnWidth: (viewport.width * 0.5 - UM.Theme.getSize("default_margin").width) | 0
  46. Flow
  47. {
  48. id: containerGrid
  49. x: UM.Theme.getSize("default_margin").width
  50. y: UM.Theme.getSize("default_lining").height
  51. width: base.width
  52. property real rowHeight: textField.height + UM.Theme.getSize("default_lining").height
  53. Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Display Name") }
  54. ReadOnlyTextField
  55. {
  56. id: displayNameTextField;
  57. width: scrollView.columnWidth;
  58. text: properties.name;
  59. readOnly: !base.editingEnabled;
  60. onEditingFinished: base.updateMaterialDisplayName(properties.name, text)
  61. }
  62. Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Brand") }
  63. ReadOnlyTextField
  64. {
  65. id: textField;
  66. width: scrollView.columnWidth;
  67. text: properties.supplier;
  68. readOnly: !base.editingEnabled;
  69. onEditingFinished: base.updateMaterialSupplier(properties.supplier, text)
  70. }
  71. Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Material Type") }
  72. ReadOnlyTextField
  73. {
  74. width: scrollView.columnWidth;
  75. text: properties.material_type;
  76. readOnly: !base.editingEnabled;
  77. onEditingFinished: base.updateMaterialType(properties.material_type, text)
  78. }
  79. Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Color") }
  80. Row {
  81. width: scrollView.columnWidth
  82. height: parent.rowHeight
  83. spacing: Math.floor(UM.Theme.getSize("default_margin").width/2)
  84. // color indicator square
  85. Rectangle {
  86. id: colorSelector
  87. color: properties.color_code
  88. width: Math.floor(colorLabel.height * 0.75)
  89. height: Math.floor(colorLabel.height * 0.75)
  90. border.width: UM.Theme.getSize("default_lining").height
  91. anchors.verticalCenter: parent.verticalCenter
  92. // open the color selection dialog on click
  93. MouseArea {
  94. anchors.fill: parent
  95. onClicked: colorDialog.open()
  96. enabled: base.editingEnabled
  97. }
  98. }
  99. // pretty color name text field
  100. ReadOnlyTextField {
  101. id: colorLabel;
  102. text: properties.color_name;
  103. readOnly: !base.editingEnabled
  104. onEditingFinished: base.setMetaDataEntry("color_name", properties.color_name, text)
  105. }
  106. // popup dialog to select a new color
  107. // if successful it sets the properties.color_code value to the new color
  108. ColorDialog {
  109. id: colorDialog
  110. color: properties.color_code
  111. onAccepted: base.setMetaDataEntry("color_code", properties.color_code, color)
  112. }
  113. }
  114. Item { width: parent.width; height: UM.Theme.getSize("default_margin").height }
  115. Label { width: parent.width; height: parent.rowHeight; font.bold: true; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Properties") }
  116. Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Density") }
  117. ReadOnlySpinBox
  118. {
  119. id: densitySpinBox
  120. width: scrollView.columnWidth
  121. value: properties.density
  122. decimals: 2
  123. suffix: " g/cm³"
  124. stepSize: 0.01
  125. readOnly: !base.editingEnabled
  126. onEditingFinished: base.setMetaDataEntry("properties/density", properties.density, value)
  127. onValueChanged: updateCostPerMeter()
  128. }
  129. Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Diameter") }
  130. ReadOnlySpinBox
  131. {
  132. id: diameterSpinBox
  133. width: scrollView.columnWidth
  134. value: properties.diameter
  135. decimals: 2
  136. suffix: " mm"
  137. stepSize: 0.01
  138. readOnly: !base.editingEnabled
  139. onEditingFinished:
  140. {
  141. // This does not use a SettingPropertyProvider, because we need to make the change to all containers
  142. // which derive from the same base_file
  143. var old_diameter = Cura.ContainerManager.getContainerProperty(base.containerId, "material_diameter", "value").toString();
  144. var old_approximate_diameter = Cura.ContainerManager.getContainerMetaDataEntry(base.containerId, "approximate_diameter");
  145. base.setMetaDataEntry("approximate_diameter", old_approximate_diameter, Math.round(value).toString());
  146. base.setMetaDataEntry("properties/diameter", properties.diameter, value);
  147. var new_approximate_diameter = Cura.ContainerManager.getContainerMetaDataEntry(base.containerId, "approximate_diameter");
  148. if (Cura.MachineManager.filterMaterialsByMachine && new_approximate_diameter != Cura.MachineManager.activeMachine.approximateMaterialDiameter)
  149. {
  150. Cura.MaterialManager.showMaterialWarningMessage(base.containerId, old_diameter);
  151. }
  152. Cura.ContainerManager.setContainerProperty(base.containerId, "material_diameter", "value", value);
  153. }
  154. onValueChanged: updateCostPerMeter()
  155. }
  156. Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament Cost") }
  157. SpinBox
  158. {
  159. id: spoolCostSpinBox
  160. width: scrollView.columnWidth
  161. value: base.getMaterialPreferenceValue(properties.guid, "spool_cost")
  162. prefix: base.currency + " "
  163. decimals: 2
  164. maximumValue: 100000000
  165. onValueChanged: {
  166. base.setMaterialPreferenceValue(properties.guid, "spool_cost", parseFloat(value))
  167. updateCostPerMeter()
  168. }
  169. }
  170. Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament weight") }
  171. SpinBox
  172. {
  173. id: spoolWeightSpinBox
  174. width: scrollView.columnWidth
  175. value: base.getMaterialPreferenceValue(properties.guid, "spool_weight")
  176. suffix: " g"
  177. stepSize: 100
  178. decimals: 0
  179. maximumValue: 10000
  180. onValueChanged: {
  181. base.setMaterialPreferenceValue(properties.guid, "spool_weight", parseFloat(value))
  182. updateCostPerMeter()
  183. }
  184. }
  185. Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament length") }
  186. Label
  187. {
  188. width: scrollView.columnWidth
  189. text: "~ %1 m".arg(Math.round(base.spoolLength))
  190. verticalAlignment: Qt.AlignVCenter
  191. height: parent.rowHeight
  192. }
  193. Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Cost per Meter") }
  194. Label
  195. {
  196. width: scrollView.columnWidth
  197. text: "~ %1 %2/m".arg(base.costPerMeter.toFixed(2)).arg(base.currency)
  198. verticalAlignment: Qt.AlignVCenter
  199. height: parent.rowHeight
  200. }
  201. Item { width: parent.width; height: UM.Theme.getSize("default_margin").height; visible: unlinkMaterialButton.visible }
  202. Label
  203. {
  204. width: 2 * scrollView.columnWidth
  205. verticalAlignment: Qt.AlignVCenter
  206. text: catalog.i18nc("@label", "This material is linked to %1 and shares some of its properties.").arg(base.linkedMaterialNames)
  207. wrapMode: Text.WordWrap
  208. visible: unlinkMaterialButton.visible
  209. }
  210. Button
  211. {
  212. id: unlinkMaterialButton
  213. text: catalog.i18nc("@label", "Unlink Material")
  214. visible: base.linkedMaterialNames != ""
  215. onClicked:
  216. {
  217. Cura.ContainerManager.unlinkMaterial(base.containerId)
  218. base.reevaluateLinkedMaterials = true
  219. }
  220. }
  221. Item { width: parent.width; height: UM.Theme.getSize("default_margin").height }
  222. Label { width: parent.width; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Description") }
  223. ReadOnlyTextArea
  224. {
  225. text: properties.description;
  226. width: 2 * scrollView.columnWidth
  227. wrapMode: Text.WordWrap
  228. readOnly: !base.editingEnabled;
  229. onEditingFinished: base.setMetaDataEntry("description", properties.description, text)
  230. }
  231. Label { width: parent.width; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Adhesion Information") }
  232. ReadOnlyTextArea
  233. {
  234. text: properties.adhesion_info;
  235. width: 2 * scrollView.columnWidth
  236. wrapMode: Text.WordWrap
  237. readOnly: !base.editingEnabled;
  238. onEditingFinished: base.setMetaDataEntry("adhesion_info", properties.adhesion_info, text)
  239. }
  240. Item { width: parent.width; height: UM.Theme.getSize("default_margin").height }
  241. }
  242. function updateCostPerMeter()
  243. {
  244. base.spoolLength = calculateSpoolLength(diameterSpinBox.value, densitySpinBox.value, spoolWeightSpinBox.value);
  245. base.costPerMeter = calculateCostPerMeter(spoolCostSpinBox.value);
  246. }
  247. }
  248. }
  249. Tab
  250. {
  251. title: catalog.i18nc("@label", "Print settings")
  252. anchors
  253. {
  254. leftMargin: UM.Theme.getSize("default_margin").width
  255. topMargin: UM.Theme.getSize("default_margin").height
  256. bottomMargin: UM.Theme.getSize("default_margin").height
  257. rightMargin: 0
  258. }
  259. ScrollView
  260. {
  261. anchors.fill: parent;
  262. ListView
  263. {
  264. model: UM.SettingDefinitionsModel
  265. {
  266. containerId: Cura.MachineManager.activeDefinitionId
  267. visibilityHandler: Cura.MaterialSettingsVisibilityHandler { }
  268. expanded: ["*"]
  269. }
  270. delegate: UM.TooltipArea
  271. {
  272. width: childrenRect.width
  273. height: childrenRect.height
  274. text: model.description
  275. Label
  276. {
  277. id: label
  278. width: base.firstColumnWidth;
  279. height: spinBox.height + UM.Theme.getSize("default_lining").height
  280. text: model.label
  281. elide: Text.ElideRight
  282. verticalAlignment: Qt.AlignVCenter
  283. }
  284. ReadOnlySpinBox
  285. {
  286. id: spinBox
  287. anchors.left: label.right
  288. value: {
  289. if (!isNaN(parseFloat(materialPropertyProvider.properties.value)))
  290. {
  291. return parseFloat(materialPropertyProvider.properties.value);
  292. }
  293. if (!isNaN(parseFloat(machinePropertyProvider.properties.value)))
  294. {
  295. return parseFloat(machinePropertyProvider.properties.value);
  296. }
  297. return 0;
  298. }
  299. width: base.secondColumnWidth
  300. readOnly: !base.editingEnabled
  301. suffix: " " + model.unit
  302. maximumValue: 99999
  303. decimals: model.unit == "mm" ? 2 : 0
  304. onEditingFinished: materialPropertyProvider.setPropertyValue("value", value)
  305. }
  306. UM.ContainerPropertyProvider { id: materialPropertyProvider; containerId: base.containerId; watchedProperties: [ "value" ]; key: model.key }
  307. UM.ContainerPropertyProvider { id: machinePropertyProvider; containerId: Cura.MachineManager.activeDefinitionId; watchedProperties: [ "value" ]; key: model.key }
  308. }
  309. }
  310. }
  311. }
  312. function calculateSpoolLength(diameter, density, spoolWeight)
  313. {
  314. if(!diameter)
  315. {
  316. diameter = properties.diameter;
  317. }
  318. if(!density)
  319. {
  320. density = properties.density;
  321. }
  322. if(!spoolWeight)
  323. {
  324. spoolWeight = base.getMaterialPreferenceValue(properties.guid, "spool_weight");
  325. }
  326. if (diameter == 0 || density == 0 || spoolWeight == 0)
  327. {
  328. return 0;
  329. }
  330. var area = Math.PI * Math.pow(diameter / 2, 2); // in mm2
  331. var volume = (spoolWeight / density); // in cm3
  332. return volume / area; // in m
  333. }
  334. function calculateCostPerMeter(spoolCost)
  335. {
  336. if(!spoolCost)
  337. {
  338. spoolCost = base.getMaterialPreferenceValue(properties.guid, "spool_cost");
  339. }
  340. if (spoolLength == 0)
  341. {
  342. return 0;
  343. }
  344. return spoolCost / spoolLength;
  345. }
  346. // Tiny convenience function to check if a value really changed before trying to set it.
  347. function setMetaDataEntry(entry_name, old_value, new_value) {
  348. if (old_value != new_value) {
  349. Cura.ContainerManager.setContainerMetaDataEntry(base.containerId, entry_name, new_value)
  350. // make sure the UI properties are updated as well since we don't re-fetch the entire model here
  351. properties[entry_name] = new_value
  352. }
  353. }
  354. function setMaterialPreferenceValue(material_guid, entry_name, new_value)
  355. {
  356. if(!(material_guid in materialPreferenceValues))
  357. {
  358. materialPreferenceValues[material_guid] = {};
  359. }
  360. if(entry_name in materialPreferenceValues[material_guid] && materialPreferenceValues[material_guid][entry_name] == new_value)
  361. {
  362. // value has not changed
  363. return
  364. }
  365. materialPreferenceValues[material_guid][entry_name] = new_value;
  366. // store preference
  367. UM.Preferences.setValue("cura/material_settings", JSON.stringify(materialPreferenceValues));
  368. }
  369. function getMaterialPreferenceValue(material_guid, entry_name)
  370. {
  371. if(material_guid in materialPreferenceValues && entry_name in materialPreferenceValues[material_guid])
  372. {
  373. return materialPreferenceValues[material_guid][entry_name];
  374. }
  375. return 0;
  376. }
  377. // update the display name of the material
  378. function updateMaterialDisplayName (old_name, new_name) {
  379. // don't change when new name is the same
  380. if (old_name == new_name) {
  381. return
  382. }
  383. // update the values
  384. Cura.ContainerManager.setContainerName(base.containerId, new_name)
  385. materialProperties.name = new_name
  386. }
  387. // update the type of the material
  388. function updateMaterialType (old_type, new_type) {
  389. base.setMetaDataEntry("material", old_type, new_type)
  390. materialProperties.material_type = new_type
  391. }
  392. // update the supplier of the material
  393. function updateMaterialSupplier (old_supplier, new_supplier) {
  394. base.setMetaDataEntry("brand", old_supplier, new_supplier)
  395. materialProperties.supplier = new_supplier
  396. }
  397. }