PostProcessingPlugin.qml 18 KB

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