PostProcessingPlugin.qml 19 KB

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