PostProcessingPlugin.qml 17 KB

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