PostProcessingPlugin.qml 20 KB

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