PostProcessingPlugin.qml 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. // Copyright (c) 2022 Jaime van Kessel, Ultimaker B.V.
  2. // The PostProcessingPlugin is released under the terms of the AGPLv3 or higher.
  3. import QtQuick 2.2
  4. import QtQuick.Controls 2.15
  5. import QtQml.Models 2.15 as Models
  6. import QtQuick.Layouts 1.1
  7. import QtQuick.Window 2.2
  8. import UM 1.5 as UM
  9. import Cura 1.0 as Cura
  10. UM.Dialog
  11. {
  12. id: dialog
  13. title: catalog.i18nc("@title:window", "Post Processing Plugin")
  14. width: 700 * screenScaleFactor
  15. height: 500 * screenScaleFactor
  16. minimumWidth: 400 * screenScaleFactor
  17. minimumHeight: 250 * screenScaleFactor
  18. onVisibleChanged:
  19. {
  20. // Whenever the window is closed (either via the "Close" button or the X on the window frame), we want to update it in the stack.
  21. if (!visible)
  22. {
  23. manager.writeScriptsToStack()
  24. }
  25. }
  26. Item
  27. {
  28. UM.I18nCatalog{id: catalog; name: "cura"}
  29. id: base
  30. property int columnWidth: Math.round((base.width / 2) - UM.Theme.getSize("default_margin").width)
  31. property int textMargin: UM.Theme.getSize("narrow_margin").width
  32. property string activeScriptName
  33. anchors.fill: parent
  34. ButtonGroup
  35. {
  36. id: selectedScriptGroup
  37. }
  38. Column
  39. {
  40. id: activeScripts
  41. width: base.columnWidth
  42. height: parent.height
  43. spacing: base.textMargin
  44. UM.Label
  45. {
  46. id: activeScriptsHeader
  47. text: catalog.i18nc("@label", "Post Processing Scripts")
  48. anchors.left: parent.left
  49. anchors.right: parent.right
  50. font: UM.Theme.getFont("large_bold")
  51. elide: Text.ElideRight
  52. }
  53. ListView
  54. {
  55. id: activeScriptsList
  56. anchors
  57. {
  58. left: parent.left
  59. right: parent.right
  60. rightMargin: base.textMargin
  61. }
  62. height: Math.min(contentHeight, parent.height - parent.spacing * 2 - activeScriptsHeader.height - addButton.height) //At the window height, start scrolling this one.
  63. clip: true
  64. ScrollBar.vertical: UM.ScrollBar
  65. {
  66. id: activeScriptsScrollBar
  67. }
  68. model: manager.scriptList
  69. delegate: Button
  70. {
  71. id: activeScriptButton
  72. width: parent.width - activeScriptsScrollBar.width
  73. height: UM.Theme.getSize("standard_list_lineheight").height
  74. ButtonGroup.group: selectedScriptGroup
  75. checkable: true
  76. checked:
  77. {
  78. if (manager.selectedScriptIndex == index)
  79. {
  80. base.activeScriptName = manager.getScriptLabelByKey(modelData.toString())
  81. return true
  82. }
  83. else
  84. {
  85. return false
  86. }
  87. }
  88. background: Rectangle
  89. {
  90. color: activeScriptButton.checked ? UM.Theme.getColor("background_3") : "transparent"
  91. }
  92. onClicked:
  93. {
  94. forceActiveFocus()
  95. manager.setSelectedScriptIndex(index)
  96. base.activeScriptName = manager.getScriptLabelByKey(modelData.toString())
  97. }
  98. RowLayout
  99. {
  100. anchors.fill: parent
  101. UM.Label
  102. {
  103. Layout.fillWidth: true
  104. text: manager.getScriptLabelByKey(modelData.toString())
  105. }
  106. Item
  107. {
  108. id: downButton
  109. Layout.preferredWidth: height
  110. Layout.fillHeight: true
  111. enabled: index != manager.scriptList.length - 1
  112. MouseArea
  113. {
  114. anchors.fill: parent
  115. onClicked:
  116. {
  117. if (manager.selectedScriptIndex == index)
  118. {
  119. manager.setSelectedScriptIndex(index + 1)
  120. }
  121. return manager.moveScript(index, index + 1)
  122. }
  123. }
  124. UM.ColorImage
  125. {
  126. anchors.verticalCenter: parent.verticalCenter
  127. anchors.horizontalCenter: parent.horizontalCenter
  128. width: UM.Theme.getSize("standard_arrow").width
  129. height: UM.Theme.getSize("standard_arrow").height
  130. color: parent.enabled ? UM.Theme.getColor("text") : UM.Theme.getColor("text_disabled")
  131. source: UM.Theme.getIcon("ChevronSingleDown")
  132. }
  133. }
  134. Item
  135. {
  136. id: upButton
  137. Layout.preferredWidth: height
  138. Layout.fillHeight: true
  139. enabled: index != 0
  140. MouseArea
  141. {
  142. anchors.fill: parent
  143. onClicked:
  144. {
  145. if (manager.selectedScriptIndex == index)
  146. {
  147. manager.setSelectedScriptIndex(index - 1)
  148. }
  149. return manager.moveScript(index, index - 1)
  150. }
  151. }
  152. UM.ColorImage
  153. {
  154. anchors.verticalCenter: parent.verticalCenter
  155. anchors.horizontalCenter: parent.horizontalCenter
  156. width: UM.Theme.getSize("standard_arrow").width
  157. height: UM.Theme.getSize("standard_arrow").height
  158. color: upButton.enabled ? UM.Theme.getColor("text") : UM.Theme.getColor("text_disabled")
  159. source: UM.Theme.getIcon("ChevronSingleUp")
  160. }
  161. }
  162. Item
  163. {
  164. id: removeButton
  165. Layout.preferredWidth: height
  166. Layout.fillHeight: true
  167. MouseArea
  168. {
  169. anchors.fill: parent
  170. onClicked: manager.removeScriptByIndex(index)
  171. }
  172. UM.ColorImage
  173. {
  174. anchors.verticalCenter: parent.verticalCenter
  175. anchors.horizontalCenter: parent.horizontalCenter
  176. width: UM.Theme.getSize("standard_arrow").width
  177. height: UM.Theme.getSize("standard_arrow").height
  178. color: UM.Theme.getColor("text")
  179. source: UM.Theme.getIcon("Cancel")
  180. }
  181. }
  182. }
  183. }
  184. }
  185. Cura.SecondaryButton
  186. {
  187. id: addButton
  188. text: catalog.i18nc("@action", "Add a script")
  189. onClicked: scriptsMenu.open()
  190. }
  191. }
  192. Cura.Menu
  193. {
  194. id: scriptsMenu
  195. Models.Instantiator
  196. {
  197. model: manager.loadedScriptList
  198. Cura.MenuItem
  199. {
  200. text: manager.getScriptLabelByKey(modelData.toString())
  201. onTriggered: manager.addScriptToList(modelData.toString())
  202. }
  203. onObjectAdded: function(index, object) { scriptsMenu.insertItem(index, object)}
  204. onObjectRemoved: function(index, object) { scriptsMenu.removeItem(object) }
  205. }
  206. }
  207. Rectangle
  208. {
  209. color: UM.Theme.getColor("main_background")
  210. anchors.left: activeScripts.right
  211. anchors.leftMargin: UM.Theme.getSize("default_margin").width
  212. anchors.right: parent.right
  213. height: parent.height
  214. id: settingsPanel
  215. UM.Label
  216. {
  217. id: scriptSpecsHeader
  218. text: manager.selectedScriptIndex == -1 ? catalog.i18nc("@label", "Settings") : base.activeScriptName
  219. anchors
  220. {
  221. top: parent.top
  222. topMargin: base.textMargin
  223. left: parent.left
  224. leftMargin: base.textMargin
  225. right: parent.right
  226. rightMargin: base.textMargin
  227. }
  228. elide: Text.ElideRight
  229. height: 20 * screenScaleFactor
  230. font: UM.Theme.getFont("large_bold")
  231. }
  232. ListView
  233. {
  234. id: listview
  235. anchors
  236. {
  237. top: scriptSpecsHeader.bottom
  238. topMargin: settingsPanel.textMargin
  239. left: parent.left
  240. leftMargin: UM.Theme.getSize("default_margin").width
  241. right: parent.right
  242. bottom: parent.bottom
  243. }
  244. ScrollBar.vertical: UM.ScrollBar {}
  245. clip: true
  246. visible: manager.selectedScriptDefinitionId != ""
  247. spacing: UM.Theme.getSize("default_lining").height
  248. model: UM.SettingDefinitionsModel
  249. {
  250. id: definitionsModel
  251. containerId: manager.selectedScriptDefinitionId
  252. showAll: true
  253. }
  254. delegate: Loader
  255. {
  256. id: settingLoader
  257. width: listview.width
  258. height:
  259. {
  260. if (provider.properties.enabled == "True" && model.type != undefined)
  261. {
  262. return UM.Theme.getSize("section").height;
  263. }
  264. else
  265. {
  266. return 0
  267. }
  268. }
  269. Behavior on height { NumberAnimation { duration: 100 } }
  270. opacity: provider.properties.enabled == "True" ? 1 : 0
  271. Behavior on opacity { NumberAnimation { duration: 100 } }
  272. enabled: opacity > 0
  273. property var definition: model
  274. property var settingDefinitionsModel: definitionsModel
  275. property var propertyProvider: provider
  276. property var globalPropertyProvider: inheritStackProvider
  277. //Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989
  278. //In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes,
  279. //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely.
  280. asynchronous: model.type != "enum" && model.type != "extruder"
  281. onLoaded:
  282. {
  283. settingLoader.item.showRevertButton = false
  284. settingLoader.item.showInheritButton = false
  285. settingLoader.item.showLinkedSettingIcon = false
  286. settingLoader.item.doDepthIndentation = false
  287. settingLoader.item.doQualityUserSettingEmphasis = false
  288. }
  289. sourceComponent:
  290. {
  291. switch(model.type)
  292. {
  293. case "int":
  294. return settingTextField
  295. case "float":
  296. return settingTextField
  297. case "enum":
  298. return settingComboBox
  299. case "extruder":
  300. return settingExtruder
  301. case "bool":
  302. return settingCheckBox
  303. case "str":
  304. return settingTextField
  305. case "category":
  306. return settingCategory
  307. default:
  308. return settingUnknown
  309. }
  310. }
  311. UM.SettingPropertyProvider
  312. {
  313. id: provider
  314. containerStackId: manager.selectedScriptStackId
  315. key: model.key ? model.key : "None"
  316. watchedProperties: [ "value", "enabled", "state", "validationState" ]
  317. storeIndex: 0
  318. }
  319. // Specialty provider that only watches global_inherits (we can't filter on what property changed we get events
  320. // so we bypass that to make a dedicated provider).
  321. UM.SettingPropertyProvider
  322. {
  323. id: inheritStackProvider
  324. containerStack: Cura.MachineManager.activeMachine
  325. key: model.key ? model.key : "None"
  326. watchedProperties: [ "limit_to_extruder" ]
  327. }
  328. Connections
  329. {
  330. target: item
  331. function onShowTooltip(text)
  332. {
  333. tooltip.text = text;
  334. var position = settingLoader.mapToItem(settingsPanel, settingsPanel.x, 0);
  335. tooltip.show(position);
  336. tooltip.target.x = position.x + 1;
  337. }
  338. function onHideTooltip() { tooltip.hide() }
  339. }
  340. }
  341. }
  342. }
  343. Cura.PrintSetupTooltip
  344. {
  345. id: tooltip
  346. }
  347. Component
  348. {
  349. id: settingTextField;
  350. Cura.SettingTextField { }
  351. }
  352. Component
  353. {
  354. id: settingComboBox;
  355. Cura.SettingComboBox { }
  356. }
  357. Component
  358. {
  359. id: settingExtruder;
  360. Cura.SettingExtruder { }
  361. }
  362. Component
  363. {
  364. id: settingCheckBox;
  365. Cura.SettingCheckBox { }
  366. }
  367. Component
  368. {
  369. id: settingCategory;
  370. Cura.SettingCategory { }
  371. }
  372. Component
  373. {
  374. id: settingUnknown;
  375. Cura.SettingUnknown { }
  376. }
  377. }
  378. rightButtons: Cura.TertiaryButton
  379. {
  380. text: catalog.i18nc("@action:button", "Close")
  381. onClicked: dialog.accept()
  382. }
  383. Item
  384. {
  385. objectName: "postProcessingSaveAreaButton"
  386. visible: activeScriptsList.count > 0
  387. height: UM.Theme.getSize("action_button").height
  388. width: height
  389. Cura.SecondaryButton
  390. {
  391. height: UM.Theme.getSize("action_button").height
  392. tooltip:
  393. {
  394. var tipText = catalog.i18nc("@info:tooltip", "Change active post-processing scripts.");
  395. if (activeScriptsList.count > 0)
  396. {
  397. tipText += "<br><br>" + catalog.i18ncp("@info:tooltip",
  398. "The following script is active:",
  399. "The following scripts are active:",
  400. activeScriptsList.count
  401. ) + "<ul>";
  402. for(var i = 0; i < activeScriptsList.count; i++)
  403. {
  404. tipText += "<li>" + manager.getScriptLabelByKey(manager.scriptList[i]) + "</li>";
  405. }
  406. tipText += "</ul>";
  407. }
  408. return tipText
  409. }
  410. toolTipContentAlignment: UM.Enums.ContentAlignment.AlignLeft
  411. onClicked: dialog.show()
  412. iconSource: Qt.resolvedUrl("Script.svg")
  413. fixedWidthMode: false
  414. }
  415. Cura.NotificationIcon
  416. {
  417. id: activeScriptCountIcon
  418. visible: activeScriptsList.count > 0
  419. anchors
  420. {
  421. horizontalCenter: parent.right
  422. verticalCenter: parent.top
  423. }
  424. labelText: activeScriptsList.count
  425. }
  426. }
  427. }