SimulationView.qml 33 KB

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