PostProcessingPlugin.qml 17 KB

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