PostProcessingPlugin.qml 18 KB

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