Compare commits
704 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 903cecc107 | |||
| a8c5bd573f | |||
| 1d2fe047bf | |||
| 3465f86605 | |||
| 540e727b73 | |||
| 8c576f820c | |||
| df3b673064 | |||
| 69bde5539c | |||
| aa12b7b11b | |||
| e0b3b3cca2 | |||
| ea9a5741d7 | |||
| 1fe1c8d5a8 | |||
| ac58560a69 | |||
| d0b234bf3d | |||
| 981fe05c15 | |||
| 918550465b | |||
| 963d4f1738 | |||
| d809732280 | |||
| c4e38a11b7 | |||
| 7abe215bc2 | |||
| 0f269430bc | |||
| b8a298c54b | |||
| e1d33cd250 | |||
| 4563dec9bc | |||
| de284083fd | |||
| 85ee66ca4d | |||
| 5365dc858e | |||
| 69f9544638 | |||
| bf5409cf90 | |||
| bd4f668526 | |||
| d21df0c6fd | |||
| d808fdaa09 | |||
| b32d23b9d6 | |||
| d1b8ba95df | |||
| 5e6825bbdb | |||
| 3e5ba136be | |||
| 294b49a11c | |||
| 9e0cca447f | |||
| bc3f23d8dd | |||
| 4fcf11eaa8 | |||
| 1f45902837 | |||
| bc55543e23 | |||
| c1b8ec7036 | |||
| abe9de1b4a | |||
| 09cc83eb14 | |||
| 8f7b3fce0c | |||
| f121f1adfe | |||
| 522ace443a | |||
| 8f97f59a9a | |||
| 8e9d98cd55 | |||
| 746230caa0 | |||
| 03e80c6361 | |||
| bc547c13db | |||
| 173df6128e | |||
| 666d882ec6 | |||
| 6ea13c4edc | |||
| 39bdff1c02 | |||
| 45fc851722 | |||
| ede81f3a7d | |||
| bae9f30445 | |||
| 527cefa3ef | |||
| 830aee116e | |||
| 243fbea769 | |||
| 9c885258d9 | |||
| 0ad4e15f0a | |||
| a2ba6823a3 | |||
| 3713abd860 | |||
| 5ae78fb192 | |||
| 0b694833fb | |||
| dfd82e6d40 | |||
| 1694786177 | |||
| ec72cc1454 | |||
| 37ba4d9a80 | |||
| 526e497037 | |||
| a81a723ba8 | |||
| 5976898f07 | |||
| 09fec26841 | |||
| 165eb238b5 | |||
| de305a3508 | |||
| d124478a92 | |||
| d9acc5b39d | |||
| 5b91a04e1e | |||
| d145ce52f7 | |||
| ec598bf4a8 | |||
| 568e679e3f | |||
| 85cc49f4d9 | |||
| 65b07d44ab | |||
| f87bc98169 | |||
| 04270a8abc | |||
| 65fa47c9ac | |||
| 9367ea7e17 | |||
| b7ac9d1fee | |||
| f20b26045c | |||
| 4bcbc5131b | |||
| eeea2d7c8d | |||
| 68e9468294 | |||
| 694da73b77 | |||
| 15657bf0ec | |||
| 78c6898ff0 | |||
| 836e97a57c | |||
| 7f708108f2 | |||
| 2d3e282150 | |||
| 75b933ef0a | |||
| c19799f081 | |||
| 848ed922b5 | |||
| 16e96b69a4 | |||
| fbdd7ee7b6 | |||
| d3df5fceec | |||
| 948925d156 | |||
| 7ab6b1b167 | |||
| ca3a109bc8 | |||
| ebe9551e72 | |||
| d2836189c3 | |||
| 3703963ec8 | |||
| 02ca8e3a59 | |||
| 7c73658fa5 | |||
| e03b448618 | |||
| c8d635752b | |||
| df9a5600d9 | |||
| dd730ea517 | |||
| 5bbfe1be59 | |||
| dd04bd8792 | |||
| 20bc1f41f0 | |||
| 9e838734c0 | |||
| 17aeca5e70 | |||
| 98852d8c22 | |||
| 674d9cd37d | |||
| c35f9c22ae | |||
| e5f861c0dc | |||
| 7a31143ef4 | |||
| 9daa0e4059 | |||
| eaedeb4f8b | |||
| bd2f1d2777 | |||
| 52e43bac2d | |||
| daef503970 | |||
| 4d0ba3cd13 | |||
| bd111a2106 | |||
| 22daade5d2 | |||
| a39d72a59d | |||
| 3a2e523589 | |||
| 8bd27c6ad1 | |||
| 4c20cf67c8 | |||
| 337da3d523 | |||
| 3050803e68 | |||
| beb803fc63 | |||
| b056bcae2c | |||
| 6a2c297640 | |||
| 8b3127eda4 | |||
| b63d51ab1d | |||
| 3b2dfd27d6 | |||
| b8753195df | |||
| e76eb113a5 | |||
| d285e10565 | |||
| 66803f9036 | |||
| d7cff48374 | |||
| d66ed0566b | |||
| fde2b3bf0f | |||
| dcc8270cc6 | |||
| 23b6ca7552 | |||
| 437173e6a4 | |||
| 1274facbed | |||
| 180fc2ca59 | |||
| 187cf8f55e | |||
| dd8868b2a2 | |||
| 921e8ea1a8 | |||
| 54e8782e12 | |||
| 9e690dd304 | |||
| 373b42041b | |||
| 30ead47fb9 | |||
| 2dc7206f17 | |||
| ab7594bd23 | |||
| 710a22aea7 | |||
| 2c7c801efc | |||
| 41ebe058e7 | |||
| 288c71b3e0 | |||
| d7a8afcb31 | |||
| a1d120ee22 | |||
| b58d6d0d82 | |||
| 5ab65391ca | |||
| 2b40d58996 | |||
| 96129388ec | |||
| 6f6058a2d1 | |||
| 063ef91613 | |||
| 5233072099 | |||
| cd063b0e8a | |||
| 719d796e20 | |||
| 9767bf5261 | |||
| a9998bf12d | |||
| 2b7dc899e1 | |||
| cbc3f51d4c | |||
| ff1c8c1bfe | |||
| 6d4222bb1a | |||
| 7692a6f258 | |||
| ed8e6b00c6 | |||
| 85db9570dd | |||
| be174b9cce | |||
| f0099090b4 | |||
| b72bdfcbf0 | |||
| e1f5addddc | |||
| 87d3145317 | |||
| 84fc89cbbe | |||
| fbbddd8365 | |||
| dcfb787563 | |||
| 6822b2db9b | |||
| d89b3772de | |||
| e4a4eb0455 | |||
| 759efa7da3 | |||
| bf1c271784 | |||
| 9754893181 | |||
| 5b05182a1c | |||
| 20528f72df | |||
| 7de08d9f24 | |||
| d047f5e6d2 | |||
| 71071f817c | |||
| ad9af9bb3d | |||
| c7c864b8c0 | |||
| 67d4862f6b | |||
| 6a16327c30 | |||
| 060b1b8f41 | |||
| da2e228293 | |||
| ab7397bf55 | |||
| f79547f781 | |||
| 2152f1c90e | |||
| 503fb4d246 | |||
| 2befefa752 | |||
| 85e64c5076 | |||
| 60523dc994 | |||
| 6d780bf350 | |||
| eec02a1f84 | |||
| ace2fe6fe3 | |||
| 188794af8d | |||
| 92a941a944 | |||
| 0e1ddf2b11 | |||
| b57fa010d1 | |||
| f816452b78 | |||
| 133308141b | |||
| 120083bb31 | |||
| a5bb5c4686 | |||
| e5e2729f0a | |||
| ba8b902f48 | |||
| 2d67815ae6 | |||
| ec0c9066d2 | |||
| 58ae858077 | |||
| 613e7938b3 | |||
| e07ff1a445 | |||
| de7dd34ea2 | |||
| 0552f695f9 | |||
| b8d4f3d946 | |||
| fa112a70b1 | |||
| 97309ebb88 | |||
| 556ddc0b6f | |||
| a0dde690ea | |||
| a76dab5be6 | |||
| 2d10bc5bbf | |||
| 4042632e0b | |||
| 7ccf83e1a4 | |||
| 019cd0756f | |||
| 0e5f9f80be | |||
| fc6767860a | |||
| 5b5b4be7b2 | |||
| 45351d082e | |||
| 22ccd07491 | |||
| 2cf9ee647b | |||
| efb567824b | |||
| f0aac39486 | |||
| f278055805 | |||
| 6f2e36fd11 | |||
| 119d80ffc8 | |||
| 771c3df864 | |||
| 7d1963e458 | |||
| dde85972b3 | |||
| 5e061da910 | |||
| 46bea345de | |||
| bc53462ad6 | |||
| 884df40a1d | |||
| b23168c067 | |||
| 5568212f15 | |||
| 79db79d799 | |||
| 18a4008efd | |||
| 83e4abd1ee | |||
| 243bcfba72 | |||
| af2c8c560f | |||
| 6a37f3871c | |||
| 759a388448 | |||
| 360e89d7ce | |||
| 64655a3284 | |||
| c58356bde8 | |||
| f74117632d | |||
| 5f2b8b8e2b | |||
| f0ce7481fd | |||
| 6e7a5c6140 | |||
| 079c18ee19 | |||
| 26ef6a3815 | |||
| cf6dcefe6c | |||
| 35590eb979 | |||
| 583a8b8a76 | |||
| c6e8a664de | |||
| 24a5e0a579 | |||
| a242c197fb | |||
| 08bdd23149 | |||
| c5b35b2d98 | |||
| 5407fecd1f | |||
| 12d2821d26 | |||
| 2e6d58e6a3 | |||
| 0f0c0fd5ae | |||
| ef9ec1c223 | |||
| f4387bae30 | |||
| 49b238a23a | |||
| 4b75c01b28 | |||
| e7f641046b | |||
| 9aaabe0fab | |||
| b6e4b711bf | |||
| 58fcfd210b | |||
| 5868b9c234 | |||
| 0dc6d9cf9d | |||
| 67f50cf2fd | |||
| 8b26a4d49a | |||
| a1d0bb0aa1 | |||
| bfe08560b1 | |||
| ac3ac24272 | |||
| 03e7191d0e | |||
| b3a42f8723 | |||
| 9c4b740300 | |||
| 2a12bdadf2 | |||
| c90e8ad4d2 | |||
| 4a52c51c86 | |||
| 0efc817ddc | |||
| fee54fc98c | |||
| 210f751396 | |||
| 2e2bc3fe29 | |||
| a6f05f86d1 | |||
| fc144e4848 | |||
| cef9531428 | |||
| abd4faefbf | |||
| 966f7aaed5 | |||
| 51b59fa995 | |||
| 0b713736bd | |||
| 9e33581c66 | |||
| b97792b596 | |||
| c0746f8eff | |||
| a826a9d692 | |||
| 6d04203d37 | |||
| 33b2ed8a94 | |||
| 4f16da7ad0 | |||
| 36f92c7655 | |||
| 1d4f5a759e | |||
| 28af9bc811 | |||
| cf04cd4094 | |||
| 23e9efb28a | |||
| 57322df29c | |||
| fff82d34c6 | |||
| 7211860c21 | |||
| 9fc69044f8 | |||
| 76467c3e81 | |||
| 4cfc04e2f3 | |||
| 6bfc7771d0 | |||
| 7055135257 | |||
| 85312cf20d | |||
| 4051cae5b0 | |||
| c64bb6dedf | |||
| 7bb17ae0db | |||
| 3244eb9b15 | |||
| 6e173847ba | |||
| 8cbc1f763d | |||
| 2d45abeb28 | |||
| 2fd0ad77bc | |||
| 53c1167831 | |||
| 48d4a1d7bb | |||
| 4bbbba6e89 | |||
| 0a13575325 | |||
| d6075209df | |||
| 9d1b39422b | |||
| 38e297d32b | |||
| 459ef3c9f1 | |||
| 3bb12487ba | |||
| 8b2428c60d | |||
| f9befd9051 | |||
| 1020a9bd5d | |||
| 2844c4ea86 | |||
| 3344188fee | |||
| 67138c2f78 | |||
| f59d19ef21 | |||
| d0fa7e638f | |||
| 63011e466e | |||
| 92d1976300 | |||
| a0cdc9fa07 | |||
| 60f0006597 | |||
| 67a3c62a08 | |||
| 21d5dc1e0b | |||
| 0d810f59f9 | |||
| dba60b700f | |||
| ad9a56bd20 | |||
| 82585e9104 | |||
| dfbb241b0b | |||
| f69ea91f45 | |||
| 768d916092 | |||
| c0acecae10 | |||
| f741d1c7e4 | |||
| d25c70f1d1 | |||
| 6f954467ef | |||
| 867987a5f5 | |||
| 61e0a6351c | |||
| 558264c23b | |||
| cf7aa371af | |||
| ffedaf6a73 | |||
| d9ae272b36 | |||
| 3c5d1f5c9e | |||
| b69b8b7585 | |||
| 8c7e498fb2 | |||
| 359413a296 | |||
| cef7d894c4 | |||
| 7d9cc1aacc | |||
| a6780a756b | |||
| 4e37d17b42 | |||
| 793923348f | |||
| 700db1788d | |||
| 68a5a44702 | |||
| 464891f5a1 | |||
| d2e5db2680 | |||
| a9c41d0545 | |||
| 0bc458d307 | |||
| 36c7cc285e | |||
| f9fbd31a0f | |||
| 8789c1f855 | |||
| f65073480a | |||
| 157ed831a7 | |||
| 0799a59a15 | |||
| 60ea3e83e1 | |||
| 4b874deb50 | |||
| 6726b9ad50 | |||
| 75e6fe609e | |||
| b40d1ccf7d | |||
| 4f7ba23904 | |||
| 49084706f2 | |||
| 1852e5f6bf | |||
| be0ed5428a | |||
| f428efde6a | |||
| e79f04f33e | |||
| 04db8c281f | |||
| 2681698186 | |||
| 1682c66da6 | |||
| 38bc1032d8 | |||
| ba37eef9ca | |||
| 3db179882a | |||
| ba8f25a807 | |||
| eac3d3089b | |||
| 0454a9e147 | |||
| f390cd1c68 | |||
| aaa1ba5aa9 | |||
| fb9556abd9 | |||
| 3cfb3b1f84 | |||
| b071bab137 | |||
| 5dbc68ea76 | |||
| e76fbc3b77 | |||
| 09ca0514d1 | |||
| faec32a5bb | |||
| 1f5793ab79 | |||
| df22bd1cec | |||
| 61dba4e78d | |||
| bb678117f8 | |||
| 2dc08e71b7 | |||
| df2f844e74 | |||
| 621c602fc0 | |||
| f809169757 | |||
| 848b135612 | |||
| db6af66705 | |||
| 728e1f5a86 | |||
| d02d95bc9e | |||
| c1180c5373 | |||
| 4e01fb64e6 | |||
| d0fcb1da34 | |||
| 48352d06b3 | |||
| d995652569 | |||
| 5a958fa51c | |||
| cfb9e2cacd | |||
| 7932fc1cab | |||
| e0fc1715b5 | |||
| 1cfd6caa64 | |||
| 54bf18888d | |||
| 6b60fc4259 | |||
| 216af8697c | |||
| d97e7314d0 | |||
| 67d9dda143 | |||
| 5c60e303cb | |||
| e36b8f3a56 | |||
| 1e7a19b463 | |||
| 8004249a29 | |||
| 6cd800e4ef | |||
| e182bc7ed2 | |||
| c338d51c9d | |||
| c1912250df | |||
| 994c41980e | |||
| 385b7a514d | |||
| 3aaade9228 | |||
| b4dd19b711 | |||
| 9e9b83b4ba | |||
| 5ff5114669 | |||
| f63039f3fb | |||
| b39399463d | |||
| 8217ef7fbb | |||
| b4851c34e1 | |||
| 8e39832d3e | |||
| ce7ac6da16 | |||
| 57879a57cd | |||
| 6f5b367028 | |||
| 291948c1ef | |||
| 0ca6888fb1 | |||
| 5e92236396 | |||
| 28db40112b | |||
| b2153883ef | |||
| 807cbeb75d | |||
| 4730aebdc6 | |||
| c2279eec87 | |||
| f5567ae9ad | |||
| 2fcba04cf5 | |||
| 0eefd1605f | |||
| 7b88ea022d | |||
| 7a922114ab | |||
| f717c270fd | |||
| ee5ed468c3 | |||
| a9ded445a7 | |||
| 9ecad52df2 | |||
| 8c500985bf | |||
| 3567f9ba5d | |||
| 852bfb716c | |||
| 473956aa3c | |||
| b22fc19400 | |||
| f6a8ece992 | |||
| afc0c21aae | |||
| 08e6106c1f | |||
| 1f9f654e3d | |||
| 501e923760 | |||
| 37b716cfc5 | |||
| 8584db0ab5 | |||
| 5aff3e9692 | |||
| 5d8f03cbc3 | |||
| b6c85ac15a | |||
| c2af757f4e | |||
| 26252c55ac | |||
| 3ce547bcea | |||
| e0492f589e | |||
| 4931288ffd | |||
| 52e0f77a3c | |||
| 20c016f1bf | |||
| 00a271cbba | |||
| 3a6b69634d | |||
| 78cf7f42e3 | |||
| 2b52454c00 | |||
| e032e4561b | |||
| 23ce1e0476 | |||
| 825b7b98d7 | |||
| 3de3128a2a | |||
| 92d70ccc8b | |||
| f8c5154457 | |||
| 3a3874e9f1 | |||
| 61b94c519b | |||
| ac0f46ca66 | |||
| e538cdb509 | |||
| df8a63c5f5 | |||
| 6827a61bf8 | |||
| 20e56c05b3 | |||
| 5494139319 | |||
| c491ba087a | |||
| 5cf045c941 | |||
| 55fea5f077 | |||
| 3a9cb73950 | |||
| d99f613b79 | |||
| 68db8ddff3 | |||
| c7490b264b | |||
| a8e84cfad3 | |||
| 5ec4f7e4e8 | |||
| b019ce2f2e | |||
| dd90e41610 | |||
| bdf78e374d | |||
| 163197f583 | |||
| 8e13bba44a | |||
| e4478b86a5 | |||
| 1b1ae59ed7 | |||
| a54f44d22a | |||
| d2394274eb | |||
| 0eedb0b397 | |||
| 782e9db1f6 | |||
| 2977472c56 | |||
| 8f3a8bfa91 | |||
| 914f6e9516 | |||
| fa6f65cb7c | |||
| dafbe6f995 | |||
| 4a8ac6377b | |||
| c91fac4ec4 | |||
| 00d23b084e | |||
| e0a3b82cea | |||
| e49036d8c4 | |||
| 4a8356692b | |||
| adfb7bc63a | |||
| 3f41cefa88 | |||
| 2074ff1987 | |||
| 65fe189421 | |||
| bb7590eab4 | |||
| 6a04457219 | |||
| 7f8b1d9586 | |||
| 4362cc53bb | |||
| 959e6b2a12 | |||
| 2d91070e5a | |||
| cc038ece32 | |||
| 7af1292f29 | |||
| 2c3fd7a84f | |||
| d36f70dbc7 | |||
| 77f5f29c90 | |||
| ead45ed843 | |||
| a6259bb7eb | |||
| 0249ebeb95 | |||
| 1c3a35a137 | |||
| c12319b417 | |||
| 90ac00a628 | |||
| e5c71cb3a4 | |||
| ebf0681574 | |||
| 642643f412 | |||
| 8dd65ac255 | |||
| 8df58f226b | |||
| 58b4f2ce14 | |||
| 65f0c836fe | |||
| 2aa16085a5 | |||
| 25f05a69c6 | |||
| 5c2a94da16 | |||
| 162325e90e | |||
| b022a8c608 | |||
| 1e404f5e6b | |||
| 8ef7780332 | |||
| 51b4f7b3f7 | |||
| 9b3fa33e50 | |||
| 9349d0813d | |||
| 8d9bc500a1 | |||
| cae7b6e29f | |||
| 0b4ac732b2 | |||
| acacbb91e3 | |||
| fd6d3d9a2f | |||
| 3b531e30b1 | |||
| 0c78085b2e | |||
| 4ab53308f7 | |||
| 06ae161793 | |||
| 94e005d2f8 | |||
| 717072c3a5 | |||
| 02b4bde92a | |||
| a397d1e233 | |||
| d2198c0765 | |||
| 549bf63198 | |||
| 8b824f5342 | |||
| d052d5e8a1 | |||
| 610c22dd02 | |||
| a5496ab6a9 | |||
| c29c8f009c | |||
| fb7e9f2a6c | |||
| 62c2bbb9fa | |||
| 7656772194 | |||
| f22ff050e0 | |||
| 708f0b44fd | |||
| 2ee4581f17 | |||
| e337fb869f | |||
| 4a8b0147e1 | |||
| c95a1c7e1f | |||
| a07cd5c3f5 | |||
| 4d1473582e | |||
| 3bc9f4c452 | |||
| 11377038a0 | |||
| 6053d3eac1 | |||
| 529830f36b | |||
| 505cf6265c | |||
| 8cd9673eec | |||
| ac9cb28558 | |||
| 6eefe0698c | |||
| d0113532b6 | |||
| 5a1d2ad5f4 | |||
| dfe02f4c74 | |||
| 5349d556b9 | |||
| 7f7d8a501b | |||
| cbee0e465b | |||
| faf00f0b0d | |||
| fa97da5781 | |||
| e7bab546db | |||
| e2f4a30b5b | |||
| ccff1df041 | |||
| 2037cfc25a | |||
| 268a091d8a | |||
| 6b52dfab3e | |||
| 839999851f | |||
| a87470b7b5 | |||
| e76aeb80fd | |||
| 28292e59e2 | |||
| 25dda481b2 | |||
| bbda233fd8 | |||
| 349218f0b5 | |||
| f18d00a69d | |||
| 25ea6504de | |||
| 43081c70e2 | |||
| 0fde1c2026 | |||
| b35383571e | |||
| 45a84847a2 | |||
| 70d92f26d6 | |||
| 737ed86e69 | |||
| 3865057b7a | |||
| 42a84dcd86 | |||
| e2d819c59d | |||
| bfee6a88dc | |||
| 46e740154e |
@@ -1,140 +1,17 @@
|
||||
version: 2.1
|
||||
|
||||
orbs:
|
||||
# Using windows for builds
|
||||
win: circleci/windows@2.4.0
|
||||
# Upload artifacts to s3
|
||||
aws-s3: circleci/aws-s3@2.0.0
|
||||
|
||||
# Define the jobs we want to run for this project
|
||||
jobs:
|
||||
build-ui:
|
||||
build:
|
||||
docker:
|
||||
- image: "circleci/node:16"
|
||||
- image: cimg/base:2023.03
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
command: "npm install"
|
||||
working_directory: "ui"
|
||||
- run:
|
||||
command: "npm run build"
|
||||
working_directory: "ui"
|
||||
- persist_to_workspace:
|
||||
root: ./
|
||||
paths:
|
||||
- speckle_connector/vue_ui
|
||||
|
||||
build-connector: # Reusable job for basic connectors
|
||||
executor:
|
||||
name: win/default # comes with python 3.7.3
|
||||
shell: cmd.exe
|
||||
parameters:
|
||||
slug:
|
||||
type: string
|
||||
default: ""
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: ./
|
||||
- run:
|
||||
name: Patch
|
||||
shell: powershell.exe
|
||||
command:
|
||||
| # If no tag, use 0.0.0.1 and don't make any YML (for testing only!)
|
||||
$tag = if([string]::IsNullOrEmpty($env:CIRCLE_TAG)) { "0.0.0" } else { $env:CIRCLE_TAG }
|
||||
$semver = if($tag.Contains('/')) {$tag.Split("/")[1] } else { $tag }
|
||||
$ver = if($semver.Contains('-')) {$semver.Split("-")[0] } else { $semver }
|
||||
$channel = if($semver.Contains('-')) {$semver.Split("-")[1] } else { "latest" }
|
||||
$version = "$($ver).$($env:CIRCLE_BUILD_NUM)"
|
||||
New-Item -Force "speckle-sharp-ci-tools/Installers/sketchup/$channel.yml" -ItemType File -Value "version: $semver"
|
||||
echo $version
|
||||
python patch_version.py $semver
|
||||
speckle-sharp-ci-tools\InnoSetup\ISCC.exe speckle-sharp-ci-tools\sketchup.iss
|
||||
- persist_to_workspace:
|
||||
root: ./
|
||||
paths:
|
||||
- speckle-sharp-ci-tools/Installers
|
||||
|
||||
get-ci-tools: # Clones our ci tools and persists them to the workspace
|
||||
docker:
|
||||
- image: cimg/base:2021.01
|
||||
steps:
|
||||
- add_ssh_keys:
|
||||
fingerprints:
|
||||
- "03:2e:ee:4f:14:67:2b:88:32:e8:cc:f0:cb:df:92:29"
|
||||
- run:
|
||||
name: I know Github as a host
|
||||
command: |
|
||||
mkdir ~/.ssh
|
||||
touch ~/.ssh/known_hosts
|
||||
ssh-keyscan github.com >> ~/.ssh/known_hosts
|
||||
- run:
|
||||
name: Clone
|
||||
command: git clone git@github.com:specklesystems/speckle-sharp-ci-tools.git speckle-sharp-ci-tools
|
||||
- persist_to_workspace:
|
||||
root: ./
|
||||
paths:
|
||||
- speckle-sharp-ci-tools
|
||||
- persist_to_workspace:
|
||||
root: ./
|
||||
paths:
|
||||
- speckle-sharp-ci-tools
|
||||
deploy-manager2:
|
||||
docker:
|
||||
- image: mcr.microsoft.com/dotnet/sdk:6.0
|
||||
parameters:
|
||||
slug:
|
||||
type: string
|
||||
os:
|
||||
type: string
|
||||
extension:
|
||||
type: string
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: ./
|
||||
- run:
|
||||
name: Install Manager Feed CLI
|
||||
command: dotnet tool install --global Speckle.Manager.Feed
|
||||
- run:
|
||||
name: Upload new version
|
||||
command: |
|
||||
TAG=$(if [ "${CIRCLE_TAG}" ]; then echo $CIRCLE_TAG; else echo "0.0.0"; fi;)
|
||||
SEMVER=$(echo "$TAG" | sed -e 's/\/[a-zA-Z-]*//')
|
||||
/root/.dotnet/tools/Speckle.Manager.Feed deploy -s << parameters.slug >> -v ${SEMVER} -u https://releases.speckle.dev/installers/<< parameters.slug >>/<< parameters.slug >>-${SEMVER}.<< parameters.extension >> -o << parameters.os >> -f speckle-sharp-ci-tools/Installers/<< parameters.slug >>/<< parameters.slug >>-${SEMVER}.<< parameters.extension >>
|
||||
- run: echo "so long and thanks for all the fish"
|
||||
|
||||
# Orchestrate our job run sequence
|
||||
workflows:
|
||||
build-and-deploy:
|
||||
build_and_test:
|
||||
when:
|
||||
false
|
||||
jobs:
|
||||
- get-ci-tools:
|
||||
filters:
|
||||
tags:
|
||||
only: /.*/
|
||||
|
||||
- build-ui:
|
||||
filters:
|
||||
tags:
|
||||
only: /.*/
|
||||
|
||||
- build-connector:
|
||||
slug: sketchup
|
||||
requires:
|
||||
- get-ci-tools
|
||||
- build-ui
|
||||
filters:
|
||||
tags:
|
||||
only: /.*/
|
||||
|
||||
- deploy-manager2:
|
||||
context: do-spaces-speckle-releases
|
||||
slug: sketchup
|
||||
os: Win
|
||||
extension: exe
|
||||
requires:
|
||||
- get-ci-tools
|
||||
- build-ui
|
||||
- build-connector
|
||||
filters:
|
||||
tags:
|
||||
only: /([0-9]+)\.([0-9]+)\.([0-9]+)(?:-\w+)?$/
|
||||
branches:
|
||||
ignore: /.*/ # For testing only! /ci\/.*/
|
||||
- build
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# This workflow will install Python dependencies, run tests and lint with a single version of Python
|
||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
|
||||
|
||||
name: Build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
workflow_call:
|
||||
outputs:
|
||||
semver:
|
||||
description: "The full SemVer 2.0 version of this build, e.g. '3.0.0-alpha.1234' (note: no 'v'-prefix)"
|
||||
value: ${{ jobs.build.outputs.semver }}
|
||||
file_version:
|
||||
description: "The file info version, e.g. '3.0.0.1234'"
|
||||
value: ${{ jobs.build.outputs.file_version }}
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
semver: ${{ steps.set-version.outputs.semver }}
|
||||
file_version: ${{ steps.set-version.outputs.file-version }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.10"
|
||||
|
||||
- id: set-version
|
||||
name: Set version to output
|
||||
shell: bash
|
||||
run: |
|
||||
TAG=${{ github.ref_name }}
|
||||
if [[ "${{ github.ref }}" != refs/tags/* ]]; then
|
||||
TAG="v3.0.99.${{ github.run_number }}"
|
||||
fi
|
||||
SEMVER="${TAG#v}"
|
||||
FILE_VERSION=$(echo "$TAG" | sed -E 's/^v([0-9]+\.[0-9]+\.[0-9]+).*/\1/')
|
||||
FILE_VERSION="$FILE_VERSION.${{ github.run_number }}"
|
||||
|
||||
echo "semver=$SEMVER" >> "$GITHUB_OUTPUT"
|
||||
echo "file-version=$FILE_VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
echo $SEMVER
|
||||
echo $FILE_VERSION
|
||||
|
||||
- name: Set connector version
|
||||
run: |
|
||||
python patch_version.py ${{steps.set-version.outputs.semver}}
|
||||
|
||||
- uses: montudor/action-zip@v1
|
||||
with:
|
||||
args: zip -q -r sketchup.zip vendor speckle_connector_3/ speckle_connector_3.rb
|
||||
|
||||
- name: ⬆️ Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: output-${{steps.set-version.outputs.semver}}
|
||||
path: sketchup.zip
|
||||
retention-days: 1
|
||||
if-no-files-found: error
|
||||
compression-level: 0 # no compression
|
||||
@@ -0,0 +1,42 @@
|
||||
# This workflow will install Python dependencies, run tests and lint with a single version of Python
|
||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
|
||||
|
||||
name: Build and deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main", "installer-test/**"]
|
||||
tags: ["v3.*.*"] # Manual delivery on every 3.x tag
|
||||
|
||||
jobs:
|
||||
build:
|
||||
uses: ./.github/workflows/build.yml
|
||||
|
||||
deploy-installers:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
env:
|
||||
IS_PUBLIC_RELEASE: ${{ github.ref_type == 'tag' }}
|
||||
steps:
|
||||
- name: 🔫 Trigger Build Installer(s)
|
||||
uses: the-actions-org/workflow-dispatch@v4.0.0
|
||||
with:
|
||||
workflow: Build Installers
|
||||
repo: specklesystems/connector-installers
|
||||
token: ${{ secrets.CONNECTORS_GH_TOKEN }}
|
||||
inputs: '{
|
||||
"run_id": "${{ github.run_id }}",
|
||||
"semver": "${{ needs.build.outputs.semver }}",
|
||||
"file_version": "${{ needs.build.outputs.file_version }}",
|
||||
"repo": "${{ github.repository }}",
|
||||
"is_public_release": ${{ env.IS_PUBLIC_RELEASE }}
|
||||
}'
|
||||
ref: jrm/installer-warnings
|
||||
wait-for-completion: true
|
||||
wait-for-completion-interval: 10s
|
||||
wait-for-completion-timeout: 10m
|
||||
display-workflow-run-url: true
|
||||
display-workflow-run-url-interval: 10s
|
||||
- uses: geekyeggo/delete-artifact@v5
|
||||
with:
|
||||
name: output-*
|
||||
@@ -1,38 +0,0 @@
|
||||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
# separate terms of service, privacy policy, and support
|
||||
# documentation.
|
||||
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
||||
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
||||
|
||||
name: Ruby
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
ruby-version: ['2.7']
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Ruby
|
||||
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
||||
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
||||
# uses: ruby/setup-ruby@v1
|
||||
uses: ruby/setup-ruby@0a29871fe2b0200a17a4497bae54fe5df0d973aa # v1.115.3
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby-version }}
|
||||
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
||||
- name: Run tests
|
||||
run: bundle exec rake
|
||||
@@ -10,8 +10,8 @@
|
||||
settings.json
|
||||
|
||||
# vue app build dist folder
|
||||
speckle_connector/vue_ui
|
||||
speckle_connector/html
|
||||
speckle_connector_3/vue_ui
|
||||
speckle_connector_3/html
|
||||
|
||||
# speckle-sharp-ci-tools
|
||||
/speckle-sharp-ci-tools
|
||||
|
||||
@@ -18,7 +18,7 @@ AllCops:
|
||||
- '_tools/su_attributes/**/*.rb'
|
||||
- '_sqlite3/**/*.rb'
|
||||
- 'ui/**/*'
|
||||
- 'speckle_connector/src/ext/**/*.rb'
|
||||
- 'speckle_connector_3/src/ext/**/*.rb'
|
||||
- 'vendor/bundle/**/*'
|
||||
- 'tests/**/*.rb'
|
||||
SketchUp:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
require_paths:
|
||||
- "C:/Program Files/SketchUp/SketchUp 2021/Tools"
|
||||
- speckle_connector
|
||||
- speckle_connector_3
|
||||
|
||||
require:
|
||||
- sketchup-api-stubs
|
||||
|
||||
@@ -24,6 +24,8 @@ group :development do
|
||||
gem 'rubycritic', '~> 4.3', '>= 4.3.3', require: false
|
||||
# Auto completions for SketchUp API.
|
||||
gem 'sketchup-api-stubs'
|
||||
# Runtime dependency of skippy for Ruby 3.2. Have it!
|
||||
gem 'sorted_set', '~> 1.0'
|
||||
# Aid with common SketchUp extension tasks.
|
||||
gem 'skippy', '~> 0.4.1.a'
|
||||
gem 'skippy', '~> 0.5.2.a'
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
addressable (2.8.1)
|
||||
addressable (2.8.4)
|
||||
public_suffix (>= 2.0.2, < 6.0)
|
||||
ast (2.4.2)
|
||||
axiom-types (0.1.1)
|
||||
@@ -26,7 +26,7 @@ GEM
|
||||
path_expander (~> 1.0)
|
||||
ruby_parser (~> 3.1, > 3.1.0)
|
||||
sexp_processor (~> 4.8)
|
||||
git (1.12.0)
|
||||
git (1.19.1)
|
||||
addressable (~> 2.8)
|
||||
rchardet (~> 1.8)
|
||||
ice_nine (0.11.2)
|
||||
@@ -48,10 +48,10 @@ GEM
|
||||
pry (0.14.1)
|
||||
coderay (~> 1.1)
|
||||
method_source (~> 1.0)
|
||||
psych (3.3.4)
|
||||
public_suffix (5.0.0)
|
||||
public_suffix (5.0.1)
|
||||
rainbow (3.1.1)
|
||||
rake (13.0.6)
|
||||
rbtree (0.4.6)
|
||||
rchardet (1.8.0)
|
||||
reek (6.1.1)
|
||||
kwalify (~> 0.7.0)
|
||||
@@ -90,6 +90,7 @@ GEM
|
||||
simplecov (>= 0.17.0)
|
||||
tty-which (~> 0.4.0)
|
||||
virtus (~> 1.0)
|
||||
set (1.1.0)
|
||||
sexp_processor (4.16.1)
|
||||
simplecov (0.21.2)
|
||||
docile (~> 1.1)
|
||||
@@ -98,11 +99,15 @@ GEM
|
||||
simplecov-html (0.12.3)
|
||||
simplecov_json_formatter (0.1.4)
|
||||
sketchup-api-stubs (0.7.8)
|
||||
skippy (0.4.3.a)
|
||||
skippy (0.5.2.a)
|
||||
git (~> 1.3)
|
||||
naturally (~> 2.1)
|
||||
thor (~> 0.19)
|
||||
thor (0.20.3)
|
||||
sorted_set (~> 1.0)
|
||||
thor (>= 0.19, < 2.0)
|
||||
sorted_set (1.0.3)
|
||||
rbtree
|
||||
set (~> 1.0)
|
||||
thor (1.3.1)
|
||||
thread_safe (0.3.6)
|
||||
tty-which (0.4.2)
|
||||
unicode-display_width (1.8.0)
|
||||
@@ -113,6 +118,7 @@ GEM
|
||||
equalizer (~> 0.0, >= 0.0.9)
|
||||
|
||||
PLATFORMS
|
||||
x64-mingw-ucrt
|
||||
x64-mingw32
|
||||
x64-unknown
|
||||
x86_64-linux
|
||||
@@ -128,7 +134,8 @@ DEPENDENCIES
|
||||
rubocop-sketchup
|
||||
rubycritic (~> 4.3, >= 4.3.3)
|
||||
sketchup-api-stubs
|
||||
skippy (~> 0.4.1.a)
|
||||
skippy (~> 0.5.2.a)
|
||||
sorted_set (~> 1.0)
|
||||
|
||||
BUNDLED WITH
|
||||
2.3.25
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
workflow: GitFlow/v1
|
||||
next-version: 3.0.0
|
||||
mode: ManualDeployment
|
||||
branches:
|
||||
main:
|
||||
label: rc
|
||||
develop:
|
||||
regex: ^dui3/alpha$
|
||||
label: beta
|
||||
unknown:
|
||||
increment: None
|
||||
@@ -49,9 +49,9 @@ This repo is split into three parts:
|
||||
### 1. **Speckle Connector extension**
|
||||
|
||||
Includes the `ruby` source files to run extension on SketchUp environment. SketchUp Extensions are composed of
|
||||
a **.rb** file as entry and **folder** that .rb file refers to. In our case entry file is `speckle_connector.rb`
|
||||
a **.rb** file as entry and **folder** that .rb file refers to. In our case entry file is `speckle_connector_3.rb`
|
||||
that responsible to register Speckle Connector extension to SketchUp and also it shows address to where extension
|
||||
will start to read extension. Source folder is `speckle_connector`.
|
||||
will start to read extension. Source folder is `speckle_connector_3`.
|
||||
|
||||
### 2. **User Interface**
|
||||
|
||||
@@ -64,7 +64,7 @@ This repo is split into three parts:
|
||||
we use extensions as native part of the source `ruby` code.
|
||||
|
||||
After building `sqlite3.sln` file, compiled `sqlite3.so` (for Windows) and `sqlite3.bundle` (for OSX) dynamic library files are created
|
||||
by solution to place them into source code into `speckle_connector/src/ext`. Building this project should be only
|
||||
by solution to place them into source code into `speckle_connector_3/src/ext`. Building this project should be only
|
||||
happen when SketchUp starts to support newer Ruby versions (currently it is `2.7`).
|
||||
|
||||
## Contribution Guide
|
||||
@@ -115,9 +115,23 @@ You can now open up the repo in VS Code or you can use JetBrains' tools RubyMine
|
||||
|
||||
If you will use VS Code, make sure you've installed the Ruby extension for VS Code.
|
||||
|
||||
#### RubyMine
|
||||
|
||||
To debug:
|
||||
- Add configuration as **'Ruby remote debug'**
|
||||
- Remote host: localhost
|
||||
- Remote port: 7000
|
||||
- Remote root folder: <repo_path>
|
||||
- Local port: 26162
|
||||
- Local root folder: <repo_path>
|
||||
- Run below script
|
||||
|
||||
bundle exec skippy sketchup:debug 2024
|
||||
- When sketchup opened, click Debug button on RubyMine
|
||||
|
||||
### Loading the Speckle Connector Plugin
|
||||
|
||||
1. Find already prepared `speckle_connector_loader.rb` file on the `_tools`
|
||||
1. Find already prepared `speckle_connector_3_loader.rb` file on the `_tools`
|
||||
folder.
|
||||
2. Copy this Ruby file into your SketchUp Plugins directory. You will likely find this at:
|
||||
`C:\Users\{YOU}\AppData\Roaming\SketchUp\SketchUp 20XX\SketchUp\Plugins`
|
||||
|
||||
@@ -32,12 +32,12 @@ end
|
||||
|
||||
# Glob pattern to match source files. Defaults to FileList['.'].
|
||||
ruby_critic_paths = FileList[
|
||||
'speckle_connector/**/*.rb',
|
||||
'speckle_connector.rb',
|
||||
'speckle_connector_3/**/*.rb',
|
||||
'speckle_connector_3.rb',
|
||||
'tests/**/*.rb'] -
|
||||
FileList[
|
||||
'_tools/**/*.rb',
|
||||
'speckle_connector/src/ext/**/*.rb',
|
||||
'speckle_connector_3/src/ext/**/*.rb',
|
||||
]
|
||||
|
||||
# for local
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# This is for automated pre-debugger configuration.
|
||||
# We run skippy first, then activate debugger.
|
||||
# The purpose of this file to wait till skp is live
|
||||
|
||||
# To establish a configuration
|
||||
# 1. Create 'Run External Tool' before lunch step
|
||||
# 2. Program -> C:\Ruby32-x64\bin\ruby.exe or whatever
|
||||
# 3. Arguments -> C:\Users\KORAL\Documents\Git\Speckle\speckle-sketchup\_tools\debugger\bundle_exec_2024.rb or whatever
|
||||
# 4. Working directory -> C:\Users\KORAL\Documents\Git\Speckle\speckle-sketchup or whatever
|
||||
|
||||
# Add a delay of 10 seconds, it is arbitrary, do not hesitate to change for what works best for you
|
||||
sleep(10)
|
||||
|
||||
# Execute the original command
|
||||
exec('bundle exec skippy sketchup:debug 2024')
|
||||
@@ -24,7 +24,7 @@ module JF_RubyToolbar
|
||||
def self.load_toolbar
|
||||
@last_dir = "#{$LOAD_PATH[0]}/"
|
||||
@last_dir = @last_dir.gsub('/', '\\\\\\\\')
|
||||
@last_dir = File.join($JF_RUBYTOOLBAR, 'speckle_connector')
|
||||
@last_dir = File.join($JF_RUBYTOOLBAR, 'speckle_connector_3')
|
||||
curdir = File.dirname __FILE__
|
||||
|
||||
# create toolbar
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# Create a link to Plugins folder with this command
|
||||
|
||||
# rubocop:disable Layout/LineLength
|
||||
# New-Item -ItemType SymbolicLink -Path '~\AppData\Roaming\SketchUp\SketchUp 2022\SketchUp\Plugins\speckle_connector_loader.rb' -Target ~\Git\Speckle\speckle-sketchup\_tools\speckle_connector_loader.rb
|
||||
# New-Item -ItemType SymbolicLink -Path '~\AppData\Roaming\SketchUp\SketchUp 2022\SketchUp\Plugins\speckle_connector_3_loader.rb' -Target ~\Git\Speckle\speckle-sketchup\_tools\speckle_connector_3_loader.rb
|
||||
# rubocop:enable Layout/LineLength
|
||||
|
||||
SKETCHUP_CONSOLE.show # if you want to show Ruby console on startup
|
||||
@@ -32,7 +32,7 @@ $LOAD_PATH << File.join(speckle_path, '_tools')
|
||||
$JF_RUBYTOOLBAR = speckle_path
|
||||
# rubocop:enable Style/GlobalVars
|
||||
|
||||
files = %w[speckle_connector jf_RubyPanel su_attributes]
|
||||
files = %w[speckle_connector_3 jf_RubyPanel su_attributes]
|
||||
|
||||
files.each do |ruby_file|
|
||||
puts "Loading #{ruby_file}"
|
||||
@@ -4,7 +4,7 @@ import sys
|
||||
|
||||
def patch_connector(tag):
|
||||
"""Patches the connector version within the connector file"""
|
||||
rb_file = "speckle_connector.rb"
|
||||
rb_file = "speckle_connector_3.rb"
|
||||
|
||||
with open(rb_file, "r") as file:
|
||||
lines = file.readlines()
|
||||
@@ -15,6 +15,12 @@ def patch_connector(tag):
|
||||
print(f"Patched connector version number in {rb_file}")
|
||||
break
|
||||
|
||||
for (index, line) in enumerate(lines):
|
||||
if 'DEV_MODE = ' in line:
|
||||
lines[index] = f' DEV_MODE = false\n'
|
||||
print(f"Patched dev mode to false in {rb_file}")
|
||||
break
|
||||
|
||||
with open(rb_file, "w") as file:
|
||||
file.writelines(lines)
|
||||
|
||||
@@ -45,7 +51,7 @@ def main():
|
||||
|
||||
print(f"Patching version: {tag}")
|
||||
patch_connector(tag)
|
||||
patch_installer(tag)
|
||||
# patch_installer(tag)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
|
Before Width: | Height: | Size: 2.4 KiB |
@@ -1,31 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'JSON'
|
||||
require_relative '../ext/sqlite3'
|
||||
require_relative '../constants/path_constants'
|
||||
|
||||
module SpeckleConnector
|
||||
# Accounts to communicate with models on user's account.
|
||||
module Accounts
|
||||
def self.load_accounts
|
||||
db_path = SPECKLE_ACCOUNTS_DB_PATH
|
||||
unless File.exist?(db_path)
|
||||
raise(
|
||||
IOError,
|
||||
"No Accounts db found. Please read the guide for different options for adding your account:\n
|
||||
https://speckle.guide/user/manager.html#adding-accounts"
|
||||
)
|
||||
end
|
||||
|
||||
db = Sqlite3::Database.new(db_path)
|
||||
rows = db.exec('SELECT * FROM objects')
|
||||
db.close
|
||||
rows.map { |row| JSON.parse(row[1]) }
|
||||
end
|
||||
|
||||
def self.default_account
|
||||
accounts = load_accounts
|
||||
accounts.select { |acc| acc['isDefault'] }[0] || accounts[0]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,27 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'action'
|
||||
require_relative '../states/state'
|
||||
require_relative '../states/speckle_state'
|
||||
require_relative '../states/sketchup_state'
|
||||
require_relative '../accounts/accounts'
|
||||
require_relative '../preferences/preferences'
|
||||
|
||||
module SpeckleConnector
|
||||
module Actions
|
||||
# Initialization of the real state of the speckle.
|
||||
class InitializeSpeckle < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state)
|
||||
accounts = SpeckleConnector::Accounts.load_accounts
|
||||
speckle_state = States::SpeckleState.new(accounts, {}, {})
|
||||
# This should be the only point that `Sketchup_active_model` passed to application state.
|
||||
sketchup_state = States::SketchupState.new(Sketchup.active_model)
|
||||
preferences = Preferences.init_preferences(sketchup_state.sketchup_model)
|
||||
user_state_with_preferences = state.user_state.with_preferences(preferences)
|
||||
States::State.new(user_state_with_preferences, speckle_state, sketchup_state, false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,45 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'action'
|
||||
require_relative '../accounts/accounts'
|
||||
require_relative '../actions/create_stream'
|
||||
require_relative '../actions/queue_send'
|
||||
require_relative '../convertors/to_speckle'
|
||||
|
||||
module SpeckleConnector
|
||||
module Actions
|
||||
# Sends to speckle.
|
||||
class OneClickSend < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state)
|
||||
puts 'send to speckle'
|
||||
default_account = Accounts.default_account
|
||||
if default_account.nil?
|
||||
puts 'No local account found. Please refer to speckle.guide for more information.'
|
||||
return state
|
||||
end
|
||||
sketchup_model = state.sketchup_state.sketchup_model
|
||||
to_convert = sketchup_model.selection.count > 0 ? sketchup_model.selection : sketchup_model.entities
|
||||
first_saved_stream = first_saved_stream(sketchup_model)
|
||||
action = if first_saved_stream.nil?
|
||||
Actions::CreateStream.new
|
||||
else
|
||||
Actions::QueueSend.new(first_saved_stream, convert_to_speckle(sketchup_model, to_convert))
|
||||
end
|
||||
|
||||
action.update_state(state)
|
||||
end
|
||||
|
||||
def self.first_saved_stream(model)
|
||||
(saved_streams = model.attribute_dictionary('speckle', true)['streams']) or []
|
||||
saved_streams.nil? || saved_streams.empty? ? nil : saved_streams[0]
|
||||
end
|
||||
|
||||
def self.convert_to_speckle(sketchup_model, to_convert)
|
||||
converter = Converters::ToSpeckle.new(sketchup_model)
|
||||
to_convert.map { |entity| converter.convert(entity) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,32 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'action'
|
||||
require_relative '../convertors/units'
|
||||
require_relative '../convertors/to_speckle'
|
||||
|
||||
module SpeckleConnector
|
||||
module Actions
|
||||
# Send selection to server.
|
||||
class SendSelection < Action
|
||||
def initialize(stream_id)
|
||||
super()
|
||||
@stream_id = stream_id
|
||||
end
|
||||
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def update_state(state)
|
||||
sketchup_model = state.sketchup_state.sketchup_model
|
||||
converter = Converters::ToSpeckle.new(sketchup_model)
|
||||
base = converter.convert_selection_to_base(state.user_state.preferences)
|
||||
id, total_children_count, batches = converter.send_info(base)
|
||||
puts("converted #{base.count} objects for stream #{@stream_id}")
|
||||
state.with_add_queue('convertedFromSketchup', @stream_id, [
|
||||
{ is_string: false, val: batches },
|
||||
{ is_string: true, val: id },
|
||||
{ is_string: false, val: total_children_count }
|
||||
])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,31 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module SpeckleConnector
|
||||
module Commands
|
||||
# Base command schema to wrap common operations for all commands.
|
||||
class Command
|
||||
# @return [App::SpeckleConnectorApp] the main app object
|
||||
attr_reader :app
|
||||
|
||||
# @return [Ui::View] view object holds dialog and it's state
|
||||
attr_reader :view
|
||||
|
||||
# @@param app [App::SpeckleConnectorApp] the main app object
|
||||
def initialize(app)
|
||||
@app = app
|
||||
@view = app.ui_controller.user_interfaces[Ui::SPECKLE_UI_ID]
|
||||
end
|
||||
|
||||
def run(*parameters)
|
||||
# Run here common operations that same for each command.
|
||||
_run(*parameters)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _run(*_parameters)
|
||||
raise NotImplementedError, 'Implement in subclass'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,15 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'command'
|
||||
|
||||
module SpeckleConnector
|
||||
module Commands
|
||||
# Run this command when the UI is ready to get data
|
||||
class DialogReady < Command
|
||||
# Update the selected user interface
|
||||
def _run(_data)
|
||||
view.update_view(app.state)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,47 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'command'
|
||||
require_relative '../states/initial_state'
|
||||
require_relative '../ui/vue_view'
|
||||
require_relative '../actions/initialize_speckle'
|
||||
|
||||
module SpeckleConnector
|
||||
module Commands
|
||||
# Command to initialize Speckle UI and register it to ui_controller.
|
||||
# This is the command where we show UI to user.
|
||||
class InitializeSpeckle < Command
|
||||
def dialog_title
|
||||
"Speckle #{CONNECTOR_VERSION}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _run
|
||||
app = self.app
|
||||
unless app.state.instance_of?(States::InitialState)
|
||||
vue_view = app.ui_controller.user_interfaces[Ui::SPECKLE_UI_ID]
|
||||
vue_view.show
|
||||
return
|
||||
end
|
||||
|
||||
initialize_speckle(app)
|
||||
end
|
||||
|
||||
# Do the actual Speckle initialization.
|
||||
def initialize_speckle(app)
|
||||
# TODO: Initialize here speckle states and observers.
|
||||
app.update_state!(Actions::InitializeSpeckle)
|
||||
dialog_specs = {
|
||||
dialog_id: Ui::SPECKLE_UI_ID,
|
||||
htm_file: Ui::VUE_UI_HTML,
|
||||
dialog_title: dialog_title,
|
||||
height: 950,
|
||||
width: 300
|
||||
}
|
||||
vue_view = Ui::VueView.new(dialog_specs, app)
|
||||
app.ui_controller.register_ui(Ui::SPECKLE_UI_ID, vue_view)
|
||||
vue_view.show
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,58 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'menu_command_handler'
|
||||
require_relative 'action_command'
|
||||
require_relative 'initialize_speckle'
|
||||
require_relative '../actions/one_click_send'
|
||||
|
||||
module SpeckleConnector
|
||||
module Commands
|
||||
# Speckle menu commands that adds them to Sketchup menu and toolbar.
|
||||
class SpeckleMenuCommands
|
||||
CMD_INITIALIZE_SPECKLE = :initialize_speckle
|
||||
CMD_SEND_TO_SPECKLE = :send_to_speckle
|
||||
CMD_RECEIVE_FROM_SPECKLE = :receive_from_speckle
|
||||
|
||||
# Add initial set of commands to Speckle application object and to Sketchup menu and toolbar
|
||||
# @param app [App::SpeckleConnectorApp] the application object
|
||||
def self.add_initial_commands!(app)
|
||||
commands = app.menu_commands
|
||||
ui_controller = app.ui_controller
|
||||
sketchup_ui = ui_controller.sketchup_ui
|
||||
speckle_menu = sketchup_ui.speckle_menu
|
||||
speckle_toolbar = sketchup_ui.speckle_toolbar
|
||||
|
||||
commands[CMD_INITIALIZE_SPECKLE] = initialize_speckle_command(app)
|
||||
commands.add_to_menu!(CMD_INITIALIZE_SPECKLE, speckle_menu)
|
||||
commands.add_to_toolbar!(CMD_INITIALIZE_SPECKLE, speckle_toolbar)
|
||||
|
||||
# commands[CMD_SEND_TO_SPECKLE] = send_command(app)
|
||||
# commands.add_to_menu!(CMD_SEND_TO_SPECKLE, speckle_menu)
|
||||
# commands.add_to_toolbar!(CMD_SEND_TO_SPECKLE, speckle_toolbar)
|
||||
end
|
||||
|
||||
def self.initialize_speckle_command(app)
|
||||
cmd = MenuCommandHandler.sketchup_command(
|
||||
InitializeSpeckle.new(app), 'Initialize Speckle'
|
||||
)
|
||||
cmd.tooltip = 'Launch Connector'
|
||||
cmd.status_bar_text = 'Opens the Speckle Connector window'
|
||||
cmd.small_icon = '../../img/s2logo.png'
|
||||
cmd.large_icon = '../../img/s2logo.png'
|
||||
cmd
|
||||
end
|
||||
|
||||
def self.send_command(app)
|
||||
cmd = MenuCommandHandler.sketchup_command(
|
||||
ActionCommand.new(app, Actions::OneClickSend), 'Send to Speckle'
|
||||
)
|
||||
cmd.tooltip = 'Send to Speckle'
|
||||
cmd.status_bar_text = 'Send to Speckle'
|
||||
cmd.small_icon = '../../img/Sender.png'
|
||||
cmd.large_icon = '../../img/Sender.png'
|
||||
cmd.set_validation_proc { MenuCommandHandler.speckle_started(app) }
|
||||
cmd
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,8 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module SpeckleConnector
|
||||
SPECKLE_ID = 'speckle_id'
|
||||
SPECKLE_TYPE = 'speckle_type'
|
||||
APPLICATION_ID = 'application_id'
|
||||
TOTAL_CHILDREN_COUNT = 'total_children_count'
|
||||
end
|
||||
@@ -1,5 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module SpeckleConnector
|
||||
BASE_OBJECT = 'Base'
|
||||
end
|
||||
@@ -1,22 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module SpeckleConnector
|
||||
module Converters
|
||||
# Helper class to convert geometries between server and Sketchup.
|
||||
class Converter
|
||||
# @return [Sketchup::Model] active sketchup model.
|
||||
attr_reader :sketchup_model
|
||||
|
||||
attr_accessor :units, :definitions, :registry, :entity_observer
|
||||
|
||||
def initialize(sketchup_model)
|
||||
@sketchup_model = sketchup_model
|
||||
su_unit = @sketchup_model.options['UnitsOptions']['LengthUnit']
|
||||
@units = Converters::SKETCHUP_UNITS[su_unit]
|
||||
@definitions = {}
|
||||
# @registry = Sketchup.active_model.attribute_dictionary("speckle_id_registry", true)
|
||||
# @entity_observer = SpeckleEntityObserver.new
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,230 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'converter'
|
||||
require_relative '../speckle_objects/other/transform'
|
||||
require_relative '../speckle_objects/other/render_material'
|
||||
require_relative '../speckle_objects/other/block_definition'
|
||||
require_relative '../speckle_objects/other/block_instance'
|
||||
require_relative '../speckle_objects/geometry/point'
|
||||
require_relative '../speckle_objects/geometry/line'
|
||||
require_relative '../speckle_objects/geometry/mesh'
|
||||
|
||||
module SpeckleConnector
|
||||
module Converters
|
||||
# Converts sketchup entities to speckle objects.
|
||||
class ToNative < Converter
|
||||
# Module aliases
|
||||
GEOMETRY = SpeckleObjects::Geometry
|
||||
OTHER = SpeckleObjects::Other
|
||||
|
||||
# Class aliases
|
||||
POINT = GEOMETRY::Point
|
||||
LINE = GEOMETRY::Line
|
||||
MESH = GEOMETRY::Mesh
|
||||
BLOCK_DEFINITION = OTHER::BlockDefinition
|
||||
BLOCK_INSTANCE = OTHER::BlockInstance
|
||||
|
||||
BASE_OBJECT_PROPS = %w[applicationId id speckle_type totalChildrenCount].freeze
|
||||
CONVERTABLE_SPECKLE_TYPES = %w[
|
||||
Objects.Geometry.Line
|
||||
Objects.Geometry.Polyline
|
||||
Objects.Geometry.Mesh
|
||||
Objects.Geometry.Brep
|
||||
Objects.Other.BlockInstance
|
||||
Objects.Other.BlockDefinition
|
||||
Objects.Other.RenderMaterial
|
||||
].freeze
|
||||
|
||||
def can_convert_to_native(obj)
|
||||
return false unless obj.is_a?(Hash) && obj.key?('speckle_type')
|
||||
|
||||
CONVERTABLE_SPECKLE_TYPES.include?(obj['speckle_type'])
|
||||
end
|
||||
|
||||
def ignored_speckle_type?(obj)
|
||||
['Objects.BuiltElements.Revit.Parameter'].include?(obj['speckle_type'])
|
||||
end
|
||||
|
||||
# @param obj [Object] speckle commit object.
|
||||
def receive_commit_object(obj, model_preferences)
|
||||
# First create layers on the sketchup before starting traversing
|
||||
create_layers(obj.keys.filter_map { |key| key if key.start_with?('@') }, sketchup_model.layers)
|
||||
# Define default commit layer which is the fallback
|
||||
default_commit_layer = sketchup_model.layers.layers.find { |layer| layer.display_name == '@Untagged' }
|
||||
traverse_commit_object(obj, sketchup_model.layers, default_commit_layer, model_preferences)
|
||||
end
|
||||
|
||||
# Create actual Sketchup layers from layer_paths that taken from Speckle base object.
|
||||
# @param layer_paths [Array<String>] layer paths to decompose it to folders and it's layers.
|
||||
# @param folder [Sketchup::Layers, Sketchup::LayerFolder] folder to create folders and layers under it.
|
||||
def create_layers(layer_paths, folder)
|
||||
# Strip leading '@'
|
||||
layers_with_folders = layer_paths.map { |layer| layer[1..-1] }
|
||||
# Split layer_paths according to having parent folder or not.
|
||||
layers_with_head_folder, headless_layers = layers_with_folders.partition { |layer| layer.include?('::') }
|
||||
# Create array of array that split with '::'
|
||||
folder_layer_arrays = layers_with_head_folder.collect { |folder_layer| folder_layer.split('::') }
|
||||
# Add headless layers into `Sketchup.active_model.layers`
|
||||
create_headless_layers(headless_layers, folder)
|
||||
# Create layers that have parent folder(s)- this method is recursive until all tree is created.
|
||||
create_folder_layers(folder_layer_arrays, folder)
|
||||
end
|
||||
|
||||
# @param headless_layers [Array<String>] headless layer names.
|
||||
# @param folder [Sketchup::Layers, Sketchup::LayerFolder] layer folder to create commit layers under it.
|
||||
def create_headless_layers(headless_layers, folder)
|
||||
headless_layers.each do |layer_name|
|
||||
# Add layer first to the layers object of sketchup model.
|
||||
layer = sketchup_model.layers.add(layer_name)
|
||||
folder.add_layer(layer) unless folder.layers.any? { |l| l.display_name == layer_name }
|
||||
end
|
||||
end
|
||||
|
||||
# Create layers with it's parent folders.
|
||||
# @param folder [Sketchup::LayerFolder] layer folder to create commit layers under it.
|
||||
def create_folder_layers(folder_layer_arrays, folder)
|
||||
folder_layer_arrays.each do |folder_layer_array|
|
||||
create_folder_layer(folder_layer_array, folder)
|
||||
end
|
||||
end
|
||||
|
||||
# Create layers that have parent folder(s)- this method is recursive (self-caller) until all tree is created.
|
||||
def create_folder_layer(folder_array, folder)
|
||||
if folder_array.length > 1
|
||||
# add folder if it is not exist.
|
||||
folder.add_folder(folder_array[0]) unless folder.folders.any? { |f| f.display_name == folder_array[0] }
|
||||
new_folder = folder.folders.find { |f| f.display_name == folder_array[0] }
|
||||
create_folder_layer(folder_array[1..-1], new_folder)
|
||||
else
|
||||
# Add layer first to the layers object of sketchup model.
|
||||
layer = sketchup_model.layers.add(folder_array[0])
|
||||
folder.add_layer(layer) unless folder.layers.any? { |l| l.display_name == layer }
|
||||
end
|
||||
end
|
||||
|
||||
# Traversal method to create Sketchup objects from upcoming base object.
|
||||
# @param obj [Hash, Array] object might be source base object or it's sub objects, because this method is a
|
||||
# self-caller method means that call itself according to conditions inside of it.
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
# rubocop:disable Metrics/PerceivedComplexity
|
||||
def traverse_commit_object(obj, commit_folder, layer, model_preferences)
|
||||
if can_convert_to_native(obj)
|
||||
convert_to_native(obj, layer, model_preferences)
|
||||
elsif obj.is_a?(Hash) && obj.key?('speckle_type')
|
||||
return if ignored_speckle_type?(obj)
|
||||
|
||||
if obj['displayValue'].nil?
|
||||
# puts(">>> Found #{obj['speckle_type']}: #{obj['id']}. Continuing traversal.")
|
||||
props = obj.keys.filter_map { |key| key unless key.start_with?('_') }
|
||||
props.each do |prop|
|
||||
layer_path = prop if prop.start_with?('@') && obj[prop].is_a?(Array)
|
||||
layer = find_layer(layer_path, commit_folder, layer)
|
||||
traverse_commit_object(obj[prop], commit_folder, layer, model_preferences)
|
||||
end
|
||||
else
|
||||
# puts(">>> Found #{obj['speckle_type']}: #{obj['id']} with displayValue.")
|
||||
convert_to_native(obj, layer, model_preferences)
|
||||
end
|
||||
elsif obj.is_a?(Hash)
|
||||
obj.each_value { |value| traverse_commit_object(value, commit_folder, layer, model_preferences) }
|
||||
elsif obj.is_a?(Array)
|
||||
obj.each { |value| traverse_commit_object(value, commit_folder, layer, model_preferences) }
|
||||
end
|
||||
end
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
# rubocop:enable Metrics/PerceivedComplexity
|
||||
|
||||
# Find layer of the Speckle object by checking iteratively into folder.
|
||||
# @param layer_path [String] complete layer_path to retrieve
|
||||
# @param folder [Sketchup::LayerFolder, Sketchup::Layers] entry folder to search layer
|
||||
# @param fallback_layer [Sketchup::Layer] fallback layer to assign object later if any error occur.
|
||||
# @return [Sketchup::Layer] layer according to path
|
||||
# @example
|
||||
# "@folder_1::folder_2::layer_1"
|
||||
# # it will return the layer object which has display name as `layer_1`.
|
||||
def find_layer(layer_path, folder, fallback_layer)
|
||||
begin
|
||||
# Split folders and it's tail layer (last one is layer, others are folders.)
|
||||
layer_path_array = layer_path[1..-1].split('::')
|
||||
# Get sub folders as array, might be empty if `layer_path_array` has only 1 entry
|
||||
sub_folders = layer_path_array.length > 1 ? layer_path_array[0..-2] : []
|
||||
# Get exact layer name from last entry
|
||||
layer_name = layer_path_array.last
|
||||
# Iterate sub folders to find new sub folder to switch it.
|
||||
# It help to search in the tree by switching the target search folder.
|
||||
# Finally we can reach the layer name.
|
||||
sub_folders.each do |sub_folder|
|
||||
# Try to find sub folder into source folder passes by argument
|
||||
s_f = folder.folders.find { |f| f.display_name == sub_folder }
|
||||
# Switch source folder if any exist
|
||||
folder = s_f unless s_f.nil?
|
||||
end
|
||||
# Find finally the layer into related folder
|
||||
folder.layers.find { |l| l.display_name == layer_name }
|
||||
rescue StandardError
|
||||
return fallback_layer
|
||||
end
|
||||
end
|
||||
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
# rubocop:disable Metrics/MethodLength
|
||||
def convert_to_native(obj, layer, model_preferences, entities = sketchup_model.entities)
|
||||
convert = method(:convert_to_native)
|
||||
unless obj['displayValue'].nil?
|
||||
return display_value_to_native_component(obj, layer, entities, model_preferences, &convert)
|
||||
end
|
||||
|
||||
case obj['speckle_type']
|
||||
when 'Objects.Geometry.Line', 'Objects.Geometry.Polyline' then LINE.to_native(obj, layer, entities)
|
||||
when 'Objects.Other.BlockInstance' then BLOCK_INSTANCE.to_native(sketchup_model, obj, layer, entities,
|
||||
model_preferences, &convert)
|
||||
when 'Objects.Other.BlockDefinition' then BLOCK_DEFINITION.to_native(sketchup_model, obj, layer,
|
||||
obj['name'],
|
||||
obj['always_face_camera'],
|
||||
model_preferences,
|
||||
obj['sketchup_attributes'],
|
||||
obj['applicationId'],
|
||||
&convert)
|
||||
when 'Objects.Geometry.Mesh' then MESH.to_native(sketchup_model, obj, layer, entities, model_preferences)
|
||||
when 'Objects.Geometry.Brep' then MESH.to_native(sketchup_model, obj['displayValue'], layer, entities,
|
||||
model_preferences)
|
||||
end
|
||||
rescue StandardError => e
|
||||
puts("Failed to convert #{obj['speckle_type']} (id: #{obj['id']})")
|
||||
puts(e)
|
||||
nil
|
||||
end
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
# rubocop:enable Metrics/MethodLength
|
||||
|
||||
# Creates a component definition and instance from a speckle object with a display value
|
||||
def display_value_to_native_component(obj, layer, entities, model_preferences, &convert)
|
||||
obj_id = obj['applicationId'].to_s.empty? ? obj['id'] : obj['applicationId']
|
||||
definition = BLOCK_DEFINITION.to_native(
|
||||
sketchup_model,
|
||||
obj['displayValue'],
|
||||
layer,
|
||||
"def::#{obj_id}",
|
||||
obj['@blockDefinition']['always_face_camera'],
|
||||
model_preferences,
|
||||
obj['@blockDefinition']['sketchup_attributes'],
|
||||
obj_id,
|
||||
&convert
|
||||
)
|
||||
|
||||
find_and_erase_existing_instance(definition, obj_id)
|
||||
t_arr = obj['transform']
|
||||
transform = t_arr.nil? ? Geom::Transformation.new : OTHER::Transform.to_native(t_arr, units)
|
||||
instance = entities.add_instance(definition, transform)
|
||||
instance.name = obj_id
|
||||
instance
|
||||
end
|
||||
|
||||
# Takes a component definition and finds and erases the first instance with the matching name
|
||||
# (and optionally the applicationId)
|
||||
def find_and_erase_existing_instance(definition, name, app_id = '')
|
||||
definition.instances.find { |ins| ins.name == name || ins.guid == app_id }&.erase!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,138 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'converter'
|
||||
require_relative 'base_object_serializer'
|
||||
require_relative '../speckle_objects/base'
|
||||
require_relative '../speckle_objects/geometry/line'
|
||||
require_relative '../speckle_objects/geometry/mesh'
|
||||
require_relative '../speckle_objects/other/block_instance'
|
||||
require_relative '../speckle_objects/other/block_definition'
|
||||
|
||||
module SpeckleConnector
|
||||
module Converters
|
||||
# Converts sketchup entities to speckle objects.
|
||||
class ToSpeckle < Converter
|
||||
# @return [Hash{Symbol=>Array}] layers to hold it's objects under the base object.
|
||||
attr_reader :layers
|
||||
|
||||
def initialize(sketchup_model)
|
||||
super(sketchup_model)
|
||||
@layers = add_all_layers
|
||||
end
|
||||
|
||||
# Convert selected objects by putting them into related array that grouped by layer.
|
||||
# @return [Hash{Symbol=>Array}] layers -which only have objects- to hold it's objects under the base object.
|
||||
def convert_selection_to_base(preferences)
|
||||
sketchup_model.selection.each do |entity|
|
||||
converted_object = convert(entity, preferences)
|
||||
layer_name = entity_layer_path(entity)
|
||||
layers[layer_name].push(converted_object)
|
||||
end
|
||||
# send only layers that have any object
|
||||
base_object_properties = layers.reject { |_layer_name, objects| objects.empty? }
|
||||
SpeckleObjects::Base.with_detached_layers(base_object_properties)
|
||||
end
|
||||
|
||||
# Serialized and traversed information to send batches.
|
||||
# @param base [SpeckleObjects::Base] base object to serialize.
|
||||
# @return [String, Integer, Array<Object>] base id, total_children_count of base and batches
|
||||
def send_info(base)
|
||||
serializer = SpeckleConnector::Converters::BaseObjectSerializer.new
|
||||
# t = Time.now.to_f
|
||||
id, _traversed = serializer.serialize(base)
|
||||
# puts "Generating traversed object elapsed #{Time.now.to_f - t} s"
|
||||
base_total_children_count = serializer.total_children_count(id)
|
||||
return id, base_total_children_count, serializer.batch_objects
|
||||
end
|
||||
|
||||
# @param entity [Sketchup::Entity] sketchup entity to convert Speckle.
|
||||
def convert(entity, preferences)
|
||||
convert = method(:convert)
|
||||
if entity.is_a?(Sketchup::Edge)
|
||||
return SpeckleObjects::Geometry::Line.from_edge(entity, @units, preferences[:model]).to_h
|
||||
end
|
||||
|
||||
if entity.is_a?(Sketchup::Face)
|
||||
return SpeckleObjects::Geometry::Mesh.from_face(entity, @units, preferences[:model])
|
||||
end
|
||||
|
||||
if entity.is_a?(Sketchup::Group)
|
||||
return SpeckleObjects::Other::BlockInstance.from_group(entity, @units, @definitions, preferences, &convert)
|
||||
end
|
||||
|
||||
if entity.is_a?(Sketchup::ComponentInstance)
|
||||
return SpeckleObjects::Other::BlockInstance.from_component_instance(entity, @units, @definitions,
|
||||
preferences, &convert)
|
||||
end
|
||||
if entity.is_a?(Sketchup::ComponentDefinition)
|
||||
return SpeckleObjects::Other::BlockDefinition.from_definition(entity, @units, @definitions, preferences,
|
||||
&convert)
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
# Create layers -> {Hash{Symbol=>Array}} from sketchup model with empty array as hash entry values.
|
||||
# This method add first headless layers (not belong to any folder),
|
||||
# then goes through each folder, their sub-folders and their layers.
|
||||
# @return [Hash{Symbol=>Array}] layers from sketchup model with empty array as hash entry values.
|
||||
def add_all_layers
|
||||
# add headless layers
|
||||
layer_objects = add_layers(sketchup_model.layers.layers)
|
||||
# add layers from folders
|
||||
add_layers_from_folders(sketchup_model.layers.folders, layer_objects)
|
||||
layer_objects
|
||||
end
|
||||
|
||||
# @param layers [Array<Sketchup::Layer>] layers in sketchup model
|
||||
# @return [Hash{Symbol=>Array}] layers with empty array value.
|
||||
def add_layers(layers, layer_objects = {}, parent_name = '')
|
||||
layers.each do |layer|
|
||||
layer_name = parent_name.empty? ? "@#{layer.display_name}" : "#{parent_name}::#{layer.display_name}"
|
||||
layer_objects[layer_name] = []
|
||||
end
|
||||
layer_objects
|
||||
end
|
||||
|
||||
# @param folders [Array<Sketchup::LayerFolder>] layer folders in sketchup model.
|
||||
# @param layer_objects [Hash{Symbol=>Array}] layer objects to fill in.
|
||||
# @param parent_name [String] parent folder name to structure layer path before send to Speckle.
|
||||
# ex: "@#{parent_name}::#{layer_name}"
|
||||
def add_layers_from_folders(folders, layer_objects, parent_name = '')
|
||||
folders.each do |folder|
|
||||
folder_name = parent_name.empty? ? "@#{folder.display_name}" : "#{parent_name}::#{folder.display_name}"
|
||||
add_layers(folder.layers, layer_objects, folder_name)
|
||||
add_layers_from_folders(folder.folders, layer_objects, folder_name) unless folder.folders.empty?
|
||||
end
|
||||
end
|
||||
|
||||
# Find layer path of given Sketchup entity.
|
||||
# @param entity [Sketchup::Entity] entity to find root layer.
|
||||
# @return [String] layer path of Sketchup entity.
|
||||
def entity_layer_path(entity)
|
||||
layer_name = entity.layer.display_name
|
||||
if entity.layer.folder.nil?
|
||||
"@#{layer_name}"
|
||||
else
|
||||
folders = folder_name(entity.layer.folder)
|
||||
path = ''
|
||||
folders.reverse.each do |folder|
|
||||
path += "#{folder}::"
|
||||
end
|
||||
"@#{path}#{layer_name}"
|
||||
end
|
||||
end
|
||||
|
||||
# Nested method to retrieve sub-folders until nothing found.
|
||||
# @return [Array<String>] folder names as list from bottom to top. Might need to be reversed if you want to see
|
||||
# from top to bottom.
|
||||
def folder_name(folder, folders = [])
|
||||
if folder.folder.nil?
|
||||
folders.push(folder.display_name)
|
||||
else
|
||||
folder_name(folder.folder, folders.push(folder.display_name))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,28 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module SpeckleConnector
|
||||
module Observers
|
||||
# Entities observer.
|
||||
class EntitiesObserver < Sketchup::EntitiesObserver
|
||||
attr_accessor :registry
|
||||
|
||||
def initialize
|
||||
super()
|
||||
@registry = Sketchup.active_model.attribute_dictionary('speckle_id_registry', true)
|
||||
end
|
||||
|
||||
# rubocop:disable Naming/MethodName
|
||||
def onEraseEntity(entity)
|
||||
app_id = entity.get_attribute('speckle', 'applicationId')
|
||||
return if app_id.nil?
|
||||
|
||||
p(app_id)
|
||||
|
||||
@registry.delete_key(app_id)
|
||||
|
||||
p(@registry)
|
||||
end
|
||||
# rubocop:enable Naming/MethodName
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,69 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../ext/sqlite3'
|
||||
require_relative '../immutable/immutable'
|
||||
require_relative '../constants/path_constants'
|
||||
require_relative '../sketchup_model/dictionary/speckle_model_dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
# Preferences that stored on config database and sketchup_model.
|
||||
module Preferences
|
||||
include Immutable::ImmutableUtils
|
||||
DICT_HANDLER = SketchupModel::Dictionary::SpeckleModelDictionaryHandler
|
||||
|
||||
# @param sketchup_model [Sketchup::Model] active model.
|
||||
# rubocop:disable Metrics/MethodLength
|
||||
def self.init_preferences(sketchup_model)
|
||||
# Init sqlite database
|
||||
db = Sqlite3::Database.new(SPECKLE_CONFIG_DB_PATH)
|
||||
|
||||
# Select data
|
||||
data = db.exec("SELECT content FROM 'objects' WHERE hash = 'configDUI'").first.first
|
||||
|
||||
# Parse string to hash
|
||||
data_hash = JSON.parse(data).to_h
|
||||
|
||||
# Get current theme value
|
||||
dark_theme = data_hash['DarkTheme']
|
||||
|
||||
speckle_dictionary = sketchup_model.attribute_dictionary('Speckle')
|
||||
|
||||
if speckle_dictionary
|
||||
Immutable::Hash.new(
|
||||
{
|
||||
user: {
|
||||
dark_theme: dark_theme
|
||||
},
|
||||
model: {
|
||||
combine_faces_by_material: DICT_HANDLER.get_attribute(sketchup_model,
|
||||
:combine_faces_by_material, 'Speckle'),
|
||||
include_entity_attributes: DICT_HANDLER.get_attribute(sketchup_model,
|
||||
:include_entity_attributes, 'Speckle'),
|
||||
merge_coplanar_faces: DICT_HANDLER.get_attribute(sketchup_model,
|
||||
:merge_coplanar_faces, 'Speckle')
|
||||
}
|
||||
}
|
||||
)
|
||||
else
|
||||
DICT_HANDLER.write_initial_model_data(sketchup_model, default_model_preferences)
|
||||
Immutable::Hash.new(
|
||||
{
|
||||
user: {
|
||||
dark_theme: dark_theme
|
||||
},
|
||||
model: default_model_preferences
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
# rubocop:enable Metrics/MethodLength
|
||||
|
||||
def self.default_model_preferences
|
||||
{
|
||||
combine_faces_by_material: true,
|
||||
include_entity_attributes: true,
|
||||
merge_coplanar_faces: true
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,27 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'dictionary_handler'
|
||||
require_relative '../../constants/dict_constants'
|
||||
require_relative '../../constants/type_constants'
|
||||
|
||||
module SpeckleConnector
|
||||
module SketchupModel
|
||||
module Dictionary
|
||||
# Dictionary handler of the speckle entity.
|
||||
class SpeckleEntityDictionaryHandler < DictionaryHandler
|
||||
# Writes initial data while speckle entity is creating first time.
|
||||
# @param sketchup_entity [Sketchup::Entity] Sketchup entity to write data into it's attribute dictionary.
|
||||
def self.write_initial_base_data(sketchup_entity)
|
||||
initial_dict_data = {
|
||||
# Add here more if you want to write here initial data
|
||||
SPECKLE_ID => '',
|
||||
SPECKLE_TYPE => BASE_OBJECT,
|
||||
APPLICATION_ID => '',
|
||||
TOTAL_CHILDREN_COUNT => 0
|
||||
}
|
||||
set_hash(sketchup_entity, initial_dict_data)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,38 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../immutable/immutable'
|
||||
require_relative '../convertors/units'
|
||||
require_relative '../speckle_objects/base'
|
||||
require_relative '../speckle_entities/speckle_line_entity'
|
||||
require_relative '../sketchup_model/dictionary/speckle_entity_dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleEntities
|
||||
# Speckle base entity is the state object for Sketchup::Entity and it's converted (or not yet) state.
|
||||
class SpeckleBaseEntity
|
||||
include Immutable::ImmutableUtils
|
||||
# @return [Sketchup::Entity] sketchup entity represents {SpeckleEntity} on the model.
|
||||
attr_reader :sketchup_entity
|
||||
|
||||
# @return [SpeckleObjects::Base] speckle object that represented on server.
|
||||
attr_reader :speckle_object
|
||||
|
||||
# @return [Integer] application id of the sketchup entity.
|
||||
attr_reader :application_id
|
||||
|
||||
# @param sketchup_entity [Sketchup::Entity] sketchup entity represents {SpeckleEntity} on the model.
|
||||
def initialize(sketchup_model, sketchup_entity)
|
||||
@sketchup_entity = sketchup_entity
|
||||
@application_id = @sketchup_entity.persistent_id
|
||||
@speckle_object = SpeckleObjects::Base.new
|
||||
su_unit = sketchup_model.options['UnitsOptions']['LengthUnit']
|
||||
@units = Converters::SKETCHUP_UNITS[su_unit]
|
||||
SketchupModel::Dictionary::SpeckleEntityDictionaryHandler.write_initial_base_data(@sketchup_entity)
|
||||
end
|
||||
|
||||
def valid?
|
||||
sketchup_entity.valid?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,20 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../speckle_entities/speckle_line_entity'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleEntities
|
||||
# Speckle entity is the state object for Sketchup::Entity and it's converted (or not yet) state.
|
||||
module SpeckleEntity
|
||||
def self.with_converted(skp_model, skp_entity)
|
||||
# return the same object if it is already SpeckleEntity
|
||||
return skp_entity if skp_entity.is_a?(SpeckleEntity)
|
||||
return SpeckleBlockEntity.new(skp_model, skp_entity) if skp_entity.is_a?(Sketchup::Group)
|
||||
return SpeckleBlockEntity.new(skp_model, skp_entity) if skp_entity.is_a?(Sketchup::ComponentInstance)
|
||||
return SpeckleMeshEntity.new(skp_model, skp_entity) if skp_entity.is_a?(Sketchup::Face)
|
||||
|
||||
SpeckleLineEntity.new(skp_model, skp_entity) if skp_entity.is_a?(Sketchup::Edge)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,25 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'speckle_base_entity'
|
||||
require_relative '../immutable/immutable'
|
||||
require_relative '../speckle_objects/geometry/line'
|
||||
require_relative '../sketchup_model/dictionary/speckle_entity_dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleEntities
|
||||
# Speckle line entity is the state object for Sketchup::Entity and it's converted (or not yet) state.
|
||||
class SpeckleLineEntity < SpeckleBaseEntity
|
||||
include Immutable::ImmutableUtils
|
||||
|
||||
# @return [SpeckleObjects::Geometry::Line] speckle line object
|
||||
attr_reader :speckle_object
|
||||
|
||||
def initialize(sketchup_model, sketchup_edge)
|
||||
super(sketchup_model, sketchup_edge)
|
||||
@speckle_object = SpeckleObjects::Geometry::Line.from_edge(sketchup_edge, units)
|
||||
end
|
||||
|
||||
alias sketchup_edge sketchup_entity
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,18 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../convertors/units'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
# Geometric objects to convert speckle.
|
||||
module Geometry
|
||||
def self.length_to_speckle(length, units)
|
||||
length.__send__("to_#{SpeckleConnector::Converters::SKETCHUP_UNIT_STRINGS[units]}")
|
||||
end
|
||||
|
||||
def self.length_to_native(length, units)
|
||||
length.__send__(SpeckleConnector::Converters::SKETCHUP_UNIT_STRINGS[units])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,102 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'length'
|
||||
require_relative 'point'
|
||||
require_relative 'bounding_box'
|
||||
require_relative '../base'
|
||||
require_relative '../primitive/interval'
|
||||
require_relative '../../sketchup_model/dictionary/dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module Geometry
|
||||
# Line object definition for Speckle.
|
||||
class Line < Base
|
||||
SPECKLE_TYPE = 'Objects.Geometry.Line'
|
||||
|
||||
# @param start_pt [Geometry::Point] start point speckle object of the speckle line.
|
||||
# @param end_pt [Geometry::Point] end point speckle object of the speckle line.
|
||||
# @param domain [Primitive::Interval] interval speckle object of the speckle line -represents domain.
|
||||
# @param bbox [Geometry::BoundingBox] bounding box speckle object of the speckle line.
|
||||
# @param units [String] units of the speckle line.
|
||||
# @param application_id [String, nil] entity id of the {Sketchup::Edge} that represents to the speckle line.
|
||||
# rubocop:disable Metrics/ParameterLists
|
||||
def initialize(start_pt:, end_pt:, domain:, bbox:, units:, sketchup_attributes: {}, application_id: nil)
|
||||
super(
|
||||
speckle_type: 'Objects.Geometry.Line',
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: nil
|
||||
)
|
||||
self[:start] = start_pt
|
||||
self[:end] = end_pt
|
||||
self[:domain] = domain
|
||||
self[:bbox] = bbox
|
||||
self[:units] = units
|
||||
self[:sketchup_attributes] = sketchup_attributes if sketchup_attributes.any?
|
||||
end
|
||||
# rubocop:enable Metrics/ParameterLists
|
||||
|
||||
# @param edge [Sketchup::Edge] edge to convert line.
|
||||
def self.from_edge(edge, units, model_preferences)
|
||||
dictionaries = {}
|
||||
if model_preferences[:include_entity_attributes]
|
||||
dictionaries = SketchupModel::Dictionary::DictionaryHandler.attribute_dictionaries_to_speckle(edge)
|
||||
end
|
||||
att = dictionaries.any? ? { dictionaries: dictionaries } : {}
|
||||
start_pt = Geometry::Point.from_vertex(edge.start.position, units)
|
||||
end_pt = Geometry::Point.from_vertex(edge.end.position, units)
|
||||
domain = Primitive::Interval.from_numeric(0, Float(edge.length), units)
|
||||
bbox = Geometry::BoundingBox.from_bounds(edge.bounds, units)
|
||||
Line.new(
|
||||
start_pt: start_pt,
|
||||
end_pt: end_pt,
|
||||
domain: domain,
|
||||
bbox: bbox,
|
||||
units: units,
|
||||
sketchup_attributes: att,
|
||||
application_id: edge.persistent_id.to_s
|
||||
)
|
||||
end
|
||||
|
||||
# @param line [Object] object represents Speckle line.
|
||||
# @param layer [Sketchup::Layer] layer to add {Sketchup::Edge} into it.
|
||||
# @param entities [Sketchup::Entities] entities collection to add {Sketchup::Edge} into it.
|
||||
# rubocop:disable Metrics/AbcSize
|
||||
def self.to_native(line, layer, entities)
|
||||
if line.key?('value')
|
||||
values = line['value']
|
||||
points = values.each_slice(3).to_a.map { |pt| Point.to_native(pt[0], pt[1], pt[2], line['units']) }
|
||||
points.push(points[0]) if line['closed']
|
||||
edges = entities.add_edges(*points)
|
||||
else
|
||||
start_pt = Point.to_native(line['start']['x'], line['start']['y'], line['start']['z'], line['units'])
|
||||
end_pt = Point.to_native(line['end']['x'], line['end']['y'], line['end']['z'], line['units'])
|
||||
edges = entities.add_edges(start_pt, end_pt)
|
||||
end
|
||||
edges.each do |edge|
|
||||
edge.layer = layer
|
||||
unless line['sketchup_attributes'].nil?
|
||||
SketchupModel::Dictionary::DictionaryHandler
|
||||
.attribute_dictionaries_to_native(edge, line['sketchup_attributes']['dictionaries'])
|
||||
end
|
||||
end
|
||||
end
|
||||
# rubocop:enable Metrics/AbcSize
|
||||
|
||||
def self.test_line(start_point, end_point, units)
|
||||
domain = Primitive::Interval.from_numeric(0, 5, units)
|
||||
bbox = Geometry::BoundingBox.test_bounds(units)
|
||||
Line.new(
|
||||
start_pt: start_point,
|
||||
end_pt: end_point,
|
||||
domain: domain,
|
||||
bbox: bbox,
|
||||
application_id: '',
|
||||
units: units
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,183 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../base'
|
||||
require_relative '../geometry/bounding_box'
|
||||
require_relative '../other/render_material'
|
||||
require_relative '../../convertors/clean_up'
|
||||
require_relative '../../sketchup_model/dictionary/dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
# Geometry objects in the Speckleverse.
|
||||
module Geometry
|
||||
# Mesh object definition for Speckle.
|
||||
class Mesh < Base
|
||||
SPECKLE_TYPE = 'Objects.Geometry.Mesh'
|
||||
|
||||
# @param units [String] units of the speckle mesh.
|
||||
# @param render_material [Other::RenderMaterial, nil] render material of the speckle mesh.
|
||||
# @param bbox [Geometry::BoundingBox] bounding box speckle object of the speckle mesh.
|
||||
# @param vertices [Array] vertices of the speckle mesh.
|
||||
# @param faces [Array] faces of the speckle mesh.
|
||||
# @param face_edge_flags [Array] face edge flags of the speckle mesh.
|
||||
# @param sketchup_attributes [Hash] additional information about speckle mesh.
|
||||
# rubocop:disable Metrics/ParameterLists
|
||||
def initialize(units:, render_material:, bbox:, vertices:, faces:, face_edge_flags:, sketchup_attributes:)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: nil,
|
||||
id: nil
|
||||
)
|
||||
self[:units] = units
|
||||
self[:renderMaterial] = render_material
|
||||
self[:bbox] = bbox
|
||||
self[:'@(31250)vertices'] = vertices
|
||||
self[:'@(62500)faces'] = faces
|
||||
self[:'@(31250)faceEdgeFlags'] = face_edge_flags
|
||||
self[:sketchup_attributes] = sketchup_attributes if sketchup_attributes.any?
|
||||
end
|
||||
# rubocop:enable Metrics/ParameterLists
|
||||
|
||||
# @param entities [Sketchup::Entities] entities to add
|
||||
# rubocop:disable Metrics/MethodLength
|
||||
# rubocop:disable Metrics/AbcSize
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
def self.to_native(sketchup_model, mesh, layer, entities, model_preferences)
|
||||
# Get soft? flag of {Sketchup::Edge} object to understand smoothness of edge.
|
||||
is_soften = get_soften_setting(mesh)
|
||||
smooth_flags = is_soften ? 4 : 1
|
||||
# Get native points to add polygon into native mesh.
|
||||
points = get_native_points(mesh)
|
||||
# Initialize native PolygonMesh object later to add polygon inside it.
|
||||
native_mesh = Geom::PolygonMesh.new(mesh['vertices'].count / 3)
|
||||
faces = mesh['faces']
|
||||
while faces.count > 0
|
||||
num_pts = faces.shift
|
||||
# 0 -> 3, 1 -> 4 to preserve backwards compatibility
|
||||
num_pts += 3 if num_pts < 3
|
||||
indices = faces.shift(num_pts)
|
||||
native_mesh.add_polygon(indices.map { |index| points[index] })
|
||||
end
|
||||
material = Other::RenderMaterial.to_native(sketchup_model, mesh['renderMaterial'])
|
||||
entities.add_faces_from_mesh(native_mesh, smooth_flags, material)
|
||||
added_faces = entities.grep(Sketchup::Face).last(native_mesh.polygons.length)
|
||||
added_faces.each do |face|
|
||||
face.layer = layer
|
||||
unless mesh['sketchup_attributes'].nil?
|
||||
SketchupModel::Dictionary::DictionaryHandler
|
||||
.attribute_dictionaries_to_native(face, mesh['sketchup_attributes']['dictionaries'])
|
||||
end
|
||||
end
|
||||
# Merge only added faces in this scope
|
||||
Converters::CleanUp.merge_coplanar_faces(added_faces) if model_preferences[:merge_coplanar_faces]
|
||||
native_mesh
|
||||
end
|
||||
# rubocop:enable Metrics/MethodLength
|
||||
# rubocop:enable Metrics/AbcSize
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
|
||||
# @param face [Sketchup::Face] face to convert mesh
|
||||
# rubocop:disable Style/MultilineTernaryOperator
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
# rubocop:disable Metrics/PerceivedComplexity
|
||||
def self.from_face(face, units, model_preferences)
|
||||
dictionaries = {}
|
||||
if model_preferences[:include_entity_attributes]
|
||||
dictionaries = SketchupModel::Dictionary::DictionaryHandler.attribute_dictionaries_to_speckle(face)
|
||||
end
|
||||
mesh = face.loops.count > 1 ? face.mesh : nil
|
||||
has_any_soften_edge = face.edges.any?(&:soft?)
|
||||
att = dictionaries.any? ? { is_soften: has_any_soften_edge, dictionaries: dictionaries }
|
||||
: { is_soften: has_any_soften_edge }
|
||||
Mesh.new(
|
||||
units: units,
|
||||
render_material: face.material.nil? && face.back_material.nil? ? nil : Other::RenderMaterial
|
||||
.from_material(face.material || face.back_material),
|
||||
bbox: Geometry::BoundingBox.from_bounds(face.bounds, units),
|
||||
vertices: mesh.nil? ? face_vertices_to_array(face, units) : mesh_points_to_array(mesh, units),
|
||||
faces: mesh.nil? ? face_indices_to_array(face, 0) : mesh_faces_to_array(mesh, -1),
|
||||
face_edge_flags: mesh.nil? ? face_edge_flags_to_array(face) : mesh_edge_flags_to_array(mesh),
|
||||
sketchup_attributes: att
|
||||
)
|
||||
end
|
||||
# rubocop:enable Style/MultilineTernaryOperator
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
# rubocop:enable Metrics/PerceivedComplexity
|
||||
|
||||
# get a flat array of vertices from a list of sketchup vertices
|
||||
def self.face_vertices_to_array(face, units)
|
||||
pts_array = []
|
||||
face.vertices.each do |v|
|
||||
pt = v.position
|
||||
pts_array.push(Geometry.length_to_speckle(pt[0], units),
|
||||
Geometry.length_to_speckle(pt[1], units),
|
||||
Geometry.length_to_speckle(pt[2], units))
|
||||
end
|
||||
pts_array
|
||||
end
|
||||
|
||||
# get a flat array of vertices from a sketchup polygon mesh
|
||||
def self.mesh_points_to_array(mesh, units)
|
||||
pts_array = []
|
||||
mesh.points.each do |pt|
|
||||
pts_array.push(
|
||||
Geometry.length_to_speckle(pt[0], units),
|
||||
Geometry.length_to_speckle(pt[1], units),
|
||||
Geometry.length_to_speckle(pt[2], units)
|
||||
)
|
||||
end
|
||||
pts_array
|
||||
end
|
||||
|
||||
# get a flat array of face indices from a sketchup face
|
||||
def self.face_indices_to_array(face, offset)
|
||||
face_array = [face.vertices.count]
|
||||
face_array.push(*face.vertices.count.times.map { |index| index + offset })
|
||||
face_array
|
||||
end
|
||||
|
||||
# get an array of face indices from a sketchup polygon mesh
|
||||
def self.mesh_faces_to_array(mesh, offset = 0)
|
||||
faces = []
|
||||
mesh.polygons.each do |poly|
|
||||
faces.push(
|
||||
poly.count, *poly.map { |index| index.abs + offset }
|
||||
)
|
||||
end
|
||||
faces
|
||||
end
|
||||
|
||||
def self.face_edge_flags_to_array(face)
|
||||
face.outer_loop.edges.map(&:soft?)
|
||||
end
|
||||
|
||||
def self.mesh_edge_flags_to_array(mesh)
|
||||
edge_flags = []
|
||||
mesh.polygons.each do |poly|
|
||||
edge_flags.push(
|
||||
*poly.map(&:negative?)
|
||||
)
|
||||
end
|
||||
edge_flags
|
||||
end
|
||||
|
||||
def self.get_soften_setting(mesh)
|
||||
if mesh['sketchup_attributes'].nil?
|
||||
true
|
||||
else
|
||||
mesh['sketchup_attributes']['is_soften'].nil? ? true : mesh['sketchup_attributes']['is_soften']
|
||||
end
|
||||
end
|
||||
|
||||
def self.get_native_points(mesh)
|
||||
points = []
|
||||
mesh['vertices'].each_slice(3) do |pt|
|
||||
points.push(Point.to_native(pt[0], pt[1], pt[2], mesh['units']))
|
||||
end
|
||||
points
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,200 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'render_material'
|
||||
require_relative 'transform'
|
||||
require_relative 'block_instance'
|
||||
require_relative '../base'
|
||||
require_relative '../geometry/point'
|
||||
require_relative '../geometry/mesh'
|
||||
require_relative '../geometry/bounding_box'
|
||||
require_relative '../../sketchup_model/dictionary/dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module Other
|
||||
# BlockDefinition object definition for Speckle.
|
||||
class BlockDefinition < Base
|
||||
SPECKLE_TYPE = 'Objects.Other.BlockDefinition'
|
||||
|
||||
# @param geometry [Object] geometric definition of the block.
|
||||
# @param name [String] name of the block definition.
|
||||
# @param units [String] units of the block definition.
|
||||
# @param application_id [String, NilClass] application id of the block definition.
|
||||
# rubocop:disable Metrics/ParameterLists
|
||||
def initialize(geometry:, name:, units:, always_face_camera:, sketchup_attributes: {}, application_id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: nil
|
||||
)
|
||||
self[:units] = units
|
||||
self[:name] = name
|
||||
self[:always_face_camera] = always_face_camera
|
||||
self[:sketchup_attributes] = sketchup_attributes if sketchup_attributes.any?
|
||||
self['@geometry'] = geometry
|
||||
end
|
||||
# rubocop:enable Metrics/ParameterLists
|
||||
|
||||
# @param definition [Sketchup::ComponentDefinition] component definition might be belong to group or component
|
||||
# instance
|
||||
# @param units [String] units of the Sketchup model
|
||||
# @param definitions [Hash{String=>BlockDefinition}] all converted {BlockDefinition}s on the converter.
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
# rubocop:disable Metrics/PerceivedComplexity
|
||||
# rubocop:disable Metrics/MethodLength
|
||||
def self.from_definition(definition, units, definitions, preferences, &convert)
|
||||
guid = definition.guid
|
||||
return definitions[guid] if definitions.key?(guid)
|
||||
|
||||
dictionaries = {}
|
||||
if preferences[:model][:include_entity_attributes]
|
||||
dictionaries = SketchupModel::Dictionary::DictionaryHandler.attribute_dictionaries_to_speckle(definition)
|
||||
end
|
||||
att = dictionaries.any? ? { dictionaries: dictionaries } : {}
|
||||
|
||||
# TODO: Solve logic
|
||||
geometry = if definition.entities[0].is_a?(Sketchup::Edge) || definition.entities[0].is_a?(Sketchup::Face)
|
||||
group_entities_to_speckle(definition, units, definitions, preferences, &convert)
|
||||
else
|
||||
definition.entities.map do |entity|
|
||||
convert.call(entity, preferences) unless entity.is_a?(Sketchup::Edge) && entity.faces.any?
|
||||
end
|
||||
end
|
||||
|
||||
# FIXME: Decide how to approach base point of the definition instead origin.
|
||||
BlockDefinition.new(
|
||||
units: units,
|
||||
name: definition.name,
|
||||
geometry: geometry,
|
||||
always_face_camera: definition.behavior.always_face_camera?,
|
||||
sketchup_attributes: att,
|
||||
application_id: guid
|
||||
)
|
||||
end
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
# rubocop:enable Metrics/PerceivedComplexity
|
||||
# rubocop:enable Metrics/MethodLength
|
||||
|
||||
# Finds or creates a component definition from the geometry and the given name
|
||||
# @param sketchup_model [Sketchup::Model] sketchup model to check block definitions.
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
# rubocop:disable Metrics/PerceivedComplexity
|
||||
# rubocop:disable Metrics/ParameterLists
|
||||
def self.to_native(sketchup_model, geometry, layer, name, always_face_camera, model_preferences,
|
||||
sketchup_attributes, application_id = '', &convert)
|
||||
definition = sketchup_model.definitions[name]
|
||||
return definition if definition && (definition.name == name || definition.guid == application_id)
|
||||
|
||||
definition&.entities&.clear!
|
||||
definition ||= sketchup_model.definitions.add(name)
|
||||
definition.layer = layer
|
||||
if geometry.is_a?(Array)
|
||||
geometry.each { |obj| convert.call(obj, layer, model_preferences, definition.entities) }
|
||||
end
|
||||
if geometry.is_a?(Hash) && !geometry['speckle_type'].nil?
|
||||
convert.call(geometry, layer, model_preferences, definition.entities)
|
||||
end
|
||||
# puts("definition finished: #{name} (#{application_id})")
|
||||
# puts(" entity count: #{definition.entities.count}")
|
||||
definition.behavior.always_face_camera = always_face_camera
|
||||
unless sketchup_attributes.nil?
|
||||
SketchupModel::Dictionary::DictionaryHandler
|
||||
.attribute_dictionaries_to_native(definition, sketchup_attributes['dictionaries'])
|
||||
end
|
||||
definition
|
||||
end
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
# rubocop:enable Metrics/PerceivedComplexity
|
||||
# rubocop:enable Metrics/ParameterLists
|
||||
|
||||
# rubocop:disable Metrics/AbcSize
|
||||
# rubocop:disable Metrics/MethodLength
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
# rubocop:disable Metrics/PerceivedComplexity
|
||||
def self.group_entities_to_speckle(definition, units, definitions, preferences, &convert)
|
||||
orphan_edges = definition.entities.grep(Sketchup::Edge).filter { |edge| edge.faces.none? }
|
||||
lines = orphan_edges.collect do |orphan_edge|
|
||||
Geometry::Line.from_edge(orphan_edge, units, preferences[:model])
|
||||
end
|
||||
|
||||
nested_blocks = definition.entities.grep(Sketchup::ComponentInstance).collect do |component_instance|
|
||||
BlockInstance.from_component_instance(component_instance, units, definitions, preferences, &convert)
|
||||
end
|
||||
|
||||
nested_groups = definition.entities.grep(Sketchup::Group).collect do |group|
|
||||
BlockInstance.from_group(group, units, definitions, preferences, &convert)
|
||||
end
|
||||
|
||||
if preferences[:model][:combine_faces_by_material]
|
||||
mesh_groups = {}
|
||||
definition.entities.grep(Sketchup::Face).collect do |face|
|
||||
group_meshes_by_material(definition, face, mesh_groups, units, preferences[:model])
|
||||
end
|
||||
|
||||
lines + nested_blocks + nested_groups + mesh_groups.values
|
||||
else
|
||||
meshes = definition.entities.grep(Sketchup::Face).collect do |face|
|
||||
Geometry::Mesh.from_face(face, units, preferences[:model])
|
||||
end
|
||||
|
||||
lines + nested_blocks + nested_groups + meshes
|
||||
end
|
||||
end
|
||||
# rubocop:enable Metrics/AbcSize
|
||||
# rubocop:enable Metrics/MethodLength
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
# rubocop:enable Metrics/PerceivedComplexity
|
||||
|
||||
# rubocop:disable Metrics/AbcSize
|
||||
def self.group_meshes_by_material(definition, face, mat_groups, units, model_preferences)
|
||||
# convert material
|
||||
mat_id = get_mesh_group_id(face, model_preferences)
|
||||
mat_groups[mat_id] = initialise_group_mesh(face, definition.bounds, units) unless mat_groups.key?(mat_id)
|
||||
mat_group = mat_groups[mat_id]
|
||||
if face.loops.size > 1
|
||||
mesh = face.mesh
|
||||
mat_group[:'@(31250)vertices'].push(*Geometry::Mesh.mesh_points_to_array(mesh, units))
|
||||
mat_group[:'@(62500)faces'].push(*Geometry::Mesh.mesh_faces_to_array(mesh, mat_group[:pt_count] - 1))
|
||||
mat_group[:'@(31250)faceEdgeFlags'].push(*Geometry::Mesh.mesh_edge_flags_to_array(mesh))
|
||||
else
|
||||
mat_group[:'@(31250)vertices'].push(*Geometry::Mesh.face_vertices_to_array(face, units))
|
||||
mat_group[:'@(62500)faces'].push(*Geometry::Mesh.face_indices_to_array(face, mat_group[:pt_count]))
|
||||
mat_group[:'@(31250)faceEdgeFlags'].push(*Geometry::Mesh.face_edge_flags_to_array(face))
|
||||
end
|
||||
mat_group[:pt_count] += face.vertices.count
|
||||
end
|
||||
# rubocop:enable Metrics/AbcSize
|
||||
|
||||
def self.initialise_group_mesh(face, bounds, units)
|
||||
has_any_soften_edge = face.edges.any?(&:soft?)
|
||||
mesh = Geometry::Mesh.new(
|
||||
units: units,
|
||||
render_material: face.material.nil? ? nil : RenderMaterial.from_material(face.material),
|
||||
bbox: Geometry::BoundingBox.from_bounds(bounds, units),
|
||||
vertices: [],
|
||||
faces: [],
|
||||
face_edge_flags: [],
|
||||
sketchup_attributes: { is_soften: has_any_soften_edge }
|
||||
)
|
||||
mesh[:pt_count] = 0
|
||||
mesh
|
||||
end
|
||||
|
||||
# Mesh group id helps to determine how to group faces into meshes.
|
||||
# @param face [Sketchup::Face] face to get mesh group id.
|
||||
def self.get_mesh_group_id(face, model_preferences)
|
||||
if model_preferences[:include_entity_attributes]
|
||||
has_attribute_dictionary = !(face.attribute_dictionaries.nil? || face.attribute_dictionaries.first.nil?)
|
||||
return face.persistent_id.to_s if has_attribute_dictionary
|
||||
end
|
||||
|
||||
material = face.material || face.back_material
|
||||
return 'none' if material.nil?
|
||||
|
||||
return material.entityID.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,161 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'render_material'
|
||||
require_relative 'transform'
|
||||
require_relative 'block_definition'
|
||||
require_relative '../base'
|
||||
require_relative '../geometry/bounding_box'
|
||||
require_relative '../../sketchup_model/dictionary/dictionary_handler'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleObjects
|
||||
module Other
|
||||
# BlockInstance object definition for Speckle.
|
||||
class BlockInstance < Base
|
||||
SPECKLE_TYPE = 'Objects.Other.BlockInstance'
|
||||
|
||||
# @param units [String] units of the block instance.
|
||||
# @param is_sketchup_group [Boolean] whether is sketchup group or not. Sketchup Groups represented as
|
||||
# block instance on Speckle.
|
||||
# @param name [String] name of the block instance.
|
||||
# @param transform [Other::Transform] transform of the block instance.
|
||||
# @param block_definition [Other::BlockDefinition] definition of the block instance.
|
||||
# @param sketchup_attributes [Hash{Symbol=>Object}] sketchup attributes of the block instance.
|
||||
# @param application_id [String] application id of the block instance.
|
||||
# rubocop:disable Metrics/ParameterLists
|
||||
def initialize(units:, is_sketchup_group:, name:, render_material:, transform:, block_definition:,
|
||||
sketchup_attributes: {}, application_id: nil)
|
||||
super(
|
||||
speckle_type: SPECKLE_TYPE,
|
||||
total_children_count: 0,
|
||||
application_id: application_id,
|
||||
id: nil
|
||||
)
|
||||
self[:units] = units
|
||||
self[:name] = name
|
||||
self[:is_sketchup_group] = is_sketchup_group
|
||||
self[:renderMaterial] = render_material
|
||||
self[:transform] = transform
|
||||
self[:sketchup_attributes] = sketchup_attributes if sketchup_attributes.any?
|
||||
self['@blockDefinition'] = block_definition
|
||||
end
|
||||
# rubocop:enable Metrics/ParameterLists
|
||||
|
||||
# @param group [Sketchup::Group] group to convert Speckle BlockInstance
|
||||
def self.from_group(group, units, component_defs, preferences, &convert)
|
||||
dictionaries = {}
|
||||
if preferences[:model][:include_entity_attributes]
|
||||
dictionaries = SketchupModel::Dictionary::DictionaryHandler.attribute_dictionaries_to_speckle(group)
|
||||
end
|
||||
att = dictionaries.any? ? { dictionaries: dictionaries } : {}
|
||||
BlockInstance.new(
|
||||
units: units,
|
||||
is_sketchup_group: true,
|
||||
name: group.name == '' ? nil : group.name,
|
||||
render_material: group.material.nil? ? nil : RenderMaterial.from_material(group.material),
|
||||
transform: Other::Transform.from_transformation(group.transformation, units),
|
||||
block_definition: BlockDefinition.from_definition(group.definition, units, component_defs,
|
||||
preferences, &convert),
|
||||
sketchup_attributes: att,
|
||||
application_id: group.guid
|
||||
)
|
||||
end
|
||||
|
||||
# @param component_instance [Sketchup::ComponentInstance] component instance to convert Speckle BlockInstance
|
||||
# rubocop:disable Metrics/MethodLength
|
||||
def self.from_component_instance(component_instance, units, component_defs, preferences, &convert)
|
||||
dictionaries = {}
|
||||
if preferences[:model][:include_entity_attributes]
|
||||
dictionaries = SketchupModel::Dictionary::DictionaryHandler
|
||||
.attribute_dictionaries_to_speckle(component_instance)
|
||||
end
|
||||
att = dictionaries.any? ? { dictionaries: dictionaries } : {}
|
||||
BlockInstance.new(
|
||||
units: units,
|
||||
is_sketchup_group: false,
|
||||
name: component_instance.name == '' ? nil : component_instance.name,
|
||||
render_material: if component_instance.material.nil?
|
||||
nil
|
||||
else
|
||||
RenderMaterial.from_material(component_instance.material)
|
||||
end,
|
||||
transform: Other::Transform.from_transformation(component_instance.transformation, units),
|
||||
block_definition: BlockDefinition.from_definition(component_instance.definition, units, component_defs,
|
||||
preferences, &convert),
|
||||
sketchup_attributes: att,
|
||||
application_id: component_instance.guid
|
||||
)
|
||||
end
|
||||
# rubocop:enable Metrics/MethodLength
|
||||
|
||||
# Creates a component instance from a block
|
||||
# @param sketchup_model [Sketchup::Model] sketchup model to check block definitions.
|
||||
# @param block [Object] block object that represents Speckle block.
|
||||
# @param layer [Sketchup::Layer] layer to add {Sketchup::Edge} into it.
|
||||
# @param entities [Sketchup::Entities] entities collection to add {Sketchup::Edge} into it.
|
||||
# rubocop:disable Metrics/AbcSize
|
||||
# rubocop:disable Metrics/MethodLength
|
||||
# rubocop:disable Metrics/ParameterLists
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
# rubocop:disable Metrics/PerceivedComplexity
|
||||
def self.to_native(sketchup_model, block, layer, entities, model_preferences, &convert)
|
||||
# is_group = block.key?("is_sketchup_group") && block["is_sketchup_group"]
|
||||
# something about this conversion is freaking out if nested block geo is a group
|
||||
# so this is set to false always until I can figure this out
|
||||
is_group = false
|
||||
# is_group = block['is_sketchup_group']
|
||||
definition = BlockDefinition.to_native(
|
||||
sketchup_model,
|
||||
block['@blockDefinition']['@geometry'],
|
||||
layer,
|
||||
block['@blockDefinition']['name'],
|
||||
block['@blockDefinition']['always_face_camera'],
|
||||
model_preferences,
|
||||
block['@blockDefinition']['sketchup_attributes'],
|
||||
block['@blockDefinition']['applicationId'],
|
||||
&convert
|
||||
)
|
||||
|
||||
instance_name = block['name'].nil? || block['name'].empty? ? block['id'] : block['name']
|
||||
t_arr = block['transform'].is_a?(Hash) ? block['transform']['value'] : block['transform']
|
||||
transform = Other::Transform.to_native(t_arr, block['units'])
|
||||
instance = if is_group
|
||||
# rubocop:disable SketchupSuggestions/AddGroup
|
||||
group = entities.add_group(definition.entities.to_a)
|
||||
group.layer = layer
|
||||
group
|
||||
# rubocop:enable SketchupSuggestions/AddGroup
|
||||
else
|
||||
instance = entities.add_instance(definition, transform)
|
||||
instance.layer = layer
|
||||
instance
|
||||
end
|
||||
|
||||
# erase existing instances after creation and before rename because you can't have definitions
|
||||
# without instances
|
||||
find_and_erase_existing_instance(definition, instance_name, block['applicationId'])
|
||||
puts("Failed to create instance for speckle block instance #{block['id']}") if instance.nil?
|
||||
instance.transformation = transform if is_group
|
||||
instance.material = Other::RenderMaterial.to_native(sketchup_model, block['renderMaterial'])
|
||||
instance.name = instance_name
|
||||
unless block['sketchup_attributes'].nil?
|
||||
SketchupModel::Dictionary::DictionaryHandler
|
||||
.attribute_dictionaries_to_native(instance, block['sketchup_attributes']['dictionaries'])
|
||||
end
|
||||
instance
|
||||
end
|
||||
# rubocop:enable Metrics/AbcSize
|
||||
# rubocop:enable Metrics/MethodLength
|
||||
# rubocop:enable Metrics/ParameterLists
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
# rubocop:enable Metrics/PerceivedComplexity
|
||||
|
||||
# takes a component definition and finds and erases the first instance with the matching name
|
||||
# (and optionally the applicationId)
|
||||
def self.find_and_erase_existing_instance(definition, name, app_id = '')
|
||||
definition.instances.find { |ins| ins.name == name || ins.guid == app_id }&.erase!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,41 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../immutable/immutable'
|
||||
require_relative '../callbacks/callback_message'
|
||||
|
||||
module SpeckleConnector
|
||||
module States
|
||||
# State of the speckle on ruby.
|
||||
class SpeckleState
|
||||
include Immutable::ImmutableUtils
|
||||
|
||||
# @return [Array] accounts on appdata.
|
||||
attr_reader :accounts
|
||||
|
||||
# @return [Hash] queue to send to server.
|
||||
attr_reader :message_queue
|
||||
|
||||
# @return [Hash] stream queue to send to server.
|
||||
attr_reader :stream_queue
|
||||
|
||||
def initialize(accounts, queue, stream_queue)
|
||||
@accounts = accounts
|
||||
@message_queue = queue
|
||||
@stream_queue = stream_queue
|
||||
end
|
||||
|
||||
# @param callback_name [String] name of the callback command
|
||||
# @param stream_id [String] id of the stream
|
||||
# @param parameters [Array<String>] parameters of the callback method call
|
||||
def with_add_queue(callback_name, stream_id, parameters)
|
||||
next_queue_message = Callbacks::CallbackMessage.serialize(callback_name, stream_id, parameters)
|
||||
new_queue = message_queue.merge({ "#{callback_name}": next_queue_message })
|
||||
with(:@message_queue => new_queue)
|
||||
end
|
||||
|
||||
def with_accounts(new_accounts)
|
||||
with(:@accounts => new_accounts)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,57 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'json'
|
||||
|
||||
module SpeckleConnector
|
||||
module Typescript
|
||||
# Object to help convert object attributes to JSON and by checking types.
|
||||
class TypescriptObject
|
||||
# @param attributes [Hash{Symbol=>Object}] attributes are given as key value pairs
|
||||
def initialize(**attributes)
|
||||
@attributes = attributes
|
||||
check_attributes
|
||||
end
|
||||
|
||||
# @return [String] the JSON representation of the object
|
||||
def to_json(*options)
|
||||
@attributes.to_json(*options)
|
||||
end
|
||||
|
||||
def to_h(*options)
|
||||
JSON.parse(to_json(*options), { symbolize_names: true })
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
def check_attributes
|
||||
attribute_types.each do |key, class_or_classes|
|
||||
value = @attributes[key]
|
||||
case class_or_classes
|
||||
when Array
|
||||
is_class_correct = class_or_classes.any? do |klass|
|
||||
raise "#{klass} is not a class" unless klass.is_a? Class
|
||||
|
||||
value.is_a? klass
|
||||
end
|
||||
raise "attribute #{key} is of class #{value.class} and not #{class_or_classes}" unless is_class_correct
|
||||
when Class
|
||||
raise ArgumentError, "#{class_or_classes} should be class" unless class_or_classes.is_a? Class
|
||||
|
||||
unless value.is_a? class_or_classes
|
||||
raise ArgumentError,
|
||||
"attribute #{key} is of class #{value.class} and not #{class_or_classes}"
|
||||
end
|
||||
else
|
||||
raise ArgumentError, "#{class_or_classes} should be class or array of classes"
|
||||
end
|
||||
end
|
||||
end
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
|
||||
def attribute_types
|
||||
raise NotImplementedError, 'Implement in child class'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,12 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module SpeckleConnector
|
||||
module Ui
|
||||
# The abstract class for view to send data to a user interface.
|
||||
class View
|
||||
def update_view(_state)
|
||||
raise NotImplementedError, 'Implement in a subclass'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,74 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'view'
|
||||
require_relative '../ui/dialog'
|
||||
require_relative '../constants/path_constants'
|
||||
|
||||
require_relative '../commands/send_selection'
|
||||
require_relative '../commands/receive_objects'
|
||||
require_relative '../commands/action_command'
|
||||
require_relative '../commands/dialog_ready'
|
||||
require_relative '../commands/save_stream'
|
||||
require_relative '../commands/remove_stream'
|
||||
require_relative '../commands/notify_connected'
|
||||
require_relative '../commands/user_preferences_updated'
|
||||
require_relative '../commands/model_preferences_updated'
|
||||
|
||||
require_relative '../actions/reload_accounts'
|
||||
require_relative '../actions/load_saved_streams'
|
||||
require_relative '../actions/init_local_accounts'
|
||||
require_relative '../actions/collect_preferences'
|
||||
|
||||
module SpeckleConnector
|
||||
module Ui
|
||||
SPECKLE_UI_ID = 'speckle_ui'
|
||||
VUE_UI_HTML = Pathname.new(File.join(SPECKLE_SRC_PATH, '..', 'vue_ui', 'index.html')).cleanpath.to_s
|
||||
|
||||
# View that provided by vue.js
|
||||
class VueView < View
|
||||
CMD_UPDATE_VIEW = 'speckle.updateView'
|
||||
|
||||
# @param dialog_specs [Hash] the specifications for the {SpeckleConnector::Ui::Dialog}.
|
||||
# @param app [App::SpeckleConnectorApp] the reference to the app object
|
||||
def initialize(dialog_specs, app)
|
||||
super()
|
||||
@dialog_specs = dialog_specs
|
||||
@app = app
|
||||
end
|
||||
|
||||
# Show the HTML dialog
|
||||
def show
|
||||
dialog.show
|
||||
end
|
||||
|
||||
# @return [SpeckleConnector::Ui::Dialog] wrapper for the {Sketchup::HTMLDialog}
|
||||
def dialog
|
||||
@dialog ||= SpeckleConnector::Ui::Dialog.new(commands: commands, **@dialog_specs)
|
||||
end
|
||||
|
||||
def update_view(_state)
|
||||
# TODO: If you want to send data to dialog additionally, consume this method.
|
||||
# App object triggers this method by ui_controller
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def commands
|
||||
@commands ||= {
|
||||
dialog_ready: Commands::DialogReady.new(@app),
|
||||
send_selection: Commands::SendSelection.new(@app),
|
||||
receive_objects: Commands::ReceiveObjects.new(@app),
|
||||
reload_accounts: Commands::ActionCommand.new(@app, Actions::ReloadAccounts),
|
||||
init_local_accounts: Commands::ActionCommand.new(@app, Actions::InitLocalAccounts),
|
||||
load_saved_streams: Commands::ActionCommand.new(@app, Actions::LoadSavedStreams),
|
||||
save_stream: Commands::SaveStream.new(@app),
|
||||
remove_stream: Commands::RemoveStream.new(@app),
|
||||
notify_connected: Commands::NotifyConnected.new(@app),
|
||||
collect_preferences: Commands::ActionCommand.new(@app, Actions::CollectPreferences),
|
||||
user_preferences_updated: Commands::UserPreferencesUpdated.new(@app),
|
||||
model_preferences_updated: Commands::ModelPreferencesUpdated.new(@app)
|
||||
}.freeze
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -4,7 +4,7 @@ require 'sketchup'
|
||||
require 'extensions'
|
||||
|
||||
# Speckle connector module to enable multiplayer mode ON!
|
||||
module SpeckleConnector
|
||||
module SpeckleConnector3
|
||||
# Version - patched by CI
|
||||
CONNECTOR_VERSION = '0.0.0'
|
||||
|
||||
@@ -23,11 +23,11 @@ module SpeckleConnector
|
||||
PATH = File.join(PATH_ROOT, folder_name).freeze
|
||||
|
||||
# Run from localhost or from build files
|
||||
DEV_MODE = false
|
||||
DEV_MODE = true
|
||||
puts("Loading Speckle Connector v#{CONNECTOR_VERSION} from #{DEV_MODE ? 'dev' : 'build'}")
|
||||
|
||||
unless file_loaded?(__FILE__)
|
||||
ex = SketchupExtension.new('Speckle SketchUp', File.join(PATH, 'bootstrap'))
|
||||
ex = SketchupExtension.new('Speckle SketchUp v3', File.join(PATH, 'bootstrap'))
|
||||
ex.description = 'Speckle Connector for SketchUp'
|
||||
ex.version = CONNECTOR_VERSION
|
||||
ex.copyright = 'AEC Systems Ltd.'
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
require 'sketchup'
|
||||
require 'pathname'
|
||||
require 'speckle_connector/debug'
|
||||
require 'speckle_connector_3/debug'
|
||||
require_relative 'src/log/log'
|
||||
require_relative 'src/ui/sketchup_ui'
|
||||
require_relative 'src/ui/ui_controller'
|
||||
require_relative 'src/commands/menu_command_handler'
|
||||
@@ -12,7 +13,7 @@ require_relative 'src/states/initial_state'
|
||||
require_relative 'src/commands/speckle_menu_commands'
|
||||
|
||||
# Speckle Connector on SketchUp to enable Multiplayer mode ON!
|
||||
module SpeckleConnector
|
||||
module SpeckleConnector3
|
||||
SKETCHUP_VERSION = Sketchup.version.to_i
|
||||
|
||||
dir = __dir__.dup
|
||||
@@ -23,9 +24,9 @@ module SpeckleConnector
|
||||
sketchup_ui = Ui::SketchupUi.new
|
||||
ui_controller = Ui::UiController.new(sketchup_ui)
|
||||
menu_commands = Commands::MenuCommandHandler.new
|
||||
user_state = SpeckleConnector::States::UserState.new({})
|
||||
initial_state = SpeckleConnector::States::InitialState.new(user_state)
|
||||
app = SpeckleConnector::App::SpeckleConnectorApp.new(menu_commands, initial_state, ui_controller)
|
||||
user_state = SpeckleConnector3::States::UserState.new({})
|
||||
initial_state = SpeckleConnector3::States::InitialState.new(user_state)
|
||||
app = SpeckleConnector3::App::SpeckleConnectorApp.new(menu_commands, initial_state, ui_controller)
|
||||
# Add menu commands to SketchUp and Speckle application
|
||||
Commands::SpeckleMenuCommands.add_initial_commands!(app)
|
||||
app
|
||||
@@ -1,7 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Speckle connector module to enable multiplayer mode ON!
|
||||
module SpeckleConnector
|
||||
module SpeckleConnector3
|
||||
# from thomthom
|
||||
# https://github.com/thomthom/true-bend/blob/master/src/tt_truebend/debug.rb
|
||||
|
||||
@@ -15,7 +15,9 @@ module SpeckleConnector
|
||||
def self.reload
|
||||
load(__FILE__)
|
||||
pattern = File.join(__dir__, '**/*.rb')
|
||||
Dir.glob(pattern).each { |file| load(file) }
|
||||
# TODO: Here is a opportunity to improve reloading process.
|
||||
# We can cache last edited time of the each file later to check which file need to be reloaded.
|
||||
Dir.glob(pattern).each { |file| load(file) unless file.include?('bootstrap') }
|
||||
.size
|
||||
end
|
||||
# rubocop:enable SketchupSuggestions/FileEncoding
|
||||
|
Before Width: | Height: | Size: 798 B After Width: | Height: | Size: 798 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 665 B After Width: | Height: | Size: 665 B |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 639 B After Width: | Height: | Size: 639 B |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1,66 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'JSON'
|
||||
require_relative '../ext/sqlite3'
|
||||
require_relative '../constants/path_constants'
|
||||
require_relative '../preferences/preferences'
|
||||
|
||||
module SpeckleConnector3
|
||||
# Accounts to communicate with models on user's account.
|
||||
module Accounts
|
||||
# Load accounts from user's app data.
|
||||
def self.load_accounts
|
||||
db_path = SPECKLE_ACCOUNTS_DB_PATH
|
||||
unless File.exist?(db_path)
|
||||
File.new(SPECKLE_ACCOUNTS_DB_PATH, "w")
|
||||
db = Sqlite3::Database.new(SPECKLE_ACCOUNTS_DB_PATH)
|
||||
Preferences.create_objects_table(db)
|
||||
db.close
|
||||
return []
|
||||
end
|
||||
|
||||
db = Sqlite3::Database.new(db_path)
|
||||
rows = db.exec('SELECT * FROM objects')
|
||||
db.close
|
||||
rows.map { |row| JSON.parse(row[1]) }
|
||||
end
|
||||
|
||||
def self.remove_account(account_id)
|
||||
db_path = SPECKLE_ACCOUNTS_DB_PATH
|
||||
unless File.exist?(db_path)
|
||||
raise(
|
||||
IOError,
|
||||
"No Accounts db found. Please read the guide for different options for adding your account:\n
|
||||
https://speckle.guide/user/manager.html#adding-accounts"
|
||||
)
|
||||
end
|
||||
db = Sqlite3::Database.new(db_path)
|
||||
|
||||
begin
|
||||
db.exec("DELETE FROM objects WHERE hash = '#{account_id}'")
|
||||
puts "Account with hash #{account_id} has been removed."
|
||||
rescue StandardError => e
|
||||
puts "An error occurred: #{e}"
|
||||
ensure
|
||||
db.close
|
||||
end
|
||||
end
|
||||
|
||||
def self.get_account_by_id(id)
|
||||
accounts = load_accounts
|
||||
accounts.select { |acc| acc['id'] == id }[0]
|
||||
end
|
||||
|
||||
# Default account on the user computer.
|
||||
def self.default_account
|
||||
accounts = load_accounts
|
||||
accounts.select { |acc| acc['isDefault'] }[0] || accounts[0]
|
||||
end
|
||||
|
||||
# Try to get local server account for debug/test purposes.
|
||||
def self.try_get_local_server_account
|
||||
accounts = load_accounts
|
||||
accounts.select { |acc| acc['serverInfo']['url'].include?('localhost') }[0] || nil
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,21 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../action'
|
||||
require_relative '../../accounts/accounts'
|
||||
require_relative '../load_saved_streams'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Action to initialize local accounts from database.
|
||||
class GetAccounts < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, resolve_id)
|
||||
puts 'Initialisation of Speckle accounts requested by plugin'
|
||||
accounts_data = SpeckleConnector3::Accounts.load_accounts
|
||||
js_script = "accountsBinding.receiveResponse('#{resolve_id}', #{accounts_data.to_json})"
|
||||
state.with_add_queue_js_command('getAccounts', js_script)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,20 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../action'
|
||||
require_relative '../../accounts/accounts'
|
||||
require_relative '../load_saved_streams'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Action to remove account from database.
|
||||
class RemoveAccount < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, resolve_id, account_id)
|
||||
SpeckleConnector3::Accounts.remove_account(account_id)
|
||||
js_script = "accountsBinding.receiveResponse('#{resolve_id}')"
|
||||
state.with_add_queue_js_command('removeAccount', js_script)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,6 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# State changer object.
|
||||
class Action
|
||||
@@ -0,0 +1,33 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'action'
|
||||
require_relative 'deactivate_diffing'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Deactivate diffing for stream.
|
||||
class ActivateDiffing < Action
|
||||
def initialize(stream_id)
|
||||
super()
|
||||
@stream_id = stream_id
|
||||
end
|
||||
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def update_state(state)
|
||||
state = DeactivateDiffing.update_state(state, nil, {})
|
||||
puts "Diffing activated for #{@stream_id}"
|
||||
speckle_entities = state.speckle_state.speckle_entities
|
||||
invalid_speckle_entities = speckle_entities.select do |_id, entity|
|
||||
entity.invalid_stream_ids.include?(@stream_id) && entity.sketchup_entity.is_a?(Sketchup::Face)
|
||||
end
|
||||
invalid_speckle_entities.each do |id, entity|
|
||||
new_entity = entity.activate_diffing(@stream_id, state.sketchup_state.materials.by_id(MAT_EDIT))
|
||||
speckle_entities = speckle_entities.put(id, new_entity)
|
||||
end
|
||||
new_speckle_state = state.speckle_state.with_speckle_entities(speckle_entities)
|
||||
state.with_speckle_state(new_speckle_state)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,52 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'action'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Adds material to speckle state and Sketchup.
|
||||
class AddMaterial < Action
|
||||
def self.update_state(state, material_name:, color:, material_id:, alpha: nil)
|
||||
materials = state.sketchup_state.materials
|
||||
existing_material = materials.by_id(material_id)
|
||||
return state if existing_material&.valid?
|
||||
|
||||
new_material = create_or_get_material(state.sketchup_state.sketchup_model,
|
||||
material_name,
|
||||
color,
|
||||
material_id,
|
||||
alpha: alpha)
|
||||
new_materials = materials.add_material(material_id, new_material)
|
||||
new_sketchup_state = state.sketchup_state.with(:@materials => new_materials)
|
||||
state.with(:@sketchup_state => new_sketchup_state)
|
||||
end
|
||||
|
||||
def self.create_or_get_material(model, material_name, color, material_id, alpha: nil)
|
||||
materials = model.materials
|
||||
existing_material = materials.find { |mat| mat.name == material_name }
|
||||
return existing_material if existing_material&.valid?
|
||||
|
||||
existing_material = materials.add material_name
|
||||
existing_material.set_attribute(MAT_DICTIONARY, MAT_ID, material_id.to_s)
|
||||
set_hex_color(existing_material, color)
|
||||
existing_material.alpha = alpha if alpha
|
||||
existing_material
|
||||
end
|
||||
|
||||
def self.set_hex_color(skp_material, hex_value)
|
||||
hex_value = hex_value.to_s
|
||||
col_blue, col_green, col_red = parse_hex_color(hex_value)
|
||||
skp_material.color = col_red, col_green, col_blue
|
||||
end
|
||||
|
||||
def self.parse_hex_color(hex_value)
|
||||
split_values = hex_value.match(/^#([a-fA-F\d]{2})([a-fA-F\d]{2})([a-fA-F\d]{2})$/) ||
|
||||
hex_value.match(/^#([a-fA-F\d])([a-fA-F\d])([a-fA-F\d])$/)
|
||||
col_red = split_values[1].hex
|
||||
col_green = split_values[2].hex
|
||||
col_blue = split_values[3].hex
|
||||
return col_blue, col_green, col_red
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,73 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'action'
|
||||
require_relative 'mapped_entities_updated'
|
||||
require_relative 'events/selection_event_action'
|
||||
require_relative '../sketchup_model/dictionary/speckle_schema_dictionary_handler'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Apply mappings for selected entities.
|
||||
class ApplyMappings < Action
|
||||
def initialize(entities_to_map, method, category, family,
|
||||
family_type, level, name, is_definition)
|
||||
super()
|
||||
@entities_to_map = entities_to_map
|
||||
@method = method
|
||||
@category = category
|
||||
@name = name
|
||||
@family = family
|
||||
@family_type = family_type
|
||||
@level = level
|
||||
@is_definition = is_definition
|
||||
end
|
||||
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
# rubocop:disable Metrics/AbcSize
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
# rubocop:disable Metrics/PerceivedComplexity
|
||||
# rubocop:disable Metrics/MethodLength
|
||||
def update_state(state)
|
||||
sketchup_model = state.sketchup_state.sketchup_model
|
||||
entities = if sketchup_model.active_path.nil?
|
||||
sketchup_model.entities
|
||||
else
|
||||
sketchup_model.active_path.last.definition.entities
|
||||
end
|
||||
|
||||
# Collect entities from entity ids that comes from UI as list
|
||||
entities_to_map = entities.select { |e| @entities_to_map.include?(e.persistent_id.to_s) }
|
||||
|
||||
# Switch to definitions if all entities are component instance and UI flag shows that
|
||||
if entities_to_map.all? { |e| e.is_a?(Sketchup::ComponentInstance) } && @is_definition
|
||||
entities_to_map = entities_to_map.collect(&:definition).uniq
|
||||
end
|
||||
|
||||
# Store speckle state to update with mapped entities.
|
||||
speckle_state = state.speckle_state
|
||||
entities_to_map.each do |entity|
|
||||
name = if @name == '<Mixed>'
|
||||
entity.respond_to?(:name) ? entity.name : ''
|
||||
else
|
||||
@name
|
||||
end
|
||||
SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.set_attribute(entity, :category, @category)
|
||||
SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.set_attribute(entity, :name, name)
|
||||
SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.set_attribute(entity, :method, @method)
|
||||
SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.set_attribute(entity, :family, @family)
|
||||
SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.set_attribute(entity, :family_type, @family_type)
|
||||
SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.set_attribute(entity, :level, @level)
|
||||
speckle_state = speckle_state.with_mapped_entity(entity)
|
||||
end
|
||||
|
||||
new_state = MappedEntitiesUpdated.update_state(state.with_speckle_state(speckle_state))
|
||||
Events::SelectionEventAction.update_state(new_state, { apply: true })
|
||||
end
|
||||
# rubocop:enable Metrics/AbcSize
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
# rubocop:enable Metrics/PerceivedComplexity
|
||||
# rubocop:enable Metrics/MethodLength
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,28 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'add_send_model_card'
|
||||
require_relative 'add_receive_model_card'
|
||||
require_relative '../action'
|
||||
require_relative '../../cards/send_card'
|
||||
require_relative '../../cards/receive_card'
|
||||
require_relative '../../filters/send/everything_filter'
|
||||
require_relative '../../filters/send/selection_filter'
|
||||
require_relative '../../filters/send_filters'
|
||||
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Action to add send card.
|
||||
class AddModel < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, resolve_id, data)
|
||||
if data['typeDiscriminator'] == 'SenderModelCard'
|
||||
Actions::AddSendModelCard.update_state(state, resolve_id, data)
|
||||
else
|
||||
Actions::AddReceiveModelCard.update_state(state, resolve_id, data)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,52 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../action'
|
||||
require_relative '../../cards/send_card'
|
||||
require_relative '../../cards/receive_card'
|
||||
require_relative '../../filters/send/everything_filter'
|
||||
require_relative '../../filters/send/selection_filter'
|
||||
require_relative '../../filters/send_filters'
|
||||
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Action to add receive model card.
|
||||
class AddReceiveModelCard < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, resolve_id, data)
|
||||
model_card_id = data['modelCardId']
|
||||
account_id = data['accountId']
|
||||
server_url = data['serverUrl']
|
||||
workspace_id = data['workspaceId']
|
||||
workspace_slug = data['workspaceSlug']
|
||||
project_id = data['projectId']
|
||||
model_id = data['modelId']
|
||||
project_name = data['projectName']
|
||||
model_name = data['modelName']
|
||||
expired = data['expired']
|
||||
selected_version_id = data['selectedVersionId']
|
||||
selected_version_source_app = data['selectedVersionSourceApp']
|
||||
selected_version_user_id = data['selectedVersionUserId']
|
||||
latest_version_id = data['latestVersionId']
|
||||
latest_version_source_app = data['latestVersionSourceApp']
|
||||
latest_version_user_id = data['latestVersionUserId']
|
||||
has_dismissed_update_warning = data['hasDismissedUpdateWarning']
|
||||
baked_object_ids = data['bakedObjectIds'].nil? ? nil : data['bakedObjectIds'].values
|
||||
|
||||
receive_card = Cards::ReceiveCard.new(model_card_id, account_id, server_url, workspace_id, workspace_slug,
|
||||
project_id, model_id,
|
||||
project_name, model_name,
|
||||
selected_version_id, selected_version_source_app, selected_version_user_id,
|
||||
latest_version_id, latest_version_source_app, latest_version_user_id,
|
||||
has_dismissed_update_warning, expired, baked_object_ids)
|
||||
SketchupModel::Dictionary::ModelCardDictionaryHandler
|
||||
.save_receive_card_to_model(receive_card, state.sketchup_state.sketchup_model)
|
||||
new_speckle_state = state.speckle_state.with_receive_card(receive_card)
|
||||
state = state.with_speckle_state(new_speckle_state)
|
||||
js_script = "baseBinding.receiveResponse('#{resolve_id}')"
|
||||
return state.with_add_queue_js_command('addReceiveCard', js_script)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,48 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../action'
|
||||
require_relative '../../cards/send_card'
|
||||
require_relative '../../cards/receive_card'
|
||||
require_relative '../../filters/send/everything_filter'
|
||||
require_relative '../../filters/send/selection_filter'
|
||||
require_relative '../../filters/send_filters'
|
||||
require_relative '../../settings/card_settings'
|
||||
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Action to add send model card.
|
||||
class AddSendModelCard < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, resolve_id, data)
|
||||
send_filter = Filters::SendFilters.get_filter_from_ui_data(data['sendFilter'])
|
||||
# settings = Settings::CardSetting.get_setting_from_ui_data(data['settings'])
|
||||
# Init card and add to the state
|
||||
send_card = Cards::SendCard.new(
|
||||
data['modelCardId'],
|
||||
data['accountId'],
|
||||
data['serverUrl'],
|
||||
data['workspaceId'],
|
||||
data['workspaceSlug'],
|
||||
data['projectId'],
|
||||
data['projectName'],
|
||||
data['modelId'],
|
||||
data['modelName'],
|
||||
data['latestCreatedVersionId'],
|
||||
send_filter,
|
||||
data['settings']
|
||||
)
|
||||
|
||||
SketchupModel::Dictionary::ModelCardDictionaryHandler
|
||||
.save_send_card_to_model(send_card, state.sketchup_state.sketchup_model)
|
||||
|
||||
new_speckle_state = state.speckle_state.with_send_card(send_card)
|
||||
state = state.with_speckle_state(new_speckle_state)
|
||||
# Resolve promise
|
||||
js_script = "baseBinding.receiveResponse('#{resolve_id}')"
|
||||
state.with_add_queue_js_command('addSendCard', js_script)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,17 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../action'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Get connector version.
|
||||
class GetConnectorVersion < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, resolve_id)
|
||||
js_command = "baseBinding.receiveResponse('#{resolve_id}', '#{CONNECTOR_VERSION}')"
|
||||
state.with_add_queue_js_command('getConnectorVersion', js_command)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,97 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../action'
|
||||
require_relative '../../filters/send_filters'
|
||||
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Gets document state.
|
||||
class GetDocumentState < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, resolve_id)
|
||||
send_cards_hash = SketchupModel::Dictionary::ModelCardDictionaryHandler
|
||||
.get_send_cards_from_dict(state.sketchup_state.sketchup_model)
|
||||
|
||||
# TODO: CONVERTER_V2: Extract into new actions
|
||||
send_cards = send_cards_hash.collect do |id, card|
|
||||
filter = Filters::SendFilters.get_filter_from_document(card['sendFilter'])
|
||||
settings = Settings::CardSetting.get_filter_from_document(card['sendSettings'])
|
||||
send_card = Cards::SendCard.new(
|
||||
id,
|
||||
card['account_id'],
|
||||
card['server_url'],
|
||||
card['workspace_id'],
|
||||
card['workspace_slug'],
|
||||
card['project_id'],
|
||||
card['project_name'],
|
||||
card['model_id'],
|
||||
card['model_name'],
|
||||
card['latest_created_version_id'],
|
||||
filter,
|
||||
settings
|
||||
)
|
||||
|
||||
new_speckle_state = state.speckle_state.with_send_card(send_card)
|
||||
state = state.with_speckle_state(new_speckle_state)
|
||||
{
|
||||
modelCardId: send_card.model_card_id,
|
||||
accountId: send_card.account_id,
|
||||
serverUrl: send_card.server_url,
|
||||
workspaceId: send_card.workspace_id,
|
||||
workspaceSlug: send_card.workspace_slug,
|
||||
projectId: send_card.project_id,
|
||||
modelId: send_card.model_id,
|
||||
sendFilter: send_card.send_filter,
|
||||
settings: send_card.send_settings,
|
||||
latestCreatedVersionId: send_card.latest_created_version_id,
|
||||
typeDiscriminator: send_card.type_discriminator
|
||||
}
|
||||
end
|
||||
|
||||
receive_cards_hash = SketchupModel::Dictionary::ModelCardDictionaryHandler
|
||||
.get_receive_cards_from_dict(state.sketchup_state.sketchup_model)
|
||||
|
||||
# TODO: CONVERTER_V2: Extract into new actions
|
||||
receive_cards = receive_cards_hash.collect do |id, card|
|
||||
receive_card = Cards::ReceiveCard.new(id, card['account_id'], card['server_url'], card['workspace_id'], card['workspace_slug'], card['project_id'], card['model_id'],
|
||||
card['project_name'], card['model_name'], card['selected_version_id'],
|
||||
card['selected_version_source_app'], card['selected_version_user_id'],
|
||||
card['latest_version_id'], card['latest_version_source_app'],
|
||||
card['latest_version_user_id'], card['has_dismissed_update_warning'],
|
||||
card['expired'], card['baked_object_ids'])
|
||||
|
||||
new_speckle_state = state.speckle_state.with_receive_card(receive_card)
|
||||
state = state.with_speckle_state(new_speckle_state)
|
||||
{
|
||||
modelCardId: receive_card.model_card_id,
|
||||
accountId: receive_card.account_id,
|
||||
serverUrl: receive_card.server_url,
|
||||
workspaceId: receive_card.workspace_id,
|
||||
workspaceSlug: receive_card.workspace_slug,
|
||||
projectId: receive_card.project_id,
|
||||
modelId: receive_card.model_id,
|
||||
projectName: receive_card.project_name,
|
||||
modelName: receive_card.model_name,
|
||||
selectedVersionId: receive_card.selected_version_id,
|
||||
selectedVersionSourceApp: receive_card.selected_version_source_app,
|
||||
selectedVersionUserId: receive_card.selected_version_user_id,
|
||||
latestVersionId: receive_card.latest_version_id,
|
||||
latestVersionSourceApp: receive_card.latest_version_source_app,
|
||||
latestVersionUserId: receive_card.latest_version_user_id,
|
||||
hasDismissedUpdateWarning: receive_card.has_dismissed_update_warning,
|
||||
expired: receive_card.expired,
|
||||
bakedObjectIds: receive_card.baked_object_ids,
|
||||
typeDiscriminator: receive_card.type_discriminator
|
||||
}
|
||||
end
|
||||
|
||||
model_state = { models: send_cards + receive_cards }
|
||||
|
||||
js_script = "baseBinding.receiveResponse('#{resolve_id}', #{model_state.to_json})"
|
||||
state.with_add_queue_js_command('getDocumentState', js_script)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,19 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../action'
|
||||
require_relative '../../filters/send_filters'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Action to get send filter.
|
||||
class GetSendFilters < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, resolve_id)
|
||||
default_filters = Filters::SendFilters.get_default(state.sketchup_state.sketchup_model)
|
||||
js_script = "sendBinding.receiveResponse('#{resolve_id}', #{default_filters.to_json})"
|
||||
state.with_add_queue_js_command('getSendFilter', js_script)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,24 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../action'
|
||||
require_relative '../../settings/card_settings'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Action to get send settings.
|
||||
class GetSendSettings < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, resolve_id)
|
||||
# NOTE: below code is tested and works!
|
||||
# default_settings = [
|
||||
# Settings::CardSetting.new(id: "includeAttributes", title: "Include Attributes", type: "boolean", value: true),
|
||||
# Settings::CardSetting.new(id: "test", title: "Test", type: "string", value: "a", enum: %w[a b c])
|
||||
# ]
|
||||
default_settings = []
|
||||
js_script = "sendBinding.receiveResponse('#{resolve_id}', #{default_settings.to_json})"
|
||||
state.with_add_queue_js_command('getSendSettings', js_script)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,17 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../action'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Get source app name.
|
||||
class GetSourceAppName < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, resolve_id)
|
||||
js_command = "baseBinding.receiveResponse('#{resolve_id}', 'sketchup')"
|
||||
state.with_add_queue_js_command('getSourceAppName', js_command)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,17 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../action'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Get source app version.
|
||||
class GetSourceAppVersion < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, resolve_id)
|
||||
js_command = "baseBinding.receiveResponse('#{resolve_id}', #{SKETCHUP_VERSION})"
|
||||
state.with_add_queue_js_command('getSourceAppVersion', js_command)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,31 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../action'
|
||||
require_relative '../../sketchup_model/query/entity'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Action to add send card.
|
||||
class HighlightModel < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, resolve_id, model_card_id)
|
||||
receiver_card = state.speckle_state.receive_cards[model_card_id]
|
||||
sender_card = state.speckle_state.send_cards[model_card_id]
|
||||
card = receiver_card || sender_card
|
||||
|
||||
objects_to_highlight = if card.type_discriminator == 'ReceiverModelCard'
|
||||
state.speckle_state.receive_cards[model_card_id].baked_object_ids
|
||||
else
|
||||
state.speckle_state.send_cards[model_card_id].send_filter.selected_object_ids
|
||||
end
|
||||
|
||||
SketchupModel::Utils::ViewUtils.highlight_entities(state.sketchup_state.sketchup_model, objects_to_highlight)
|
||||
|
||||
# Resolve promise
|
||||
js_script = "baseBinding.receiveResponse('#{resolve_id}')"
|
||||
state.with_add_queue_js_command('highlightModel', js_script)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,20 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../action'
|
||||
require_relative '../../sketchup_model/query/entity'
|
||||
require_relative '../../sketchup_model/utils/view_utils'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Action to add send card.
|
||||
class HighlightObjects < Action
|
||||
def self.update_state(state, resolve_id, object_ids)
|
||||
SketchupModel::Utils::ViewUtils.highlight_entities(state.sketchup_state.sketchup_model, object_ids)
|
||||
|
||||
# Resolve promise
|
||||
js_script = "baseBinding.receiveResponse('#{resolve_id}')"
|
||||
state.with_add_queue_js_command('highlightObjects', js_script)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,31 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../action'
|
||||
require_relative '../../cards/send_card'
|
||||
require_relative '../../cards/receive_card'
|
||||
require_relative '../../filters/send/everything_filter'
|
||||
require_relative '../../filters/send/selection_filter'
|
||||
require_relative '../../filters/send_filters'
|
||||
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Action to remove send card.
|
||||
class RemoveModel < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, resolve_id, data)
|
||||
SketchupModel::Dictionary::ModelCardDictionaryHandler.remove_card_dict(state.sketchup_state.sketchup_model, data)
|
||||
new_speckle_state = if data['typeDiscriminator'] == 'ReceiverModelCard'
|
||||
state.speckle_state.without_receive_card(data['id'])
|
||||
else
|
||||
state.speckle_state.without_send_card(data['id'])
|
||||
end
|
||||
state = state.with_speckle_state(new_speckle_state)
|
||||
# Resolve promise
|
||||
js_script = "baseBinding.receiveResponse('#{resolve_id}')"
|
||||
state.with_add_queue_js_command('removeModel', js_script)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,34 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../action'
|
||||
require_relative '../../cards/send_card'
|
||||
require_relative '../../cards/receive_card'
|
||||
require_relative '../../filters/send/everything_filter'
|
||||
require_relative '../../filters/send/selection_filter'
|
||||
require_relative '../../filters/send_filters'
|
||||
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Action to remove cards.
|
||||
class RemoveModels < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, resolve_id, data)
|
||||
data.each do |model_card|
|
||||
SketchupModel::Dictionary::ModelCardDictionaryHandler.remove_card_dict(state.sketchup_state.sketchup_model, model_card)
|
||||
new_speckle_state = if model_card['typeDiscriminator'] == 'ReceiverModelCard'
|
||||
state.speckle_state.without_receive_card(model_card['id'])
|
||||
else
|
||||
state.speckle_state.without_send_card(model_card['id'])
|
||||
end
|
||||
state = state.with_speckle_state(new_speckle_state)
|
||||
end
|
||||
|
||||
# Resolve promise
|
||||
js_script = "baseBinding.receiveResponse('#{resolve_id}')"
|
||||
state.with_add_queue_js_command('removeModels', js_script)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,20 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../action'
|
||||
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Action to update send filter.
|
||||
class UpdateSendFilter < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, resolve_id, data, value)
|
||||
SketchupModel::Dictionary::ModelCardDictionaryHandler.update_filter(state.sketchup_state.sketchup_model, data, value)
|
||||
|
||||
js_script = "sendBinding.receiveResponse('#{resolve_id}')"
|
||||
state.with_add_queue_js_command('updateSendFilter', js_script)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,31 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'action'
|
||||
require_relative '../sketchup_model/dictionary/speckle_entity_dictionary_handler'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Clear mapper source.
|
||||
class ClearMapperSource < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, _resolve_id, _data)
|
||||
new_speckle_state = state.speckle_state.with_removed_mapper_source
|
||||
erase_levels(state)
|
||||
state.with_speckle_state(new_speckle_state)
|
||||
end
|
||||
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
def self.erase_levels(state)
|
||||
levels = state.sketchup_state.sketchup_model.definitions.select do |definition|
|
||||
SketchupModel::Dictionary::SpeckleEntityDictionaryHandler.get_attribute(definition, :speckle_type) ==
|
||||
OBJECTS_BUILTELEMENTS_REVIT_LEVEL
|
||||
end
|
||||
levels.each do |level|
|
||||
level.entities.clear!
|
||||
level.instances.each(&:erase!)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,52 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'action'
|
||||
require_relative 'mapped_entities_updated'
|
||||
require_relative 'events/selection_event_action'
|
||||
require_relative '../sketchup_model/dictionary/speckle_schema_dictionary_handler'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Clear mappings for selected entities.
|
||||
class ClearMappings < Action
|
||||
def initialize(entities_to_map, is_definition)
|
||||
super()
|
||||
@entities_to_map = entities_to_map
|
||||
@is_definition = is_definition
|
||||
end
|
||||
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
# rubocop:disable Metrics/PerceivedComplexity
|
||||
def update_state(state)
|
||||
sketchup_model = state.sketchup_state.sketchup_model
|
||||
entities = if sketchup_model.active_path.nil?
|
||||
sketchup_model.entities
|
||||
else
|
||||
sketchup_model.active_path.last.definition.entities
|
||||
end
|
||||
|
||||
# Collect entities from entity ids that comes from UI as list
|
||||
entities_to_map = entities.select { |e| @entities_to_map.include?(e.persistent_id.to_s) }
|
||||
|
||||
# Switch to definitions if all entities are component instance and UI flag shows that
|
||||
if entities_to_map.all? { |e| e.is_a?(Sketchup::ComponentInstance) } && @is_definition
|
||||
entities_to_map = entities_to_map.collect(&:definition).uniq
|
||||
end
|
||||
|
||||
# Store speckle state to update with mapped entities.
|
||||
speckle_state = state.speckle_state
|
||||
entities_to_map.each do |entity|
|
||||
SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.remove_dictionary(entity)
|
||||
speckle_state = speckle_state.with_removed_mapped_entity(entity)
|
||||
end
|
||||
|
||||
new_state = MappedEntitiesUpdated.update_state(state.with_speckle_state(speckle_state))
|
||||
Events::SelectionEventAction.update_state(new_state, { clear: true })
|
||||
end
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
# rubocop:enable Metrics/PerceivedComplexity
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,34 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'action'
|
||||
require_relative 'mapped_entities_updated'
|
||||
require_relative 'events/selection_event_action'
|
||||
require_relative '../sketchup_model/dictionary/speckle_schema_dictionary_handler'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Clear mappings for selected entities from mapped elements table.
|
||||
class ClearMappingsFromTable < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, _resolve_id, data)
|
||||
# Flat entities to clear mappings
|
||||
flat_entities = SketchupModel::Query::Entity.flat_entities(state.sketchup_state.sketchup_model.entities)
|
||||
|
||||
# Collect entity ids to clear mappings
|
||||
entity_ids = data.collect { |_, entities| entities['selectedElements'].collect { |e| e['entityId'] } }.flatten
|
||||
# Store speckle state to update with mapped entities.
|
||||
speckle_state = state.speckle_state
|
||||
flat_entities.each do |entity|
|
||||
next unless entity_ids.include?(entity.persistent_id.to_s)
|
||||
|
||||
SketchupModel::Dictionary::SpeckleSchemaDictionaryHandler.remove_dictionary(entity)
|
||||
speckle_state = speckle_state.with_removed_mapped_entity(entity)
|
||||
end
|
||||
|
||||
new_state = MappedEntitiesUpdated.update_state(state.with_speckle_state(speckle_state))
|
||||
Events::SelectionEventAction.update_state(new_state, { clear: true })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
require_relative 'action'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Clear queue from state.
|
||||
class ClearQueue < Action
|
||||
@@ -4,13 +4,13 @@ require_relative 'action'
|
||||
require_relative '../ext/sqlite3'
|
||||
require_relative '../constants/path_constants'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Action to collect preferences from database to UI.
|
||||
class CollectPreferences < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, _data)
|
||||
def self.update_state(state, _resolve_id, _data)
|
||||
state.with_add_queue('collectPreferences', state.user_state.preferences.to_json, [])
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,20 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'action'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Action to collect versions from sketchup and connector to track user's version by mixpanel.
|
||||
class CollectVersions < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, _resolve_id, _data)
|
||||
versions = {
|
||||
sketchup: Sketchup.version.to_i,
|
||||
speckle: SpeckleConnector3::CONNECTOR_VERSION
|
||||
}
|
||||
state.with_add_queue('collectVersions', versions.to_json, [])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,22 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../action'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Action to get config.
|
||||
class GetConfig < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, resolve_id)
|
||||
# Previously it was stored in user state
|
||||
# config = state.user_state.preferences.to_json
|
||||
config = {
|
||||
darkTheme: state.user_state.user_preferences[:dark_theme]
|
||||
}
|
||||
js_script = "configBinding.receiveResponse('#{resolve_id}', #{config.to_json})"
|
||||
state.with_add_queue_js_command('getConfig', js_script)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,17 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../action'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Action to get is dev mode.
|
||||
class GetIsDevMode < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, resolve_id)
|
||||
js_script = "configBinding.receiveResponse('#{resolve_id}', #{DEV_MODE})"
|
||||
state.with_add_queue_js_command('getIsDevMode', js_script)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,21 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../action'
|
||||
require_relative '../../preferences/preferences'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
class GetUserSelectedAccountId < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, resolve_id)
|
||||
user_selected_account_id = Preferences.get_user_selected_account_id
|
||||
accountsConfig = {
|
||||
userSelectedAccountId: user_selected_account_id
|
||||
}
|
||||
js_script = "configBinding.receiveResponse('#{resolve_id}', #{accountsConfig.to_json})"
|
||||
state.with_add_queue_js_command('getUserSelectedAccountId', js_script)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,18 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../action'
|
||||
require_relative '../../preferences/preferences'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
class SetUserSelectedAccountId < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, resolve_id, account_id)
|
||||
Preferences.set_user_selected_account_id(account_id)
|
||||
js_script = "configBinding.receiveResponse('#{resolve_id}')"
|
||||
state.with_add_queue_js_command('setUserSelectedAccountId', js_script)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,26 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../action'
|
||||
require_relative '../user_preferences_updated'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Action to update config.
|
||||
class UpdateConfig < Action
|
||||
KEY_VALUES = {
|
||||
'darkTheme' => 'dark_theme'
|
||||
}.freeze
|
||||
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, resolve_id, config)
|
||||
config.each do |key, value|
|
||||
state = Actions::UserPreferencesUpdated.new('Sketchup', KEY_VALUES[key], value).update_state(state)
|
||||
end
|
||||
|
||||
js_script = "configBinding.receiveResponse('#{resolve_id}')"
|
||||
state.with_add_queue_js_command('updateConfig', js_script)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,6 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Action to update connected state of application.
|
||||
class Connected < Action
|
||||
@@ -6,7 +6,7 @@ require_relative '../actions/save_stream'
|
||||
require_relative '../actions/queue_send'
|
||||
require_relative '../convertors/converter'
|
||||
|
||||
module SpeckleConnector
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Create stream.
|
||||
class CreateStream < Action
|
||||
@@ -0,0 +1,26 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'action'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
# Deactivate diffing.
|
||||
class DeactivateDiffing < Action
|
||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||
# @return [States::State] the new updated state object
|
||||
def self.update_state(state, _resolve_id, _data)
|
||||
puts 'Diffing deactivated!'
|
||||
speckle_entities = state.speckle_state.speckle_entities
|
||||
diffing_activated_speckle_entities = speckle_entities.reject do |_id, entity|
|
||||
entity.active_diffing_stream_id.nil?
|
||||
end
|
||||
diffing_activated_speckle_entities.each do |id, entity|
|
||||
new_entity = entity.deactivate_diffing
|
||||
speckle_entities = speckle_entities.put(id, new_entity)
|
||||
end
|
||||
new_speckle_state = state.speckle_state.with_speckle_entities(speckle_entities)
|
||||
state.with_speckle_state(new_speckle_state)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,58 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'event_action'
|
||||
require_relative 'on_document_changed'
|
||||
require_relative '../load_sketchup_model'
|
||||
require_relative '../collect_preferences'
|
||||
|
||||
module SpeckleConnector3
|
||||
module Actions
|
||||
module Events
|
||||
# Handle events that are triggered by the {AppObserver}.
|
||||
class AppEventAction < EventAction
|
||||
# Handle loading new or existing model
|
||||
class OnNewOrChangedModel
|
||||
# Handle events when the new or existing model is loaded in Sketchup
|
||||
# @param state [States::State] the current state of speckle application
|
||||
# @param event_data [Array<(Sketchup::Model)>] the event data for the given event. It consists of
|
||||
# a double array with a single element that is the {Sketchup::Model} object of the loaded model.
|
||||
def self.update_state(state, event_data)
|
||||
return state unless event_data&.any?
|
||||
|
||||
model = event_data.flatten.first
|
||||
# LoadSketchupModel action should be responsible to update all model specific data for state and then
|
||||
# should notify the UI to update it's components.
|
||||
new_state = Actions::LoadSketchupModel.update_state(state, model)
|
||||
# Action to let UI to render itself with new preferences state
|
||||
# TODO: Later UI should be updated if any stream is invalid after
|
||||
# we collected speckle_entities appropriately
|
||||
new_state = CollectPreferences.update_state(new_state, nil, {})
|
||||
OnDocumentChanged.update_state(new_state)
|
||||
end
|
||||
end
|
||||
|
||||
# Run actions that are needed before the sketchup quits
|
||||
class OnQuit
|
||||
# Handle when Sketchup application closes
|
||||
# @param state [States::State] the current state of speckle application
|
||||
# @param _event_data [Array] the event data
|
||||
# @return [States::State] the transformed state object
|
||||
def self.update_state(state, _event_data)
|
||||
state
|
||||
end
|
||||
end
|
||||
|
||||
# Handlers that are used to handle specific events
|
||||
ACTIONS = {
|
||||
onNewModel: OnNewOrChangedModel,
|
||||
onOpenModel: OnNewOrChangedModel,
|
||||
onQuit: OnQuit
|
||||
}.freeze
|
||||
|
||||
def self.actions
|
||||
ACTIONS
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||