PostProcessingPlugin.qml 18 KB

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