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. 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. showAll: true
  254. }
  255. delegate: Loader
  256. {
  257. id: settingLoader
  258. width: listview.width
  259. height:
  260. {
  261. if (provider.properties.enabled == "True" && model.type != undefined)
  262. {
  263. return UM.Theme.getSize("section").height;
  264. }
  265. else
  266. {
  267. return 0
  268. }
  269. }
  270. Behavior on height { NumberAnimation { duration: 100 } }
  271. opacity: provider.properties.enabled == "True" ? 1 : 0
  272. Behavior on opacity { NumberAnimation { duration: 100 } }
  273. enabled: opacity > 0
  274. property var definition: model
  275. property var settingDefinitionsModel: definitionsModel
  276. property var propertyProvider: provider
  277. property var globalPropertyProvider: inheritStackProvider
  278. //Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989
  279. //In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes,
  280. //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely.
  281. asynchronous: model.type != "enum" && model.type != "extruder"
  282. onLoaded:
  283. {
  284. settingLoader.item.showRevertButton = false
  285. settingLoader.item.showInheritButton = false
  286. settingLoader.item.showLinkedSettingIcon = false
  287. settingLoader.item.doDepthIndentation = false
  288. settingLoader.item.doQualityUserSettingEmphasis = false
  289. }
  290. sourceComponent:
  291. {
  292. switch(model.type)
  293. {
  294. case "int":
  295. return settingTextField
  296. case "float":
  297. return settingTextField
  298. case "enum":
  299. return settingComboBox
  300. case "extruder":
  301. return settingExtruder
  302. case "bool":
  303. return settingCheckBox
  304. case "str":
  305. return settingTextField
  306. case "category":
  307. return settingCategory
  308. default:
  309. return settingUnknown
  310. }
  311. }
  312. UM.SettingPropertyProvider
  313. {
  314. id: provider
  315. containerStackId: manager.selectedScriptStackId
  316. key: model.key ? model.key : "None"
  317. watchedProperties: [ "value", "enabled", "state", "validationState" ]
  318. storeIndex: 0
  319. }
  320. // Specialty provider that only watches global_inherits (we can't filter on what property changed we get events
  321. // so we bypass that to make a dedicated provider).
  322. UM.SettingPropertyProvider
  323. {
  324. id: inheritStackProvider
  325. containerStack: Cura.MachineManager.activeMachine
  326. key: model.key ? model.key : "None"
  327. watchedProperties: [ "limit_to_extruder" ]
  328. }
  329. Connections
  330. {
  331. target: item
  332. function onShowTooltip(text)
  333. {
  334. tooltip.text = text;
  335. var position = settingLoader.mapToItem(settingsPanel, settingsPanel.x, 0);
  336. tooltip.show(position);
  337. tooltip.target.x = position.x + 1;
  338. }
  339. function onHideTooltip() { tooltip.hide() }
  340. }
  341. }
  342. }
  343. }
  344. Cura.PrintSetupTooltip
  345. {
  346. id: tooltip
  347. }
  348. Component
  349. {
  350. id: settingTextField;
  351. Cura.SettingTextField { }
  352. }
  353. Component
  354. {
  355. id: settingComboBox;
  356. Cura.SettingComboBox { }
  357. }
  358. Component
  359. {
  360. id: settingExtruder;
  361. Cura.SettingExtruder { }
  362. }
  363. Component
  364. {
  365. id: settingCheckBox;
  366. Cura.SettingCheckBox { }
  367. }
  368. Component
  369. {
  370. id: settingCategory;
  371. Cura.SettingCategory { }
  372. }
  373. Component
  374. {
  375. id: settingUnknown;
  376. Cura.SettingUnknown { }
  377. }
  378. }
  379. rightButtons: Cura.TertiaryButton
  380. {
  381. text: catalog.i18nc("@action:button", "Close")
  382. onClicked: dialog.accept()
  383. }
  384. Item
  385. {
  386. objectName: "postProcessingSaveAreaButton"
  387. visible: activeScriptsList.count > 0
  388. height: UM.Theme.getSize("action_button").height
  389. width: height
  390. Cura.SecondaryButton
  391. {
  392. height: UM.Theme.getSize("action_button").height
  393. tooltip:
  394. {
  395. var tipText = catalog.i18nc("@info:tooltip", "Change active post-processing scripts.");
  396. if (activeScriptsList.count > 0)
  397. {
  398. tipText += "<br><br>" + catalog.i18ncp("@info:tooltip",
  399. "The following script is active:",
  400. "The following scripts are active:",
  401. activeScriptsList.count
  402. ) + "<ul>";
  403. for(var i = 0; i < activeScriptsList.count; i++)
  404. {
  405. tipText += "<li>" + manager.getScriptLabelByKey(manager.scriptList[i]) + "</li>";
  406. }
  407. tipText += "</ul>";
  408. }
  409. return tipText
  410. }
  411. toolTipContentAlignment: UM.Enums.ContentAlignment.AlignLeft
  412. onClicked: dialog.show()
  413. iconSource: Qt.resolvedUrl("Script.svg")
  414. fixedWidthMode: false
  415. }
  416. Cura.NotificationIcon
  417. {
  418. id: activeScriptCountIcon
  419. visible: activeScriptsList.count > 0
  420. anchors
  421. {
  422. horizontalCenter: parent.right
  423. verticalCenter: parent.top
  424. }
  425. labelText: activeScriptsList.count
  426. }
  427. }
  428. }