SimulationView.qml 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. // Copyright (c) 2017 Ultimaker B.V.
  2. // Cura is released under the terms of the LGPLv3 or higher.
  3. import QtQuick 2.4
  4. import QtQuick.Controls 1.2
  5. import QtQuick.Layouts 1.1
  6. import QtQuick.Controls.Styles 1.1
  7. import UM 1.0 as UM
  8. import Cura 1.0 as Cura
  9. Item
  10. {
  11. id: base
  12. width: {
  13. if (UM.SimulationView.compatibilityMode) {
  14. return UM.Theme.getSize("layerview_menu_size_compatibility").width;
  15. } else {
  16. return UM.Theme.getSize("layerview_menu_size").width;
  17. }
  18. }
  19. height: {
  20. if (viewSettings.collapsed) {
  21. if (UM.SimulationView.compatibilityMode) {
  22. return UM.Theme.getSize("layerview_menu_size_compatibility_collapsed").height;
  23. }
  24. return UM.Theme.getSize("layerview_menu_size_collapsed").height;
  25. } else if (UM.SimulationView.compatibilityMode) {
  26. return UM.Theme.getSize("layerview_menu_size_compatibility").height;
  27. } else if (UM.Preferences.getValue("layerview/layer_view_type") == 0) {
  28. return UM.Theme.getSize("layerview_menu_size_material_color_mode").height + UM.SimulationView.extruderCount * (UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("layerview_row_spacing").height)
  29. } else {
  30. return UM.Theme.getSize("layerview_menu_size").height + UM.SimulationView.extruderCount * (UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("layerview_row_spacing").height)
  31. }
  32. }
  33. Behavior on height { NumberAnimation { duration: 100 } }
  34. property var buttonTarget: {
  35. if(parent != null)
  36. {
  37. var force_binding = parent.y; // ensure this gets reevaluated when the panel moves
  38. return base.mapFromItem(parent.parent, parent.buttonTarget.x, parent.buttonTarget.y)
  39. }
  40. return Qt.point(0,0)
  41. }
  42. visible: parent != null ? !parent.parent.monitoringPrint: true
  43. Rectangle {
  44. id: layerViewMenu
  45. anchors.right: parent.right
  46. anchors.top: parent.top
  47. width: parent.width
  48. height: parent.height
  49. clip: true
  50. z: layerSlider.z - 1
  51. color: UM.Theme.getColor("tool_panel_background")
  52. border.width: UM.Theme.getSize("default_lining").width
  53. border.color: UM.Theme.getColor("lining")
  54. Button {
  55. id: collapseButton
  56. anchors.top: parent.top
  57. anchors.topMargin: Math.round(UM.Theme.getSize("default_margin").height + (UM.Theme.getSize("layerview_row").height - UM.Theme.getSize("default_margin").height) / 2)
  58. anchors.right: parent.right
  59. anchors.rightMargin: UM.Theme.getSize("default_margin").width
  60. width: UM.Theme.getSize("standard_arrow").width
  61. height: UM.Theme.getSize("standard_arrow").height
  62. onClicked: viewSettings.collapsed = !viewSettings.collapsed
  63. style: ButtonStyle
  64. {
  65. background: UM.RecolorImage
  66. {
  67. width: control.width
  68. height: control.height
  69. sourceSize.width: width
  70. sourceSize.height: width
  71. color: UM.Theme.getColor("setting_control_text")
  72. source: viewSettings.collapsed ? UM.Theme.getIcon("arrow_left") : UM.Theme.getIcon("arrow_bottom")
  73. }
  74. label: Label{ }
  75. }
  76. }
  77. ColumnLayout {
  78. id: viewSettings
  79. property bool collapsed: false
  80. property var extruder_opacities: UM.Preferences.getValue("layerview/extruder_opacities").split("|")
  81. property bool show_travel_moves: UM.Preferences.getValue("layerview/show_travel_moves")
  82. property bool show_helpers: UM.Preferences.getValue("layerview/show_helpers")
  83. property bool show_skin: UM.Preferences.getValue("layerview/show_skin")
  84. property bool show_infill: UM.Preferences.getValue("layerview/show_infill")
  85. // if we are in compatibility mode, we only show the "line type"
  86. property bool show_legend: UM.SimulationView.compatibilityMode ? true : UM.Preferences.getValue("layerview/layer_view_type") == 1
  87. property bool show_gradient: UM.SimulationView.compatibilityMode ? false : UM.Preferences.getValue("layerview/layer_view_type") == 2 || UM.Preferences.getValue("layerview/layer_view_type") == 3
  88. property bool show_feedrate_gradient: show_gradient && UM.Preferences.getValue("layerview/layer_view_type") == 2
  89. property bool show_thickness_gradient: show_gradient && UM.Preferences.getValue("layerview/layer_view_type") == 3
  90. property bool only_show_top_layers: UM.Preferences.getValue("view/only_show_top_layers")
  91. property int top_layer_count: UM.Preferences.getValue("view/top_layer_count")
  92. anchors.top: parent.top
  93. anchors.topMargin: UM.Theme.getSize("default_margin").height
  94. anchors.left: parent.left
  95. anchors.leftMargin: UM.Theme.getSize("default_margin").width
  96. anchors.right: parent.right
  97. anchors.rightMargin: UM.Theme.getSize("default_margin").width
  98. spacing: UM.Theme.getSize("layerview_row_spacing").height
  99. Label
  100. {
  101. id: layerViewTypesLabel
  102. anchors.left: parent.left
  103. text: catalog.i18nc("@label","Color scheme")
  104. font: UM.Theme.getFont("default");
  105. visible: !UM.SimulationView.compatibilityMode
  106. Layout.fillWidth: true
  107. color: UM.Theme.getColor("setting_control_text")
  108. }
  109. ListModel // matches SimulationView.py
  110. {
  111. id: layerViewTypes
  112. }
  113. Component.onCompleted:
  114. {
  115. layerViewTypes.append({
  116. text: catalog.i18nc("@label:listbox", "Material Color"),
  117. type_id: 0
  118. })
  119. layerViewTypes.append({
  120. text: catalog.i18nc("@label:listbox", "Line Type"),
  121. type_id: 1
  122. })
  123. layerViewTypes.append({
  124. text: catalog.i18nc("@label:listbox", "Feedrate"),
  125. type_id: 2
  126. })
  127. layerViewTypes.append({
  128. text: catalog.i18nc("@label:listbox", "Layer thickness"),
  129. type_id: 3 // these ids match the switching in the shader
  130. })
  131. }
  132. ComboBox
  133. {
  134. id: layerTypeCombobox
  135. anchors.left: parent.left
  136. Layout.fillWidth: true
  137. Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
  138. model: layerViewTypes
  139. visible: !UM.SimulationView.compatibilityMode
  140. style: UM.Theme.styles.combobox
  141. anchors.right: parent.right
  142. onActivated:
  143. {
  144. UM.Preferences.setValue("layerview/layer_view_type", index);
  145. }
  146. Component.onCompleted:
  147. {
  148. currentIndex = UM.SimulationView.compatibilityMode ? 1 : UM.Preferences.getValue("layerview/layer_view_type");
  149. updateLegends(currentIndex);
  150. }
  151. function updateLegends(type_id)
  152. {
  153. // update visibility of legends
  154. viewSettings.show_legend = UM.SimulationView.compatibilityMode || (type_id == 1);
  155. viewSettings.show_gradient = !UM.SimulationView.compatibilityMode && (type_id == 2 || type_id == 3);
  156. viewSettings.show_feedrate_gradient = viewSettings.show_gradient && (type_id == 2);
  157. viewSettings.show_thickness_gradient = viewSettings.show_gradient && (type_id == 3);
  158. }
  159. }
  160. Label
  161. {
  162. id: compatibilityModeLabel
  163. anchors.left: parent.left
  164. text: catalog.i18nc("@label","Compatibility Mode")
  165. font: UM.Theme.getFont("default")
  166. color: UM.Theme.getColor("text")
  167. visible: UM.SimulationView.compatibilityMode
  168. Layout.fillWidth: true
  169. Layout.preferredHeight: UM.Theme.getSize("layerview_row").height
  170. Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
  171. }
  172. Item
  173. {
  174. height: Math.round(UM.Theme.getSize("default_margin").width / 2)
  175. width: width
  176. }
  177. Connections {
  178. target: UM.Preferences
  179. onPreferenceChanged:
  180. {
  181. layerTypeCombobox.currentIndex = UM.SimulationView.compatibilityMode ? 1 : UM.Preferences.getValue("layerview/layer_view_type");
  182. layerTypeCombobox.updateLegends(layerTypeCombobox.currentIndex);
  183. playButton.pauseSimulation();
  184. viewSettings.extruder_opacities = UM.Preferences.getValue("layerview/extruder_opacities").split("|");
  185. viewSettings.show_travel_moves = UM.Preferences.getValue("layerview/show_travel_moves");
  186. viewSettings.show_helpers = UM.Preferences.getValue("layerview/show_helpers");
  187. viewSettings.show_skin = UM.Preferences.getValue("layerview/show_skin");
  188. viewSettings.show_infill = UM.Preferences.getValue("layerview/show_infill");
  189. viewSettings.only_show_top_layers = UM.Preferences.getValue("view/only_show_top_layers");
  190. viewSettings.top_layer_count = UM.Preferences.getValue("view/top_layer_count");
  191. }
  192. }
  193. Repeater {
  194. model: Cura.ExtrudersModel{}
  195. CheckBox {
  196. id: extrudersModelCheckBox
  197. checked: viewSettings.extruder_opacities[index] > 0.5 || viewSettings.extruder_opacities[index] == undefined || viewSettings.extruder_opacities[index] == ""
  198. onClicked: {
  199. viewSettings.extruder_opacities[index] = checked ? 1.0 : 0.0
  200. UM.Preferences.setValue("layerview/extruder_opacities", viewSettings.extruder_opacities.join("|"));
  201. }
  202. visible: !UM.SimulationView.compatibilityMode
  203. enabled: index + 1 <= 4
  204. Rectangle {
  205. anchors.verticalCenter: parent.verticalCenter
  206. anchors.right: extrudersModelCheckBox.right
  207. width: UM.Theme.getSize("layerview_legend_size").width
  208. height: UM.Theme.getSize("layerview_legend_size").height
  209. color: model.color
  210. radius: Math.round(width / 2)
  211. border.width: UM.Theme.getSize("default_lining").width
  212. border.color: UM.Theme.getColor("lining")
  213. visible: !viewSettings.show_legend & !viewSettings.show_gradient
  214. }
  215. Layout.fillWidth: true
  216. Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height
  217. Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
  218. style: UM.Theme.styles.checkbox
  219. Label
  220. {
  221. text: model.name
  222. elide: Text.ElideRight
  223. color: UM.Theme.getColor("setting_control_text")
  224. font: UM.Theme.getFont("default")
  225. anchors.verticalCenter: parent.verticalCenter
  226. anchors.left: extrudersModelCheckBox.left;
  227. anchors.right: extrudersModelCheckBox.right;
  228. anchors.leftMargin: UM.Theme.getSize("checkbox").width + Math.round(UM.Theme.getSize("default_margin").width/2)
  229. anchors.rightMargin: UM.Theme.getSize("default_margin").width * 2
  230. }
  231. }
  232. }
  233. Repeater {
  234. model: ListModel {
  235. id: typesLegendModel
  236. Component.onCompleted:
  237. {
  238. typesLegendModel.append({
  239. label: catalog.i18nc("@label", "Show Travels"),
  240. initialValue: viewSettings.show_travel_moves,
  241. preference: "layerview/show_travel_moves",
  242. colorId: "layerview_move_combing"
  243. });
  244. typesLegendModel.append({
  245. label: catalog.i18nc("@label", "Show Helpers"),
  246. initialValue: viewSettings.show_helpers,
  247. preference: "layerview/show_helpers",
  248. colorId: "layerview_support"
  249. });
  250. typesLegendModel.append({
  251. label: catalog.i18nc("@label", "Show Shell"),
  252. initialValue: viewSettings.show_skin,
  253. preference: "layerview/show_skin",
  254. colorId: "layerview_inset_0"
  255. });
  256. typesLegendModel.append({
  257. label: catalog.i18nc("@label", "Show Infill"),
  258. initialValue: viewSettings.show_infill,
  259. preference: "layerview/show_infill",
  260. colorId: "layerview_infill"
  261. });
  262. }
  263. }
  264. CheckBox {
  265. id: legendModelCheckBox
  266. checked: model.initialValue
  267. onClicked: {
  268. UM.Preferences.setValue(model.preference, checked);
  269. }
  270. Rectangle {
  271. anchors.verticalCenter: parent.verticalCenter
  272. anchors.right: legendModelCheckBox.right
  273. width: UM.Theme.getSize("layerview_legend_size").width
  274. height: UM.Theme.getSize("layerview_legend_size").height
  275. color: UM.Theme.getColor(model.colorId)
  276. border.width: UM.Theme.getSize("default_lining").width
  277. border.color: UM.Theme.getColor("lining")
  278. visible: viewSettings.show_legend
  279. }
  280. Layout.fillWidth: true
  281. Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height
  282. Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
  283. style: UM.Theme.styles.checkbox
  284. Label
  285. {
  286. text: label
  287. font: UM.Theme.getFont("default")
  288. elide: Text.ElideRight
  289. color: UM.Theme.getColor("setting_control_text")
  290. anchors.verticalCenter: parent.verticalCenter
  291. anchors.left: legendModelCheckBox.left;
  292. anchors.right: legendModelCheckBox.right;
  293. anchors.leftMargin: UM.Theme.getSize("checkbox").width + Math.round(UM.Theme.getSize("default_margin").width/2)
  294. anchors.rightMargin: UM.Theme.getSize("default_margin").width * 2
  295. }
  296. }
  297. }
  298. CheckBox {
  299. checked: viewSettings.only_show_top_layers
  300. onClicked: {
  301. UM.Preferences.setValue("view/only_show_top_layers", checked ? 1.0 : 0.0);
  302. }
  303. text: catalog.i18nc("@label", "Only Show Top Layers")
  304. visible: UM.SimulationView.compatibilityMode
  305. style: UM.Theme.styles.checkbox
  306. }
  307. CheckBox {
  308. checked: viewSettings.top_layer_count == 5
  309. onClicked: {
  310. UM.Preferences.setValue("view/top_layer_count", checked ? 5 : 1);
  311. }
  312. text: catalog.i18nc("@label", "Show 5 Detailed Layers On Top")
  313. visible: UM.SimulationView.compatibilityMode
  314. style: UM.Theme.styles.checkbox
  315. }
  316. Repeater {
  317. model: ListModel {
  318. id: typesLegendModelNoCheck
  319. Component.onCompleted:
  320. {
  321. typesLegendModelNoCheck.append({
  322. label: catalog.i18nc("@label", "Top / Bottom"),
  323. colorId: "layerview_skin",
  324. });
  325. typesLegendModelNoCheck.append({
  326. label: catalog.i18nc("@label", "Inner Wall"),
  327. colorId: "layerview_inset_x",
  328. });
  329. }
  330. }
  331. Label {
  332. text: label
  333. visible: viewSettings.show_legend
  334. id: typesLegendModelLabel
  335. Rectangle {
  336. anchors.verticalCenter: parent.verticalCenter
  337. anchors.right: typesLegendModelLabel.right
  338. width: UM.Theme.getSize("layerview_legend_size").width
  339. height: UM.Theme.getSize("layerview_legend_size").height
  340. color: UM.Theme.getColor(model.colorId)
  341. border.width: UM.Theme.getSize("default_lining").width
  342. border.color: UM.Theme.getColor("lining")
  343. visible: viewSettings.show_legend
  344. }
  345. Layout.fillWidth: true
  346. Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height
  347. Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
  348. color: UM.Theme.getColor("setting_control_text")
  349. font: UM.Theme.getFont("default")
  350. }
  351. }
  352. // Text for the minimum, maximum and units for the feedrates and layer thickness
  353. Item {
  354. id: gradientLegend
  355. visible: viewSettings.show_gradient
  356. width: parent.width
  357. height: UM.Theme.getSize("layerview_row").height
  358. anchors {
  359. topMargin: UM.Theme.getSize("slider_layerview_margin").height
  360. horizontalCenter: parent.horizontalCenter
  361. }
  362. Label {
  363. text: minText()
  364. anchors.left: parent.left
  365. color: UM.Theme.getColor("setting_control_text")
  366. font: UM.Theme.getFont("default")
  367. function minText() {
  368. if (UM.SimulationView.layerActivity && CuraApplication.platformActivity) {
  369. // Feedrate selected
  370. if (UM.Preferences.getValue("layerview/layer_view_type") == 2) {
  371. return parseFloat(UM.SimulationView.getMinFeedrate()).toFixed(2)
  372. }
  373. // Layer thickness selected
  374. if (UM.Preferences.getValue("layerview/layer_view_type") == 3) {
  375. return parseFloat(UM.SimulationView.getMinThickness()).toFixed(2)
  376. }
  377. }
  378. return catalog.i18nc("@label","min")
  379. }
  380. }
  381. Label {
  382. text: unitsText()
  383. anchors.horizontalCenter: parent.horizontalCenter
  384. color: UM.Theme.getColor("setting_control_text")
  385. font: UM.Theme.getFont("default")
  386. function unitsText() {
  387. if (UM.SimulationView.layerActivity && CuraApplication.platformActivity) {
  388. // Feedrate selected
  389. if (UM.Preferences.getValue("layerview/layer_view_type") == 2) {
  390. return "mm/s"
  391. }
  392. // Layer thickness selected
  393. if (UM.Preferences.getValue("layerview/layer_view_type") == 3) {
  394. return "mm"
  395. }
  396. }
  397. return ""
  398. }
  399. }
  400. Label {
  401. text: maxText()
  402. anchors.right: parent.right
  403. color: UM.Theme.getColor("setting_control_text")
  404. font: UM.Theme.getFont("default")
  405. function maxText() {
  406. if (UM.SimulationView.layerActivity && CuraApplication.platformActivity) {
  407. // Feedrate selected
  408. if (UM.Preferences.getValue("layerview/layer_view_type") == 2) {
  409. return parseFloat(UM.SimulationView.getMaxFeedrate()).toFixed(2)
  410. }
  411. // Layer thickness selected
  412. if (UM.Preferences.getValue("layerview/layer_view_type") == 3) {
  413. return parseFloat(UM.SimulationView.getMaxThickness()).toFixed(2)
  414. }
  415. }
  416. return catalog.i18nc("@label","max")
  417. }
  418. }
  419. }
  420. // Gradient colors for feedrate
  421. Rectangle { // In QML 5.9 can be changed by LinearGradient
  422. // Invert values because then the bar is rotated 90 degrees
  423. id: feedrateGradient
  424. visible: viewSettings.show_feedrate_gradient
  425. anchors.left: parent.right
  426. height: parent.width
  427. width: Math.round(UM.Theme.getSize("layerview_row").height * 1.5)
  428. border.width: UM.Theme.getSize("default_lining").width
  429. border.color: UM.Theme.getColor("lining")
  430. transform: Rotation {origin.x: 0; origin.y: 0; angle: 90}
  431. gradient: Gradient {
  432. GradientStop {
  433. position: 0.000
  434. color: Qt.rgba(1, 0.5, 0, 1)
  435. }
  436. GradientStop {
  437. position: 0.625
  438. color: Qt.rgba(0.375, 0.5, 0, 1)
  439. }
  440. GradientStop {
  441. position: 0.75
  442. color: Qt.rgba(0.25, 1, 0, 1)
  443. }
  444. GradientStop {
  445. position: 1.0
  446. color: Qt.rgba(0, 0, 1, 1)
  447. }
  448. }
  449. }
  450. // Gradient colors for layer thickness (similar to parula colormap)
  451. Rectangle { // In QML 5.9 can be changed by LinearGradient
  452. // Invert values because then the bar is rotated 90 degrees
  453. id: thicknessGradient
  454. visible: viewSettings.show_thickness_gradient
  455. anchors.left: parent.right
  456. height: parent.width
  457. width: Math.round(UM.Theme.getSize("layerview_row").height * 1.5)
  458. border.width: UM.Theme.getSize("default_lining").width
  459. border.color: UM.Theme.getColor("lining")
  460. transform: Rotation {origin.x: 0; origin.y: 0; angle: 90}
  461. gradient: Gradient {
  462. GradientStop {
  463. position: 0.000
  464. color: Qt.rgba(1, 1, 0, 1)
  465. }
  466. GradientStop {
  467. position: 0.25
  468. color: Qt.rgba(1, 0.75, 0.25, 1)
  469. }
  470. GradientStop {
  471. position: 0.5
  472. color: Qt.rgba(0, 0.75, 0.5, 1)
  473. }
  474. GradientStop {
  475. position: 0.75
  476. color: Qt.rgba(0, 0.375, 0.75, 1)
  477. }
  478. GradientStop {
  479. position: 1.0
  480. color: Qt.rgba(0, 0, 0.5, 1)
  481. }
  482. }
  483. }
  484. }
  485. }
  486. Item {
  487. id: slidersBox
  488. width: parent.width
  489. visible: UM.SimulationView.layerActivity && CuraApplication.platformActivity
  490. anchors {
  491. top: parent.bottom
  492. topMargin: UM.Theme.getSize("slider_layerview_margin").height
  493. left: parent.left
  494. }
  495. PathSlider {
  496. id: pathSlider
  497. height: UM.Theme.getSize("slider_handle").width
  498. anchors.left: playButton.right
  499. anchors.leftMargin: UM.Theme.getSize("default_margin").width
  500. anchors.right: parent.right
  501. visible: !UM.SimulationView.compatibilityMode
  502. // custom properties
  503. handleValue: UM.SimulationView.currentPath
  504. maximumValue: UM.SimulationView.numPaths
  505. handleSize: UM.Theme.getSize("slider_handle").width
  506. trackThickness: UM.Theme.getSize("slider_groove").width
  507. trackColor: UM.Theme.getColor("slider_groove")
  508. trackBorderColor: UM.Theme.getColor("slider_groove_border")
  509. handleColor: UM.Theme.getColor("slider_handle")
  510. handleActiveColor: UM.Theme.getColor("slider_handle_active")
  511. rangeColor: UM.Theme.getColor("slider_groove_fill")
  512. // update values when layer data changes
  513. Connections {
  514. target: UM.SimulationView
  515. onMaxPathsChanged: pathSlider.setHandleValue(UM.SimulationView.currentPath)
  516. onCurrentPathChanged: pathSlider.setHandleValue(UM.SimulationView.currentPath)
  517. }
  518. // make sure the slider handlers show the correct value after switching views
  519. Component.onCompleted: {
  520. pathSlider.setHandleValue(UM.SimulationView.currentPath)
  521. }
  522. }
  523. LayerSlider {
  524. id: layerSlider
  525. width: UM.Theme.getSize("slider_handle").width
  526. height: UM.Theme.getSize("layerview_menu_size").height
  527. anchors {
  528. top: !UM.SimulationView.compatibilityMode ? pathSlider.bottom : parent.top
  529. topMargin: !UM.SimulationView.compatibilityMode ? UM.Theme.getSize("default_margin").height : 0
  530. right: parent.right
  531. rightMargin: UM.Theme.getSize("slider_layerview_margin").width
  532. }
  533. // custom properties
  534. upperValue: UM.SimulationView.currentLayer
  535. lowerValue: UM.SimulationView.minimumLayer
  536. maximumValue: UM.SimulationView.numLayers
  537. handleSize: UM.Theme.getSize("slider_handle").width
  538. trackThickness: UM.Theme.getSize("slider_groove").width
  539. trackColor: UM.Theme.getColor("slider_groove")
  540. trackBorderColor: UM.Theme.getColor("slider_groove_border")
  541. upperHandleColor: UM.Theme.getColor("slider_handle")
  542. lowerHandleColor: UM.Theme.getColor("slider_handle")
  543. rangeHandleColor: UM.Theme.getColor("slider_groove_fill")
  544. handleActiveColor: UM.Theme.getColor("slider_handle_active")
  545. handleLabelWidth: UM.Theme.getSize("slider_layerview_background").width
  546. // update values when layer data changes
  547. Connections {
  548. target: UM.SimulationView
  549. onMaxLayersChanged: layerSlider.setUpperValue(UM.SimulationView.currentLayer)
  550. onMinimumLayerChanged: layerSlider.setLowerValue(UM.SimulationView.minimumLayer)
  551. onCurrentLayerChanged: layerSlider.setUpperValue(UM.SimulationView.currentLayer)
  552. }
  553. // make sure the slider handlers show the correct value after switching views
  554. Component.onCompleted: {
  555. layerSlider.setLowerValue(UM.SimulationView.minimumLayer)
  556. layerSlider.setUpperValue(UM.SimulationView.currentLayer)
  557. }
  558. }
  559. // Play simulation button
  560. Button {
  561. id: playButton
  562. iconSource: "./resources/simulation_resume.svg"
  563. style: UM.Theme.styles.small_tool_button
  564. visible: !UM.SimulationView.compatibilityMode
  565. anchors {
  566. verticalCenter: pathSlider.verticalCenter
  567. }
  568. property var status: 0 // indicates if it's stopped (0) or playing (1)
  569. onClicked: {
  570. switch(status) {
  571. case 0: {
  572. resumeSimulation()
  573. break
  574. }
  575. case 1: {
  576. pauseSimulation()
  577. break
  578. }
  579. }
  580. }
  581. function pauseSimulation() {
  582. UM.SimulationView.setSimulationRunning(false)
  583. iconSource = "./resources/simulation_resume.svg"
  584. simulationTimer.stop()
  585. status = 0
  586. }
  587. function resumeSimulation() {
  588. UM.SimulationView.setSimulationRunning(true)
  589. iconSource = "./resources/simulation_pause.svg"
  590. simulationTimer.start()
  591. }
  592. }
  593. Timer
  594. {
  595. id: simulationTimer
  596. interval: 100
  597. running: false
  598. repeat: true
  599. onTriggered: {
  600. var currentPath = UM.SimulationView.currentPath
  601. var numPaths = UM.SimulationView.numPaths
  602. var currentLayer = UM.SimulationView.currentLayer
  603. var numLayers = UM.SimulationView.numLayers
  604. // When the user plays the simulation, if the path slider is at the end of this layer, we start
  605. // the simulation at the beginning of the current layer.
  606. if (playButton.status == 0)
  607. {
  608. if (currentPath >= numPaths)
  609. {
  610. UM.SimulationView.setCurrentPath(0)
  611. }
  612. else
  613. {
  614. UM.SimulationView.setCurrentPath(currentPath+1)
  615. }
  616. }
  617. // If the simulation is already playing and we reach the end of a layer, then it automatically
  618. // starts at the beginning of the next layer.
  619. else
  620. {
  621. if (currentPath >= numPaths)
  622. {
  623. // At the end of the model, the simulation stops
  624. if (currentLayer >= numLayers)
  625. {
  626. playButton.pauseSimulation()
  627. }
  628. else
  629. {
  630. UM.SimulationView.setCurrentLayer(currentLayer+1)
  631. UM.SimulationView.setCurrentPath(0)
  632. }
  633. }
  634. else
  635. {
  636. UM.SimulationView.setCurrentPath(currentPath+1)
  637. }
  638. }
  639. playButton.status = 1
  640. }
  641. }
  642. }
  643. FontMetrics {
  644. id: fontMetrics
  645. font: UM.Theme.getFont("default")
  646. }
  647. }