PostProcessingPlugin.qml 17 KB

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