MaterialView.qml 20 KB

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