DynamicRigidBodySection.qml 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. // Copyright (C) 2021 The Qt Company Ltd.
  2. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
  3. import QtQuick 2.15
  4. import QtQuick.Layouts 1.15
  5. import HelperWidgets 2.0
  6. import StudioTheme 1.0 as StudioTheme
  7. Column {
  8. width: parent.width
  9. Section {
  10. width: parent.width
  11. caption: qsTr("Dynamic Rigid Body")
  12. SectionLayout {
  13. id: baseSectionLayout
  14. property bool isDefaultDensityMode: massModeComboBox.currentIndex === 0
  15. property bool isCustomDensityMode: massModeComboBox.currentIndex === 1
  16. property bool isMassMode: massModeComboBox.currentIndex === 2
  17. property bool isMassAndInertiaTensorMode: massModeComboBox.currentIndex === 3
  18. property bool isMassAndInertiaMatrixMode: massModeComboBox.currentIndex === 4
  19. PropertyLabel {
  20. text: "Mass Mode"
  21. tooltip: "Describes how mass and inertia are calculated for this body."
  22. }
  23. SecondColumnLayout {
  24. ComboBox {
  25. id: massModeComboBox
  26. scope: "DynamicRigidBody"
  27. model: ["DefaultDensity", "CustomDensity", "Mass", "MassAndInertiaTensor", "MassAndInertiaMatrix"]
  28. backendValue: backendValues.massMode
  29. implicitWidth: StudioTheme.Values.singleControlColumnWidth
  30. + StudioTheme.Values.actionIndicatorWidth
  31. }
  32. ExpandingSpacer {}
  33. }
  34. PropertyLabel {
  35. visible: baseSectionLayout.isMassAndInertiaMatrixMode || baseSectionLayout.isMassAndInertiaTensorMode
  36. }
  37. SecondColumnLayout {
  38. visible: baseSectionLayout.isMassAndInertiaMatrixMode || baseSectionLayout.isMassAndInertiaTensorMode
  39. Item {
  40. // spacer for the always hiden action indicator
  41. width: StudioTheme.Values.actionIndicatorWidth
  42. }
  43. Label {
  44. text: qsTr("Tensor and Matrix modes require QML code.")
  45. Layout.fillWidth: true
  46. Layout.preferredWidth: StudioTheme.Values.singleControlColumnWidth
  47. Layout.minimumWidth: StudioTheme.Values.singleControlColumnWidth
  48. Layout.maximumWidth: StudioTheme.Values.singleControlColumnWidth
  49. }
  50. }
  51. PropertyLabel {
  52. visible: !baseSectionLayout.isDefaultDensityMode && !baseSectionLayout.isCustomDensityMode
  53. text: "Mass"
  54. tooltip: "The mass of the body."
  55. }
  56. SecondColumnLayout {
  57. visible: !baseSectionLayout.isDefaultDensityMode && !baseSectionLayout.isCustomDensityMode
  58. SpinBox {
  59. minimumValue: 0
  60. maximumValue: 9999999
  61. decimals: 2
  62. stepSize: 0.01
  63. backendValue: backendValues.mass
  64. implicitWidth: StudioTheme.Values.singleControlColumnWidth
  65. + StudioTheme.Values.actionIndicatorWidth
  66. }
  67. ExpandingSpacer {}
  68. }
  69. PropertyLabel {
  70. visible: baseSectionLayout.isCustomDensityMode
  71. text: "Density"
  72. tooltip: "The density of the body."
  73. }
  74. SecondColumnLayout {
  75. visible: baseSectionLayout.isCustomDensityMode
  76. SpinBox {
  77. minimumValue: -1
  78. maximumValue: 9999999
  79. decimals: 2
  80. stepSize: 0.01
  81. backendValue: backendValues.density
  82. implicitWidth: StudioTheme.Values.singleControlColumnWidth
  83. + StudioTheme.Values.actionIndicatorWidth
  84. }
  85. ExpandingSpacer {}
  86. }
  87. PropertyLabel {
  88. text: "Enable Gravity"
  89. tooltip: "Sets if the body affected by gravity."
  90. }
  91. SecondColumnLayout {
  92. CheckBox {
  93. text: backendValues.gravityEnabled.valueToString
  94. backendValue: backendValues.gravityEnabled
  95. implicitWidth: StudioTheme.Values.twoControlColumnWidth
  96. + StudioTheme.Values.actionIndicatorWidth
  97. }
  98. ExpandingSpacer {}
  99. }
  100. PropertyLabel {
  101. text: "Linear Axis Lock"
  102. tooltip: "Lock the linear axis of the body."
  103. }
  104. SecondColumnLayout {
  105. ActionIndicator {
  106. id: linearAxisLockController
  107. icon.color: extFuncLogic.color
  108. icon.text: extFuncLogic.glyph
  109. onClicked: extFuncLogic.show()
  110. forceVisible: extFuncLogic.menuVisible
  111. visible: true
  112. property var enableLockX: { "value": false, "isInModel": false}
  113. property var enableLockY: { "value": false, "isInModel": false}
  114. property var enableLockZ: { "value": false, "isInModel": false}
  115. property variant backendValue: backendValues.linearAxisLock
  116. property variant valueFromBackend: backendValue === undefined ? 0 : backendValue.value
  117. property bool blockLocks: false
  118. onBackendValueChanged: evaluateLocks()
  119. onValueFromBackendChanged: evaluateLocks()
  120. Connections {
  121. target: modelNodeBackend
  122. function onSelectionChanged() {
  123. evaluateLevels()
  124. }
  125. }
  126. Component.onCompleted: evaluateLocks()
  127. function evaluateLocks() {
  128. blockLocks = true
  129. enableLockX = { "value": valueFromBackend & 1, "isInModel": false}
  130. enableLockY = { "value": valueFromBackend & 2, "isInModel": false}
  131. enableLockZ = { "value": valueFromBackend & 4, "isInModel": false}
  132. blockLocks = false
  133. }
  134. function composeExpressionString() {
  135. if (blockLocks)
  136. return
  137. let expressionStr = "";
  138. if (enableLockX.value || enableLockY.value || enableLockY.value) {
  139. if (enableLockX.value)
  140. expressionStr += " | DynamicRigidBody.LockX";
  141. if (enableLockY.value)
  142. expressionStr += " | DynamicRigidBody.LockY";
  143. if (enableLockZ.value)
  144. expressionStr += " | DynamicRigidBody.LockZ";
  145. expressionStr = expressionStr.substring(3);
  146. backendValue.expression = expressionStr
  147. } else {
  148. expressionStr = "DynamicRigidBody.None";
  149. backendValue.expression = expressionStr
  150. }
  151. }
  152. ExtendedFunctionLogic {
  153. id: extFuncLogic
  154. backendValue: backendValues.linearAxisLock
  155. onReseted: {
  156. linearAxisLockController.enableLockX = { "value": false, "isInModel": false}
  157. linearAxisLockController.enableLockY = { "value": false, "isInModel": false}
  158. linearAxisLockController.enableLockZ = { "value": false, "isInModel": false}
  159. linearAxisLockController.evaluateLocks()
  160. }
  161. }
  162. }
  163. }
  164. PropertyLabel {
  165. // spacer
  166. }
  167. SecondColumnLayout {
  168. Item {
  169. // spacer for the always hiden action indicator
  170. width: StudioTheme.Values.actionIndicatorWidth
  171. }
  172. CheckBox {
  173. text: qsTr("Lock X")
  174. backendValue: linearAxisLockController.enableLockX
  175. actionIndicatorVisible: false
  176. onCheckedChanged: linearAxisLockController.composeExpressionString()
  177. implicitWidth: StudioTheme.Values.twoControlColumnWidth
  178. }
  179. ExpandingSpacer {}
  180. }
  181. PropertyLabel {
  182. // spacer
  183. }
  184. SecondColumnLayout {
  185. Item {
  186. // spacer for the always hiden action indicator
  187. width: StudioTheme.Values.actionIndicatorWidth
  188. }
  189. CheckBox {
  190. text: qsTr("Lock Y")
  191. backendValue: linearAxisLockController.enableLockY
  192. actionIndicatorVisible: false
  193. onCheckedChanged: linearAxisLockController.composeExpressionString()
  194. implicitWidth: StudioTheme.Values.twoControlColumnWidth
  195. }
  196. ExpandingSpacer {}
  197. }
  198. PropertyLabel {
  199. // spacer
  200. }
  201. SecondColumnLayout {
  202. Item {
  203. // spacer for the always hiden action indicator
  204. width: StudioTheme.Values.actionIndicatorWidth
  205. }
  206. CheckBox {
  207. text: qsTr("Lock Z")
  208. backendValue: linearAxisLockController.enableLockZ
  209. actionIndicatorVisible: false
  210. onCheckedChanged: linearAxisLockController.composeExpressionString()
  211. implicitWidth: StudioTheme.Values.twoControlColumnWidth
  212. }
  213. ExpandingSpacer {}
  214. }
  215. PropertyLabel {
  216. text: "Angular Axis Lock"
  217. tooltip: "Lock the angular axis of the body."
  218. }
  219. SecondColumnLayout {
  220. ActionIndicator {
  221. id: angularAxisLockController
  222. icon.color: extFuncLogicAngular.color
  223. icon.text: extFuncLogicAngular.glyph
  224. onClicked: extFuncLogicAngular.show()
  225. forceVisible: extFuncLogic.menuVisible
  226. visible: true
  227. property var enableLockX: { "value": false, "isInModel": false}
  228. property var enableLockY: { "value": false, "isInModel": false}
  229. property var enableLockZ: { "value": false, "isInModel": false}
  230. property variant backendValue: backendValues.angularAxisLock
  231. property variant valueFromBackend: backendValue === undefined ? 0 : backendValue.value
  232. property bool blockLocks: false
  233. onBackendValueChanged: evaluateLocks()
  234. onValueFromBackendChanged: evaluateLocks()
  235. Connections {
  236. target: modelNodeBackend
  237. function onSelectionChanged() {
  238. evaluateLevels()
  239. }
  240. }
  241. Component.onCompleted: evaluateLocks()
  242. function evaluateLocks() {
  243. blockLocks = true
  244. enableLockX = { "value": valueFromBackend & 1, "isInModel": false}
  245. enableLockY = { "value": valueFromBackend & 2, "isInModel": false}
  246. enableLockZ = { "value": valueFromBackend & 4, "isInModel": false}
  247. blockLocks = false
  248. }
  249. function composeExpressionString() {
  250. if (blockLocks)
  251. return
  252. let expressionStr = "";
  253. if (enableLockX.value || enableLockY.value || enableLockY.value) {
  254. if (enableLockX.value)
  255. expressionStr += " | DynamicRigidBody.LockX";
  256. if (enableLockY.value)
  257. expressionStr += " | DynamicRigidBody.LockY";
  258. if (enableLockZ.value)
  259. expressionStr += " | DynamicRigidBody.LockZ";
  260. expressionStr = expressionStr.substring(3);
  261. backendValue.expression = expressionStr
  262. } else {
  263. expressionStr = "DynamicRigidBody.None";
  264. backendValue.expression = expressionStr
  265. }
  266. }
  267. ExtendedFunctionLogic {
  268. id: extFuncLogicAngular
  269. backendValue: backendValues.angularAxisLock
  270. onReseted: {
  271. angularAxisLockController.enableLockX = { "value": false, "isInModel": false}
  272. angularAxisLockController.enableLockY = { "value": false, "isInModel": false}
  273. angularAxisLockController.enableLockZ = { "value": false, "isInModel": false}
  274. angularAxisLockController.evaluateLocks()
  275. }
  276. }
  277. }
  278. }
  279. PropertyLabel {
  280. // spacer
  281. }
  282. SecondColumnLayout {
  283. Item {
  284. // spacer for the always hiden action indicator
  285. width: StudioTheme.Values.actionIndicatorWidth
  286. }
  287. CheckBox {
  288. text: qsTr("Lock X")
  289. backendValue: angularAxisLockController.enableLockX
  290. actionIndicatorVisible: false
  291. onCheckedChanged: angularAxisLockController.composeExpressionString()
  292. implicitWidth: StudioTheme.Values.twoControlColumnWidth
  293. }
  294. ExpandingSpacer {}
  295. }
  296. PropertyLabel {
  297. // spacer
  298. }
  299. SecondColumnLayout {
  300. Item {
  301. // spacer for the always hiden action indicator
  302. width: StudioTheme.Values.actionIndicatorWidth
  303. }
  304. CheckBox {
  305. text: qsTr("Lock Y")
  306. backendValue: angularAxisLockController.enableLockY
  307. actionIndicatorVisible: false
  308. onCheckedChanged: angularAxisLockController.composeExpressionString()
  309. implicitWidth: StudioTheme.Values.twoControlColumnWidth
  310. }
  311. ExpandingSpacer {}
  312. }
  313. PropertyLabel {
  314. // spacer
  315. }
  316. SecondColumnLayout {
  317. Item {
  318. // spacer for the always hiden action indicator
  319. width: StudioTheme.Values.actionIndicatorWidth
  320. }
  321. CheckBox {
  322. text: qsTr("Lock Z")
  323. backendValue: angularAxisLockController.enableLockZ
  324. actionIndicatorVisible: false
  325. onCheckedChanged: angularAxisLockController.composeExpressionString()
  326. implicitWidth: StudioTheme.Values.twoControlColumnWidth
  327. }
  328. ExpandingSpacer {}
  329. }
  330. PropertyLabel {
  331. text: "Is Kinematic"
  332. tooltip: "Kinematic objects are not influenced by external forces and can be seen as an object of infinite mass."
  333. }
  334. SecondColumnLayout {
  335. CheckBox {
  336. id: isKinematicCheckBox
  337. text: backendValues.isKinematic.valueToString
  338. backendValue: backendValues.isKinematic
  339. implicitWidth: StudioTheme.Values.twoControlColumnWidth
  340. + StudioTheme.Values.actionIndicatorWidth
  341. }
  342. ExpandingSpacer {}
  343. }
  344. PropertyLabel {
  345. visible: isKinematicCheckBox.checked
  346. text: "Kinematic Position"
  347. tooltip: "The position of the kinematic object."
  348. }
  349. SecondColumnLayout {
  350. visible: isKinematicCheckBox.checked
  351. SpinBox {
  352. implicitWidth: StudioTheme.Values.singleControlColumnWidth
  353. + StudioTheme.Values.actionIndicatorWidth
  354. minimumValue: -9999999
  355. maximumValue: 9999999
  356. decimals: 2
  357. backendValue: backendValues.kinematicPosition_x
  358. }
  359. Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
  360. ControlLabel {
  361. text: "X"
  362. color: StudioTheme.Values.theme3DAxisXColor
  363. }
  364. ExpandingSpacer {}
  365. }
  366. PropertyLabel {
  367. visible: isKinematicCheckBox.checked
  368. }
  369. SecondColumnLayout {
  370. visible: isKinematicCheckBox.checked
  371. SpinBox {
  372. implicitWidth: StudioTheme.Values.singleControlColumnWidth
  373. + StudioTheme.Values.actionIndicatorWidth
  374. minimumValue: -9999999
  375. maximumValue: 9999999
  376. decimals: 2
  377. backendValue: backendValues.kinematicPosition_y
  378. }
  379. Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
  380. ControlLabel {
  381. text: "Y"
  382. color: StudioTheme.Values.theme3DAxisYColor
  383. }
  384. ExpandingSpacer {}
  385. }
  386. PropertyLabel {
  387. visible: isKinematicCheckBox.checked
  388. }
  389. SecondColumnLayout {
  390. visible: isKinematicCheckBox.checked
  391. SpinBox {
  392. implicitWidth: StudioTheme.Values.singleControlColumnWidth
  393. + StudioTheme.Values.actionIndicatorWidth
  394. minimumValue: -9999999
  395. maximumValue: 9999999
  396. decimals: 2
  397. backendValue: backendValues.kinematicPosition_z
  398. }
  399. Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
  400. ControlLabel {
  401. text: "Z"
  402. color: StudioTheme.Values.theme3DAxisZColor
  403. }
  404. ExpandingSpacer {}
  405. }
  406. PropertyLabel {
  407. visible: isKinematicCheckBox.checked
  408. text: "Kinematic Rotation"
  409. tooltip: "The rotation of the kinematic object."
  410. }
  411. SecondColumnLayout {
  412. visible: isKinematicCheckBox.checked
  413. SpinBox {
  414. implicitWidth: StudioTheme.Values.singleControlColumnWidth
  415. + StudioTheme.Values.actionIndicatorWidth
  416. minimumValue: -9999999
  417. maximumValue: 9999999
  418. decimals: 2
  419. backendValue: backendValues.kinematicEulerRotation_x
  420. }
  421. Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
  422. ControlLabel {
  423. text: "X"
  424. color: StudioTheme.Values.theme3DAxisXColor
  425. }
  426. ExpandingSpacer {}
  427. }
  428. PropertyLabel {
  429. visible: isKinematicCheckBox.checked
  430. }
  431. SecondColumnLayout {
  432. visible: isKinematicCheckBox.checked
  433. SpinBox {
  434. implicitWidth: StudioTheme.Values.singleControlColumnWidth
  435. + StudioTheme.Values.actionIndicatorWidth
  436. minimumValue: -9999999
  437. maximumValue: 9999999
  438. decimals: 2
  439. backendValue: backendValues.kinematicEulerRotation_y
  440. }
  441. Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
  442. ControlLabel {
  443. text: "Y"
  444. color: StudioTheme.Values.theme3DAxisYColor
  445. }
  446. ExpandingSpacer {}
  447. }
  448. PropertyLabel {
  449. visible: isKinematicCheckBox.checked
  450. }
  451. SecondColumnLayout {
  452. visible: isKinematicCheckBox.checked
  453. SpinBox {
  454. implicitWidth: StudioTheme.Values.singleControlColumnWidth
  455. + StudioTheme.Values.actionIndicatorWidth
  456. minimumValue: -9999999
  457. maximumValue: 9999999
  458. decimals: 2
  459. backendValue: backendValues.kinematicEulerRotation_z
  460. }
  461. Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
  462. ControlLabel {
  463. text: "Z"
  464. color: StudioTheme.Values.theme3DAxisZColor
  465. }
  466. ExpandingSpacer {}
  467. }
  468. PropertyLabel {
  469. visible: isKinematicCheckBox.checked
  470. text: "Kinematic Pivot"
  471. tooltip: "The pivot point of the kinematic object."
  472. }
  473. SecondColumnLayout {
  474. visible: isKinematicCheckBox.checked
  475. SpinBox {
  476. implicitWidth: StudioTheme.Values.singleControlColumnWidth
  477. + StudioTheme.Values.actionIndicatorWidth
  478. minimumValue: -9999999
  479. maximumValue: 9999999
  480. decimals: 2
  481. backendValue: backendValues.kinematicPivot_x
  482. }
  483. Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
  484. ControlLabel {
  485. text: "X"
  486. color: StudioTheme.Values.theme3DAxisXColor
  487. }
  488. ExpandingSpacer {}
  489. }
  490. PropertyLabel {
  491. visible: isKinematicCheckBox.checked
  492. }
  493. SecondColumnLayout {
  494. visible: isKinematicCheckBox.checked
  495. SpinBox {
  496. implicitWidth: StudioTheme.Values.singleControlColumnWidth
  497. + StudioTheme.Values.actionIndicatorWidth
  498. minimumValue: -9999999
  499. maximumValue: 9999999
  500. decimals: 2
  501. backendValue: backendValues.kinematicPivot_y
  502. }
  503. Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
  504. ControlLabel {
  505. text: "Y"
  506. color: StudioTheme.Values.theme3DAxisYColor
  507. }
  508. ExpandingSpacer {}
  509. }
  510. PropertyLabel {
  511. visible: isKinematicCheckBox.checked
  512. }
  513. SecondColumnLayout {
  514. visible: isKinematicCheckBox.checked
  515. SpinBox {
  516. implicitWidth: StudioTheme.Values.singleControlColumnWidth
  517. + StudioTheme.Values.actionIndicatorWidth
  518. minimumValue: -9999999
  519. maximumValue: 9999999
  520. decimals: 2
  521. backendValue: backendValues.kinematicPivot_z
  522. }
  523. Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
  524. ControlLabel {
  525. text: "Z"
  526. color: StudioTheme.Values.theme3DAxisZColor
  527. }
  528. ExpandingSpacer {}
  529. }
  530. }
  531. }
  532. }
  533. // Other Properties Not covered by the UI
  534. // QVector3D inertiaTensor
  535. // QVector3D centerOfMassPosition
  536. // QQuaternion centerOfMassRotation
  537. // List<float> inertiaMatrix (9 floats for a Mat3x3)